gitmeta
Fast per-file git metadata for Rust — last-commit time / author / subject, first-seen,
commit count (churn), and tracked / ignored status — resolved by scanning a working tree
once and answering per-path lookups in constant time. Shells out to the system git
binary rather than reimplementing git.
The batch design is the point: one Cache runs git ls-files + a single git log pass up
front, so a 10k-file / 5k-commit repo costs a handful of git invocations (~½ s) instead of
10k git log -1 -- <path> calls (~100 s).
A Rust port of the Go
gitmetalibrary.
One-shot Cache
let Some = new? else ;
if let Some = cache.lookup
cache.is_tracked; // bool
cache.is_ignored; // bool
lookup returns a &FileGitInfo:
Cache::new returns Ok(None) when the path isn't a git working tree (or no git binary is
present) — handle it as "no git data" rather than an error. Err is reserved for a git that
is present but failing on the happy path.
Why git rather than filesystem mtimes? A fresh clone sets every file's mtime to checkout time — so "recently changed" / "hot file" questions need git history, not the filesystem.
Pool — reuse across calls
A Pool keeps one Cache per repo and re-validates on HEAD change, so repeated lookups
over an unchanging tree don't re-scan. Ideal for a long-running process (server, watcher,
language tooling) answering many git-metadata queries. Pool::get hands back an
Arc<Cache>, shared unchanged across cache hits.
let pool = new;
if let Some = pool.get?
Async
Enable the tokio feature for async constructors — the sync API pulls in no async runtime:
[]
= { = "0.1", = ["tokio"] }
let cache = new_async.await?;
let pool = new;
let cache = pool.get_async.await?;
Cancellation comes for free: dropping the future (e.g. via tokio::time::timeout) kills the
in-flight git process.
Requirements
- Rust 1.79+ (MSRV).
- The system
gitbinary onPATH(gitmeta::has_git_binary()reports its presence;Cache::newreturnsOk(None)when git is absent or the path isn't a working tree).
Differences from the Go original
- Non-UTF-8 paths are decoded lossily (Go carried raw bytes). The crate passes
-c core.quotePath=falseto keep non-ASCII paths literal — fixing a latent bug in the Gologparse. - The sync API has no cancellation (Go used
context.Context); the async API cancels via future-drop.
License
MIT — see LICENSE.