Blog
Post · 2026-06-12

The Sibling Clobber

In the spring of 2026 a git reset --hard ran in one CANONIC session and silently deleted fourteen commits that belonged to another. Nothing crashed. No error printed. The working tree simply rewound to match the remote, and the unpushed work of a sibling session — real commits, real closures, hours of it — became unreachable, orphaned in the reflog where nothing routine would ever look again. This is the quiet kind of disaster: the kind that leaves no smoke. We had been promising ourselves we would avoid it for weeks — commit often, fetch first, do not rebase over a sibling — and we kept not avoiding it, because a promise is not a mechanism. The fix, when it finally came, was not a better promise. It was a guard one layer down, in git itself, that makes the destructive command refuse to run. It is the same lesson the homelab teardown taught, told one level lower: you do not ask people to avoid the worst command — you make the worst command safe.


The disaster that leaves no smoke

Run several sessions against the same repository at once — a normal day here — and they share one working tree and one set of refs. One session finishes a unit of work, commits it locally, and has not yet pushed. A second session, cleaning up, runs git reset --hard origin/main to get back to a known state. To git, that is a perfectly ordinary request: move the branch pointer to the remote tip and make the working tree match. To the first session, it is an erasure. Its commits were never on the remote, so "match the remote" means "discard them." They are not deleted in the strict sense — they live in the reflog for ninety days — but they are off every branch, invisible to status, log, and diff, recoverable only by someone who already knows to go digging. In practice, gone.

What makes it a particular kind of bad is that it is silent and it is recurring. Silent, because a hard reset reports nothing about the work it just orphaned — there is no "you are about to drop 14 commits," because git does not consider them yours to keep. Recurring, because the conditions that produce it — parallel sessions, a shared tree, a fast hand reaching for a known-good state — are the conditions we work in every day. A hazard that only fires under normal operating conditions is not an edge case. It is a design flaw waiting for a quiet afternoon.

Discipline is a prompt, and a prompt does not hold

The first several responses to this were disciplinary, and they all failed the same way. Commit often, so there is less unpushed work to lose. Fetch before you reset. Never rebase over a branch a sibling is on. Each of these is correct, and each of them is a sentence — an instruction that lives in someone's working memory and has to be recalled, correctly, under time pressure, every single time, by every session, forever. That is not a mechanism; it is a hope.

The same realization runs under a lot of CANONIC's hardest lessons: a rule that exists only as a prompt is rule-by-whim. It is ephemeral, unauditable, and it degrades the moment attention does. The reset kept happening not because anyone was careless but because we were defending against a structural hazard with a behavioral patch. You can lose the same way a hundred times while doing everything you told yourself to do, because the thing you told yourself was never load-bearing.

The guard one layer down

Git has a place to put a mechanism exactly here: the reference-transaction hook, which runs inside the atomic operation that updates any ref and has the power to abort it. A guard installed there sees every branch update before it commits, and can refuse the dangerous ones. The rule it enforces is narrow on purpose, so it never touches honest work: abort only when the update is a rewind of a local branch — the new tip is not a descendant of the old — and the commits about to fall off the branch exist on no remote. A fast-forward passes. A normal rebase of your own un-pushed work passes. Pulling the latest passes. The only thing that does not pass is the specific move that silently orphans a sibling's unpushed commits — and when it is attempted, the transaction aborts and the commits stay on the branch where they belong.

Two details make it real rather than aspirational. It fires for every actor uniformly — every session, every tab, the operator included — because a guard that only some participants honor is just a slower prompt. And there is a deliberate escape hatch, CANONIC_ALLOW_REWIND, for the rare legitimate rewind, so the guard is strict by default and explicit to override rather than easy to forget. A separate gate, verify-no-destructive-reset, checks that the hook stays installed, because a guard that can quietly fall out of place is the same hazard wearing a different mask. The guard, the escape hatch, and the gate all live in the build canon, where a guideline cannot.

The same shape as the teardown

Set this beside the homelab teardown and they are the same event at two scales. In both, a single destructive command — docker rm, git reset --hard — could have erased work that took real effort to make. In both, the work survived not because anyone remembered to be careful but because something structural stood between the command and the loss: data bind-mounted to the host in one case, a reference-transaction guard in the other. And in both, the disaster did not end in an apology — it ended in an invariant, a thing now true about the system that was not true before, that makes the whole class of loss impossible to repeat. It is the same discipline that makes the books refuse to close below a perfect score, and a closure refuse to count until it is committed: structural, not remembered. That is the pattern: a scare arrives, the loss is prevented or undone, and the system comes out of it with one more thing it can no longer do to itself.

The reset that orphaned fourteen commits was, for a while, a scare without a tome — named in the walk but never written down on its own. This is the writing-down. The guard it left behind is small, narrow, and almost invisible in operation, which is exactly what a good invariant looks like: you only notice it on the day it refuses to let you delete your own history.

Sources

Claim Source Link
git reset --hard moves a branch to a new tip and discards commits that are not on the remote; they survive only in the reflog Git documentation: git-reset git-scm.com/docs/git-reset
Git's reference-transaction hook runs inside the atomic ref update and can abort it Git documentation: githooks git-scm.com/docs/githooks
A rule that exists only as a prompt is rule-by-whim; govern through durable, auditable canon The Right to Read and Write, HadleyLab hadleylab.org/blogs/the-right-to-read-and-write
Durability must be coupled to the work, not left to memory — the sixth move The Sixth Move, HadleyLab hadleylab.org/blogs/the-sixth-move
The close refuses to ship below a perfect score Closing the Books, HadleyLab hadleylab.org/blogs/closing-the-books
The reference-transaction guard, the CANONIC_ALLOW_REWIND escape, and the verify-no-destructive-reset gate are governed in the build canon CANONIC, BUILD/CANON canonic.org
The same make-the-worst-command-safe pattern at homelab scale Disaster Recovery, HadleyLab hadleylab.org/blogs/disaster-recovery

A promise not to delete your work is worth exactly nothing the first time someone forgets. A guard that cannot let you delete it is worth everything, every day, in silence.

The Sibling Clobber | THEORY | BLOGS