Merge branch 'ak/commit-only-allow-empty' into maint
authorJunio C Hamano <gitster@pobox.com>
Tue, 17 Jan 2017 23:11:03 +0000 (15:11 -0800)
committerJunio C Hamano <gitster@pobox.com>
Tue, 17 Jan 2017 23:11:03 +0000 (15:11 -0800)
"git commit --allow-empty --only" (no pathspec) with dirty index
ought to be an acceptable way to create a new commit that does not
change any paths, but it was forbidden, perhaps because nobody
needed it so far.

* ak/commit-only-allow-empty:
commit: remove 'Clever' message for --only --amend
commit: make --only --allow-empty work without paths

1  2 
Documentation/git-commit.txt
builtin/commit.c
index f2ab0ee2e7d1ff0f79c09cbd27e745f5f08d139d,374808b966e3d67d7bf24fb54d4da3a6ff6cbc55..4f8f20a3606201b1835affc523ff2828549d0285
@@@ -29,8 -29,7 +29,8 @@@ The content to be added can be specifie
  2. by using 'git rm' to remove files from the working tree
     and the index, again before using the 'commit' command;
  
 -3. by listing files as arguments to the 'commit' command, in which
 +3. by listing files as arguments to the 'commit' command
 +   (without --interactive or --patch switch), in which
     case the commit will ignore changes staged in the index, and instead
     record the current content of the listed files (which must already
     be known to Git);
@@@ -42,8 -41,7 +42,8 @@@
     actual commit;
  
  5. by using the --interactive or --patch switches with the 'commit' command
 -   to decide one by one which files or hunks should be part of the commit,
 +   to decide one by one which files or hunks should be part of the commit
 +   in addition to contents in the index,
     before finalizing the operation. See the ``Interactive Mode'' section of
     linkgit:git-add[1] to learn how to operate these modes.
  
@@@ -265,7 -263,8 +265,8 @@@ FROM UPSTREAM REBASE" section in linkgi
        If this option is specified together with `--amend`, then
        no paths need to be specified, which can be used to amend
        the last commit without committing changes that have
-       already been staged.
+       already been staged. If used together with `--allow-empty`
+       paths are also not required, and an empty commit will be created.
  
  -u[<mode>]::
  --untracked-files[=<mode>]::
diff --combined builtin/commit.c
index 8976c3d29bf817be789f983697f7052fe5769f39,fc3655ae4c3f8cdc8425650739288b6bd9d98f09..276c74034e278fe40975c6390839112d0493664d
@@@ -142,24 -142,14 +142,24 @@@ static int show_ignored_in_status, have
  static const char *only_include_assumed;
  static struct strbuf message = STRBUF_INIT;
  
 -static enum status_format {
 -      STATUS_FORMAT_NONE = 0,
 -      STATUS_FORMAT_LONG,
 -      STATUS_FORMAT_SHORT,
 -      STATUS_FORMAT_PORCELAIN,
 +static enum wt_status_format status_format = STATUS_FORMAT_UNSPECIFIED;
  
 -      STATUS_FORMAT_UNSPECIFIED
 -} status_format = STATUS_FORMAT_UNSPECIFIED;
 +static int opt_parse_porcelain(const struct option *opt, const char *arg, int unset)
 +{
 +      enum wt_status_format *value = (enum wt_status_format *)opt->value;
 +      if (unset)
 +              *value = STATUS_FORMAT_NONE;
 +      else if (!arg)
 +              *value = STATUS_FORMAT_PORCELAIN;
 +      else if (!strcmp(arg, "v1") || !strcmp(arg, "1"))
 +              *value = STATUS_FORMAT_PORCELAIN;
 +      else if (!strcmp(arg, "v2") || !strcmp(arg, "2"))
 +              *value = STATUS_FORMAT_PORCELAIN_V2;
 +      else
 +              die("unsupported porcelain version '%s'", arg);
 +
 +      return 0;
 +}
  
  static int opt_parse_m(const struct option *opt, const char *arg, int unset)
  {
@@@ -183,7 -173,7 +183,7 @@@ static void determine_whence(struct wt_
                whence = FROM_MERGE;
        else if (file_exists(git_path_cherry_pick_head())) {
                whence = FROM_CHERRY_PICK;
 -              if (file_exists(git_path(SEQ_DIR)))
 +              if (file_exists(git_path_seq_dir()))
                        sequencer_in_use = 1;
        }
        else
@@@ -397,7 -387,7 +397,7 @@@ static const char *prepare_index(int ar
         */
        if (all || (also && pathspec.nr)) {
                hold_locked_index(&index_lock, 1);
 -              add_files_to_cache(also ? prefix : NULL, &pathspec, 0, 0);
 +              add_files_to_cache(also ? prefix : NULL, &pathspec, 0);
                refresh_cache_or_die(refresh_flags);
                update_main_cache_tree(WRITE_TREE_SILENT);
                if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
@@@ -510,13 -500,24 +510,13 @@@ static int run_status(FILE *fp, const c
        s->fp = fp;
        s->nowarn = nowarn;
        s->is_initial = get_sha1(s->reference, sha1) ? 1 : 0;
 +      if (!s->is_initial)
 +              hashcpy(s->sha1_commit, sha1);
 +      s->status_format = status_format;
 +      s->ignore_submodule_arg = ignore_submodule_arg;
  
        wt_status_collect(s);
 -
 -      switch (status_format) {
 -      case STATUS_FORMAT_SHORT:
 -              wt_shortstatus_print(s);
 -              break;
 -      case STATUS_FORMAT_PORCELAIN:
 -              wt_porcelain_print(s);
 -              break;
 -      case STATUS_FORMAT_UNSPECIFIED:
 -              die("BUG: finalize_deferred_config() should have been called");
 -              break;
 -      case STATUS_FORMAT_NONE:
 -      case STATUS_FORMAT_LONG:
 -              wt_status_print(s);
 -              break;
 -      }
 +      wt_status_print(s);
  
        return s->commitable;
  }
@@@ -894,14 -895,9 +894,14 @@@ static int prepare_to_commit(const cha
                if (amend)
                        parent = "HEAD^1";
  
 -              if (get_sha1(parent, sha1))
 -                      commitable = !!active_nr;
 -              else {
 +              if (get_sha1(parent, sha1)) {
 +                      int i, ita_nr = 0;
 +
 +                      for (i = 0; i < active_nr; i++)
 +                              if (ce_intent_to_add(active_cache[i]))
 +                                      ita_nr++;
 +                      commitable = active_nr - ita_nr > 0;
 +              } else {
                        /*
                         * Unless the user did explicitly request a submodule
                         * ignore mode by passing a command line option we do
                        if (ignore_submodule_arg &&
                            !strcmp(ignore_submodule_arg, "all"))
                                diff_flags |= DIFF_OPT_IGNORE_SUBMODULES;
 -                      commitable = index_differs_from(parent, diff_flags);
 +                      commitable = index_differs_from(parent, diff_flags, 1);
                }
        }
        strbuf_release(&committer_ident);
@@@ -1103,7 -1099,7 +1103,7 @@@ static const char *read_commit_message(
   * is not in effect here.
   */
  static struct status_deferred_config {
 -      enum status_format status_format;
 +      enum wt_status_format status_format;
        int show_branch;
  } status_deferred_config = {
        STATUS_FORMAT_UNSPECIFIED,
  static void finalize_deferred_config(struct wt_status *s)
  {
        int use_deferred_config = (status_format != STATUS_FORMAT_PORCELAIN &&
 +                                 status_format != STATUS_FORMAT_PORCELAIN_V2 &&
                                   !s->null_termination);
  
        if (s->null_termination) {
@@@ -1206,10 -1201,8 +1206,8 @@@ static int parse_and_validate_options(i
  
        if (also + only + all + interactive > 1)
                die(_("Only one of --include/--only/--all/--interactive/--patch can be used."));
-       if (argc == 0 && (also || (only && !amend)))
+       if (argc == 0 && (also || (only && !amend && !allow_empty)))
                die(_("No paths with --include/--only does not make sense."));
-       if (argc == 0 && only && amend)
-               only_include_assumed = _("Clever... amending the last one with dirty index.");
        if (argc > 0 && !also && !only)
                only_include_assumed = _("Explicit paths specified without -i or -o; assuming --only paths...");
        if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
@@@ -1341,9 -1334,9 +1339,9 @@@ int cmd_status(int argc, const char **a
                            N_("show status concisely"), STATUS_FORMAT_SHORT),
                OPT_BOOL('b', "branch", &s.show_branch,
                         N_("show branch information")),
 -              OPT_SET_INT(0, "porcelain", &status_format,
 -                          N_("machine-readable output"),
 -                          STATUS_FORMAT_PORCELAIN),
 +              { OPTION_CALLBACK, 0, "porcelain", &status_format,
 +                N_("version"), N_("machine-readable output"),
 +                PARSE_OPT_OPTARG, opt_parse_porcelain },
                OPT_SET_INT(0, "long", &status_format,
                            N_("show status in long format (default)"),
                            STATUS_FORMAT_LONG),
        fd = hold_locked_index(&index_lock, 0);
  
        s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0;
 +      if (!s.is_initial)
 +              hashcpy(s.sha1_commit, sha1);
 +
        s.ignore_submodule_arg = ignore_submodule_arg;
 +      s.status_format = status_format;
 +      s.verbose = verbose;
 +
        wt_status_collect(&s);
  
        if (0 <= fd)
        if (s.relative_paths)
                s.prefix = prefix;
  
 -      switch (status_format) {
 -      case STATUS_FORMAT_SHORT:
 -              wt_shortstatus_print(&s);
 -              break;
 -      case STATUS_FORMAT_PORCELAIN:
 -              wt_porcelain_print(&s);
 -              break;
 -      case STATUS_FORMAT_UNSPECIFIED:
 -              die("BUG: finalize_deferred_config() should have been called");
 -              break;
 -      case STATUS_FORMAT_NONE:
 -      case STATUS_FORMAT_LONG:
 -              s.verbose = verbose;
 -              s.ignore_submodule_arg = ignore_submodule_arg;
 -              wt_status_print(&s);
 -              break;
 -      }
 +      wt_status_print(&s);
        return 0;
  }
  
@@@ -1642,7 -1645,7 +1640,7 @@@ int cmd_commit(int argc, const char **a
        const char *index_file, *reflog_msg;
        char *nl;
        unsigned char sha1[20];
 -      struct commit_list *parents = NULL, **pptr = &parents;
 +      struct commit_list *parents = NULL;
        struct stat statbuf;
        struct commit *current_head = NULL;
        struct commit_extra_header *extra = NULL;
                if (!reflog_msg)
                        reflog_msg = "commit (initial)";
        } else if (amend) {
 -              struct commit_list *c;
 -
                if (!reflog_msg)
                        reflog_msg = "commit (amend)";
 -              for (c = current_head->parents; c; c = c->next)
 -                      pptr = &commit_list_insert(c->item, pptr)->next;
 +              parents = copy_commit_list(current_head->parents);
        } else if (whence == FROM_MERGE) {
                struct strbuf m = STRBUF_INIT;
                FILE *fp;
                int allow_fast_forward = 1;
 +              struct commit_list **pptr = &parents;
  
                if (!reflog_msg)
                        reflog_msg = "commit (merge)";
 -              pptr = &commit_list_insert(current_head, pptr)->next;
 +              pptr = commit_list_append(current_head, pptr);
                fp = fopen(git_path_merge_head(), "r");
                if (fp == NULL)
                        die_errno(_("could not open '%s' for reading"),
                        parent = get_merge_parent(m.buf);
                        if (!parent)
                                die(_("Corrupt MERGE_HEAD file (%s)"), m.buf);
 -                      pptr = &commit_list_insert(parent, pptr)->next;
 +                      pptr = commit_list_append(parent, pptr);
                }
                fclose(fp);
                strbuf_release(&m);
                        reflog_msg = (whence == FROM_CHERRY_PICK)
                                        ? "commit (cherry-pick)"
                                        : "commit";
 -              pptr = &commit_list_insert(current_head, pptr)->next;
 +              commit_list_insert(current_head, &parents);
        }
  
        /* Finally, get the commit message */