alembic 版本修订 - 多个头(因分支)错误

67 投票
4 回答
72836 浏览
提问于 2025-04-17 21:53

我有一个应用程序,今天想为它创建一个新的迁移。当我运行

$ alembic revision -m "__name__"

时,我收到了一个消息

Only a single head is supported. The script directory has multiple heads (due branching), which must be resolved by manually editing the revision files to form a linear sequence. 
Run `alembic branches` to see the divergence(s).

运行

alembic branches

却没有任何反应。

我对alembic还不太熟悉。这个应用有两个开发者在一起工作,我们有两个git分支 - master和develop(我不确定这是否有关系)。

有人知道这是怎么回事吗?

4 个回答

6

使用 merge 命令。

Alembic 的合并是一个迁移文件,它把两个或多个“头”文件合在一起。如果我们现在有的两个分支可以看作是一个“树”结构,那么引入这个合并文件后,它就会变成一个“菱形”结构:


                              -- ae1027a6acf -->
                           /                   \
<base> --> 1975ea83b712 -->                      --> mergepoint
                           \                   /
                            -- 27c6a30d7c24 -->

因此;

$ alembic merge -m "merge ae1 and 27c" ae1027 27c6a
  Generating /path/to/foo/versions/53fffde5ad5_merge_ae1_and_27c.py ... done

如果你更喜欢使用 command

>>> from alembic.config import Config
>>> from alembic import command
>>> alembic_cfg = Config("path to alembic.ini")
>>> command.merge(alembic_cfg, revisions=["27c6a30d7c24", "ae1027a6acf"], message="Merge 27c6a30d7c24 and ae1027a6acf")

参考资料

38

这个问题发生在两个数据库迁移(也就是对数据库结构的修改)是从同一个迁移分出来的。通常,这种情况出现在多个开发者同时对数据库结构进行修改的时候。要解决这个问题,你只需要把你的迁移文件中的down_revision调整为最新的那个迁移的编号。运行alembic history命令可以看到这样的信息:

2f4682466279 -> f34e92e9dc54 (head), Fifth revision (on a separate branch)
2f4682466279 -> f673ac37b34a (head), Fifth revision (local)
2dc9337c3987 -> 2f4682466279, Fourth revision
0fa2aed0866a -> 2dc9337c3987, Third revision
22af4a75cf06 -> 0fa2aed0866a, Second revision
9a8942e953eb -> 22af4a75cf06, First revision

你会发现其中一个第五个版本是本地创建的,它的下游版本是2f4682466279,但是另外一个创建第五个版本的人也得到了相同的下游版本。

进入其中一个第五个版本的文件,把down_revision变量更新为指向另一个第五个版本,像这样:

f673ac37b34a -> f34e92e9dc54 (head), Fifth revision (on a separate branch)
2f4682466279 -> f673ac37b34a, Fifth revision (local)
2dc9337c3987 -> 2f4682466279, Fourth revision
0fa2aed0866a -> 2dc9337c3987, Third revision
22af4a75cf06 -> 0fa2aed0866a, Second revision
9a8942e953eb -> 22af4a75cf06, First revision

在这个例子中,我把迁移f34e92e9dc54更新为down_revision='f673ac37b34a'

81

最常见且可靠的解决方案是使用 alembic merge heads。就像在 Git 中,当你有两个分支时,可以通过合并提交把它们合在一起;在 Alembic 中,当你有两个版本时,也可以通过合并修订把它们合在一起。

比如说,我们有一个修订版本 1a6b1a4a0574,它添加了表 A,还有一个修订版本 2e49118db057,它添加了表 B。我们可以在 alembic history 中看到这两个修订(都标记为 (head)):

$ alembic history
<base> -> 2e49118db057 (head), Add table B
<base> -> 1a6b1a4a0574 (head), Add table A

然后我们可以通过运行 alembic merge heads 来合并它们:

$ alembic merge heads
  Generating /Users/markamery/alembictest/alembic/versions/409782f4c459_.py ... done
$ alembic history
2e49118db057, 1a6b1a4a0574 -> 409782f4c459 (head) (mergepoint), empty message
<base> -> 2e49118db057, Add table B
<base> -> 1a6b1a4a0574, Add table A

如果你的某个修订版本可能已经在其他地方运行过(比如在你同事的开发机器上),那么你可能想用 alembic merge,而不是像其他答案那样去修改某个修订的 down_revision。因为修改 down_revision 可能会导致某个修订永远无法应用。举个例子,假设你的同事 Bob 已经拉取了你的分支并运行了 alembic upgrade head,创建了表 B。然后你决定修改 2e49118db057 的 down_revision 指向 1a6b1a4a0574,而 Bob 从来没有见过或运行过这个修订。Bob 拉取了你的更改,运行 alembic upgrade head,结果... 什么都没发生,因为在 Alembic 看来,他已经在 head 了,不需要再运行 1a6b1a4a0574。所以 Bob 最终得不到表 A,可能也永远不知道他的数据库为什么会出现问题。

别让 Bob 的数据库出问题——还是做一个合并修订吧。

3

我运行了

$ python manage.py db history

结果我得到了

vagrant@precise64:/vagrant$ python manage.py db history

Rev: 29c319804087 (head)
Parent: 313837798149
Path: migrations/versions/29c319804087_.py

    empty message

    Revision ID: 29c319804087
    Revises: 313837798149
    Create Date: 2014-03-05 21:26:32.538027

Rev: 313837798149
Parent: 280061454d2a
Path: migrations/versions/313837798149_.py

    empty message

    Revision ID: 313837798149
    Revises: 280061454d2a
    Create Date: 2014-01-10 03:19:39.838932

Rev: 280061454d2a
Parent: None
Path: migrations/versions/280061454d2a_.py

    empty message

    Revision ID: 280061454d2a
    Revises: None
    Create Date: 2013-12-08 03:04:55.885033


Rev: 2e74f61d3b80 (head)
Parent: 49501407aec9
Path: migrations/versions/2e74f61d3b80_o2_lease.py

    o2 lease

    Revision ID: 2e74f61d3b80
    Revises: 49501407aec9
    Create Date: 2014-02-28 10:38:06.187420

Rev: 49501407aec9
Parent: None
Path: migrations/versions/49501407aec9_.py

    empty message

    Revision ID: 49501407aec9
    Revises: None
    Create Date: 2014-01-22 11:27:08.002187

你可以看到这里有两个不同的分支。一个是从 49501407aec9 开始的,另一个是从 280061454d2a 开始的。我把 49501407aec9 和接下来的 2e74f61d3b80 移出了 /versions 目录,然后运行了

$ python manage.py db revision

这就创建了一个新的迁移文件。

撰写回答