Compaction Is a Rewrite

Retention keeps a history finite. Rewriting a branch to do it changes every hash downstream — including the labels that were supposed to outlive the rewrite.

A recorder that never forgets becomes a disk problem. The history is deduplicated by Git, but a snapshot every few seconds still adds up: the trees are cheap, the commits and indexes are not, and the timeline becomes unusable long before the disk is full.

Retention is age-tiered. Every snapshot survives for a day, one per hour up to a week, one per day up to a month, one per week up to ninety days, with a minimum of fifty snapshots. The tip is never dropped. Before the first retained snapshot, an archive: root keeps the tree that existed just before the window, even when the snapshots around it are gone.

You Cannot Delete from the Middle

Git cannot remove a commit from the middle of a branch without rewriting everything that follows. Compaction reads the branch oldest first, plans what stays, and rebuilds the chain with git commit-tree, reusing the original tree, author date and message:

git commit-tree <tree> -p <parent> -m "snap: …"

The branch tip is updated with a compare-and-swap update-ref, then reflog expire --expire=now --all and gc --prune=now reclaim the old objects. The project repository is not involved. The history is not edited; it is reconstructed, and the old chain is allowed to disappear.

The archive root is the one new commit. It represents the state immediately before the first kept snapshot, so a retention policy that keeps no old snapshots still leaves a usable starting point.

The Labels Paid the Tax

Labels were the obvious casualty. A label is keyed by full commit hash in the history directory’s labels.json, and rewriting a commit changes its hash. If compaction had simply dropped the old chain, every label on a kept snapshot would have pointed at nothing.

Compaction now builds an old-to-new map while it rebuilds the branch and rewrites the label file in the same locked pass. A label whose snapshot was dropped disappears with it. A label on a kept snapshot follows the new hash. The labels are not stored as Git tags or notes for exactly this reason: they would have been a second history to compact.

The same question applies to any future metadata keyed by a commit hash. The rewrite is not a maintenance detail at the edge of the system; it is a migration of every reference the system has ever stored.

The Second Run

The interesting test is not the first compaction. It is the second one. An archive root is older than the retention window by design, so a naive policy rewrites it again on every run. The compaction planner treats archive: as a deliberate base and leaves it alone. After the rewrite, the placeholder must still accept new snapshots on the rewritten branch, and the next snapshot must chain onto the new tip.

That is the contract: retention may remove history, but it may not break the recorder’s ability to add to it.

One rewrite at a time is manageable. The next problem was two operations at once.


Compaction is not maintenance at the edge of the system. It is a migration of every reference the system has ever stored, and the second run is the real test. A policy that survives one rewrite and breaks the next has not solved retention; it has scheduled a failure.

AI Insights: Retention Is a Migration
Source Code: MPL-2.0 · Content: CC BY-SA 4.0 · Credits & AI Disclosure