merge-recursive: fix rename/rename(1to2) for working tree with a binary

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>
This commit is contained in:
Elijah Newren 2020-05-13 23:56:32 +00:00 committed by Junio C Hamano
parent 172e8ff696
commit 95983da6b4
2 changed files with 67 additions and 0 deletions

View 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;

View File

@ -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