Skip to content

Latest commit

 

History

333 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Void

The anatomy of version control.

A complete reimplementation of git in C - the object store, the index, the merge algorithm, and the wire protocol - plus four commands git doesn't have.

One external dependency: zlib. SHA-1, the binary index format, packfile parsing, delta reconstruction, the three-way merge, and the HTTP and SSH transports are all implemented from scratch.

📖 Documentation site →

Void — the anatomy of version control

The journey

Six phases, built bottom-up, in this order for a reason: nothing in a later phase could have been written before the one under it worked.

Six phases, one binary

Phase 1 is the whole foundation - a file becomes a blob, a blob becomes a tree, a tree becomes a commit, and every one of those is a real, inspectable file format, not an abstraction over one:

How a file becomes history

Phases 2 through 5 are git, rebuilt from that foundation up to a real network protocol: the staging index, commit history, branching and merging, and finally the pack protocol over HTTP and SSH - the phase most student git reimplementations don't reach.

Phase 6 is what came after the reimplementation was actually finished: four commands that don't exist in git at all, built by recombining what the first five phases had already made solid.

Four commands git doesn't have

The destination

It is actually git-compatible. Not "inspired by git" - compatible, and the test suite proves it rather than claiming it:

  • Objects are byte-identical to git's. Same SHA-1 over the same "<type> <size>\0<content>" framing, same zlib compression, same objects/xx/xxxxxxxx… layout. Tests cross-check against real git cat-file, git write-tree, and git's known empty-blob hash.
  • The networking talks to real git. clone, fetch, pull, push, and ls-remote are tested against actual git http-backend - genuine git server code, not a mock. Void speaks the real pack protocol, parses real packfiles, and reconstructs real deltas.

You can clone a GitHub repository with Void and commit to it with git.

And it goes past reimplementing. void undo, void fixup, void audit, and void checkpoint are four commands with no git equivalent, all resting on one invariant established in Phase 1: void never destroys an object.

void undo

Reverse the last operation that moved a ref - commit, merge, reset, branch delete, tag delete, rebase, fixup. Git has the reflog; this is one command.

void reset --hard HEAD~3   # oh no
void undo                  # fixed

Every operation that moves a ref writes a journal entry recording what moved, where it was, and how much undoing it is allowed to touch. Nothing is ever deleted from the object store, so undo always has something to point back at.

void fixup <commit>

Fold what's staged into an earlier commit, as if it had always been there. --amend only reaches the last commit; this reaches any of them.

void add oauth_client.c
void fixup a1b2c3d          # the commit where the bug actually is

Every commit after the target is rebuilt through a three-way merge. Messages, authors and dates are preserved exactly - a rewrite must never put your name on someone else's commit.

void audit

Scan the whole history - every commit reachable from every branch and tag - for committed secrets.

$ void audit
AWS access key id
    config.ini:1
    in commit a1b2c3d
    AKIA...(20 characters)

Deleting a secret in a later commit does not remove it - the
blob is still in the object store and in every clone. Rotate
the credential.

Detects private keys, AWS/GitHub/Google/Stripe/Slack/npm/Shopify/SendGrid token formats, JWTs, URL-embedded credentials, and hardcoded assignments. Never prints a secret in full - an audit tool that dumps credentials into your CI logs has moved them somewhere worse. Exits nonzero, so void audit && void push works as a gate.

void checkpoint

Snapshot the working tree - untracked files included - without touching your branch, index, or staged changes.

*/5 * * * * cd /path/to/repo && void checkpoint    # cron, not a daemon

Everything else in Void protects work you've already committed. This protects the hour of editing you haven't. A snapshot identical to the previous one isn't taken at all, so idle time costs nothing; the newest 50 are kept. void checkpoint restore snapshots your current state first, so it can't lose anything either.

Quick start

git clone https://github.com/ITAXBOX/Void.git
cd Void
make

./void init
./void add .
./void commit -m "first commit"
./void log --oneline

Requires: a C compiler, make, and zlib. POSIX (Linux, macOS, WSL).

Everything implemented

Repository - init, clone, status, help

Working tree - add, rm, diff (LCS-based unified diff, binary detection), .voidignore

History - commit (-m, -a, --amend, --no-edit), log (--oneline, -n), show, reset (--soft, --mixed, --hard), undo, fixup, audit, checkpoint

Branching - branch (-d, -D, -m, --list), switch / checkout (-c, -b), merge (fast-forward + three-way, conflict markers, --abort), rebase (--continue, --abort), stash, tag

Remotes - remote, fetch, pull, push (--force), ls-remote, over HTTP and SSH

Plumbing - hash-object, cat-file, ls-tree, write-tree, commit-tree, update-index, ls-files, pack-objects, unpack-objects

Every command above is documented in full on the documentation site as its own implementation card - the problem it solved, the files it touched, and the tests that prove it:

Implementation cards

Tested

make tests

63 suites, 2,251 assertions, all passing, checked under valgrind:

43 CLI suites one per command, black-box
15 unit suites SHA-1, packfiles, delta decoding, the index format, pkt-line framing, HTTP, transport, the journal
5 e2e journeys one per phase - multi-command sequences asserting HEAD, the index and the working tree agree after every transition

The e2e journeys exist to catch what per-command tests structurally cannot: drift that only becomes visible several operations later. The Phase 6 journey drives fixuprebasefixup on the rebase's own output → a conflict → checkpoint mid-conflict → --abort → four undos, then asserts that every commit id it ever saw is still readable.

How it works

src/
  core/       objects, sha1, compression, index, trees, commits, refs,
              packfiles, delta, http, ssh, transport, diff, journal
  commands/   one file per command
  utils/      files, repo detection, error handling, colour
include/      one shared header
tests/        cli/ · unit/ · e2e/

A few decisions worth knowing:

  • Nothing is ever deleted from the object store. "Deleting" a branch removes a name. This single invariant is what makes undo, fixup, rebase and checkpoint safe - and it's asserted end-to-end, not assumed.
  • Concurrent processes are handled. The index, refs, the journal and the config are each protected by lock files; the test suite launches real concurrent processes rather than simulating them.
  • Errors return, they don't exit. Callers decide whether to recover.

Why

Two reasons, and neither one was "the world needs another git."

Git is a tool I've used every day for years and always found genuinely useful and creative - not just infrastructure to get out of the way, but a piece of engineering worth understanding on its own terms: content-addressed storage, a merge algorithm that mostly gets out of your way, a wire protocol that turns a whole repository's history into a stream of deltas. Building it myself, from the object model up to the pack protocol, was the only way to actually see how those pieces fit rather than take them on faith.

The other reason is C. This project exists to master it at depth - binary file formats, network protocols, compression, cryptographic hashing, graph algorithms, memory management at scale - before moving into reverse engineering. Void is deliberately not an exercise: it is a real tool, git-compatible and tested against git itself, because the depth that transfers to RE work only shows up when the thing you built actually has to be correct.

License

MIT - see LICENSE.

About

A Git reimplementation written in C, featuring custom commands and core Git functionality implemented from scratch

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages