alembic 版本修订 - 多个头(因分支)错误
我有一个应用程序,今天想为它创建一个新的迁移。当我运行
$ 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 个回答
使用 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")
参考资料
这个问题发生在两个数据库迁移(也就是对数据库结构的修改)是从同一个迁移分出来的。通常,这种情况出现在多个开发者同时对数据库结构进行修改的时候。要解决这个问题,你只需要把你的迁移文件中的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'
。
最常见且可靠的解决方案是使用 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 的数据库出问题——还是做一个合并修订吧。
我运行了
$ 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
这就创建了一个新的迁移文件。