diff options
Diffstat (limited to 't/t3404-rebase-interactive.sh')
-rwxr-xr-x | t/t3404-rebase-interactive.sh | 1085 |
1 files changed, 723 insertions, 362 deletions
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index 7a440e08d8..b06fc36159 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -12,7 +12,7 @@ Initial setup: one - two - three - four (conflict-branch) / - A - B - C - D - E (master) + A - B - C - D - E (primary) | \ | F - G - H (branch1) | \ @@ -29,10 +29,8 @@ Initial setup: . "$TEST_DIRECTORY"/lib-rebase.sh -# WARNING: Modifications to the initial repository can change the SHA ID used -# in the expect2 file for the 'stop on conflicting pick' test. - test_expect_success 'setup' ' + git switch -C primary && test_commit A file1 && test_commit B file1 && test_commit C file2 && @@ -68,25 +66,28 @@ SHELL= export SHELL test_expect_success 'rebase --keep-empty' ' - git checkout -b emptybranch master && + git checkout -b emptybranch primary && git commit --allow-empty -m "empty" && git rebase --keep-empty -i HEAD~2 && git log --oneline >actual && test_line_count = 6 actual ' -cat > expect <<EOF -error: nothing to do -EOF - -test_expect_success 'rebase -i with empty HEAD' ' - set_fake_editor && - test_must_fail env FAKE_LINES="1 exec_true" git rebase -i HEAD^ >actual 2>&1 && +test_expect_success 'rebase -i with empty todo list' ' + cat >expect <<-\EOF && + error: nothing to do + EOF + ( + set_fake_editor && + test_must_fail env FAKE_LINES="#" \ + git rebase -i HEAD^ >output 2>&1 + ) && + tail -n 1 output >actual && # Ignore output about changing todo list test_i18ncmp expect actual ' test_expect_success 'rebase -i with the exec command' ' - git checkout master && + git checkout primary && ( set_fake_editor && FAKE_LINES="1 exec_>touch-one @@ -103,12 +104,12 @@ test_expect_success 'rebase -i with the exec command' ' test_path_is_file touch-three && test_path_is_file "touch-file name with spaces" && test_path_is_file touch-after-semicolon && - test_cmp_rev master HEAD && + test_cmp_rev primary HEAD && rm -f touch-* ' test_expect_success 'rebase -i with the exec command runs from tree root' ' - git checkout master && + git checkout primary && mkdir subdir && (cd subdir && set_fake_editor && FAKE_LINES="1 exec_>touch-subdir" \ @@ -121,7 +122,7 @@ test_expect_success 'rebase -i with the exec command runs from tree root' ' test_expect_success 'rebase -i with exec allows git commands in subdirs' ' test_when_finished "rm -rf subdir" && test_when_finished "git rebase --abort ||:" && - git checkout master && + git checkout primary && mkdir subdir && (cd subdir && set_fake_editor && FAKE_LINES="1 x_cd_subdir_&&_git_rev-parse_--is-inside-work-tree" \ @@ -139,103 +140,128 @@ test_expect_success 'rebase -i sets work tree properly' ' ' test_expect_success 'rebase -i with the exec command checks tree cleanness' ' - git checkout master && - set_fake_editor && - test_must_fail env FAKE_LINES="exec_echo_foo_>file1 1" git rebase -i HEAD^ && - test_cmp_rev master^ HEAD && + git checkout primary && + ( + set_fake_editor && + test_must_fail env FAKE_LINES="exec_echo_foo_>file1 1" \ + git rebase -i HEAD^ + ) && + test_cmp_rev primary^ HEAD && git reset --hard && git rebase --continue ' +test_expect_success 'rebase -x with empty command fails' ' + test_when_finished "git rebase --abort ||:" && + test_must_fail env git rebase -x "" @ 2>actual && + test_write_lines "error: empty exec command" >expected && + test_i18ncmp expected actual && + test_must_fail env git rebase -x " " @ 2>actual && + test_i18ncmp expected actual +' + +test_expect_success 'rebase -x with newline in command fails' ' + test_when_finished "git rebase --abort ||:" && + test_must_fail env git rebase -x "a${LF}b" @ 2>actual && + test_write_lines "error: exec commands cannot contain newlines" \ + >expected && + test_i18ncmp expected actual +' + test_expect_success 'rebase -i with exec of inexistent command' ' - git checkout master && + git checkout primary && test_when_finished "git rebase --abort" && - set_fake_editor && - test_must_fail env FAKE_LINES="exec_this-command-does-not-exist 1" \ - git rebase -i HEAD^ >actual 2>&1 && + ( + set_fake_editor && + test_must_fail env FAKE_LINES="exec_this-command-does-not-exist 1" \ + git rebase -i HEAD^ >actual 2>&1 + ) && ! grep "Maybe git-rebase is broken" actual ' +test_expect_success 'implicit interactive rebase does not invoke sequence editor' ' + test_when_finished "git rebase --abort ||:" && + GIT_SEQUENCE_EDITOR="echo bad >" git rebase -x"echo one" @^ +' + test_expect_success 'no changes are a nop' ' git checkout branch2 && - set_fake_editor && git rebase -i F && test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch2" && - test $(git rev-parse I) = $(git rev-parse HEAD) + test_cmp_rev I HEAD ' test_expect_success 'test the [branch] option' ' git checkout -b dead-end && git rm file6 && git commit -m "stop here" && - set_fake_editor && git rebase -i F branch2 && test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch2" && - test $(git rev-parse I) = $(git rev-parse branch2) && - test $(git rev-parse I) = $(git rev-parse HEAD) + test_cmp_rev I branch2 && + test_cmp_rev I HEAD ' test_expect_success 'test --onto <branch>' ' git checkout -b test-onto branch2 && - set_fake_editor && git rebase -i --onto branch1 F && test "$(git symbolic-ref -q HEAD)" = "refs/heads/test-onto" && - test $(git rev-parse HEAD^) = $(git rev-parse branch1) && - test $(git rev-parse I) = $(git rev-parse branch2) + test_cmp_rev HEAD^ branch1 && + test_cmp_rev I branch2 ' test_expect_success 'rebase on top of a non-conflicting commit' ' git checkout branch1 && git tag original-branch1 && - set_fake_editor && git rebase -i branch2 && test file6 = $(git diff --name-only original-branch1) && test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch1" && - test $(git rev-parse I) = $(git rev-parse branch2) && - test $(git rev-parse I) = $(git rev-parse HEAD~2) + test_cmp_rev I branch2 && + test_cmp_rev I HEAD~2 ' test_expect_success 'reflog for the branch shows state before rebase' ' - test $(git rev-parse branch1@{1}) = $(git rev-parse original-branch1) + test_cmp_rev branch1@{1} original-branch1 ' test_expect_success 'reflog for the branch shows correct finish message' ' - printf "rebase -i (finish): refs/heads/branch1 onto %s\n" \ + printf "rebase (finish): refs/heads/branch1 onto %s\n" \ "$(git rev-parse branch2)" >expected && git log -g --pretty=%gs -1 refs/heads/branch1 >actual && test_cmp expected actual ' test_expect_success 'exchange two commits' ' - set_fake_editor && - FAKE_LINES="2 1" git rebase -i HEAD~2 && + ( + set_fake_editor && + FAKE_LINES="2 1" git rebase -i HEAD~2 + ) && test H = $(git cat-file commit HEAD^ | sed -ne \$p) && - test G = $(git cat-file commit HEAD | sed -ne \$p) + test G = $(git cat-file commit HEAD | sed -ne \$p) && + blob1=$(git rev-parse --short HEAD^:file1) && + blob2=$(git rev-parse --short HEAD:file1) && + commit=$(git rev-parse --short HEAD) ' -cat > expect << EOF -diff --git a/file1 b/file1 -index f70f10e..fd79235 100644 ---- a/file1 -+++ b/file1 -@@ -1 +1 @@ --A -+G -EOF - -cat > expect2 << EOF -<<<<<<< HEAD -D -======= -G ->>>>>>> 5d18e54... G -EOF - test_expect_success 'stop on conflicting pick' ' + cat >expect <<-EOF && + diff --git a/file1 b/file1 + index $blob1..$blob2 100644 + --- a/file1 + +++ b/file1 + @@ -1 +1 @@ + -A + +G + EOF + cat >expect2 <<-EOF && + <<<<<<< HEAD + D + ======= + G + >>>>>>> $commit (G) + EOF git tag new-branch1 && - set_fake_editor && - test_must_fail git rebase -i master && - test "$(git rev-parse HEAD~3)" = "$(git rev-parse master)" && + test_must_fail git rebase -i primary && + test "$(git rev-parse HEAD~3)" = "$(git rev-parse primary)" && test_cmp expect .git/rebase-merge/patch && test_cmp expect2 file1 && test "$(git diff --name-status | @@ -254,7 +280,7 @@ test_expect_success 'show conflicted patch' ' test_expect_success 'abort' ' git rebase --abort && - test $(git rev-parse new-branch1) = $(git rev-parse HEAD) && + test_cmp_rev new-branch1 HEAD && test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch1" && test_path_is_missing .git/rebase-merge ' @@ -262,8 +288,7 @@ test_expect_success 'abort' ' test_expect_success 'abort with error when new base cannot be checked out' ' git rm --cached file1 && git commit -m "remove file in base" && - set_fake_editor && - test_must_fail git rebase -i master > output 2>&1 && + test_must_fail git rebase -i primary > output 2>&1 && test_i18ngrep "The following untracked working tree files would be overwritten by checkout:" \ output && test_i18ngrep "file1" output && @@ -277,8 +302,7 @@ test_expect_success 'retain authorship' ' test_tick && GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" && git tag twerp && - set_fake_editor && - git rebase -i --onto master HEAD^ && + git rebase -i --onto primary HEAD^ && git show HEAD | grep "^Author: Twerp Snog" ' @@ -295,12 +319,11 @@ test_expect_success 'retain authorship w/ conflicts' ' test_commit b conflict b conflict-b && GIT_AUTHOR_NAME=$oGIT_AUTHOR_NAME && - set_fake_editor && test_must_fail git rebase -i conflict-a && echo resolved >conflict && git add conflict && git rebase --continue && - test $(git rev-parse conflict-a^0) = $(git rev-parse HEAD^) && + test_cmp_rev conflict-a^0 HEAD^ && git show >out && grep AttributeMe out ' @@ -311,11 +334,13 @@ test_expect_success 'squash' ' test_tick && GIT_AUTHOR_NAME="Nitfol" git commit -m "nitfol" file7 && echo "******************************" && - set_fake_editor && - FAKE_LINES="1 squash 2" EXPECT_HEADER_COUNT=2 \ - git rebase -i --onto master HEAD~2 && + ( + set_fake_editor && + FAKE_LINES="1 squash 2" EXPECT_HEADER_COUNT=2 \ + git rebase -i --onto primary HEAD~2 + ) && test B = $(cat file7) && - test $(git rev-parse HEAD^) = $(git rev-parse master) + test_cmp_rev HEAD^ primary ' test_expect_success 'retain authorship when squashing' ' @@ -324,7 +349,6 @@ test_expect_success 'retain authorship when squashing' ' test_expect_success REBASE_P '-p handles "no changes" gracefully' ' HEAD=$(git rev-parse HEAD) && - set_fake_editor && git rebase -i -p HEAD^ && git update-index --refresh && git diff-files --quiet && @@ -334,19 +358,21 @@ test_expect_success REBASE_P '-p handles "no changes" gracefully' ' test_expect_failure REBASE_P 'exchange two commits with -p' ' git checkout H && - set_fake_editor && - FAKE_LINES="2 1" git rebase -i -p HEAD~2 && + ( + set_fake_editor && + FAKE_LINES="2 1" git rebase -i -p HEAD~2 + ) && test H = $(git cat-file commit HEAD^ | sed -ne \$p) && test G = $(git cat-file commit HEAD | sed -ne \$p) ' test_expect_success REBASE_P 'preserve merges with -p' ' - git checkout -b to-be-preserved master^ && + git checkout -b to-be-preserved primary^ && : > unrelated-file && git add unrelated-file && test_tick && git commit -m "unrelated" && - git checkout -b another-branch master && + git checkout -b another-branch primary && echo B > file1 && test_tick && git commit -m J file1 && @@ -369,14 +395,13 @@ test_expect_success REBASE_P 'preserve merges with -p' ' git commit -m M file1 && git checkout -b to-be-rebased && test_tick && - set_fake_editor && - git rebase -i -p --onto branch1 master && + git rebase -i -p --onto branch1 primary && git update-index --refresh && git diff-files --quiet && git diff-index --quiet --cached HEAD -- && - test $(git rev-parse HEAD~6) = $(git rev-parse branch1) && - test $(git rev-parse HEAD~4^2) = $(git rev-parse to-be-preserved) && - test $(git rev-parse HEAD^^2^) = $(git rev-parse HEAD^^^) && + test_cmp_rev HEAD~6 branch1 && + test_cmp_rev HEAD~4^2 to-be-preserved && + test_cmp_rev HEAD^^2^ HEAD^^^ && test $(git show HEAD~5:file1) = B && test $(git show HEAD~3:file1) = C && test $(git show HEAD:file1) = E && @@ -384,8 +409,10 @@ test_expect_success REBASE_P 'preserve merges with -p' ' ' test_expect_success REBASE_P 'edit ancestor with -p' ' - set_fake_editor && - FAKE_LINES="1 2 edit 3 4" git rebase -i -p HEAD~3 && + ( + set_fake_editor && + FAKE_LINES="1 2 edit 3 4" git rebase -i -p HEAD~3 + ) && echo 2 > unrelated-file && test_tick && git commit -m L2-modified --amend unrelated-file && @@ -399,19 +426,20 @@ test_expect_success REBASE_P 'edit ancestor with -p' ' test_expect_success '--continue tries to commit' ' git reset --hard D && test_tick && - set_fake_editor && - test_must_fail git rebase -i --onto new-branch1 HEAD^ && - echo resolved > file1 && - git add file1 && - FAKE_COMMIT_MESSAGE="chouette!" git rebase --continue && - test $(git rev-parse HEAD^) = $(git rev-parse new-branch1) && + ( + set_fake_editor && + test_must_fail git rebase -i --onto new-branch1 HEAD^ && + echo resolved > file1 && + git add file1 && + FAKE_COMMIT_MESSAGE="chouette!" git rebase --continue + ) && + test_cmp_rev HEAD^ new-branch1 && git show HEAD | grep chouette ' test_expect_success 'verbose flag is heeded, even after --continue' ' - git reset --hard master@{1} && + git reset --hard primary@{1} && test_tick && - set_fake_editor && test_must_fail git rebase -v -i --onto new-branch1 HEAD^ && echo resolved > file1 && git add file1 && @@ -421,10 +449,13 @@ test_expect_success 'verbose flag is heeded, even after --continue' ' test_expect_success C_LOCALE_OUTPUT 'multi-squash only fires up editor once' ' base=$(git rev-parse HEAD~4) && - set_fake_editor && - FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="1 squash 2 squash 3 squash 4" \ - EXPECT_HEADER_COUNT=4 \ - git rebase -i $base && + ( + set_fake_editor && + FAKE_COMMIT_AMEND="ONCE" \ + FAKE_LINES="1 squash 2 squash 3 squash 4" \ + EXPECT_HEADER_COUNT=4 \ + git rebase -i $base + ) && test $base = $(git rev-parse HEAD^) && test 1 = $(git show | grep ONCE | wc -l) ' @@ -432,9 +463,12 @@ test_expect_success C_LOCALE_OUTPUT 'multi-squash only fires up editor once' ' test_expect_success C_LOCALE_OUTPUT 'multi-fixup does not fire up editor' ' git checkout -b multi-fixup E && base=$(git rev-parse HEAD~4) && - set_fake_editor && - FAKE_COMMIT_AMEND="NEVER" FAKE_LINES="1 fixup 2 fixup 3 fixup 4" \ - git rebase -i $base && + ( + set_fake_editor && + FAKE_COMMIT_AMEND="NEVER" \ + FAKE_LINES="1 fixup 2 fixup 3 fixup 4" \ + git rebase -i $base + ) && test $base = $(git rev-parse HEAD^) && test 0 = $(git show | grep NEVER | wc -l) && git checkout @{-1} && @@ -444,12 +478,15 @@ test_expect_success C_LOCALE_OUTPUT 'multi-fixup does not fire up editor' ' test_expect_success 'commit message used after conflict' ' git checkout -b conflict-fixup conflict-branch && base=$(git rev-parse HEAD~4) && - set_fake_editor && - test_must_fail env FAKE_LINES="1 fixup 3 fixup 4" git rebase -i $base && - echo three > conflict && - git add conflict && - FAKE_COMMIT_AMEND="ONCE" EXPECT_HEADER_COUNT=2 \ - git rebase --continue && + ( + set_fake_editor && + test_must_fail env FAKE_LINES="1 fixup 3 fixup 4" \ + git rebase -i $base && + echo three > conflict && + git add conflict && + FAKE_COMMIT_AMEND="ONCE" EXPECT_HEADER_COUNT=2 \ + git rebase --continue + ) && test $base = $(git rev-parse HEAD^) && test 1 = $(git show | grep ONCE | wc -l) && git checkout @{-1} && @@ -459,33 +496,38 @@ test_expect_success 'commit message used after conflict' ' test_expect_success 'commit message retained after conflict' ' git checkout -b conflict-squash conflict-branch && base=$(git rev-parse HEAD~4) && - set_fake_editor && - test_must_fail env FAKE_LINES="1 fixup 3 squash 4" git rebase -i $base && - echo three > conflict && - git add conflict && - FAKE_COMMIT_AMEND="TWICE" EXPECT_HEADER_COUNT=2 \ - git rebase --continue && + ( + set_fake_editor && + test_must_fail env FAKE_LINES="1 fixup 3 squash 4" \ + git rebase -i $base && + echo three > conflict && + git add conflict && + FAKE_COMMIT_AMEND="TWICE" EXPECT_HEADER_COUNT=2 \ + git rebase --continue + ) && test $base = $(git rev-parse HEAD^) && test 2 = $(git show | grep TWICE | wc -l) && git checkout @{-1} && git branch -D conflict-squash ' -cat > expect-squash-fixup << EOF -B - -D +test_expect_success C_LOCALE_OUTPUT 'squash and fixup generate correct log messages' ' + cat >expect-squash-fixup <<-\EOF && + B -ONCE -EOF + D -test_expect_success C_LOCALE_OUTPUT 'squash and fixup generate correct log messages' ' + ONCE + EOF git checkout -b squash-fixup E && base=$(git rev-parse HEAD~4) && - set_fake_editor && - FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="1 fixup 2 squash 3 fixup 4" \ - EXPECT_HEADER_COUNT=4 \ - git rebase -i $base && + ( + set_fake_editor && + FAKE_COMMIT_AMEND="ONCE" \ + FAKE_LINES="1 fixup 2 squash 3 fixup 4" \ + EXPECT_HEADER_COUNT=4 \ + 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} | @@ -499,10 +541,13 @@ test_expect_success C_LOCALE_OUTPUT 'squash and fixup generate correct log messa test_expect_success C_LOCALE_OUTPUT 'squash ignores comments' ' git checkout -b skip-comments E && base=$(git rev-parse HEAD~4) && - set_fake_editor && - FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="# 1 # squash 2 # squash 3 # squash 4 #" \ - EXPECT_HEADER_COUNT=4 \ - git rebase -i $base && + ( + set_fake_editor && + FAKE_COMMIT_AMEND="ONCE" \ + FAKE_LINES="# 1 # squash 2 # squash 3 # squash 4 #" \ + EXPECT_HEADER_COUNT=4 \ + git rebase -i $base + ) && test $base = $(git rev-parse HEAD^) && test 1 = $(git show | grep ONCE | wc -l) && git checkout @{-1} && @@ -512,10 +557,13 @@ test_expect_success C_LOCALE_OUTPUT 'squash ignores comments' ' test_expect_success C_LOCALE_OUTPUT 'squash ignores blank lines' ' git checkout -b skip-blank-lines E && base=$(git rev-parse HEAD~4) && - set_fake_editor && - FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="> 1 > squash 2 > squash 3 > squash 4 >" \ - EXPECT_HEADER_COUNT=4 \ - git rebase -i $base && + ( + set_fake_editor && + FAKE_COMMIT_AMEND="ONCE" \ + FAKE_LINES="> 1 > squash 2 > squash 3 > squash 4 >" \ + EXPECT_HEADER_COUNT=4 \ + git rebase -i $base + ) && test $base = $(git rev-parse HEAD^) && test 1 = $(git show | grep ONCE | wc -l) && git checkout @{-1} && @@ -525,17 +573,21 @@ test_expect_success C_LOCALE_OUTPUT 'squash ignores blank lines' ' test_expect_success 'squash works as expected' ' git checkout -b squash-works no-conflict-branch && one=$(git rev-parse HEAD~3) && - set_fake_editor && - FAKE_LINES="1 s 3 2" EXPECT_HEADER_COUNT=2 \ - git rebase -i HEAD~3 && + ( + set_fake_editor && + FAKE_LINES="1 s 3 2" EXPECT_HEADER_COUNT=2 git rebase -i HEAD~3 + ) && test $one = $(git rev-parse HEAD~2) ' test_expect_success 'interrupted squash works as expected' ' git checkout -b interrupted-squash conflict-branch && one=$(git rev-parse HEAD~3) && - set_fake_editor && - test_must_fail env FAKE_LINES="1 squash 3 2" git rebase -i HEAD~3 && + ( + set_fake_editor && + test_must_fail env FAKE_LINES="1 squash 3 2" \ + git rebase -i HEAD~3 + ) && test_write_lines one two four > conflict && git add conflict && test_must_fail git rebase --continue && @@ -548,8 +600,11 @@ test_expect_success 'interrupted squash works as expected' ' test_expect_success 'interrupted squash works as expected (case 2)' ' git checkout -b interrupted-squash2 conflict-branch && one=$(git rev-parse HEAD~3) && - set_fake_editor && - test_must_fail env FAKE_LINES="3 squash 1 2" git rebase -i HEAD~3 && + ( + set_fake_editor && + test_must_fail env FAKE_LINES="3 squash 1 2" \ + git rebase -i HEAD~3 + ) && test_write_lines one four > conflict && git add conflict && test_must_fail git rebase --continue && @@ -569,11 +624,13 @@ test_expect_success '--continue tries to commit, even for "edit"' ' git commit -m "unrelated change" && parent=$(git rev-parse HEAD^) && test_tick && - set_fake_editor && - FAKE_LINES="edit 1" git rebase -i HEAD^ && - echo edited > file7 && - git add file7 && - FAKE_COMMIT_MESSAGE="chouette!" git rebase --continue && + ( + set_fake_editor && + FAKE_LINES="edit 1" git rebase -i HEAD^ && + echo edited > file7 && + git add file7 && + FAKE_COMMIT_MESSAGE="chouette!" git rebase --continue + ) && test edited = $(git show HEAD:file7) && git show HEAD | grep chouette && test $parent = $(git rev-parse HEAD^) @@ -582,34 +639,41 @@ test_expect_success '--continue tries to commit, even for "edit"' ' test_expect_success 'aborted --continue does not squash commits after "edit"' ' old=$(git rev-parse HEAD) && test_tick && - set_fake_editor && - FAKE_LINES="edit 1" git rebase -i HEAD^ && - echo "edited again" > file7 && - git add file7 && - test_must_fail env FAKE_COMMIT_MESSAGE=" " git rebase --continue && + ( + set_fake_editor && + FAKE_LINES="edit 1" git rebase -i HEAD^ && + echo "edited again" > file7 && + git add file7 && + test_must_fail env FAKE_COMMIT_MESSAGE=" " git rebase --continue + ) && test $old = $(git rev-parse HEAD) && git rebase --abort ' test_expect_success 'auto-amend only edited commits after "edit"' ' test_tick && - set_fake_editor && - FAKE_LINES="edit 1" git rebase -i HEAD^ && - echo "edited again" > file7 && - git add file7 && - FAKE_COMMIT_MESSAGE="edited file7 again" git commit && - echo "and again" > file7 && - git add file7 && - test_tick && - test_must_fail env FAKE_COMMIT_MESSAGE="and again" git rebase --continue && + ( + set_fake_editor && + FAKE_LINES="edit 1" git rebase -i HEAD^ && + echo "edited again" > file7 && + git add file7 && + FAKE_COMMIT_MESSAGE="edited file7 again" git commit && + echo "and again" > file7 && + git add file7 && + test_tick && + test_must_fail env FAKE_COMMIT_MESSAGE="and again" \ + git rebase --continue + ) && git rebase --abort ' test_expect_success 'clean error after failed "exec"' ' test_tick && test_when_finished "git rebase --abort || :" && - set_fake_editor && - test_must_fail env FAKE_LINES="1 exec_false" git rebase -i HEAD^ && + ( + set_fake_editor && + test_must_fail env FAKE_LINES="1 exec_false" git rebase -i HEAD^ + ) && echo "edited again" > file7 && git add file7 && test_must_fail git rebase --continue 2>error && @@ -620,8 +684,10 @@ test_expect_success 'rebase a detached HEAD' ' grandparent=$(git rev-parse HEAD~2) && git checkout $(git rev-parse HEAD) && test_tick && - set_fake_editor && - FAKE_LINES="2 1" git rebase -i HEAD~2 && + ( + set_fake_editor && + FAKE_LINES="2 1" git rebase -i HEAD~2 + ) && test $grandparent = $(git rev-parse HEAD~2) ' @@ -636,9 +702,10 @@ test_expect_success 'rebase a commit violating pre-commit' ' test_must_fail git commit -m doesnt-verify file1 && git commit -m doesnt-verify --no-verify file1 && test_tick && - set_fake_editor && - FAKE_LINES=2 git rebase -i HEAD~2 - + ( + set_fake_editor && + FAKE_LINES=2 git rebase -i HEAD~2 + ) ' test_expect_success 'rebase with a file named HEAD in worktree' ' @@ -658,8 +725,10 @@ test_expect_success 'rebase with a file named HEAD in worktree' ' git commit -m "Add body" ) && - set_fake_editor && - FAKE_LINES="1 squash 2" git rebase -i @{-1} && + ( + set_fake_editor && + FAKE_LINES="1 squash 2" git rebase -i @{-1} + ) && test "$(git show -s --pretty=format:%an)" = "Squashed Away" ' @@ -670,9 +739,8 @@ test_expect_success 'do "noop" when there is nothing to cherry-pick' ' GIT_EDITOR=: git commit --amend \ --author="Somebody else <somebody@else.com>" && test $(git rev-parse branch3) != $(git rev-parse branch4) && - set_fake_editor && git rebase -i branch3 && - test $(git rev-parse branch3) = $(git rev-parse branch4) + test_cmp_rev branch3 branch4 ' @@ -695,13 +763,14 @@ test_expect_success 'submodule rebase setup' ' git commit -a -m "submodule second" ) && test_tick && - set_fake_editor && git commit -a -m "Three changes submodule" ' test_expect_success 'submodule rebase -i' ' - set_fake_editor && - FAKE_LINES="1 squash 2 3" git rebase -i A + ( + set_fake_editor && + FAKE_LINES="1 squash 2 3" git rebase -i A + ) ' test_expect_success 'submodule conflict setup' ' @@ -718,7 +787,6 @@ test_expect_success 'submodule conflict setup' ' ' test_expect_success 'rebase -i continue with only submodule staged' ' - set_fake_editor && test_must_fail git rebase -i submodule-base && git add sub && git rebase --continue && @@ -728,20 +796,18 @@ test_expect_success 'rebase -i continue with only submodule staged' ' test_expect_success 'rebase -i continue with unstaged submodule' ' git checkout submodule-topic && git reset --hard && - set_fake_editor && test_must_fail git rebase -i submodule-base && git reset && git rebase --continue && - test $(git rev-parse submodule-base) = $(git rev-parse HEAD) + test_cmp_rev submodule-base HEAD ' test_expect_success 'avoid unnecessary reset' ' - git checkout master && + git checkout primary && git reset --hard && test-tool chmtime =123456789 file3 && git update-index --refresh && HEAD=$(git rev-parse HEAD) && - set_fake_editor && git rebase -i HEAD~4 && test $HEAD = $(git rev-parse HEAD) && MTIME=$(test-tool chmtime --get file3) && @@ -749,17 +815,23 @@ test_expect_success 'avoid unnecessary reset' ' ' test_expect_success 'reword' ' - git checkout -b reword-branch master && - set_fake_editor && - FAKE_LINES="1 2 3 reword 4" FAKE_COMMIT_MESSAGE="E changed" git rebase -i A && - git show HEAD | grep "E changed" && - test $(git rev-parse master) != $(git rev-parse HEAD) && - test $(git rev-parse master^) = $(git rev-parse HEAD^) && - FAKE_LINES="1 2 reword 3 4" FAKE_COMMIT_MESSAGE="D changed" git rebase -i A && - git show HEAD^ | grep "D changed" && - FAKE_LINES="reword 1 2 3 4" FAKE_COMMIT_MESSAGE="B changed" git rebase -i A && - git show HEAD~3 | grep "B changed" && - FAKE_LINES="1 r 2 pick 3 p 4" FAKE_COMMIT_MESSAGE="C changed" git rebase -i A && + git checkout -b reword-branch primary && + ( + set_fake_editor && + FAKE_LINES="1 2 3 reword 4" FAKE_COMMIT_MESSAGE="E changed" \ + git rebase -i A && + git show HEAD | grep "E changed" && + test $(git rev-parse primary) != $(git rev-parse HEAD) && + test_cmp_rev primary^ HEAD^ && + FAKE_LINES="1 2 reword 3 4" FAKE_COMMIT_MESSAGE="D changed" \ + git rebase -i A && + git show HEAD^ | grep "D changed" && + FAKE_LINES="reword 1 2 3 4" FAKE_COMMIT_MESSAGE="B changed" \ + git rebase -i A && + git show HEAD~3 | grep "B changed" && + FAKE_LINES="1 r 2 pick 3 p 4" FAKE_COMMIT_MESSAGE="C changed" \ + git rebase -i A + ) && git show HEAD~2 | grep "C changed" ' @@ -770,22 +842,23 @@ test_expect_success 'rebase -i can copy notes' ' test_commit n2 && test_commit n3 && git notes add -m"a note" n3 && - set_fake_editor && git rebase -i --onto n1 n2 && test "a note" = "$(git notes show HEAD)" ' -cat >expect <<EOF -an earlier note - -a note -EOF - test_expect_success 'rebase -i can copy notes over a fixup' ' + cat >expect <<-\EOF && + an earlier note + + a note + EOF git reset --hard n3 && git notes add -m"an earlier note" n2 && - set_fake_editor && - GIT_NOTES_REWRITE_MODE=concatenate FAKE_LINES="1 f 2" git rebase -i n1 && + ( + set_fake_editor && + GIT_NOTES_REWRITE_MODE=concatenate FAKE_LINES="1 f 2" \ + git rebase -i n1 + ) && git notes show > output && test_cmp expect output ' @@ -794,8 +867,10 @@ test_expect_success 'rebase while detaching HEAD' ' git symbolic-ref HEAD && grandparent=$(git rev-parse HEAD~2) && test_tick && - set_fake_editor && - FAKE_LINES="2 1" git rebase -i HEAD~2 HEAD^0 && + ( + set_fake_editor && + FAKE_LINES="2 1" git rebase -i HEAD~2 HEAD^0 + ) && test $grandparent = $(git rev-parse HEAD~2) && test_must_fail git symbolic-ref HEAD ' @@ -804,7 +879,6 @@ test_tick # Ensure that the rebased commits get a different timestamp. test_expect_success 'always cherry-pick with --no-ff' ' git checkout no-ff-branch && git tag original-no-ff-branch && - set_fake_editor && git rebase -i --no-ff A && for p in 0 1 2 do @@ -812,7 +886,7 @@ test_expect_success 'always cherry-pick with --no-ff' ' git diff HEAD~$p original-no-ff-branch~$p > out && test_must_be_empty out done && - test $(git rev-parse HEAD~3) = $(git rev-parse original-no-ff-branch~3) && + test_cmp_rev HEAD~3 original-no-ff-branch~3 && git diff HEAD~3 original-no-ff-branch~3 > out && test_must_be_empty out ' @@ -836,14 +910,16 @@ test_expect_success 'set up commits with funny messages' ' test_expect_success 'rebase-i history with funny messages' ' git rev-list A..funny >expect && test_tick && - set_fake_editor && - FAKE_LINES="1 2 3 4" git rebase -i A && + ( + set_fake_editor && + FAKE_LINES="1 2 3 4" git rebase -i A + ) && git rev-list A.. >actual && test_cmp expect actual ' test_expect_success 'prepare for rebase -i --exec' ' - git checkout master && + git checkout primary && git checkout -b execute && test_commit one_exec main.txt one_exec && test_commit two_exec main.txt two_exec && @@ -851,9 +927,9 @@ test_expect_success 'prepare for rebase -i --exec' ' ' test_expect_success 'running "git rebase -i --exec git show HEAD"' ' - set_fake_editor && - git rebase -i --exec "git show HEAD" HEAD~2 >actual && ( + set_fake_editor && + git rebase -i --exec "git show HEAD" HEAD~2 >actual && FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" && export FAKE_LINES && git rebase -i HEAD~2 >expect @@ -864,9 +940,9 @@ test_expect_success 'running "git rebase -i --exec git show HEAD"' ' test_expect_success 'running "git rebase --exec git show HEAD -i"' ' git reset --hard execute && - set_fake_editor && - git rebase --exec "git show HEAD" -i HEAD~2 >actual && ( + set_fake_editor && + git rebase --exec "git show HEAD" -i HEAD~2 >actual && FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" && export FAKE_LINES && git rebase -i HEAD~2 >expect @@ -877,9 +953,9 @@ test_expect_success 'running "git rebase --exec git show HEAD -i"' ' test_expect_success 'running "git rebase -ix git show HEAD"' ' git reset --hard execute && - set_fake_editor && - git rebase -ix "git show HEAD" HEAD~2 >actual && ( + set_fake_editor && + git rebase -ix "git show HEAD" HEAD~2 >actual && FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" && export FAKE_LINES && git rebase -i HEAD~2 >expect @@ -891,9 +967,9 @@ test_expect_success 'running "git rebase -ix git show HEAD"' ' test_expect_success 'rebase -ix with several <CMD>' ' git reset --hard execute && - set_fake_editor && - git rebase -ix "git show HEAD; pwd" HEAD~2 >actual && ( + set_fake_editor && + git rebase -ix "git show HEAD; pwd" HEAD~2 >actual && FAKE_LINES="1 exec_git_show_HEAD;_pwd 2 exec_git_show_HEAD;_pwd" && export FAKE_LINES && git rebase -i HEAD~2 >expect @@ -904,9 +980,9 @@ test_expect_success 'rebase -ix with several <CMD>' ' test_expect_success 'rebase -ix with several instances of --exec' ' git reset --hard execute && - set_fake_editor && - git rebase -i --exec "git show HEAD" --exec "pwd" HEAD~2 >actual && ( + set_fake_editor && + git rebase -i --exec "git show HEAD" --exec "pwd" HEAD~2 >actual && FAKE_LINES="1 exec_git_show_HEAD exec_pwd 2 exec_git_show_HEAD exec_pwd" && export FAKE_LINES && @@ -925,13 +1001,11 @@ test_expect_success C_LOCALE_OUTPUT 'rebase -ix with --autosquash' ' echo bis >bis.txt && git add bis.txt && git commit -m "fixup! two_exec" && - set_fake_editor && - ( - git checkout -b autosquash_actual && - git rebase -i --exec "git show HEAD" --autosquash HEAD~4 >actual - ) && + git checkout -b autosquash_actual && + git rebase -i --exec "git show HEAD" --autosquash HEAD~4 >actual && git checkout autosquash && ( + set_fake_editor && git checkout -b autosquash_expected && FAKE_LINES="1 fixup 3 fixup 4 exec_git_show_HEAD 2 exec_git_show_HEAD" && export FAKE_LINES && @@ -952,16 +1026,17 @@ test_expect_success 'rebase --exec works without -i ' ' test_expect_success 'rebase -i --exec without <CMD>' ' git reset --hard execute && - set_fake_editor && test_must_fail git rebase -i --exec 2>actual && test_i18ngrep "requires a value" actual && - git checkout master + git checkout primary ' test_expect_success 'rebase -i --root re-order and drop commits' ' git checkout E && - set_fake_editor && - FAKE_LINES="3 1 2 5" git rebase -i --root && + ( + set_fake_editor && + FAKE_LINES="3 1 2 5" git rebase -i --root + ) && test E = $(git cat-file commit HEAD | sed -ne \$p) && test B = $(git cat-file commit HEAD^ | sed -ne \$p) && test A = $(git cat-file commit HEAD^^ | sed -ne \$p) && @@ -974,48 +1049,70 @@ test_expect_success 'rebase -i --root retain root commit author and message' ' echo B >file7 && git add file7 && GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" && - set_fake_editor && - FAKE_LINES="2" git rebase -i --root && + ( + set_fake_editor && + FAKE_LINES="2" git rebase -i --root + ) && git cat-file commit HEAD | grep -q "^author Twerp Snog" && git cat-file commit HEAD | grep -q "^different author$" ' test_expect_success 'rebase -i --root temporary sentinel commit' ' git checkout B && - set_fake_editor && - test_must_fail env FAKE_LINES="2" git rebase -i --root && - git cat-file commit HEAD | grep "^tree 4b825dc642cb" && + ( + set_fake_editor && + test_must_fail env FAKE_LINES="2" git rebase -i --root + ) && + git cat-file commit HEAD | grep "^tree $EMPTY_TREE" && git rebase --abort ' test_expect_success 'rebase -i --root fixup root commit' ' git checkout B && - set_fake_editor && - FAKE_LINES="1 fixup 2" git rebase -i --root && + ( + set_fake_editor && + FAKE_LINES="1 fixup 2" git rebase -i --root + ) && test A = $(git cat-file commit HEAD | sed -ne \$p) && test B = $(git show HEAD:file1) && test 0 = $(git cat-file commit HEAD | grep -c ^parent\ ) ' -test_expect_success 'rebase -i --root reword root commit' ' +test_expect_success 'rebase -i --root reword original root commit' ' test_when_finished "test_might_fail git rebase --abort" && - git checkout -b reword-root-branch master && - set_fake_editor && - FAKE_LINES="reword 1 2" FAKE_COMMIT_MESSAGE="A changed" \ - git rebase -i --root && + git checkout -b reword-original-root-branch primary && + ( + set_fake_editor && + FAKE_LINES="reword 1 2" FAKE_COMMIT_MESSAGE="A changed" \ + git rebase -i --root + ) && git show HEAD^ | grep "A changed" && test -z "$(git show -s --format=%p HEAD^)" ' -test_expect_success 'rebase -i --root when root has untracked file confilct' ' +test_expect_success 'rebase -i --root reword new root commit' ' + test_when_finished "test_might_fail git rebase --abort" && + git checkout -b reword-now-root-branch primary && + ( + set_fake_editor && + FAKE_LINES="reword 3 1" FAKE_COMMIT_MESSAGE="C changed" \ + git rebase -i --root + ) && + git show HEAD^ | grep "C changed" && + test -z "$(git show -s --format=%p HEAD^)" +' + +test_expect_success 'rebase -i --root when root has untracked file conflict' ' test_when_finished "reset_rebase" && git checkout -b failing-root-pick A && echo x >file2 && git rm file1 && git commit -m "remove file 1 add file 2" && echo z >file1 && - set_fake_editor && - test_must_fail env FAKE_LINES="1 2" git rebase -i --root && + ( + set_fake_editor && + test_must_fail env FAKE_LINES="1 2" git rebase -i --root + ) && rm file1 && git rebase --continue && test "$(git log -1 --format=%B)" = "remove file 1 add file 2" && @@ -1025,32 +1122,38 @@ test_expect_success 'rebase -i --root when root has untracked file confilct' ' test_expect_success 'rebase -i --root reword root when root has untracked file conflict' ' test_when_finished "reset_rebase" && echo z>file1 && - set_fake_editor && - test_must_fail env FAKE_LINES="reword 1 2" \ - FAKE_COMMIT_MESSAGE="Modified A" git rebase -i --root && - rm file1 && - FAKE_COMMIT_MESSAGE="Reworded A" git rebase --continue && + ( + set_fake_editor && + test_must_fail env FAKE_LINES="reword 1 2" \ + FAKE_COMMIT_MESSAGE="Modified A" git rebase -i --root && + rm file1 && + FAKE_COMMIT_MESSAGE="Reworded A" git rebase --continue + ) && test "$(git log -1 --format=%B HEAD^)" = "Reworded A" && test "$(git rev-list --count HEAD)" = 2 ' test_expect_success C_LOCALE_OUTPUT 'rebase --edit-todo does not work on non-interactive rebase' ' - git checkout reword-root-branch && + git checkout reword-original-root-branch && git reset --hard && git checkout conflict-branch && - set_fake_editor && - test_must_fail git rebase --onto HEAD~2 HEAD~ && - test_must_fail git rebase --edit-todo && + ( + set_fake_editor && + test_must_fail git rebase -f --apply --onto HEAD~2 HEAD~ && + test_must_fail git rebase --edit-todo + ) && git rebase --abort ' test_expect_success 'rebase --edit-todo can be used to modify todo' ' git reset --hard && git checkout no-conflict-branch^0 && - set_fake_editor && - FAKE_LINES="edit 1 2 3" git rebase -i HEAD~3 && - FAKE_LINES="2 1" git rebase --edit-todo && - git rebase --continue && + ( + set_fake_editor && + FAKE_LINES="edit 1 2 3" git rebase -i HEAD~3 && + FAKE_LINES="2 1" git rebase --edit-todo && + git rebase --continue + ) && test M = $(git cat-file commit HEAD^ | sed -ne \$p) && test L = $(git cat-file commit HEAD | sed -ne \$p) ' @@ -1058,13 +1161,12 @@ test_expect_success 'rebase --edit-todo can be used to modify todo' ' test_expect_success 'rebase -i produces readable reflog' ' git reset --hard && git branch -f branch-reflog-test H && - set_fake_editor && git rebase -i --onto I F branch-reflog-test && cat >expect <<-\EOF && - rebase -i (finish): returning to refs/heads/branch-reflog-test - rebase -i (pick): H - rebase -i (pick): G - rebase -i (start): checkout I + rebase (finish): returning to refs/heads/branch-reflog-test + rebase (pick): H + rebase (pick): G + rebase (start): checkout I EOF git reflog -n4 HEAD | sed "s/[^:]*: //" >actual && @@ -1079,8 +1181,10 @@ test_expect_success 'rebase -i respects core.commentchar' ' sed -e "2,\$s/^/\\\\/" "$1" >"$1.tmp" && mv "$1.tmp" "$1" EOF - test_set_editor "$(pwd)/remove-all-but-first.sh" && - git rebase -i B && + ( + test_set_editor "$(pwd)/remove-all-but-first.sh" && + git rebase -i B + ) && test B = $(git cat-file commit HEAD^ | sed -ne \$p) ' @@ -1089,9 +1193,11 @@ test_expect_success 'rebase -i respects core.commentchar=auto' ' write_script copy-edit-script.sh <<-\EOF && cp "$1" edit-script EOF - test_set_editor "$(pwd)/copy-edit-script.sh" && test_when_finished "git rebase --abort || :" && - git rebase -i HEAD^ && + ( + test_set_editor "$(pwd)/copy-edit-script.sh" && + git rebase -i HEAD^ + ) && test -z "$(grep -ve "^#" -e "^\$" -e "^pick" edit-script)" ' @@ -1126,8 +1232,11 @@ test_expect_success 'interrupted rebase -i with --strategy and -X' ' echo five >conflict && echo Z >file1 && git commit -a -m "one file conflict" && - set_fake_editor && - FAKE_LINES="edit 1 2" git rebase -i --strategy=recursive -Xours conflict-branch && + ( + set_fake_editor && + FAKE_LINES="edit 1 2" git rebase -i --strategy=recursive \ + -Xours conflict-branch + ) && git rebase --continue && test $(git show conflict-branch:conflict) = $(cat conflict) && test $(cat file1) = Z @@ -1142,8 +1251,8 @@ test_expect_success 'rebase -i error on commits with \ in message' ' test_expect_code 1 grep " emp" error ' -test_expect_success 'short SHA-1 setup' ' - test_when_finished "git checkout master" && +test_expect_success 'short commit ID setup' ' + test_when_finished "git checkout primary" && git checkout --orphan collide && git rm -rf . && ( @@ -1154,22 +1263,68 @@ test_expect_success 'short SHA-1 setup' ' ) ' -test_expect_success 'short SHA-1 collide' ' - test_when_finished "reset_rebase && git checkout master" && +if test -n "$GIT_TEST_FIND_COLLIDER" +then + author="$(unset test_tick; test_tick; git var GIT_AUTHOR_IDENT)" + committer="$(unset test_tick; test_tick; git var GIT_COMMITTER_IDENT)" + blob="$(git rev-parse collide2:collide)" + from="$(git rev-parse collide1^0)" + repl="commit refs/heads/collider-&\\n" + repl="${repl}author $author\\ncommitter $committer\\n" + repl="${repl}data <<EOF\\ncollide2 &\\nEOF\\n" + repl="${repl}from $from\\nM 100644 $blob collide\\n" + test_seq 1 32768 | sed "s|.*|$repl|" >script && + git fast-import <script && + git pack-refs && + git for-each-ref >refs && + grep "^$(test_oid t3404_collision)" <refs >matches && + cat matches && + test_line_count -gt 2 matches || { + echo "Could not find a collider" >&2 + exit 1 + } +fi + +test_expect_success 'short commit ID collide' ' + test_oid_cache <<-EOF && + # collision-related constants + t3404_collision sha1:6bcd + t3404_collision sha256:0161 + t3404_collider sha1:ac4f2ee + t3404_collider sha256:16697 + EOF + test_when_finished "reset_rebase && git checkout primary" && git checkout collide && + colliding_id=$(test_oid t3404_collision) && + hexsz=$(test_oid hexsz) && + test $colliding_id = "$(git rev-parse HEAD | cut -c 1-4)" && + test_config core.abbrev 4 && ( - unset test_tick && - test_tick && - set_fake_editor && - FAKE_COMMIT_MESSAGE="collide2 ac4f2ee" \ - FAKE_LINES="reword 1 2" git rebase -i HEAD~2 - ) + unset test_tick && + test_tick && + set_fake_editor && + FAKE_COMMIT_MESSAGE="collide2 $(test_oid t3404_collider)" \ + FAKE_LINES="reword 1 break 2" git rebase -i HEAD~2 && + test $colliding_id = "$(git rev-parse HEAD | cut -c 1-4)" && + grep "^pick $colliding_id " \ + .git/rebase-merge/git-rebase-todo.tmp && + grep "^pick [0-9a-f]\{$hexsz\}" \ + .git/rebase-merge/git-rebase-todo && + grep "^pick [0-9a-f]\{$hexsz\}" \ + .git/rebase-merge/git-rebase-todo.backup && + git rebase --continue + ) && + collide2="$(git rev-parse HEAD~1 | cut -c 1-4)" && + collide3="$(git rev-parse collide3 | cut -c 1-4)" && + test "$collide2" = "$collide3" ' test_expect_success 'respect core.abbrev' ' git config core.abbrev 12 && - set_cat_todo_editor && - test_must_fail git rebase -i HEAD~4 >todo-list && + ( + set_cat_todo_editor && + test_must_fail git rebase -i HEAD~4 >todo-list + ) && test 4 = $(grep -c "pick [0-9a-f]\{12,\}" todo-list) ' @@ -1177,16 +1332,20 @@ test_expect_success 'todo count' ' write_script dump-raw.sh <<-\EOF && cat "$1" EOF - test_set_editor "$(pwd)/dump-raw.sh" && - git rebase -i HEAD~4 >actual && + ( + test_set_editor "$(pwd)/dump-raw.sh" && + git rebase -i HEAD~4 >actual + ) && test_i18ngrep "^# Rebase ..* onto ..* ([0-9]" actual ' test_expect_success 'rebase -i commits that overwrite untracked files (pick)' ' git checkout --force branch2 && git clean -f && - set_fake_editor && - FAKE_LINES="edit 1 2" git rebase -i A && + ( + set_fake_editor && + FAKE_LINES="edit 1 2" git rebase -i A + ) && test_cmp_rev HEAD F && test_path_is_missing file6 && >file6 && @@ -1201,8 +1360,10 @@ test_expect_success 'rebase -i commits that overwrite untracked files (squash)' git checkout --force branch2 && git clean -f && git tag original-branch2 && - set_fake_editor && - FAKE_LINES="edit 1 squash 2" git rebase -i A && + ( + set_fake_editor && + FAKE_LINES="edit 1 squash 2" git rebase -i A + ) && test_cmp_rev HEAD F && test_path_is_missing file6 && >file6 && @@ -1217,8 +1378,10 @@ test_expect_success 'rebase -i commits that overwrite untracked files (squash)' test_expect_success 'rebase -i commits that overwrite untracked files (no ff)' ' git checkout --force branch2 && git clean -f && - set_fake_editor && - FAKE_LINES="edit 1 2" git rebase -i --no-ff A && + ( + set_fake_editor && + FAKE_LINES="edit 1 2" git rebase -i --no-ff A + ) && test $(git cat-file commit HEAD | sed -ne \$p) = F && test_path_is_missing file6 && >file6 && @@ -1241,8 +1404,10 @@ test_expect_success 'rebase --continue removes CHERRY_PICK_HEAD' ' git tag seq-onto && git reset --hard HEAD~2 && git cherry-pick seq-onto && - set_fake_editor && - test_must_fail env FAKE_LINES= git rebase -i seq-onto && + ( + set_fake_editor && + test_must_fail env FAKE_LINES= git rebase -i seq-onto + ) && test -d .git/rebase-merge && git rebase --continue && git diff --exit-code seq-onto && @@ -1252,17 +1417,19 @@ test_expect_success 'rebase --continue removes CHERRY_PICK_HEAD' ' rebase_setup_and_clean () { test_when_finished " - git checkout master && + git checkout primary && test_might_fail git branch -D $1 && test_might_fail git rebase --abort " && - git checkout -b $1 ${2:-master} + git checkout -b $1 ${2:-primary} } test_expect_success 'drop' ' rebase_setup_and_clean drop-test && - set_fake_editor && - FAKE_LINES="1 drop 2 3 d 4 5" git rebase -i --root && + ( + set_fake_editor && + FAKE_LINES="1 drop 2 3 d 4 5" git rebase -i --root + ) && test E = $(git cat-file commit HEAD | sed -ne \$p) && test C = $(git cat-file commit HEAD^ | sed -ne \$p) && test A = $(git cat-file commit HEAD^^ | sed -ne \$p) @@ -1271,76 +1438,185 @@ test_expect_success 'drop' ' test_expect_success 'rebase -i respects rebase.missingCommitsCheck = ignore' ' test_config rebase.missingCommitsCheck ignore && rebase_setup_and_clean missing-commit && - set_fake_editor && - FAKE_LINES="1 2 3 4" \ - git rebase -i --root 2>actual && + ( + set_fake_editor && + FAKE_LINES="1 2 3 4" git rebase -i --root 2>actual + ) && test D = $(git cat-file commit HEAD | sed -ne \$p) && test_i18ngrep \ "Successfully rebased and updated refs/heads/missing-commit" \ actual ' -cat >expect <<EOF -Warning: some commits may have been dropped accidentally. -Dropped commits (newer to older): - - $(git rev-list --pretty=oneline --abbrev-commit -1 master) -To avoid this message, use "drop" to explicitly remove a commit. - -Use 'git config rebase.missingCommitsCheck' to change the level of warnings. -The possible behaviours are: ignore, warn, error. - -Rebasing (1/4) -Rebasing (2/4) -Rebasing (3/4) -Rebasing (4/4) -Successfully rebased and updated refs/heads/missing-commit. -EOF - -cr_to_nl () { - tr '\015' '\012' -} - test_expect_success 'rebase -i respects rebase.missingCommitsCheck = warn' ' + cat >expect <<-EOF && + Warning: some commits may have been dropped accidentally. + Dropped commits (newer to older): + - $(git rev-list --pretty=oneline --abbrev-commit -1 primary) + To avoid this message, use "drop" to explicitly remove a commit. + EOF test_config rebase.missingCommitsCheck warn && rebase_setup_and_clean missing-commit && - set_fake_editor && - FAKE_LINES="1 2 3 4" \ - git rebase -i --root 2>actual.2 && - cr_to_nl <actual.2 >actual && + ( + set_fake_editor && + FAKE_LINES="1 2 3 4" git rebase -i --root 2>actual.2 + ) && + head -n4 actual.2 >actual && test_i18ncmp expect actual && test D = $(git cat-file commit HEAD | sed -ne \$p) ' -cat >expect <<EOF -Warning: some commits may have been dropped accidentally. -Dropped commits (newer to older): - - $(git rev-list --pretty=oneline --abbrev-commit -1 master) - - $(git rev-list --pretty=oneline --abbrev-commit -1 master~2) -To avoid this message, use "drop" to explicitly remove a commit. - -Use 'git config rebase.missingCommitsCheck' to change the level of warnings. -The possible behaviours are: ignore, warn, error. - -You can fix this with 'git rebase --edit-todo' and then run 'git rebase --continue'. -Or you can abort the rebase with 'git rebase --abort'. -EOF - test_expect_success 'rebase -i respects rebase.missingCommitsCheck = error' ' + cat >expect <<-EOF && + Warning: some commits may have been dropped accidentally. + Dropped commits (newer to older): + - $(git rev-list --pretty=oneline --abbrev-commit -1 primary) + - $(git rev-list --pretty=oneline --abbrev-commit -1 primary~2) + To avoid this message, use "drop" to explicitly remove a commit. + + Use '\''git config rebase.missingCommitsCheck'\'' to change the level of warnings. + The possible behaviours are: ignore, warn, error. + + You can fix this with '\''git rebase --edit-todo'\'' and then run '\''git rebase --continue'\''. + Or you can abort the rebase with '\''git rebase --abort'\''. + EOF test_config rebase.missingCommitsCheck error && rebase_setup_and_clean missing-commit && - set_fake_editor && - test_must_fail env FAKE_LINES="1 2 4" \ - git rebase -i --root 2>actual && - test_i18ncmp expect actual && - cp .git/rebase-merge/git-rebase-todo.backup \ - .git/rebase-merge/git-rebase-todo && - FAKE_LINES="1 2 drop 3 4 drop 5" \ - git rebase --edit-todo && + ( + set_fake_editor && + test_must_fail env FAKE_LINES="1 2 4" \ + git rebase -i --root 2>actual && + test_i18ncmp expect actual && + cp .git/rebase-merge/git-rebase-todo.backup \ + .git/rebase-merge/git-rebase-todo && + FAKE_LINES="1 2 drop 3 4 drop 5" git rebase --edit-todo + ) && git rebase --continue && test D = $(git cat-file commit HEAD | sed -ne \$p) && test B = $(git cat-file commit HEAD^ | sed -ne \$p) ' +test_expect_success 'rebase --edit-todo respects rebase.missingCommitsCheck = ignore' ' + test_config rebase.missingCommitsCheck ignore && + rebase_setup_and_clean missing-commit && + ( + set_fake_editor && + FAKE_LINES="break 1 2 3 4 5" git rebase -i --root && + FAKE_LINES="1 2 3 4" git rebase --edit-todo && + git rebase --continue 2>actual + ) && + test D = $(git cat-file commit HEAD | sed -ne \$p) && + test_i18ngrep \ + "Successfully rebased and updated refs/heads/missing-commit" \ + actual +' + +test_expect_success 'rebase --edit-todo respects rebase.missingCommitsCheck = warn' ' + cat >expect <<-EOF && + error: invalid line 1: badcmd $(git rev-list --pretty=oneline --abbrev-commit -1 primary~4) + Warning: some commits may have been dropped accidentally. + Dropped commits (newer to older): + - $(git rev-list --pretty=oneline --abbrev-commit -1 primary) + - $(git rev-list --pretty=oneline --abbrev-commit -1 primary~4) + To avoid this message, use "drop" to explicitly remove a commit. + EOF + head -n4 expect >expect.2 && + tail -n1 expect >>expect.2 && + tail -n4 expect.2 >expect.3 && + test_config rebase.missingCommitsCheck warn && + rebase_setup_and_clean missing-commit && + ( + set_fake_editor && + test_must_fail env FAKE_LINES="bad 1 2 3 4 5" \ + git rebase -i --root && + cp .git/rebase-merge/git-rebase-todo.backup orig && + FAKE_LINES="2 3 4" git rebase --edit-todo 2>actual.2 && + head -n6 actual.2 >actual && + test_i18ncmp expect actual && + cp orig .git/rebase-merge/git-rebase-todo && + FAKE_LINES="1 2 3 4" git rebase --edit-todo 2>actual.2 && + head -n4 actual.2 >actual && + test_i18ncmp expect.3 actual && + git rebase --continue 2>actual + ) && + test D = $(git cat-file commit HEAD | sed -ne \$p) && + test_i18ngrep \ + "Successfully rebased and updated refs/heads/missing-commit" \ + actual +' + +test_expect_success 'rebase --edit-todo respects rebase.missingCommitsCheck = error' ' + cat >expect <<-EOF && + error: invalid line 1: badcmd $(git rev-list --pretty=oneline --abbrev-commit -1 primary~4) + Warning: some commits may have been dropped accidentally. + Dropped commits (newer to older): + - $(git rev-list --pretty=oneline --abbrev-commit -1 primary) + - $(git rev-list --pretty=oneline --abbrev-commit -1 primary~4) + To avoid this message, use "drop" to explicitly remove a commit. + + Use '\''git config rebase.missingCommitsCheck'\'' to change the level of warnings. + The possible behaviours are: ignore, warn, error. + + You can fix this with '\''git rebase --edit-todo'\'' and then run '\''git rebase --continue'\''. + Or you can abort the rebase with '\''git rebase --abort'\''. + EOF + tail -n11 expect >expect.2 && + head -n3 expect.2 >expect.3 && + tail -n7 expect.2 >>expect.3 && + test_config rebase.missingCommitsCheck error && + rebase_setup_and_clean missing-commit && + ( + set_fake_editor && + test_must_fail env FAKE_LINES="bad 1 2 3 4 5" \ + git rebase -i --root && + cp .git/rebase-merge/git-rebase-todo.backup orig && + test_must_fail env FAKE_LINES="2 3 4" \ + git rebase --edit-todo 2>actual && + test_i18ncmp expect actual && + test_must_fail git rebase --continue 2>actual && + test_i18ncmp expect.2 actual && + test_must_fail git rebase --edit-todo && + cp orig .git/rebase-merge/git-rebase-todo && + test_must_fail env FAKE_LINES="1 2 3 4" \ + git rebase --edit-todo 2>actual && + test_i18ncmp expect.3 actual && + test_must_fail git rebase --continue 2>actual && + test_i18ncmp expect.3 actual && + cp orig .git/rebase-merge/git-rebase-todo && + FAKE_LINES="1 2 3 4 drop 5" git rebase --edit-todo && + git rebase --continue 2>actual + ) && + test D = $(git cat-file commit HEAD | sed -ne \$p) && + test_i18ngrep \ + "Successfully rebased and updated refs/heads/missing-commit" \ + actual +' + +test_expect_success 'rebase.missingCommitsCheck = error after resolving conflicts' ' + test_config rebase.missingCommitsCheck error && + ( + set_fake_editor && + FAKE_LINES="drop 1 break 2 3 4" git rebase -i A E + ) && + git rebase --edit-todo && + test_must_fail git rebase --continue && + echo x >file1 && + git add file1 && + git rebase --continue +' + +test_expect_success 'rebase.missingCommitsCheck = error when editing for a second time' ' + test_config rebase.missingCommitsCheck error && + ( + set_fake_editor && + FAKE_LINES="1 break 2 3" git rebase -i A D && + cp .git/rebase-merge/git-rebase-todo todo && + test_must_fail env FAKE_LINES=2 git rebase --edit-todo && + GIT_SEQUENCE_EDITOR="cp todo" git rebase --edit-todo && + git rebase --continue + ) +' + test_expect_success 'respects rebase.abbreviateCommands with fixup, squash and exec' ' rebase_setup_and_clean abbrevcmd && test_commit "first" file1.txt "first line" first && @@ -1356,21 +1632,27 @@ test_expect_success 'respects rebase.abbreviateCommands with fixup, squash and e x git show HEAD EOF git checkout abbrevcmd && - set_cat_todo_editor && test_config rebase.abbreviateCommands true && - test_must_fail git rebase -i --exec "git show HEAD" \ - --autosquash master >actual && + ( + set_cat_todo_editor && + test_must_fail git rebase -i --exec "git show HEAD" \ + --autosquash primary >actual + ) && test_cmp expected actual ' test_expect_success 'static check of bad command' ' rebase_setup_and_clean bad-cmd && - set_fake_editor && - test_must_fail env FAKE_LINES="1 2 3 bad 4 5" \ + ( + set_fake_editor && + test_must_fail env FAKE_LINES="1 2 3 bad 4 5" \ git rebase -i --root 2>actual && - test_i18ngrep "badcmd $(git rev-list --oneline -1 master~1)" actual && - test_i18ngrep "You can fix this with .git rebase --edit-todo.." actual && - FAKE_LINES="1 2 3 drop 4 5" git rebase --edit-todo && + test_i18ngrep "badcmd $(git rev-list --oneline -1 primary~1)" \ + actual && + test_i18ngrep "You can fix this with .git rebase --edit-todo.." \ + actual && + FAKE_LINES="1 2 3 drop 4 5" git rebase --edit-todo + ) && git rebase --continue && test E = $(git cat-file commit HEAD | sed -ne \$p) && test C = $(git cat-file commit HEAD^ | sed -ne \$p) @@ -1386,19 +1668,24 @@ test_expect_success 'tabs and spaces are accepted in the todolist' ' ) >"$1.new" mv "$1.new" "$1" EOF - test_set_editor "$(pwd)/add-indent.sh" && - git rebase -i HEAD^^^ && + ( + test_set_editor "$(pwd)/add-indent.sh" && + git rebase -i HEAD^^^ + ) && test E = $(git cat-file commit HEAD | sed -ne \$p) ' test_expect_success 'static check of bad SHA-1' ' rebase_setup_and_clean bad-sha && - set_fake_editor && - test_must_fail env FAKE_LINES="1 2 edit fakesha 3 4 5 #" \ - git rebase -i --root 2>actual && - test_i18ngrep "edit XXXXXXX False commit" actual && - test_i18ngrep "You can fix this with .git rebase --edit-todo.." actual && - FAKE_LINES="1 2 4 5 6" git rebase --edit-todo && + ( + set_fake_editor && + test_must_fail env FAKE_LINES="1 2 edit fakesha 3 4 5 #" \ + git rebase -i --root 2>actual && + test_i18ngrep "edit XXXXXXX False commit" actual && + test_i18ngrep "You can fix this with .git rebase --edit-todo.." \ + actual && + FAKE_LINES="1 2 4 5 6" git rebase --edit-todo + ) && git rebase --continue && test E = $(git cat-file commit HEAD | sed -ne \$p) ' @@ -1415,42 +1702,116 @@ test_expect_success 'editor saves as CR/LF' ' ) ' -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 && + ( + 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 && + ( + 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 'valid author header after --root swap' ' rebase_setup_and_clean author-header no-conflict-branch && - set_fake_editor && git commit --amend --author="Au ${SQ}thor <author@example.com>" --no-edit && git cat-file commit HEAD | grep ^author >expected && - FAKE_LINES="5 1" git rebase -i --root && + ( + set_fake_editor && + FAKE_LINES="5 1" git rebase -i --root + ) && git cat-file commit HEAD^ | grep ^author >actual && test_cmp expected actual ' test_expect_success 'valid author header when author contains single quote' ' rebase_setup_and_clean author-header no-conflict-branch && - set_fake_editor && git commit --amend --author="Au ${SQ}thor <author@example.com>" --no-edit && git cat-file commit HEAD | grep ^author >expected && - FAKE_LINES="2" git rebase -i HEAD~2 && + ( + set_fake_editor && + FAKE_LINES="2" git rebase -i HEAD~2 + ) && git cat-file commit HEAD | grep ^author >actual && test_cmp expected actual ' +test_expect_success 'post-commit hook is called' ' + test_when_finished "rm -f .git/hooks/post-commit" && + >actual && + mkdir -p .git/hooks && + write_script .git/hooks/post-commit <<-\EOS && + git rev-parse HEAD >>actual + EOS + ( + set_fake_editor && + FAKE_LINES="edit 4 1 reword 2 fixup 3" git rebase -i A E && + echo x>file3 && + git add file3 && + FAKE_COMMIT_MESSAGE=edited git rebase --continue + ) && + git rev-parse HEAD@{5} HEAD@{4} HEAD@{3} HEAD@{2} HEAD@{1} HEAD \ + >expect && + test_cmp expect actual +' + +test_expect_success 'correct error message for partial commit after empty pick' ' + test_when_finished "git rebase --abort" && + ( + set_fake_editor && + FAKE_LINES="2 1 1" && + export FAKE_LINES && + test_must_fail git rebase -i A D + ) && + echo x >file1 && + test_must_fail git commit file1 2>err && + test_i18ngrep "cannot do a partial commit during a rebase." err +' + +test_expect_success 'correct error message for commit --amend after empty pick' ' + test_when_finished "git rebase --abort" && + ( + set_fake_editor && + FAKE_LINES="1 1" && + export FAKE_LINES && + test_must_fail git rebase -i A D + ) && + echo x>file1 && + test_must_fail git commit -a --amend 2>err && + test_i18ngrep "middle of a rebase -- cannot amend." err +' + +test_expect_success 'todo has correct onto hash' ' + GIT_SEQUENCE_EDITOR=cat git rebase -i no-conflict-branch~4 no-conflict-branch >actual && + onto=$(git rev-parse --short HEAD~4) && + test_i18ngrep "^# Rebase ..* onto $onto" actual +' + +test_expect_success 'ORIG_HEAD is updated correctly' ' + test_when_finished "git checkout primary && git branch -D test-orig-head" && + git checkout -b test-orig-head A && + git commit --allow-empty -m A1 && + git commit --allow-empty -m A2 && + git commit --allow-empty -m A3 && + git commit --allow-empty -m A4 && + git rebase primary && + test_cmp_rev ORIG_HEAD test-orig-head@{1} +' + +# This must be the last test in this file +test_expect_success '$EDITOR and friends are unchanged' ' + test_editor_unchanged +' + test_done |