Skip to content

Commit 8536821

Browse files
newrengitster
authored andcommitted
t6423: update directory rename detection tests with new rule
While investigating the issues highlighted by the testcase in the previous patch, I also found a shortcoming in the directory rename detection rules. Split testcase 6b into two to explain this issue and update directory-rename-detection.txt to remove one of the previous rules that I know believe to be detrimental. Also, update the wording around testcase 8e; while we are not modifying the results of that testcase, we were previously unsure of the appropriate resolution of that test and the new rule makes the previously chosen resolution for that testcase a bit more solid. Signed-off-by: Elijah Newren <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 902c521 commit 8536821

File tree

2 files changed

+124
-25
lines changed

2 files changed

+124
-25
lines changed

Documentation/technical/directory-rename-detection.txt

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,7 @@ additional rules:
7070
a) If renames split a directory into two or more others, the directory
7171
with the most renames, "wins".
7272

73-
b) Avoid directory-rename-detection for a path, if that path is the
74-
source of a rename on either side of a merge.
75-
76-
c) Only apply implicit directory renames to directories if the other side
73+
b) Only apply implicit directory renames to directories if the other side
7774
of history is the one doing the renaming.
7875

7976
Limitations -- support in different commands

t/t6423-merge-rename-directories.sh

Lines changed: 123 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,20 +1277,114 @@ test_expect_success '6a: Tricky rename/delete' '
12771277
)
12781278
'
12791279

1280-
# Testcase 6b, Same rename done on both sides
1280+
# Testcase 6b1, Same rename done on both sides
1281+
# (Related to testcase 6b2 and 8e)
1282+
# Commit O: z/{b,c,d,e}
1283+
# Commit A: y/{b,c,d}, x/e
1284+
# Commit B: y/{b,c,d}, z/{e,f}
1285+
# Expected: y/{b,c,d,f}, x/e
1286+
# Note: Directory rename detection says A renamed z/ -> y/ (3 paths renamed
1287+
# to y/ and only 1 renamed to x/), therefore the new file 'z/f' in B
1288+
# should be moved to 'y/f'.
1289+
#
1290+
# This is a bit of an edge case where any behavior might surprise users,
1291+
# whether that is treating A as renaming z/ -> y/, treating A as renaming
1292+
# z/ -> x/, or treating A as not doing any directory rename. However, I
1293+
# think this answer is the least confusing and most consistent with the
1294+
# rules elsewhere.
1295+
#
1296+
# A note about z/ -> x/, since it may not be clear how that could come
1297+
# about: If we were to ignore files renamed by both sides
1298+
# (i.e. z/{b,c,d}), as directory rename detection did in git-2.18 thru
1299+
# at least git-2.28, then we would note there are no renames from z/ to
1300+
# y/ and one rename from z/ to x/ and thus come to the conclusion that
1301+
# A renamed z/ -> x/. This seems more confusing for end users than a
1302+
# rename of z/ to y/, it makes directory rename detection behavior
1303+
# harder for them to predict. As such, we modified the rule, changed
1304+
# the behavior on testcases 6b2 and 8e, and introduced this 6b1 testcase.
1305+
1306+
test_setup_6b1 () {
1307+
test_create_repo 6b1 &&
1308+
(
1309+
cd 6b1 &&
1310+
1311+
mkdir z &&
1312+
echo b >z/b &&
1313+
echo c >z/c &&
1314+
echo d >z/d &&
1315+
echo e >z/e &&
1316+
git add z &&
1317+
test_tick &&
1318+
git commit -m "O" &&
1319+
1320+
git branch O &&
1321+
git branch A &&
1322+
git branch B &&
1323+
1324+
git checkout A &&
1325+
git mv z y &&
1326+
mkdir x &&
1327+
git mv y/e x/e &&
1328+
test_tick &&
1329+
git commit -m "A" &&
1330+
1331+
git checkout B &&
1332+
git mv z y &&
1333+
mkdir z &&
1334+
git mv y/e z/e &&
1335+
echo f >z/f &&
1336+
git add z/f &&
1337+
test_tick &&
1338+
git commit -m "B"
1339+
)
1340+
}
1341+
1342+
test_expect_failure '6b1: Same renames done on both sides, plus another rename' '
1343+
test_setup_6b1 &&
1344+
(
1345+
cd 6b1 &&
1346+
1347+
git checkout A^0 &&
1348+
1349+
git -c merge.directoryRenames=true merge -s recursive B^0 &&
1350+
1351+
git ls-files -s >out &&
1352+
test_line_count = 5 out &&
1353+
git ls-files -u >out &&
1354+
test_line_count = 0 out &&
1355+
git ls-files -o >out &&
1356+
test_line_count = 1 out &&
1357+
1358+
git rev-parse >actual \
1359+
HEAD:y/b HEAD:y/c HEAD:y/d HEAD:x/e HEAD:y/f &&
1360+
git rev-parse >expect \
1361+
O:z/b O:z/c O:z/d O:z/e B:z/f &&
1362+
test_cmp expect actual
1363+
)
1364+
'
1365+
1366+
# Testcase 6b2, Same rename done on both sides
12811367
# (Related to testcases 6c and 8e)
12821368
# Commit O: z/{b,c}
12831369
# Commit A: y/{b,c}
12841370
# Commit B: y/{b,c}, z/d
1285-
# Expected: y/{b,c}, z/d
1286-
# Note: If we did directory rename detection here, we'd move z/d into y/,
1287-
# but B did that rename and still decided to put the file into z/,
1288-
# so we probably shouldn't apply directory rename detection for it.
1289-
1290-
test_setup_6b () {
1291-
test_create_repo 6b &&
1371+
# Expected: y/{b,c,d}
1372+
# Alternate: y/{b,c}, z/d
1373+
# Note: Directory rename detection says A renamed z/ -> y/, therefore the new
1374+
# file 'z/d' in B should be moved to 'y/d'.
1375+
#
1376+
# We could potentially ignore the renames of z/{b,c} on side A since
1377+
# those were renamed on both sides. However, it's a bit of a corner
1378+
# case because what if there was also a z/e that side A moved to x/e
1379+
# and side B left alone? If we used the "ignore renames done on both
1380+
# sides" logic, then we'd compute that A renamed z/ -> x/, and move
1381+
# z/d to x/d. That seems more surprising and uglier than allowing
1382+
# the z/ -> y/ rename.
1383+
1384+
test_setup_6b2 () {
1385+
test_create_repo 6b2 &&
12921386
(
1293-
cd 6b &&
1387+
cd 6b2 &&
12941388

12951389
mkdir z &&
12961390
echo b >z/b &&
@@ -1318,10 +1412,10 @@ test_setup_6b () {
13181412
)
13191413
}
13201414

1321-
test_expect_success '6b: Same rename done on both sides' '
1322-
test_setup_6b &&
1415+
test_expect_failure '6b2: Same rename done on both sides' '
1416+
test_setup_6b2 &&
13231417
(
1324-
cd 6b &&
1418+
cd 6b2 &&
13251419
13261420
git checkout A^0 &&
13271421
@@ -1335,15 +1429,15 @@ test_expect_success '6b: Same rename done on both sides' '
13351429
test_line_count = 1 out &&
13361430
13371431
git rev-parse >actual \
1338-
HEAD:y/b HEAD:y/c HEAD:z/d &&
1432+
HEAD:y/b HEAD:y/c HEAD:y/d &&
13391433
git rev-parse >expect \
13401434
O:z/b O:z/c B:z/d &&
13411435
test_cmp expect actual
13421436
)
13431437
'
13441438

13451439
# Testcase 6c, Rename only done on same side
1346-
# (Related to testcases 6b and 8e)
1440+
# (Related to testcases 6b1, 6b2, and 8e)
13471441
# Commit O: z/{b,c}
13481442
# Commit A: z/{b,c} (no change)
13491443
# Commit B: y/{b,c}, z/d
@@ -2269,14 +2363,22 @@ test_expect_success '8d: rename/delete...or not?' '
22692363
# Notes: In commit A, directory z got renamed to y. In commit B, directory z
22702364
# did NOT get renamed; the directory is still present; instead it is
22712365
# considered to have just renamed a subset of paths in directory z
2272-
# elsewhere. However, this is much like testcase 6b (where commit B
2273-
# moves all the original paths out of z/ but opted to keep d
2274-
# within z/). This makes it hard to judge where d should end up.
2366+
# elsewhere. This is much like testcase 6b2 (where commit B moves all
2367+
# the original paths out of z/ but opted to keep d within z/).
2368+
#
2369+
# It was not clear in the past what should be done with this testcase;
2370+
# in fact, I noted that I "just picked one" previously. However,
2371+
# following the new logic for testcase 6b2, we should take the rename
2372+
# and move z/d to y/d.
22752373
#
2276-
# It's possible that users would get confused about this, but what
2277-
# should we do instead? It's not at all clear to me whether z/d or
2278-
# y/d or something else is a better resolution here, and other cases
2279-
# start getting really tricky, so I just picked one.
2374+
# 6b1, 6b2, and this case are definitely somewhat fuzzy in terms of
2375+
# whether they are optimal for end users, but (a) the default for
2376+
# directory rename detection is to mark these all as conflicts
2377+
# anyway, (b) it feels like this is less prone to higher order corner
2378+
# case confusion, and (c) the current algorithm requires less global
2379+
# knowledge (i.e. less coupling in the algorithm between renames done
2380+
# on both sides) which thus means users are better able to predict
2381+
# the behavior, and predict it without computing as many details.
22802382

22812383
test_setup_8e () {
22822384
test_create_repo 8e &&

0 commit comments

Comments
 (0)