Artifact c87d8f11775e7f5f6efe086d068b299f7d16252c92dbd2416425b0c514df090d:
- File
docs/RELEASE-NOTES-0.3.31.md
— part of check-in
[60890d6661]
at
2026-09-26 17:56:15
on branch trunk
— landing accept: merge the tip it read once; --expect-tip refuses a moved branch
accept read the branch tip up to three times and merged it by name, so a push mid-accept could be merged unprobed. It now reads the tip once and merges that hash on both paths. --expect-tip HASH refuses with exit 6 and nothing written when the branch is no longer at HASH. Release 0.3.31. (user: dmestas, size: 2304) [annotate] [blame] [check-ins using]
# zit 0.3.31 zit 0.3.31 makes `landing accept` merge exactly one branch tip, and lets a caller refuse the accept if that tip isn't the one it checked. No artifact, tag namespace, sync message, or on-disk repository format changed. ## `landing accept` merges the tip it read, once A forge checks a landing — CI, a preflight — against a particular branch tip and then calls `zit landing accept`. If someone pushes to the branch in between, the accept merged the new tip, which nothing had checked. That window was wider than the caller's side of it. `accept` read the branch tip up to three times: once to see whether it was already landed, once to probe whether it merged cleanly, and once more when the merge itself resolved the branch by name. So even a caller that re-read the tip immediately before calling could have a push arrive mid-accept and be merged without having been probed. `accept` now reads the tip once, at the start, and merges that exact check-in by hash — from a checkout and on a bare store with `-R` alike. Later pushes stay on the branch, unlanded. This protects every caller, whether or not it uses the new flag. ## `--expect-tip HASH` A caller that checked a tip names it: ``` zit landing accept ID -R store --user NAME --expect-tip HASH ``` If the branch isn't at HASH, the accept is refused with **exit status 6** and nothing is written: ``` zit landing: branch feat/x is at CURRENT, not HASH; nothing was written ``` Exit 6 is its own status so a caller can tell "the branch moved; check the new tip and ask again" apart from exit 5 (conflicts, which need a human) and exit 1 (an error). The flag is refused on the other `landing` subcommands. Without it, `accept` behaves as before, except that it now merges a single tip read. `zit merge` needs no such flag: it already accepts an exact hash as NAME. ## Compatibility - No on-disk repository or wire format changed; Fossil RFC revision 00 remains the target. - `zit landing accept` gains `--expect-tip HASH` and exit status 6. - A push that lands on a branch while it is being accepted is no longer merged by that accept; it stays on the branch. ## Qualification `zig fmt --check`, `zig build test`, `e2e`, `smoke`, `git-import-e2e`, `git-export-e2e`, and `dst`, plus the three-runner CI battery.