[PATCH 0/4] last-modified: use the pathspec's Bloom key to pre-filter commits
From: Toon Claes <hidden>
Date: 2026-07-17 15:47:08
We have received a report[1] git-last-modified(1) is slow compared to
git-log(1) if you want to find the last commit for all entries in a
directory. For example running the following command on ziglang/zig[2]:
$ git last-modified -t --max-depth=0 $OID -- doc/langref/
Turns out to find results about 2.5 times slower than:
$ git log --name-status -c --format=commit%x00%H %P%x00" \
--parents --no-renames -t -z $OID -- :(literal)doc/langref
Now the latter needs some post-processing to come to the same results,
the total solution still is faster than integrating
git-last-modified(1).
After some research we've discovered the Bloom filters aren't used
optimally. But it turns out the code powering git-log(1) can fairly easy
be reused. We do this in a few steps:
- Patch 1 moves a condition around so it becomes deduplicated and
eventually can be reused by git-last-modified(1).
- Patch 2 exposes a helper from revision.c publicly. The function is
split out so the Bloom filter wouldn't be looked up twice from
git-last-modified(1).
- Patch 3 uses this new helper in git-last-modified(1).
- Patch 4 is bonus change, which optimizes when working with wildcard
pathspecs.
Below are benchmark on the ziglang/zig repository for the `doc/langref/`
directory (with commit-graphs writting using `--changed-paths`):
Benchmark 1: master last-modified
Time (mean ± σ): 52.6 ms ± 4.0 ms [User: 49.2 ms, System: 3.0 ms]
Range (min … max): 48.2 ms … 73.8 ms 62 runs
Benchmark 2: HEAD last-modified
Time (mean ± σ): 14.3 ms ± 1.8 ms [User: 12.0 ms, System: 2.1 ms]
Range (min … max): 10.5 ms … 18.9 ms 182 runs
Benchmark 3: git log
Time (mean ± σ): 17.4 ms ± 1.4 ms [User: 13.5 ms, System: 3.7 ms]
Range (min … max): 15.0 ms … 26.1 ms 185 runs
Summary
HEAD last-modified ran
1.22 ± 0.18 times faster than git log
3.66 ± 0.55 times faster than master last-modified
Similar timings are seen across a few other repositories (like GitLab's
monolith gitlab-org/gitlab)
[1]: https://lore.kernel.org/git/17f356ff-7bfb-47f5-b714-62a95cc8b821@codeberg.org/ (local)
[2]: https://codeberg.org/ziglang/zig
---
Toon Claes (4):
revision: move bloom keyvec precondition into function
revision: expose check for paths maybe changed in Bloom filter
last-modified: check pathspec against Bloom filter first
last-modified: keep per-path Bloom filters for wildcard pathspecs
builtin/last-modified.c | 11 +++++++++++
revision.c | 32 +++++++++++++++++++++++---------
revision.h | 17 +++++++++++++++++
3 files changed, 51 insertions(+), 9 deletions(-)
---
base-commit: 55526a18268bbc1ddaf8a6b7850c33d984eac9e9
change-id: 20260716-toon-speed-up-last-modified-b04ea1f21831