panproto-vcs
Git-style version control for schemas, with structural merging and automatic data migration.
What it does
Every schema, migration, data snapshot, and commit is stored as a content-addressed object identified by its blake3 hash. Commits form a directed acyclic graph (DAG), the same structure git uses. You get branches, merging, rebasing, cherry-picking, bisecting, and blame, all operating on schemas rather than source files.
The key difference from git is how merges work. Git merges text by looking for the longest common substring. panproto-vcs merges schemas by comparing their graph structure: two branches that both added a field named email to a User vertex are recognized as adding the same thing, even if they were written independently. This structural comparison (implemented via categorical pushout) produces fewer false conflicts than text diffing.
The VCS also versions data alongside schemas. When you commit a schema change that removes a field, the complement (the dropped field values) is stored so that a future backward migration can recover them. migrate_forward applies a migration to a data snapshot and stores the complement; migrate_backward restores the original data from the complement. This gives you lossless schema history, not just structural diffs.
Quick example
use ;
let mut repo = init.unwrap;
// Stage a schema and commit it.
repo.add.unwrap;
let commit_id = repo.commit.unwrap;
// Create a branch, evolve the schema, and merge back.
create_branch.unwrap;
repo.add.unwrap;
let feature_id = repo.commit.unwrap;
repo.merge.unwrap;
API overview
| Export | What it does |
|---|---|
Repository |
High-level API: init, open, add, commit, merge, rebase, cherry_pick, reset, gc |
FsStore |
Filesystem-backed object store (.panproto/ directory) |
MemStore |
In-memory object store for tests and WASM contexts |
Store |
Trait abstracting over storage backends |
ObjectId |
Blake3 content address (32 bytes) |
Object |
Enum covering all object types: Schema, Migration, Commit, Theory, Expr, and others |
CommitObject |
A point in the schema evolution DAG |
CommitObjectBuilder |
Builder for CommitObject with sensible defaults |
DataSetObject |
A content-addressed data snapshot bound to a schema version |
ComplementObject |
Stored complement for lossless backward migration |
HeadState |
Branch name or detached HEAD (a bare ObjectId) |
Index |
Staging area for the next commit |
CommitOptions |
Commit configuration (includes skip_verify to bypass GAT validation) |
VcsError |
Error type for all VCS operations |
dag::log_walk |
Walk commits from HEAD toward roots |
dag::merge_base |
Find the common ancestor of two commits |
refs::create_branch |
Create a branch pointing at a commit |
merge |
Three-way structural merge with typed conflict detection |
rebase |
Replay commits onto a new base |
cherry_pick |
Apply a single commit's migration to the current HEAD |
bisect |
Binary search for the commit that introduced a breaking change |
blame |
Determine which commit introduced a schema element |
gc |
Mark-sweep garbage collection for unreachable objects |
data_mig::migrate_forward |
Apply a migration to a data snapshot, storing the complement |
data_mig::migrate_backward |
Restore data from a stored complement |
data_mig::detect_staleness |
Check which data snapshots need migration |