Skip to content

Allow custom RevisionMap subclass for pluggable revision ordering #1804

@jasonwbarnett

Description

@jasonwbarnett

Problem

We run a high-velocity monorepo where multiple teams land migrations concurrently. In our merge queue, when two PRs each add a migration, the second one to merge discovers there are now two Alembic heads. This kicks the PR out of the merge queue and requires the author to manually rebase and update their migration's down_revision to point at the new head, re-push, and re-enter the queue. With many developers contributing migrations, this compounds — the more PRs in flight, the more frequently authors get ejected and have to rebase, creating a frustrating cycle of churn.

We want to solve this by using git history to automatically determine migration ordering — when concurrent migrations create multiple heads, order them by when they were first introduced in git, so that the merge queue can resolve the ordering deterministically without human intervention. This requires being able to swap in a custom RevisionMap subclass that overrides _topological_sort().

Today there is no way to customize the ordering behavior without monkey-patching internals. The RevisionMap class is instantiated directly inside ScriptDirectory.__init__() with no way to substitute a subclass.

Proposed Solution

Add a revision_map_class configuration option to ScriptDirectory that accepts a dotted Python path to a RevisionMap subclass. This would allow external packages (e.g. a hypothetical alembic-git-ordering) to provide custom ordering logic by overriding _topological_sort() or other methods, without any changes to Alembic core.

This is a minimal, non-breaking change: a single new keyword argument with a None default, and a config option that is entirely opt-in.

Use Cases

  • Merge queue compatibility: In CI merge queues (GitHub, Mergify, etc.), concurrent migrations cause repeated head conflicts that eject PRs. Authors must rebase and update down_revision each time, which compounds with team size. A git-history-aware RevisionMap could order unrelated migrations deterministically, eliminating this manual churn.
  • Git-history-based ordering: Order concurrent migrations by their first commit date, giving a stable timeline-based ordering across branches.
  • Custom merge strategies: Organizations with many parallel branches could implement project-specific rules for how unrelated migrations should be sequenced.

Current Workarounds

The only current options are:

  1. Monkey-patching RevisionMap or ScriptDirectory in env.py — fragile and breaks across Alembic upgrades
  2. Forking Alembic — heavy-handed for a small customization point
  3. Manually rebasing and updating down_revision every time a PR gets ejected — the status quo we're trying to escape

We have a PR ready at #1805 that implements this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    use casenot quite a feature and not quite a bug, something we just didn't think ofversioning model

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions