{"thread":{"id":"53468","subject":"[PATCH] merge-recursive: fix rename/rename(1to2) for working tree with a binary","startedAt":"2020-05-13T23:56:37Z","lastAt":"2020-05-13T23:56:37Z","messageCount":1,"participants":["Elijah Newren via GitGitGadget"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"397797","messageId":"pull.784.git.git.1589414193064.gitgitgadget@gmail.com","threadId":"53468","inReplyTo":null,"subject":"[PATCH] merge-recursive: fix rename/rename(1to2) for working tree with a binary","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2020-05-13T23:56:32Z","receivedAt":"2020-05-13T23:56:37Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nWith a rename/rename(1to2) conflict, we attempt to do a three-way merge\nof the file contents, so that the correct contents can be placed in the\nworking tree at both paths.  If the file is a binary, however, no\ncontent merging is possible and we should just use the original version\nof the file at each of the paths.\n\nReported-by: Chunlin Zhang <zhangchunlin@gmail.com>\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n    merge-recursive: fix rename/rename(1to2) for working tree with a binary\n    \n    rename/rename(1to2) is unique among our conflict resolutions in that it\n    tries to put the as-merged-as-possible contents into two different\n    paths, so I think this should be the only code path that needs an update\n    for this issue.\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-784%2Fnewren%2Frr1to2-binary-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-784/newren/rr1to2-binary-v1\nPull-Request: https://github.com/git/git/pull/784\n\n merge-recursive.c                    | 12 ++++++\n t/t6042-merge-rename-corner-cases.sh | 55 ++++++++++++++++++++++++++++\n 2 files changed, 67 insertions(+)\n\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex d92e2acf1ed..36948eafb75 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -1750,6 +1750,18 @@ static int handle_rename_rename_1to2(struct merge_options *opt,\n \t\t\treturn -1;\n \t}\n \n+\tif (!mfi.clean && mfi.blob.mode == a->mode &&\n+\t    oideq(&mfi.blob.oid, &a->oid)) {\n+\t\t/*\n+\t\t * Getting here means we were attempting to merge a binary\n+\t\t * blob.  Since we can't merge binaries, the merge algorithm\n+\t\t * just takes one side.  But we don't want to copy the\n+\t\t * contents of one side to both paths; we'd rather use the\n+\t\t * original content at the given path for each path.\n+\t\t */\n+\t\toidcpy(&mfi.blob.oid, &b->oid);\n+\t\tmfi.blob.mode = b->mode;\n+\t}\n \tadd = &ci->ren2->dst_entry->stages[flip_stage(3)];\n \tif (is_valid(add)) {\n \t\tadd->path = mfi.blob.path = b->path;\ndiff --git a/t/t6042-merge-rename-corner-cases.sh b/t/t6042-merge-rename-corner-cases.sh\nindex b047cf1c1c3..f163893ff97 100755\n--- a/t/t6042-merge-rename-corner-cases.sh\n+++ b/t/t6042-merge-rename-corner-cases.sh\n@@ -1379,4 +1379,59 @@ test_expect_success 'check nested conflicts from rename/rename(2to1)' '\n \t)\n '\n \n+# Testcase rename/rename(1to2) of a binary file\n+#   Commit O: orig\n+#   Commit A: orig-A\n+#   Commit B: orig-B\n+#   Expected: CONFLICT(rename/rename) message, three unstaged entries in the\n+#             index, and contents of orig-[AB] at path orig-[AB]\n+test_setup_rename_rename_1_to_2_binary () {\n+\ttest_create_repo rename_rename_1_to_2_binary &&\n+\t(\n+\t\tcd rename_rename_1_to_2_binary &&\n+\n+\t\techo '* binary' >.gitattributes &&\n+\t\tgit add .gitattributes &&\n+\n+\t\ttest_seq 1 10 >orig &&\n+\t\tgit add orig &&\n+\t\tgit commit -m orig &&\n+\n+\t\tgit branch A &&\n+\t\tgit branch B &&\n+\n+\t\tgit checkout A &&\n+\t\tgit mv orig orig-A &&\n+\t\ttest_seq 1 11 >orig-A &&\n+\t\tgit add orig-A &&\n+\t\tgit commit -m orig-A &&\n+\n+\t\tgit checkout B &&\n+\t\tgit mv orig orig-B &&\n+\t\ttest_seq 0 10 >orig-B &&\n+\t\tgit add orig-B &&\n+\t\tgit commit -m orig-B\n+\n+\t)\n+}\n+\n+test_expect_success 'rename/rename(1to2) with a binary file' '\n+\ttest_setup_rename_rename_1_to_2_binary &&\n+\t(\n+\t\tcd rename_rename_1_to_2_binary &&\n+\n+\t\tgit checkout A^0 &&\n+\n+\t\ttest_must_fail git merge -s recursive B^0 &&\n+\n+\t\t# Make sure the index has the right number of entries\n+\t\tgit ls-files -s >actual &&\n+\t\ttest_line_count = 4 actual &&\n+\n+\t\tgit rev-parse A:orig-A B:orig-B >expect &&\n+\t\tgit hash-object orig-A orig-B >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n test_done\n\nbase-commit: b994622632154fc3b17fb40a38819ad954a5fb88\n-- \ngitgitgadget\n"}]}