eee40896e5eb
never snapshot a nested repo's .koh or .git, so the outer repo cannot roll an inner repo's history back (3.0.33)
- time
- 2026-09-24 03:47 UTC · 2 weeks ago
- machine
- koh2
- agent
- claude-opus-5-5
- session
- koh 3 reliability campaign
- parent
- ff9e6b8d886f
↓ koh-eee40896.tar.gzatlas at this save
files changed4 files
VERSION+1 −1src/snapshot/ignore.v+6 −11src/snapshot/snapshot_test.v+9 −0v.mod+1 −1src/snapshot/ignore.v+6 −11
@@ -98,26 +98,21 @@9898 }9999 100100 // hard_ignored covers the files Koh writes into a repo as part of working101-// there. They are never snapshotted whatever `.kohignore` says.101+// there. They are never snapshotted whatever `.kohignore` says, at any depth:102+// a repo inside the repo keeps its own history, and restoring an old copy of103+// its `.koh` or `.git` would roll that history back.102104 //103105 // LOG.md is rewritten after every save from the history itself. Tracking it104106 // would make the tree dirty the moment a save lands, so `status` could never105107 // report a clean tree and every diff would carry the log's own churn.106108 pub fn hard_ignored(rel string) bool {107- if rel == '.koh' || rel == '.koh-wal' || rel == '.koh-shm' {108- return true109- }110- if rel == '.koh-v2' || rel.starts_with('.koh-v2/') {111- return true112- }113- if rel == '.git' || rel.starts_with('.git/') {114- return true115- }116109 if rel == 'LOG.md' {117110 return true118111 }119- return false112+ return rel.split('/').any(it in hard_ignored_names)120113 }114+115+const hard_ignored_names = ['.koh', '.koh-wal', '.koh-shm', '.koh-v2', '.git']121116 122117 // matches reports whether a repo-relative path is ignored. `is_dir` matters123118 // because a pattern ending in `/` names a directory: it covers the directorysrc/snapshot/snapshot_test.v+9 −0
@@ -50,6 +50,15 @@5050 }5151 assert !hard_ignored('.kohignore')5252 assert !hard_ignored('src/log.md')53+ // A repo inside the repo keeps its own history: restoring an old copy of54+ // its .koh or .git would roll that history back.55+ for path in ['inner/.koh', 'inner/.koh-wal', 'inner/.koh-shm', 'a/b/.git', 'vendored/.git/HEAD',56+ 'old/.koh-v2/snapshots/x.json', 'koh2repo/.koh/objects/ab/cd'] {57+ assert hard_ignored(path), '${path} should be hard ignored'58+ }59+ assert !hard_ignored('inner/.kohignore')60+ assert !hard_ignored('docs/.github/workflow.yml')61+ assert !hard_ignored('notes/.koh.md')5362 // A pattern list cannot un-ignore them, and `.kohignore` itself is content.5463 ig := parse('')5564 assert ig.matches('.koh', false)v.mod+1 −1
@@ -1,6 +1,6 @@11 Module {22 name: 'koh3'3- version: '3.0.32'3+ version: '3.0.33'44 description: 'One SQLite file per repo, one line of history.'55 license: 'MIT'66 }