summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--diffcore-rename.c40
1 files changed, 36 insertions, 4 deletions
diff --git a/diffcore-rename.c b/diffcore-rename.c
index a1ccf14001..2cf9c47c63 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -543,8 +543,15 @@ void partial_clear_dir_rename_count(struct strmap *dir_rename_count)
strmap_partial_clear(dir_rename_count, 1);
}
-static void cleanup_dir_rename_info(struct dir_rename_info *info)
+static void cleanup_dir_rename_info(struct dir_rename_info *info,
+ struct strset *dirs_removed,
+ int keep_dir_rename_count)
{
+ struct hashmap_iter iter;
+ struct strmap_entry *entry;
+ struct string_list to_remove = STRING_LIST_INIT_NODUP;
+ int i;
+
if (!info->setup)
return;
@@ -555,8 +562,33 @@ static void cleanup_dir_rename_info(struct dir_rename_info *info)
strmap_clear(&info->dir_rename_guess, 1);
/* dir_rename_count */
- partial_clear_dir_rename_count(info->dir_rename_count);
- strmap_clear(info->dir_rename_count, 1);
+ if (!keep_dir_rename_count) {
+ partial_clear_dir_rename_count(info->dir_rename_count);
+ strmap_clear(info->dir_rename_count, 1);
+ FREE_AND_NULL(info->dir_rename_count);
+ return;
+ }
+
+ /*
+ * 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
+ * associated with directories that weren't renamed.
+ */
+ strmap_for_each_entry(info->dir_rename_count, &iter, entry) {
+ const char *source_dir = entry->key;
+ struct strintmap *counts = entry->value;
+
+ if (!strset_contains(dirs_removed, source_dir)) {
+ string_list_append(&to_remove, source_dir);
+ strintmap_clear(counts);
+ continue;
+ }
+ }
+ for (i = 0; i < to_remove.nr; ++i)
+ strmap_remove(info->dir_rename_count,
+ to_remove.items[i].string, 1);
+ string_list_clear(&to_remove, 0);
}
static const char *get_basename(const char *filename)
@@ -1218,7 +1250,7 @@ void diffcore_rename_extended(struct diff_options *options,
if (rename_dst[i].filespec_to_free)
free_filespec(rename_dst[i].filespec_to_free);
- cleanup_dir_rename_info(&info);
+ cleanup_dir_rename_info(&info, dirs_removed, dir_rename_count != NULL);
FREE_AND_NULL(rename_dst);
rename_dst_nr = rename_dst_alloc = 0;
FREE_AND_NULL(rename_src);