diff options
Diffstat (limited to '')
-rwxr-xr-x | t/t3415-rebase-autosquash.sh | 469 |
1 files changed, 469 insertions, 0 deletions
diff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh new file mode 100755 index 0000000..a364530 --- /dev/null +++ b/t/t3415-rebase-autosquash.sh @@ -0,0 +1,469 @@ +#!/bin/sh + +test_description='auto squash' + +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + +. ./test-lib.sh + +. "$TEST_DIRECTORY"/lib-rebase.sh + +test_expect_success setup ' + echo 0 >file0 && + git add . && + test_tick && + git commit -m "initial commit" && + echo 0 >file1 && + echo 2 >file2 && + git add . && + test_tick && + git commit -m "first commit" && + git tag first-commit && + echo 3 >file3 && + git add . && + test_tick && + git commit -m "second commit" && + git tag base +' + +test_auto_fixup () { + no_squash= && + if test "x$1" = 'x!' + then + no_squash=true + shift + fi && + + git reset --hard base && + echo 1 >file1 && + git add -u && + test_tick && + git commit -m "fixup! first" && + + git tag $1 && + test_tick && + git rebase $2 -i HEAD^^^ && + git log --oneline >actual && + if test -n "$no_squash" + then + test_line_count = 4 actual + else + test_line_count = 3 actual && + git diff --exit-code $1 && + echo 1 >expect && + git cat-file blob HEAD^:file1 >actual && + test_cmp expect actual && + git cat-file commit HEAD^ >commit && + grep first commit >actual && + test_line_count = 1 actual + fi +} + +test_expect_success 'auto fixup (option)' ' + test_auto_fixup final-fixup-option --autosquash +' + +test_expect_success 'auto fixup (config)' ' + git config rebase.autosquash true && + test_auto_fixup final-fixup-config-true && + test_auto_fixup ! fixup-config-true-no --no-autosquash && + git config rebase.autosquash false && + test_auto_fixup ! final-fixup-config-false +' + +test_auto_squash () { + no_squash= && + if test "x$1" = 'x!' + then + no_squash=true + shift + fi && + + git reset --hard base && + echo 1 >file1 && + git add -u && + test_tick && + git commit -m "squash! first" -m "extra para for first" && + git tag $1 && + test_tick && + git rebase $2 -i HEAD^^^ && + git log --oneline >actual && + if test -n "$no_squash" + then + test_line_count = 4 actual + else + test_line_count = 3 actual && + git diff --exit-code $1 && + echo 1 >expect && + git cat-file blob HEAD^:file1 >actual && + test_cmp expect actual && + git cat-file commit HEAD^ >commit && + grep first commit >actual && + test_line_count = 2 actual + fi +} + +test_expect_success 'auto squash (option)' ' + test_auto_squash final-squash --autosquash +' + +test_expect_success 'auto squash (config)' ' + git config rebase.autosquash true && + test_auto_squash final-squash-config-true && + test_auto_squash ! squash-config-true-no --no-autosquash && + git config rebase.autosquash false && + test_auto_squash ! final-squash-config-false +' + +test_expect_success 'misspelled auto squash' ' + git reset --hard base && + echo 1 >file1 && + git add -u && + test_tick && + git commit -m "squash! forst" && + git tag final-missquash && + test_tick && + git rebase --autosquash -i HEAD^^^ && + git log --oneline >actual && + test_line_count = 4 actual && + git diff --exit-code final-missquash && + git rev-list final-missquash...HEAD >list && + test_must_be_empty list +' + +test_expect_success 'auto squash that matches 2 commits' ' + git reset --hard base && + echo 4 >file4 && + git add file4 && + test_tick && + git commit -m "first new commit" && + echo 1 >file1 && + git add -u && + test_tick && + git commit -m "squash! first" -m "extra para for first" && + git tag final-multisquash && + test_tick && + git rebase --autosquash -i HEAD~4 && + git log --oneline >actual && + test_line_count = 4 actual && + git diff --exit-code final-multisquash && + echo 1 >expect && + git cat-file blob HEAD^^:file1 >actual && + test_cmp expect actual && + git cat-file commit HEAD^^ >commit && + grep first commit >actual && + test_line_count = 2 actual && + git cat-file commit HEAD >commit && + grep first commit >actual && + test_line_count = 1 actual +' + +test_expect_success 'auto squash that matches a commit after the squash' ' + git reset --hard base && + echo 1 >file1 && + git add -u && + test_tick && + git commit -m "squash! third" && + echo 4 >file4 && + git add file4 && + test_tick && + git commit -m "third commit" && + git tag final-presquash && + test_tick && + git rebase --autosquash -i HEAD~4 && + git log --oneline >actual && + test_line_count = 5 actual && + git diff --exit-code final-presquash && + echo 0 >expect && + git cat-file blob HEAD^^:file1 >actual && + test_cmp expect actual && + echo 1 >expect && + git cat-file blob HEAD^:file1 >actual && + test_cmp expect actual && + git cat-file commit HEAD >commit && + grep third commit >actual && + test_line_count = 1 actual && + git cat-file commit HEAD^ >commit && + grep third commit >actual && + test_line_count = 1 actual +' +test_expect_success 'auto squash that matches a sha1' ' + git reset --hard base && + echo 1 >file1 && + git add -u && + test_tick && + oid=$(git rev-parse --short HEAD^) && + git commit -m "squash! $oid" -m "extra para" && + git tag final-shasquash && + test_tick && + git rebase --autosquash -i HEAD^^^ && + git log --oneline >actual && + test_line_count = 3 actual && + git diff --exit-code final-shasquash && + echo 1 >expect && + git cat-file blob HEAD^:file1 >actual && + test_cmp expect actual && + git cat-file commit HEAD^ >commit && + ! grep "squash" commit && + grep "^extra para" commit >actual && + test_line_count = 1 actual +' + +test_expect_success 'auto squash that matches longer sha1' ' + git reset --hard base && + echo 1 >file1 && + git add -u && + test_tick && + oid=$(git rev-parse --short=11 HEAD^) && + git commit -m "squash! $oid" -m "extra para" && + git tag final-longshasquash && + test_tick && + git rebase --autosquash -i HEAD^^^ && + git log --oneline >actual && + test_line_count = 3 actual && + git diff --exit-code final-longshasquash && + echo 1 >expect && + git cat-file blob HEAD^:file1 >actual && + test_cmp expect actual && + git cat-file commit HEAD^ >commit && + ! grep "squash" commit && + grep "^extra para" commit >actual && + test_line_count = 1 actual +' + +test_expect_success 'auto squash of fixup commit that matches branch name which points back to fixup commit' ' + git reset --hard base && + git commit --allow-empty -m "fixup! self-cycle" && + git branch self-cycle && + GIT_SEQUENCE_EDITOR="cat >tmp" git rebase --autosquash -i HEAD^^ && + sed -ne "/^[^#]/{s/[0-9a-f]\{7,\}/HASH/g;p;}" tmp >actual && + cat <<-EOF >expect && + pick HASH second commit + pick HASH fixup! self-cycle # empty + EOF + test_cmp expect actual +' + +test_auto_commit_flags () { + git reset --hard base && + echo 1 >file1 && + git add -u && + test_tick && + git commit --$1 first-commit -m "extra para for first" && + git tag final-commit-$1 && + test_tick && + git rebase --autosquash -i HEAD^^^ && + git log --oneline >actual && + test_line_count = 3 actual && + git diff --exit-code final-commit-$1 && + echo 1 >expect && + git cat-file blob HEAD^:file1 >actual && + test_cmp expect actual && + git cat-file commit HEAD^ >commit && + grep first commit >actual && + test_line_count = $2 actual +} + +test_expect_success 'use commit --fixup' ' + test_auto_commit_flags fixup 1 +' + +test_expect_success 'use commit --squash' ' + test_auto_commit_flags squash 2 +' + +test_auto_fixup_fixup () { + git reset --hard base && + echo 1 >file1 && + git add -u && + test_tick && + git commit -m "$1! first" -m "extra para for first" && + echo 2 >file1 && + git add -u && + test_tick && + git commit -m "$1! $2! first" -m "second extra para for first" && + git tag "final-$1-$2" && + test_tick && + ( + set_cat_todo_editor && + test_must_fail git rebase --autosquash -i HEAD^^^^ >actual && + head=$(git rev-parse --short HEAD) && + parent1=$(git rev-parse --short HEAD^) && + parent2=$(git rev-parse --short HEAD^^) && + parent3=$(git rev-parse --short HEAD^^^) && + cat >expected <<-EOF && + pick $parent3 first commit + $1 $parent1 $1! first + $1 $head $1! $2! first + pick $parent2 second commit + EOF + test_cmp expected actual + ) && + git rebase --autosquash -i HEAD^^^^ && + git log --oneline >actual && + test_line_count = 3 actual + git diff --exit-code "final-$1-$2" && + echo 2 >expect && + git cat-file blob HEAD^:file1 >actual && + test_cmp expect actual && + git cat-file commit HEAD^ >commit && + grep first commit >actual && + if test "$1" = "fixup" + then + test_line_count = 1 actual + elif test "$1" = "squash" + then + test_line_count = 3 actual + else + false + fi +} + +test_expect_success 'fixup! fixup!' ' + test_auto_fixup_fixup fixup fixup +' + +test_expect_success 'fixup! squash!' ' + test_auto_fixup_fixup fixup squash +' + +test_expect_success 'squash! squash!' ' + test_auto_fixup_fixup squash squash +' + +test_expect_success 'squash! fixup!' ' + test_auto_fixup_fixup squash fixup +' + +test_expect_success 'autosquash with custom inst format' ' + git reset --hard base && + git config --add rebase.instructionFormat "[%an @ %ar] %s" && + echo 2 >file1 && + git add -u && + test_tick && + oid=$(git rev-parse --short HEAD^) && + git commit -m "squash! $oid" -m "extra para for first" && + echo 1 >file1 && + git add -u && + test_tick && + subject=$(git log -n 1 --format=%s HEAD~2) && + git commit -m "squash! $subject" -m "second extra para for first" && + git tag final-squash-instFmt && + test_tick && + git rebase --autosquash -i HEAD~4 && + git log --oneline >actual && + test_line_count = 3 actual && + git diff --exit-code final-squash-instFmt && + echo 1 >expect && + git cat-file blob HEAD^:file1 >actual && + test_cmp expect actual && + git cat-file commit HEAD^ >commit && + ! grep "squash" commit && + grep first commit >actual && + test_line_count = 3 actual +' + +test_expect_success 'autosquash with empty custom instructionFormat' ' + git reset --hard base && + test_commit empty-instructionFormat-test && + ( + set_cat_todo_editor && + test_must_fail git -c rebase.instructionFormat= \ + rebase --autosquash --force-rebase -i HEAD^ >actual && + git log -1 --format="pick %h %s" >expect && + test_cmp expect actual + ) +' + +set_backup_editor () { + write_script backup-editor.sh <<-\EOF + cp "$1" .git/backup-"$(basename "$1")" + EOF + test_set_editor "$PWD/backup-editor.sh" +} + +test_expect_success 'autosquash with multiple empty patches' ' + test_tick && + git commit --allow-empty -m "empty" && + test_tick && + git commit --allow-empty -m "empty2" && + test_tick && + >fixup && + git add fixup && + git commit --fixup HEAD^^ && + ( + set_backup_editor && + GIT_USE_REBASE_HELPER=false \ + git rebase -i --force-rebase --autosquash HEAD~4 && + grep empty2 .git/backup-git-rebase-todo + ) +' + +test_expect_success 'extra spaces after fixup!' ' + base=$(git rev-parse HEAD) && + test_commit to-fixup && + git commit --allow-empty -m "fixup! to-fixup" && + git rebase -i --autosquash --keep-empty HEAD~2 && + parent=$(git rev-parse HEAD^) && + test $base = $parent +' + +test_expect_success 'wrapped original subject' ' + if test -d .git/rebase-merge; then git rebase --abort; fi && + base=$(git rev-parse HEAD) && + echo "wrapped subject" >wrapped && + git add wrapped && + test_tick && + git commit --allow-empty -m "$(printf "To\nfixup")" && + test_tick && + git commit --allow-empty -m "fixup! To fixup" && + git rebase -i --autosquash --keep-empty HEAD~2 && + parent=$(git rev-parse HEAD^) && + test $base = $parent +' + +test_expect_success 'abort last squash' ' + test_when_finished "test_might_fail git rebase --abort" && + test_when_finished "git checkout main" && + + git checkout -b some-squashes && + git commit --allow-empty -m first && + git commit --allow-empty --squash HEAD && + git commit --allow-empty -m second && + git commit --allow-empty --squash HEAD && + + test_must_fail git -c core.editor="grep -q ^pick" \ + rebase -ki --autosquash HEAD~4 && + : do not finish the squash, but resolve it manually && + git commit --allow-empty --amend -m edited-first && + git rebase --skip && + git show >actual && + ! grep first actual +' + +test_expect_success 'fixup a fixup' ' + echo 0to-fixup >file0 && + test_tick && + git commit -m "to-fixup" file0 && + test_tick && + git commit --squash HEAD -m X --allow-empty && + test_tick && + git commit --squash HEAD^ -m Y --allow-empty && + test_tick && + git commit -m "squash! $(git rev-parse HEAD^)" -m Z --allow-empty && + test_tick && + git commit -m "squash! $(git rev-parse HEAD^^)" -m W --allow-empty && + git rebase -ki --autosquash HEAD~5 && + test XZWY = $(git show | tr -cd W-Z) +' + +test_expect_success 'fixup does not clean up commit message' ' + oneline="#818" && + git commit --allow-empty -m "$oneline" && + git commit --fixup HEAD --allow-empty && + git -c commit.cleanup=strip rebase -ki --autosquash HEAD~2 && + test "$oneline" = "$(git show -s --format=%s)" +' + +test_done |