#!/bin/sh # # Copyright (c) 2005 Amos Waterland # global test_description := ''git rebase assorted tests This test runs git rebase and checks that the author information is not lost among other things. '' source ./test-lib.sh global GIT_AUTHOR_NAME := 'author@name' global GIT_AUTHOR_EMAIL := 'bogus@email@address' export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL test_expect_success 'prepare repository with topic branches' ' git config core.logAllRefUpdates true && echo First >A && git update-index --add A && git commit -m "Add A." && git checkout -b force-3way && echo Dummy >Y && git update-index --add Y && git commit -m "Add Y." && git checkout -b filemove && git reset --soft master && mkdir D && git mv A D/A && git commit -m "Move A." && git checkout -b my-topic-branch master && echo Second >B && git update-index --add B && git commit -m "Add B." && git checkout -f master && echo Third >>A && git update-index A && git commit -m "Modify A." && git checkout -b side my-topic-branch && echo Side >>C && git add C && git commit -m "Add C" && git checkout -f my-topic-branch && git tag topic ' test_expect_success 'rebase on dirty worktree' ' echo dirty >>A && test_must_fail git rebase master ' test_expect_success 'rebase on dirty cache' ' git add A && test_must_fail git rebase master ' test_expect_success 'rebase against master' ' git reset --hard HEAD && git rebase master ' test_expect_success 'rebase, with and specified as :/quuxery' ' test_when_finished "git branch -D torebase" && git checkout -b torebase my-topic-branch^ && upstream=$(git rev-parse ":/Add B") && onto=$(git rev-parse ":/Add A") && git rebase --onto $onto $upstream && git reset --hard my-topic-branch^ && git rebase --onto ":/Add A" ":/Add B" && git checkout my-topic-branch ' test_expect_success 'the rebase operation should not have destroyed author information' ' ! (git log | grep "Author:" | grep "<>") ' test_expect_success 'the rebase operation should not have destroyed author information (2)' " git log -1 | grep 'Author: $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>' " test_expect_success 'HEAD was detached during rebase' ' test $(git rev-parse HEAD@{1}) != $(git rev-parse my-topic-branch@{1}) ' test_expect_success 'rebase from ambiguous branch name' ' git checkout -b topic side && git rebase master ' test_expect_success 'rebase off of the previous branch using "-"' ' git checkout master && git checkout HEAD^ && git rebase @{-1} >expect.messages && git merge-base master HEAD >expect.forkpoint && git checkout master && git checkout HEAD^ && git rebase - >actual.messages && git merge-base master HEAD >actual.forkpoint && test_cmp expect.forkpoint actual.forkpoint && # the next one is dubious---we may want to say "-", # instead of @{-1}, in the message test_i18ncmp expect.messages actual.messages ' test_expect_success 'rebase a single mode change' ' git checkout master && git branch -D topic && echo 1 >X && git add X && test_tick && git commit -m prepare && git checkout -b modechange HEAD^ && echo 1 >X && git add X && test_chmod +x A && test_tick && git commit -m modechange && GIT_TRACE=1 git rebase master ' test_expect_success 'rebase is not broken by diff.renames' ' test_config diff.renames copies && git checkout filemove && GIT_TRACE=1 git rebase force-3way ' test_expect_success 'setup: recover' ' test_might_fail git rebase --abort && git reset --hard && git checkout modechange ' test_expect_success 'Show verbose error when HEAD could not be detached' ' >B && test_must_fail git rebase topic 2>output.err >output.out && test_i18ngrep "The following untracked working tree files would be overwritten by checkout:" output.err && test_i18ngrep B output.err ' rm -f B test_expect_success 'fail when upstream arg is missing and not on branch' ' git checkout topic && test_must_fail git rebase ' test_expect_success 'fail when upstream arg is missing and not configured' ' git checkout -b no-config topic && test_must_fail git rebase ' test_expect_success 'default to common base in @{upstream}s reflog if no upstream arg' ' git checkout -b default-base master && git checkout -b default topic && git config branch.default.remote . && git config branch.default.merge refs/heads/default-base && git rebase && git rev-parse --verify default-base >expect && git rev-parse default~1 >actual && test_cmp expect actual && git checkout default-base && git reset --hard HEAD^ && git checkout default && git rebase && git rev-parse --verify default-base >expect && git rev-parse default~1 >actual && test_cmp expect actual ' test_expect_success 'cherry-picked commits and fork-point work together' ' git checkout default-base && echo Amended >A && git commit -a --no-edit --amend && test_commit B B && test_commit new_B B "New B" && test_commit C C && git checkout default && git reset --hard default-base@{4} && test_commit D D && git cherry-pick -2 default-base^ && test_commit final_B B "Final B" && git rebase && echo Amended >expect && test_cmp A expect && echo "Final B" >expect && test_cmp B expect && echo C >expect && test_cmp C expect && echo D >expect && test_cmp D expect ' test_expect_success 'rebase -q is quiet' ' git checkout -b quiet topic && git rebase -q master >output.out 2>&1 && test_must_be_empty output.out ' test_expect_success 'Rebase a commit that sprinkles CRs in' ' ( echo "One" echo "TwoQ" echo "Three" echo "FQur" echo "Five" ) | q_to_cr >CR && git add CR && test_tick && git commit -a -m "A file with a line with CR" && git tag file-with-cr && git checkout HEAD^0 && git rebase --onto HEAD^^ HEAD^ && git diff --exit-code file-with-cr:CR HEAD:CR ' test_expect_success 'rebase can copy notes' ' git config notes.rewrite.rebase true && git config notes.rewriteRef "refs/notes/*" && test_commit n1 && test_commit n2 && test_commit n3 && git notes add -m"a note" n3 && git rebase --onto n1 n2 && test "a note" = "$(git notes show HEAD)" ' test_expect_success 'rebase -m can copy notes' ' git reset --hard n3 && git rebase -m --onto n1 n2 && test "a note" = "$(git notes show HEAD)" ' test_expect_success 'rebase commit with an ancient timestamp' ' git reset --hard && >old.one && git add old.one && test_tick && git commit --date="@12345 +0400" -m "Old one" && >old.two && git add old.two && test_tick && git commit --date="@23456 +0500" -m "Old two" && >old.three && git add old.three && test_tick && git commit --date="@34567 +0600" -m "Old three" && git cat-file commit HEAD^^ >actual && grep "author .* 12345 +0400$" actual && git cat-file commit HEAD^ >actual && grep "author .* 23456 +0500$" actual && git cat-file commit HEAD >actual && grep "author .* 34567 +0600$" actual && git rebase --onto HEAD^^ HEAD^ && git cat-file commit HEAD >actual && grep "author .* 34567 +0600$" actual ' test_done (CommandList children: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:test_description) op: Equal rhs: { (SQ <"git rebase assorted tests\n"> <"\n"> <"This test runs git rebase and checks that the author information is not lost\n"> <"among other things.\n"> ) } spids: [13] ) ] spids: [13] ) (C {(.)} {(./test-lib.sh)}) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:GIT_AUTHOR_NAME) op: Equal rhs: {(author) (Lit_Other "@") (name)} spids: [26] ) ] spids: [26] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:GIT_AUTHOR_EMAIL) op: Equal rhs: {(bogus) (Lit_Other "@") (email) (Lit_Other "@") (address)} spids: [31] ) ] spids: [31] ) (C {(export)} {(GIT_AUTHOR_NAME)} {(GIT_AUTHOR_EMAIL)}) (C {(test_expect_success)} {(SQ <"prepare repository with topic branches">)} { (SQ <"\n"> <"\tgit config core.logAllRefUpdates true &&\n"> <"\techo First >A &&\n"> <"\tgit update-index --add A &&\n"> <"\tgit commit -m \"Add A.\" &&\n"> <"\tgit checkout -b force-3way &&\n"> <"\techo Dummy >Y &&\n"> <"\tgit update-index --add Y &&\n"> <"\tgit commit -m \"Add Y.\" &&\n"> <"\tgit checkout -b filemove &&\n"> <"\tgit reset --soft master &&\n"> <"\tmkdir D &&\n"> <"\tgit mv A D/A &&\n"> <"\tgit commit -m \"Move A.\" &&\n"> <"\tgit checkout -b my-topic-branch master &&\n"> <"\techo Second >B &&\n"> <"\tgit update-index --add B &&\n"> <"\tgit commit -m \"Add B.\" &&\n"> <"\tgit checkout -f master &&\n"> <"\techo Third >>A &&\n"> <"\tgit update-index A &&\n"> <"\tgit commit -m \"Modify A.\" &&\n"> <"\tgit checkout -b side my-topic-branch &&\n"> <"\techo Side >>C &&\n"> <"\tgit add C &&\n"> <"\tgit commit -m \"Add C\" &&\n"> <"\tgit checkout -f my-topic-branch &&\n"> <"\tgit tag topic\n"> ) } ) (C {(test_expect_success)} {(SQ <"rebase on dirty worktree">)} {(SQ <"\n"> <"\techo dirty >>A &&\n"> <"\ttest_must_fail git rebase master\n">)} ) (C {(test_expect_success)} {(SQ <"rebase on dirty cache">)} {(SQ <"\n"> <"\tgit add A &&\n"> <"\ttest_must_fail git rebase master\n">)} ) (C {(test_expect_success)} {(SQ <"rebase against master">)} {(SQ <"\n"> <"\tgit reset --hard HEAD &&\n"> <"\tgit rebase master\n">)} ) (C {(test_expect_success)} {(SQ <"rebase, with and specified as :/quuxery">)} { (SQ <"\n"> <"\ttest_when_finished \"git branch -D torebase\" &&\n"> <"\tgit checkout -b torebase my-topic-branch^ &&\n"> <"\tupstream=$(git rev-parse \":/Add B\") &&\n"> <"\tonto=$(git rev-parse \":/Add A\") &&\n"> <"\tgit rebase --onto $onto $upstream &&\n"> <"\tgit reset --hard my-topic-branch^ &&\n"> <"\tgit rebase --onto \":/Add A\" \":/Add B\" &&\n"> <"\tgit checkout my-topic-branch\n"> ) } ) (C {(test_expect_success)} {(SQ <"the rebase operation should not have destroyed author information">)} {(SQ <"\n"> <"\t! (git log | grep \"Author:\" | grep \"<>\")\n">)} ) (C {(test_expect_success)} {(SQ <"the rebase operation should not have destroyed author information (2)">)} { (DQ ("\n") ("\tgit log -1 |\n") ("\tgrep 'Author: ") ($ VSub_Name "$GIT_AUTHOR_NAME") (" <") ($ VSub_Name "$GIT_AUTHOR_EMAIL") (">'\n") ) } ) (C {(test_expect_success)} {(SQ <"HEAD was detached during rebase">)} {(SQ <"\n"> <"\ttest $(git rev-parse HEAD@{1}) != $(git rev-parse my-topic-branch@{1})\n">)} ) (C {(test_expect_success)} {(SQ <"rebase from ambiguous branch name">)} {(SQ <"\n"> <"\tgit checkout -b topic side &&\n"> <"\tgit rebase master\n">)} ) (C {(test_expect_success)} {(SQ <"rebase off of the previous branch using \"-\"">)} { (SQ <"\n"> <"\tgit checkout master &&\n"> <"\tgit checkout HEAD^ &&\n"> <"\tgit rebase @{-1} >expect.messages &&\n"> <"\tgit merge-base master HEAD >expect.forkpoint &&\n"> <"\n"> <"\tgit checkout master &&\n"> <"\tgit checkout HEAD^ &&\n"> <"\tgit rebase - >actual.messages &&\n"> <"\tgit merge-base master HEAD >actual.forkpoint &&\n"> <"\n"> <"\ttest_cmp expect.forkpoint actual.forkpoint &&\n"> <"\t# the next one is dubious---we may want to say \"-\",\n"> <"\t# instead of @{-1}, in the message\n"> <"\ttest_i18ncmp expect.messages actual.messages\n"> ) } ) (C {(test_expect_success)} {(SQ <"rebase a single mode change">)} { (SQ <"\n"> <"\tgit checkout master &&\n"> <"\tgit branch -D topic &&\n"> <"\techo 1 >X &&\n"> <"\tgit add X &&\n"> <"\ttest_tick &&\n"> <"\tgit commit -m prepare &&\n"> <"\tgit checkout -b modechange HEAD^ &&\n"> <"\techo 1 >X &&\n"> <"\tgit add X &&\n"> <"\ttest_chmod +x A &&\n"> <"\ttest_tick &&\n"> <"\tgit commit -m modechange &&\n"> <"\tGIT_TRACE=1 git rebase master\n"> ) } ) (C {(test_expect_success)} {(SQ <"rebase is not broken by diff.renames">)} { (SQ <"\n"> <"\ttest_config diff.renames copies &&\n"> <"\tgit checkout filemove &&\n"> <"\tGIT_TRACE=1 git rebase force-3way\n"> ) } ) (C {(test_expect_success)} {(SQ <"setup: recover">)} { (SQ <"\n"> <"\ttest_might_fail git rebase --abort &&\n"> <"\tgit reset --hard &&\n"> <"\tgit checkout modechange\n"> ) } ) (C {(test_expect_success)} {(SQ <"Show verbose error when HEAD could not be detached">)} { (SQ <"\n"> <"\t>B &&\n"> <"\ttest_must_fail git rebase topic 2>output.err >output.out &&\n"> < "\ttest_i18ngrep \"The following untracked working tree files would be overwritten by checkout:\" output.err &&\n" > <"\ttest_i18ngrep B output.err\n"> ) } ) (C {(rm)} {(-f)} {(B)}) (C {(test_expect_success)} {(SQ <"fail when upstream arg is missing and not on branch">)} {(SQ <"\n"> <"\tgit checkout topic &&\n"> <"\ttest_must_fail git rebase\n">)} ) (C {(test_expect_success)} {(SQ <"fail when upstream arg is missing and not configured">)} {(SQ <"\n"> <"\tgit checkout -b no-config topic &&\n"> <"\ttest_must_fail git rebase\n">)} ) (C {(test_expect_success)} {(SQ <"default to common base in @{upstream}s reflog if no upstream arg">)} { (SQ <"\n"> <"\tgit checkout -b default-base master &&\n"> <"\tgit checkout -b default topic &&\n"> <"\tgit config branch.default.remote . &&\n"> <"\tgit config branch.default.merge refs/heads/default-base &&\n"> <"\tgit rebase &&\n"> <"\tgit rev-parse --verify default-base >expect &&\n"> <"\tgit rev-parse default~1 >actual &&\n"> <"\ttest_cmp expect actual &&\n"> <"\tgit checkout default-base &&\n"> <"\tgit reset --hard HEAD^ &&\n"> <"\tgit checkout default &&\n"> <"\tgit rebase &&\n"> <"\tgit rev-parse --verify default-base >expect &&\n"> <"\tgit rev-parse default~1 >actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"cherry-picked commits and fork-point work together">)} { (SQ <"\n"> <"\tgit checkout default-base &&\n"> <"\techo Amended >A &&\n"> <"\tgit commit -a --no-edit --amend &&\n"> <"\ttest_commit B B &&\n"> <"\ttest_commit new_B B \"New B\" &&\n"> <"\ttest_commit C C &&\n"> <"\tgit checkout default &&\n"> <"\tgit reset --hard default-base@{4} &&\n"> <"\ttest_commit D D &&\n"> <"\tgit cherry-pick -2 default-base^ &&\n"> <"\ttest_commit final_B B \"Final B\" &&\n"> <"\tgit rebase &&\n"> <"\techo Amended >expect &&\n"> <"\ttest_cmp A expect &&\n"> <"\techo \"Final B\" >expect &&\n"> <"\ttest_cmp B expect &&\n"> <"\techo C >expect &&\n"> <"\ttest_cmp C expect &&\n"> <"\techo D >expect &&\n"> <"\ttest_cmp D expect\n"> ) } ) (C {(test_expect_success)} {(SQ <"rebase -q is quiet">)} { (SQ <"\n"> <"\tgit checkout -b quiet topic &&\n"> <"\tgit rebase -q master >output.out 2>&1 &&\n"> <"\ttest_must_be_empty output.out\n"> ) } ) (C {(test_expect_success)} {(SQ <"Rebase a commit that sprinkles CRs in">)} { (SQ <"\n"> <"\t(\n"> <"\t\techo \"One\"\n"> <"\t\techo \"TwoQ\"\n"> <"\t\techo \"Three\"\n"> <"\t\techo \"FQur\"\n"> <"\t\techo \"Five\"\n"> <"\t) | q_to_cr >CR &&\n"> <"\tgit add CR &&\n"> <"\ttest_tick &&\n"> <"\tgit commit -a -m \"A file with a line with CR\" &&\n"> <"\tgit tag file-with-cr &&\n"> <"\tgit checkout HEAD^0 &&\n"> <"\tgit rebase --onto HEAD^^ HEAD^ &&\n"> <"\tgit diff --exit-code file-with-cr:CR HEAD:CR\n"> ) } ) (C {(test_expect_success)} {(SQ <"rebase can copy notes">)} { (SQ <"\n"> <"\tgit config notes.rewrite.rebase true &&\n"> <"\tgit config notes.rewriteRef \"refs/notes/*\" &&\n"> <"\ttest_commit n1 &&\n"> <"\ttest_commit n2 &&\n"> <"\ttest_commit n3 &&\n"> <"\tgit notes add -m\"a note\" n3 &&\n"> <"\tgit rebase --onto n1 n2 &&\n"> <"\ttest \"a note\" = \"$(git notes show HEAD)\"\n"> ) } ) (C {(test_expect_success)} {(SQ <"rebase -m can copy notes">)} { (SQ <"\n"> <"\tgit reset --hard n3 &&\n"> <"\tgit rebase -m --onto n1 n2 &&\n"> <"\ttest \"a note\" = \"$(git notes show HEAD)\"\n"> ) } ) (C {(test_expect_success)} {(SQ <"rebase commit with an ancient timestamp">)} { (SQ <"\n"> <"\tgit reset --hard &&\n"> <"\n"> <"\t>old.one && git add old.one && test_tick &&\n"> <"\tgit commit --date=\"@12345 +0400\" -m \"Old one\" &&\n"> <"\t>old.two && git add old.two && test_tick &&\n"> <"\tgit commit --date=\"@23456 +0500\" -m \"Old two\" &&\n"> <"\t>old.three && git add old.three && test_tick &&\n"> <"\tgit commit --date=\"@34567 +0600\" -m \"Old three\" &&\n"> <"\n"> <"\tgit cat-file commit HEAD^^ >actual &&\n"> <"\tgrep \"author .* 12345 +0400$\" actual &&\n"> <"\tgit cat-file commit HEAD^ >actual &&\n"> <"\tgrep \"author .* 23456 +0500$\" actual &&\n"> <"\tgit cat-file commit HEAD >actual &&\n"> <"\tgrep \"author .* 34567 +0600$\" actual &&\n"> <"\n"> <"\tgit rebase --onto HEAD^^ HEAD^ &&\n"> <"\n"> <"\tgit cat-file commit HEAD >actual &&\n"> <"\tgrep \"author .* 34567 +0600$\" actual\n"> ) } ) (C {(test_done)}) ] )