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 - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html