Artifact cd658b63040a13a2e565ec04b0a06a791a2f7bf66b30975ce8eef22d338b1255:
- File docs/RELEASE-NOTES-0.3.38.md — part of check-in [bda4cf23d0] at 2026-10-05 22:16:26 on branch trunk — Release 0.3.38 (user: dmestas, size: 4748) [annotate] [blame] [check-ins using]
zit 0.3.38
zit 0.3.38 is about the person whose push onto a protected branch is refused. The refusal now says how to get out, the way out works whatever shape the push took, and behind a front that allows it, pushing again keeps the work on a branch of its own instead of being refused again. It also closes five ways past branch protection.
No artifact, tag namespace, or on-disk repository format changed. The cache beside a repository gained a column and rebuilds once from its saved records.
A refusal names the way out
A zit serve --fronted that refuses a push onto a protected branch now says
what to do:
check-in 9e1c5d97f9be would join protected branch 'trunk'; move it with
`amend 9e1c5d97f9be --branch NAME` and push again
That amend works for every way a check-in can land on trunk. Before, it
worked only for a check-in that joined trunk through its parent. A check-in
committed with --branch trunk, or one the pusher had already moved onto
trunk with amend, was refused again on every later push, and only a fresh
clone got out.
The reason is that the server now asks the same question its own derive answers. It replays the pushed artifacts over the check-ins they build on, newest move winning as in Fossil, and reads off where each pushed check-in ends up. It replays them in both orders the server's log can hold them in and refuses if either lands on a protected branch.
Pushing again keeps the work
A front can send X-Zit-Divert-Login with the login it authenticated. Then
the first refusal says what the next push will do:
check-in 9e1c5d97f9be would join protected branch 'trunk'. Your next push,
including the autosync after your next commit, keeps it on branch
attempt/jan/9e1c5d97f9be; or move it yourself with `amend 9e1c5d97f9be --branch NAME`.
and the next push lands there. The server writes the move itself, as a
control artifact recorded as zit-serve, in the same commit as the push, so
the protected branch never shows the check-in. It is dated after everything
in the push, so a pusher's clock running ahead cannot keep the check-in on
trunk. The reply says where the work went; stock Fossil prints it as "Server
says: ...", and a fossil sync brings the move back in the same exchange. An
X-Zit-Diverted response header tells the front, which can open a landing
from the attempt branch.
Nothing lands without the pusher having been told: a check-in is moved only
after a refusal for it, kept for a week in .zit-cache. Fossil's
autosync-tries retry counts as pushing again; the same command then prints
both the refusal and where the work went.
The client says what the server said
zit push and zit sync print the server's messages as server: ....
Before, zit read them and showed nothing. When the server kept a pushed
check-in on an attempt branch, zit push pulls the move straight away, so
the local repository agrees with the server before the next commit. zit
sync now quotes a refusal in the server's own words, as zit push already
did.
Five ways past protection, closed
Each needed a hand-made artifact or an unusual history; none is what zit or
fossil writes in ordinary use.
- A pushed amend dated in the past could "move" a check-in off trunk that the derive kept on trunk.
- A check-in whose parent the server did not hold landed on trunk, the main branch, until a parent that might never come arrived. It is now refused until the parent is pushed, when the main branch is protected.
- A check-in branching off trunk without cancelling the inherited
sym-trunkmade the nametrunkresolve to it. - Cancelling the
branchtag of a held check-in dropped it onto the main branch. - Retagging a held trunk check-in onto another branch removed it from trunk.
Compatibility
- No artifact or wire format changed; Fossil RFC revision 00 remains the
target. The new headers pass only between a front and a
--frontedserver, and the new pragma is one stock Fossil ignores. - The repository cache gained per-tag dates. A cache written by an older release is rebuilt from its saved records on first open.
- A push to a protected branch that builds on a check-in the server does not have is now refused when the main branch is protected, naming the parent to push first.
fossil pushandfossil syncexit 0 even after printing a refusal; a script driving stock Fossil cannot tell from the exit status. zit's own client exits non-zero.
Qualification
zig fmt --check, zig build test, e2e, smoke (now 19 scenarios, the
new one a stock Fossil 2.28 pushing onto a protected branch through a front
that diverts), git-import-e2e, git-export-e2e, and dst, plus the
three-runner battery.