Graft
Structural version control powered by gotreesitter — entity-level merge, diff, and commit indexing for Git
Install / Use
/learn @odvcencio/GraftREADME
graft
Structural version control. Merges functions, not lines.
Git treats source files as bags of lines. Two developers add different functions to the same file — conflict. Both add different imports — conflict. One renames a variable, another adds a function nearby — conflict. None of these are real conflicts.
graft is a standalone version control system that decomposes source into structural entities via gotreesitter — functions, methods, classes, imports — and merges at that level. Independent additions merge cleanly. Import blocks get set-union merged. Only genuine semantic overlaps produce conflicts.
# Git: CONFLICT (both modified main.go)
# Graft: clean merge — two independent functions added
$ graft merge feature
merging feature into main...
main.go: clean
merge completed cleanly
How it works
Graft parses every source file into an ordered list of entities:
| Entity kind | Examples |
|------------|---------|
| Preamble | package main, license headers |
| Import block | import (...), from x import y |
| Declaration | Functions, methods, types, classes, structs, traits |
| Interstitial | Whitespace and comments between declarations |
Each entity has an identity key (e.g. decl:function_definition::ProcessOrder) that survives editing, reordering, and branch divergence. Merge operates on these identities instead of line numbers:
- Unchanged — keep as-is
- Modified by one side — take the modification
- Modified identically by both — no conflict
- Modified differently by both — diff3 fallback on that entity's body
- Import blocks — set-union merge (combine all imports, deduplicate)
- Added by one side — insert at correct position
- Deleted by one side, unchanged by other — remove
- Deleted vs modified — real conflict
The critical invariant: reconstructing entities always reproduces the original source byte-for-byte.
Install
go install github.com/odvcencio/graft/cmd/graft@latest
Requires Go 1.25+. Pure Go, no C dependencies.
Usage
Graft follows the same mental model as Git:
# Initialize a repository
graft init myproject
cd myproject
# Stage and commit
echo 'package main
func Hello() {}
' > main.go
graft add main.go
graft commit -m "initial commit"
# Branch and diverge
graft branch feature
graft checkout feature
# ... add func Goodbye() ...
graft add main.go
graft commit -m "add Goodbye"
# Back to main, make a different change
graft checkout main
# ... add func Greet() ...
graft add main.go
graft commit -m "add Greet"
# Structural merge — no conflict
graft merge feature
Commands
Core
graft init [path] Create a new repository
graft add <files...> Stage files for commit
graft commit -m <message> Record changes
graft status Show working tree status
graft diff [ref1..ref2] [--staged] [--entity] [--review] [--json]
Show changes (line-level, entity-level, or review summary)
graft log [--oneline] [-n N] [--entity <selector>] Show commit history
graft show [commit-ish] Show commit metadata and changed files
Branching & Merging
graft branch [name] [-d name] List, create, or delete branches
graft checkout <target> [-b] Switch branches
graft switch <branch> [-c <new>] Switch branches (modern alternative to checkout)
graft merge <branch> Three-way structural merge
graft rebase [--onto] [-i] <upstream> Reapply commits on a new base (--continue/--abort/--skip/--autostash)
graft cherry-pick [--entity <sel>] <commit> Cherry-pick a commit or entity (--continue/--abort/--skip)
graft revert <commit> Revert a commit by creating an inverse commit (--continue/--abort)
Remote
graft clone <url> [dir] Clone from Graft/Orchard or Git forge
graft push [remote] [branch] Push local branch to remote
graft pull [remote] [branch] Fetch and fast-forward local branch
graft fetch [remote] Download objects and refs without merging
graft remote Manage remotes (add, remove, list)
graft publish [owner/repo] Create remote repo on Orchard, set origin, and push
graft auth Authenticate with Orchard (setup, ssh-login, bootstrap-ssh, status, logout)
History & Inspection
graft blame [<path>] [--entity <path::key>] [--limit N] [--json]
Structural blame for an entity or every entity in a file
graft bisect start|good|bad|skip|reset|log|run Binary search for a bug-introducing commit
graft reflog Show local ref update history
graft shortlog [-s] [-n] Summarise commit history by author
graft tag [name] List, create, or delete tags
Working Tree
graft clean [-n] [-f] [-d] Remove untracked files from the working tree
graft grep [-i] [-F] [--entity] [--kind <kind>] [--json] <pattern>
Search file content or entity names for a pattern
graft stash [push|pop|apply|list|drop|show] Stash and restore working directory changes
graft reset [paths...] Unstage paths (restore index from HEAD)
graft rm [--cached] <paths...> Remove paths from index and/or working tree
graft sparse-checkout set|add|list|disable Manage sparse checkout patterns
graft worktree add|list|remove|prune Manage multiple linked working trees
Modules
graft module add <url> [path] Add a module (--track <branch> or --pin <tag>)
graft module rm <name> Remove a module and its working tree
graft module update [name...] Fetch latest objects for modules (--depth N)
graft module sync Sync module working trees from lock file
graft module status Show module state vs lock vs upstream
graft module list List configured modules with paths and versions
Large Files
graft lfs track <pattern> Track files matching pattern with LFS
graft lfs untrack <pattern> Stop tracking pattern with LFS
graft lfs ls-files List LFS-tracked files in staging
graft lfs status Show LFS status for tracked files
Archive & Maintenance
graft archive [--format=tar|zip] <tree-ish> Create an archive of files from a commit
graft gc Pack loose objects and prune unreachable data
graft verify [--signatures] [--json] Verify object integrity and commit signatures
graft version Print version
Remote shorthand
Use orchard:owner/repo instead of full URLs:
graft remote add origin orchard:alice/demo
graft clone orchard:alice/demo
graft publish alice/demo
Auth configuration
graft supports global auth/config in ~/.graftconfig (token, default host, owner/username).
Environment variables still override file values.
# Interactive setup (magic-link login + optional SSH key registration)
graft auth setup --host https://orchard.dev
# Agent-native login (no browser/magic-link flow, uses registered SSH key)
graft auth ssh-login --host https://orchard.dev --username alice --ssh-key ~/.ssh/id_ed25519
# First-key bootstrap for headless agents.
# If already authenticated, graft auto-mints a short-lived bootstrap token.
graft auth bootstrap-ssh --host https://orchard.dev --username alice --ssh-key ~/.ssh/id_ed25519
# First-time from terminal (no prior auth token):
# requests magic-link auth, verifies, mints bootstrap token, registers key.
graft auth bootstrap-ssh --host https://orchard.dev --email alice@example.com --username alice --ssh-key ~/.ssh/id_ed25519
# Optional explicit token override for automation:
GRAFT_BOOTSTRAP_TOKEN=... graft auth bootstrap-ssh --host https://orchard.dev --username alice --ssh-key ~/.ssh/id_ed25519
# Inspect stored auth state
graft auth status
Git forge shorthand is also supported:
graft clone github:owner/repo
graft clone gitlab:group/subgroup/repo
graft clone bitbucket:workspace/repo
For Git-forge clones, graft bootstraps a local .graft repository from the cloned Git HEAD snapshot.
For self-hosted instances, set GRAFT_ORCHARD_URL:
export GRAFT_ORCHARD_URL=https://code.example.com
graft remote add origin orchard:alice/demo
When a remote is a Git forge URL, graft routes clone/pull/push through Git transport; Orchard remotes continue to use native Graft transport.
graft clone from a Git forge bootstraps .graft from the cloned Git HEAD snapshot so structural workflows can start immediately.
Structural diff
# Line-level diff (default)
graft diff
# Entity-level diff — shows which functions/types changed
graft diff --entity
# Review summary — declaration-level changes only, good for PR review
graft diff --review
# Diff between two branches or commits
graft diff main..feature
graft diff main..feature --entity
# JSON output for tooling (pairs with --entity or ref range)
graft diff --json
graft diff main..feature --json
Architecture
.graft/
HEAD ref: refs/heads/main
objects/ SHA-256 content-addressed store (2-char fan-out)
refs/heads/ Branch tips
index Staging area
Object types: blob, entity, entitylist, tree, commit
Hashing: SHA-256 with type-length envelope (type len\0content)
Packages
| Package | Purpose |
|---------|---------|
| pkg/object | Content-addressed store with atomic writes and pack files |
| pkg/entity | Tree-sitter entity extraction and reconstruction |
| pkg/diff3 | Myers diff + three-way line merge |
| pkg/diff | Entity-level diff computation |
| pkg/merge | Structural three-way merge orch
Related Skills
node-connect
341.6kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
84.6kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
341.6kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
84.6kCommit, push, and open a PR
