# zit 0.3.41

zit 0.3.41 makes the crosslink line counts opt-in. A forge that shows
"+15 −3" on its timeline asks for them with `zit crosslink --lines`; every
other caller gets the stream 0.3.39 printed, at 0.3.39's cost. And
`zit merge-tree --commit` now records a clean merge, so a forge can merge
from the web without a checkout.

No artifact, tag namespace, wire, or on-disk repository format changed. The
crosslink record format is still `crosslink 1`.

## Action for forge clients

If you read `lines` lines from `zit crosslink`, add `--lines` to the call.
Without it, 0.3.41 prints no `lines` lines at all. A consumer that does not
read them needs no change.

## Line counts are opt-in

0.3.40 counted every changed file of every check-in the first time
`crosslink` ran over a repository, whether or not the caller wanted the
counts. On a long history that first run took many times longer than it
used to. Now:

- `zit crosslink` counts nothing, prints no `lines` lines, and reads and
  writes no line-count cache.
- `zit crosslink --lines` prints them exactly as 0.3.40 did: the counts
  `zit diff --numstat --checkin` gives, `- -` for a binary file, `0 0` for a
  mode-only change, and no `lines` line when the store cannot produce a
  side's content.
- A cache written by 0.3.40 is reused as it is.

## A shun no longer recounts everything

A check-in's counts are fixed by its name, so they are counted once. Under
0.3.40 a shun threw every stored count away. Now a shun recounts only the
check-ins that touch a path a shunned blob was written to: the check-in that
wrote it, and any later one that read it as the parent side. Those lose the
`lines` line for that file; everything else is served as stored.

The one exception is a history that holds a check-in whose changed files
are unknown. A shunned blob could sit at a path nothing records, so the
counts are taken again in full.

## merge-tree --commit records a clean merge

Before, `--commit` recorded a merge only when it had conflicts to settle,
and refused a clean one with "there is nothing to resolve". The clean case
is the common one, and it had no path that worked on the store alone. Now:

```
zit merge-tree feat --into trunk --commit -m "merge feat" --user u \
  --expect-current TRUNK_TIP --expect-other FEAT_TIP
```

records the merge on trunk, the check-in `zit merge feat && zit commit`
would make in a checkout of trunk. `--expect-current` and `--expect-other`
still guard it, and any `--resolved` file or `--delete` path is refused,
since nothing conflicts. The source may be any check-in, not only a branch
tip.

## Compatibility

- `zit crosslink` without `--lines` is byte-identical to 0.3.39.
- `zit crosslink --lines` is byte-identical to 0.3.40, except for files a
  shun has made uncountable.
- `--lines --no-cache` still matches the cached run byte for byte.
- `merge-tree --commit` on a conflicting pair is unchanged.
