# zit 0.13.0

zit 0.13.0 aligns its line diff and three-way merge with Fossil's, and
makes the reads a forge pages through cheap on large stores: annotate,
the history of one file, and the daemon's start and feed.

This release is from trunk. Stores and the wire are unchanged from 0.12.1.
Two caches beside each store are rebuilt once; see Compatibility.

## Diff and merge follow Fossil

- **Line diff.** Every line diff in zit, from `diff` and its line counts to
  `annotate` and `merge`, is a port of the line diff in Fossil's diff.c
  (D. Richard Hipp). It replaces the patience and Myers engines, so zit
  aligns repeated lines as Fossil does, and `annotate` credits a check-in
  only with the lines its diff adds.
- **Three-way merge.** `merge` walks the two edit scripts as Fossil's
  merge3.c does. An edit beside the other side's change now merges cleanly.
  Where both sides add lines at the same point, the merge now stops with a
  conflict, as Fossil's does, instead of taking both. Every merge decision
  and merged text matches `fossil 3-way-merge`, except where zit keeps a
  final newline or a byte-order mark on purpose.

## annotate

- **`-n N` is Fossil's version limit.** `annotate -n N` walks at most N
  versions of the file, newest first. A line the oldest walked version
  already carried is printed with blank check-in and date columns, as
  `fossil annotate` prints it. Before, `-n` counted check-ins and credited
  older lines to the oldest check-in shown. A script that read those
  columns from every line must now allow blank ones, or pass `-n none`.
- **Versions come from the file-history index**, and the walk stops as
  soon as `-n` or the nearest cached version allows. `annotate -n 50` of
  the most-edited file in a 644 MB store went from 38 s to 50 ms.
- **A blame cache.** `annotate` keeps the answers for a file's recently
  annotated versions in `.zit-cache` and starts from the nearest one, so
  annotating a tip after a new commit costs tens of milliseconds instead
  of seconds. An answer that depended on a missing parent, a gap, a limit
  or content removed by policy is never cached.

## log for a path

- `zit log PATH` reads content only for the rows it prints and decides the
  rest from the file index. A 200-row page of a 2,000-version history costs
  tens of milliseconds.
- `--offset N` skips N rows, as Fossil's `finfo` spells it. `--cursor C`
  starts after the row a cursor names, and `-F json` returns the next
  cursor. A cursor page costs the same at any depth; an offset page still
  costs the rows it skips. Page by cursor where you can.

## Daemon

- **Start.** `zit daemon` answers its first request in about 0.3 s on a
  68,000-file store, where it took 8 to 10 s. It opens what a commit needs
  on the first commit, from the saved log index, and that commit costs
  about a second more than later ones.
- **After a commit** the daemon reads only the frames the commit added
  instead of reopening the store.
- **Feed pages.** A `feed` request may carry `limit`, the most check-ins to
  return; the reply's `more` says whether more follow. A page of 500 costs
  about 0.2 s. A request without `limit` is answered as before, and every
  feed reply now carries `more`. `more` can be true when only tag or other
  control artifacts follow, in which case the next page is empty. A daemon
  older than 0.13.0 refuses a request carrying `limit`.
- A session that reads the whole bootstrap feed peaks at 1.0 to 1.1 GB on
  a 68,000-file store, paged or not.

## Compatibility

Stores, check-ins, the sync protocol and the daemon protocol version are
unchanged.

Two caches in `.zit-cache` are rebuilt from the store, because the line
diff behind them changed: the blame cache, by the first `annotate` of each
file, and the line counts, by the first `crosslink --lines`. The line counts
are the whole upgrade cost, and they grow with a store's history, not its
size: stores with long histories take longest. Measured on a forge's stores
(8 cores, zit at low CPU priority beside the live forge), first command
after upgrading from caches 0.12.1 built:

| store | size | `crosslink --lines` | peak memory | `info` | `ls --long tip` | `annotate -n 50` |
|---|---|---|---|---|---|---|
| tcl | 420 MB | 717 s | 218 MB | 0.01 s | 0.11 s | 0.54 s |
| sqlite | 331 MB | 366 s | 220 MB | 0.02 s | 0.04 s | 0.28 s |
| pkgsrc (sub-manifests) | 632 MB | 299 s | 781 MB | 0.13 s | 0.94 s | 0.16 s |

Later `crosslink --lines` calls take under a second. A store with no
`.zit-cache` at all builds every cache on its first commands; on the same
forge, from an empty cache, `crosslink --lines` took 1,524 s on netbsd-src
(3.8 GB, 928 MB peak), 681 s on tcl, 353 s on sqlite, 341 s on fossil and
275 s on pkgsrc, and under 50 s on every smaller store.

A server can build the new caches ahead of time on a copy of each store,
taken with its `.zit-cache` (`crosslink --lines`, then `ls --long tip`),
then move the copy's `.zit-cache` into place at the switch, as for 0.12.0.
Do not let an older zit open a store whose caches are in the new format: it
rebuilds its own over them.

Merges that both add lines at the same point now conflict where 0.12.1
took both sides; see above.

## Qualification

The release manifest records native qualification against the exact tagged
source archive on macOS ARM64, Linux x86-64 and Linux ARM64, using the pinned
Zig 0.17.0 toolchain. Publication is gated on unit and end-to-end tests, Git
differentials, deterministic simulation, seeded fuzzing, and Fossil
interoperability checks on every distributed target.

For the basis of the conformance claim, see
[the 0.1.0 release notes](RELEASE-NOTES-0.1.0.md).
