directory rename detection: more involved edge/corner testcases

Reviewed-by: Stefan Beller <sbeller@google.com> Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Elijah Newren committed Apr 19, 2018 at 10:57 UTC f95de9602b409b1385a1133d9be0d5e6ec8e498f
1 file changed +396
t/t6043-merge-rename-directories.sh
+396
@@ -1516,4 +1516,400 @@ test_expect_success '6e-check: Add/add from one side' '
1516 # side of history is the one doing the renaming.
1517 ###########################################################################
1518
1519 +
1520 +###########################################################################
1521 +# SECTION 7: More involved Edge/Corner cases
1522 +#
1523 +# The ruleset we have generated in the above sections seems to provide
1524 +# well-defined merges. But can we find edge/corner cases that either (a)
1525 +# are harder for users to understand, or (b) have a resolution that is
1526 +# non-intuitive or suboptimal?
1527 +#
1528 +# The testcases in this section dive into cases that I've tried to craft in
1529 +# a way to find some that might be surprising to users or difficult for
1530 +# them to understand (the next section will look at non-intuitive or
1531 +# suboptimal merge results). Some of the testcases are similar to ones
1532 +# from past sections, but have been simplified to try to highlight error
1533 +# messages using a "modified" path (due to the directory rename). Are
1534 +# users okay with these?
1535 +#
1536 +# In my opinion, testcases that are difficult to understand from this
1537 +# section is due to difficulty in the testcase rather than the directory
1538 +# renaming (similar to how t6042 and t6036 have difficult resolutions due
1539 +# to the problem setup itself being complex). And I don't think the
1540 +# error messages are a problem.
1541 +#
1542 +# On the other hand, the testcases in section 8 worry me slightly more...
1543 +###########################################################################
1544 +
1545 +# Testcase 7a, rename-dir vs. rename-dir (NOT split evenly) PLUS add-other-file
1546 +# Commit O: z/{b,c}
1547 +# Commit A: y/{b,c}
1548 +# Commit B: w/b, x/c, z/d
1549 +# Expected: y/d, CONFLICT(rename/rename for both z/b and z/c)
1550 +# NOTE: There's a rename of z/ here, y/ has more renames, so z/d -> y/d.
1551 +
1552 +test_expect_success '7a-setup: rename-dir vs. rename-dir (NOT split evenly) PLUS add-other-file' '
1553 + test_create_repo 7a &&
1554 + (
1555 + cd 7a &&
1556 +
1557 + mkdir z &&
1558 + echo b >z/b &&
1559 + echo c >z/c &&
1560 + git add z &&
1561 + test_tick &&
1562 + git commit -m "O" &&
1563 +
1564 + git branch O &&
1565 + git branch A &&
1566 + git branch B &&
1567 +
1568 + git checkout A &&
1569 + git mv z y &&
1570 + test_tick &&
1571 + git commit -m "A" &&
1572 +
1573 + git checkout B &&
1574 + mkdir w &&
1575 + mkdir x &&
1576 + git mv z/b w/ &&
1577 + git mv z/c x/ &&
1578 + echo d > z/d &&
1579 + git add z/d &&
1580 + test_tick &&
1581 + git commit -m "B"
1582 + )
1583 +'
1584 +
1585 +test_expect_failure '7a-check: rename-dir vs. rename-dir (NOT split evenly) PLUS add-other-file' '
1586 + (
1587 + cd 7a &&
1588 +
1589 + git checkout A^0 &&
1590 +
1591 + test_must_fail git merge -s recursive B^0 >out &&
1592 + test_i18ngrep "CONFLICT (rename/rename).*z/b.*y/b.*w/b" out &&
1593 + test_i18ngrep "CONFLICT (rename/rename).*z/c.*y/c.*x/c" out &&
1594 +
1595 + git ls-files -s >out &&
1596 + test_line_count = 7 out &&
1597 + git ls-files -u >out &&
1598 + test_line_count = 6 out &&
1599 + git ls-files -o >out &&
1600 + test_line_count = 1 out &&
1601 +
1602 + git rev-parse >actual \
1603 + :1:z/b :2:y/b :3:w/b :1:z/c :2:y/c :3:x/c :0:y/d &&
1604 + git rev-parse >expect \
1605 + O:z/b O:z/b O:z/b O:z/c O:z/c O:z/c B:z/d &&
1606 + test_cmp expect actual &&
1607 +
1608 + git hash-object >actual \
1609 + y/b w/b y/c x/c &&
1610 + git rev-parse >expect \
1611 + O:z/b O:z/b O:z/c O:z/c &&
1612 + test_cmp expect actual
1613 + )
1614 +'
1615 +
1616 +# Testcase 7b, rename/rename(2to1), but only due to transitive rename
1617 +# (Related to testcase 1d)
1618 +# Commit O: z/{b,c}, x/d_1, w/d_2
1619 +# Commit A: y/{b,c,d_2}, x/d_1
1620 +# Commit B: z/{b,c,d_1}, w/d_2
1621 +# Expected: y/{b,c}, CONFLICT(rename/rename(2to1): x/d_1, w/d_2 -> y_d)
1622 +
1623 +test_expect_success '7b-setup: rename/rename(2to1), but only due to transitive rename' '
1624 + test_create_repo 7b &&
1625 + (
1626 + cd 7b &&
1627 +
1628 + mkdir z &&
1629 + mkdir x &&
1630 + mkdir w &&
1631 + echo b >z/b &&
1632 + echo c >z/c &&
1633 + echo d1 > x/d &&
1634 + echo d2 > w/d &&
1635 + git add z x w &&
1636 + test_tick &&
1637 + git commit -m "O" &&
1638 +
1639 + git branch O &&
1640 + git branch A &&
1641 + git branch B &&
1642 +
1643 + git checkout A &&
1644 + git mv z y &&
1645 + git mv w/d y/ &&
1646 + test_tick &&
1647 + git commit -m "A" &&
1648 +
1649 + git checkout B &&
1650 + git mv x/d z/ &&
1651 + rmdir x &&
1652 + test_tick &&
1653 + git commit -m "B"
1654 + )
1655 +'
1656 +
1657 +test_expect_failure '7b-check: rename/rename(2to1), but only due to transitive rename' '
1658 + (
1659 + cd 7b &&
1660 +
1661 + git checkout A^0 &&
1662 +
1663 + test_must_fail git merge -s recursive B^0 >out &&
1664 + test_i18ngrep "CONFLICT (rename/rename)" out &&
1665 +
1666 + git ls-files -s >out &&
1667 + test_line_count = 4 out &&
1668 + git ls-files -u >out &&
1669 + test_line_count = 2 out &&
1670 + git ls-files -o >out &&
1671 + test_line_count = 3 out &&
1672 +
1673 + git rev-parse >actual \
1674 + :0:y/b :0:y/c :2:y/d :3:y/d &&
1675 + git rev-parse >expect \
1676 + O:z/b O:z/c O:w/d O:x/d &&
1677 + test_cmp expect actual &&
1678 +
1679 + test_path_is_missing y/d &&
1680 + test_path_is_file y/d~HEAD &&
1681 + test_path_is_file y/d~B^0 &&
1682 +
1683 + git hash-object >actual \
1684 + y/d~HEAD y/d~B^0 &&
1685 + git rev-parse >expect \
1686 + O:w/d O:x/d &&
1687 + test_cmp expect actual
1688 + )
1689 +'
1690 +
1691 +# Testcase 7c, rename/rename(1to...2or3); transitive rename may add complexity
1692 +# (Related to testcases 3b and 5c)
1693 +# Commit O: z/{b,c}, x/d
1694 +# Commit A: y/{b,c}, w/d
1695 +# Commit B: z/{b,c,d}
1696 +# Expected: y/{b,c}, CONFLICT(x/d -> w/d vs. y/d)
1697 +# NOTE: z/ was renamed to y/ so we do want to report
1698 +# neither CONFLICT(x/d -> w/d vs. z/d)
1699 +# nor CONFLiCT x/d -> w/d vs. y/d vs. z/d)
1700 +
1701 +test_expect_success '7c-setup: rename/rename(1to...2or3); transitive rename may add complexity' '
1702 + test_create_repo 7c &&
1703 + (
1704 + cd 7c &&
1705 +
1706 + mkdir z &&
1707 + echo b >z/b &&
1708 + echo c >z/c &&
1709 + mkdir x &&
1710 + echo d >x/d &&
1711 + git add z x &&
1712 + test_tick &&
1713 + git commit -m "O" &&
1714 +
1715 + git branch O &&
1716 + git branch A &&
1717 + git branch B &&
1718 +
1719 + git checkout A &&
1720 + git mv z y &&
1721 + git mv x w &&
1722 + test_tick &&
1723 + git commit -m "A" &&
1724 +
1725 + git checkout B &&
1726 + git mv x/d z/ &&
1727 + rmdir x &&
1728 + test_tick &&
1729 + git commit -m "B"
1730 + )
1731 +'
1732 +
1733 +test_expect_failure '7c-check: rename/rename(1to...2or3); transitive rename may add complexity' '
1734 + (
1735 + cd 7c &&
1736 +
1737 + git checkout A^0 &&
1738 +
1739 + test_must_fail git merge -s recursive B^0 >out &&
1740 + test_i18ngrep "CONFLICT (rename/rename).*x/d.*w/d.*y/d" out &&
1741 +
1742 + git ls-files -s >out &&
1743 + test_line_count = 5 out &&
1744 + git ls-files -u >out &&
1745 + test_line_count = 3 out &&
1746 + git ls-files -o >out &&
1747 + test_line_count = 1 out &&
1748 +
1749 + git rev-parse >actual \
1750 + :0:y/b :0:y/c :1:x/d :2:w/d :3:y/d &&
1751 + git rev-parse >expect \
1752 + O:z/b O:z/c O:x/d O:x/d O:x/d &&
1753 + test_cmp expect actual
1754 + )
1755 +'
1756 +
1757 +# Testcase 7d, transitive rename involved in rename/delete; how is it reported?
1758 +# (Related somewhat to testcases 5b and 8d)
1759 +# Commit O: z/{b,c}, x/d
1760 +# Commit A: y/{b,c}
1761 +# Commit B: z/{b,c,d}
1762 +# Expected: y/{b,c}, CONFLICT(delete x/d vs rename to y/d)
1763 +# NOTE: z->y so NOT CONFLICT(delete x/d vs rename to z/d)
1764 +
1765 +test_expect_success '7d-setup: transitive rename involved in rename/delete; how is it reported?' '
1766 + test_create_repo 7d &&
1767 + (
1768 + cd 7d &&
1769 +
1770 + mkdir z &&
1771 + echo b >z/b &&
1772 + echo c >z/c &&
1773 + mkdir x &&
1774 + echo d >x/d &&
1775 + git add z x &&
1776 + test_tick &&
1777 + git commit -m "O" &&
1778 +
1779 + git branch O &&
1780 + git branch A &&
1781 + git branch B &&
1782 +
1783 + git checkout A &&
1784 + git mv z y &&
1785 + git rm -rf x &&
1786 + test_tick &&
1787 + git commit -m "A" &&
1788 +
1789 + git checkout B &&
1790 + git mv x/d z/ &&
1791 + rmdir x &&
1792 + test_tick &&
1793 + git commit -m "B"
1794 + )
1795 +'
1796 +
1797 +test_expect_failure '7d-check: transitive rename involved in rename/delete; how is it reported?' '
1798 + (
1799 + cd 7d &&
1800 +
1801 + git checkout A^0 &&
1802 +
1803 + test_must_fail git merge -s recursive B^0 >out &&
1804 + test_i18ngrep "CONFLICT (rename/delete).*x/d.*y/d" out &&
1805 +
1806 + git ls-files -s >out &&
1807 + test_line_count = 3 out &&
1808 + git ls-files -u >out &&
1809 + test_line_count = 1 out &&
1810 + git ls-files -o >out &&
1811 + test_line_count = 1 out &&
1812 +
1813 + git rev-parse >actual \
1814 + :0:y/b :0:y/c :3:y/d &&
1815 + git rev-parse >expect \
1816 + O:z/b O:z/c O:x/d &&
1817 + test_cmp expect actual
1818 + )
1819 +'
1820 +
1821 +# Testcase 7e, transitive rename in rename/delete AND dirs in the way
1822 +# (Very similar to 'both rename source and destination involved in D/F conflict' from t6022-merge-rename.sh)
1823 +# (Also related to testcases 9c and 9d)
1824 +# Commit O: z/{b,c}, x/d_1
1825 +# Commit A: y/{b,c,d/g}, x/d/f
1826 +# Commit B: z/{b,c,d_1}
1827 +# Expected: rename/delete(x/d_1->y/d_1 vs. None) + D/F conflict on y/d
1828 +# y/{b,c,d/g}, y/d_1~B^0, x/d/f
1829 +
1830 +# NOTE: The main path of interest here is d_1 and where it ends up, but
1831 +# this is actually a case that has two potential directory renames
1832 +# involved and D/F conflict(s), so it makes sense to walk through
1833 +# each step.
1834 +#
1835 +# Commit A renames z/ -> y/. Thus everything that B adds to z/
1836 +# should be instead moved to y/. This gives us the D/F conflict on
1837 +# y/d because x/d_1 -> z/d_1 -> y/d_1 conflicts with y/d/g.
1838 +#
1839 +# Further, commit B renames x/ -> z/, thus everything A adds to x/
1840 +# should instead be moved to z/...BUT we removed z/ and renamed it
1841 +# to y/, so maybe everything should move not from x/ to z/, but
1842 +# from x/ to z/ to y/. Doing so might make sense from the logic so
1843 +# far, but note that commit A had both an x/ and a y/; it did the
1844 +# renaming of z/ to y/ and created x/d/f and it clearly made these
1845 +# things separate, so it doesn't make much sense to push these
1846 +# together. Doing so is what I'd call a doubly transitive rename;
1847 +# see testcases 9c and 9d for further discussion of this issue and
1848 +# how it's resolved.
1849 +
1850 +test_expect_success '7e-setup: transitive rename in rename/delete AND dirs in the way' '
1851 + test_create_repo 7e &&
1852 + (
1853 + cd 7e &&
1854 +
1855 + mkdir z &&
1856 + echo b >z/b &&
1857 + echo c >z/c &&
1858 + mkdir x &&
1859 + echo d1 >x/d &&
1860 + git add z x &&
1861 + test_tick &&
1862 + git commit -m "O" &&
1863 +
1864 + git branch O &&
1865 + git branch A &&
1866 + git branch B &&
1867 +
1868 + git checkout A &&
1869 + git mv z y &&
1870 + git rm x/d &&
1871 + mkdir -p x/d &&
1872 + mkdir -p y/d &&
1873 + echo f >x/d/f &&
1874 + echo g >y/d/g &&
1875 + git add x/d/f y/d/g &&
1876 + test_tick &&
1877 + git commit -m "A" &&
1878 +
1879 + git checkout B &&
1880 + git mv x/d z/ &&
1881 + rmdir x &&
1882 + test_tick &&
1883 + git commit -m "B"
1884 + )
1885 +'
1886 +
1887 +test_expect_failure '7e-check: transitive rename in rename/delete AND dirs in the way' '
1888 + (
1889 + cd 7e &&
1890 +
1891 + git checkout A^0 &&
1892 +
1893 + test_must_fail git merge -s recursive B^0 >out &&
1894 + test_i18ngrep "CONFLICT (rename/delete).*x/d.*y/d" out &&
1895 +
1896 + git ls-files -s >out &&
1897 + test_line_count = 5 out &&
1898 + git ls-files -u >out &&
1899 + test_line_count = 1 out &&
1900 + git ls-files -o >out &&
1901 + test_line_count = 2 out &&
1902 +
1903 + git rev-parse >actual \
1904 + :0:x/d/f :0:y/d/g :0:y/b :0:y/c :3:y/d &&
1905 + git rev-parse >expect \
1906 + A:x/d/f A:y/d/g O:z/b O:z/c O:x/d &&
1907 + test_cmp expect actual &&
1908 +
1909 + git hash-object y/d~B^0 >actual &&
1910 + git rev-parse O:x/d >expect &&
1911 + test_cmp expect actual
1912 + )
1913 +'
1914 +
1915 test_done