Merge branch 'jn/cherry-revert-message-clean-up'
authorJunio C Hamano <gitster@pobox.com>
Tue, 31 Aug 2010 23:25:11 +0000 (16:25 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 31 Aug 2010 23:25:11 +0000 (16:25 -0700)
* jn/cherry-revert-message-clean-up:
tests: fix syntax error in "Use advise() for hints" test
cherry-pick/revert: Use advise() for hints
cherry-pick/revert: Use error() for failure message
Introduce advise() to print hints
Eliminate “Finished cherry-pick/revert” message
t3508: add check_head_differs_from() helper function and use it
revert: improve success message by adding abbreviated commit sha1
revert: don't print "Finished one cherry-pick." if commit failed
revert: refactor commit code into a new run_git_commit() function
revert: report success when using option --strategy

1  2 
builtin/revert.c
git-rebase--interactive.sh
diff --combined builtin/revert.c
index 9215e665046a8991b57f8d4cfda123dae084414c,7f35cc6e1734c4000d8971f808356d0fb344ffc6..5ca81580d37b20e6f65fc8e8d1cdf09228f33ca1
@@@ -102,9 -102,9 +102,9 @@@ struct commit_message 
  static int get_message(const char *raw_message, struct commit_message *out)
  {
        const char *encoding;
 -      const char *p, *abbrev, *eol;
 +      const char *abbrev, *subject;
 +      int abbrev_len, subject_len;
        char *q;
 -      int abbrev_len, oneline_len;
  
        if (!raw_message)
                return -1;
        abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
        abbrev_len = strlen(abbrev);
  
 -      /* Find beginning and end of commit subject. */
 -      p = out->message;
 -      while (*p && (*p != '\n' || p[1] != '\n'))
 -              p++;
 -      if (*p) {
 -              p += 2;
 -              for (eol = p + 1; *eol && *eol != '\n'; eol++)
 -                      ; /* do nothing */
 -      } else
 -              eol = p;
 -      oneline_len = eol - p;
 +      subject_len = find_commit_subject(out->message, &subject);
  
        out->parent_label = xmalloc(strlen("parent of ") + abbrev_len +
 -                            strlen("... ") + oneline_len + 1);
 +                            strlen("... ") + subject_len + 1);
        q = out->parent_label;
        q = mempcpy(q, "parent of ", strlen("parent of "));
        out->label = q;
        q = mempcpy(q, abbrev, abbrev_len);
        q = mempcpy(q, "... ", strlen("... "));
        out->subject = q;
 -      q = mempcpy(q, p, oneline_len);
 +      q = mempcpy(q, subject, subject_len);
        *q = '\0';
        return 0;
  }
@@@ -231,27 -241,30 +231,30 @@@ static void set_author_ident_env(const 
                        sha1_to_hex(commit->object.sha1));
  }
  
- static char *help_msg(void)
+ static void advise(const char *advice, ...)
  {
-       struct strbuf helpbuf = STRBUF_INIT;
-       char *msg = getenv("GIT_CHERRY_PICK_HELP");
+       va_list params;
  
-       if (msg)
-               return msg;
+       va_start(params, advice);
+       vreportf("hint: ", advice, params);
+       va_end(params);
+ }
  
-       strbuf_addstr(&helpbuf, "  After resolving the conflicts,\n"
-               "mark the corrected paths with 'git add <paths>' or 'git rm <paths>'\n"
-               "and commit the result");
+ static void print_advice(void)
+ {
+       char *msg = getenv("GIT_CHERRY_PICK_HELP");
  
-       if (action == CHERRY_PICK) {
-               strbuf_addf(&helpbuf, " with: \n"
-                       "\n"
-                       "        git commit -c %s\n",
-                           sha1_to_hex(commit->object.sha1));
+       if (msg) {
+               fprintf(stderr, "%s\n", msg);
+               return;
        }
-       else
-               strbuf_addch(&helpbuf, '.');
-       return strbuf_detach(&helpbuf, NULL);
+       advise("after resolving the conflicts, mark the corrected paths");
+       advise("with 'git add <paths>' or 'git rm <paths>'");
+       if (action == CHERRY_PICK)
+               advise("and commit the result with 'git commit -c %s'",
+                      find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
  }
  
  static void write_message(struct strbuf *msgbuf, const char *filename)
@@@ -301,10 -314,9 +304,9 @@@ static int fast_forward_to(const unsign
        return write_ref_sha1(ref_lock, to, "cherry-pick");
  }
  
- static void do_recursive_merge(struct commit *base, struct commit *next,
-                              const char *base_label, const char *next_label,
-                              unsigned char *head, struct strbuf *msgbuf,
-                              char *defmsg)
+ static int do_recursive_merge(struct commit *base, struct commit *next,
+                             const char *base_label, const char *next_label,
+                             unsigned char *head, struct strbuf *msgbuf)
  {
        struct merge_options o;
        struct tree *result, *next_tree, *base_tree, *head_tree;
                                        i++;
                        }
                }
-               write_message(msgbuf, defmsg);
-               fprintf(stderr, "Automatic %s failed.%s\n",
-                       me, help_msg());
-               rerere(allow_rerere_auto);
-               exit(1);
        }
-       write_message(msgbuf, defmsg);
-       fprintf(stderr, "Finished one %s.\n", me);
+       return !clean;
+ }
+ /*
+  * If we are cherry-pick, and if the merge did not result in
+  * hand-editing, we will hit this commit and inherit the original
+  * author date and name.
+  * If we are revert, or if our cherry-pick results in a hand merge,
+  * we had better say that the current user is responsible for that.
+  */
+ static int run_git_commit(const char *defmsg)
+ {
+       /* 6 is max possible length of our args array including NULL */
+       const char *args[6];
+       int i = 0;
+       args[i++] = "commit";
+       args[i++] = "-n";
+       if (signoff)
+               args[i++] = "-s";
+       if (!edit) {
+               args[i++] = "-F";
+               args[i++] = defmsg;
+       }
+       args[i] = NULL;
+       return run_command_v_opt(args, RUN_GIT_CMD);
  }
  
  static int do_pick_commit(void)
        struct commit_message msg = { NULL, NULL, NULL, NULL, NULL };
        char *defmsg = NULL;
        struct strbuf msgbuf = STRBUF_INIT;
+       int res;
  
        if (no_commit) {
                /*
                }
        }
  
-       if (!strategy || !strcmp(strategy, "recursive") || action == REVERT)
-               do_recursive_merge(base, next, base_label, next_label,
-                                  head, &msgbuf, defmsg);
-       else {
-               int res;
+       if (!strategy || !strcmp(strategy, "recursive") || action == REVERT) {
+               res = do_recursive_merge(base, next, base_label, next_label,
+                                        head, &msgbuf);
+               write_message(&msgbuf, defmsg);
+       } else {
                struct commit_list *common = NULL;
                struct commit_list *remotes = NULL;
                write_message(&msgbuf, defmsg);
                commit_list_insert(base, &common);
                commit_list_insert(next, &remotes);
                res = try_merge_command(strategy, common,
                                        sha1_to_hex(head), remotes);
                free_commit_list(common);
                free_commit_list(remotes);
-               if (res) {
-                       fprintf(stderr, "Automatic %s with strategy %s failed.%s\n",
-                               me, strategy, help_msg());
-                       rerere(allow_rerere_auto);
-                       exit(1);
-               }
        }
  
-       free_message(&msg);
-       /*
-        *
-        * If we are cherry-pick, and if the merge did not result in
-        * hand-editing, we will hit this commit and inherit the original
-        * author date and name.
-        * If we are revert, or if our cherry-pick results in a hand merge,
-        * we had better say that the current user is responsible for that.
-        */
-       if (!no_commit) {
-               /* 6 is max possible length of our args array including NULL */
-               const char *args[6];
-               int res;
-               int i = 0;
-               args[i++] = "commit";
-               args[i++] = "-n";
-               if (signoff)
-                       args[i++] = "-s";
-               if (!edit) {
-                       args[i++] = "-F";
-                       args[i++] = defmsg;
-               }
-               args[i] = NULL;
-               res = run_command_v_opt(args, RUN_GIT_CMD);
-               free(defmsg);
-               return res;
+       if (res) {
+               error("could not %s %s... %s",
+                     action == REVERT ? "revert" : "apply",
+                     find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV),
+                     msg.subject);
+               print_advice();
+               rerere(allow_rerere_auto);
+       } else {
+               if (!no_commit)
+                       res = run_git_commit(defmsg);
        }
  
+       free_message(&msg);
        free(defmsg);
  
-       return 0;
+       return res;
  }
  
  static void prepare_revs(struct rev_info *revs)
index 4d14b077d22ac030956fa686b637ac86763f05c0,8f6876d3019939c6f4c4f5433abaa5fb7e43151f..eb2dff55f81b6726340ce26db93bb161087a4857
@@@ -111,16 -111,15 +111,16 @@@ VERBOSE
  OK_TO_SKIP_PRE_REBASE=
  REBASE_ROOT=
  AUTOSQUASH=
 +test "$(git config --bool rebase.autosquash)" = "true" && AUTOSQUASH=t
  NEVER_FF=
  
- GIT_CHERRY_PICK_HELP="  After resolving the conflicts,
- mark the corrected paths with 'git add <paths>', and
- run 'git rebase --continue'"
+ GIT_CHERRY_PICK_HELP="\
+ hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' and run 'git rebase --continue'"
  export GIT_CHERRY_PICK_HELP
  
  warn () {
 -      echo "$*" >&2
 +      printf '%s\n' "$*" >&2
  }
  
  output () {
@@@ -538,34 -537,6 +538,34 @@@ do_next () 
                esac
                record_in_rewritten $sha1
                ;;
 +      x|"exec")
 +              read -r command rest < "$TODO"
 +              mark_action_done
 +              printf 'Executing: %s\n' "$rest"
 +              # "exec" command doesn't take a sha1 in the todo-list.
 +              # => can't just use $sha1 here.
 +              git rev-parse --verify HEAD > "$DOTEST"/stopped-sha
 +              ${SHELL:-@SHELL_PATH@} -c "$rest" # Actual execution
 +              status=$?
 +              if test "$status" -ne 0
 +              then
 +                      warn "Execution failed: $rest"
 +                      warn "You can fix the problem, and then run"
 +                      warn
 +                      warn "  git rebase --continue"
 +                      warn
 +                      exit "$status"
 +              fi
 +              # Run in subshell because require_clean_work_tree can die.
 +              if ! (require_clean_work_tree)
 +              then
 +                      warn "Commit or stash your changes, and then run"
 +                      warn
 +                      warn "  git rebase --continue"
 +                      warn
 +                      exit 1
 +              fi
 +              ;;
        *)
                warn "Unknown command: $command $sha1 $rest"
                if git rev-parse --verify -q "$sha1" >/dev/null
@@@ -620,30 -591,22 +620,30 @@@ do_rest () 
  # skip picking commits whose parents are unchanged
  skip_unnecessary_picks () {
        fd=3
 -      while read -r command sha1 rest
 +      while read -r command rest
        do
                # fd=3 means we skip the command
 -              case "$fd,$command,$(git rev-parse --verify --quiet $sha1^)" in
 -              3,pick,"$ONTO"*|3,p,"$ONTO"*)
 +              case "$fd,$command" in
 +              3,pick|3,p)
                        # pick a commit whose parent is current $ONTO -> skip
 -                      ONTO=$sha1
 +                      sha1=$(printf '%s' "$rest" | cut -d ' ' -f 1)
 +                      case "$(git rev-parse --verify --quiet "$sha1"^)" in
 +                      "$ONTO"*)
 +                              ONTO=$sha1
 +                              ;;
 +                      *)
 +                              fd=1
 +                              ;;
 +                      esac
                        ;;
 -              3,#*|3,,*)
 +              3,#*|3,)
                        # copy comments
                        ;;
                *)
                        fd=1
                        ;;
                esac
 -              echo "$command${sha1:+ }$sha1${rest:+ }$rest" >&$fd
 +              printf '%s\n' "$command${rest:+ }$rest" >&$fd
        done <"$TODO" >"$TODO.new" 3>>"$DONE" &&
        mv -f "$TODO".new "$TODO" &&
        case "$(peek_next_command)" in
@@@ -686,12 -649,12 +686,12 @@@ rearrange_squash () 
                case " $used" in
                *" $sha1 "*) continue ;;
                esac
 -              echo "$pick $sha1 $message"
 +              printf '%s\n' "$pick $sha1 $message"
                while read -r squash action msg
                do
                        case "$message" in
                        "$msg"*)
 -                              echo "$action $squash $action! $msg"
 +                              printf '%s\n' "$action $squash $action! $msg"
                                used="$used$squash "
                                ;;
                        esac
@@@ -832,9 -795,6 +832,9 @@@ first and then run 'git rebase --contin
        --autosquash)
                AUTOSQUASH=t
                ;;
 +      --no-autosquash)
 +              AUTOSQUASH=
 +              ;;
        --onto)
                shift
                ONTO=$(parse_onto "$1") ||
                do
                        if test t != "$PRESERVE_MERGES"
                        then
 -                              echo "pick $shortsha1 $rest" >> "$TODO"
 +                              printf '%s\n' "pick $shortsha1 $rest" >> "$TODO"
                        else
                                sha1=$(git rev-parse $shortsha1)
                                if test -z "$REBASE_ROOT"
                                if test f = "$preserve"
                                then
                                        touch "$REWRITTEN"/$sha1
 -                                      echo "pick $shortsha1 $rest" >> "$TODO"
 +                                      printf '%s\n' "pick $shortsha1 $rest" >> "$TODO"
                                fi
                        fi
                done
  #  e, edit = use commit, but stop for amending
  #  s, squash = use commit, but meld into previous commit
  #  f, fixup = like "squash", but discard this commit's log message
 +#  x <cmd>, exec <cmd> = Run a shell command <cmd>, and stop if it fails
  #
  # If you remove a line here THAT COMMIT WILL BE LOST.
  # However, if you remove everything, the rebase will be aborted.