A forge that runs CI on a landing wants to test the branch as it would be once merged into its target, not the branch alone. Until now the only way to get that tree was to make it: clone the whole repository, check out the target, turn autosync off so nothing escapes, merge, and read the conflicts out of output written for people. That is a full clone per run, and a working checkout with a remote sitting in the pipeline's directory, safe only by convention.
A trial merge check-in is no better. Artifacts are permanent and sync to every clone, so a throwaway merge per push would scatter throwaway check-ins through everyone's history. Nobody needs that check-in anyway; the pair of tips already names what was tested.
0.3.35 adds the missing piece:
zit merge-tree feat --into trunk --out merged/
zit merge-tree feat --into trunk --tar > merged.tar.gz
It merges from the repository alone, in memory, and writes plain files or a tar. Nothing is written to the repository and no checkout is made, so nothing it leaves can commit or push. A pair that does not merge writes nothing, prints the conflicting paths one per line, and exits 5. The tar depends only on the two tips, so a forge can build it once per pair and hand it to every runner that asks.
Building it turned up a bug in zit merge itself. A branch that made a
script executable merged as "0 files changed": the merge compared files by
content and always kept the target's mode. Fossil takes a mode that only
one side changed, and now zit does too.
It also left one merge where there had been two. merge --probe, the
landing verbs and merge-tree now call the same function for the merged
tree, so a forge can no longer be told a branch merges cleanly by one and
see it conflict in another.
The same release stops zit commit holding the repository's lock while
its message is being written, which had turned every other writer away,
a push to zit serve included, whenever someone left an editor open. And
the landing verbs keep an index of forum posts in .zit-cache instead of
reading the whole store on every call.