t6036, t6042: testcases for rename collision of already conflicting files

When a single file is renamed, it can also be modified, yielding the possibility of that renamed file having content conflicts. If two different such files are renamed into the same location, then two-way merging those files may result in nested conflicts. Add a testcase that makes sure we get this case correct, and uses different lengths of conflict markers to differentiate between the different nestings. Also add another case with an extra (i.e. third) level of conflict markers due to using merge.conflictstyle=diff3 and the virtual merge base also having conflicts present. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Elijah Newren committed Nov 7, 2018 at 20:40 UTC b28eeb3092fd12e24485fbadebfa57df457dd09a
2 files changed +312
t/t6036-recursive-corner-cases.sh
+194
@@ -1402,4 +1402,198 @@ test_expect_failure 'check conflicting modes for regular file' '
1402 )
1403 '
1404
1405 +# Setup:
1406 +# L1---L2
1407 +# / \ / \
1408 +# master X ?
1409 +# \ / \ /
1410 +# R1---R2
1411 +#
1412 +# Where:
1413 +# master has two files, named 'b' and 'a'
1414 +# branches L1 and R1 both modify each of the two files in conflicting ways
1415 +#
1416 +# L2 is a merge of R1 into L1; more on it later.
1417 +# R2 is a merge of L1 into R1; more on it later.
1418 +#
1419 +# X is an auto-generated merge-base used when merging L2 and R2.
1420 +# since X is a merge of L1 and R1, it has conflicting versions of each file
1421 +#
1422 +# More about L2 and R2:
1423 +# - both resolve the conflicts in 'b' and 'a' differently
1424 +# - L2 renames 'b' to 'm'
1425 +# - R2 renames 'a' to 'm'
1426 +#
1427 +# In the end, in file 'm' we have four different conflicting files (from
1428 +# two versions of 'b' and two of 'a'). In addition, if
1429 +# merge.conflictstyle is diff3, then the base version also has
1430 +# conflict markers of its own, leading to a total of three levels of
1431 +# conflict markers. This is a pretty weird corner case, but we just want
1432 +# to ensure that we handle it as well as practical.
1433 +
1434 +test_expect_success 'setup nested conflicts' '
1435 + test_create_repo nested_conflicts &&
1436 + (
1437 + cd nested_conflicts &&
1438 +
1439 + # Create some related files now
1440 + for i in $(test_seq 1 10)
1441 + do
1442 + echo Random base content line $i
1443 + done >initial &&
1444 +
1445 + cp initial b_L1 &&
1446 + cp initial b_R1 &&
1447 + cp initial b_L2 &&
1448 + cp initial b_R2 &&
1449 + cp initial a_L1 &&
1450 + cp initial a_R1 &&
1451 + cp initial a_L2 &&
1452 + cp initial a_R2 &&
1453 +
1454 + test_write_lines b b_L1 >>b_L1 &&
1455 + test_write_lines b b_R1 >>b_R1 &&
1456 + test_write_lines b b_L2 >>b_L2 &&
1457 + test_write_lines b b_R2 >>b_R2 &&
1458 + test_write_lines a a_L1 >>a_L1 &&
1459 + test_write_lines a a_R1 >>a_R1 &&
1460 + test_write_lines a a_L2 >>a_L2 &&
1461 + test_write_lines a a_R2 >>a_R2 &&
1462 +
1463 + # Setup original commit (or merge-base), consisting of
1464 + # files named "b" and "a"
1465 + cp initial b &&
1466 + cp initial a &&
1467 + echo b >>b &&
1468 + echo a >>a &&
1469 + git add b a &&
1470 + test_tick && git commit -m initial &&
1471 +
1472 + git branch L &&
1473 + git branch R &&
1474 +
1475 + # Handle the left side
1476 + git checkout L &&
1477 + mv -f b_L1 b &&
1478 + mv -f a_L1 a &&
1479 + git add b a &&
1480 + test_tick && git commit -m "version L1 of files" &&
1481 + git tag L1 &&
1482 +
1483 + # Handle the right side
1484 + git checkout R &&
1485 + mv -f b_R1 b &&
1486 + mv -f a_R1 a &&
1487 + git add b a &&
1488 + test_tick && git commit -m "verson R1 of files" &&
1489 + git tag R1 &&
1490 +
1491 + # Create first merge on left side
1492 + git checkout L &&
1493 + test_must_fail git merge R1 &&
1494 + mv -f b_L2 b &&
1495 + mv -f a_L2 a &&
1496 + git add b a &&
1497 + git mv b m &&
1498 + test_tick && git commit -m "left merge, rename b->m" &&
1499 + git tag L2 &&
1500 +
1501 + # Create first merge on right side
1502 + git checkout R &&
1503 + test_must_fail git merge L1 &&
1504 + mv -f b_R2 b &&
1505 + mv -f a_R2 a &&
1506 + git add b a &&
1507 + git mv a m &&
1508 + test_tick && git commit -m "right merge, rename a->m" &&
1509 + git tag R2
1510 + )
1511 +'
1512 +
1513 +test_expect_failure 'check nested conflicts' '
1514 + (
1515 + cd nested_conflicts &&
1516 +
1517 + git clean -f &&
1518 + git checkout L2^0 &&
1519 +
1520 + # Merge must fail; there is a conflict
1521 + test_must_fail git -c merge.conflictstyle=diff3 merge -s recursive R2^0 &&
1522 +
1523 + # Make sure the index has the right number of entries
1524 + git ls-files -s >out &&
1525 + test_line_count = 2 out &&
1526 + git ls-files -u >out &&
1527 + test_line_count = 2 out &&
1528 + # Ensure we have the correct number of untracked files
1529 + git ls-files -o >out &&
1530 + test_line_count = 1 out &&
1531 +
1532 + # Create a and b from virtual merge base X
1533 + git cat-file -p master:a >base &&
1534 + git cat-file -p L1:a >ours &&
1535 + git cat-file -p R1:a >theirs &&
1536 + test_must_fail git merge-file --diff3 \
1537 + -L "Temporary merge branch 1" \
1538 + -L "merged common ancestors" \
1539 + -L "Temporary merge branch 2" \
1540 + ours \
1541 + base \
1542 + theirs &&
1543 + sed -e "s/^\([<|=>]\)/\1\1/" ours >vmb_a &&
1544 +
1545 + git cat-file -p master:b >base &&
1546 + git cat-file -p L1:b >ours &&
1547 + git cat-file -p R1:b >theirs &&
1548 + test_must_fail git merge-file --diff3 \
1549 + -L "Temporary merge branch 1" \
1550 + -L "merged common ancestors" \
1551 + -L "Temporary merge branch 2" \
1552 + ours \
1553 + base \
1554 + theirs &&
1555 + sed -e "s/^\([<|=>]\)/\1\1/" ours >vmb_b &&
1556 +
1557 + # Compare :2:m to expected values
1558 + git cat-file -p L2:m >ours &&
1559 + git cat-file -p R2:b >theirs &&
1560 + test_must_fail git merge-file --diff3 \
1561 + -L "HEAD:m" \
1562 + -L "merged common ancestors:b" \
1563 + -L "R2^0:b" \
1564 + ours \
1565 + vmb_b \
1566 + theirs &&
1567 + sed -e "s/^\([<|=>]\)/\1\1/" ours >m_stage_2 &&
1568 + git cat-file -p :2:m >actual &&
1569 + test_cmp m_stage_2 actual &&
1570 +
1571 + # Compare :3:m to expected values
1572 + git cat-file -p L2:a >ours &&
1573 + git cat-file -p R2:m >theirs &&
1574 + test_must_fail git merge-file --diff3 \
1575 + -L "HEAD:a" \
1576 + -L "merged common ancestors:a" \
1577 + -L "R2^0:m" \
1578 + ours \
1579 + vmb_a \
1580 + theirs &&
1581 + sed -e "s/^\([<|=>]\)/\1\1/" ours >m_stage_3 &&
1582 + git cat-file -p :3:m >actual &&
1583 + test_cmp m_stage_3 actual &&
1584 +
1585 + # Compare m to expected contents
1586 + >empty &&
1587 + cp -a m_stage_2 expected_final_m &&
1588 + test_must_fail git merge-file --diff3 \
1589 + -L "HEAD" \
1590 + -L "merged common ancestors" \
1591 + -L "R2^0" \
1592 + expected_final_m \
1593 + empty \
1594 + m_stage_3 &&
1595 + test_cmp expected_final_m m
1596 + )
1597 +'
1598 +
1599 test_done
t/t6042-merge-rename-corner-cases.sh
+118
@@ -1099,4 +1099,122 @@ test_conflicts_with_adds_and_renames rename add failure
1099 test_conflicts_with_adds_and_renames add rename failure
1100 test_conflicts_with_adds_and_renames add add success
1101
1102 +# Setup:
1103 +# L
1104 +# / \
1105 +# master ?
1106 +# \ /
1107 +# R
1108 +#
1109 +# Where:
1110 +# master has two files, named 'one' and 'two'.
1111 +# branches L and R both modify 'one', in conflicting ways.
1112 +# branches L and R both modify 'two', in conflicting ways.
1113 +# branch L also renames 'one' to 'three'.
1114 +# branch R also renames 'two' to 'three'.
1115 +#
1116 +# So, we have four different conflicting files that all end up at path
1117 +# 'three'.
1118 +test_expect_success 'setup nested conflicts from rename/rename(2to1)' '
1119 + test_create_repo nested_conflicts_from_rename_rename &&
1120 + (
1121 + cd nested_conflicts_from_rename_rename &&
1122 +
1123 + # Create some related files now
1124 + for i in $(test_seq 1 10)
1125 + do
1126 + echo Random base content line $i
1127 + done >file_v1 &&
1128 +
1129 + cp file_v1 file_v2 &&
1130 + cp file_v1 file_v3 &&
1131 + cp file_v1 file_v4 &&
1132 + cp file_v1 file_v5 &&
1133 + cp file_v1 file_v6 &&
1134 +
1135 + echo one >>file_v1 &&
1136 + echo uno >>file_v2 &&
1137 + echo eins >>file_v3 &&
1138 +
1139 + echo two >>file_v4 &&
1140 + echo dos >>file_v5 &&
1141 + echo zwei >>file_v6 &&
1142 +
1143 + # Setup original commit (or merge-base), consisting of
1144 + # files named "one" and "two".
1145 + mv file_v1 one &&
1146 + mv file_v4 two &&
1147 + git add one two &&
1148 + test_tick && git commit -m english &&
1149 +
1150 + git branch L &&
1151 + git branch R &&
1152 +
1153 + # Handle the left side
1154 + git checkout L &&
1155 + git mv one three &&
1156 + mv -f file_v2 three &&
1157 + mv -f file_v5 two &&
1158 + git add two three &&
1159 + test_tick && git commit -m spanish &&
1160 +
1161 + # Handle the right side
1162 + git checkout R &&
1163 + git mv two three &&
1164 + mv -f file_v3 one &&
1165 + mv -f file_v6 three &&
1166 + git add one three &&
1167 + test_tick && git commit -m german
1168 + )
1169 +'
1170 +
1171 +test_expect_failure 'check nested conflicts from rename/rename(2to1)' '
1172 + (
1173 + cd nested_conflicts_from_rename_rename &&
1174 +
1175 + git checkout L^0 &&
1176 +
1177 + # Merge must fail; there is a conflict
1178 + test_must_fail git merge -s recursive R^0 &&
1179 +
1180 + # Make sure the index has the right number of entries
1181 + git ls-files -s >out &&
1182 + test_line_count = 2 out &&
1183 + git ls-files -u >out &&
1184 + test_line_count = 2 out &&
1185 + # Ensure we have the correct number of untracked files
1186 + git ls-files -o >out &&
1187 + test_line_count = 1 out &&
1188 +
1189 + # Compare :2:three to expected values
1190 + git cat-file -p master:one >base &&
1191 + git cat-file -p L:three >ours &&
1192 + git cat-file -p R:one >theirs &&
1193 + test_must_fail git merge-file \
1194 + -L "HEAD:three" -L "" -L "R^0:one" \
1195 + ours base theirs &&
1196 + sed -e "s/^\([<=>]\)/\1\1/" ours >L-three &&
1197 + git cat-file -p :2:three >expect &&
1198 + test_cmp expect L-three &&
1199 +
1200 + # Compare :2:three to expected values
1201 + git cat-file -p master:two >base &&
1202 + git cat-file -p L:two >ours &&
1203 + git cat-file -p R:three >theirs &&
1204 + test_must_fail git merge-file \
1205 + -L "HEAD:two" -L "" -L "R^0:three" \
1206 + ours base theirs &&
1207 + sed -e "s/^\([<=>]\)/\1\1/" ours >R-three &&
1208 + git cat-file -p :3:three >expect &&
1209 + test_cmp expect R-three &&
1210 +
1211 + # Compare three to expected contents
1212 + >empty &&
1213 + test_must_fail git merge-file \
1214 + -L "HEAD" -L "" -L "R^0" \
1215 + L-three empty R-three &&
1216 + test_cmp three L-three
1217 + )
1218 +'
1219 +
1220 test_done