Skip to content

Schema Merge

The merge command applies schema changes from one branch to another.

Terminal window
pgbranch merge <source> <target> [flags]
ArgumentDescription
sourceBranch containing the changes to apply
targetBranch to apply changes to
FlagShortDescriptionDefault
--dry-run-Show SQL without applying changesfalse
--migration-file-Generate a migration file instead of applyingfalse
--migration-dir-Directory for migration filesmigrations
--force-fSkip confirmation promptsfalse

Always start with a dry run:

Terminal window
pgbranch merge feature-auth main --dry-run

Output:

-- Dry Run: Changes that would be applied to 'main'
-- Source: feature-auth
CREATE TYPE auth_provider AS ENUM ('local', 'google', 'github');
CREATE TABLE sessions (
id uuid NOT NULL DEFAULT gen_random_uuid(),
user_id uuid NOT NULL,
token text NOT NULL,
expires_at timestamp with time zone,
PRIMARY KEY (id)
);
ALTER TABLE users ADD COLUMN last_login timestamp with time zone;
ALTER TABLE users ADD COLUMN login_count integer DEFAULT 0;
CREATE INDEX sessions_user_id_idx ON sessions(user_id);
ALTER TABLE sessions
ADD CONSTRAINT sessions_user_id_fkey
FOREIGN KEY (user_id) REFERENCES users(id);
-- No changes applied (dry run mode)

After reviewing the dry run:

Terminal window
pgbranch merge feature-auth main

Output:

Merging schema changes from 'feature-auth' to 'main'
Changes to apply:
+ 1 table
+ 2 columns
+ 1 index
+ 1 foreign key
+ 1 enum type
Apply these changes? [y/N]: y
Applying changes...
✓ Created enum type: auth_provider
✓ Created table: sessions
✓ Added column: users.last_login
✓ Added column: users.login_count
✓ Created index: sessions_user_id_idx
✓ Added foreign key: sessions_user_id_fkey
Schema merge complete!

Instead of applying changes directly, generate a migration file:

Terminal window
pgbranch merge feature-auth main --migration-file

Output:

Migration file created: migrations/20240115143022_merge_feature_auth_to_main.sql

The generated file:

-- Migration: feature-auth → main
-- Generated by pgbranch at 2024-01-15 14:30:22
-- Create enum type
CREATE TYPE auth_provider AS ENUM ('local', 'google', 'github');
-- Create table: sessions
CREATE TABLE sessions (
id uuid NOT NULL DEFAULT gen_random_uuid(),
user_id uuid NOT NULL,
token text NOT NULL,
expires_at timestamp with time zone,
PRIMARY KEY (id)
);
-- Add columns to users
ALTER TABLE users ADD COLUMN last_login timestamp with time zone;
ALTER TABLE users ADD COLUMN login_count integer DEFAULT 0;
-- Create indexes
CREATE INDEX sessions_user_id_idx ON sessions(user_id);
-- Add foreign keys
ALTER TABLE sessions
ADD CONSTRAINT sessions_user_id_fkey
FOREIGN KEY (user_id) REFERENCES users(id);
Terminal window
pgbranch merge feature-auth main --migration-file --migration-dir db/migrations
Terminal window
pgbranch merge feature-auth main --force

When the merge includes destructive changes, pgbranch displays extra warnings:

Terminal window
pgbranch merge main feature-cleanup

Output:

Merging schema changes from 'main' to 'feature-cleanup'
⚠️ DESTRUCTIVE CHANGES DETECTED:
The following changes may result in data loss:
- DROP TABLE legacy_sessions
- DROP COLUMN users.deprecated_field
- DROP INDEX users_old_email_idx
Changes to apply:
- 1 table (DESTRUCTIVE)
- 1 column (DESTRUCTIVE)
- 1 index (DESTRUCTIVE)
Type 'yes' to confirm destructive changes: yes
Applying changes...

The merge process:

  1. Computes diff between source and target branches
  2. Generates SQL to transform target schema to match source
  3. Validates SQL for syntax and dependency order
  4. Applies changes to the target branch’s template database
  5. Updates metadata to record the merge
Source: feature-auth Target: main
│ │
│ │
└──────── DIFF ───────────────┘
Generate SQL
Apply to target
template database
main now has
feature-auth schema

pgbranch uses an additive merge strategy by default:

  • Additions are applied (new tables, columns, etc.)
  • Modifications are applied (type changes, constraint changes)
  • Deletions require explicit confirmation

This minimizes accidental data loss.

Schema merge only handles schema changes, not data:

  • New columns are added with NULL or default values
  • Data from the source branch is not copied
  • Custom data migrations must be handled separately

pgbranch does not automatically resolve conflicts:

  • If both branches modified the same column differently, you must resolve manually
  • Complex schema changes may require manual SQL

There is no automatic rollback for failed merges. Before merging:

Terminal window
# Create a backup branch
pgbranch checkout main
pgbranch branch main-backup
# Then merge
pgbranch merge feature-auth main
# If something goes wrong
pgbranch checkout main-backup
pgbranch delete main --force
pgbranch branch main # Recreate from backup
Terminal window
pgbranch merge source target --dry-run

Check the generated SQL for correctness before applying.

Terminal window
pgbranch branch target-backup
pgbranch merge source target

For changes that need to go to production:

Terminal window
pgbranch merge feature target --migration-file

Then apply the migration file through your normal deployment process.

Terminal window
# Create test branch
pgbranch checkout target
pgbranch branch target-test
# Test merge
pgbranch merge source target-test
# Verify everything works
# Then merge to real target
pgbranch merge source target
  • diff - Preview schema differences
  • branch - Create backup branches
  • checkout - Switch between branches