>
dbwarden
/ tool scope / merge handling

Git Merges, Reconciled
Before They Run.

When branches generate divergent migrations, dbwarden uses the merged models and merge-base state to create one reconciliation migration instead of guessing which branch wins.

Branch migrations are derived, not authoritative.

In a conventional migration workflow, each branch generates its own migration files. When those branches merge, the migration history diverges: two files with different versions, different SQL, and no clear winner. The database cannot tell which branch's changes are correct, and neither can the developer without reading both files and comparing them against the models.

dbwarden treats branch migrations as derived artifacts. The models are the source of truth; the migration files are outputs. After a Git merge, dbwarden computes the correct next change as the diff between the merge-base state and the merged models. The branch files remain as provenance, but the reconciliation migration is the only new runnable migration.

Generation and status detect divergent bases, version collisions, and snapshot discontinuities. Until the merge is resolved, make-migrations refuses to generate from an ambiguous history. This prevents the common failure mode where two developers generate migrations on top of the same base, merge, and end up with two migrations that conflict.

$ dbwarden status
Database: primary
Merge: PENDING

$ dbwarden make-migrations "add feature" --database primary
Error: Merge pending. Resolve before generating.
the merge detection
-- After a Git merge, dbwarden detects:
-- 1. Divergent bases (branch migrations from same base)
-- 2. Version collisions (same version, different SQL)
-- 3. Snapshot discontinuities (state mismatch)

-- Status reports: Merge: PENDING
-- make-migrations refuses until resolved

Reconcile the repository, then each environment.

dbwarden provides three commands for handling merges, each solving a different part of the problem. The commands are designed to be run in sequence: first reconcile the repository, then each environment.

merge generates the reconciliation migration. It computes the diff between the merge-base state and the merged models, writes one migration file that accounts for both branches, and marks the divergent branch files as superseded. The superseded files are never deleted; they retain full provenance for review and recovery.

rebase recovers a disposable environment, such as a local database, against the merged models. It replays the reconciliation migration on top of the current state, so the environment matches the merged models. This is useful for local development after a merge.

reconcile recovers a persistent environment after a dirty merge. It creates an environment-specific plan that accounts for what has already been applied in that environment, so the reconciliation is safe to run on staging or production.

merge
$ dbwarden merge --database primary
Created migration: migrations/primary/primary__0005_reconcile.sql
Superseded: primary__0003_add_feature_a.sql
Superseded: primary__0004_add_feature_b.sql
rebase
$ dbwarden rebase --database local
Rebased local database against merged models
reconcile
$ dbwarden reconcile --environment staging
Created migration: migrations/primary/primary__0006_reconcile_staging.sql

The history stays auditable.

Superseded migrations are never deleted. They are excluded from the runnable chain and retain merge-base, branch, checksum, and environment information for review and recovery. The generated reconciliation file records what it supersedes and how it was produced, so the entire history remains auditable.

This is important for incident response: if a reconciliation migration causes problems, you can trace it back to the original branch files, understand what each branch intended, and make an informed decision about how to fix it. The provenance is preserved in the repository, not lost in a merge.

MariaDB has incomplete snapshot support, so merge-base resolution relies on model state and rename candidates require explicit confirmation. All merge operations require Git, and manual migrations remain SQL-only. The merge handling is designed to work within these constraints, not around them.

$ dbwarden merge --database primary \
    --rename-column users.name=full_name

# The reconciliation file records:
# - What it supersedes (branch files)
# - How it was produced (merge-base diff)
# - What renames were confirmed
superseded files retain provenance
-- primary__0003_add_feature_a.sql
-- dbwarden: superseded by primary__0005_reconcile.sql
-- merge-base: abc123
-- branch: feature/a
-- environment: local
What happens when two branches add the same column?

dbwarden detects the version collision and refuses to generate until the merge is resolved. The merge command creates a reconciliation migration that accounts for both branches.

Can I use merge handling with MariaDB?

MariaDB has incomplete snapshot support, so merge-base resolution relies on model state. Rename candidates require explicit confirmation with --rename.

What does superseded mean?

Superseded migrations are excluded from the runnable chain but never deleted. They retain full provenance for review and recovery, and the reconciliation file records what it supersedes.

Do I need to run all three commands?

Not always. merge is required for repository reconciliation. rebase is for disposable environments like local databases. reconcile is for persistent environments like staging or production.

Choose dbwarden merge handling when

Multiple developers generate migrations on the same database, or you use feature branches that modify the schema.

Choose something else when

You have a single developer, or your branching strategy never modifies the schema in parallel.

Merge handling deep dive Schema state and drift detection Safety and impact analysis