Skip to content

Branching and Merging Migrations — Complete Guide

DodaTech Updated 2026-06-28 8 min read

In this tutorial, you will learn about Branching and Merging Migrations. We cover key concepts, practical examples, and best practices to help you master this topic.

Learn branching and merging strategies for database migrations: handle parallel development branches, resolve Migration conflicts, create merge migrations, and maintain linear migration history in team environments.

What You Learn

You will learn how to manage database migrations when multiple developers work in parallel: how branches create divergent migration histories, how to detect and resolve conflicts, how to create merge migrations, and how to maintain a clean migration history.

Why It Matters

In team development, two developers create migrations in parallel branches. When both branches merge, the migration history diverges. Without proper handling, the migration order becomes ambiguous and applications may apply migrations in the wrong order.

Real-World Use

DodaTech's Django application with 10 developers creates 20-30 migrations per sprint. Branching conflicts occur 2-3 times per sprint. Merge migrations resolve these conflicts. The migration history remains linear and clean after merging.

The Problem

graph LR
    Main1[Main: migration 003] --> B1[Branch A: creates 004a]
    Main1 --> B2[Branch B: creates 004b]
    B1 --> Merge[Merge to main]
    B2 --> Merge
    Merge --> Conflict{Which is 004?}

When two branches both create migration 004, the main branch has two migrations claiming the same position. The migration tool does not know which to apply first or how to order them.

Creating a Merge Migration

# After merging both branches, create a merge migration
# Alembic:
alembic merge -m "merge heads" head1 head2

# Output:
# Generated /migrations/abc123_merge_heads.py

# Django:
python manage.py makemigrations --merge

# Output:
# Created merge migration /migrations/0005_merge.py
# Alembic merge migration
"""merge heads

Revision ID: abc123def456
Revises: branch1_revision, branch2_revision
Create Date: 2026-06-28 12:00:00.000000
"""

revision = 'abc123def456'
down_revision = ('branch1_revision', 'branch2_revision')
# Merges two parent revisions

def upgrade():
    pass  # No schema changes, only merge

def downgrade():
    pass

Expected output: Merge migration has two parent revisions. It tells Alembic that both migrations have been applied and the current state combines both. The merge migration itself makes no schema changes.

Django Merge Migration

# Django merge migration
from django.db import migrations

class Migration(migrations.Migration):
    dependencies = [
        ('users', '0004_add_phone'),
        ('users', '0005_add_bio'),
        # Two parents means this is a merge
    ]

    operations = []  # No operations, only merge

Expected output: Django merge migration declares dependencies on both heads. Django knows that both migrations have been applied. The merge migration has no operations, serving only to reconcile the history.

Preventing Conflicts

# Prevention strategy 1: Timestamp naming
# Both developers create migrations with different timestamps
# Branch A: 20260628_120000_add_phone.py
# Branch B: 20260628_130000_add_bio.py
# No conflict because timestamps differ and are applied in order

# Prevention strategy 2: Sequential naming with lock
# Developer A claims migration 004
# Developer B claims migration 005
# Requires coordination or a locking mechanism

# Prevention strategy 3: Run migrations when pulling
# After pulling main, run migrations to catch up
git checkout main
git pull
alembic upgrade head  # Apply any new migrations
git checkout feature-branch
git rebase main
# Resolve any conflicts before creating new migrations

Expected output: Timestamp-based naming prevents most conflicts. Running migrations after syncing with main ensures you build on the latest migration state. Rebasing before creating migrations reduces merge complexity.

Detecting Conflicts

# Check if migration history has diverged
# Alembic:
alembic heads

# Output:
# abc123 (head)
# def456 (head)
# Two heads means the history has diverged

# Django:
python manage.py showmigrations
# Look for two [ ] migrations with the same prefix
# that depend on the same parent

# Prisma:
npx prisma migrate status
# Shows all migrations and their status

Expected output: Two heads (Alembic) or two unsapplied migrations with the same parent (Django) indicate divergent history. A merge migration is needed to reconcile them.

Resolving Conflicts

# Step-by-step conflict resolution

# 1. Identify the heads
alembic heads
# Output: head1, head2

# 2. Check what each migration does
cat migrations/head1_add_phone.py
cat migrations/head2_add_bio.py

# 3. Verify they are compatible (no overlapping changes)
# Both add different columns to different tables - safe

# 4. Create merge migration
alembic merge -m "merge heads" head1 head2

# 5. Apply the merge
alembic upgrade head

# 6. Verify
alembic current
# Output: merge_revision (head)

Expected output: Conflict Resolution creates a merge migration reconciling both heads. The merge is applied, resulting in a single head. The history now includes both feature migrations.

Handling Overlapping Changes

# Two migrations modifying the same column - conflict!

# Branch A migration:
def upgrade():
    op.alter_column('users', 'name', type_=sa.String(200))

# Branch B migration:
def upgrade():
    op.alter_column('users', 'name', type_=sa.String(100))

# Resolution options:
# 1. Keep one, drop the other
# 2. Apply both (last one wins)
# 3. Create a new migration that sets the correct type

# Best approach: Drop both conflicting migrations
# Create a single migration with the correct change:
def upgrade():
    op.alter_column('users', 'name', type_=sa.String(200))

Expected output: Overlapping changes to the same column must be resolved manually. Both migrations cannot apply. Drop both, create a single migration with the correct change. Communicate with the other developer.

Rebase Strategy

# Preferred approach: Rebase before creating migrations
# This avoids merge migrations entirely

# 1. Start work on a feature branch
git checkout -b feat/add-phone

# 2. Make model changes

# 3. Sync with main first
git fetch origin
git rebase origin/main

# 4. Now create the migration
alembic revision --autogenerate -m "add phone"
# This migration builds on the latest main migration

# 5. When the PR merges, no merge migration needed
# The migration chains cleanly from the main history

Expected output: Rebasing before creating migrations ensures the new migration chains from the latest main migration. When the PR merges, the migration history remains linear. No merge migration is needed.

Common Mistakes

1. Ignoring Migration Conflicts

Merging a branch with a migration conflict without resolving causes the main branch to have divergent history. Migration tools refuse to apply or behave unpredictably. Always resolve migration conflicts before merging.

2. Editing Another Developers Migration

Editing someone else's migration after it has been applied to any environment causes inconsistency. If changes are needed, create a new migration. Never modify applied migrations.

3. Not Running Migrations After Rebasing

After rebasing, the old migration may conflict with the new base. Run migrations before creating new ones. This ensures the new migration chains from the correct base.

4. Creating Merge Migrations Without Understanding Both Sides

Merge migrations should only reconcile history, not make changes. If a merge migration includes schema operations, it means the migrations were incompatible. Fix the underlying issue instead.

5. Merging Without Testing

After creating a merge migration, test: apply all migrations from scratch, verify the schema, run the application, test revert. A merge that breaks the migration chain causes issues for new environments.

Practice Questions

1. What causes migration branching?

Two developers create migrations in parallel branches. Both migrations depend on the same parent migration. When both branches merge, the main branch has two heads (divergent history).

2. How do you resolve migration branching?

Create a merge migration that depends on both branch heads. The merge migration has no schema changes. It tells the migration tool that both branches have been applied and the history is now linear.

3. What is the advantage of timestamp-based naming?

Timestamps are unique across branches. Two developers creating migrations at different times get different timestamps. The migration tool applies them in chronological order, avoiding most conflicts.

4. How does rebasing help avoid migration conflicts?

Rebasing before creating a migration ensures the migration chains from the latest main migration. When the branch merges, the migration chains cleanly from the main history without branching.

Challenge

Simulate a migration conflict scenario: create a main branch with migration 001, two feature branches each creating migration 002 (conflict), merge both branches, detect the two heads, create a merge migration, and verify linear history. Then repeat with the rebase strategy to avoid the conflict entirely.

FAQ

Can I have more than two heads to merge?

Yes. Multiple branches can create heads. Use alembic merge with multiple revision IDs. The merge migration lists all parents. All branches are reconciled in one merge.

What happens if I do not create a merge migration?

The migration tool has multiple heads and refuses to apply further migrations. New developers setting up the database get an error. The migration history is broken until a merge is created.

Does Prisma Migrate support merge migrations?

Prisma Migrate uses linear migration history. Conflicts are detected during migrate dev. Prisma may reset the database if history diverges. Always rebase before creating Prisma migrations.

How do I handle conflicts in squashed migrations?

Squashed migrations replace old migrations. All branches that depend on the old migrations must update their dependencies. Coordinate squashing with the team to minimize disruption.

Should I delete the branch migrations after merge?

No. The merge migration references both branch migrations. Deleting them breaks the history. Keep all migration files. Only delete during squashing.

Mini Project: Branching Resolution

Create a branching scenario and resolve it: initialize a project with migration 001, create two branches each with migration 002 (different changes), merge both branches, detect divergent heads, create a merge migration, verify all migrations apply cleanly from scratch, and repeat with rebase strategy to show the alternative.

What's Next

Now that you understand branching and merging, learn about Data Migrations for transforming existing data alongside schema changes.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro