Skip to content
zit Timeline
Login

Timeline

50 descendants of edac449311916aa9

2026-09-16
22:11
file index: built by the derive, at ingest

fossil fills mlink as each check-in arrives and answers finfo by lookup. zit's derive computed the same row per check-in and dropped it; the index was rebuilt by a separate pass on the first PATH query, 6.8 min on pkgsrc and not resumable. The derive now hands each change set to an index builder as it links, stores it beside the checkpoint, and extends it over the tail on append; a cache hit computes nothing. The on-query build is the fallback and checkpoints every 8192 entries. Index format 4 records completeness so a partial checkpoint is never adopted whole. crosslink reports a tree's files instead of unknown. pkgsrc, fresh clone to first answer: 11.7 min -> 7.1 min + 1s. check-in: df99743ca4 user: dmestas tags: trunk

13:44
Release 0.3.17

A push with no URL keeps its credential; the tree-manifest index build is proportional to what changed. check-in: dbfe2adebc user: dmestas tags: trunk, version-0.3.17

13:43
file index: diff tree manifests by S card

Two tree check-ins were diffed by flattening both to full file lists, files-per-check-in per check-in: 34 minutes once on a pkgsrc mirror. The S-card runs are now walked side by side, skipping every sub-manifest whose hash did not move and resolving only where it did. Deletes are held to the end so a moved partition key cannot make a live file look deleted. Trees flatten on demand only for the root and flat/tree pairings; the derive feed never flattens. pkgsrc: 34.3 min -> 6.8 min. check-in: ea4abe48fd user: dmestas tags: trunk

13:43
push: keep the credential when the URL is omitted

push --user U --password P with no URL parsed to a payload-less no_url, which the verb rebuilt as a bare empty URL, dropping the credential; the push went out anonymous and a peer requiring a login refused it. The parser now mirrors sync: an omitted URL is an empty one, resolved to the saved remote at run time, and the credential comes through. S12 asserts an authenticated no-URL push and a stored-login push both land on fossil. check-in: 4dba18d355 user: dmestas tags: trunk

07:42
Release 0.3.16

File index works on submanifest stores; artifact shows S cards; a saved login authenticates a push that names no user. check-in: 8cfa57ecd3 user: dmestas tags: trunk, version-0.3.16

07:28
push: a saved login authenticates a push that names no user

push --user saved the derived secret, but the resolver returned anonymous the instant --user was absent, so autosync (which pushes with no arguments) always went anonymous and a peer requiring a login refused it. With --user absent the saved login now stands in, never prompting; --user "" still forces anonymous. push, sync and config pull share the resolver. Whether such a push lands on a fossil peer is zit#196, a separate pre-existing matter. check-in: e37768d073 user: dmestas tags: trunk

07:28
log PATH: diff tree manifests in the file index

On a submanifest store every check-in is a tree manifest, which the change-set capture refused as unknown, so the index recorded the whole log as unknown and a PATH query reconstructed per check-in anyway -- 39 minutes on a pkgsrc mirror. Trees now flatten inside the diff memo through the Repository seam, so the untouched diff sees a flat list; a tree that cannot be flattened stays unknown. Index format 2 -> 3 so a stale all-unknown blob is rebuilt once. check-in: 001c73defa user: dmestas tags: trunk

06:05
artifact: render S cards

A tree check-in carries its file set entirely by S cards and the card renderer had no S lane, so it printed as a manifest with no files while ls on the same hash listed thousands. One lane, in card order, checked against --raw. check-in: da2598d1ca user: dmestas tags: trunk

2026-09-15
01:30
Add Submanifest Guide check-in: e88e3d88ed user: dmestas tags: trunk
2026-09-14
16:27
Release 0.3.15

Makes the file-history index durable across commits. check-in: 37e2519ac5 user: dmestas tags: trunk, version-0.3.15

16:12
Extend the file index instead of rebuilding it

The v1 index recorded no coverage, so every commit threw it away and re-walked the whole log. v2 records n_rids, the entry count the index covers, and a later query walks only the tail past it. A fresh query walks the new check-ins; a repeat query walks none. check-in: 788b69f097 user: dmestas tags: trunk

13:43
0.3.14: version bump and release notes check-in: 37a5af6b08 user: dmestas tags: trunk, version-0.3.14
12:48
build: register the cross step with the CI pin

The negative-space pin requires every build.zig step to be either invoked by CI or listed with the reason it is not. The cross step was neither, so it failed all three runners -- the pin doing exactly its job on the commit that added an unregistered step.

CI compiles the real thing on all three shipped targets, so cross-compiling them again proves nothing new; the step is for the developer, before the push. Recorded as such. check-in: 770e641725 user: dmestas tags: trunk

12:14
build: compile for CI's Linux targets in the gate

This project links no libc and macOS links libc always, so a call that demands it compiles on a mac, passes every local lane, and refuses on both Linux runners -- the discovery order the fmt check already exists to prevent, and what zit#188 spent a red main on.

`zig build cross` compiles the CLI for x86_64-linux and aarch64-linux and runs nothing; gate depends on it. Verified to discriminate: reintroducing std.c.getenv fails cross while a plain macOS build still passes. check-in: 31c4850b95 user: dmestas tags: trunk

11:48
log: read the file-index kill switch at main's environ seam, not through libc

std.c.getenv demands libc linkage, which this project does not take, so both Linux runners refused to compile while macOS -- which always links libc -- built it and the local gate passed. cli.Ambient.environ documents exactly this rule; the seam existed and was bypassed.

Read $ZIT_NO_FILE_INDEX in main from init.environ_map like every other seam and hand the runner a flag. Cross-compiles clean to x86_64-linux and aarch64-linux. check-in: 1317aa9864 user: dmestas tags: trunk

02:46
log: answer a PATH filter from a file index, not by reconstruction (zit#188)

The predicate reconstructed a manifest per visited check-in, so one file's history on a mirror of SQLite cost minutes and grew with the history behind it. Persist what the derive already computes and throws away: captureFileFacts is Fossil's mlink row, so invert it by path into .zit-cache/finfo, keyed to the log tail and shun fingerprint like its sibling sidecars.

The PATH walk now traverses the derived adjacency, as the unfiltered walk has since #98, and the index narrows it. The index only NARROWS: an F-card-level diff over-reports a delta that restates a path with the hash it already had (one check-in in 2,113 on SQLite), so every candidate is still confirmed by the B-log-2 predicate and the output is byte-identical. --long reads one manifest per emitted row instead of per visited node.

README.md 72s to 1.6s, btree.c 25s to 1.1s, reconstructions 25,106 to 141. check-in: 17c3b0aaa2 user: dmestas tags: trunk

2026-09-13
23:05
log: memoize the PATH predicate's reconstruction (zit#188)

logChangesPath computed a check-in's effective content for PATH twice — once as `here`, once as the `parent` of the child below it — and each call re-read, re-verified and re-parsed the manifest because fileAt takes neither the walk's plaintext cache nor a baseline memo. One file's history on a mirror of SQLite took 129s.

Thread the walk's cache, a baseline memo, and an answer memo keyed by rid through the predicate, and through timeline -p, which shares the defect. Reconstructions per PATH walk fall from 2N-1 to exactly N; README.md 72s to 24s, btree.c 25s to 9s, timeline -p 16s to 7.5s, output byte-identical. check-in: 184cee5a2e user: dmestas tags: trunk

2026-09-11
20:39
0.3.13: version bump and release notes check-in: 2a427c830b user: dmestas tags: trunk, version-0.3.13
20:29
attach: add/rm/list verbs and the quarry stub (zit#186, zit#187)

The write side of the A card. add stores the blob then the attachment artifact in one commit and prints both hashes; rm ends the association with a sourceless card; list folds latest-per-(target, name). The new attachment-size-limit setting (config key 17) caps add, fossil's semantics with a 1 MiB default. A quarry attachment stub lists as external and zit artifact describes it. Smoke S15 pushes an attachment to real fossil and reads it back from fossil's attachment table. check-in: 170a2e88d0 user: dmestas tags: trunk

18:49
0.3.12: version bump and release notes check-in: 5a962c69ff user: dmestas tags: trunk, version-0.3.12
18:43
serve: mint clusters on a pull reply (zit#184)

Once a pull finds 100 or more held artifacts no cluster names, fold them into cluster artifacts — sorted, 800 M cards each, md5 Z — at fossil's create_cluster point and thresholds. They persist with the round and extend the index; the next reply announces the clusters, not the members. A zit-born repository clusters itself the first time anyone pulls from it: 161 artifacts, one cluster, 201 bytes on the next pull. check-in: 10c905d27b user: dmestas tags: trunk

17:52
sync: announce only what no held cluster names (zit#184)

A pull or push announced every held artifact with igot, every round — 1.25M lines, ~63 MB per direction on pkgsrc. Clusters are igot in bulk: index the held clusters (.zit-cache/clusters, keyed to the log prefix, kept warm by persist), announce held minus what they name, seed the promises they made that this repository never collected, absorb pushed clusters server-side so the reply begs for their members, and honour send-catalog (full inventory) and req-clusters (enclosed cluster igots). A no-op pkgsrc pull now sends 4.7 KB. Cluster promises the peer cannot keep are a warning, not a failed pull. No format changed. check-in: e1ca72a8ef user: dmestas tags: trunk

16:10
pull: persist only what was received, not the whole holdings store (zit#185)

A pull walked every held artifact in persistStore, reading each once from the lazy disk-backed holdings store just to early-return it: 194s of a 197s no-op pull at 1.25M artifacts, reconstructing nothing. Received artifacts are appended beyond the holdings' log-backed prefix, so persist now begins the walk there and processes only the received set. A no-op pull persists nothing; an incremental pull persists what it received, not the millions it already holds. No-op pkgsrc pull 209s to 7s. check-in: a25dcf28f5 user: dmestas tags: trunk

2026-09-10
23:56
0.3.11: version bump and release notes check-in: b1dc991ac0 user: dmestas tags: trunk, version-0.3.11
23:42
serve: suppress announced igot with a set, not a scan per artifact (zit#183)

emitReply walked every held rid and, for each, linear-scanned the peer's announced list to suppress a redundant igot — O(held × announced), so a no-op pull where both sides hold everything cost 760 s of server CPU at 1.25M artifacts. Build the announced/requested names into one set per reply and probe it once per rid. ZIT reports the probe count; a test pins it to the held count at two sizes regardless of what the peer announced. check-in: a93f014321 user: dmestas tags: trunk

2026-09-09
22:53
0.3.10: version bump and release notes check-in: 77f89b0bec user: dmestas tags: trunk, version-0.3.10
20:04
derive: a disposition sidecar skips what cannot contribute a record (zit#182)

One bit per log frame in .zit-cache/dispositions: crosslink-relevant or not. A full derive consults it and never reconstructs the file blobs and SUBMANIFEST tree nodes that were most of a wide store's walk; the walk distills a fresh map either way. Same trust tier as the log-scan index: self-checksummed, keyed to a validated log prefix, stamped with the shun fingerprint, absent on any doubt. pkgsrc submanifest cold derive 302 s to 22 s; a consuming derive's body is byte-identical, pinned by test. check-in: a18d2edd67 user: dmestas tags: trunk

17:58
derive: write the cache in place, never a second copy (zit#182)

repocache.store and checkpoint.store concatenated header + body + image into a full resident copy before writing; both now stream the pieces to the file with the checksum folded incrementally, byte-identical output. The clone path frees its view before the reopen builds a second derived state. ZIT_DERIVE_FOOTPRINT reports the derive body's composition. pkgsrc cold open: peak RSS 2.32 GB to 2.07 GB. check-in: 3107e23e24 user: dmestas tags: trunk

14:26
0.3.9: version bump and release notes check-in: c641321230 user: dmestas tags: trunk, version-0.3.9
14:13
clone: persist each round as it converges, release what is written (zit#172)

A dense clone no longer holds the repository in memory until the exchange ends: each round's artifacts land in the log and their resident bytes are released, the shape of git's index-pack. A delta whose basis has not arrived defers on its hash; a basis first seen as a phantom is revisited when its content lands. Cone-scoped clones keep the batched pass, whose keep set needs the converged store. Streamed and batched logs are byte-identical, pinned by test. ZIT_PERSIST_WAITING reports the drain's peak deferred set. check-in: 533b0a6490 user: dmestas tags: trunk

2026-09-07
16:17
README: describe zit as it is today check-in: bc8f8da929 user: dmestas tags: trunk
01:44
0.3.8: version bump and release notes check-in: f0b4cd974f user: dmestas tags: trunk, version-0.3.8
01:37
settings: read the checkout the way fossil does (zit#175)

Fossil-dialect globs treat ! as a class member; only ^ negates. open reads a versioned-only manifest setting out of the check-in and remembers --manifest=off so update cannot re-enable stamps. add --force adds a named ignore-glob match; directory expansion always honours ignore and clean globs. .fos root names compare case-sensitively on Linux. check-in: b7e077e430 user: dmestas tags: trunk

01:09
annotate: per-file hashes in the crosslink record, Myers diff

The crosslink record now carries each changed file's artifact hash (fossil's mlink shape), so annotate reads blobs by hash instead of re-deriving every manifest on the walk. merge3 moves to a linear-space Myers LCS and annotate caches plaintext and baselines across versions. Repocache format 5, checkpoint format 5: the first open after upgrading re-derives. Help states the 12-character prefix annotate actually prints. check-in: a6c2215859 user: dmestas tags: trunk

00:09
info: many names in one call, -F json check-in: e751c1c8a2 user: dmestas tags: trunk
2026-09-06
21:49
0.3.7: version bump and release notes check-in: 1f12f7b9a9 user: dmestas tags: trunk, version-0.3.7
21:39
info: render Q cards from the state, not the manifest (zit#177)

The crosslink record, the state and the image now carry each check-in's Q cards (sign and target), so the cherrypick/backout line needs no manifest read. Record format 4, image layout 7. info NAME 16 ms to 6 ms on libspatialite, level with leaves; output unchanged. check-in: adb05cc14e user: dmestas tags: trunk

20:59
repocache: a hit rewrites a stale or missing image (zit#180)

A cache whose image is absent or at an old layout replayed the record body on every fast_read open, since only a miss stored. The hit now serializes the image from the view it just built and stores it, so the fallback is paid once. check-in: 98c5d6c61a user: dmestas tags: trunk

20:47
timeline: read the image, not a full derive (zit#181)

The image has carried adjacency since layout 2 and comment/login since layout 6, so every default row renders from the zero-parse path; only full/-v/-p still read manifests. 60 ms to 8 ms on a 22k check-in store, output byte-identical across formats. check-in: 18ffce5678 user: dmestas tags: trunk

20:06
grep: read manifests only where the record says PATH changed (zit#178)

One record scan, as annotate, instead of a manifest per check-in: 20,937 reads to 272 on VERSION, 19s to 0.4s. Each version is reported once under its oldest introducer, matching fossil grep's list byte for byte. check-in: 6be0341149 user: dmestas tags: trunk

14:06
sync: read the Content-Type media type, not the whole header (zit#179)

A front web server that appends "; charset=utf-8" made the clone reply look compressed, so its plaintext was read as a 1.6 GB container and refused as too large. parseMediaType now ignores parameters and case, as fossil does; serve uses it instead of its own copy. check-in: 8488af309e user: dmestas tags: trunk, version-0.3.6

14:06
0.3.6: version bump and release notes check-in: 762cd0d3cc user: dmestas tags: trunk
2026-09-05
17:34
0.3.5: version bump and release notes check-in: 882eaddc57 user: dmestas tags: trunk, version-0.3.5
15:13
Honour every Fossil checkout setting file (#174)

Glob lists follow Fossil's tokenizer and '#' comment lines; crnl-glob, clean-glob, empty-dirs, encoding-glob, dotfiles and mimetypes work at every tier. Dotfiles are hidden by default and Fossil's checkout-state names are never listed. UTF-16 and invalid UTF-8 classify as Fossil's lookslike.c does; tokenizer rules from glob.c. check-in: 982afa3d8f user: dmestas tags: trunk

2026-09-02
22:25
0.3.4: version bump and release notes check-in: f785e3286b user: dmestas tags: trunk, version-0.3.4
22:15
zit#173: route ordering tiebreaks through the hashOf door; trap the raw store under image backing check-in: 8216f43a66 user: dmestas tags: trunk
02:57
0.3.3: version bump and release notes check-in: 441d99370f user: dmestas tags: trunk, version-0.3.3
01:32
annotate walks the file's versions, not the whole ancestry

Every ancestor cost a manifest read and a full-file line diff — ~36k of each on SQLite where ~400 touched the file. The cache records already say who changed PATH (their diff is against the primary parent, so unlisted means byte-equal there): untouched ancestors inherit the parent's content pointer, the engine copies the parent's origins on pointer-identity, and the LCS trims the common prefix/suffix before its O(n*m) table.

Unfinishable on SQLite before; 0.5-1.2s typical, 57s for a 15k-line heavily-edited file (the multi-hunk quadratic middle remains — a real diff core is the named follow-up). Attribution of a repeated line between equally-valid origins can shift, as any LCS tiebreak may.

zit#172 check-in: 22bdf84fd3 user: dmestas tags: trunk

2026-09-01
23:10
timeline reads no manifest for what the state answers; count the reads that remain

The default-format timeline inflated a manifest per row — the fetch condition still said 'a.format != .oneline' from when oneline was the default, so zit#170's medium default made every row read one for two strings the image now carries. 66.5s to 0.37s for the full SQLite timeline, output identical.

Repository.manifest counts its reads (ZIT_MANIFEST_READS=1 reports on exit), and an e2e runs ten listings over two history sizes and requires identical counts — a per-row reader fails by construction, no timing, no constants.

zit#172 check-in: 09fa1a7fb3 user: dmestas tags: trunk

2026-08-31
17:02
image: carry the comment and login per rid, so a listing reads no manifest

zit leaves read and parsed a whole manifest per row — through its delta chain — for the comment's first line and the login. A warm store is image-backed and the image carried neither, so commentOf answered null and every row fell back to that read: 472 leaves, one second, on sqlite.

The image now materializes both: the comment CSR-addressed per rid, the login interned (a repository has a handful of committers). layout_version 6 — an older image is a miss and rebuilds, as the disposable cache intends.

0.3.2. check-in: 71d327a695 user: dmestas tags: trunk, version-0.3.2

01:01
import-fossil help: keep 'zit submanifest enable' on one line check-in: edac449311 user: dmestas tags: trunk, version-0.3.1