zit 0.3.27 gives a refused protected-branch push a way back: the pusher moves the check-in to another branch and pushes again, and it lands there.
No artifact, tag namespace, sync message, or on-disk repository format changed.
A refused check-in can be amended onto another branch
A push that would join a protected branch is refused, and correctly so.
But the obvious recovery — zit amend X --branch other, which cancels
sym-trunk on X from a control artifact — was refused as well. The rule
judged a cancel by the name it carried and never by whether the server held
its target, so it treated "move this check-in you never admitted" the same
as "remove this check-in you hold". Every later push from that checkout
then carried the same refused round, and the only exits were a fresh clone
or a local purge and recommit.
Two things changed in the rule, both on the server:
A cancel aimed at a check-in the server does not hold is admitted. It removes that check-in from nothing the server has, so the check-in is judged where it joins instead — in the same round when the two travel together, or on its own arrival otherwise. This is the principle the rule already applied to
closed. A cancel on a check-in the server holds is refused exactly as before, because that is how a check-in leaves a protected branch.When a check-in is judged, a control artifact in the same round that moves it — the
*branch=Band*sym-Ba branch move mints against its hash — now counts. Judging the check-in by its parent alone would have put it straight back on the branch it was refused from.
Two smaller corrections fell out of testing this:
A check-in the server already holds, re-offered in a push, is no longer judged as joining anything. It was judged when it arrived; re-offering it is a no-op, not a claim.
The end-to-end fixture that builds a raw push from a clone was comparing raw digests against hex names, so it never excluded anything and every push it built re-sent the server's own artifacts. The refusal it pinned was real, but for the wrong reason. It now excludes what it means to.
The fronted push remains the front's rule: protect_globs decide which
branches are guarded, and nothing here introduces a new identity question
or a new header.
Compatibility
- No on-disk repository or wire format changed; Fossil RFC revision 00 remains the target.
- A pushed control artifact cancelling
sym-Bon a check-in the server does not hold was previously refused namingB. It is now admitted, and the check-in it targets is judged on its own. - A held check-in re-sent in a push against a protected branch was previously refused as a join. It is now ignored.
Qualification
zig fmt --check, zig build test, e2e, smoke, git-import-e2e,
git-export-e2e, and dst, plus the three-runner CI battery.