diff --git a/merge-recursive.c b/merge-recursive.c index d92e2acf1ed2cf..36948eafb75028 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -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; diff --git a/t/t6042-merge-rename-corner-cases.sh b/t/t6042-merge-rename-corner-cases.sh index b047cf1c1c3735..f163893ff97125 100755 --- a/t/t6042-merge-rename-corner-cases.sh +++ b/t/t6042-merge-rename-corner-cases.sh @@ -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