Artifact fcfc1d65dbd22aee8f853843fc53636ef23705ae846d430104a94b6e14270a62:
- File
internal/checkout/undo.go
— part of check-in
[294a537880]
at
2026-10-19 16:10:06
on branch feat/submanifest-reader
— fix(checkout): save undo state in Update, as fossil does
Update saved no undo state, so nothing could reverse it. It now reads the file of every step that writes or removes one before writing, as fossil's update calls undo_save, and saves those files with copies of vfile and vmerge and the checked-out version in the same transaction that moves the checkout to the target. If a write fails partway the files are put back, as fossil's undo_rollback does.
Checkout.Undo and Checkout.Redo (internal and public) swap that state back and forth and keep checkout-hash naming the restored version. The undo package gains ReadFile, SaveTx and RestoreFiles, and its undo table now has fossil's schema (isExe, unique pathname, rowid order, the executable bit read from disk), so fossil undo reverses a go-libfossil update and Checkout.Undo reverses fossil update; fossil 2.28 interop tests check both. Under js/wasm, which has no undo package, Update saves nothing.
Tracked in #446 (user: [email protected], size: 1258) [annotate] [blame] [check-ins using] [more...]
//go:build !js package checkout import ( "fmt" "github.com/danmestas/go-libfossil/internal/undo" ) // Undo reverses the last operation that saved undo state (Update, for // one), as fossil's undo does: the working files it saved come back, and // the file list, the pending merges and the checked-out version are as they // were before it. // // Panics if c is nil (TigerStyle precondition). func (c *Checkout) Undo() error { if c == nil { panic("checkout.Undo: nil *Checkout") } if err := undo.Swap(c.db, c.env, c.dir, false, c.versionHash); err != nil { return fmt.Errorf("checkout.Undo: %w", err) } return nil } // Redo reverses the last Undo. // // Panics if c is nil (TigerStyle precondition). func (c *Checkout) Redo() error { if c == nil { panic("checkout.Redo: nil *Checkout") } if err := undo.Swap(c.db, c.env, c.dir, true, c.versionHash); err != nil { return fmt.Errorf("checkout.Redo: %w", err) } return nil } // versionHash returns the hash of check-in rid. func (c *Checkout) versionHash(rid int64) (string, error) { var uuid string if err := c.repo.DB().QueryRow("SELECT uuid FROM blob WHERE rid = ?", rid).Scan(&uuid); err != nil { return "", fmt.Errorf("hash of version %d: %w", rid, err) } return uuid, nil }