If there were several files conflicting below a directory corresponding to a D/F conflict, and the file of that D/F conflict is in the way, we want it to be removed. Since files of D/F conflicts are handled last, they can be reinstated later and possibly with a new unique name. Signed-off-by: Elijah Newren <newren@xxxxxxxxx> --- Changes since v1: (1) Made use of Johannes' new string-list API to remove items we have already checked in order to avoid trying to unlink a path more than once (2) Moved the comment about removing paths to make room to the location where we actually remove the path. (3) Fixed a bug with accidentally removing wrong paths (by adding the path[df_pathlen] == '/' check) merge-recursive.c | 26 ++++++++++++++++++++++---- t/t6036-recursive-corner-cases.sh | 2 +- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/merge-recursive.c b/merge-recursive.c index c12e4d5..1547691 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -412,7 +412,6 @@ static void record_df_conflict_files(struct merge_options *o, len > last_len && memcmp(path, last_file, last_len) == 0 && path[last_len] == '/') { - output(o, 3, "Removing %s to make room for subdirectory; may re-add later.", last_file); string_list_insert(&o->df_conflict_file_set, last_file); } @@ -652,11 +651,30 @@ static int would_lose_untracked(const char *path) return !was_tracked(path) && file_exists(path); } -static int make_room_for_path(const char *path) +static int make_room_for_path(struct merge_options *o, const char *path) { - int status; + int status, i; const char *msg = "failed to create path '%s'%s"; + /* Unlink any D/F conflict files that are in the way */ + for (i = 0; i < o->df_conflict_file_set.nr; i++) { + const char *df_path = o->df_conflict_file_set.items[i].string; + size_t pathlen = strlen(path); + size_t df_pathlen = strlen(df_path); + if (df_pathlen < pathlen && + path[df_pathlen] == '/' && + strncmp(path, df_path, df_pathlen) == 0) { + output(o, 3, + "Removing %s to make room for subdirectory\n", + df_path); + unlink(df_path); + unsorted_string_list_delete_item(&o->df_conflict_file_set, + i, 0); + break; + } + } + + /* Make sure leading directories are created */ status = safe_create_leading_directories_const(path); if (status) { if (status == -3) { @@ -724,7 +742,7 @@ static void update_file_flags(struct merge_options *o, } } - if (make_room_for_path(path) < 0) { + if (make_room_for_path(o, path) < 0) { update_wd = 0; free(buf); goto update_index; diff --git a/t/t6036-recursive-corner-cases.sh b/t/t6036-recursive-corner-cases.sh index ed6c6f4..279f33c 100755 --- a/t/t6036-recursive-corner-cases.sh +++ b/t/t6036-recursive-corner-cases.sh @@ -496,7 +496,7 @@ test_expect_success 'setup differently handled merges of directory/file conflict git tag E2 ' -test_expect_failure 'merge of D & E1 fails but has appropriate contents' ' +test_expect_success 'merge of D & E1 fails but has appropriate contents' ' get_clean_checkout D^0 && test_must_fail git merge -s recursive E1^0 && -- 1.7.6.100.gac5c1 -- 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