diff options
author | Junio C Hamano <gitster@pobox.com> | 2022-07-18 23:31:56 +0300 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2022-07-18 23:31:56 +0300 |
commit | e3349f288826d54ee056330222a902360c192b0b (patch) | |
tree | fe892a39a65b5184034908eee55cf4cf1334f5cf /merge-ort.c | |
parent | 3d3874d537af1149c85b73d7c4317ed1b0d0b419 (diff) | |
parent | 751e16542472c7040565f97c2149c2d501ed0b81 (diff) |
Merge branch 'en/merge-dual-dir-renames-fix'
Fixes a long-standing corner case bug around directory renames in
the merge-ort strategy.
* en/merge-dual-dir-renames-fix:
merge-ort: fix issue with dual rename and add/add conflict
merge-ort: shuffle the computation and cleanup of potential collisions
merge-ort: make a separate function for freeing struct collisions
merge-ort: small cleanups of check_for_directory_rename
t6423: add tests of dual directory rename plus add/add conflict
Diffstat (limited to 'merge-ort.c')
-rw-r--r-- | merge-ort.c | 74 |
1 files changed, 48 insertions, 26 deletions
diff --git a/merge-ort.c b/merge-ort.c index 01f150ef3b..8b7de0fbd8 100644 --- a/merge-ort.c +++ b/merge-ort.c @@ -2398,6 +2398,27 @@ static void compute_collisions(struct strmap *collisions, } } +static void free_collisions(struct strmap *collisions) +{ + struct hashmap_iter iter; + struct strmap_entry *entry; + + /* Free each value in the collisions map */ + strmap_for_each_entry(collisions, &iter, entry) { + struct collision_info *info = entry->value; + string_list_clear(&info->source_files, 0); + } + /* + * In compute_collisions(), we set collisions.strdup_strings to 0 + * so that we wouldn't have to make another copy of the new_path + * allocated by apply_dir_rename(). But now that we've used them + * and have no other references to these strings, it is time to + * deallocate them. + */ + free_strmap_strings(collisions); + strmap_clear(collisions, 1); +} + static char *check_for_directory_rename(struct merge_options *opt, const char *path, unsigned side_index, @@ -2406,18 +2427,23 @@ static char *check_for_directory_rename(struct merge_options *opt, struct strmap *collisions, int *clean_merge) { - char *new_path = NULL; + char *new_path; struct strmap_entry *rename_info; - struct strmap_entry *otherinfo = NULL; + struct strmap_entry *otherinfo; const char *new_dir; + int other_side = 3 - side_index; + /* + * Cases where we don't have or don't want a directory rename for + * this path. + */ if (strmap_empty(dir_renames)) - return new_path; + return NULL; + if (strmap_get(&collisions[other_side], path)) + return NULL; rename_info = check_dir_renamed(path, dir_renames); if (!rename_info) - return new_path; - /* old_dir = rename_info->key; */ - new_dir = rename_info->value; + return NULL; /* * This next part is a little weird. We do not want to do an @@ -2443,6 +2469,7 @@ static char *check_for_directory_rename(struct merge_options *opt, * As it turns out, this also prevents N-way transient rename * confusion; See testcases 9c and 9d of t6043. */ + new_dir = rename_info->value; /* old_dir = rename_info->key; */ otherinfo = strmap_get_entry(dir_rename_exclusions, new_dir); if (otherinfo) { path_msg(opt, INFO_DIR_RENAME_SKIPPED_DUE_TO_RERENAME, 1, @@ -2454,7 +2481,8 @@ static char *check_for_directory_rename(struct merge_options *opt, } new_path = handle_path_level_conflicts(opt, path, side_index, - rename_info, collisions); + rename_info, + &collisions[side_index]); *clean_merge &= (new_path != NULL); return new_path; @@ -3171,18 +3199,15 @@ static int detect_regular_renames(struct merge_options *opt, static int collect_renames(struct merge_options *opt, struct diff_queue_struct *result, unsigned side_index, + struct strmap *collisions, struct strmap *dir_renames_for_side, struct strmap *rename_exclusions) { int i, clean = 1; - struct strmap collisions; struct diff_queue_struct *side_pairs; - struct hashmap_iter iter; - struct strmap_entry *entry; struct rename_info *renames = &opt->priv->renames; side_pairs = &renames->pairs[side_index]; - compute_collisions(&collisions, dir_renames_for_side, side_pairs); for (i = 0; i < side_pairs->nr; ++i) { struct diff_filepair *p = side_pairs->queue[i]; @@ -3198,7 +3223,7 @@ static int collect_renames(struct merge_options *opt, side_index, dir_renames_for_side, rename_exclusions, - &collisions, + collisions, &clean); possibly_cache_new_pair(renames, p, side_index, new_path); @@ -3224,20 +3249,6 @@ static int collect_renames(struct merge_options *opt, result->queue[result->nr++] = p; } - /* Free each value in the collisions map */ - strmap_for_each_entry(&collisions, &iter, entry) { - struct collision_info *info = entry->value; - string_list_clear(&info->source_files, 0); - } - /* - * In compute_collisions(), we set collisions.strdup_strings to 0 - * so that we wouldn't have to make another copy of the new_path - * allocated by apply_dir_rename(). But now that we've used them - * and have no other references to these strings, it is time to - * deallocate them. - */ - free_strmap_strings(&collisions); - strmap_clear(&collisions, 1); return clean; } @@ -3248,6 +3259,7 @@ static int detect_and_process_renames(struct merge_options *opt, { struct diff_queue_struct combined = { 0 }; struct rename_info *renames = &opt->priv->renames; + struct strmap collisions[3]; int need_dir_renames, s, i, clean = 1; unsigned detection_run = 0; @@ -3297,12 +3309,22 @@ static int detect_and_process_renames(struct merge_options *opt, ALLOC_GROW(combined.queue, renames->pairs[1].nr + renames->pairs[2].nr, combined.alloc); + for (i = MERGE_SIDE1; i <= MERGE_SIDE2; i++) { + int other_side = 3 - i; + compute_collisions(&collisions[i], + &renames->dir_renames[other_side], + &renames->pairs[i]); + } clean &= collect_renames(opt, &combined, MERGE_SIDE1, + collisions, &renames->dir_renames[2], &renames->dir_renames[1]); clean &= collect_renames(opt, &combined, MERGE_SIDE2, + collisions, &renames->dir_renames[1], &renames->dir_renames[2]); + for (i = MERGE_SIDE1; i <= MERGE_SIDE2; i++) + free_collisions(&collisions[i]); STABLE_QSORT(combined.queue, combined.nr, compare_pairs); trace2_region_leave("merge", "directory renames", opt->repo); |