Merge branch 'nd/rebase-show-current-patch' into next
authorJunio C Hamano <gitster@pobox.com>
Tue, 27 Feb 2018 19:15:10 +0000 (11:15 -0800)
committerJunio C Hamano <gitster@pobox.com>
Tue, 27 Feb 2018 19:15:10 +0000 (11:15 -0800)
The new "--show-current-patch" option gives an end-user facing way
to get the diff being applied when "git rebase" (and "git am")
stops with a conflict.

* nd/rebase-show-current-patch:
rebase: introduce and use pseudo-ref REBASE_HEAD
rebase: add --show-current-patch
am: add --show-current-patch

1  2 
Documentation/git-am.txt
Documentation/git-rebase.txt
builtin/am.c
contrib/completion/git-completion.bash
git-rebase--am.sh
git-rebase--interactive.sh
git-rebase--merge.sh
git-rebase.sh
sequencer.c
t/t3404-rebase-interactive.sh
t/t4150-am.sh
diff --combined Documentation/git-am.txt
index 460662e4b92b56c25989c9d1770165ea9a6a16a2,0f426ae8749c31efc98af8d155a60358705d4c3a..6f6c34b0f4bc9ba18ec890dff1a6fe10af2fd68f
@@@ -16,7 -16,7 +16,7 @@@ SYNOPSI
         [--exclude=<path>] [--include=<path>] [--reject] [-q | --quiet]
         [--[no-]scissors] [-S[<keyid>]] [--patch-format=<format>]
         [(<mbox> | <Maildir>)...]
- 'git am' (--continue | --skip | --abort | --quit)
 -'git am' (--continue | --skip | --abort | --show-current-patch)
++'git am' (--continue | --skip | --abort | --quit | --show-current-patch)
  
  DESCRIPTION
  -----------
@@@ -167,10 -167,10 +167,14 @@@ default.   You can use `--no-utf8` to o
  --abort::
        Restore the original branch and abort the patching operation.
  
 +--quit::
 +      Abort the patching operation but keep HEAD and the index
 +      untouched.
 +
+ --show-current-patch::
+       Show the patch being applied when "git am" is stopped because
+       of conflicts.
  DISCUSSION
  ----------
  
index d713951b86abaa3fbea48703f87cce5cf0330019,0b29e48221696ac41641bccd12c215a2a332a597..3277ca143273e01f5f4973ed351c8a5cb4b8e0fa
@@@ -12,7 -12,7 +12,7 @@@ SYNOPSI
        [<upstream> [<branch>]]
  'git rebase' [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>]
        --root [<branch>]
- 'git rebase' --continue | --skip | --abort | --quit | --edit-todo
+ 'git rebase' --continue | --skip | --abort | --quit | --edit-todo | --show-current-patch
  
  DESCRIPTION
  -----------
@@@ -244,17 -244,17 +244,22 @@@ leave out at most one of A and B, in wh
        Keep the commits that do not change anything from its
        parents in the result.
  
 +--allow-empty-message::
 +      By default, rebasing commits with an empty message will fail.
 +      This option overrides that behavior, allowing commits with empty
 +      messages to be rebased.
 +
  --skip::
        Restart the rebasing process by skipping the current patch.
  
  --edit-todo::
        Edit the todo list during an interactive rebase.
  
+ --show-current-patch::
+       Show the current patch in an interactive rebase or when rebase
+       is stopped because of conflicts. This is the equivalent of
+       `git show REBASE_HEAD`.
  -m::
  --merge::
        Use merging strategies to rebase.  When the recursive (default) merge
diff --combined builtin/am.c
index 05a82f4aa5be6ba82d409f002dce7786734780a1,21aedec41f0aa742af2b611fe059a59ff1c21621..1151b5c73aec81dbfca36a799cd4049429c75973
@@@ -1011,6 -1011,7 +1011,7 @@@ static void am_setup(struct am_state *s
  
        if (mkdir(state->dir, 0777) < 0 && errno != EEXIST)
                die_errno(_("failed to create directory '%s'"), state->dir);
+       delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
  
        if (split_mail(state, patch_format, paths, keep_cr) < 0) {
                am_destroy(state);
        }
        write_state_text(state, "scissors", str);
  
 -      sq_quote_argv(&sb, state->git_apply_opts.argv, 0);
 +      sq_quote_argv(&sb, state->git_apply_opts.argv);
        write_state_text(state, "apply-opt", sb.buf);
  
        if (state->rebasing)
@@@ -1110,6 -1111,7 +1111,7 @@@ static void am_next(struct am_state *st
  
        oidclr(&state->orig_commit);
        unlink(am_path(state, "original-commit"));
+       delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
  
        if (!get_oid("HEAD", &head))
                write_state_text(state, "abort-safety", oid_to_hex(&head));
@@@ -1441,6 -1443,8 +1443,8 @@@ static int parse_mail_rebase(struct am_
  
        oidcpy(&state->orig_commit, &commit_oid);
        write_state_text(state, "original-commit", oid_to_hex(&commit_oid));
+       update_ref("am", "REBASE_HEAD", &commit_oid,
+                  NULL, REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR);
  
        return 0;
  }
@@@ -1641,8 -1645,8 +1645,8 @@@ static void do_commit(const struct am_s
                setenv("GIT_COMMITTER_DATE",
                        state->ignore_date ? "" : state->author_date, 1);
  
 -      if (commit_tree(state->msg, state->msg_len, tree.hash, parents, commit.hash,
 -                              author, state->sign_commit))
 +      if (commit_tree(state->msg, state->msg_len, &tree, parents, &commit,
 +                      author, state->sign_commit))
                die(_("failed to write commit object"));
  
        reflog_msg = getenv("GIT_REFLOG_ACTION");
@@@ -1831,8 -1835,7 +1835,7 @@@ static void am_run(struct am_state *sta
                        git_config_get_bool("advice.amworkdir", &advice_amworkdir);
  
                        if (advice_amworkdir)
-                               printf_ln(_("The copy of the patch that failed is found in: %s"),
-                                               am_path(state, "patch"));
+                               printf_ln(_("Use 'git am --show-current-patch' to see the failed patch"));
  
                        die_user_resolve(state);
                }
@@@ -2121,6 -2124,34 +2124,34 @@@ static void am_abort(struct am_state *s
        am_destroy(state);
  }
  
+ static int show_patch(struct am_state *state)
+ {
+       struct strbuf sb = STRBUF_INIT;
+       const char *patch_path;
+       int len;
+       if (!is_null_oid(&state->orig_commit)) {
+               const char *av[4] = { "show", NULL, "--", NULL };
+               char *new_oid_str;
+               int ret;
+               av[1] = new_oid_str = xstrdup(oid_to_hex(&state->orig_commit));
+               ret = run_command_v_opt(av, RUN_GIT_CMD);
+               free(new_oid_str);
+               return ret;
+       }
+       patch_path = am_path(state, msgnum(state));
+       len = strbuf_read_file(&sb, patch_path, 0);
+       if (len < 0)
+               die_errno(_("failed to read '%s'"), patch_path);
+       setup_pager();
+       write_in_full(1, sb.buf, sb.len);
+       strbuf_release(&sb);
+       return 0;
+ }
  /**
   * parse_options() callback that validates and sets opt->value to the
   * PATCH_FORMAT_* enum value corresponding to `arg`.
@@@ -2150,7 -2181,7 +2181,8 @@@ enum resume_mode 
        RESUME_RESOLVED,
        RESUME_SKIP,
        RESUME_ABORT,
-       RESUME_QUIT
++      RESUME_QUIT,
+       RESUME_SHOW_PATCH
  };
  
  static int git_am_config(const char *k, const char *v, void *cb)
@@@ -2172,6 -2203,7 +2204,7 @@@ int cmd_am(int argc, const char **argv
        int patch_format = PATCH_FORMAT_UNKNOWN;
        enum resume_mode resume = RESUME_FALSE;
        int in_progress;
+       int ret = 0;
  
        const char * const usage[] = {
                N_("git am [<options>] [(<mbox> | <Maildir>)...]"),
                OPT_CMDMODE(0, "abort", &resume,
                        N_("restore the original branch and abort the patching operation."),
                        RESUME_ABORT),
 +              OPT_CMDMODE(0, "quit", &resume,
 +                      N_("abort the patching operation but keep HEAD where it is."),
 +                      RESUME_QUIT),
+               OPT_CMDMODE(0, "show-current-patch", &resume,
+                       N_("show the patch being applied."),
+                       RESUME_SHOW_PATCH),
                OPT_BOOL(0, "committer-date-is-author-date",
                        &state.committer_date_is_author_date,
                        N_("lie about committer date")),
                 * stray directories.
                 */
                if (file_exists(state.dir) && !state.rebasing) {
 -                      if (resume == RESUME_ABORT) {
 +                      if (resume == RESUME_ABORT || resume == RESUME_QUIT) {
                                am_destroy(&state);
                                am_state_release(&state);
                                return 0;
        case RESUME_ABORT:
                am_abort(&state);
                break;
 +      case RESUME_QUIT:
 +              am_rerere_clear();
 +              am_destroy(&state);
 +              break;
+       case RESUME_SHOW_PATCH:
+               ret = show_patch(&state);
+               break;
        default:
                die("BUG: invalid resume value");
        }
  
        am_state_release(&state);
  
-       return 0;
+       return ret;
  }
index 4c86ab66e23ee02e15f15173bc7e613c20347f36,8777805c9fd64f5513462540b20464bfdaf9ca24..91536d831c8954b67efe738ace3fad7f8f2ee2d7
@@@ -439,7 -439,7 +439,7 @@@ __git_refs (
                        track=""
                        ;;
                *)
-                       for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD; do
+                       for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD; do
                                case "$i" in
                                $match*)
                                        if [ -e "$dir/$i" ]; then
@@@ -594,7 -594,7 +594,7 @@@ __git_is_configured_remote (
  
  __git_list_merge_strategies ()
  {
 -      git merge -s help 2>&1 |
 +      LANG=C LC_ALL=C git merge -s help 2>&1 |
        sed -n -e '/[Aa]vailable strategies are: /,/^$/{
                s/\.$//
                s/.*://
@@@ -1077,7 -1077,7 +1077,7 @@@ _git_am (
  {
        __git_find_repo_path
        if [ -d "$__git_repo_path"/rebase-apply ]; then
-               __gitcomp "--skip --continue --resolved --abort --quit"
 -              __gitcomp "--skip --continue --resolved --abort --show-current-patch"
++              __gitcomp "--skip --continue --resolved --abort --quit --show-current-patch"
                return
        fi
        case "$cur" in
@@@ -1468,7 -1468,7 +1468,7 @@@ __git_fetch_recurse_submodules="yes on-
  __git_fetch_options="
        --quiet --verbose --append --upload-pack --force --keep --depth=
        --tags --no-tags --all --prune --dry-run --recurse-submodules=
 -      --unshallow --update-shallow
 +      --unshallow --update-shallow --prune-tags
  "
  
  _git_fetch ()
@@@ -1992,11 -1992,11 +1992,11 @@@ _git_rebase (
  {
        __git_find_repo_path
        if [ -f "$__git_repo_path"/rebase-merge/interactive ]; then
-               __gitcomp "--continue --skip --abort --quit --edit-todo"
+               __gitcomp "--continue --skip --abort --quit --edit-todo --show-current-patch"
                return
        elif [ -d "$__git_repo_path"/rebase-apply ] || \
             [ -d "$__git_repo_path"/rebase-merge ]; then
-               __gitcomp "--continue --skip --abort --quit"
+               __gitcomp "--continue --skip --abort --quit --show-current-patch"
                return
        fi
        __git_complete_strategy && return
diff --combined git-rebase--am.sh
index 0f78051792fae93f7966c2a3f9fc670b4fca9188,c931891cbc45845f3e781b75a3978e327d770696..be3f068922c5a3ba0d1112f3b8b1cf1228567d2e
@@@ -27,6 -27,9 +27,9 @@@ skip
        move_to_original_branch
        return
        ;;
+ show-current-patch)
+       exec git am --show-current-patch
+       ;;
  esac
  
  if test -z "$rebase_root"
@@@ -46,7 -49,6 +49,7 @@@ the
        # makes this easy
        git cherry-pick ${gpg_sign_opt:+"$gpg_sign_opt"} --allow-empty \
                $allow_rerere_autoupdate --right-only "$revisions" \
 +              $allow_empty_message \
                ${restrict_revision+^$restrict_revision}
        ret=$?
  else
index 637bb3ecd5bd25222b725c10619cd3a078fd95b4,a613156bcb65170d617c11f4dfe8a341c006108f..331c8dfeac3cac2fd2d9d9287d5c487669fe80a0
@@@ -199,12 -199,14 +199,14 @@@ make_patch () 
  
  die_with_patch () {
        echo "$1" > "$state_dir"/stopped-sha
+       git update-ref REBASE_HEAD "$1"
        make_patch "$1"
        die "$2"
  }
  
  exit_with_patch () {
        echo "$1" > "$state_dir"/stopped-sha
+       git update-ref REBASE_HEAD "$1"
        make_patch $1
        git rev-parse --verify HEAD > "$amend"
        gpg_sign_opt_quoted=${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")}
@@@ -281,7 -283,7 +283,7 @@@ pick_one () 
  
        test -d "$rewritten" &&
                pick_one_preserving_merges "$@" && return
 -      output eval git cherry-pick $allow_rerere_autoupdate \
 +      output eval git cherry-pick $allow_rerere_autoupdate $allow_empty_message \
                        ${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \
                        "$strategy_args" $empty_args $ff "$@"
  
@@@ -396,7 -398,7 +398,7 @@@ pick_one_preserving_merges () 
                                        --sq-quote "$gpg_sign_opt")} \
                                $allow_rerere_autoupdate "$merge_args" \
                                "$strategy_args" \
 -                              -m $(git rev-parse --sq-quote "$msg_content") \
 +                              -m "$(git rev-parse --sq-quote "$msg_content")" \
                                "$new_parents"
                        then
                                printf "%s\n" "$msg_content" > "$GIT_DIR"/MERGE_MSG
                        ;;
                *)
                        output eval git cherry-pick $allow_rerere_autoupdate \
 +                              $allow_empty_message \
                                ${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \
                                "$strategy_args" "$@" ||
                                die_with_patch $sha1 "$(eval_gettext "Could not pick \$sha1")"
@@@ -560,8 -561,7 +562,8 @@@ do_next () 
  
                mark_action_done
                do_pick $sha1 "$rest"
 -              git commit --amend --no-post-rewrite ${gpg_sign_opt:+"$gpg_sign_opt"} || {
 +              git commit --amend --no-post-rewrite ${gpg_sign_opt:+"$gpg_sign_opt"} \
 +                      $allow_empty_message || {
                        warn "$(eval_gettext "\
  Could not amend commit after successfully picking \$sha1... \$rest
  This is most likely due to an empty commit message, or the pre-commit hook
@@@ -609,7 -609,7 +611,7 @@@ you are able to reword the commit.")
                        # This is an intermediate commit; its message will only be
                        # used in case of trouble.  So use the long version:
                        do_with_author output git commit --amend --no-verify -F "$squash_msg" \
 -                              ${gpg_sign_opt:+"$gpg_sign_opt"} ||
 +                              ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message ||
                                die_failed_squash $sha1 "$rest"
                        ;;
                *)
                        if test -f "$fixup_msg"
                        then
                                do_with_author git commit --amend --no-verify -F "$fixup_msg" \
 -                                      ${gpg_sign_opt:+"$gpg_sign_opt"} ||
 +                                      ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message ||
                                        die_failed_squash $sha1 "$rest"
                        else
                                cp "$squash_msg" "$GIT_DIR"/SQUASH_MSG || exit
                                rm -f "$GIT_DIR"/MERGE_MSG
                                do_with_author git commit --amend --no-verify -F "$GIT_DIR"/SQUASH_MSG -e \
 -                                      ${gpg_sign_opt:+"$gpg_sign_opt"} ||
 +                                      ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message ||
                                        die_failed_squash $sha1 "$rest"
                        fi
                        rm -f "$squash_msg" "$fixup_msg"
@@@ -756,8 -756,7 +758,8 @@@ case "$action" i
  continue)
        if test ! -d "$rewritten"
        then
 -              exec git rebase--helper ${force_rebase:+--no-ff} --continue
 +              exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
 +                      --continue
        fi
        # do we have anything to commit?
        if git diff-index --cached --quiet HEAD --
@@@ -797,11 -796,11 +799,11 @@@ In both cases, once you're done, contin
  You have uncommitted changes in your working tree. Please commit them
  first and then run 'git rebase --continue' again.")"
                        do_with_author git commit --amend --no-verify -F "$msg" -e \
 -                              ${gpg_sign_opt:+"$gpg_sign_opt"} ||
 +                              ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message ||
                                die "$(gettext "Could not commit staged changes.")"
                else
                        do_with_author git commit --no-verify -F "$msg" -e \
 -                              ${gpg_sign_opt:+"$gpg_sign_opt"} ||
 +                              ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message ||
                                die "$(gettext "Could not commit staged changes.")"
                fi
        fi
@@@ -820,8 -819,7 +822,8 @@@ skip
  
        if test ! -d "$rewritten"
        then
 -              exec git rebase--helper ${force_rebase:+--no-ff} --continue
 +              exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
 +                      --continue
        fi
        do_rest
        return 0
@@@ -844,6 -842,9 +846,9 @@@ To continue rebase after editing, run
  
        exit
        ;;
+ show-current-patch)
+       exec git show REBASE_HEAD --
+       ;;
  esac
  
  comment_for_reflog start
@@@ -859,6 -860,7 +864,7 @@@ f
  
  orig_head=$(git rev-parse --verify HEAD) || die "$(gettext "No HEAD?")"
  mkdir -p "$state_dir" || die "$(eval_gettext "Could not create temporary \$state_dir")"
+ rm -f "$(git rev-parse --git-path REBASE_HEAD)"
  
  : > "$state_dir"/interactive || die "$(gettext "Could not mark as interactive")"
  write_basic_state
@@@ -1020,8 -1022,7 +1026,8 @@@ checkout_ont
  if test -z "$rebase_root" && test ! -d "$rewritten"
  then
        require_clean_work_tree "rebase"
 -      exec git rebase--helper ${force_rebase:+--no-ff} --continue
 +      exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
 +              --continue
  fi
  do_rest
  
diff --combined git-rebase--merge.sh
index 1831e589b8c94b3fbcee710c5742b71a3e7e8f9e,957688f236a6bc06622912ccbe48bd06ae3bc5df..ceb715453cc9eba0b6e91abfd2ea3863e74f3e05
@@@ -27,8 -27,7 +27,8 @@@ continue_merge () 
        cmt=$(cat "$state_dir/current")
        if ! git diff-index --quiet --ignore-submodules HEAD --
        then
 -              if ! git commit ${gpg_sign_opt:+"$gpg_sign_opt"} --no-verify -C "$cmt"
 +              if ! git commit ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message \
 +                      --no-verify -C "$cmt"
                then
                        echo "Commit failed, please do not call \"git commit\""
                        echo "directly, but instead do one of the following: "
@@@ -58,6 -57,7 +58,7 @@@ call_merge () 
        echo "$msgnum" >"$state_dir/msgnum"
        cmt="$(cat "$state_dir/cmt.$msgnum")"
        echo "$cmt" > "$state_dir/current"
+       git update-ref REBASE_HEAD "$cmt"
        hd=$(git rev-parse --verify HEAD)
        cmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD)
        eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"'
@@@ -138,11 -138,15 +139,15 @@@ skip
        finish_rb_merge
        return
        ;;
+ show-current-patch)
+       exec git show REBASE_HEAD --
+       ;;
  esac
  
  mkdir -p "$state_dir"
  echo "$onto_name" > "$state_dir/onto_name"
  write_basic_state
+ rm -f "$(git rev-parse --git-path REBASE_HEAD)"
  
  msgnum=0
  for cmt in $(git rev-list --reverse --no-merges "$revisions")
diff --combined git-rebase.sh
index b353c33d417a913c2b356b3c070b1dbbc033f162,a13a581fe65438dcada8ff05226a808b71fed2ad..a1f6e5de6a3ed1fe9a6217a136611682f3db6582
@@@ -24,7 -24,6 +24,7 @@@ m,merge!           use merging strategi
  i,interactive!     let the user edit the list of commits to rebase
  x,exec=!           add exec lines after each commit of the editable list
  k,keep-empty     preserve empty commits during rebase
 +allow-empty-message allow rebasing commits with empty messages
  f,force-rebase!    force rebase even if branch is up to date
  X,strategy-option=! pass the argument through to the merge strategy
  stat!              display a diffstat of what changed upstream
@@@ -46,6 -45,7 +46,7 @@@ abort!             abort and check out 
  skip!              skip current patch and continue
  edit-todo!         edit the todo list during an interactive rebase
  quit!              abort but keep HEAD where it is
+ show-current-patch! show the patch file being applied or merged
  "
  . git-sh-setup
  set_reflog_action rebase
@@@ -90,7 -90,6 +91,7 @@@ action
  preserve_merges=
  autosquash=
  keep_empty=
 +allow_empty_message=
  test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
  case "$(git config --bool commit.gpgsign)" in
  true) gpg_sign_opt=-S ;;
@@@ -183,6 -182,7 +184,7 @@@ You can run "git stash pop" or "git sta
  }
  
  finish_rebase () {
+       rm -f "$(git rev-parse --git-path REBASE_HEAD)"
        apply_autostash &&
        { git gc --auto || true; } &&
        rm -rf "$state_dir"
@@@ -247,7 -247,7 +249,7 @@@ d
        --verify)
                ok_to_skip_pre_rebase=
                ;;
-       --continue|--skip|--abort|--quit|--edit-todo)
+       --continue|--skip|--abort|--quit|--edit-todo|--show-current-patch)
                test $total_argc -eq 2 || usage
                action=${1##--}
                ;;
        --keep-empty)
                keep_empty=yes
                ;;
 +      --allow-empty-message)
 +              allow_empty_message=--allow-empty-message
 +              ;;
        --preserve-merges)
                preserve_merges=t
                test -z "$interactive_rebase" && interactive_rebase=implied
@@@ -417,6 -414,10 +419,10 @@@ quit
  edit-todo)
        run_specific_rebase
        ;;
+ show-current-patch)
+       run_specific_rebase
+       die "BUG: run_specific_rebase is not supposed to return here"
+       ;;
  esac
  
  # Make sure no rebase is in progress
diff --combined sequencer.c
index e9baaf59bd954279970367631c930fe051712cda,f69222199929399b37ce240e464282bb5e330b6c..c24ecdb21fdaac2dd70a127b761e536f1eef196f
@@@ -1,10 -1,10 +1,10 @@@
  #include "cache.h"
  #include "config.h"
  #include "lockfile.h"
 -#include "sequencer.h"
  #include "dir.h"
  #include "object.h"
  #include "commit.h"
 +#include "sequencer.h"
  #include "tag.h"
  #include "run-command.h"
  #include "exec_cmd.h"
  #include "log-tree.h"
  #include "wt-status.h"
  #include "hashmap.h"
 +#include "notes-utils.h"
 +#include "sigchain.h"
  
  #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
  
  const char sign_off_header[] = "Signed-off-by: ";
  static const char cherry_picked_prefix[] = "(cherry picked from commit ";
  
 +GIT_PATH_FUNC(git_path_commit_editmsg, "COMMIT_EDITMSG")
 +
  GIT_PATH_FUNC(git_path_seq_dir, "sequencer")
  
  static GIT_PATH_FUNC(git_path_todo_file, "sequencer/todo")
@@@ -134,51 -130,6 +134,51 @@@ static GIT_PATH_FUNC(rebase_path_strate
  static GIT_PATH_FUNC(rebase_path_strategy_opts, "rebase-merge/strategy_opts")
  static GIT_PATH_FUNC(rebase_path_allow_rerere_autoupdate, "rebase-merge/allow_rerere_autoupdate")
  
 +static int git_sequencer_config(const char *k, const char *v, void *cb)
 +{
 +      struct replay_opts *opts = cb;
 +      int status;
 +
 +      if (!strcmp(k, "commit.cleanup")) {
 +              const char *s;
 +
 +              status = git_config_string(&s, k, v);
 +              if (status)
 +                      return status;
 +
 +              if (!strcmp(s, "verbatim"))
 +                      opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_NONE;
 +              else if (!strcmp(s, "whitespace"))
 +                      opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SPACE;
 +              else if (!strcmp(s, "strip"))
 +                      opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_ALL;
 +              else if (!strcmp(s, "scissors"))
 +                      opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SPACE;
 +              else
 +                      warning(_("invalid commit message cleanup mode '%s'"),
 +                                s);
 +
 +              return status;
 +      }
 +
 +      if (!strcmp(k, "commit.gpgsign")) {
 +              opts->gpg_sign = git_config_bool(k, v) ? xstrdup("") : NULL;
 +              return 0;
 +      }
 +
 +      status = git_gpg_config(k, v, NULL);
 +      if (status)
 +              return status;
 +
 +      return git_diff_basic_config(k, v, NULL);
 +}
 +
 +void sequencer_init_config(struct replay_opts *opts)
 +{
 +      opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_NONE;
 +      git_config(git_sequencer_config, opts);
 +}
 +
  static inline int is_rebase_i(const struct replay_opts *opts)
  {
        return opts->action == REPLAY_INTERACTIVE_REBASE;
@@@ -527,6 -478,9 +527,6 @@@ static int do_recursive_merge(struct co
                        _(action_name(opts)));
        rollback_lock_file(&index_lock);
  
 -      if (opts->signoff)
 -              append_signoff(msgbuf, 0, 0);
 -
        if (!clean)
                append_conflicts_hint(msgbuf);
  
@@@ -642,18 -596,6 +642,18 @@@ static int read_env_script(struct argv_
        return 0;
  }
  
 +static char *get_author(const char *message)
 +{
 +      size_t len;
 +      const char *a;
 +
 +      a = find_commit_header(message, "author", &len);
 +      if (a)
 +              return xmemdupz(a, len);
 +
 +      return NULL;
 +}
 +
  static const char staged_changes_advice[] =
  N_("you have staged changes in your working tree\n"
  "If these changes are meant to be squashed into the previous commit, run:\n"
@@@ -716,6 -658,8 +716,6 @@@ static int run_git_commit(const char *d
                argv_array_push(&cmd.args, "--amend");
        if (opts->gpg_sign)
                argv_array_pushf(&cmd.args, "-S%s", opts->gpg_sign);
 -      if (opts->signoff)
 -              argv_array_push(&cmd.args, "-s");
        if (defmsg)
                argv_array_pushl(&cmd.args, "-F", defmsg, NULL);
        if ((flags & CLEANUP_MSG))
        return run_command(&cmd);
  }
  
 +static int rest_is_empty(const struct strbuf *sb, int start)
 +{
 +      int i, eol;
 +      const char *nl;
 +
 +      /* Check if the rest is just whitespace and Signed-off-by's. */
 +      for (i = start; i < sb->len; i++) {
 +              nl = memchr(sb->buf + i, '\n', sb->len - i);
 +              if (nl)
 +                      eol = nl - sb->buf;
 +              else
 +                      eol = sb->len;
 +
 +              if (strlen(sign_off_header) <= eol - i &&
 +                  starts_with(sb->buf + i, sign_off_header)) {
 +                      i = eol;
 +                      continue;
 +              }
 +              while (i < eol)
 +                      if (!isspace(sb->buf[i++]))
 +                              return 0;
 +      }
 +
 +      return 1;
 +}
 +
 +/*
 + * Find out if the message in the strbuf contains only whitespace and
 + * Signed-off-by lines.
 + */
 +int message_is_empty(const struct strbuf *sb,
 +                   enum commit_msg_cleanup_mode cleanup_mode)
 +{
 +      if (cleanup_mode == COMMIT_MSG_CLEANUP_NONE && sb->len)
 +              return 0;
 +      return rest_is_empty(sb, 0);
 +}
 +
 +/*
 + * See if the user edited the message in the editor or left what
 + * was in the template intact
 + */
 +int template_untouched(const struct strbuf *sb, const char *template_file,
 +                     enum commit_msg_cleanup_mode cleanup_mode)
 +{
 +      struct strbuf tmpl = STRBUF_INIT;
 +      const char *start;
 +
 +      if (cleanup_mode == COMMIT_MSG_CLEANUP_NONE && sb->len)
 +              return 0;
 +
 +      if (!template_file || strbuf_read_file(&tmpl, template_file, 0) <= 0)
 +              return 0;
 +
 +      strbuf_stripspace(&tmpl, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
 +      if (!skip_prefix(sb->buf, tmpl.buf, &start))
 +              start = sb->buf;
 +      strbuf_release(&tmpl);
 +      return rest_is_empty(sb, start - sb->buf);
 +}
 +
 +int update_head_with_reflog(const struct commit *old_head,
 +                          const struct object_id *new_head,
 +                          const char *action, const struct strbuf *msg,
 +                          struct strbuf *err)
 +{
 +      struct ref_transaction *transaction;
 +      struct strbuf sb = STRBUF_INIT;
 +      const char *nl;
 +      int ret = 0;
 +
 +      if (action) {
 +              strbuf_addstr(&sb, action);
 +              strbuf_addstr(&sb, ": ");
 +      }
 +
 +      nl = strchr(msg->buf, '\n');
 +      if (nl) {
 +              strbuf_add(&sb, msg->buf, nl + 1 - msg->buf);
 +      } else {
 +              strbuf_addbuf(&sb, msg);
 +              strbuf_addch(&sb, '\n');
 +      }
 +
 +      transaction = ref_transaction_begin(err);
 +      if (!transaction ||
 +          ref_transaction_update(transaction, "HEAD", new_head,
 +                                 old_head ? &old_head->object.oid : &null_oid,
 +                                 0, sb.buf, err) ||
 +          ref_transaction_commit(transaction, err)) {
 +              ret = -1;
 +      }
 +      ref_transaction_free(transaction);
 +      strbuf_release(&sb);
 +
 +      return ret;
 +}
 +
 +static int run_rewrite_hook(const struct object_id *oldoid,
 +                          const struct object_id *newoid)
 +{
 +      struct child_process proc = CHILD_PROCESS_INIT;
 +      const char *argv[3];
 +      int code;
 +      struct strbuf sb = STRBUF_INIT;
 +
 +      argv[0] = find_hook("post-rewrite");
 +      if (!argv[0])
 +              return 0;
 +
 +      argv[1] = "amend";
 +      argv[2] = NULL;
 +
 +      proc.argv = argv;
 +      proc.in = -1;
 +      proc.stdout_to_stderr = 1;
 +
 +      code = start_command(&proc);
 +      if (code)
 +              return code;
 +      strbuf_addf(&sb, "%s %s\n", oid_to_hex(oldoid), oid_to_hex(newoid));
 +      sigchain_push(SIGPIPE, SIG_IGN);
 +      write_in_full(proc.in, sb.buf, sb.len);
 +      close(proc.in);
 +      strbuf_release(&sb);
 +      sigchain_pop(SIGPIPE);
 +      return finish_command(&proc);
 +}
 +
 +void commit_post_rewrite(const struct commit *old_head,
 +                       const struct object_id *new_head)
 +{
 +      struct notes_rewrite_cfg *cfg;
 +
 +      cfg = init_copy_notes_for_rewrite("amend");
 +      if (cfg) {
 +              /* we are amending, so old_head is not NULL */
 +              copy_note_for_rewrite(cfg, &old_head->object.oid, new_head);
 +              finish_copy_notes_for_rewrite(cfg, "Notes added by 'git commit --amend'");
 +      }
 +      run_rewrite_hook(&old_head->object.oid, new_head);
 +}
 +
 +static int run_prepare_commit_msg_hook(struct strbuf *msg, const char *commit)
 +{
 +      struct argv_array hook_env = ARGV_ARRAY_INIT;
 +      int ret;
 +      const char *name;
 +
 +      name = git_path_commit_editmsg();
 +      if (write_message(msg->buf, msg->len, name, 0))
 +              return -1;
 +
 +      argv_array_pushf(&hook_env, "GIT_INDEX_FILE=%s", get_index_file());
 +      argv_array_push(&hook_env, "GIT_EDITOR=:");
 +      if (commit)
 +              ret = run_hook_le(hook_env.argv, "prepare-commit-msg", name,
 +                                "commit", commit, NULL);
 +      else
 +              ret = run_hook_le(hook_env.argv, "prepare-commit-msg", name,
 +                                "message", NULL);
 +      if (ret)
 +              ret = error(_("'prepare-commit-msg' hook failed"));
 +      argv_array_clear(&hook_env);
 +
 +      return ret;
 +}
 +
 +static const char implicit_ident_advice_noconfig[] =
 +N_("Your name and email address were configured automatically based\n"
 +"on your username and hostname. Please check that they are accurate.\n"
 +"You can suppress this message by setting them explicitly. Run the\n"
 +"following command and follow the instructions in your editor to edit\n"
 +"your configuration file:\n"
 +"\n"
 +"    git config --global --edit\n"
 +"\n"
 +"After doing this, you may fix the identity used for this commit with:\n"
 +"\n"
 +"    git commit --amend --reset-author\n");
 +
 +static const char implicit_ident_advice_config[] =
 +N_("Your name and email address were configured automatically based\n"
 +"on your username and hostname. Please check that they are accurate.\n"
 +"You can suppress this message by setting them explicitly:\n"
 +"\n"
 +"    git config --global user.name \"Your Name\"\n"
 +"    git config --global user.email you@example.com\n"
 +"\n"
 +"After doing this, you may fix the identity used for this commit with:\n"
 +"\n"
 +"    git commit --amend --reset-author\n");
 +
 +static const char *implicit_ident_advice(void)
 +{
 +      char *user_config = expand_user_path("~/.gitconfig", 0);
 +      char *xdg_config = xdg_config_home("config");
 +      int config_exists = file_exists(user_config) || file_exists(xdg_config);
 +
 +      free(user_config);
 +      free(xdg_config);
 +
 +      if (config_exists)
 +              return _(implicit_ident_advice_config);
 +      else
 +              return _(implicit_ident_advice_noconfig);
 +
 +}
 +
 +void print_commit_summary(const char *prefix, const struct object_id *oid,
 +                        unsigned int flags)
 +{
 +      struct rev_info rev;
 +      struct commit *commit;
 +      struct strbuf format = STRBUF_INIT;
 +      const char *head;
 +      struct pretty_print_context pctx = {0};
 +      struct strbuf author_ident = STRBUF_INIT;
 +      struct strbuf committer_ident = STRBUF_INIT;
 +
 +      commit = lookup_commit(oid);
 +      if (!commit)
 +              die(_("couldn't look up newly created commit"));
 +      if (parse_commit(commit))
 +              die(_("could not parse newly created commit"));
 +
 +      strbuf_addstr(&format, "format:%h] %s");
 +
 +      format_commit_message(commit, "%an <%ae>", &author_ident, &pctx);
 +      format_commit_message(commit, "%cn <%ce>", &committer_ident, &pctx);
 +      if (strbuf_cmp(&author_ident, &committer_ident)) {
 +              strbuf_addstr(&format, "\n Author: ");
 +              strbuf_addbuf_percentquote(&format, &author_ident);
 +      }
 +      if (flags & SUMMARY_SHOW_AUTHOR_DATE) {
 +              struct strbuf date = STRBUF_INIT;
 +
 +              format_commit_message(commit, "%ad", &date, &pctx);
 +              strbuf_addstr(&format, "\n Date: ");
 +              strbuf_addbuf_percentquote(&format, &date);
 +              strbuf_release(&date);
 +      }
 +      if (!committer_ident_sufficiently_given()) {
 +              strbuf_addstr(&format, "\n Committer: ");
 +              strbuf_addbuf_percentquote(&format, &committer_ident);
 +              if (advice_implicit_identity) {
 +                      strbuf_addch(&format, '\n');
 +                      strbuf_addstr(&format, implicit_ident_advice());
 +              }
 +      }
 +      strbuf_release(&author_ident);
 +      strbuf_release(&committer_ident);
 +
 +      init_revisions(&rev, prefix);
 +      setup_revisions(0, NULL, &rev, NULL);
 +
 +      rev.diff = 1;
 +      rev.diffopt.output_format =
 +              DIFF_FORMAT_SHORTSTAT | DIFF_FORMAT_SUMMARY;
 +
 +      rev.verbose_header = 1;
 +      rev.show_root_diff = 1;
 +      get_commit_format(format.buf, &rev);
 +      rev.always_show_header = 0;
 +      rev.diffopt.detect_rename = DIFF_DETECT_RENAME;
 +      rev.diffopt.break_opt = 0;
 +      diff_setup_done(&rev.diffopt);
 +
 +      head = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
 +      if (!head)
 +              die_errno(_("unable to resolve HEAD after creating commit"));
 +      if (!strcmp(head, "HEAD"))
 +              head = _("detached HEAD");
 +      else
 +              skip_prefix(head, "refs/heads/", &head);
 +      printf("[%s%s ", head, (flags & SUMMARY_INITIAL_COMMIT) ?
 +                                              _(" (root-commit)") : "");
 +
 +      if (!log_tree_commit(&rev, commit)) {
 +              rev.always_show_header = 1;
 +              rev.use_terminator = 1;
 +              log_tree_commit(&rev, commit);
 +      }
 +
 +      strbuf_release(&format);
 +}
 +
 +static int parse_head(struct commit **head)
 +{
 +      struct commit *current_head;
 +      struct object_id oid;
 +
 +      if (get_oid("HEAD", &oid)) {
 +              current_head = NULL;
 +      } else {
 +              current_head = lookup_commit_reference(&oid);
 +              if (!current_head)
 +                      return error(_("could not parse HEAD"));
 +              if (oidcmp(&oid, &current_head->object.oid)) {
 +                      warning(_("HEAD %s is not a commit!"),
 +                              oid_to_hex(&oid));
 +              }
 +              if (parse_commit(current_head))
 +                      return error(_("could not parse HEAD commit"));
 +      }
 +      *head = current_head;
 +
 +      return 0;
 +}
 +
 +/*
 + * Try to commit without forking 'git commit'. In some cases we need
 + * to run 'git commit' to display an error message
 + *
 + * Returns:
 + *  -1 - error unable to commit
 + *   0 - success
 + *   1 - run 'git commit'
 + */
 +static int try_to_commit(struct strbuf *msg, const char *author,
 +                       struct replay_opts *opts, unsigned int flags,
 +                       struct object_id *oid)
 +{
 +      struct object_id tree;
 +      struct commit *current_head;
 +      struct commit_list *parents = NULL;
 +      struct commit_extra_header *extra = NULL;
 +      struct strbuf err = STRBUF_INIT;
 +      struct strbuf commit_msg = STRBUF_INIT;
 +      char *amend_author = NULL;
 +      const char *hook_commit = NULL;
 +      enum commit_msg_cleanup_mode cleanup;
 +      int res = 0;
 +
 +      if (parse_head(&current_head))
 +              return -1;
 +
 +      if (flags & AMEND_MSG) {
 +              const char *exclude_gpgsig[] = { "gpgsig", NULL };
 +              const char *out_enc = get_commit_output_encoding();
 +              const char *message = logmsg_reencode(current_head, NULL,
 +                                                    out_enc);
 +
 +              if (!msg) {
 +                      const char *orig_message = NULL;
 +
 +                      find_commit_subject(message, &orig_message);
 +                      msg = &commit_msg;
 +                      strbuf_addstr(msg, orig_message);
 +                      hook_commit = "HEAD";
 +              }
 +              author = amend_author = get_author(message);
 +              unuse_commit_buffer(current_head, message);
 +              if (!author) {
 +                      res = error(_("unable to parse commit author"));
 +                      goto out;
 +              }
 +              parents = copy_commit_list(current_head->parents);
 +              extra = read_commit_extra_headers(current_head, exclude_gpgsig);
 +      } else if (current_head) {
 +              commit_list_insert(current_head, &parents);
 +      }
 +
 +      if (write_cache_as_tree(tree.hash, 0, NULL)) {
 +              res = error(_("git write-tree failed to write a tree"));
 +              goto out;
 +      }
 +
 +      if (!(flags & ALLOW_EMPTY) && !oidcmp(current_head ?
 +                                            &current_head->tree->object.oid :
 +                                            &empty_tree_oid, &tree)) {
 +              res = 1; /* run 'git commit' to display error message */
 +              goto out;
 +      }
 +
 +      if (find_hook("prepare-commit-msg")) {
 +              res = run_prepare_commit_msg_hook(msg, hook_commit);
 +              if (res)
 +                      goto out;
 +              if (strbuf_read_file(&commit_msg, git_path_commit_editmsg(),
 +                                   2048) < 0) {
 +                      res = error_errno(_("unable to read commit message "
 +                                            "from '%s'"),
 +                                          git_path_commit_editmsg());
 +                      goto out;
 +              }
 +              msg = &commit_msg;
 +      }
 +
 +      cleanup = (flags & CLEANUP_MSG) ? COMMIT_MSG_CLEANUP_ALL :
 +                                        opts->default_msg_cleanup;
 +
 +      if (cleanup != COMMIT_MSG_CLEANUP_NONE)
 +              strbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL);
 +      if (!opts->allow_empty_message && message_is_empty(msg, cleanup)) {
 +              res = 1; /* run 'git commit' to display error message */
 +              goto out;
 +      }
 +
 +      if (commit_tree_extended(msg->buf, msg->len, &tree, parents,
 +                               oid, author, opts->gpg_sign, extra)) {
 +              res = error(_("failed to write commit object"));
 +              goto out;
 +      }
 +
 +      if (update_head_with_reflog(current_head, oid,
 +                                  getenv("GIT_REFLOG_ACTION"), msg, &err)) {
 +              res = error("%s", err.buf);
 +              goto out;
 +      }
 +
 +      if (flags & AMEND_MSG)
 +              commit_post_rewrite(current_head, oid);
 +
 +out:
 +      free_commit_extra_headers(extra);
 +      strbuf_release(&err);
 +      strbuf_release(&commit_msg);
 +      free(amend_author);
 +
 +      return res;
 +}
 +
 +static int do_commit(const char *msg_file, const char *author,
 +                   struct replay_opts *opts, unsigned int flags)
 +{
 +      int res = 1;
 +
 +      if (!(flags & EDIT_MSG) && !(flags & VERIFY_MSG)) {
 +              struct object_id oid;
 +              struct strbuf sb = STRBUF_INIT;
 +
 +              if (msg_file && strbuf_read_file(&sb, msg_file, 2048) < 0)
 +                      return error_errno(_("unable to read commit message "
 +                                           "from '%s'"),
 +                                         msg_file);
 +
 +              res = try_to_commit(msg_file ? &sb : NULL, author, opts, flags,
 +                                  &oid);
 +              strbuf_release(&sb);
 +              if (!res) {
 +                      unlink(git_path_cherry_pick_head());
 +                      unlink(git_path_merge_msg());
 +                      if (!is_rebase_i(opts))
 +                              print_commit_summary(NULL, &oid,
 +                                              SUMMARY_SHOW_AUTHOR_DATE);
 +                      return res;
 +              }
 +      }
 +      if (res == 1)
 +              return run_git_commit(msg_file, opts, flags);
 +
 +      return res;
 +}
 +
  static int is_original_commit_empty(struct commit *commit)
  {
        const struct object_id *ptree_oid;
@@@ -1463,7 -952,6 +1463,7 @@@ static int do_pick_commit(enum todo_com
        struct object_id head;
        struct commit *base, *next, *parent;
        const char *base_label, *next_label;
 +      char *author = NULL;
        struct commit_message msg = { NULL, NULL, NULL, NULL };
        struct strbuf msgbuf = STRBUF_INIT;
        int res, unborn = 0, allow;
                        strbuf_addstr(&msgbuf, oid_to_hex(&commit->object.oid));
                        strbuf_addstr(&msgbuf, ")\n");
                }
 +              if (!is_fixup(command))
 +                      author = get_author(msg.message);
        }
  
        if (command == TODO_REWORD)
                }
        }
  
 +      if (opts->signoff)
 +              append_signoff(&msgbuf, 0, 0);
 +
        if (is_rebase_i(opts) && write_author_script(msg.message) < 0)
                res = -1;
        else if (!opts->strategy || !strcmp(opts->strategy, "recursive") || command == TODO_REVERT) {
                goto leave;
        } else if (allow)
                flags |= ALLOW_EMPTY;
 -      if (!opts->no_commit)
 +      if (!opts->no_commit) {
  fast_forward_edit:
 -              res = run_git_commit(msg_file, opts, flags);
 +              if (author || command == TODO_REVERT || (flags & AMEND_MSG))
 +                      res = do_commit(msg_file, author, opts, flags);
 +              else
 +                      res = error(_("unable to parse commit author"));
 +      }
  
        if (!res && final_fixup) {
                unlink(rebase_path_fixup_msg());
  
  leave:
        free_message(commit, &msg);
 +      free(author);
        update_abort_safety_file();
  
        return res;
@@@ -2314,6 -1792,9 +2314,9 @@@ static int make_patch(struct commit *co
        p = short_commit_name(commit);
        if (write_message(p, strlen(p), rebase_path_stopped_sha(), 1) < 0)
                return -1;
+       if (update_ref("rebase", "REBASE_HEAD", &commit->object.oid,
+                      NULL, REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
+               res |= error(_("could not update %s"), "REBASE_HEAD");
  
        strbuf_addf(&buf, "%s/patch", get_dir(opts));
        memset(&log_tree_opt, 0, sizeof(log_tree_opt));
@@@ -2565,6 -2046,7 +2568,7 @@@ static int pick_commits(struct todo_lis
                        unlink(rebase_path_author_script());
                        unlink(rebase_path_stopped_sha());
                        unlink(rebase_path_amend());
+                       delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
                }
                if (item->command <= TODO_SQUASH) {
                        if (is_rebase_i(opts))
index ef2887bd852b15a0d1c1e6fb1ea9eff09664f27e,23a54a4c497d9a70f3234fd24ba2403a05dc5f6e..3b905406df79187f70c828f72e9e2dc187f1be57
@@@ -225,6 -225,14 +225,14 @@@ test_expect_success 'stop on conflictin
        test 0 = $(grep -c "^[^#]" < .git/rebase-merge/git-rebase-todo)
  '
  
+ test_expect_success 'show conflicted patch' '
+       GIT_TRACE=1 git rebase --show-current-patch >/dev/null 2>stderr &&
+       grep "show.*REBASE_HEAD" stderr &&
+       # the original stopped-sha1 is abbreviated
+       stopped_sha1="$(git rev-parse $(cat ".git/rebase-merge/stopped-sha"))" &&
+       test "$(git rev-parse REBASE_HEAD)" = "$stopped_sha1"
+ '
  test_expect_success 'abort' '
        git rebase --abort &&
        test $(git rev-parse new-branch1) = $(git rev-parse HEAD) &&
@@@ -453,10 -461,6 +461,10 @@@ test_expect_success C_LOCALE_OUTPUT 'sq
                git rebase -i $base &&
        git cat-file commit HEAD | sed -e 1,/^\$/d > actual-squash-fixup &&
        test_cmp expect-squash-fixup actual-squash-fixup &&
 +      git cat-file commit HEAD@{2} |
 +              grep "^# This is a combination of 3 commits\."  &&
 +      git cat-file commit HEAD@{3} |
 +              grep "^# This is a combination of 2 commits\."  &&
        git checkout to-be-rebased &&
        git branch -D squash-fixup
  '
@@@ -1340,16 -1344,6 +1348,16 @@@ test_expect_success 'editor saves as CR
  
  SQ="'"
  test_expect_success 'rebase -i --gpg-sign=<key-id>' '
 +      test_when_finished "test_might_fail git rebase --abort" &&
 +      set_fake_editor &&
 +      FAKE_LINES="edit 1" git rebase -i --gpg-sign="\"S I Gner\"" HEAD^ \
 +              >out 2>err &&
 +      test_i18ngrep "$SQ-S\"S I Gner\"$SQ" err
 +'
 +
 +test_expect_success 'rebase -i --gpg-sign=<key-id> overrides commit.gpgSign' '
 +      test_when_finished "test_might_fail git rebase --abort" &&
 +      test_config commit.gpgsign true &&
        set_fake_editor &&
        FAKE_LINES="edit 1" git rebase -i --gpg-sign="\"S I Gner\"" HEAD^ \
                >out 2>err &&
diff --combined t/t4150-am.sh
index 512c754e02a84ee0beb467d3862b0d677c7aae2c,23abf42abcf1851a7921d034629a55efb319893a..1eccfb71d0c8e26f88708459f065dea622baf9d3
@@@ -662,6 -662,11 +662,11 @@@ test_expect_success 'am pauses on confl
        test -d .git/rebase-apply
  '
  
+ test_expect_success 'am --show-current-patch' '
+       git am --show-current-patch >actual.patch &&
+       test_cmp .git/rebase-apply/0001 actual.patch
+ '
  test_expect_success 'am --skip works' '
        echo goodbye >expected &&
        git am --skip &&
@@@ -1045,16 -1050,4 +1050,16 @@@ test_expect_success 'am works with mult
        git cat-file commit HEAD | grep "^$LONG$"
  '
  
 +test_expect_success 'am --quit keeps HEAD where it is' '
 +      mkdir .git/rebase-apply &&
 +      >.git/rebase-apply/last &&
 +      >.git/rebase-apply/next &&
 +      git rev-parse HEAD^ >.git/ORIG_HEAD &&
 +      git rev-parse HEAD >expected &&
 +      git am --quit &&
 +      test_path_is_missing .git/rebase-apply &&
 +      git rev-parse HEAD >actual &&
 +      test_cmp expected actual
 +'
 +
  test_done