Fork
A fork makes a past (or the current) state of a store into a new, writable store in another directory. The source store is not changed; to undo a fork, delete the new directory.
#![allow(unused)] fn main() { use graphersal::persist::{RecoveryTarget, Store, StoreOptions}; let store = Store::open("data", StoreOptions::new())?; let report = store.fork(RecoveryTarget::Mark("before-import".into()), "branch")?; let info = &report.snapshot; println!("forked at commit {}: graph {:032x}, parent {:032x}", info.commit_seq, info.graph_id, info.parent_graph_id); for mark in &report.marks_not_carried { println!("mark not carried: {} @ commit {}", mark.name(), mark.commit_seq()); } let branch = Store::open("branch", StoreOptions::new())?; // Without opening the source (works while a writer has it open): Store::fork_dir("data", RecoveryTarget::CommitSeq(2), "branch2")?; Ok::<(), Box<dyn std::error::Error>>(()) }
$ graphersal store fork data/ branch/ --at-mark before-import
Forked into branch/ at commit 1: graph 01a11a54-87d2-7995-b2cb-e450e4319735 (parent 01a11a54-8209-7661-92e2-147ae6d8bbd3).
Marks not carried (1; they stay targets of data/ only):
before-import @ commit 1
Open it: graphersal --graph branch/ --server (or the REPL: graphersal --graph branch/).
data/ is unchanged; to undo the fork, delete the directory branch/.
- The target is any point in time; without one, the latest state.
- The new store has a new lineage id that records its parent and the commit it branched at
(
graphersal store info branch/showsparentandbranched at), one snapshot at the target, and an empty WAL. It keeps the source's chunk size and damage policy, but it is another store with its own store id: it never continues the source's incremental backups (back it up into a new directory). - Marks are not carried: the new lineage starts without marks (they are names in the
source's history, which the fork does not copy). The
ForkReport(marks_not_carried), the CLI (Marks not carried ..., onename @ commit Nline each), Python ("marks_not_carried") and the dev server (marksNotCarried) list the source's marks at or before the fork's position; they stay targets of the source store. Set them again in the fork if you need them there (store.mark(..),graphersal store mark). NEW_DIRmust not exist (or be empty). A fork of a single-file store can be a.gstorefile (the dev server names it<store>-fork-<target>.gstorenext to the source).- A fork reads the source without any lock: it works while a dev server or a REPL has the source open, and on a backup (the way to get a writable copy that leaves the backup as it is).
- A fork of a past state is how you continue writing from it without touching the source. To take the source itself back, use an in-place rollback.
- An attic entry can be forked too:
store.attic_fork(id, dir),graphersal store attic <DIR> fork <ID> <NEW_DIR>. Its report lists the marks of the entry's history (the store's before the rollback target, the entry's own after it), not carried either.
Python: store.fork("branch", mark="before-import") (or commit_seq=, time= in
microseconds) returns the snapshot's dict plus "marks_not_carried": [{"name", "commit_seq"}].