[PATCH] An attempt to resolve a rename/rename conflict in recursive merge
From: Alex Riesen <hidden>
Date: 2016-06-15 22:43:02
Subsystem:
the rest · Maintainer:
Linus Torvalds
The structure looks like this:
o---A-o-o---o-o-o-o-AA
\ ____\_/
\ / \
B-------o-o-o-BB
There is a rename/rename conflict somewhere around A and B commits.
The conflict was resolved at the merge points. Now, the problem is
that when the merge-recursive generates that virtual merge there seem
to be no way to get to the resolved state. The ends up resolving the
conflict again, and of course does not do it without intelligent help,
leaving index with unresolved entries. git_write_tree fails, returning
NULL and the rest breaks.
I just left all three entries in the index for the virtual commit to
pick them up: it'll usually(always?) generate a conflict which has to
be resolved manually. Many times, perhaps.
The small change in git_write_tree() was useful to see the relevant
portion of the index. The output in rename/rename conflict handling
code modified to improve its readability: it can be a lot of text.
---
merge-recursive.c | 37 +++++++++++++++++++++++++++++++------
1 files changed, 31 insertions(+), 6 deletions(-)
diff --git a/merge-recursive.c b/merge-recursive.c
index c96e1a7..2568c4e 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c@@ -278,8 +278,16 @@ static struct tree *git_write_tree(void) { struct tree *result = NULL; - if (unmerged_index()) + if (unmerged_index()) { + output(0, "There are unmerged index entries:"); + int i; + for (i = 0; i < active_nr; i++) { + struct cache_entry *ce = active_cache[i]; + if (ce_stage(ce)) + output(0, "%d %.*s", ce_stage(ce), ce_namelen(ce), ce->name); + } return NULL; + } if (!active_cache_tree) active_cache_tree = cache_tree();
@@ -735,8 +743,17 @@ static void conflict_rename_rename(struct rename *ren1, ren2_dst, branch1, dst_name2); remove_file(0, ren2_dst, 0); } - update_stages(dst_name1, NULL, ren1->pair->two, NULL, 1); - update_stages(dst_name2, NULL, NULL, ren2->pair->two, 1); + if (index_only) { + remove_file_from_cache(dst_name1); + remove_file_from_cache(dst_name2); + add_cacheinfo(ren1->pair->two->mode, ren1->pair->two->sha1, dst_name1, + 0, 0, ADD_CACHE_OK_TO_ADD); + add_cacheinfo(ren1->pair->two->mode, ren2->pair->two->sha1, dst_name2, + 0, 0, ADD_CACHE_OK_TO_ADD); + } else { + update_stages(dst_name1, NULL, ren1->pair->two, NULL, 1); + update_stages(dst_name2, NULL, NULL, ren2->pair->two, 1); + } while (delp--) free(del[delp]); }
@@ -852,10 +869,18 @@ static int process_renames(struct path_list *a_renames, if (strcmp(ren1_dst, ren2_dst) != 0) { clean_merge = 0; output(1, "CONFLICT (rename/rename): " - "Rename %s->%s in branch %s " - "rename %s->%s in %s", + "Rename \"%s\"->\"%s\" in branch \"%s\" " + "rename \"%s\"->\"%s\" in \"%s\"%s", src, ren1_dst, branch1, - src, ren2_dst, branch2); + src, ren2_dst, branch2, + index_only ? " (left unresolved)": ""); + if (index_only) { + remove_file_from_cache(src); + add_cacheinfo(ren1->pair->one->mode, + ren1->pair->one->sha1, + src, + 0, 0, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE); + } conflict_rename_rename(ren1, branch1, ren2, branch2); } else { struct merge_file_info mfi;
--
1.5.1.rc2.18.g157b4