{"thread":{"id":"7560","subject":"[PATCH 3/5] merge-recursive: do not barf on \"to be removed\" entries.","startedAt":"2007-04-07T14:40:53Z","lastAt":"2007-04-07T14:40:53Z","messageCount":1,"participants":["Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"38847","messageId":"7v8xd4ckne.fsf@assigned-by-dhcp.cox.net","threadId":"7560","inReplyTo":null,"subject":"[PATCH 3/5] merge-recursive: do not barf on \"to be removed\" entries.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-04-07T14:40:53Z","receivedAt":"2007-04-07T14:40:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"When update-trees::threeway_merge() decides that a path that\nexists in the current index (and HEAD) is to be removed, it\nleaves a stage 0 entry whose mode bits are set to 0.  The code\nmistook it as \"this stage wants the blob here\", and proceeded\nto call update_file_flags() which ended up trying to put the\nmode=0 entry in the index, got very confused, and ended up\nbarfing with \"do not know what to do with 000000\".\n\nSince threeway_merge() does not handle case #10 (one side\nremoves while the other side does not do anything), this is not\na problem while we refuse to merge branches that have D/F\nconflicts, but when we start resolving them, we would need to be\nable to remove cache entries, and at that point it starts to\nmatter.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n merge-recursive.c |   16 +++++++++++-----\n 1 files changed, 11 insertions(+), 5 deletions(-)\n\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex e1aebd7..aa3d913 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -1002,9 +1002,9 @@ static int process_renames(struct path_list *a_renames,\n \treturn clean_merge;\n }\n \n-static unsigned char *has_sha(const unsigned char *sha)\n+static unsigned char *stage_sha(const unsigned char *sha, unsigned mode)\n {\n-\treturn is_null_sha1(sha) ? NULL: (unsigned char *)sha;\n+\treturn (is_null_sha1(sha) || mode == 0) ? NULL: (unsigned char *)sha;\n }\n \n /* Per entry merge function */\n@@ -1017,12 +1017,12 @@ static int process_entry(const char *path, struct stage_data *entry,\n \tprint_index_entry(\"\\tpath: \", entry);\n \t*/\n \tint clean_merge = 1;\n-\tunsigned char *o_sha = has_sha(entry->stages[1].sha);\n-\tunsigned char *a_sha = has_sha(entry->stages[2].sha);\n-\tunsigned char *b_sha = has_sha(entry->stages[3].sha);\n \tunsigned o_mode = entry->stages[1].mode;\n \tunsigned a_mode = entry->stages[2].mode;\n \tunsigned b_mode = entry->stages[3].mode;\n+\tunsigned char *o_sha = stage_sha(entry->stages[1].sha, o_mode);\n+\tunsigned char *a_sha = stage_sha(entry->stages[2].sha, a_mode);\n+\tunsigned char *b_sha = stage_sha(entry->stages[3].sha, b_mode);\n \n \tif (o_sha && (!a_sha || !b_sha)) {\n \t\t/* Case A: Deleted in one */\n@@ -1123,6 +1123,12 @@ static int process_entry(const char *path, struct stage_data *entry,\n \t\t\t\tupdate_file_flags(mfi.sha, mfi.mode, path,\n \t\t\t\t\t      0 /* update_cache */, 1 /* update_working_directory */);\n \t\t}\n+\t} else if (!o_sha && !a_sha && !b_sha) {\n+\t\t/*\n+\t\t * this entry was deleted altogether. a_mode == 0 means\n+\t\t * we had that path and want to actively remove it.\n+\t\t */\n+\t\tremove_file(1, path, !a_mode);\n \t} else\n \t\tdie(\"Fatal merge failure, shouldn't happen.\");\n \n-- \n1.5.1.81.gee969\n"}]}