version control
DoltGres is Postgres that branches, commits, and merges like Git — but the unit of versioning is the whole database, not a file. Every operation is a SQL function you call with SELECT.
the model: working → staged → committed
Like Git, DoltGres tracks three tiers of change. A normal INSERT/UPDATE/DELETE lands in the working set — your uncommitted edits. You stage the changes you want to keep, then commit them to permanent, named history.
- working set — uncommitted, unstaged edits. Each branch has its own working set, so changes stay isolated.
- staged — changes added with
dolt_add, queued for the next commit. - committed — a permanent, hashed snapshot of the entire database state, linked to its parent commit.
gotcha: a Dolt commit is NOT a SQL transaction COMMIT
COMMIT just ends a database transaction — it makes your writes durable in the working set. A Dolt commit (SELECT dolt_commit(...)) creates a versioned snapshot in history with an author, message, and content hash. You can run a thousand SQL transactions and still have zero Dolt commits. To capture a point in history, you must take a Dolt commit explicitly.the golden rule: SELECT, never CALL
DoltGres speaks the PostgreSQL dialect, and Postgres allows side-effects inside a SELECT (the same way nextval() does). So every mutating version-control operation is a function invoked with SELECT:
SELECT dolt_commit('-a', '-m', 'add notes table'); -- DoltGres (Postgres)If you have seen MySQL-flavored Dolt, this is the one thing to unlearn: MySQL Dolt uses CALL dolt_commit(...). DoltGres does not — it is always SELECT dolt_xxx(...).
the mutating functions
Each returns a small result — a status, and/or a commit hash and message. The core set:
| function | example | returns |
|---|---|---|
dolt_add | SELECT dolt_add('-A'); | status |
dolt_commit | SELECT dolt_commit('-a','-m','msg'); | hash |
dolt_checkout | SELECT dolt_checkout('-b','feat'); | status, message |
dolt_branch | SELECT dolt_branch('-c','main','feat'); | status |
dolt_merge | SELECT dolt_merge('feat','--no-ff','-m','msg'); | hash, fast_forward, conflicts, message |
dolt_reset | SELECT dolt_reset('--hard','<hash>'); | status |
dolt_tag | SELECT dolt_tag('v1','HEAD'); | status |
The same SELECT dolt_xxx(...) convention covers the rest of the surface too — dolt_revert, dolt_cherry_pick, dolt_rebase, dolt_stash, dolt_clean, and dolt_verify_constraints.
end-to-end: branch → change → commit → merge
A realistic workflow. Make a feature branch, edit data on it, commit the snapshot, switch back to main, and merge the branch in.
-- 1. create a feature branch off main and switch to it
SELECT dolt_checkout('-b', 'add-welcome-note');
-- 2. make changes (ordinary SQL — these land in the working set)
INSERT INTO notes (id, body) VALUES ('n_001', 'welcome to briven');
-- 3. stage everything and commit a snapshot of the whole database
SELECT dolt_add('-A');
SELECT dolt_commit('-m', 'seed welcome note'); -- returns the new commit hash
-- 4. go back to main
SELECT dolt_checkout('main');
-- 5. merge the feature branch in (--no-ff forces a real merge commit)
SELECT dolt_merge('add-welcome-note', '--no-ff', '-m', 'merge welcome note');dolt_merge returns a row with hash, fast_forward, conflicts, and message. If conflicts is non-zero, the merge stopped and is waiting for you to resolve them (see below). A fast-forward merge — where main had no new commits since the branch point — moves the pointer forward and creates no merge commit unless you pass --no-ff.
reading state: system tables
Writes are functions; reads are tables. DoltGres exposes version-control state as tables in the dolt schema, each with a dolt_-prefixed alias you can use unqualified. This dolt. schema namespace is the main DoltGres-specific divergence from MySQL Dolt (which only has the dolt_ prefixed names).
-- what is staged / unstaged right now
SELECT * FROM dolt.status;
-- every branch, its head commit, latest committer + message
SELECT * FROM dolt.branches;
-- commit history reachable from the current HEAD
SELECT * FROM dolt.commits WHERE date < '2026-01-01';
-- the same tables are reachable via the dolt_ aliases:
SELECT * FROM dolt_status;
SELECT * FROM dolt_branches;conflicts
DoltGres merges cell-by-cell. A conflict happens when both branches changed the same cell to different values. Unlike Git, conflicts are not written as inline <<<<< markers in a file — they are recorded in a per-table system table: dolt_conflicts_<table>. Each conflicted cell shows three values:
- base — the original common-ancestor value
- ours — the current branch's value
- theirs — the merging branch's value
-- inspect the conflicts on a specific table
SELECT * FROM dolt_conflicts_notes;
-- resolve by keeping the current branch's version of every conflicted row
SELECT dolt_conflicts_resolve('--ours', 'notes');
-- ...or keep the incoming branch's version
SELECT dolt_conflicts_resolve('--theirs', 'notes');resolving conflicts does not guarantee a valid merge
SELECT dolt_verify_constraints(); to surface any constraint violations the merge introduced before you commit it.info functions
Read-only helpers for answering “where am I?” and “how do these two branches relate?”
-- which branch is this session on?
SELECT active_branch();
-- the common-ancestor commit of two branches (their merge base)
SELECT dolt_merge_base('main', 'add-welcome-note');