zig · one scan · zero deps
Per-file git metadata in Zig.
A Zig port of gitmeta — one git ls-files + single git log pass builds a Cache, then per-file metadata (last commit, author, churn, tracked/ignored) resolves in constant time. Zero third-party dependencies.
MIT licensed · no third-party dependencies · Zig 0.16 · POSIX
const gitmeta = @import("gitmeta"); const cache = (try gitmeta.New(gpa, "/path/to/repo")) orelse return; defer cache.deinit(); if (cache.lookup("main.zig")) |info| { std.debug.print("{d} {s} {d}\n", .{ info.last_commit_time, info.last_commit_author, info.commit_count }); }
what you get
Git history, one scan away.
One batch scan of the working tree, then constant-time answers to "who touched this file, when, and how often" — without a git log per path.
One-shot Cache
A single git scan up front, then O(1) per-path lookups. A 10k-file repo costs one git invocation, not one per file.
FileGitInfo
Last-commit time (Unix seconds, UTC), author, subject, first-seen, and commit count (churn) — all in one struct returned by lookup.
Tracked / ignored
Ask whether a path is under version control with isTracked, or excluded by .gitignore with isIgnored.
Pool
One Cache per repo, re-validated on HEAD change, and safe for concurrent use — ideal for a long-running server, watcher, or language tooling.
Zero dependencies
No third-party libraries — just the system git binary. Nothing to audit, nothing to vendor beyond git itself.
Clear "no git data" contract
New returns null (an optional ?*Cache) when the path isn't a working tree or git is missing — a signal, not an error. Zig 0.16, POSIX.
usage
Scan once, then look up.
Build a Cache with gitmeta.New, then resolve per-file metadata and tracked / ignored status in constant time. Wire the module in through build.zig.zon.
// Build once, then O(1) lookups const cache = (try gitmeta.New(gpa, "/path/to/repo")) orelse return; defer cache.deinit(); if (cache.lookup("main.zig")) |info| { _ = info.last_commit_author; _ = info.commit_count; // churn proxy } _ = cache.isTracked("main.zig"); // bool
// build.zig.zon → build.zig wiring const gitmeta = b.dependency("gitmeta", .{ .target = target, .optimize = optimize, }); exe.root_module.addImport("gitmeta", gitmeta.module("gitmeta"));
- gitmeta.New
- Cache.lookup
- Cache.isTracked
- Cache.isIgnored
- FileGitInfo
- Pool.get
- hasGitBinary
install
Add it to your build.
No package registry for Zig — fetch straight from the GitHub repo, then add the import in build.zig. Requires Zig 0.16.
zig fetch --save git+https://github.com/richardwooding/gitmeta-zig
This is the Zig port of gitmeta. Source, issues, and releases live on the GitHub repo.