Artifact 614189c9b06e57a5b197e80a99813c36a47be01485484c5d92953d709f91982d:
- File
docs/RELEASE-NOTES-0.3.28.md
— part of check-in
[c5243e961f]
at
2026-09-23 13:47:42
on branch trunk
— config export, and merge --probe over a stack
config export AREA [FILE] writes fossil's configuration export format, so an area can be backed up before import replaces it; import and merge now apply /shun cards, add-only in both modes. merge --probe with several NAMEs answers each against TARGET with the ones before it landed, holding merged files in memory and moving the merge base with the landing. Release 0.3.28. (user: dmestas, size: 4276) [annotate] [blame] [check-ins using]
# zit 0.3.28 zit 0.3.28 adds the counterpart to `config import`, so a configuration area can be backed up before it is replaced, and lets `merge --probe` answer a whole stack of branches the way a landing will meet them. No artifact, tag namespace, sync message, or on-disk repository format changed. ## `zit config export AREA [FILE]` `config import` replaces a configuration area from a file and `config merge` folds one in, but nothing wrote the current area out. The round trip is the point of the pair: back the table up, replace it, restore it if needed. ``` zit config export user backup.txt zit config import other.txt zit config import backup.txt # the table is back as it was ``` The output is fossil's `configuration export` format: a `#` banner, then one `config /AREA SIZE` card per row, byte-identical to what the sync protocol carries for that area — the same cards `import` and `merge` read and the same cards a fossil repository writes. FILE absent or `-` is stdout. The file carries no timestamp, so two exports of an unchanged table are the same bytes and a backup can be compared with `cmp`. The user area includes password hashes; the help says to treat the file as you would the repository. `import` and `merge` now also read `/shun` cards; before, they counted them as an area zit does not model and skipped them. Shun rows are **added in both modes**. `import` still replaces the user table, but replacing the shun table would un-shun whatever the file does not name, and a shun is never undone here — not by `zit shun`, and so not as a side effect of restoring a backup. `config pull` already held that line. The round trip is therefore exact for `user` and add-only for `shun`. The wire and a file now share one `/shun` payload parser, so a file cannot admit a row the wire would refuse. ## `zit merge --probe` answers a stack `merge --probe NAME --into TARGET` answers whether one branch merges cleanly into one target. A stacked landing asks something else: whether rung 3 merges into the target *once rungs 1 and 2 are on it*. Probing each rung against the one below cannot answer that, because it knows nothing of what the target changed in the meantime. It can call a rung clean that stops the landing. Given several NAMEs, `--probe` now answers the landing's question: ``` $ zit merge --probe --into trunk r1 r2 r3 r4 merges r1 clean merges r2 clean merges r3 conflict (1) conflict f.txt merges r4 not-reached ``` Each rung is merged, in memory, onto the target with the rungs before it already landed. A rung after one that stopped is `not-reached`: a merge that did not complete leaves nothing to continue from. A rung already inside the landed tree is `up-to-date` and the chain continues. Still read-only, still exit 0 in every case. One NAME prints exactly what it always has, and a real merge still takes one NAME. Two things make the chain more than a loop over the existing probe: - **The landed tree is held as content, not names.** The single probe compares file hashes and only reads blobs to decide a conflict. A cleanly merged file has no name in the store until someone commits it, so the next rung's side is a map of stored blobs *or* merged bytes. - **The merge base moves with the landing.** Once rung 1 has landed, the target's tip has it as an ancestor, so rung 2's base is the nearest common ancestor with anything landed, not the target's old fork point. Merging the landed tree against the old fork point would see rung 1's edit on one side and rung 2's rewrite of it on the other, and report a stacked rung as conflicting with its own parent. The test for this was checked by breaking the base on purpose: it then reports exactly that false conflict. ## Compatibility - No on-disk repository or wire format changed; Fossil RFC revision 00 remains the target. - `zit config import|merge` now apply `/shun` cards (add-only) instead of ignoring them. The summary prints one line per area touched. - `zit merge --probe` with more than one NAME was previously refused as an extra argument; it now probes the chain. ## Qualification `zig fmt --check`, `zig build test`, `e2e`, `smoke`, `git-import-e2e`, `git-export-e2e`, and `dst`, plus the three-runner CI battery.