zit 0.3.35 adds zit merge-tree, which writes the tree a merge would
produce without a checkout. A commit no longer holds the repository's lock
while you write its message. Landing verbs stop reading the whole store.
A merge keeps a file mode that only the other side changed.
No artifact, tag namespace, sync message, or on-disk repository format changed.
zit merge-tree
A forge that tests a branch as merged into its target used to clone the whole repository, check out the target, turn autosync off, merge, and read the conflicts out of text meant for people. It needed only the merged files.
zit merge-tree feat --into trunk --out merged/ # the files
zit merge-tree feat --into trunk --tar > merged.tar.gz
It merges from the repository alone and writes plain files or a
gzip-compressed tar. Nothing is written to the repository and no checkout
is created, so nothing it leaves behind can commit or push. It works with
-R on a bare store.
A pair that does not merge cleanly writes nothing, lists the conflicting
paths on stdout one per line, and exits 5, the status landing accept
gives the same finding. The tar's bytes depend only on the pair, so a forge
can cache it by the two tips.
It is the same merge merge --probe judges and landing relies on: one
function now produces the merged tree for all three, so they cannot
disagree about whether a pair merges or what it merges to.
A commit waiting for its message holds no lock
zit commit took the repository's write lock before scanning the tree and
held it until the check-in was on disk, through the message editor and
PGP signing. Other writers wait at most a minute for that lock, so a commit
message left half-written turned them away: a tag add, a pull, and a
peer's push to zit serve on that checkout, which answered HTTP 500.
A commit now takes the lock twice, briefly: once to read the repository,
and once to write the check-in. The tree scan, content checks, the
before-commit check, the editor and signing all run without it. If
another writer changed the repository in between, the commit checks again
before writing. If its parent is no longer the tip of the branch, or its
branch tags or the settings it acted on changed, it is refused, nothing is
written, and a message from the editor is kept for -M.
With it:
- A writer turned away by a busy lock prints the lock's own message and stops, instead of adding "input/output error".
zit serveanswers 503 for a repository another writer holds, andpushsays the peer's repository is busy and to try again.- The lock's messages no longer overwrite what a command has already written to a redirected stderr.
Landing verbs no longer read the whole store
Every landing verb found its records by reading every entry in the store,
so an accept grew slower as the repository grew. They now find forum posts
through .zit-cache/forum, a list of their names kept against the store's
current contents. Each read extends it over what was added since the last
one, so it gives exactly the answer a full scan would. A store rewritten by
pack or shun --force rebuilds it once.
A merge keeps a mode the other side changed
A branch that made a script executable merged as "0 files changed", and
the script stayed non-executable. zit merge now does what Fossil does: a
mode only one side changed is taken from that side. An overwritten file
also gets its new mode; before, only a newly created one did.
Compatibility
- No on-disk repository or wire format changed; Fossil RFC revision 00
remains the target.
.zit-cache/forumis a disposable cache. zit merge-treeis new.zit serveanswers 503, not 500, when another writer holds the repository.
Qualification
zig fmt --check, zig build test, e2e, smoke, git-import-e2e,
git-export-e2e, and dst, plus the three-runner CI battery.