# zit 0.3.34

zit 0.3.34 adds `zit git export`, which keeps a Git mirror of a repository
and pushes it. `landing accept` can refuse when its target has moved. A
`pack` or `shun --force` that reported success now survives a power cut.

No artifact, tag namespace, sync message, or on-disk repository format
changed.

## `zit git export` and `zit git status`

Keeping a GitHub mirror of a zit repository used to take a wrapper script
and a timer: clone, pull, `zit export-git`, `git push`. It is now one
command, in the shape Fossil gives it:

```
zit git export ../mirror --autopush git@github.com:someone/project.git
zit git export        # later: export what is new and push it
zit git status        # the mirror, the URL, and whether it is current
```

The first run exports into the Git repository at MIRROR, creating it, and
remembers MIRROR and the autopush URL in the repository's config. From then
on a bare `zit git export` does the whole round trip from any checkout, a
hook, a cron job, or a forge running against a bare store with `-R`. The
main branch is pushed fast-forward only, to the remote branch `main` unless
`--push-branch` names another. Nothing on the remote is ever deleted or
overwritten. The mirror settings are local and never sync to peers.

A Git host links a commit to an account by its email address, and a zit
login need not match anyone's username there. The export now takes each
author's address from their contact in the user table, and falls back to
`login@DOMAIN` only when there is none. The new `zit users contact LOGIN
INFO` sets a contact, as `fossil user contact` does.

The autopush URL is stored, so zit refuses one that carries a password. Use
a Git credential helper or an SSH remote instead.

`zit export-git SOURCE DEST` is unchanged, and `zit git export` uses it
underneath.

## `landing accept --expect-target`

`--expect-tip` in 0.3.31 let a forge name the branch tip it had checked.
Nothing guarded the other half of the pair: the target. A forge that ran CI
on the merge of branch B onto trunk T could accept after another landing
had moved trunk to T2, and get B merged onto T2, which nothing had tested.

`accept` now reads the target once and merges onto that exact check-in.
`--expect-target HASH` names the target the caller judged against. If the
target has moved, the accept is refused with **exit status 7** and nothing
written. That is apart from 6, the branch moving, so a forge knows to
re-judge the pair and ask again.

## A rewrite that succeeded survives a power cut

`zit pack` and `zit shun --force` install the rewritten store by renaming it
over `.zit`. A rename is not durable until the directory holding it is
fsynced, and they never did that. A power cut soon after a successful
`shun --force` could bring back the old store, with the content the shun
had removed. They now fsync the directory after the rename.

The simulation's fault layer can now lose directory entries as well as file
bytes. A create, rename or delete that no directory fsync made durable is
undone at a simulated power cut. The rewrite sweep uses this at every crash
point, and it requires a rewrite that reported success to come back as the
new store. That check failed until the fsync was added.

## Also

- The repository config's buffer was sized for one keyed setting fewer than
  it can hold. A config with every setting at its maximum length would have
  overrun it. It is now sized from the number of keys, and a test fills
  every one.

## Compatibility

- No on-disk repository or wire format changed; Fossil RFC revision 00
  remains the target. The new mirror settings are keyed config entries that
  earlier releases skip.
- `zit landing accept` gains `--expect-target HASH` and exit status 7.
- `zit git` and `zit users contact` are new.

## Qualification

`zig fmt --check`, `zig build test`, `e2e`, `smoke`, `git-import-e2e`,
`git-export-e2e`, and `dst`, plus the three-runner CI battery.
