If git-rebase--interactive fails to apply the changes introduced by a commit due to conflicts, it interrupts the rebase process and gives the user a shell to resolve the conflicts manually. The process is resumed when the user executes `git rebase --continue`. If the index has changes, the script assumes that those are to be committed under the authorship and with the log message of the commit it tried to replay last. However, that assumption is most likely incorrect if the user has already committed the resolved changes herself. To prevent committing unrelated changes under the wrong authorship and with the wrong log message, at least check that HEAD is still at the same commit by tracking the hash of the last replayed commit. A similar check already happens before `git rebase --continue` amends the previous commit after an `edit` or a conflicted `squash` command. Signed-off-by: Fabian Ruch <bafain@xxxxxxxxx> --- git-rebase--interactive.sh | 35 +++++++++++++++++++++-------------- t/t3404-rebase-interactive.sh | 12 ++++++++++++ 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 8fbfe6d..51ee80c 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -62,13 +62,18 @@ msgnum="$state_dir"/msgnum # being rebased. author_script="$state_dir"/author-script -# When an "edit" rebase command is being processed, the SHA1 of the -# commit to be edited is recorded in this file. The same happens when -# rewriting a root 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 -# command is processed, this file is deleted. +# This file keeps track of the SHA1 of the last replayed commit, the +# new parent of the next commit being replayed. It is used to make +# sure that "git rebase --continue" only commits resolved conflicts +# or "edit" changes automatically. +last_head="$state_dir"/last_head + +# When an "edit" or a "squash" rebase command is being processed, the +# file 'amend' is created. 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 or the squash commit. When any other rebase command is +# processed, these files are deleted. amend="$state_dir"/amend # For the post-rewrite hook, we make a list of rewritten commits and @@ -179,7 +184,8 @@ die_with_patch () { exit_with_patch () { echo "$1" > "$state_dir"/stopped-sha make_patch $1 - git rev-parse --verify HEAD > "$amend" + >"$amend" + git rev-parse --verify HEAD >"$last_head" gpg_sign_opt_quoted=${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} warn "You can amend the commit now, with" warn @@ -535,7 +541,7 @@ do_pick () { fi rewrite=y rewrite_amend=y - git rev-parse --verify HEAD >"$amend" + >"$amend" ;; -F|--file) if test $# -eq 0 @@ -572,7 +578,7 @@ do_pick () { then rewrite=y rewrite_amend=y - git rev-parse --verify HEAD >"$amend" + >"$amend" # Set the correct commit message and author info on the # sentinel root before cherry-picking the original changes @@ -734,6 +740,7 @@ do_replay () { do_next () { rm -f "$msg" "$author_script" "$amend" || exit + git rev-parse --verify HEAD >"$last_head" || exit read -r command args <"$todo" case "$command" in @@ -1031,13 +1038,13 @@ In both case, once you're done, continue with: git rebase --continue " fi - if test -f "$amend" - then - current_head=$(git rev-parse --verify HEAD) - test "$current_head" = $(cat "$amend") || + current_head=$(git rev-parse --verify HEAD) + test "$current_head" = $(cat "$last_head") || die "\ You have uncommitted changes in your working tree. Please, commit them first and then run 'git rebase --continue' again." + if test -f "$amend" + then git commit --amend --no-verify -F "$msg" -e \ ${gpg_sign_opt:+"$gpg_sign_opt"} || die "Could not commit staged changes." diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index c037a07..5955bd8 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -444,6 +444,18 @@ test_expect_success '--continue tries to commit' ' git show HEAD | grep chouette ' +test_expect_success '--continue does not commit after head is moved' ' + git reset --hard to-be-rebased@{1} && + test_must_fail git rebase -i --onto new-branch1 HEAD^ && + echo resolved >file1 && + git add file1 && + git commit && + echo dirty >file1 && + test_must_fail git rebase --continue && + git checkout file1 && + git rebase --continue +' + test_expect_success 'verbose flag is heeded, even after --continue' ' git reset --hard master@{1} && test_tick && -- 2.0.1 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html