go · one scan · o(1) lookups
Per-file git metadata, fast.
One batch scan of a working tree, then constant-time per-path lookups for last-commit time, author, churn, and tracked/ignored status — a 10k-file repo costs one git pass, not ten thousand.
MIT licensed · no third-party dependencies · needs the system git binary
cache, _ := gitmeta.New(ctx, "/path/to/repo") if cache == nil { return } // not a git working tree if info, ok := cache.Lookup(path); ok { fmt.Println(info.LastCommitTime, info.LastCommitAuthor, info.CommitCount) } cache.IsTracked(path) // bool
what you get
Git history, at lookup speed.
Pay the git cost once, up front — then every per-path question is a map read. Built for tooling that touches thousands of files.
One scan, then O(1)
git ls-files + a single git log pass up front; per-path lookups are constant time — no git log -1 -- <path> per file.
Rich per-file info
Last-commit time / author / subject, first-seen date, and commit count as a CommitCount churn proxy — everything a "hot file" question needs.
Tracked / ignored
IsTracked and IsIgnored status checks straight off the scan, matching git's own check-ignore semantics.
Pool for long-running processes
One Cache per repo, re-validated on HEAD change — ideal for servers, watchers, and tooling that answer many queries over an unchanging tree.
Zero dependencies
Pure Go, no third-party imports. It just needs the system git binary on your PATH.
Graceful degradation
Returns a nil Cache when it isn't a git tree or git is absent (HasGitBinary() probe), so callers just treat it as "no git data".
usage
Scan once, look up anywhere.
A one-shot Cache for a single walk; a Pool when a long-running process serves many lookups over the same repo.
// One-shot: scan a tree, then look up paths cache, err := gitmeta.New(ctx, root) if err != nil { /* git error */ } if cache == nil { /* not a git tree */ } if info, ok := cache.Lookup(path); ok { fmt.Println(info.LastCommitTime, info.LastCommitAuthor, info.CommitCount) }
// Long-running: one Pool, reused across requests pool := gitmeta.NewPool() // built once per repo; refreshed when HEAD moves cache, err := pool.Get(ctx, root) if cache != nil { cache.IsTracked(path) cache.IsIgnored(path) }
- New
- Lookup
- IsTracked
- IsIgnored
- NewPool
- Pool.Get
- HasGitBinary
install
Add it to your module.
One import, no transitive dependencies — just the git binary at runtime.
go get github.com/richardwooding/gitmeta
import "github.com/richardwooding/gitmeta"
Extracted from file-search-on, where it powers the git_* search attributes. Full API on pkg.go.dev.