-
Notifications
You must be signed in to change notification settings - Fork 0
Git Like Versioning
DeepDiff DB's version command group brings Git-style commit history, branching, and ASCII graph visualization to database diff snapshots. Every commit is content-addressable (SHA-256), stored as a zlib-compressed object in a fanout directory layout, and contains enough schema context to generate rollback SQL offline — no live database required.
deepdiffdb version <subcommand> [flags]| Subcommand | Description |
|---|---|
version init |
Initialise a .deepdiffdb/ repository |
version commit |
Run a diff and store it as a new commit |
version log |
Show commit history newest-first |
version diff |
Compare schema evolution between two commits |
version rollback |
Generate rollback SQL for a commit |
version branch |
List branches or create a new one |
version checkout |
Switch the current branch |
version tree |
ASCII commit graph for all branches |
.deepdiffdb/
HEAD ← symbolic ref: "ref: refs/heads/main"
config ← verified GitHub identity (0o600, token never stored)
objects/
<2-hex>/
<62-hex> ← zlib-compressed commit object (Git fanout)
refs/
heads/
main ← tip hash for main branch
feature ← tip hash for feature branch (one file per branch)
This mirrors Git's internal layout exactly:
- Fanout: the first 2 hex characters of the SHA-256 hash form the directory name, the remaining 62 form the filename. This keeps directory entry counts bounded on large histories.
-
Symbolic refs:
HEADstoresref: refs/heads/<branch>. Each branch file stores the plain hash of its tip commit. -
Content-addressable: the hash is computed over a
"commit <size>\x00<json>"header + the JSON body, matching Git's object-header convention. The hash changes whenever the content changes. -
Identity config:
.deepdiffdb/configstores{"github_user": "<username>"}at0o600permissions. The GitHub access token is used only to verify identity and is never written to disk.
Add .deepdiffdb/config to your .gitignore to keep your personal identity local. Commit the rest of .deepdiffdb/ to share history with your team.
Creates the .deepdiffdb/ structure and optionally authenticates with GitHub to establish verified commit authorship. Idempotent — safe to re-run on an existing repo (e.g. to add GitHub identity after an initial --skip-auth run).
deepdiffdb version init [--dir <path>] [--skip-auth]| Flag | Default | Description |
|---|---|---|
--dir |
. |
Directory to initialise |
--skip-auth |
false |
Skip GitHub authentication (use --author on commits instead) |
After initialising, version init prompts you to authenticate via the GitHub device flow — no browser redirect required:
Authenticate with GitHub to verify commit authorship? [Y/n]:
Open: https://github.com/login/device
Code: ABCD-1234
Waiting for authorization ........ ✓
Authenticated as github:iamvirul — your commits will be signed automatically.
The verified username is stored in .deepdiffdb/config as {"github_user": "iamvirul"}. The access token is discarded immediately after identity confirmation — it is never persisted.
Use --skip-auth to bypass the prompt in CI pipelines and use --author on version commit instead.
Setup required:
version initneedsDEEPDIFFDB_GITHUB_CLIENT_IDto be set (or baked into the binary at build time via-ldflags). See GitHub OAuth Setup below.
Connects to both databases, runs a full schema + data diff, and saves the result as a new commit on the currently checked-out branch.
Each commit stores:
- Author, message, UTC timestamp
- Full
SchemaDiffandDataDiffresults -
ProdSchemaandDevSchemasnapshots (needed for offline rollback) - SHA-256 content hash
deepdiffdb version commit --message "describe the change" [flags]| Flag | Default | Description |
|---|---|---|
--config |
deepdiffdb.config.yaml |
Path to config file |
--message |
(required) | Commit message |
--author |
(see below) | Author name — ignored when GitHub identity is stored |
The author is resolved in this order:
-
Verified GitHub identity — if
.deepdiffdb/configcontains agithub_user, the author is automatically set togithub:<username>. Passing--authoralongside a stored identity prints a warning and the flag is ignored. -
--authorflag — used when no config identity exists. -
Error — if neither is available,
version commitexits asking you to authenticate or pass--author.
# With GitHub authentication (author resolved automatically)
deepdiffdb version commit \
--config deepdiffdb.config.yaml \
--message "V2: add reviews table"
# [e35c16c9] V2: add reviews table
# Author: github:iamvirul
# Schema drift detected.
# Without authentication (explicit author)
deepdiffdb version commit \
--config deepdiffdb.config.yaml \
--message "V2: add reviews table" \
--author "Alice"Walks the commit chain from HEAD backwards.
deepdiffdb version log [--limit N]| Flag | Default | Description |
|---|---|---|
--limit |
20 |
Maximum commits to show |
commit 142b1305...
Author: github:iamvirul
Date: 2026-03-31 14:33:29 +0000
V3: add reviews table and avg_rating column [schema drift] [data changes]
commit e35c16c9...
Author: github:iamvirul
Date: 2026-03-31 14:33:22 +0000
V2: add category_id FK and customer_email column [schema drift] [data changes]
Compares the DevSchema snapshots of two commits and prints what changed between them.
deepdiffdb version diff <hash1> <hash2>Full hashes and 8-character short hashes are both accepted.
$ deepdiffdb version diff cad39fda 142b1305
Schema evolution from cad39fda → 142b1305
+ TABLE reviews (added)
~ TABLE orders
+ COLUMN customer_email varchar(255)
~ TABLE products
+ COLUMN avg_rating decimal(3,2)
+ COLUMN category_id int
+ INDEX fk_product_category
Generates driver-aware rollback SQL by inverting a commit's diff (dev → prod direction). Uses the same SQL generator as schema-migrate — destructive operations (DROP TABLE, DROP COLUMN) are commented out by default.
deepdiffdb version rollback [--out <file>] [--driver <driver>] <hash>| Flag | Default | Description |
|---|---|---|
--out |
(stdout) | Write SQL to this file |
--driver |
(from commit) | Override dialect: mysql, postgres, sqlite, mssql, oracle
|
-- Generated rollback SQL
BEGIN;
-- DROP TABLE `reviews`; ← commented for safety, uncomment to apply
-- ALTER TABLE `orders` DROP COLUMN `customer_email`;
-- ALTER TABLE `products` DROP COLUMN `avg_rating`;
-- ALTER TABLE `products` DROP COLUMN `category_id`;
COMMIT;Lists all branches (current branch marked with *), or creates a new one.
# List branches
deepdiffdb version branch
# Create from current HEAD
deepdiffdb version branch <name>
# Create from a specific commit
deepdiffdb version branch <name> --from <hash>| Flag | Default | Description |
|---|---|---|
--from |
(current HEAD) | Hash to branch from |
$ deepdiffdb version branch
feature e35c16c9
* main 142b1305
$ deepdiffdb version branch hotfix --from cad39fda
Branch "hotfix" created.
Switches HEAD to point to the named branch as a symbolic ref. All subsequent version commit calls advance only the checked-out branch.
deepdiffdb version checkout <branch>$ deepdiffdb version checkout feature
Switched to branch "feature".
Returns an error if the branch does not exist. Create it first with version branch <name>.
Renders an ASCII commit graph showing all branches, newest commit first.
deepdiffdb version tree| * e2a3d002 (feature) 2026-03-31 V2: category link + customer email
* | 761e26c5 (HEAD -> main) 2026-03-31 V3: reviews + avg_rating
* | 18bf631b 2026-03-31 V1: baseline schema
- Each column is a branch lane:
*= commit on this lane,|= lane active elsewhere -
(HEAD -> main)= current branch and its latest commit -
(feature)= non-current branch tip - Commits shared by multiple branches (e.g. the fork point) appear in the leftmost active lane
# 1. Initialise once per project — authenticate with GitHub for verified authorship
deepdiffdb version init
# → prompts for GitHub device flow (no browser redirect needed)
# → stores {"github_user":"iamvirul"} in .deepdiffdb/config; token discarded
# 2. Commit a clean baseline on main — author resolved automatically
deepdiffdb version commit \
--config deepdiffdb.config.yaml \
--message "V1: baseline e-commerce schema"
# 3. Create a feature branch
deepdiffdb version branch feature
deepdiffdb version checkout feature
# 4. Apply schema changes to the dev database (ALTER TABLE, CREATE TABLE…)
# 5. Commit the drift on the feature branch
deepdiffdb version commit \
--config deepdiffdb.config.yaml \
--message "V2: experimental schema"
# 6. Switch back to main for a hotfix
deepdiffdb version checkout main
deepdiffdb version commit \
--config deepdiffdb.config.yaml \
--message "V2: hotfix — drop unused index"
# 7. Visualise the divergence
deepdiffdb version tree
# 8. Compare any two commits
deepdiffdb version diff <hash_v1> <hash_v2>
# 9. Generate rollback SQL if needed
deepdiffdb version rollback --out rollback.sql <hash>Use --skip-auth to bypass the GitHub prompt in pipelines and pass --author to identify the pipeline:
deepdiffdb version init --skip-auth
deepdiffdb version commit \
--config deepdiffdb.config.yaml \
--message "CI snapshot: $GIT_SHA" \
--author "ci/github-actions"To enable verified authorship, register a GitHub OAuth App:
- Go to github.com/settings/applications/new
- Fill in:
-
Application name:
DeepDiff DB -
Homepage URL:
https://github.com/iamvirul/deepdiff-db -
Authorization callback URL:
http://localhost(not used by device flow)
-
Application name:
- Tick Enable Device Flow
- Click Register application and copy the Client ID
Environment variable (personal use):
export DEEPDIFFDB_GITHUB_CLIENT_ID="your_client_id"Baked into released binaries (build-time injection):
- name: Build
run: |
go build \
-ldflags "-X github.com/iamvirul/deepdiff-db/internal/version.GitHubClientID=${{ secrets.DEEPDIFFDB_GITHUB_CLIENT_ID }}" \
-o deepdiffdb ./cmd/deepdiffdb- CLI Reference — all commands at a glance
- Sample 17 — full end-to-end demo with MySQL Docker containers, branches, and ASCII tree output
Home · Problem Statement · Architecture · Data Flow · CLI Reference · Configuration · Contributing
DeepDiff DB — safe, deterministic database synchronization