From: Elijah Newren <newren@xxxxxxxxx> The previous commit can only be effective if we have a computation of the number of paths under a given directory which are still have pending renames, and expected this number to be recorded in the dir_rename_count map under the key UNKNOWN_DIR. Add the code necessary to compute these values. Note that this change means dir_rename_count might have a directory whose only entry (for UNKNOWN_DIR) was removed by the time merge-ort goes to check it. To account for this, merge-ort needs to check for the case where the max count is 0. With this change we are now computing the necessary value for each directory in dirs_removed, but are not using that value anywhere. The next two commits will make use of the values stored in dirs_removed in order to compute whether each relevant_source (that is needed only for directory rename detection) has become unnecessary. Signed-off-by: Elijah Newren <newren@xxxxxxxxx> --- diffcore-rename.c | 41 +++++++++++++++++++++++++++++++++++++---- merge-ort.c | 3 +++ 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/diffcore-rename.c b/diffcore-rename.c index 8fa29076e0aa..9844cd48788e 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -699,7 +699,8 @@ static void cleanup_dir_rename_info(struct dir_rename_info *info, /* * Although dir_rename_count was passed in * diffcore_rename_extended() and we want to keep it around and - * return it to that caller, we first want to remove any data + * return it to that caller, we first want to remove any counts in + * the maps associated with UNKNOWN_DIR entries and any data * associated with directories that weren't renamed. */ strmap_for_each_entry(info->dir_rename_count, &iter, entry) { @@ -711,6 +712,9 @@ static void cleanup_dir_rename_info(struct dir_rename_info *info, strintmap_clear(counts); continue; } + + if (strintmap_contains(counts, UNKNOWN_DIR)) + strintmap_remove(counts, UNKNOWN_DIR); } for (i = 0; i < to_remove.nr; ++i) strmap_remove(info->dir_rename_count, @@ -1125,6 +1129,7 @@ static void handle_early_known_dir_renames(struct dir_rename_info *info, * a majority. */ + int i; struct hashmap_iter iter; struct strmap_entry *entry; @@ -1134,10 +1139,38 @@ static void handle_early_known_dir_renames(struct dir_rename_info *info, return; /* culling incompatbile with break detection */ /* - * FIXME: Supplement dir_rename_count with number of potential - * renames, marking all potential rename sources as mapping to - * UNKNOWN_DIR. + * Supplement dir_rename_count with number of potential renames, + * marking all potential rename sources as mapping to UNKNOWN_DIR. */ + for (i = 0; i < rename_src_nr; i++) { + char *old_dir; + struct diff_filespec *one = rename_src[i].p->one; + + /* + * sources that are part of a rename will have already been + * removed by a prior call to remove_unneeded_paths_from_src() + */ + assert(!one->rename_used); + + old_dir = get_dirname(one->path); + while (*old_dir != '\0' && + NOT_RELEVANT != strintmap_get(dirs_removed, old_dir)) { + char *freeme = old_dir; + + increment_count(info, old_dir, UNKNOWN_DIR); + old_dir = get_dirname(old_dir); + + /* Free resources we don't need anymore */ + free(freeme); + } + /* + * old_dir and new_dir free'd in increment_count, but + * get_dirname() gives us a new pointer we need to free for + * old_dir. Also, if the loop runs 0 times we need old_dir + * to be freed. + */ + free(old_dir); + } /* * For any directory which we need a potential rename detected for diff --git a/merge-ort.c b/merge-ort.c index e2606c73ad88..f2b259986e22 100644 --- a/merge-ort.c +++ b/merge-ort.c @@ -1546,6 +1546,9 @@ static void get_provisional_directory_renames(struct merge_options *opt, } } + if (max == 0) + continue; + if (bad_max == max) { path_msg(opt, source_dir, 0, _("CONFLICT (directory rename split): " -- gitgitgadget