| #!/bin/sh | |
| test_description='merge simplification' | |
| GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main | |
| export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME | |
| . ./test-lib.sh | |
| note () { | |
| git tag "$1" | |
| } | |
| unnote () { | |
| test_when_finished "rm -f tmp" && | |
| git name-rev --tags --annotate-stdin >tmp && | |
| sed -e "s|$OID_REGEX (tags/\([^)]*\)) |\1 |g" <tmp | |
| } | |
| # | |
| # Create a test repo with an interesting commit graph: | |
| # | |
| # A-----B-----G--H--I--K--L | |
| # \ \ / / | |
| # \ \ / / | |
| # C--D--E--F J | |
| # | |
| # The commits are laid out from left-to-right starting with | |
| # the root commit A and terminating at the tip commit L. | |
| # | |
| # There are a few places where we adjust the commit date or | |
| # author date to make the --topo-order, --date-order, and | |
| # --author-date-order flags produce different output. | |
| test_expect_success setup ' | |
| echo "Hi there" >file && | |
| echo "initial" >lost && | |
| git add file lost && | |
| test_tick && git commit -m "Initial file and lost" && | |
| note A && | |
| git branch other-branch && | |
| git symbolic-ref HEAD refs/heads/unrelated && | |
| git rm -f "*" && | |
| echo "Unrelated branch" >side && | |
| git add side && | |
| test_tick && git commit -m "Side root" && | |
| note J && | |
| git checkout main && | |
| echo "Hello" >file && | |
| echo "second" >lost && | |
| git add file lost && | |
| test_tick && GIT_AUTHOR_DATE=$(($test_tick + 120)) git commit -m "Modified file and lost" && | |
| note B && | |
| git checkout other-branch && | |
| echo "Hello" >file && | |
| >lost && | |
| git add file lost && | |
| test_tick && git commit -m "Modified the file identically" && | |
| note C && | |
| echo "This is a stupid example" >another-file && | |
| git add another-file && | |
| test_tick && git commit -m "Add another file" && | |
| note D && | |
| test_tick && | |
| test_must_fail git merge -m "merge" main && | |
| >lost && git commit -a -m "merge" && | |
| note E && | |
| echo "Yet another" >elif && | |
| git add elif && | |
| test_tick && git commit -m "Irrelevant change" && | |
| note F && | |
| git checkout main && | |
| echo "Yet another" >elif && | |
| git add elif && | |
| test_tick && git commit -m "Another irrelevant change" && | |
| note G && | |
| test_tick && git merge -m "merge" other-branch && | |
| note H && | |
| echo "Final change" >file && | |
| test_tick && git commit -a -m "Final change" && | |
| note I && | |
| git checkout main && | |
| test_tick && git merge --allow-unrelated-histories -m "Coolest" unrelated && | |
| note K && | |
| echo "Immaterial" >elif && | |
| git add elif && | |
| test_tick && git commit -m "Last" && | |
| note L | |
| ' | |
| FMT='tformat:%P %H | %s' | |
| check_outcome () { | |
| outcome=$1 | |
| shift | |
| for c in $1 | |
| do | |
| echo "$c" | |
| done >expect && | |
| shift && | |
| param="$*" && | |
| test_expect_$outcome "log $param" ' | |
| git log --pretty="$FMT" --parents $param >out && | |
| unnote >actual <out && | |
| sed -e "s/^.* \([^ ]*\) .*/\1/" >check <actual && | |
| test_cmp expect check | |
| ' | |
| } | |
| check_result () { | |
| check_outcome success "$@" | |
| } | |
| check_result 'L K J I H F E D C G B A' --full-history --topo-order | |
| check_result 'L K I H G F E D C B J A' --full-history | |
| check_result 'L K I H G F E D C B J A' --full-history --date-order | |
| check_result 'L K I H G F E D B C J A' --full-history --author-date-order | |
| check_result 'K I H E C B A' --full-history -- file | |
| check_result 'K I H E C B A' --full-history --topo-order -- file | |
| check_result 'K I H E C B A' --full-history --date-order -- file | |
| check_result 'K I H E B C A' --full-history --author-date-order -- file | |
| check_result 'I E C B A' --simplify-merges -- file | |
| check_result 'I E C B A' --simplify-merges --topo-order -- file | |
| check_result 'I E C B A' --simplify-merges --date-order -- file | |
| check_result 'I E B C A' --simplify-merges --author-date-order -- file | |
| check_result 'I B A' -- file | |
| check_result 'I B A' --topo-order -- file | |
| check_result 'I B A' --date-order -- file | |
| check_result 'I B A' --author-date-order -- file | |
| check_result 'H' --first-parent -- another-file | |
| check_result 'H' --first-parent --topo-order -- another-file | |
| check_result 'L K I H G B A' --first-parent L | |
| check_result 'F E D C' --exclude-first-parent-only F ^L | |
| check_result '' F ^L | |
| check_result 'L K I H G J' L ^F | |
| check_result 'L K I H G B J' --exclude-first-parent-only L ^F | |
| check_result 'L K I H G B' --exclude-first-parent-only --first-parent L ^F | |
| check_result 'E C B A' --full-history E -- lost | |
| test_expect_success 'full history simplification without parent' ' | |
| printf "%s\n" E C B A >expect && | |
| git log --pretty="$FMT" --full-history E -- lost >out && | |
| unnote >actual <out && | |
| sed -e "s/^.* \([^ ]*\) .*/\1/" >check <actual && | |
| test_cmp expect check | |
| ' | |
| test_expect_success '--full-diff is not affected by --parents' ' | |
| git log -p --pretty="%H" --full-diff -- file >expected && | |
| git log -p --pretty="%H" --full-diff --parents -- file >actual && | |
| test_cmp expected actual | |
| ' | |
| # | |
| # Create a new history to demonstrate the value of --show-pulls | |
| # with respect to the subtleties of simplified history, --full-history, | |
| # and --simplify-merges. | |
| # | |
| # .-A---M-----C--N---O---P | |
| # / / \ \ \/ / / | |
| # I B \ R-'`-Z' / | |
| # \ / \/ / | |
| # \ / /\ / | |
| # `---X--' `---Y--' | |
| # | |
| # This example is explained in Documentation/rev-list-options.adoc | |
| test_expect_success 'setup rebuild repo' ' | |
| rm -rf .git * && | |
| git init && | |
| git switch -c topic && | |
| echo base >file && | |
| git add file && | |
| test_commit I && | |
| echo A >file && | |
| git add file && | |
| test_commit A && | |
| git switch -c branchB I && | |
| echo B >file && | |
| git add file && | |
| test_commit B && | |
| git switch topic && | |
| test_must_fail git merge -m "M" B && | |
| echo A >file && | |
| echo B >>file && | |
| git add file && | |
| git merge --continue && | |
| note M && | |
| echo C >other && | |
| git add other && | |
| test_commit C && | |
| git switch -c branchX I && | |
| echo X >file && | |
| git add file && | |
| test_commit X && | |
| git switch -c branchR M && | |
| git merge -m R -Xtheirs X && | |
| note R && | |
| git switch topic && | |
| git merge -m N R && | |
| note N && | |
| git switch -c branchY M && | |
| echo Y >y && | |
| git add y && | |
| test_commit Y && | |
| git switch -c branchZ C && | |
| echo Z >z && | |
| git add z && | |
| test_commit Z && | |
| git switch topic && | |
| git merge -m O Z && | |
| note O && | |
| git merge -m P Y && | |
| note P | |
| ' | |
| check_result 'X I' -- file | |
| check_result 'N R X I' --show-pulls -- file | |
| check_result 'P O N R X M B A I' --full-history --topo-order -- file | |
| check_result 'N R X M B A I' --simplify-merges --topo-order --show-pulls -- file | |
| check_result 'R X M B A I' --simplify-merges --topo-order -- file | |
| check_result 'N M A I' --first-parent -- file | |
| check_result 'N M A I' --first-parent --show-pulls -- file | |
| # --ancestry-path implies --full-history | |
| check_result 'P O N R M' --topo-order \ | |
| --ancestry-path A..HEAD -- file | |
| check_result 'P O N R M' --topo-order \ | |
| --show-pulls \ | |
| --ancestry-path A..HEAD -- file | |
| check_result 'P O N R M' --topo-order \ | |
| --full-history \ | |
| --ancestry-path A..HEAD -- file | |
| check_result 'R M' --topo-order \ | |
| --simplify-merges \ | |
| --ancestry-path A..HEAD -- file | |
| check_result 'N R M' --topo-order \ | |
| --simplify-merges --show-pulls \ | |
| --ancestry-path A..HEAD -- file | |
| test_expect_success 'log --graph --simplify-merges --show-pulls' ' | |
| cat >expect <<-\EOF && | |
| * N | |
| * R | |
| |\ | |
| | * X | |
| * | M | |
| |\ \ | |
| | * | B | |
| | |/ | |
| * / A | |
| |/ | |
| * I | |
| EOF | |
| git log --graph --pretty="%s" \ | |
| --simplify-merges --show-pulls \ | |
| -- file >actual && | |
| test_cmp expect actual | |
| ' | |
| test_expect_success 'exclude-first-parent-only with parent already seen' ' | |
| git checkout --orphan test-seen && | |
| git rm -rf . && | |
| test_commit r1 && | |
| git checkout -b branch-f && | |
| test_commit f && | |
| git checkout test-seen && | |
| git merge --no-ff --no-edit -m r2 branch-f && | |
| git tag r2 && | |
| git rev-list --exclude-first-parent-only f ^r2 >actual && | |
| git rev-parse f >expect && | |
| test_cmp expect actual && | |
| git rev-list --exclude-first-parent-only f r1 ^r2 >actual2 && | |
| test_cmp expect actual2 | |
| ' | |
| test_done |