diff-index: don't queue unchanged filepairs with diff_change()

diff_cache() queues unchanged filepairs if the flag find_copies_harder
is set, and uses diff_change() for that.  This function allocates a
filespec for each side, does a few other things that are unnecessary for
unchanged filepairs and always sets the diff_flag has_changes, which is
simply misleading in this case.

Add a new streamlined function for queuing unchanged filepairs and
use it in show_modified(), which is called by diff_cache() via
oneway_diff() and do_oneway_diff().  It allocates only a single filespec
for each filepair and uses it twice with reference counting.  This has a
measurable effect if there are a lot of them, like in the Linux repo:

Benchmark 1: ./git_v2.52.0 -C ../linux diff --cached --find-copies-harder
  Time (mean ± σ):      31.8 ms ±   0.2 ms    [User: 24.2 ms, System: 6.3 ms]
  Range (min … max):    31.5 ms …  32.3 ms    85 runs

Benchmark 2: ./git -C ../linux diff --cached --find-copies-harder
  Time (mean ± σ):      23.9 ms ±   0.2 ms    [User: 18.1 ms, System: 4.6 ms]
  Range (min … max):    23.5 ms …  24.4 ms    111 runs

Summary
  ./git -C ../linux diff --cached --find-copies-harder ran
    1.33 ± 0.01 times faster than ./git_v2.52.0 -C ../linux diff --cached --find-copies-harder

Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
René Scharfe
2025-11-30 12:47:17 +01:00
committed by Junio C Hamano
parent 9a2fb147f2
commit 38f88051da
3 changed files with 31 additions and 7 deletions

20
diff.c
View File

@@ -7347,6 +7347,26 @@ void diff_change(struct diff_options *options,
concatpath, old_dirty_submodule, new_dirty_submodule);
}
void diff_same(struct diff_options *options,
unsigned mode,
const struct object_id *oid,
const char *concatpath)
{
struct diff_filespec *one;
if (S_ISGITLINK(mode) && is_submodule_ignored(concatpath, options))
return;
if (options->prefix &&
strncmp(concatpath, options->prefix, options->prefix_length))
return;
one = alloc_filespec(concatpath);
fill_filespec(one, oid, 1, mode);
one->count++;
diff_queue(&diff_queued_diff, one, one);
}
struct diff_filepair *diff_unmerge(struct diff_options *options, const char *path)
{
struct diff_filepair *pair;