Skip to content
zit Artifact [804a4fee01]
Login

Artifact [804a4fee01]

Artifact 804a4fee01a2deaf24adafb92ef63624b7e5a6ee4a94caf61d4bed4b2e0f2afb:


# zit 0.14.0

zit 0.14.0 lets a repository's owner erase a version of a file on every
peer that syncs, and makes `annotate -n` and the history of one file
cheaper on a forge.

This release is from trunk. Stores, caches and the daemon protocol version
are unchanged from 0.13.0; nothing is rebuilt on upgrade.

## Signed erasures

Until now `zit shun --force` erased a version on one store only; other
devices, the server and old clones still held the bytes and could sync
them back. An erasure the owner signs now reaches every peer that syncs,
directly or through a server, and every peer refuses the bytes afterwards.

- **Where it lives.** An erasure is a row in Fossil's existing shun list
  (`/shun`), with Fossil's payload byte for byte. Its comment carries an
  Ed25519 signature over the project code, the hash and the time, a
  not-before time and a kind (erase or cancel).
- **Who can erase.** One owner key per repository. `zit shun key generate`
  makes it and pins the public half; `--print` or `-F json` prints the pair
  without writing a key file, for a key kept in a platform keychain and
  passed per call in `ZIT_ERASURE_KEY`. A clone pins the key of the store
  it clones from; a pull, sync or `config pull` never changes it, and
  `zit shun key pin` replaces it by hand. A peer applies only rows that
  verify against its pinned key, so a lost device cannot erase history.
- **Erasing.** `zit shun --force --sign HASH...` signs one or more hashes
  in one step. An erasure applies 24 hours after it is signed, or at once
  with `--now`; `zit shun cancel HASH` withdraws it inside the 24 hours.
  `zit shun --list` (and `-F json`) shows pending and applied erasures.
- **Carriage.** Every `pull` and `sync` asks for the shun list, records the
  rows that verify, and removes the erased bytes at the end of the session.
  A push sends the signed rows the server does not already have. `zit
  serve` accepts a verified row from a user with Write access, refuses
  unsigned rows while it has a key pinned, and removes the bytes between
  connections; the server must have the owner's key pinned.
- **After it applies.** `cat`, `diff` and `annotate` of an erased version
  exit 8 saying it "was erased by the repository owner", and `log -F json`
  reports `"content": "erased"`. The bytes also leave `purge`'s graveyard,
  and `purge undo` will not restore them. An applied erasure stays applied
  if the pinned key later changes. A running `zit daemon` notices an
  erasure reaching its time without any write.
- **`sync` and `pull -F json`** report `"erasures_deferred": N`, the rows
  this session carried that are not yet fully applied, because another
  process held the store. The exit status does not change, and the next
  session applies them.
- **Stock Fossil.** `fossil clone` from a zit server removes erased bytes,
  and `fossil configuration pull shun` makes Fossil refuse them. Stock
  Fossil applies a pending erasure at once and keeps it after a cancel.
  Pushing to a stock Fossil server needs Admin; without it zit says so and
  finishes the sync without the rows. A Fossil client cloning a zit server
  that has a key pinned prints "Skipping non-exportable setting:
  erasure-key", which is harmless.

The sync protocol draft describes the row format and the rules in a new
section 9.3.1.

## annotate -n

`annotate -n N` now answers from the blame cache when that file's cache
holds an answer from an earlier unlimited `annotate`, so a file annotated
once in full costs about the same at any limit. On a 32,500-line file,
`annotate -n 50` went from 0.68 s to 0.09 s. The answer is the same as
walking the versions, byte for byte. The cache cannot stand in for the walk
where a version inside the limit has its primary parent outside it and a
merge parent inside it; that walk runs as before. A limited `annotate` does
not fill the cache on a long history.

## log for a path

`zit log PATH` walks the ancestry with bit sets instead of hash tables. A
200-row page of a 11,000-version history costs about 0.09 s instead of
0.19 s.

## Daemon

A stopping `zit daemon` lets go of its store's lock as soon as it stops
listening, before it writes its caches. A new daemon whose socket nothing
answers on waits up to 2 seconds for the lock, so a restart right after a
stop is no longer refused. A daemon that is serving is still refused at
once.

## Compatibility

Stores, check-ins, the sync protocol and the daemon protocol version are
unchanged, and no cache changes format.

A signed erasure row reads, to an older zit, as an ordinary shun with an
unusual reason: it refuses the bytes at once, with no delay and no cancel.
Until every peer runs 0.14.0, give `--now` or expect older peers to apply an
erasure early.

## 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).