{"thread":{"id":"44063","subject":"[PATCH] Do not record unstaged deleted file upon recursive merge if file was moved outside of working tree with enabled sparse-checkout.","startedAt":"2016-09-12T11:35:11Z","lastAt":"2016-09-12T11:35:11Z","messageCount":1,"participants":["Mikhail Filippov"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"301702","messageId":"1473679451-4591-1-git-send-email-mikhail@filippov.me","threadId":"44063","inReplyTo":null,"subject":"[PATCH] Do not record unstaged deleted file upon recursive merge if file was moved outside of working tree with enabled sparse-checkout.","fromName":"Mikhail Filippov","fromEmail":"mikhail@filippov.me","sentAt":"2016-09-12T11:24:11Z","receivedAt":"2016-09-12T11:35:11Z","isPatch":true,"sender":{"key":"mikhail@filippov.me","avatar":"https://gravatar.com/avatar/1ad23fcc70633ccce28c11d221f70a4318667506fb9aefaba21a91dadd055630?d=mp&s=160"},"body":"It's a very unexpected behaviour when a user sees a deleted file after a merge with enabled sparse-checkout. Moreover, when the user resolves merge conflicts and commits the changes with the command \"git commit -am xxx\", a repository can be broken because all the moved files will be deleted. Finally, it's really hard to find a user who deleted these files because \"git log file\" doesn't show any merge commits by default. I'm not sure that my fix is correct but I checked all tests and I didn't find a better way to prevent files deleting.\n---\n merge-recursive.c                    |  9 +++++---\n t/t6042-merge-rename-corner-cases.sh | 41 ++++++++++++++++++++++++++++++++++++\n 2 files changed, 47 insertions(+), 3 deletions(-)\n\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex e349126..25dc701 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -1724,9 +1724,12 @@ static int merge_content(struct merge_options *o,\n \t\t */\n \t\tpath_renamed_outside_HEAD = !path2 || !strcmp(path, path2);\n \t\tif (!path_renamed_outside_HEAD) {\n-\t\t\tadd_cacheinfo(o, mfi.mode, &mfi.oid, path,\n-\t\t\t\t      0, (!o->call_depth), 0);\n-\t\t\treturn mfi.clean;\n+\t\t\tstruct stat st;\n+\t\t\tif (lstat(path, &st) == 0) {\n+\t\t\t\tadd_cacheinfo(o, mfi.mode, &mfi.oid, path,\n+\t\t\t\t\t      0, (!o->call_depth), 0);\n+\t\t\t\treturn mfi.clean;\n+\t\t\t}\n \t\t}\n \t} else\n \t\toutput(o, 2, _(\"Auto-merging %s\"), path);\ndiff --git a/t/t6042-merge-rename-corner-cases.sh b/t/t6042-merge-rename-corner-cases.sh\nindex 411550d..5d84418 100755\n--- a/t/t6042-merge-rename-corner-cases.sh\n+++ b/t/t6042-merge-rename-corner-cases.sh\n@@ -575,4 +575,45 @@ test_expect_success 'rename/rename/add-dest merge still knows about conflicting\n \ttest ! -f c\n '\n \n+test_expect_success 'move file/sparse-checkout/merge should not delete moved file' '\n+\tgit rm -rf . &&\n+\tgit clean -fdqx &&\n+\trm -rf .git &&\n+\tgit init &&\n+\n+\techo output >.gitignore &&\n+\techo .gitignore >>.gitignore &&\n+\n+\techo b1 >b1 &&\n+\tgit add b1 &&\n+\tgit commit -m b1 &&\n+\n+\tmkdir excluded &&\n+\techo problem >excluded/to-be-moved.txt &&\n+\tgit add excluded/to-be-moved.txt &&\n+\tgit commit -m to-be-moved &&\n+\tgit tag split_point &&\n+\n+\techo b2 >b2 &&\n+\tgit add b2 &&\n+\tgit commit -m b2 &&\n+\tgit tag b2 &&\n+\n+\tgit reset --hard split_point &&\n+\n+\tgit mv excluded/to-be-moved.txt excluded/moved.txt &&\n+\tgit commit -m move &&\n+\tgit tag b1 &&\n+\n+\tgit config core.sparsecheckout true &&\n+\techo \"/*\" >.git/info/sparse-checkout &&\n+\techo \"!excluded/\" >>.git/info/sparse-checkout &&\n+\tgit read-tree -mu HEAD &&\n+\n+\tgit merge -m merge b2 &&\n+\n+\tgit status >output &&\n+\ttest_i18ngrep \"nothing to commit\" output\n+'\n+\n test_done\n-- \n2.7.4 (Apple Git-66)\n\n"}]}