Skip to content

Commit f1e6c66

Browse files
committed
diffcore-rename: only compute dir_rename_count for relevant directories
When one side adds files to a directory that the other side renamed, directory rename detection is used to either move the new paths to the newer directory or warn the user about the fact that another path location might be better. While files renamed in subdirectories of a renamed directory are part of the computation of determining where the parent directory was renamed to, we don't necessarily need to record the each rename N times for a path at depth N. Perhaps an example would help explain it. If we have a path named src/old_dir/a/b/file.c and src/old_dir doesn't exist on one side of history, but the other added a file named src/old_dir/newfile.c, then if one side renamed src/old_dir/a/b/file.c => source/new_dir/a/b/file.c then this file would affect potential directory rename detection counts for src/old_dir/a/b => source/new_dir/a/b src/old_dir/a => source/new_dir/a src/old_dir => source/new_dir src => source adding a weight of 1 to each in dir_rename_counts. However, if src/ exists on both sides of history, then we don't need to track any entries for it in dir_rename_counts. That was implemented previously. What we are adding now, is that if no new files were added to src/old_dir/a or src/old_dir/b, then we don't need to have counts in dir_rename_count for those directories either. In short, we only need to track counts in dir_rename_count for directories whose dirs_removed value is RELEVANT_FOR_SELF. And as soon as we reach a directory that isn't in dirs_removed (signalled by returning the default value of NOT_RELEVANT from strintmap_get()), we can stop looking any further up the directory hierarchy. Signed-off-by: Elijah Newren <[email protected]>
1 parent e1f6794 commit f1e6c66

File tree

1 file changed

+22
-5
lines changed

1 file changed

+22
-5
lines changed

diffcore-rename.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,8 @@ static void update_dir_rename_counts(struct dir_rename_info *info,
463463
return;
464464

465465
while (1) {
466+
int drd_flag = NOT_RELEVANT;
467+
466468
/* Get old_dir, skip if its directory isn't relevant. */
467469
dirname_munge(old_dir);
468470
if (info->relevant_source_dirs &&
@@ -511,16 +513,31 @@ static void update_dir_rename_counts(struct dir_rename_info *info,
511513
}
512514
}
513515

514-
if (strintmap_contains(dirs_removed, old_dir))
516+
/*
517+
* Above we suggested that we'd keep recording renames for
518+
* all ancestor directories where the trailing directories
519+
* matched, i.e. for
520+
* "a/b/c/d/e/foo.c" -> "a/b/some/thing/else/e/foo.c"
521+
* we'd increment rename counts for each of
522+
* a/b/c/d/e/ => a/b/some/thing/else/e/
523+
* a/b/c/d/ => a/b/some/thing/else/
524+
* However, we only need the rename counts for directories
525+
* in dirs_removed whose value is RELEVANT_FOR_SELF.
526+
* However, we add one special case of also recording it for
527+
* first_time_in_loop because find_basename_matches() can
528+
* use that as a hint to find a good pairing.
529+
*/
530+
if (dirs_removed)
531+
drd_flag = strintmap_get(dirs_removed, old_dir);
532+
if (drd_flag == RELEVANT_FOR_SELF || first_time_in_loop)
515533
increment_count(info, old_dir, new_dir);
516-
else
517-
break;
518534

535+
first_time_in_loop = 0;
536+
if (drd_flag == NOT_RELEVANT)
537+
break;
519538
/* If we hit toplevel directory ("") for old or new dir, quit */
520539
if (!*old_dir || !*new_dir)
521540
break;
522-
523-
first_time_in_loop = 0;
524541
}
525542

526543
/* Free resources we don't need anymore */

0 commit comments

Comments
 (0)