Skip to content
gitmeta-zig

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

main.zig
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 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.