Skip to content

Commit bfab7ff

Browse files
committed
diffcore-rename: use directory rename guided basename comparisons
Hook the work from the last several patches together so that when basenames in the sets of possible remaining rename sources or destinations aren't unique, we can guess which directory source files were renamed into. When that guess gives us a pairing of files, and those files are sufficiently similar, we record the two files as a rename and remove them from the large matrix of comparisons for inexact rename detection. For the testcases mentioned in commit 557ac03 ("merge-ort: begin performance work; instrument with trace2_region_* calls", 2020-10-28), this change improves the performance as follows: Before After no-renames: 12.775 s ± 0.062 s 12.596 s ± 0.061 s mega-renames: 188.754 s ± 0.284 s 130.465 s ± 0.259 s just-one-mega: 5.599 s ± 0.019 s 3.958 s ± 0.010 s Signed-off-by: Elijah Newren <newren@gmail.com>
1 parent 89a97ee commit bfab7ff

2 files changed

Lines changed: 29 additions & 10 deletions

File tree

Documentation/gitdiffcore.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ mark a file pair as a rename and stop considering other candidates for
186186
better matches. At most, one comparison is done per file in this
187187
preliminary pass; so if there are several remaining ext.txt files
188188
throughout the directory hierarchy after exact rename detection, this
189-
preliminary step will be skipped for those files.
189+
preliminary step may be skipped for those files.
190190

191191
Note. When the "-C" option is used with `--find-copies-harder`
192192
option, 'git diff-{asterisk}' commands feed unmodified filepairs to

diffcore-rename.c

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -668,7 +668,6 @@ static const char *get_basename(const char *filename)
668668
return base ? base + 1 : filename;
669669
}
670670

671-
MAYBE_UNUSED
672671
static int idx_possible_rename(char *filename, struct dir_rename_info *info)
673672
{
674673
/*
@@ -784,8 +783,6 @@ static int find_basename_matches(struct diff_options *options,
784783
int i, renames = 0;
785784
struct strintmap sources;
786785
struct strintmap dests;
787-
struct hashmap_iter iter;
788-
struct strmap_entry *entry;
789786

790787
/*
791788
* The prefeteching stuff wants to know if it can skip prefetching
@@ -835,17 +832,39 @@ static int find_basename_matches(struct diff_options *options,
835832
}
836833

837834
/* Now look for basename matchups and do similarity estimation */
838-
strintmap_for_each_entry(&sources, &iter, entry) {
839-
const char *base = entry->key;
840-
intptr_t src_index = (intptr_t)entry->value;
835+
for (i = 0; i < rename_src_nr; ++i) {
836+
char *filename = rename_src[i].p->one->path;
837+
const char *base = NULL;
838+
intptr_t src_index;
841839
intptr_t dst_index;
842-
if (src_index == -1)
843-
continue;
844840

845-
if (0 <= (dst_index = strintmap_get(&dests, base))) {
841+
/*
842+
* If the basename is unique among remaining sources, then
843+
* src_index will equal 'i' and we can attempt to match it
844+
* to a unique basename in the destinations. Otherwise,
845+
* use directory rename heuristics, if possible.
846+
*/
847+
base = get_basename(filename);
848+
src_index = strintmap_get(&sources, base);
849+
assert(src_index == -1 || src_index == i);
850+
851+
if (strintmap_contains(&dests, base)) {
846852
struct diff_filespec *one, *two;
847853
int score;
848854

855+
/* Find a matching destination, if possible */
856+
dst_index = strintmap_get(&dests, base);
857+
if (src_index == -1 || dst_index == -1) {
858+
src_index = i;
859+
dst_index = idx_possible_rename(filename, info);
860+
}
861+
if (dst_index == -1)
862+
continue;
863+
864+
/* Ignore this dest if already used in a rename */
865+
if (rename_dst[dst_index].is_rename)
866+
continue; /* already used previously */
867+
849868
/* Estimate the similarity */
850869
one = rename_src[src_index].p->one;
851870
two = rename_dst[dst_index].p->two;

0 commit comments

Comments
 (0)