]> git.ipfire.org Git - thirdparty/git.git/commitdiff
t6423: test directory renames causing rename-to-self
authorElijah Newren <newren@gmail.com>
Wed, 30 Jun 2021 17:29:58 +0000 (17:29 +0000)
committerJunio C Hamano <gitster@pobox.com>
Wed, 30 Jun 2021 21:40:09 +0000 (14:40 -0700)
Directory rename detection can cause transitive renames, e.g. if the two
different sides of history each do one half of:
    A/file -> B/file
    B/     -> C/
then directory rename detection transitively renames to give us C/file.
Since the default for merge.directoryRenames is conflict, this results
in an error message saying it is unclear whether the file should be
placed at B/file or C/file.

What if C/ is A/, though?  In such a case, the transitive rename would
give us A/file, the original name we started with.  Logically, having
an error message with B/file vs. A/file should be fine, as should
leaving the file where it started.  But the logic in both
merge-recursive and merge-ort did not handle a case of a filename being
renamed to itself correctly; merge-recursive had two bugs, and merge-ort
had one.  Add some testcases covering such a scenario.

Based-on-testcase-by: Anders Kaseorg <andersk@mit.edu>
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
t/t6423-merge-rename-directories.sh

index 7134769149fc538d685431e6963c655e9db806fd..afb88c347fc9011bbe9be623a6a8ec11ad7350fa 100755 (executable)
@@ -4966,6 +4966,181 @@ test_expect_success '12g: Testcase with two kinds of "relevant" renames' '
        )
 '
 
+# Testcase 12i, Directory rename causes rename-to-self
+#   Commit O: source/{subdir/foo, bar, baz_1}
+#   Commit A: source/{foo, bar, baz_1}
+#   Commit B: source/{subdir/{foo, bar}, baz_2}
+#   Expected: source/{foo, bar, baz_2}, with conflicts on
+#                source/bar vs. source/subdir/bar
+
+test_setup_12i () {
+       test_create_repo 12i &&
+       (
+               cd 12i &&
+
+               mkdir -p source/subdir &&
+               echo foo >source/subdir/foo &&
+               echo bar >source/bar &&
+               echo baz >source/baz &&
+               git add source &&
+               git commit -m orig &&
+
+               git branch O &&
+               git branch A &&
+               git branch B &&
+
+               git switch A &&
+               git mv source/subdir/foo source/foo &&
+               git commit -m A &&
+
+               git switch B &&
+               git mv source/bar source/subdir/bar &&
+               echo more baz >>source/baz &&
+               git commit -m B
+       )
+}
+
+test_expect_merge_algorithm failure failure '12i: Directory rename causes rename-to-self' '
+       test_setup_12i &&
+       (
+               cd 12i &&
+
+               git checkout A^0 &&
+
+               test_must_fail git -c merge.directoryRenames=conflict merge -s recursive B^0 &&
+
+               test_path_is_missing source/subdir &&
+               test_path_is_file source/bar &&
+               test_path_is_file source/baz &&
+
+               git ls-files | uniq >tracked &&
+               test_line_count = 3 tracked &&
+
+               git status --porcelain -uno >actual &&
+               cat >expect <<-\EOF &&
+               UU source/bar
+                M source/baz
+               EOF
+               test_cmp expect actual
+       )
+'
+
+# Testcase 12j, Directory rename to root causes rename-to-self
+#   Commit O: {subdir/foo, bar, baz_1}
+#   Commit A: {foo, bar, baz_1}
+#   Commit B: {subdir/{foo, bar}, baz_2}
+#   Expected: {foo, bar, baz_2}, with conflicts on bar vs. subdir/bar
+
+test_setup_12j () {
+       test_create_repo 12j &&
+       (
+               cd 12j &&
+
+               mkdir -p subdir &&
+               echo foo >subdir/foo &&
+               echo bar >bar &&
+               echo baz >baz &&
+               git add . &&
+               git commit -m orig &&
+
+               git branch O &&
+               git branch A &&
+               git branch B &&
+
+               git switch A &&
+               git mv subdir/foo foo &&
+               git commit -m A &&
+
+               git switch B &&
+               git mv bar subdir/bar &&
+               echo more baz >>baz &&
+               git commit -m B
+       )
+}
+
+test_expect_merge_algorithm failure failure '12j: Directory rename to root causes rename-to-self' '
+       test_setup_12j &&
+       (
+               cd 12j &&
+
+               git checkout A^0 &&
+
+               test_must_fail git -c merge.directoryRenames=conflict merge -s recursive B^0 &&
+
+               test_path_is_missing subdir &&
+               test_path_is_file bar &&
+               test_path_is_file baz &&
+
+               git ls-files | uniq >tracked &&
+               test_line_count = 3 tracked &&
+
+               git status --porcelain -uno >actual &&
+               cat >expect <<-\EOF &&
+               UU bar
+                M baz
+               EOF
+               test_cmp expect actual
+       )
+'
+
+# Testcase 12k, Directory rename with sibling causes rename-to-self
+#   Commit O: dirB/foo, dirA/{bar, baz_1}
+#   Commit A: dirA/{foo, bar, baz_1}
+#   Commit B: dirB/{foo, bar}, dirA/baz_2
+#   Expected: dirA/{foo, bar, baz_2}, with conflicts on dirA/bar vs. dirB/bar
+
+test_setup_12k () {
+       test_create_repo 12k &&
+       (
+               cd 12k &&
+
+               mkdir dirA dirB &&
+               echo foo >dirB/foo &&
+               echo bar >dirA/bar &&
+               echo baz >dirA/baz &&
+               git add . &&
+               git commit -m orig &&
+
+               git branch O &&
+               git branch A &&
+               git branch B &&
+
+               git switch A &&
+               git mv dirB/* dirA/ &&
+               git commit -m A &&
+
+               git switch B &&
+               git mv dirA/bar dirB/bar &&
+               echo more baz >>dirA/baz &&
+               git commit -m B
+       )
+}
+
+test_expect_merge_algorithm failure failure '12k: Directory rename with sibling causes rename-to-self' '
+       test_setup_12k &&
+       (
+               cd 12k &&
+
+               git checkout A^0 &&
+
+               test_must_fail git -c merge.directoryRenames=conflict merge -s recursive B^0 &&
+
+               test_path_is_missing dirB &&
+               test_path_is_file dirA/bar &&
+               test_path_is_file dirA/baz &&
+
+               git ls-files | uniq >tracked &&
+               test_line_count = 3 tracked &&
+
+               git status --porcelain -uno >actual &&
+               cat >expect <<-\EOF &&
+               UU dirA/bar
+                M dirA/baz
+               EOF
+               test_cmp expect actual
+       )
+'
+
 ###########################################################################
 # SECTION 13: Checking informational and conflict messages
 #