Skip to main content

alembic-git-revisions

Automatic Alembic migration chaining based on git commit history. No more Multiple head revisions are present for given argument 'head'.

The problem

You merged two branches and Alembic now refuses to run:

ERROR [alembic.util.messaging] Multiple head revisions are present for given argument 'head'; please specify a specific target revision, '<branchname>@head' to narrow to a specific head, or 'heads' for all heads

When multiple developers create Alembic migrations on separate branches, they often end up with the same down_revision — the current head at the time each branch was created. When these branches merge, Alembic fails with this MultipleHeads error because two migrations point to the same predecessor.

The usual fix is manual: rebase, update down_revision, and hope nobody else merges in the meantime.

How it works

Instead of hardcoding down_revision, this library determines the migration chain automatically from git history. It uses git log --reverse --diff-filter=A to find the order in which migration files were first committed, then chains them linearly after the last "static" (hardcoded) migration.

This means:

  • New migrations never conflict with each other
  • The chain is always linear, regardless of branch merge order
  • Existing migrations with hardcoded down_revision continue to work

Installation

pip install alembic-git-revisions

Setup

Copy the provided template to your Alembic script.py.mako:

"""${message}

Revision ID: ${up_revision}
Create Date: ${create_date}

"""
from alembic import op
from alembic_git_revisions import get_down_revision
import sqlalchemy
${imports if imports else ""}

revision = ${repr(up_revision)}
down_revision = get_down_revision(revision)
branch_labels = ${repr(branch_labels)}
depends_on = ${repr(depends_on)}


def upgrade() -> None:
    ${upgrades if upgrades else "pass"}


def downgrade() -> None:
    ${downgrades if downgrades else "pass"}

A reference template is included in the package at alembic_git_revisions/templates/script.py.mako.

That's it. New migrations generated with alembic revision --autogenerate will automatically chain themselves using git history.

Environments without git (Docker, CI)

In Docker images or CI environments where git history isn't available, pre-generate a revision_chain.json file before building:

# Using the CLI
alembic-git-revisions /path/to/alembic/versions

# Or as a Python module
python -m alembic_git_revisions /path/to/alembic/versions

This writes revision_chain.json next to the versions/ directory. The library uses this file automatically when it exists, falling back to git when it doesn't.

Important: The git clone must have full history (git clone or actions/checkout with fetch-depth: 0). Shallow clones produce incorrect ordering.

Add revision_chain.json to your .gitignore — it should only exist in built artifacts.

How migrations are classified

The library handles three types of migrations:

  • Dynamic — uses get_down_revision(), chained automatically by git history
  • Static — has a hardcoded down_revision, managed manually (legacy migrations)
  • Hybrid — a static migration whose down_revision points to a dynamic one; participates in the dynamic ordering so the chain stays linear

Classification reads the revision and down_revision attributes from each migration module (the same values Alembic loads), so any Alembic file_template and any rev_id format work.

API

get_down_revision(revision, versions_dir=None)

Returns the down_revision for the given revision ID. Auto-discovers the versions directory from the calling migration file's location. Pass versions_dir explicitly for non-standard setups or tests.

generate_chain_file(versions_dir)

Generates revision_chain.json from git history. Run this before building Docker images.

build_chain(versions_dir)

Returns the full {revision: down_revision} dict. Cached per versions_dir. Use build_chain.cache_clear() to reset in tests.

License

Apache-2.0

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

alembic_git_revisions-9.tar.gz (39.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

alembic_git_revisions-9-py3-none-any.whl (14.6 kB view details)

Uploaded Python 3

File details

Details for the file alembic_git_revisions-9.tar.gz.

File metadata

  • Download URL: alembic_git_revisions-9.tar.gz
  • Upload date:
  • Size: 39.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for alembic_git_revisions-9.tar.gz
Algorithm Hash digest
SHA256 2fc1e698675b097b79dbeb5f7ae47a03e069eb562fee95176bad882747681f12
MD5 6894e4d3dc6f2f0de0bde3499d5bb828
BLAKE2b-256 c6bc64a80cd32c4c5748ec1ba48326b47c637d941e1b3cedb0f6f93d2d8cd97b

See more details on using hashes here.

Provenance

The following attestation bundles were made for alembic_git_revisions-9.tar.gz:

Publisher: release.yaml on Mergifyio/alembic-git-revisions

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file alembic_git_revisions-9-py3-none-any.whl.

File metadata

File hashes

Hashes for alembic_git_revisions-9-py3-none-any.whl
Algorithm Hash digest
SHA256 db11e68ba4d67412c6f91ca1c084bc958ff066a0981d7d98b148058d05a84821
MD5 e964654c3bb2ec0079d295dca2e8e028
BLAKE2b-256 abf9926dcca1afd05e4c8a20ca2f46fb4001aef91cebf8073c6773b405231409

See more details on using hashes here.

Provenance

The following attestation bundles were made for alembic_git_revisions-9-py3-none-any.whl:

Publisher: release.yaml on Mergifyio/alembic-git-revisions

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page