]> git.ipfire.org Git - thirdparty/git.git/commitdiff
diff-index: don't queue unchanged filepairs with diff_change()
authorRené Scharfe <l.s.r@web.de>
Sun, 30 Nov 2025 11:47:17 +0000 (12:47 +0100)
committerJunio C Hamano <gitster@pobox.com>
Sun, 30 Nov 2025 17:58:53 +0000 (09:58 -0800)
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>
diff-lib.c
diff.c
diff.h

index b8f8f3bc312fbe7af0e95e1f4dd6720da45705f0..8e624f38c6d6f34bb499bbd8b6a96fb6c0ca09da 100644 (file)
@@ -418,13 +418,12 @@ static int show_modified(struct rev_info *revs,
        }
 
        oldmode = old_entry->ce_mode;
-       if (mode == oldmode && oideq(oid, &old_entry->oid) && !dirty_submodule &&
-           !revs->diffopt.flags.find_copies_harder)
-               return 0;
-
-       diff_change(&revs->diffopt, oldmode, mode,
-                   &old_entry->oid, oid, 1, !is_null_oid(oid),
-                   old_entry->name, 0, dirty_submodule);
+       if (mode != oldmode || !oideq(oid, &old_entry->oid) || dirty_submodule)
+               diff_change(&revs->diffopt, oldmode, mode,
+                           &old_entry->oid, oid, 1, !is_null_oid(oid),
+                           old_entry->name, 0, dirty_submodule);
+       else if (revs->diffopt.flags.find_copies_harder)
+               diff_same(&revs->diffopt, mode, oid, old_entry->name);
        return 0;
 }
 
diff --git a/diff.c b/diff.c
index a1961526c0dab1af182d4f400468bf5617f5175c..c3063d827e16d14382947302c06320108a49c270 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -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;
diff --git a/diff.h b/diff.h
index 31eedd5c0c39d336205b05ed0125c5ba316169d5..e80503aebb8d5072dd72c8faa4abe2b70d61ec9c 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -572,6 +572,11 @@ void diff_change(struct diff_options *,
                 const char *fullpath,
                 unsigned dirty_submodule1, unsigned dirty_submodule2);
 
+void diff_same(struct diff_options *,
+              unsigned mode,
+              const struct object_id *oid,
+              const char *fullpath);
+
 struct diff_filepair *diff_unmerge(struct diff_options *, const char *path);
 
 void compute_diffstat(struct diff_options *options, struct diffstat_t *diffstat,