From: Elijah Newren <newren@xxxxxxxxx> 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@xxxxxxxxx> Signed-off-by: Elijah Newren <newren@xxxxxxxxx> --- merge-recursive: fix rename/rename(1to2) for working tree with a binary rename/rename(1to2) is unique among our conflict resolutions in that it tries to put the as-merged-as-possible contents into two different paths, so I think this should be the only code path that needs an update for this issue. Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-784%2Fnewren%2Frr1to2-binary-v1 Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-784/newren/rr1to2-binary-v1 Pull-Request: https://github.com/git/git/pull/784 merge-recursive.c | 12 ++++++ t/t6042-merge-rename-corner-cases.sh | 55 ++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/merge-recursive.c b/merge-recursive.c index d92e2acf1ed..36948eafb75 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 b047cf1c1c3..f163893ff97 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 base-commit: b994622632154fc3b17fb40a38819ad954a5fb88 -- gitgitgadget