The options passed to `do_pick` determine whether the picked commit
will be rewritten or not. If the commit gets rewritten, because the
user requested to edit the commit message for instance, let
`pick_one` merely apply the changes introduced by the commit and do
not commit the resulting tree yet. If the commit is replayed as is,
leave it to `pick_one` to recreate the commit (possibly by
fast-forwarding the head). This makes it easier to combine git-commit
options like `--edit` and `--amend` in `do_pick` because
git-cherry-pick does not support `--amend`.

In the case of `--edit`, do not `exit_with_patch` but assign
`rewrite` to pick the changes with `-n`. If the pick conflicts, no
commit is created which we would have to amend when continuing the
rebase. To complete the pick after the conflicts are resolved the
user just resumes with `git rebase --continue`.

git-commit lets the user edit the commit log message by default. We
do not want that for the rewriting git-commit command line because
the default behaviour of git-rebase is exactly the opposite. Pass
`--no-edit` when rewriting a picked commit. An explicit `--edit`
passed to `do_pick` (for instance, when reword is executed) enables
the editor launch again. Similarly, pass `--allow-empty-message`
unless the log message is edited.

If `rebase--interactive` is used to rebase a complete branch onto
some head, `rebase` creates a sentinel commit that requires special
treatment by `do_pick`. Do not finalize the pick here either because
its commit message can be altered as for any other pick. Since the
orphaned root commit gets a temporary parent, it is always rewritten.
Safely use the rewrite infrastructure of `do_pick` to create the
final commit.

Signed-off-by: Fabian Ruch <>
--- | 35 ++++++++++++++++++++++-------------
 1 file changed, 22 insertions(+), 13 deletions(-)

diff --git a/ b/
index 71571c8..b8c734e 100644
--- a/
+++ b/
@@ -63,7 +63,8 @@ msgnum="$state_dir"/msgnum
 # When an "edit" rebase command is being processed, the SHA1 of the
-# commit to be edited is recorded in this file.  When "git rebase
+# commit to be edited is recorded in this file.  The same happens when
+# rewriting a commit fails, for instance "reword".  When "git rebase
 # --continue" is executed, if there are any staged changes then they
 # will be amended to the HEAD commit, but only provided the HEAD
 # commit is still the commit to be edited.  When any other rebase
@@ -479,12 +480,17 @@ record_in_rewritten() {
 #     The commit message title of <commit>. Used for information
 #     purposes only.
 do_pick () {
-       edit=
+       allow_empty_message=y
+       rewrite=
+       rewrite_amend=
+       rewrite_edit=
        while test $# -gt 0
                case "$1" in
-                       edit=y
+                       rewrite=y
+                       rewrite_edit=y
+                       allow_empty_message=
                        die "do_pick: unrecognized option -- $1"
@@ -499,6 +505,10 @@ do_pick () {
        if test "$(git rev-parse HEAD)" = "$squash_onto"
+               rewrite=y
+               rewrite_amend=y
+               git rev-parse --verify HEAD >"$amend"
                # Set the correct commit message and author info on the
                # sentinel root before cherry-picking the original changes
                # without committing (-n).  Finally, update the sentinel again
@@ -509,22 +519,21 @@ do_pick () {
                # rebase --continue.
                git commit --allow-empty --allow-empty-message --amend \
                           --no-post-rewrite -n -q -C $1 &&
-                       pick_one -n $1 &&
-                       output git commit --allow-empty --allow-empty-message \
-                                  --amend --no-post-rewrite -n --no-edit \
-                                  ${gpg_sign_opt:+"$gpg_sign_opt"} ||
+                       pick_one -n $1 ||
                        die_with_patch $1 "Could not apply $1... $2"
-               pick_one $1 ||
+               pick_one ${rewrite:+-n} $1 ||
                        die_with_patch $1 "Could not apply $1... $2"
-       if test -n "$edit"
+       if test -n "$rewrite"
-               output git commit --allow-empty --amend --no-post-rewrite 
--no-pre-commit ${gpg_sign_opt:+"$gpg_sign_opt"} || {
-                       warn "Could not amend commit after successfully picking 
$1... $2"
-                       exit_with_patch $1 1
-               }
+               output git commit --allow-empty --no-post-rewrite -n --no-edit \
+                          ${allow_empty_message:+--allow-empty-message} \
+                          ${rewrite_amend:+--amend} \
+                          ${rewrite_edit:+--edit --commit-msg} \
+                          ${gpg_sign_opt:+"$gpg_sign_opt"} ||
+                       die_with_patch $1 "Could not rewrite commit after 
successfully picking $1... $2"

To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to
More majordomo info at

Reply via email to