Skip to content

Track Databases And Files

Graft repositories are worktree based. A commit can contain multiple SQLite database paths and ordinary files that belong to the same application state.

project/
data.sqlite
analytics.sqlite
settings.json
attachments/
report.pdf
.graft/

Graft reports what each path contains with kind:

KindMeaning
sqlite_databaseSQLite database snapshot tracked through Graft.
text_fileUTF-8 text file tracked as an app artifact.
binary_fileBinary file tracked as an app artifact.

Commands that accept --kind also accept common aliases such as sqlite, db, text, and binary.

storage describes how Graft stores the path:

StorageUsed for
sqlite_snapshotSQLite database paths.
inlineSmall text files stored in the object database.
externalBinary files, configured external paths, and large text files.

Path kind and storage are separate. For example, a JSON file can be kind: "text_file" and storage: "external" if it matches an external path rule or exceeds the inline threshold.

Terminal window
graft status
graft add --all
graft commit -m "save app state"

graft add --all stages database snapshots, file modifications, additions, and deletions.

Filter by kind when an app wants to stage only one class of paths:

Terminal window
graft add --all --kind sqlite_database
graft add --all --kind text_file
graft add --all --kind binary_file

Stage one path:

Terminal window
graft add data.sqlite
graft add attachments/report.pdf

Graft reads .gitignore files from the repository root and descendant directories by default. Rules use Git’s matching syntax and precedence, including ! negation, / anchoring, directory-only patterns, **, ?, character classes, comments, and escapes. As in Git, a file cannot be re-included when one of its parent directories is excluded.

The Graft-specific .graftignore filename remains supported with the same syntax. When both files exist in one directory, .graftignore rules take precedence over .gitignore rules. Rules in deeper directories take precedence over rules inherited from their parents.

Ignore rules affect untracked path discovery and ordinary adds; paths already tracked by Graft continue to report and stage changes. Use graft add --force path to add an ignored, untracked path intentionally.

Terminal window
graft ls-files
graft ls-files --json
graft ls-files --json --details
graft ls-files --json --others

--details includes object ids, content hashes, and whether external payloads are present in the local cache. --others lists untracked worktree candidates that can be added.

Text files are stored inline until they exceed files.inline_text_threshold or match files.external_paths.

Terminal window
graft config get files.inline_text_threshold
graft config set files.inline_text_threshold 8 MB
graft config set files.external_paths "assets/**, attachments/**"

Use external_paths for app resource directories such as attachments, imports, exports, generated media, models, or assets.

Stage a deletion:

Terminal window
graft rm attachments/report.pdf
graft commit -m "remove report"

Remove a path from the repository while keeping the worktree file:

Terminal window
graft rm --cached attachments/report.pdf
graft commit -m "stop tracking report"

Normal SQLite tools are the default way to edit a physical worktree database. Commit the transaction, then stage the path:

Terminal window
sqlite3 data.sqlite "INSERT INTO notes(body) VALUES ('hello');"
graft add data.sqlite

graft add captures committed WAL frames through SQLite’s online backup API; manual checkpointing is unnecessary. It compares the consistent snapshot with the staged or committed base and writes only changed 4 KiB Graft storage chunks, independently of the physical database’s SQLite page size.