Skip to content

Repository Model

Graft repository mode gives SQLite projects a Git-like shape:

worktree files on disk, such as app.db
index staged database snapshots
HEAD current commit or current branch
refs branches, tags, and remote-tracking refs
objects immutable repository objects
store repo-local Graft page/log storage

The goal is not to make SQLite pretend to be text. The goal is to make a SQLite database file behave like a versioned project artifact.

The worktree is the physical project directory:

project/
app.db
analytics.db
.graft/

When a database is opened through the Graft VFS, the absolute database path is mapped back to a repo-relative path like app.db. That path is what status, add, commit, checkout, and diff operate on.

The ordinary app.db file does not have to exist on disk while Graft is managing the database through a Volume. See Physical Files And Volumes for the export and import workflow.

The index is the staging area. graft add app.db does not copy the whole database file into the repository. It records a snapshot descriptor for the current database state.

Terminal window
graft sql "INSERT INTO users(name) VALUES ('Alice');"
graft status
graft add app.db
graft commit -m "add alice"

This mirrors Git:

working tree -> index -> commit

SQLite transactions happen before this layer. A SQLite transaction can succeed without becoming a Graft commit until you stage and commit it.

A Graft repository commit points to a tree. The tree maps repo-relative paths to file states.

For SQLite database files, the file state points to a sqlite-snapshot-v1 object. That object records:

  • the VolumeId
  • page count
  • log ranges needed to reconstruct the database snapshot
  • storage commit hashes for the LSNs in those ranges

The commit hash is a repository object id. It is what users pass to graft show, graft diff, graft checkout, and graft reset.

Branches and tags are refs under .graft/refs/:

.graft/
HEAD
refs/
heads/main
heads/feature/search
remotes/origin/main
tags/v0.1

HEAD either points to a branch or directly to a commit in detached mode.

Graft supports multiple named remotes. origin is a convention, not a special singleton.

Terminal window
graft remote add origin fs:///srv/graft/main
graft remote add backup s3_compatible://bucket/prefix
graft remote list

Remote config is repository-local and lives in .graft/config.toml. Branch upstream configuration lives there too, so graft pull and graft push can resolve defaults from the current branch.

Repository mode isolates data by physical project directory:

/work/project-a/.graft/
/work/project-b/.graft/

Two projects can both have an app.db; they still get separate refs, objects, remotes, and repo-local storage. This is the main reason normal repository mode should not rely on environment variables for configuration.