2752ddfbc874
name the checkpoint that holds what revert discarded, recording both in one transaction (3.0.49)
- time
- 2026-09-24 19:30 UTC · 2 weeks ago
- machine
- koh2
- agent
- claude-opus-5-5
- session
- koh 3 reliability campaign
- parent
- fcd909830822
↓ koh-2752ddfb.tar.gzatlas at this save
files changed4 files
VERSION+1 −1src/cli/cmd_back.v+39 −14tests/cli_test.v+8 −1v.mod+1 −1src/cli/cmd_back.v+39 −14
@@ -136,17 +136,23 @@136136 }137137 report := snapshot.restore_files(store, store.root, snapshot.load(store.root), plan.files,138138 plan.remove) or { return refuse(as_json, err.msg()) }139+ // A revert's restore save sits right on the checkpoint of what it threw away.140+ kept := if discard_first { save.parent } else { '' }139141 if as_json {140142 emit_json(json.encode(BackJson{141- id: save.id142- restores: target.id143- written: report.written144- removed: report.removed145- discarded: discard_first143+ id: save.id144+ restores: target.id145+ written: report.written146+ removed: report.removed147+ discarded: discard_first148+ checkpoint: kept146149 }))147150 return 0148151 }149152 ok('restored [${save.id}] ${save.message}')153+ if kept != '' {154+ note('the discarded changes are kept in [${kept}] — koh load ${kept} brings them back')155+ }150156 return 0151157 }152158 @@ -169,16 +175,34 @@169175 }170176 171177 fn record_restore(store &storage.Store, target history.Save, verb string, plan RestorePlan, discard_first bool) !history.Save {178+ discarded := if discard_first {179+ snapshot.walk(store, store.root, snapshot.load(store.root))!180+ } else {181+ []snapshot.FileEntry{}182+ }183+ // One transaction, as the document asks of every history change; it also184+ // keeps the discard checkpoint the restore save's parent, which is how185+ // revert names it.186+ store.begin()!187+ save := record_both(store, target, verb, plan, discard_first, discarded) or {188+ store.rollback()189+ return err190+ }191+ store.commit()!192+ history.refresh_log_md(store)193+ return save194+}195+196+fn record_both(store &storage.Store, target history.Save, verb string, plan RestorePlan, discard_first bool, discarded []snapshot.FileEntry) !history.Save {172197 if discard_first {173198 // Recorded even while a restore is unfinished: finishing it is what174- // revert is for. The mark keeps every other writer off head meanwhile.175- history.commit_files(store, store.root, snapshot.walk(store, store.root,176- snapshot.load(store.root))!, history.SaveInput{199+ // revert is for.200+ history.record_save(store, store.root, discarded, history.SaveInput{177201 message: 'revert: discarded changes'178202 is_checkpoint: true179203 })!180204 }181- return history.commit_files(store, '', plan.files, history.SaveInput{205+ return history.record_save(store, '', plan.files, history.SaveInput{182206 message: '${verb}: ${target.id}'183207 restores: target.id184208 })!@@ -250,11 +274,12 @@250274 }251275 252276 struct BackJson {253- id string254- restores string255- written int256- removed int257- discarded bool277+ id string278+ restores string279+ written int280+ removed int281+ discarded bool282+ checkpoint string // revert only: the checkpoint holding what was discarded258283 }259284 260285 struct RevertJson {tests/cli_test.v+8 −1
@@ -476,10 +476,17 @@476476 assert run(dir, 'log').out == before.out477477 assert os.read_file(os.join_path(dir, 'a.txt'))! == 'dirty\n'478478 write(dir, 'untracked.txt', 'remove\n')479- rv := run(dir, 'revert', '--yes')479+ rv := run(dir, 'revert', '--yes', '--json')480480 assert rv.code == 0481481 assert os.read_file(os.join_path(dir, 'a.txt'))! == 'two\n'482482 assert !os.exists(os.join_path(dir, 'untracked.txt'))483+ // The way back to the discarded work is named, not left to be found.484+ kept := rv.out.all_after('"checkpoint":"')[..12]485+ assert run(dir, 'load', kept, '--yes').code == 0486+ assert os.read_file(os.join_path(dir, 'a.txt'))! == 'dirty\n'487+ assert os.read_file(os.join_path(dir, 'untracked.txt'))! == 'remove\n'488+ write(dir, 'a.txt', 'dirty again\n')489+ assert run(dir, 'revert', '--yes').out.contains('koh load ')483490 assert run(dir, 'revert', '--yes').out.contains('working tree already matches')484491 assert run(dir, 'load', '--checkpoint', '--yes').code == 0485492 assert run(dir, 'load', id2, '--json').code == 1v.mod+1 −1
@@ -1,6 +1,6 @@11 Module {22 name: 'koh3'3- version: '3.0.48'3+ version: '3.0.49'44 description: 'One SQLite file per repo, one line of history.'55 license: 'MIT'66 }