#!/bin/sh # # ,---E--. *H----------. * marks !TREESAME parent paths # / \ / \* # *A--*B---D--*F-*G---------K-*L-*M # \ /* \ / # `-C-' `-*I-*J # # A creates "file", B and F change it. # Odd merge G takes the old version from B. # I changes it, but J reverts it, so K is TREESAME to both parents. # H and L both change "file", and M merges those changes. global test_description := ''TREESAME and limiting'' source ./test-lib.sh proc note { git tag $1 } proc unnote { git name-rev --tags --stdin | sed -e "s|$_x40 (tags/\([^)]*\))\([ ]\)|\1\2|g" } test_expect_success setup ' test_commit "Initial file" file "Hi there" A && git branch other-branch && test_commit "file=Hello" file "Hello" B && git branch third-branch && git checkout other-branch && test_commit "Added other" other "Hello" C && git checkout master && test_merge D other-branch && git checkout third-branch && test_commit "Third file" third "Nothing" E && git checkout master && test_commit "file=Blah" file "Blah" F && test_tick && git merge --no-commit third-branch && git checkout third-branch file && git commit && note G && git branch fiddler-branch && git checkout -b part2-branch && test_commit "file=Part 2" file "Part 2" H && git checkout fiddler-branch && test_commit "Bad commit" file "Silly" I && test_tick && git revert I && note J && git checkout master && test_tick && git merge --no-ff fiddler-branch && note K && test_commit "file=Part 1" file "Part 1" L && test_tick && test_must_fail git merge part2-branch && test_commit M file "Parts 1+2" ' proc check_outcome { global outcome := $1 shift matchstr $1 { *"("* { global FMT := '"%P %H | %s'" global munge_actual := '" s/^\([^ ]*\) \([^ ]*\) .*/(\1)\2/ s/ //g s/()// '" } * { global FMT := '"%H | %s'" global munge_actual := '"s/^\([^ ]*\) .*/\1/'" } } && printf "%s\n" $1 >expect && shift global param := "$ifsjoin(Argv)" && test_expect_$outcome "log $param" ' git log --format="$FMT" $param | unnote >actual && sed -e "$munge_actual" check && test_cmp expect check ' } proc check_result { check_outcome success @Argv } # Odd merge G drops a change in F. Important that G is listed in all # except the most basic list. Achieving this means normal merge D will also be # shown in normal full-history, as we can't distinguish unless we do a # simplification pass. After simplification, D is dropped but G remains. # Also, merge simplification of G should not drop the parent B that the default # simple history follows. check_result 'M L K J I H G F E D C B A' check_result '(LH)M (K)L (GJ)K (I)J (G)I (G)H (FE)G (D)F (B)E (BC)D (A)C (A)B A' check_result 'M H L K J I G E F D C B A' --topo-order check_result 'M L H B A' -- file check_result '(LH)M (B)L (B)H (A)B A' --parents -- file check_result 'M L J I H G F D B A' --full-history -- file check_result '(LH)M (K)L (GJ)K (I)J (G)I (G)H (FB)G (D)F (BA)D (A)B A' --full-history --parents -- file check_result '(LH)M (G)H (J)L (I)J (G)I (FB)G (B)F (A)B A' --simplify-merges -- file check_result 'M L K G F D B A' --first-parent check_result 'M L G F B A' --first-parent -- file # Check that odd merge G remains shown when F is the bottom. check_result 'M L K J I H G E' F..M check_result 'M H L K J I G E' F..M --topo-order check_result 'M L H' F..M -- file check_result '(LH)M (B)L (B)H' --parents F..M -- file check_result 'M L J I H G' F..M --full-history -- file check_result '(LH)M (K)L (GJ)K (I)J (G)I (G)H (FB)G' F..M --full-history --parents -- file check_result '(LH)M (G)H (J)L (I)J (G)I (FB)G' F..M --simplify-merges -- file check_result 'M L K J I H G' F..M --ancestry-path check_result 'M L J I H G' F..M --ancestry-path -- file check_result '(LH)M (K)L (GJ)K (I)J (G)I (G)H (FE)G' F..M --ancestry-path --parents -- file check_result '(LH)M (G)H (J)L (I)J (G)I (FE)G' F..M --ancestry-path --simplify-merges -- file check_result 'M L K G' F..M --first-parent check_result 'M L G' F..M --first-parent -- file # Note that G is pruned when E is the bottom, even if it's the same commit list # If we want history since E, then we're quite happy to ignore G that took E. check_result 'M L K J I H G' E..M --ancestry-path check_result 'M L J I H' E..M --ancestry-path -- file check_result '(LH)M (K)L (EJ)K (I)J (E)I (E)H' E..M --ancestry-path --parents -- file check_result '(LH)M (E)H (J)L (I)J (E)I' E..M --ancestry-path --simplify-merges -- file # Should still be able to ignore I-J branch in simple log, despite limiting # to G. check_result 'M L K J I H' G..M check_result 'M H L K J I' G..M --topo-order check_result 'M L H' G..M -- file check_result '(LH)M (G)L (G)H' G..M --parents -- file check_result 'M L J I H' G..M --full-history -- file check_result 'M L K J I H' G..M --full-history --parents -- file check_result 'M H L J I' G..M --simplify-merges -- file check_result 'M L K J I H' G..M --ancestry-path check_result 'M L J I H' G..M --ancestry-path -- file check_result 'M L K J I H' G..M --ancestry-path --parents -- file check_result 'M H L J I' G..M --ancestry-path --simplify-merges -- file # B..F should be able to simplify the merge D from irrelevant side branch C. # Default log should also be free to follow B-D, and ignore C. # But --full-history shouldn't drop D on its own - without simplification, # we can't decide if the merge from INTERESTING commit C was sensible. check_result 'F D C' B..F check_result 'F' B..F -- file check_result '(B)F' B..F --parents -- file check_result 'F D' B..F --full-history -- file check_result '(D)F (BA)D' B..F --full-history --parents -- file check_result '(B)F' B..F --simplify-merges -- file check_result 'F D' B..F --ancestry-path check_result 'F' B..F --ancestry-path -- file check_result 'F' B..F --ancestry-path --parents -- file check_result 'F' B..F --ancestry-path --simplify-merges -- file check_result 'F D' B..F --first-parent check_result 'F' B..F --first-parent -- file # E...F should be equivalent to E F ^B, and be able to drop D as above. check_result 'F' E F ^B -- file # includes D check_result 'F' E...F -- file # includes D # Any sort of full history of C..F should show D, as it's the connection to C, # and it differs from it. check_result 'F D B' C..F check_result 'F B' C..F -- file check_result '(B)F (A)B' C..F --parents -- file check_result 'F D B' C..F --full-history -- file check_result '(D)F (BC)D (A)B' C..F --full-history --parents -- file check_result '(D)F (BC)D (A)B' C..F --simplify-merges -- file check_result 'F D' C..F --ancestry-path check_result 'F D' C..F --ancestry-path -- file check_result 'F D' C..F --ancestry-path --parents -- file check_result 'F D' C..F --ancestry-path --simplify-merges -- file check_result 'F D B' C..F --first-parent check_result 'F B' C..F --first-parent -- file test_done (CommandList children: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:test_description) op: Equal rhs: {(SQ <"TREESAME and limiting">)} spids: [37] ) ] spids: [37] ) (C {(.)} {(./test-lib.sh)}) (FuncDef name: note body: (BraceGroup children:[(C {(git)} {(tag)} {(DQ ($ VSub_Number "$1"))})] spids:[53]) spids: [48 52] ) (FuncDef name: unnote body: (BraceGroup children: [ (Pipeline children: [ (C {(git)} {(name-rev)} {(--tags)} {(--stdin)}) (C {(sed)} {(-e)} { (DQ ("s|") ($ VSub_Name "$_x40") (" (tags/") (EscapedLiteralPart token:) ("[^)]*") (EscapedLiteralPart token:) (")") (EscapedLiteralPart token:) ("[ \t]") (EscapedLiteralPart token:) ("|") (EscapedLiteralPart token:) (EscapedLiteralPart token:) ("|g") ) } ) ] negated: False ) ] spids: [72] ) spids: [67 71] ) (C {(test_expect_success)} {(setup)} { (SQ <"\n"> <"\ttest_commit \"Initial file\" file \"Hi there\" A &&\n"> <"\tgit branch other-branch &&\n"> <"\n"> <"\ttest_commit \"file=Hello\" file \"Hello\" B &&\n"> <"\tgit branch third-branch &&\n"> <"\n"> <"\tgit checkout other-branch &&\n"> <"\ttest_commit \"Added other\" other \"Hello\" C &&\n"> <"\n"> <"\tgit checkout master &&\n"> <"\ttest_merge D other-branch &&\n"> <"\n"> <"\tgit checkout third-branch &&\n"> <"\ttest_commit \"Third file\" third \"Nothing\" E &&\n"> <"\n"> <"\tgit checkout master &&\n"> <"\ttest_commit \"file=Blah\" file \"Blah\" F &&\n"> <"\n"> <"\ttest_tick && git merge --no-commit third-branch &&\n"> <"\tgit checkout third-branch file &&\n"> <"\tgit commit &&\n"> <"\tnote G &&\n"> <"\tgit branch fiddler-branch &&\n"> <"\n"> <"\tgit checkout -b part2-branch &&\n"> <"\ttest_commit \"file=Part 2\" file \"Part 2\" H &&\n"> <"\n"> <"\tgit checkout fiddler-branch &&\n"> <"\ttest_commit \"Bad commit\" file \"Silly\" I &&\n"> <"\n"> <"\ttest_tick && git revert I && note J &&\n"> <"\n"> <"\tgit checkout master &&\n"> <"\ttest_tick && git merge --no-ff fiddler-branch &&\n"> <"\tnote K &&\n"> <"\n"> <"\ttest_commit \"file=Part 1\" file \"Part 1\" L &&\n"> <"\n"> <"\ttest_tick && test_must_fail git merge part2-branch &&\n"> <"\ttest_commit M file \"Parts 1+2\"\n"> ) } ) (FuncDef name: check_outcome body: (BraceGroup children: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:outcome) op: Equal rhs: {($ VSub_Number "$1")} spids: [166] ) ] spids: [166] ) (C {(shift)}) (AndOr children: [ (Case to_match: {(DQ ($ VSub_Number "$1"))} arms: [ (case_arm pat_list: [{(Lit_Other "*") (DQ ("(")) (Lit_Other "*")}] action: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:FMT) op: Equal rhs: {(DQ ("%P\t%H | %s"))} spids: [191] ) ] spids: [191] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:munge_actual) op: Equal rhs: { (DQ ("\n") ("\t\t\ts/^") (EscapedLiteralPart token: ) ("[^\t]*") (EscapedLiteralPart token:) ("\t") (EscapedLiteralPart token: ) ("[^ ]*") (EscapedLiteralPart token:) (" .*/(") (EscapedLiteralPart token: ) (")") (EscapedLiteralPart token:) ("/\n") ("\t\t\ts/ //g\n") ("\t\t\ts/()//\n") ("\t\t") ) } spids: [197] ) ] spids: [197] ) ] spids: [183 188 219 -1] ) (case_arm pat_list: [{(Lit_Other "*")}] action: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:FMT) op: Equal rhs: {(DQ ("%H | %s"))} spids: [226] ) ] spids: [226] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:munge_actual) op: Equal rhs: { (DQ ("s/^") (EscapedLiteralPart token:) ("[^ ]*") (EscapedLiteralPart token:) (" .*/") (EscapedLiteralPart token: ) (/) ) } spids: [232] ) ] spids: [232] ) ] spids: [222 223 244 -1] ) ] spids: [174 180 247] ) (AndOr children: [ (SimpleCommand words: [ {(printf)} {(DQ ("%s") (EscapedLiteralPart token:))} {($ VSub_Number "$1")} ] redirects: [(Redir op_id:Redir_Great fd:-1 arg_word:{(expect)} spids:[261])] ) (C {(shift)}) ] op_id: Op_DAmp ) ] op_id: Op_DAmp ) (AndOr children: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:param) op: Equal rhs: {(DQ ($ VSub_Star "$*"))} spids: [271] ) ] spids: [271] ) (C {(test_expect_) ($ VSub_Name "$outcome")} {(DQ ("log ") ($ VSub_Name "$param"))} { (SQ <"\n"> <"\t\tgit log --format=\"$FMT\" $param |\n"> <"\t\tunnote >actual &&\n"> <"\t\tsed -e \"$munge_actual\" check &&\n"> <"\t\ttest_cmp expect check\n"> <"\t"> ) } ) ] op_id: Op_DAmp ) ] spids: [163] ) spids: [158 162] ) (FuncDef name: check_result body: (BraceGroup children: [(C {(check_outcome)} {(success)} {(DQ ($ VSub_At "$@"))})] spids: [304] ) spids: [299 303] ) (C {(check_result)} {(SQ <"M L K J I H G F E D C B A">)}) (C {(check_result)} {(SQ <"(LH)M (K)L (GJ)K (I)J (G)I (G)H (FE)G (D)F (B)E (BC)D (A)C (A)B A">)}) (C {(check_result)} {(SQ <"M H L K J I G E F D C B A">)} {(--topo-order)}) (C {(check_result)} {(SQ <"M L H B A">)} {(--)} {(file)}) (C {(check_result)} {(SQ <"(LH)M (B)L (B)H (A)B A">)} {(--parents)} {(--)} {(file)}) (C {(check_result)} {(SQ <"M L J I H G F D B A">)} {(--full-history)} {(--)} {(file)}) (C {(check_result)} {(SQ <"(LH)M (K)L (GJ)K (I)J (G)I (G)H (FB)G (D)F (BA)D (A)B A">)} {(--full-history)} {(--parents)} {(--)} {(file)} ) (C {(check_result)} {(SQ <"(LH)M (G)H (J)L (I)J (G)I (FB)G (B)F (A)B A">)} {(--simplify-merges)} {(--)} {(file)} ) (C {(check_result)} {(SQ <"M L K G F D B A">)} {(--first-parent)}) (C {(check_result)} {(SQ <"M L G F B A">)} {(--first-parent)} {(--)} {(file)}) (C {(check_result)} {(SQ <"M L K J I H G E">)} {(F..M)}) (C {(check_result)} {(SQ <"M H L K J I G E">)} {(F..M)} {(--topo-order)}) (C {(check_result)} {(SQ <"M L H">)} {(F..M)} {(--)} {(file)}) (C {(check_result)} {(SQ <"(LH)M (B)L (B)H">)} {(--parents)} {(F..M)} {(--)} {(file)}) (C {(check_result)} {(SQ <"M L J I H G">)} {(F..M)} {(--full-history)} {(--)} {(file)}) (C {(check_result)} {(SQ <"(LH)M (K)L (GJ)K (I)J (G)I (G)H (FB)G">)} {(F..M)} {(--full-history)} {(--parents)} {(--)} {(file)} ) (C {(check_result)} {(SQ <"(LH)M (G)H (J)L (I)J (G)I (FB)G">)} {(F..M)} {(--simplify-merges)} {(--)} {(file)} ) (C {(check_result)} {(SQ <"M L K J I H G">)} {(F..M)} {(--ancestry-path)}) (C {(check_result)} {(SQ <"M L J I H G">)} {(F..M)} {(--ancestry-path)} {(--)} {(file)}) (C {(check_result)} {(SQ <"(LH)M (K)L (GJ)K (I)J (G)I (G)H (FE)G">)} {(F..M)} {(--ancestry-path)} {(--parents)} {(--)} {(file)} ) (C {(check_result)} {(SQ <"(LH)M (G)H (J)L (I)J (G)I (FE)G">)} {(F..M)} {(--ancestry-path)} {(--simplify-merges)} {(--)} {(file)} ) (C {(check_result)} {(SQ <"M L K G">)} {(F..M)} {(--first-parent)}) (C {(check_result)} {(SQ <"M L G">)} {(F..M)} {(--first-parent)} {(--)} {(file)}) (C {(check_result)} {(SQ <"M L K J I H G">)} {(E..M)} {(--ancestry-path)}) (C {(check_result)} {(SQ <"M L J I H">)} {(E..M)} {(--ancestry-path)} {(--)} {(file)}) (C {(check_result)} {(SQ <"(LH)M (K)L (EJ)K (I)J (E)I (E)H">)} {(E..M)} {(--ancestry-path)} {(--parents)} {(--)} {(file)} ) (C {(check_result)} {(SQ <"(LH)M (E)H (J)L (I)J (E)I">)} {(E..M)} {(--ancestry-path)} {(--simplify-merges)} {(--)} {(file)} ) (C {(check_result)} {(SQ <"M L K J I H">)} {(G..M)}) (C {(check_result)} {(SQ <"M H L K J I">)} {(G..M)} {(--topo-order)}) (C {(check_result)} {(SQ <"M L H">)} {(G..M)} {(--)} {(file)}) (C {(check_result)} {(SQ <"(LH)M (G)L (G)H">)} {(G..M)} {(--parents)} {(--)} {(file)}) (C {(check_result)} {(SQ <"M L J I H">)} {(G..M)} {(--full-history)} {(--)} {(file)}) (C {(check_result)} {(SQ <"M L K J I H">)} {(G..M)} {(--full-history)} {(--parents)} {(--)} {(file)}) (C {(check_result)} {(SQ <"M H L J I">)} {(G..M)} {(--simplify-merges)} {(--)} {(file)}) (C {(check_result)} {(SQ <"M L K J I H">)} {(G..M)} {(--ancestry-path)}) (C {(check_result)} {(SQ <"M L J I H">)} {(G..M)} {(--ancestry-path)} {(--)} {(file)}) (C {(check_result)} {(SQ <"M L K J I H">)} {(G..M)} {(--ancestry-path)} {(--parents)} {(--)} {(file)}) (C {(check_result)} {(SQ <"M H L J I">)} {(G..M)} {(--ancestry-path)} {(--simplify-merges)} {(--)} {(file)} ) (C {(check_result)} {(SQ <"F D C">)} {(B..F)}) (C {(check_result)} {(SQ )} {(B..F)} {(--)} {(file)}) (C {(check_result)} {(SQ <"(B)F">)} {(B..F)} {(--parents)} {(--)} {(file)}) (C {(check_result)} {(SQ <"F D">)} {(B..F)} {(--full-history)} {(--)} {(file)}) (C {(check_result)} {(SQ <"(D)F (BA)D">)} {(B..F)} {(--full-history)} {(--parents)} {(--)} {(file)}) (C {(check_result)} {(SQ <"(B)F">)} {(B..F)} {(--simplify-merges)} {(--)} {(file)}) (C {(check_result)} {(SQ <"F D">)} {(B..F)} {(--ancestry-path)}) (C {(check_result)} {(SQ )} {(B..F)} {(--ancestry-path)} {(--)} {(file)}) (C {(check_result)} {(SQ )} {(B..F)} {(--ancestry-path)} {(--parents)} {(--)} {(file)}) (C {(check_result)} {(SQ )} {(B..F)} {(--ancestry-path)} {(--simplify-merges)} {(--)} {(file)}) (C {(check_result)} {(SQ <"F D">)} {(B..F)} {(--first-parent)}) (C {(check_result)} {(SQ )} {(B..F)} {(--first-parent)} {(--)} {(file)}) (C {(check_result)} {(SQ )} {(E)} {(F)} {(Lit_Other "^") (B)} {(--)} {(file)}) (C {(check_result)} {(SQ )} {(E...F)} {(--)} {(file)}) (C {(check_result)} {(SQ <"F D B">)} {(C..F)}) (C {(check_result)} {(SQ <"F B">)} {(C..F)} {(--)} {(file)}) (C {(check_result)} {(SQ <"(B)F (A)B">)} {(C..F)} {(--parents)} {(--)} {(file)}) (C {(check_result)} {(SQ <"F D B">)} {(C..F)} {(--full-history)} {(--)} {(file)}) (C {(check_result)} {(SQ <"(D)F (BC)D (A)B">)} {(C..F)} {(--full-history)} {(--parents)} {(--)} {(file)}) (C {(check_result)} {(SQ <"(D)F (BC)D (A)B">)} {(C..F)} {(--simplify-merges)} {(--)} {(file)}) (C {(check_result)} {(SQ <"F D">)} {(C..F)} {(--ancestry-path)}) (C {(check_result)} {(SQ <"F D">)} {(C..F)} {(--ancestry-path)} {(--)} {(file)}) (C {(check_result)} {(SQ <"F D">)} {(C..F)} {(--ancestry-path)} {(--parents)} {(--)} {(file)}) (C {(check_result)} {(SQ <"F D">)} {(C..F)} {(--ancestry-path)} {(--simplify-merges)} {(--)} {(file)}) (C {(check_result)} {(SQ <"F D B">)} {(C..F)} {(--first-parent)}) (C {(check_result)} {(SQ <"F B">)} {(C..F)} {(--first-parent)} {(--)} {(file)}) (C {(test_done)}) ] )