A Fossil version-control system in Zig.
zit reads and writes Fossil's artifacts and speaks Fossil's sync protocol, so
it clones from, pushes to, pulls from, and serves stock fossil, and a
checkout means the same thing to both tools. It is written from the
specifications, not ported from C: six Internet-Drafts frozen in
docs/rfcs/ are the authority, and Fossil itself appears only
in the differential tests that hold the two implementations to the same
answer.
The zit binary is a thin command over a library — a Zig counterpart to
libfossil. No module touches ambient time, randomness, filesystem, or network;
effects arrive through injected interfaces, the sync client is a pure state
machine, and the whole stack runs under seeded deterministic simulation where
any failure replays exactly from its seed.
Download
Release binaries for macOS ARM64 and Linux x86-64/ARM64, with checksums and a source archive, are at fossil.craftdesign.group/zit and mirrored to GitHub releases. See the 0.6.3 release notes for changes and compatibility, and the 0.1.0 notes for the basis of the conformance claim.
What it does
The everyday verbs — init, add, commit, update, merge, diff,
status, timeline, branch, tag, annotate, grep, bisect, stash,
undo/redo, clone, push, pull, sync, serve — with Fossil's output
shapes and Fossil's settings: .fossil-settings/ is read at every tier, and
ignore-glob, clean-glob, manifest, and the rest mean what they mean in
Fossil. zit help lists everything; any unambiguous prefix of a verb works.
Beyond that:
- Git in both directions —
import-gitandexport-git, each checked against a realgitin the differential suites. - Sub-manifests (
draft-fossil-submanifests-00) — S-card tree manifests bound per-commit manifest size on wide repositories, with adoption tooling that replays the repository's own history to measure whether enabling pays (submanifest analyze/enable;import-gitpicks a k the same way). This is the one compatibility break. A repository that emits S-bearing artifacts is permanently unreadable by stock Fossil, and sync's peer-version gate refuses to send trees to a pre-S peer rather than hand it artifacts it would misread. Emission is off by default; enabling it states the spend. - Sparse cones (
draft-fossil-sparse-cone-00) — partial worktrees (open --cone,cone). - Indexer feeds —
framesandcrosslinkstream raw artifacts and derived per-check-in records from a cursor, for a forge or a search index;infoanswers many names in one call, as text or JSON. - Store care —
verify(fsck),pack,purge,shun, and a local, disposable rebuildcheckpointthat keeps cache-cold opens fast on large histories. Never stored in the repository, never synced. - Review records —
landingproposes a branch to land on trunk as a reviewable record;precedentreuses a remembered conflict resolution.
What it leaves to Fossil
By decision, not omission — zit is a version-control system, not a forge.
- The collaboration layer. Wiki, tickets, forum, technotes, and
attachments are carried opaquely — stored and synced by hash, never
interpreted. The web UI goes with them:
zit uihands the checkout to a forge that serves it. - Unversioned files. No
uvverb and no unversioned store. The uvfile sync vocabulary is fully parsed and content-verified on the wire, and a peer's unversioned files are declined visibly — the session completes and reports how many were not transferred. - Manifest signing. Signature wrappers are recognized and stripped on read; zit never signs what it commits.
- SHA-1 repository creation. SHA-1 history clones and reads fine;
zit initwrites the sha3-256 naming policy only. - Delta-manifest authoring on fresh repositories. A repository whose history carries delta manifests keeps its dialect; a flat repository stays flat.
The specifications
The drafts are the authority, not Fossil's source. Test expectations come from the spec text and its worked examples — every normative clause a module implements gets a test citing its section. Where Fossil's implemented behaviour and an earlier draft text disagreed, the draft was corrected in place and lists the change in its Changes appendix.
| Module | Draft | What it specifies |
|---|---|---|
delta |
draft-fossil-delta-format-00 |
byte-level delta encoding |
artifact |
draft-fossil-artifact-format-00 |
manifest / control-artifact card format, naming, checksums |
repostate |
draft-fossil-repo-state-00 |
derived branch / tag / leaf / current-trunk views |
submanifest |
draft-fossil-submanifests-00 |
S-card tree manifests: bounded per-commit manifest size for wide repositories |
sync |
draft-fossil-sync-protocol-00 |
HTTP sync / clone protocol |
cone |
draft-fossil-sparse-cone-00 |
sparse cones: partial worktrees, the sparse-store path for monorepos |
Build
Requires Zig 0.16 or later.
zig build --release=fast # the shipped binary, at zig-out/bin/zit
zig-out/bin/zit version
zig build test # unit tests, one cited test per RFC clause
--release=fast is what the release builds use; a plain zig build is a
Debug binary, many times slower on a real history.
Further steps: zig build e2e (spawns the real binary), smoke (interop
against a fossil on PATH), muscle (differential transcript against
fossil), git-import-e2e / git-export-e2e (against a real git), dst
(deterministic simulation; -- --seed N replays), fuzz -- <target> --seed N,
bench, and cov (kcov line coverage). zig build --help lists them all.
Source control
This project is itself under Fossil. The repository lives in .zit.fossil
(ignored); open a checkout with fossil open --keep .zit.fossil. Trunk is
mirrored to GitHub, where issues and CI
live.