Snapshot
Freeze a table at an instant and give that state a name — the analogue of a commit or a tag. Nothing is copied; the snapshot is the object directory as it stood.
CREATE SNAPSHOT sn1 FOR TABLE T;
Snapshot, branch, diff, merge and roll back your tables the way you already do with code — at row level, in milliseconds, with zero copies, using plain SQL.
Run MatrixOne
docker run -d -p 6001:6001 --name matrixone matrixorigin/matrixone:latest
Connect with a MySQL client you already have
mysql -h 127.0.0.1 -P 6001 -u root -p111
Apache 2.0 · no account, no signup · nothing to configure. That is the whole install — version control is already in the engine.
-- name the state you are about to fork from
CREATE SNAPSHOT sn1 FOR TABLE orders;
-- fork it. metadata only: a 100 GB table clones in 0.20 s / 314 KB
DATA BRANCH CREATE TABLE orders_fix FROM orders{snapshot='sn1'};
-- an agent runs its repair on the branch. production never sees it.
UPDATE orders_fix SET region = 'EMEA' WHERE country IN ('FR','DE');
CREATE SNAPSHOT sn3 FOR TABLE orders_fix;
-- diff reads only the deltas, never the base table
DATA BRANCH DIFF orders{snapshot='sn2'} AGAINST orders_fix{snapshot='sn3'};
1000 rows in set (0.19 sec)
-- fold the accepted rows back: three-way, conflicts stop the world
DATA BRANCH MERGE orders_fix{snapshot='sn3'} INTO orders WHEN CONFLICT FAIL;
Query OK, 1000 rows affected (0.35 sec)
Why now
LLM agents are starting to act as data engineers: they read relational data, propose transformations, evaluate the SQL, and iterate. Each agent must fork the data before it speculates, inspect a row-level diff, merge only what was validated, and roll back the paths that failed — without copying the base table. Version control stopped being a convenience the moment the number of concurrent candidate states went from one to a thousand.
Capabilities
Git4Data maps Git's vocabulary onto a relational engine: the database is the repository, each table is a versioned object. Because the storage is append-only and MVCC-governed, a version is just lightweight metadata — so every operation costs in proportion to the change, not to the size of the data.
Freeze a table at an instant and give that state a name — the analogue of a commit or a tag. Nothing is copied; the snapshot is the object directory as it stood.
CREATE SNAPSHOT sn1 FOR TABLE T;
Clone a table from a snapshot into a new one that then evolves independently. Inserts, updates and deletes on either side stop affecting the other — exactly the isolation a speculating agent needs.
DATA BRANCH CREATE TABLE TClone FROM T{snapshot='sn1'};
Report the rows on which two versions disagree. Each version is an unordered multiset of records, so the diff reads only the deltas written since they split — never the base table.
DATA BRANCH DIFF T{snapshot='sn2'} AGAINST TClone{snapshot='sn3'};
Fold accepted changes back into the live table. Git4Data infers the common base revision and performs a genuine three-way merge, so non-overlapping work from several agents survives instead of being overwritten.
DATA BRANCH MERGE TClone{snapshot='sn3'} INTO T;
The engine already retains point-in-time history for a recent window, so a past state is queryable by timestamp without anyone having declared it interesting in advance.
SELECT * FROM T{timestamp='2026-08-01 12:34:56'};
Immutable objects mean two versions differ only in what was written after they diverged. Cloning a 100 GB table takes 0.20 s and 314 KB of metadata, where materialising it costs 114.6 s and 34 GB.
100 GB clone → 0.20 s · 314 KB
Conflict resolution is currently at row granularity: a conflict is flagged only when both branches independently modify the same key. The WHEN CONFLICT clause decides what happens then — FAIL aborts, SKIP keeps the target's row, ACCEPT keeps the source's.
How it works
Record a version, branch from it, compare versions, reintegrate the accepted changes. The same four moves you make every day in Git — expressed as SQL your ORM, dbt model or agent can already emit.
Name a past state. It is metadata, not bytes — and the engine already keeps a recent window you can query by timestamp without naming anything.
Clone a table from that snapshot. The clone inherits schema and data, then evolves independently — writes on either side stop touching the other.
Report the rows where the two versions disagree. Because it scans only the deltas, it beats the equivalent SQL by orders of magnitude.
Fold the accepted rows back with an explicit conflict policy — or drop the branch and pretend it never happened.
Every statement runs as a transaction inside the database, over the MySQL wire protocol. Version control inherits the transactions, authentication and access control you already rely on — no sidecar service, no object-store mount, no second catalog to keep in sync.
Landscape
Zero-copy clones are common. What is missing elsewhere is the way back: comparing two versions at the row level and reintegrating one into the other. In most systems divergence is one-way.
| Capability | Git4Data | DoltDB | Neon | lakeFS | DVC |
|---|---|---|---|---|---|
| Unit of diff identity | Row | Row | Page / branch | Object or table | File |
| Smallest thing you can branch | One table | One table | Whole database | A namespace | A file tree |
| Zero-copy branch | ✓ | ✓ | ✓ | ✓ | ✗ |
| Compare two live branches | ✓ | ✓ | ✗ | object-level | ✗ |
| Merge a branch back | three-way, per row | ✓ | one-way | object-level | ✗ |
| Explicit conflict policy | FAIL / SKIP / ACCEPT | partial | ✗ | ✗ | ✗ |
| Lives inside an OLTP engine | ✓ | ✓ | storage layer | ✗ | ✗ |
| Wire protocol | MySQL | MySQL | Postgres | S3 API | CLI |
Positioning follows the related-work analysis in the Git4Data paper. Third-party projects move fast — check their current documentation before you standardise on one.
Where it pays off
These are the four workflows BranchBench models — and the reason it models them is that this is what agents do to a database.
An agent edits schema and code, backfills, and re-runs the tests on each attempt. The rehearsal and the release are the same statement.
Binary search through the transaction log to isolate what broke. Each probe needs its own writable state, not a read-only copy.
Normalisation, fuzzy dedup and semantic fixes each repair a different subset. No branch wins outright, so you merge the accepted deltas instead of picking one.
Tree search expands a deep, narrow frontier — one branch per node, most of them discarded. Branch creation has to be free, or the search never gets deep.
Get started
MatrixOne is open source under Apache 2.0. Bring a MySQL client you already have.
# 1 · run MatrixOne
docker run -d -p 6001:6001 --name matrixone \
matrixorigin/matrixone:latest
# 2 · connect with any MySQL client
mysql -h 127.0.0.1 -P 6001 -u root -p111
# 3 · your first versioned table
CREATE SNAPSHOT s0 FOR TABLE demo.t;