Merge branch 'en/dir-rename-tests'

More preliminary tests have been added to document desired outcome
of various "directory rename" situations.

* en/dir-rename-tests:
  t6423: more involved rules for renaming directories into each other
  t6423: update directory rename detection tests with new rule
  t6423: more involved directory rename test
  directory-rename-detection.txt: update references to regression tests
This commit is contained in:
Junio C Hamano 2020-11-09 14:06:25 -08:00
Родитель cfdc70b299 c64432aacd
Коммит 0a1cceb9bd
2 изменённых файлов: 560 добавлений и 61 удалений

Просмотреть файл

@ -18,7 +18,8 @@ It is perhaps easiest to start with an example:
More interesting possibilities exist, though, such as: More interesting possibilities exist, though, such as:
* one side of history renames x -> z, and the other renames some file to * one side of history renames x -> z, and the other renames some file to
x/e, causing the need for the merge to do a transitive rename. x/e, causing the need for the merge to do a transitive rename so that
the rename ends up at z/e.
* one side of history renames x -> z, but also renames all files within x. * one side of history renames x -> z, but also renames all files within x.
For example, x/a -> z/alpha, x/b -> z/bravo, etc. For example, x/a -> z/alpha, x/b -> z/bravo, etc.
@ -35,7 +36,7 @@ More interesting possibilities exist, though, such as:
directory itself contained inner directories that were renamed to yet directory itself contained inner directories that were renamed to yet
other locations). other locations).
* combinations of the above; see t/t6043-merge-rename-directories.sh for * combinations of the above; see t/t6423-merge-rename-directories.sh for
various interesting cases. various interesting cases.
Limitations -- applicability of directory renames Limitations -- applicability of directory renames
@ -62,19 +63,19 @@ directory rename detection applies:
Limitations -- detailed rules and testcases Limitations -- detailed rules and testcases
------------------------------------------- -------------------------------------------
t/t6043-merge-rename-directories.sh contains extensive tests and commentary t/t6423-merge-rename-directories.sh contains extensive tests and commentary
which generate and explore the rules listed above. It also lists a few which generate and explore the rules listed above. It also lists a few
additional rules: additional rules:
a) If renames split a directory into two or more others, the directory a) If renames split a directory into two or more others, the directory
with the most renames, "wins". with the most renames, "wins".
b) Avoid directory-rename-detection for a path, if that path is the b) Only apply implicit directory renames to directories if the other side
source of a rename on either side of a merge.
c) Only apply implicit directory renames to directories if the other side
of history is the one doing the renaming. of history is the one doing the renaming.
c) Do not perform directory rename detection for directories which had no
new paths added to them.
Limitations -- support in different commands Limitations -- support in different commands
-------------------------------------------- --------------------------------------------

Просмотреть файл

@ -1277,20 +1277,114 @@ test_expect_success '6a: Tricky rename/delete' '
) )
' '
# Testcase 6b, Same rename done on both sides # Testcase 6b1, Same rename done on both sides
# (Related to testcase 6b2 and 8e)
# Commit O: z/{b,c,d,e}
# Commit A: y/{b,c,d}, x/e
# Commit B: y/{b,c,d}, z/{e,f}
# Expected: y/{b,c,d,f}, x/e
# Note: Directory rename detection says A renamed z/ -> y/ (3 paths renamed
# to y/ and only 1 renamed to x/), therefore the new file 'z/f' in B
# should be moved to 'y/f'.
#
# This is a bit of an edge case where any behavior might surprise users,
# whether that is treating A as renaming z/ -> y/, treating A as renaming
# z/ -> x/, or treating A as not doing any directory rename. However, I
# think this answer is the least confusing and most consistent with the
# rules elsewhere.
#
# A note about z/ -> x/, since it may not be clear how that could come
# about: If we were to ignore files renamed by both sides
# (i.e. z/{b,c,d}), as directory rename detection did in git-2.18 thru
# at least git-2.28, then we would note there are no renames from z/ to
# y/ and one rename from z/ to x/ and thus come to the conclusion that
# A renamed z/ -> x/. This seems more confusing for end users than a
# rename of z/ to y/, it makes directory rename detection behavior
# harder for them to predict. As such, we modified the rule, changed
# the behavior on testcases 6b2 and 8e, and introduced this 6b1 testcase.
test_setup_6b1 () {
test_create_repo 6b1 &&
(
cd 6b1 &&
mkdir z &&
echo b >z/b &&
echo c >z/c &&
echo d >z/d &&
echo e >z/e &&
git add z &&
test_tick &&
git commit -m "O" &&
git branch O &&
git branch A &&
git branch B &&
git checkout A &&
git mv z y &&
mkdir x &&
git mv y/e x/e &&
test_tick &&
git commit -m "A" &&
git checkout B &&
git mv z y &&
mkdir z &&
git mv y/e z/e &&
echo f >z/f &&
git add z/f &&
test_tick &&
git commit -m "B"
)
}
test_expect_failure '6b1: Same renames done on both sides, plus another rename' '
test_setup_6b1 &&
(
cd 6b1 &&
git checkout A^0 &&
git -c merge.directoryRenames=true merge -s recursive B^0 &&
git ls-files -s >out &&
test_line_count = 5 out &&
git ls-files -u >out &&
test_line_count = 0 out &&
git ls-files -o >out &&
test_line_count = 1 out &&
git rev-parse >actual \
HEAD:y/b HEAD:y/c HEAD:y/d HEAD:x/e HEAD:y/f &&
git rev-parse >expect \
O:z/b O:z/c O:z/d O:z/e B:z/f &&
test_cmp expect actual
)
'
# Testcase 6b2, Same rename done on both sides
# (Related to testcases 6c and 8e) # (Related to testcases 6c and 8e)
# Commit O: z/{b,c} # Commit O: z/{b,c}
# Commit A: y/{b,c} # Commit A: y/{b,c}
# Commit B: y/{b,c}, z/d # Commit B: y/{b,c}, z/d
# Expected: y/{b,c}, z/d # Expected: y/{b,c,d}
# Note: If we did directory rename detection here, we'd move z/d into y/, # Alternate: y/{b,c}, z/d
# but B did that rename and still decided to put the file into z/, # Note: Directory rename detection says A renamed z/ -> y/, therefore the new
# so we probably shouldn't apply directory rename detection for it. # file 'z/d' in B should be moved to 'y/d'.
#
# We could potentially ignore the renames of z/{b,c} on side A since
# those were renamed on both sides. However, it's a bit of a corner
# case because what if there was also a z/e that side A moved to x/e
# and side B left alone? If we used the "ignore renames done on both
# sides" logic, then we'd compute that A renamed z/ -> x/, and move
# z/d to x/d. That seems more surprising and uglier than allowing
# the z/ -> y/ rename.
test_setup_6b () { test_setup_6b2 () {
test_create_repo 6b && test_create_repo 6b2 &&
( (
cd 6b && cd 6b2 &&
mkdir z && mkdir z &&
echo b >z/b && echo b >z/b &&
@ -1318,10 +1412,10 @@ test_setup_6b () {
) )
} }
test_expect_success '6b: Same rename done on both sides' ' test_expect_failure '6b2: Same rename done on both sides' '
test_setup_6b && test_setup_6b2 &&
( (
cd 6b && cd 6b2 &&
git checkout A^0 && git checkout A^0 &&
@ -1335,7 +1429,7 @@ test_expect_success '6b: Same rename done on both sides' '
test_line_count = 1 out && test_line_count = 1 out &&
git rev-parse >actual \ git rev-parse >actual \
HEAD:y/b HEAD:y/c HEAD:z/d && HEAD:y/b HEAD:y/c HEAD:y/d &&
git rev-parse >expect \ git rev-parse >expect \
O:z/b O:z/c B:z/d && O:z/b O:z/c B:z/d &&
test_cmp expect actual test_cmp expect actual
@ -1343,7 +1437,7 @@ test_expect_success '6b: Same rename done on both sides' '
' '
# Testcase 6c, Rename only done on same side # Testcase 6c, Rename only done on same side
# (Related to testcases 6b and 8e) # (Related to testcases 6b1, 6b2, and 8e)
# Commit O: z/{b,c} # Commit O: z/{b,c}
# Commit A: z/{b,c} (no change) # Commit A: z/{b,c} (no change)
# Commit B: y/{b,c}, z/d # Commit B: y/{b,c}, z/d
@ -2269,14 +2363,22 @@ test_expect_success '8d: rename/delete...or not?' '
# Notes: In commit A, directory z got renamed to y. In commit B, directory z # Notes: In commit A, directory z got renamed to y. In commit B, directory z
# did NOT get renamed; the directory is still present; instead it is # did NOT get renamed; the directory is still present; instead it is
# considered to have just renamed a subset of paths in directory z # considered to have just renamed a subset of paths in directory z
# elsewhere. However, this is much like testcase 6b (where commit B # elsewhere. This is much like testcase 6b2 (where commit B moves all
# moves all the original paths out of z/ but opted to keep d # the original paths out of z/ but opted to keep d within z/).
# within z/). This makes it hard to judge where d should end up.
# #
# It's possible that users would get confused about this, but what # It was not clear in the past what should be done with this testcase;
# should we do instead? It's not at all clear to me whether z/d or # in fact, I noted that I "just picked one" previously. However,
# y/d or something else is a better resolution here, and other cases # following the new logic for testcase 6b2, we should take the rename
# start getting really tricky, so I just picked one. # and move z/d to y/d.
#
# 6b1, 6b2, and this case are definitely somewhat fuzzy in terms of
# whether they are optimal for end users, but (a) the default for
# directory rename detection is to mark these all as conflicts
# anyway, (b) it feels like this is less prone to higher order corner
# case confusion, and (c) the current algorithm requires less global
# knowledge (i.e. less coupling in the algorithm between renames done
# on both sides) which thus means users are better able to predict
# the behavior, and predict it without computing as many details.
test_setup_8e () { test_setup_8e () {
test_create_repo 8e && test_create_repo 8e &&
@ -3947,31 +4049,35 @@ test_expect_success '12a: Moving one directory hierarchy into another' '
) )
' '
# Testcase 12b, Moving two directory hierarchies into each other # Testcase 12b1, Moving two directory hierarchies into each other
# (Related to testcases 1c and 12c) # (Related to testcases 1c and 12c)
# Commit O: node1/{leaf1, leaf2}, node2/{leaf3, leaf4} # Commit O: node1/{leaf1, leaf2}, node2/{leaf3, leaf4}
# Commit A: node1/{leaf1, leaf2, node2/{leaf3, leaf4}} # Commit A: node1/{leaf1, leaf2, node2/{leaf3, leaf4}}
# Commit B: node2/{leaf3, leaf4, node1/{leaf1, leaf2}} # Commit B: node2/{leaf3, leaf4, node1/{leaf1, leaf2}}
# Expected: node1/node2/node1/{leaf1, leaf2}, # Expected: node1/node2/{leaf3, leaf4}
# node2/node1/node2/{leaf3, leaf4} # node2/node1/{leaf1, leaf2}
# NOTE: Without directory renames, we would expect # NOTE: If there were new files added to the old node1/ or node2/ directories,
# node2/node1/{leaf1, leaf2}, # then we would need to detect renames for those directories and would
# node1/node2/{leaf3, leaf4} # find that:
# with directory rename detection, we note that
# commit A renames node2/ -> node1/node2/ # commit A renames node2/ -> node1/node2/
# commit B renames node1/ -> node2/node1/ # commit B renames node1/ -> node2/node1/
# therefore, applying those directory renames to the initial result # Applying those directory renames to the initial result (making all
# (making all four paths experience a transitive renaming), yields # four paths experience a transitive renaming), yields
# the expected result. # node1/node2/node1/{leaf1, leaf2}
# # node2/node1/node2/{leaf3, leaf4}
# You may ask, is it weird to have two directories rename each other? # as the result. It may be really weird to have two directories
# To which, I can do no more than shrug my shoulders and say that # rename each other, but simple rules give weird results when given
# even simple rules give weird results when given weird inputs. # weird inputs. HOWEVER, the "If" at the beginning of those NOTE was
# false; there were no new files added and thus there is no directory
# rename detection to perform. As such, we just have simple renames
# and the expected answer is:
# node1/node2/{leaf3, leaf4}
# node2/node1/{leaf1, leaf2}
test_setup_12b () { test_setup_12b1 () {
test_create_repo 12b && test_create_repo 12b1 &&
( (
cd 12b && cd 12b1 &&
mkdir -p node1 node2 && mkdir -p node1 node2 &&
echo leaf1 >node1/leaf1 && echo leaf1 >node1/leaf1 &&
@ -3998,10 +4104,10 @@ test_setup_12b () {
) )
} }
test_expect_success '12b: Moving two directory hierarchies into each other' ' test_expect_failure '12b1: Moving two directory hierarchies into each other' '
test_setup_12b && test_setup_12b1 &&
( (
cd 12b && cd 12b1 &&
git checkout A^0 && git checkout A^0 &&
@ -4011,10 +4117,10 @@ test_expect_success '12b: Moving two directory hierarchies into each other' '
test_line_count = 4 out && test_line_count = 4 out &&
git rev-parse >actual \ git rev-parse >actual \
HEAD:node1/node2/node1/leaf1 \ HEAD:node2/node1/leaf1 \
HEAD:node1/node2/node1/leaf2 \ HEAD:node2/node1/leaf2 \
HEAD:node2/node1/node2/leaf3 \ HEAD:node1/node2/leaf3 \
HEAD:node2/node1/node2/leaf4 && HEAD:node1/node2/leaf4 &&
git rev-parse >expect \ git rev-parse >expect \
O:node1/leaf1 \ O:node1/leaf1 \
O:node1/leaf2 \ O:node1/leaf2 \
@ -4024,7 +4130,104 @@ test_expect_success '12b: Moving two directory hierarchies into each other' '
) )
' '
# Testcase 12c, Moving two directory hierarchies into each other w/ content merge # Testcase 12b2, Moving two directory hierarchies into each other
# (Related to testcases 1c and 12c)
# Commit O: node1/{leaf1, leaf2}, node2/{leaf3, leaf4}
# Commit A: node1/{leaf1, leaf2, leaf5, node2/{leaf3, leaf4}}
# Commit B: node2/{leaf3, leaf4, leaf6, node1/{leaf1, leaf2}}
# Expected: node1/node2/{node1/{leaf1, leaf2}, leaf6}
# node2/node1/{node2/{leaf3, leaf4}, leaf5}
# NOTE: Without directory renames, we would expect
# A: node2/leaf3 -> node1/node2/leaf3
# A: node2/leaf1 -> node1/node2/leaf4
# A: Adds node1/leaf5
# B: node1/leaf1 -> node2/node1/leaf1
# B: node1/leaf2 -> node2/node1/leaf2
# B: Adds node2/leaf6
# with directory rename detection, we note that
# commit A renames node2/ -> node1/node2/
# commit B renames node1/ -> node2/node1/
# therefore, applying A's directory rename to the paths added in B gives:
# B: node1/leaf1 -> node1/node2/node1/leaf1
# B: node1/leaf2 -> node1/node2/node1/leaf2
# B: Adds node1/node2/leaf6
# and applying B's directory rename to the paths added in A gives:
# A: node2/leaf3 -> node2/node1/node2/leaf3
# A: node2/leaf1 -> node2/node1/node2/leaf4
# A: Adds node2/node1/leaf5
# resulting in the expected
# node1/node2/{node1/{leaf1, leaf2}, leaf6}
# node2/node1/{node2/{leaf3, leaf4}, leaf5}
#
# You may ask, is it weird to have two directories rename each other?
# To which, I can do no more than shrug my shoulders and say that
# even simple rules give weird results when given weird inputs.
test_setup_12b2 () {
test_create_repo 12b2 &&
(
cd 12b2 &&
mkdir -p node1 node2 &&
echo leaf1 >node1/leaf1 &&
echo leaf2 >node1/leaf2 &&
echo leaf3 >node2/leaf3 &&
echo leaf4 >node2/leaf4 &&
git add node1 node2 &&
test_tick &&
git commit -m "O" &&
git branch O &&
git branch A &&
git branch B &&
git checkout A &&
git mv node2/ node1/ &&
echo leaf5 >node1/leaf5 &&
git add node1/leaf5 &&
test_tick &&
git commit -m "A" &&
git checkout B &&
git mv node1/ node2/ &&
echo leaf6 >node2/leaf6 &&
git add node2/leaf6 &&
test_tick &&
git commit -m "B"
)
}
test_expect_success '12b2: Moving two directory hierarchies into each other' '
test_setup_12b2 &&
(
cd 12b2 &&
git checkout A^0 &&
git -c merge.directoryRenames=true merge -s recursive B^0 &&
git ls-files -s >out &&
test_line_count = 6 out &&
git rev-parse >actual \
HEAD:node1/node2/node1/leaf1 \
HEAD:node1/node2/node1/leaf2 \
HEAD:node2/node1/node2/leaf3 \
HEAD:node2/node1/node2/leaf4 \
HEAD:node2/node1/leaf5 \
HEAD:node1/node2/leaf6 &&
git rev-parse >expect \
O:node1/leaf1 \
O:node1/leaf2 \
O:node2/leaf3 \
O:node2/leaf4 \
A:node1/leaf5 \
B:node2/leaf6 &&
test_cmp expect actual
)
'
# Testcase 12c1, Moving two directory hierarchies into each other w/ content merge
# (Related to testcase 12b) # (Related to testcase 12b)
# Commit O: node1/{ leaf1_1, leaf2_1}, node2/{leaf3_1, leaf4_1} # Commit O: node1/{ leaf1_1, leaf2_1}, node2/{leaf3_1, leaf4_1}
# Commit A: node1/{ leaf1_2, leaf2_2, node2/{leaf3_2, leaf4_2}} # Commit A: node1/{ leaf1_2, leaf2_2, node2/{leaf3_2, leaf4_2}}
@ -4032,13 +4235,13 @@ test_expect_success '12b: Moving two directory hierarchies into each other' '
# Expected: Content merge conflicts for each of: # Expected: Content merge conflicts for each of:
# node1/node2/node1/{leaf1, leaf2}, # node1/node2/node1/{leaf1, leaf2},
# node2/node1/node2/{leaf3, leaf4} # node2/node1/node2/{leaf3, leaf4}
# NOTE: This is *exactly* like 12c, except that every path is modified on # NOTE: This is *exactly* like 12b1, except that every path is modified on
# each side of the merge. # each side of the merge.
test_setup_12c () { test_setup_12c1 () {
test_create_repo 12c && test_create_repo 12c1 &&
( (
cd 12c && cd 12c1 &&
mkdir -p node1 node2 && mkdir -p node1 node2 &&
printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf1\n" >node1/leaf1 && printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf1\n" >node1/leaf1 &&
@ -4069,10 +4272,10 @@ test_setup_12c () {
) )
} }
test_expect_success '12c: Moving one directory hierarchy into another w/ content merge' ' test_expect_failure '12c1: Moving one directory hierarchy into another w/ content merge' '
test_setup_12c && test_setup_12c1 &&
( (
cd 12c && cd 12c1 &&
git checkout A^0 && git checkout A^0 &&
@ -4081,6 +4284,102 @@ test_expect_success '12c: Moving one directory hierarchy into another w/ content
git ls-files -u >out && git ls-files -u >out &&
test_line_count = 12 out && test_line_count = 12 out &&
git rev-parse >actual \
:1:node2/node1/leaf1 \
:1:node2/node1/leaf2 \
:1:node1/node2/leaf3 \
:1:node1/node2/leaf4 \
:2:node2/node1/leaf1 \
:2:node2/node1/leaf2 \
:2:node1/node2/leaf3 \
:2:node1/node2/leaf4 \
:3:node2/node1/leaf1 \
:3:node2/node1/leaf2 \
:3:node1/node2/leaf3 \
:3:node1/node2/leaf4 &&
git rev-parse >expect \
O:node1/leaf1 \
O:node1/leaf2 \
O:node2/leaf3 \
O:node2/leaf4 \
A:node1/leaf1 \
A:node1/leaf2 \
A:node1/node2/leaf3 \
A:node1/node2/leaf4 \
B:node2/node1/leaf1 \
B:node2/node1/leaf2 \
B:node2/leaf3 \
B:node2/leaf4 &&
test_cmp expect actual
)
'
# Testcase 12c2, Moving two directory hierarchies into each other w/ content merge
# (Related to testcase 12b)
# Commit O: node1/{ leaf1_1, leaf2_1}, node2/{leaf3_1, leaf4_1}
# Commit A: node1/{ leaf1_2, leaf2_2, node2/{leaf3_2, leaf4_2}, leaf5}
# Commit B: node2/{node1/{leaf1_3, leaf2_3}, leaf3_3, leaf4_3, leaf6}
# Expected: Content merge conflicts for each of:
# node1/node2/node1/{leaf1, leaf2}
# node2/node1/node2/{leaf3, leaf4}
# plus
# node2/node1/leaf5
# node1/node2/leaf6
# NOTE: This is *exactly* like 12b2, except that every path from O is modified
# on each side of the merge.
test_setup_12c2 () {
test_create_repo 12c2 &&
(
cd 12c2 &&
mkdir -p node1 node2 &&
printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf1\n" >node1/leaf1 &&
printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf2\n" >node1/leaf2 &&
printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf3\n" >node2/leaf3 &&
printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf4\n" >node2/leaf4 &&
git add node1 node2 &&
test_tick &&
git commit -m "O" &&
git branch O &&
git branch A &&
git branch B &&
git checkout A &&
git mv node2/ node1/ &&
for i in `git ls-files`; do echo side A >>$i; done &&
git add -u &&
echo leaf5 >node1/leaf5 &&
git add node1/leaf5 &&
test_tick &&
git commit -m "A" &&
git checkout B &&
git mv node1/ node2/ &&
for i in `git ls-files`; do echo side B >>$i; done &&
git add -u &&
echo leaf6 >node2/leaf6 &&
git add node2/leaf6 &&
test_tick &&
git commit -m "B"
)
}
test_expect_success '12c2: Moving one directory hierarchy into another w/ content merge' '
test_setup_12c2 &&
(
cd 12c2 &&
git checkout A^0 &&
test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 &&
git ls-files -s >out &&
test_line_count = 14 out &&
git ls-files -u >out &&
test_line_count = 12 out &&
git rev-parse >actual \ git rev-parse >actual \
:1:node1/node2/node1/leaf1 \ :1:node1/node2/node1/leaf1 \
:1:node1/node2/node1/leaf2 \ :1:node1/node2/node1/leaf2 \
@ -4093,7 +4392,9 @@ test_expect_success '12c: Moving one directory hierarchy into another w/ content
:3:node1/node2/node1/leaf1 \ :3:node1/node2/node1/leaf1 \
:3:node1/node2/node1/leaf2 \ :3:node1/node2/node1/leaf2 \
:3:node2/node1/node2/leaf3 \ :3:node2/node1/node2/leaf3 \
:3:node2/node1/node2/leaf4 && :3:node2/node1/node2/leaf4 \
:0:node2/node1/leaf5 \
:0:node1/node2/leaf6 &&
git rev-parse >expect \ git rev-parse >expect \
O:node1/leaf1 \ O:node1/leaf1 \
O:node1/leaf2 \ O:node1/leaf2 \
@ -4106,7 +4407,9 @@ test_expect_success '12c: Moving one directory hierarchy into another w/ content
B:node2/node1/leaf1 \ B:node2/node1/leaf1 \
B:node2/node1/leaf2 \ B:node2/node1/leaf2 \
B:node2/leaf3 \ B:node2/leaf3 \
B:node2/leaf4 && B:node2/leaf4 \
A:node1/leaf5 \
B:node2/leaf6 &&
test_cmp expect actual test_cmp expect actual
) )
' '
@ -4227,6 +4530,201 @@ test_expect_success '12e: Rename/merge subdir into the root, variant 2' '
) )
' '
# Testcase 12f, Rebase of patches with big directory rename
# Commit O:
# dir/subdir/{a,b,c,d,e_O,Makefile_TOP_O}
# dir/subdir/tweaked/{f,g,h,Makefile_SUB_O}
# dir/unchanged/<LOTS OF FILES>
# Commit A:
# (Remove f & g, move e into newsubdir, rename dir/->folder/, modify files)
# folder/subdir/{a,b,c,d,Makefile_TOP_A}
# folder/subdir/newsubdir/e_A
# folder/subdir/tweaked/{h,Makefile_SUB_A}
# folder/unchanged/<LOTS OF FILES>
# Commit B1:
# (add newfile.{c,py}, modify underscored files)
# dir/{a,b,c,d,e_B1,Makefile_TOP_B1,newfile.c}
# dir/tweaked/{f,g,h,Makefile_SUB_B1,newfile.py}
# dir/unchanged/<LOTS OF FILES>
# Commit B2:
# (Modify e further, add newfile.rs)
# dir/{a,b,c,d,e_B2,Makefile_TOP_B1,newfile.c,newfile.rs}
# dir/tweaked/{f,g,h,Makefile_SUB_B1,newfile.py}
# dir/unchanged/<LOTS OF FILES>
# Expected:
# B1-picked:
# folder/subdir/{a,b,c,d,Makefile_TOP_Merge1,newfile.c}
# folder/subdir/newsubdir/e_Merge1
# folder/subdir/tweaked/{h,Makefile_SUB_Merge1,newfile.py}
# folder/unchanged/<LOTS OF FILES>
# B2-picked:
# folder/subdir/{a,b,c,d,Makefile_TOP_Merge1,newfile.c,newfile.rs}
# folder/subdir/newsubdir/e_Merge2
# folder/subdir/tweaked/{h,Makefile_SUB_Merge1,newfile.py}
# folder/unchanged/<LOTS OF FILES>
#
# Notes: This testcase happens to exercise lots of the
# optimization-specific codepaths in merge-ort, and also
# demonstrated a failing of the directory rename detection algorithm
# in merge-recursive; newfile.c should not get pushed into
# folder/subdir/newsubdir/, yet merge-recursive put it there because
# the rename of dir/subdir/{a,b,c,d} -> folder/subdir/{a,b,c,d}
# looks like
# dir/ -> folder/,
# whereas the rename of dir/subdir/e -> folder/subdir/newsubdir/e
# looks like
# dir/subdir/ -> folder/subdir/newsubdir/
# and if we note that newfile.c is found in dir/subdir/, we might
# overlook the dir/ -> folder/ rule that has more weight.
test_setup_12f () {
test_create_repo 12f &&
(
cd 12f &&
mkdir -p dir/unchanged &&
mkdir -p dir/subdir/tweaked &&
echo a >dir/subdir/a &&
echo b >dir/subdir/b &&
echo c >dir/subdir/c &&
echo d >dir/subdir/d &&
test_seq 1 10 >dir/subdir/e &&
test_seq 10 20 >dir/subdir/Makefile &&
echo f >dir/subdir/tweaked/f &&
echo g >dir/subdir/tweaked/g &&
echo h >dir/subdir/tweaked/h &&
test_seq 20 30 >dir/subdir/tweaked/Makefile &&
for i in `test_seq 1 88`; do
echo content $i >dir/unchanged/file_$i
done &&
git add . &&
git commit -m "O" &&
git branch O &&
git branch A &&
git branch B &&
git switch A &&
git rm dir/subdir/tweaked/f dir/subdir/tweaked/g &&
test_seq 2 10 >dir/subdir/e &&
test_seq 11 20 >dir/subdir/Makefile &&
test_seq 21 30 >dir/subdir/tweaked/Makefile &&
mkdir dir/subdir/newsubdir &&
git mv dir/subdir/e dir/subdir/newsubdir/ &&
git mv dir folder &&
git add . &&
git commit -m "A" &&
git switch B &&
mkdir dir/subdir/newsubdir/ &&
echo c code >dir/subdir/newfile.c &&
echo python code >dir/subdir/newsubdir/newfile.py &&
test_seq 1 11 >dir/subdir/e &&
test_seq 10 21 >dir/subdir/Makefile &&
test_seq 20 31 >dir/subdir/tweaked/Makefile &&
git add . &&
git commit -m "B1" &&
echo rust code >dir/subdir/newfile.rs &&
test_seq 1 12 >dir/subdir/e &&
git add . &&
git commit -m "B2"
)
}
test_expect_failure '12f: Trivial directory resolve, caching, all kinds of fun' '
test_setup_12f &&
(
cd 12f &&
git checkout A^0 &&
git branch Bmod B &&
git -c merge.directoryRenames=true rebase A Bmod &&
echo Checking the pick of B1... &&
test_must_fail git rev-parse Bmod~1:dir &&
git ls-tree -r Bmod~1 >out &&
test_line_count = 98 out &&
git diff --name-status A Bmod~1 >actual &&
q_to_tab >expect <<-\EOF &&
MQfolder/subdir/Makefile
AQfolder/subdir/newfile.c
MQfolder/subdir/newsubdir/e
AQfolder/subdir/newsubdir/newfile.py
MQfolder/subdir/tweaked/Makefile
EOF
test_cmp expect actual &&
# Three-way merged files
test_seq 2 11 >e_Merge1 &&
test_seq 11 21 >Makefile_TOP &&
test_seq 21 31 >Makefile_SUB &&
git hash-object >expect \
e_Merge1 \
Makefile_TOP \
Makefile_SUB &&
git rev-parse >actual \
Bmod~1:folder/subdir/newsubdir/e \
Bmod~1:folder/subdir/Makefile \
Bmod~1:folder/subdir/tweaked/Makefile &&
test_cmp expect actual &&
# New files showed up at the right location with right contents
git rev-parse >expect \
B~1:dir/subdir/newfile.c \
B~1:dir/subdir/newsubdir/newfile.py &&
git rev-parse >actual \
Bmod~1:folder/subdir/newfile.c \
Bmod~1:folder/subdir/newsubdir/newfile.py &&
test_cmp expect actual &&
# Removed files
test_path_is_missing folder/subdir/tweaked/f &&
test_path_is_missing folder/subdir/tweaked/g &&
# Unchanged files or directories
git rev-parse >actual \
Bmod~1:folder/subdir/a \
Bmod~1:folder/subdir/b \
Bmod~1:folder/subdir/c \
Bmod~1:folder/subdir/d \
Bmod~1:folder/unchanged \
Bmod~1:folder/subdir/tweaked/h &&
git rev-parse >expect \
O:dir/subdir/a \
O:dir/subdir/b \
O:dir/subdir/c \
O:dir/subdir/d \
O:dir/unchanged \
O:dir/subdir/tweaked/h &&
test_cmp expect actual &&
echo Checking the pick of B2... &&
test_must_fail git rev-parse Bmod:dir &&
git ls-tree -r Bmod >out &&
test_line_count = 99 out &&
git diff --name-status Bmod~1 Bmod >actual &&
q_to_tab >expect <<-\EOF &&
AQfolder/subdir/newfile.rs
MQfolder/subdir/newsubdir/e
EOF
test_cmp expect actual &&
# Three-way merged file
test_seq 2 12 >e_Merge2 &&
git hash-object e_Merge2 >expect &&
git rev-parse Bmod:folder/subdir/newsubdir/e >actual &&
test_cmp expect actual
)
'
########################################################################### ###########################################################################
# SECTION 13: Checking informational and conflict messages # SECTION 13: Checking informational and conflict messages
# #