]> git.ipfire.org Git - thirdparty/git.git/commitdiff
merge-recursive: fix rename/rename(1to2) for working tree with a binary
authorElijah Newren <newren@gmail.com>
Wed, 13 May 2020 23:56:32 +0000 (23:56 +0000)
committerJunio C Hamano <gitster@pobox.com>
Thu, 14 May 2020 19:14:19 +0000 (12:14 -0700)
With a rename/rename(1to2) conflict, we attempt to do a three-way merge
of the file contents, so that the correct contents can be placed in the
working tree at both paths.  If the file is a binary, however, no
content merging is possible and we should just use the original version
of the file at each of the paths.

Reported-by: Chunlin Zhang <zhangchunlin@gmail.com>
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
merge-recursive.c
t/t6042-merge-rename-corner-cases.sh

index d92e2acf1ed2cfb4d4ce1e50fee3a64fb70b91ac..36948eafb750284551a3748405135a685ddba2ff 100644 (file)
@@ -1750,6 +1750,18 @@ static int handle_rename_rename_1to2(struct merge_options *opt,
                        return -1;
        }
 
+       if (!mfi.clean && mfi.blob.mode == a->mode &&
+           oideq(&mfi.blob.oid, &a->oid)) {
+               /*
+                * Getting here means we were attempting to merge a binary
+                * blob.  Since we can't merge binaries, the merge algorithm
+                * just takes one side.  But we don't want to copy the
+                * contents of one side to both paths; we'd rather use the
+                * original content at the given path for each path.
+                */
+               oidcpy(&mfi.blob.oid, &b->oid);
+               mfi.blob.mode = b->mode;
+       }
        add = &ci->ren2->dst_entry->stages[flip_stage(3)];
        if (is_valid(add)) {
                add->path = mfi.blob.path = b->path;
index b047cf1c1c3735faa99e3a3b2453503f4f9c4a8f..f163893ff97125c7750b9bd11c273ae8b738436c 100755 (executable)
@@ -1379,4 +1379,59 @@ test_expect_success 'check nested conflicts from rename/rename(2to1)' '
        )
 '
 
+# Testcase rename/rename(1to2) of a binary file
+#   Commit O: orig
+#   Commit A: orig-A
+#   Commit B: orig-B
+#   Expected: CONFLICT(rename/rename) message, three unstaged entries in the
+#             index, and contents of orig-[AB] at path orig-[AB]
+test_setup_rename_rename_1_to_2_binary () {
+       test_create_repo rename_rename_1_to_2_binary &&
+       (
+               cd rename_rename_1_to_2_binary &&
+
+               echo '* binary' >.gitattributes &&
+               git add .gitattributes &&
+
+               test_seq 1 10 >orig &&
+               git add orig &&
+               git commit -m orig &&
+
+               git branch A &&
+               git branch B &&
+
+               git checkout A &&
+               git mv orig orig-A &&
+               test_seq 1 11 >orig-A &&
+               git add orig-A &&
+               git commit -m orig-A &&
+
+               git checkout B &&
+               git mv orig orig-B &&
+               test_seq 0 10 >orig-B &&
+               git add orig-B &&
+               git commit -m orig-B
+
+       )
+}
+
+test_expect_success 'rename/rename(1to2) with a binary file' '
+       test_setup_rename_rename_1_to_2_binary &&
+       (
+               cd rename_rename_1_to_2_binary &&
+
+               git checkout A^0 &&
+
+               test_must_fail git merge -s recursive B^0 &&
+
+               # Make sure the index has the right number of entries
+               git ls-files -s >actual &&
+               test_line_count = 4 actual &&
+
+               git rev-parse A:orig-A B:orig-B >expect &&
+               git hash-object orig-A orig-B >actual &&
+               test_cmp expect actual
+       )
+'
+
 test_done