Merge branch 'jk/commit-how-to-abort-cherry-pick'
authorJunio C Hamano <gitster@pobox.com>
Wed, 31 Jul 2013 19:38:23 +0000 (12:38 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 31 Jul 2013 19:38:23 +0000 (12:38 -0700)
* jk/commit-how-to-abort-cherry-pick:
commit: tweak empty cherry pick advice for sequencer

1  2 
builtin/commit.c
diff --combined builtin/commit.c
index 003bd7dbec1acfda36f4d4bc5e9fb64a276ad049,39717d55bc43df77981f9198bc9c7b36019662e9..10acc53f8012f53b6a15a3d006b622bda3409b17
  #include "gpg-interface.h"
  #include "column.h"
  #include "sequencer.h"
 +#include "notes-utils.h"
  
  static const char * const builtin_commit_usage[] = {
 -      N_("git commit [options] [--] <filepattern>..."),
 +      N_("git commit [options] [--] <pathspec>..."),
        NULL
  };
  
  static const char * const builtin_status_usage[] = {
 -      N_("git status [options] [--] <filepattern>..."),
 +      N_("git status [options] [--] <pathspec>..."),
        NULL
  };
  
@@@ -63,8 -62,18 +63,18 @@@ N_("The previous cherry-pick is now emp
  "If you wish to commit it anyway, use:\n"
  "\n"
  "    git commit --allow-empty\n"
+ "\n");
+ static const char empty_cherry_pick_advice_single[] =
+ N_("Otherwise, please use 'git reset'\n");
+ static const char empty_cherry_pick_advice_multi[] =
+ N_("If you wish to skip this commit, use:\n"
  "\n"
- "Otherwise, please use 'git reset'\n");
+ "    git reset\n"
+ "\n"
+ "Then \"git cherry-pick --continue\" will resume cherry-picking\n"
+ "the remaining commits.\n");
  
  static const char *use_message_buffer;
  static const char commit_editmsg[] = "COMMIT_EDITMSG";
@@@ -104,35 -113,29 +114,36 @@@ static enum 
        CLEANUP_NONE,
        CLEANUP_ALL
  } cleanup_mode;
 -static char *cleanup_arg;
 +static const char *cleanup_arg;
  
  static enum commit_whence whence;
+ static int sequencer_in_use;
  static int use_editor = 1, include_status = 1;
 -static int show_ignored_in_status;
 +static int show_ignored_in_status, have_option_m;
  static const char *only_include_assumed;
  static struct strbuf message = STRBUF_INIT;
  
 -static enum {
 +static enum status_format {
 +      STATUS_FORMAT_NONE = 0,
        STATUS_FORMAT_LONG,
        STATUS_FORMAT_SHORT,
 -      STATUS_FORMAT_PORCELAIN
 -} status_format = STATUS_FORMAT_LONG;
 +      STATUS_FORMAT_PORCELAIN,
 +
 +      STATUS_FORMAT_UNSPECIFIED
 +} status_format = STATUS_FORMAT_UNSPECIFIED;
  
  static int opt_parse_m(const struct option *opt, const char *arg, int unset)
  {
        struct strbuf *buf = opt->value;
 -      if (unset)
 +      if (unset) {
 +              have_option_m = 0;
                strbuf_setlen(buf, 0);
 -      else {
 +      } else {
 +              have_option_m = 1;
 +              if (buf->len)
 +                      strbuf_addch(buf, '\n');
                strbuf_addstr(buf, arg);
 -              strbuf_addstr(buf, "\n\n");
 +              strbuf_complete_line(buf);
        }
        return 0;
  }
@@@ -141,8 -144,11 +152,11 @@@ static void determine_whence(struct wt_
  {
        if (file_exists(git_path("MERGE_HEAD")))
                whence = FROM_MERGE;
-       else if (file_exists(git_path("CHERRY_PICK_HEAD")))
+       else if (file_exists(git_path("CHERRY_PICK_HEAD"))) {
                whence = FROM_CHERRY_PICK;
+               if (file_exists(git_path("sequencer")))
+                       sequencer_in_use = 1;
+       }
        else
                whence = FROM_COMMIT;
        if (s)
@@@ -207,7 -213,7 +221,7 @@@ static int list_paths(struct string_lis
        }
  
        for (i = 0; i < active_nr; i++) {
 -              struct cache_entry *ce = active_cache[i];
 +              const struct cache_entry *ce = active_cache[i];
                struct string_list_item *item;
  
                if (ce->ce_flags & CE_UPDATE)
@@@ -462,10 -468,6 +476,10 @@@ static int run_status(FILE *fp, const c
        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;
@@@ -534,6 -536,7 +548,6 @@@ static void determine_author_info(struc
                                        (lb - strlen(" ") -
                                         (a + strlen("\nauthor "))));
                email = xmemdupz(lb + strlen("<"), rb - (lb + strlen("<")));
 -              date = xmemdupz(rb + strlen("> "), eol - (rb + strlen("> ")));
                len = eol - (rb + strlen("> "));
                date = xmalloc(len + 2);
                *date = '@';
@@@ -709,7 -712,7 +723,7 @@@ static int prepare_to_commit(const cha
                        previous = eol;
                }
  
 -              append_signoff(&sb, ignore_footer);
 +              append_signoff(&sb, ignore_footer, 0);
        }
  
        if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len)
                if (cleanup_mode == CLEANUP_ALL)
                        status_printf(s, GIT_COLOR_NORMAL,
                                _("Please enter the commit message for your changes."
 -                              " Lines starting\nwith '#' will be ignored, and an empty"
 -                              " message aborts the commit.\n"));
 +                                " Lines starting\nwith '%c' will be ignored, and an empty"
 +                                " message aborts the commit.\n"), comment_line_char);
                else /* CLEANUP_SPACE, that is. */
                        status_printf(s, GIT_COLOR_NORMAL,
                                _("Please enter the commit message for your changes."
 -                              " Lines starting\n"
 -                              "with '#' will be kept; you may remove them"
 -                              " yourself if you want to.\n"
 -                              "An empty message aborts the commit.\n"));
 +                                " Lines starting\n"
 +                                "with '%c' will be kept; you may remove them"
 +                                " yourself if you want to.\n"
 +                                "An empty message aborts the commit.\n"), comment_line_char);
                if (only_include_assumed)
                        status_printf_ln(s, GIT_COLOR_NORMAL,
                                        "%s", only_include_assumed);
                                ident_shown++ ? "" : "\n",
                                author_ident->buf);
  
 -              if (!user_ident_sufficiently_given())
 +              if (!committer_ident_sufficiently_given())
                        status_printf_ln(s, GIT_COLOR_NORMAL,
                                _("%s"
                                "Committer: %s"),
                run_status(stdout, index_file, prefix, 0, s);
                if (amend)
                        fputs(_(empty_amend_advice), stderr);
-               else if (whence == FROM_CHERRY_PICK)
+               else if (whence == FROM_CHERRY_PICK) {
                        fputs(_(empty_cherry_pick_advice), stderr);
+                       if (!sequencer_in_use)
+                               fputs(_(empty_cherry_pick_advice_single), stderr);
+                       else
+                               fputs(_(empty_cherry_pick_advice_multi), stderr);
+               }
                return 0;
        }
  
@@@ -955,50 -963,24 +974,50 @@@ static void handle_untracked_files_arg(
  
  static const char *read_commit_message(const char *name)
  {
 -      const char *out_enc, *out;
 +      const char *out_enc;
        struct commit *commit;
  
        commit = lookup_commit_reference_by_name(name);
        if (!commit)
                die(_("could not lookup commit %s"), name);
        out_enc = get_commit_output_encoding();
 -      out = logmsg_reencode(commit, out_enc);
 +      return logmsg_reencode(commit, NULL, out_enc);
 +}
  
 -      /*
 -       * If we failed to reencode the buffer, just copy it
 -       * byte for byte so the user can try to fix it up.
 -       * This also handles the case where input and output
 -       * encodings are identical.
 -       */
 -      if (out == NULL)
 -              out = xstrdup(commit->buffer);
 -      return out;
 +/*
 + * Enumerate what needs to be propagated when --porcelain
 + * is not in effect here.
 + */
 +static struct status_deferred_config {
 +      enum status_format status_format;
 +      int show_branch;
 +} status_deferred_config = {
 +      STATUS_FORMAT_UNSPECIFIED,
 +      -1 /* unspecified */
 +};
 +
 +static void finalize_deferred_config(struct wt_status *s)
 +{
 +      int use_deferred_config = (status_format != STATUS_FORMAT_PORCELAIN &&
 +                                 !s->null_termination);
 +
 +      if (s->null_termination) {
 +              if (status_format == STATUS_FORMAT_NONE ||
 +                  status_format == STATUS_FORMAT_UNSPECIFIED)
 +                      status_format = STATUS_FORMAT_PORCELAIN;
 +              else if (status_format == STATUS_FORMAT_LONG)
 +                      die(_("--long and -z are incompatible"));
 +      }
 +
 +      if (use_deferred_config && status_format == STATUS_FORMAT_UNSPECIFIED)
 +              status_format = status_deferred_config.status_format;
 +      if (status_format == STATUS_FORMAT_UNSPECIFIED)
 +              status_format = STATUS_FORMAT_NONE;
 +
 +      if (use_deferred_config && s->show_branch < 0)
 +              s->show_branch = status_deferred_config.show_branch;
 +      if (s->show_branch < 0)
 +              s->show_branch = 0;
  }
  
  static int parse_and_validate_options(int argc, const char *argv[],
        int f = 0;
  
        argc = parse_options(argc, argv, prefix, options, usage, 0);
 +      finalize_deferred_config(s);
  
        if (force_author && !strchr(force_author, '>'))
                force_author = find_author_by_nickname(force_author);
        if (force_author && renew_authorship)
                die(_("Using both --reset-author and --author does not make sense"));
  
 -      if (logfile || message.len || use_message || fixup_message)
 +      if (logfile || have_option_m || use_message || fixup_message)
                use_editor = 0;
        if (0 <= edit_flag)
                use_editor = edit_flag;
        if (all && argc > 0)
                die(_("Paths with -a does not make sense."));
  
 -      if (s->null_termination && status_format == STATUS_FORMAT_LONG)
 -              status_format = STATUS_FORMAT_PORCELAIN;
 -      if (status_format != STATUS_FORMAT_LONG)
 +      if (status_format != STATUS_FORMAT_NONE)
                dry_run = 1;
  
        return argc;
@@@ -1148,17 -1131,6 +1167,17 @@@ static int git_status_config(const cha
                        s->submodule_summary = -1;
                return 0;
        }
 +      if (!strcmp(k, "status.short")) {
 +              if (git_config_bool(k, v))
 +                      status_deferred_config.status_format = STATUS_FORMAT_SHORT;
 +              else
 +                      status_deferred_config.status_format = STATUS_FORMAT_NONE;
 +              return 0;
 +      }
 +      if (!strcmp(k, "status.branch")) {
 +              status_deferred_config.show_branch = git_config_bool(k, v);
 +              return 0;
 +      }
        if (!strcmp(k, "status.color") || !strcmp(k, "color.status")) {
                s->use_color = git_config_colorbool(k, v);
                return 0;
@@@ -1201,14 -1173,11 +1220,14 @@@ int cmd_status(int argc, const char **a
                OPT__VERBOSE(&verbose, N_("be verbose")),
                OPT_SET_INT('s', "short", &status_format,
                            N_("show status concisely"), STATUS_FORMAT_SHORT),
 -              OPT_BOOLEAN('b', "branch", &s.show_branch,
 -                          N_("show branch information")),
 +              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),
 +              OPT_SET_INT(0, "long", &status_format,
 +                          N_("show status in long format (default)"),
 +                          STATUS_FORMAT_LONG),
                OPT_BOOLEAN('z', "null", &s.null_termination,
                            N_("terminate entries with NUL")),
                { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg,
                             builtin_status_options,
                             builtin_status_usage, 0);
        finalize_colopts(&s.colopts, -1);
 -
 -      if (s.null_termination && status_format == STATUS_FORMAT_LONG)
 -              status_format = STATUS_FORMAT_PORCELAIN;
 +      finalize_deferred_config(&s);
  
        handle_untracked_files_arg(&s);
        if (show_ignored_in_status)
        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;
@@@ -1303,7 -1270,7 +1322,7 @@@ static void print_summary(const char *p
                strbuf_addstr(&format, "\n Author: ");
                strbuf_addbuf_percentquote(&format, &author_ident);
        }
 -      if (!user_ident_sufficiently_given()) {
 +      if (!committer_ident_sufficiently_given()) {
                strbuf_addstr(&format, "\n Committer: ");
                strbuf_addbuf_percentquote(&format, &committer_ident);
                if (advice_implicit_identity) {
@@@ -1358,8 -1325,6 +1377,8 @@@ static int git_commit_config(const cha
                include_status = git_config_bool(k, v);
                return 0;
        }
 +      if (!strcmp(k, "commit.cleanup"))
 +              return git_config_string(&cleanup_arg, k, v);
  
        status = git_gpg_config(k, v, NULL);
        if (status)
        return git_status_config(k, v, s);
  }
  
 -static const char post_rewrite_hook[] = "hooks/post-rewrite";
 -
  static int run_rewrite_hook(const unsigned char *oldsha1,
                            const unsigned char *newsha1)
  {
        int code;
        size_t n;
  
 -      if (access(git_path(post_rewrite_hook), X_OK) < 0)
 +      argv[0] = find_hook("post-rewrite");
 +      if (!argv[0])
                return 0;
  
 -      argv[0] = git_path(post_rewrite_hook);
        argv[1] = "amend";
        argv[2] = NULL;
  
@@@ -1435,12 -1402,9 +1454,12 @@@ int cmd_commit(int argc, const char **a
                OPT_BOOLEAN(0, "dry-run", &dry_run, N_("show what would be committed")),
                OPT_SET_INT(0, "short", &status_format, N_("show status concisely"),
                            STATUS_FORMAT_SHORT),
 -              OPT_BOOLEAN(0, "branch", &s.show_branch, N_("show branch information")),
 +              OPT_BOOL(0, "branch", &s.show_branch, N_("show branch information")),
                OPT_SET_INT(0, "porcelain", &status_format,
                            N_("machine-readable output"), STATUS_FORMAT_PORCELAIN),
 +              OPT_SET_INT(0, "long", &status_format,
 +                          N_("show status in long format (default)"),
 +                          STATUS_FORMAT_LONG),
                OPT_BOOLEAN('z', "null", &s.null_termination,
                            N_("terminate entries with NUL")),
                OPT_BOOLEAN(0, "amend", &amend, N_("amend previous commit")),
        wt_status_prepare(&s);
        gitmodules_config();
        git_config(git_commit_config, &s);
 +      status_format = STATUS_FORMAT_NONE; /* Ignore status.short */
        determine_whence(&s);
        s.colopts = 0;
  
                if (cfg) {
                        /* we are amending, so current_head is not NULL */
                        copy_note_for_rewrite(cfg, current_head->object.sha1, sha1);
 -                      finish_copy_notes_for_rewrite(cfg);
 +                      finish_copy_notes_for_rewrite(cfg, "Notes added by 'git commit --amend'");
                }
                run_rewrite_hook(current_head->object.sha1, sha1);
        }