【问题标题】:alembic revision - multiple heads (due branching) erroralembic 修订 - 多头(由于分支)错误
【发布时间】:2014-04-16 01:31:27
【问题描述】:

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

$ 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 的新手。有 2 个开发人员在开发这个应用程序,我们有 2 个 git 分支 - master 和 develop(我不确定这是否与它有关)。

有什么线索吗?

【问题讨论】:

    标签: python git alembic


    【解决方案1】:

    也许最传统(也是最可靠)的解决方案是使用alembic merge heads。就像在 Git 中有两个分支时,您可以通过合并提交将它们重新组合在一起,在 Alembic 中,当您有两个分支时,您可以通过合并修订将它们重新组合在一起。

    例如,假设我们有一个添加表 A 的修订版 1a6b1a4a0574 和一个添加表 B 的修订版 2e49118db057。我们可以在 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,正如这里的其他答案所建议的那样。修补向下修订的危险在于它可能导致修订永远不会被应用。例如,假设您的同事 Bob 已经使用修订版 2e49118db057 拉下您的分支并运行 alembic upgrade head,创建表 B。然后您决定修改 2e49118db057 的 down_revision 以指向 Bob 从未见过或运行过的 1a6b1a4a0574前。 Bob 拉下您的更改,运行alembic upgrade head,然后......什么也没有发生,因为就 Alembic 而言,他已经在 head 并且不需要运行 1a6b1a4a0574。所以 Bob 最终永远不会得到表 A,并且可能永远不会弄清楚为什么他的数据库处于损坏状态。

    不要破坏 Bob 的数据库 - 改为进行合并修订。

    【讨论】:

    • 这确实是解决alembic版本冲突的正确方法。
    • alembic.sqlalchemy.org/en/latest/api/… 在合并后失败,因为 head 将包含两个修订。您知道如何解决这个问题吗?
    • @Brayoni 是的 - 你运行 alembic merge heads。这就是整个答案的真正含义。
    【解决方案2】:

    当两个 alembic 迁移从同一个迁移中分支出来时,就会出现此问题。通常,当多人进行架构更改时会发生这种情况。要修复它,您只需将迁移的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'

    【讨论】:

    • 谨慎使用这种方法。如果你想保持你的修订历史整洁并且你知道你的多个头中没有一个在任何地方运行过……但如果你不'如果有这样的保证,您可能会导致其中一个数据库跳过迁移而破坏它。请参阅my answer 的末尾以了解这种方法如何出错的描述。使用 alembic merge heads - 虽然可能 uglier,由于创建了额外的修订 - 是一种更强大的方法。
    • 我意识到过去几年我们一直在这样做。当团队中有更多开发人员时,它是不可扩展的。我们应该做merge heads,我们现在才意识到。
    • 这真的不是你应该走的路。使用下面 Mark Amery 建议的合并头,否则您将破坏同事的数据库。
    【解决方案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
    

    您可以在这里看到 2 个不同的分支。一个从 49501407aec9 开始,第二个从 280061454d2a 开始。我将 49501407aec9 和以下 2e74f61d3b80 移出 /versions 目录,运行

    $ python manage.py db revision
    

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

    【讨论】:

      【解决方案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")
      

      参考

      【讨论】:

        猜你喜欢
        • 2015-04-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-28
        • 2017-03-23
        • 2019-07-14
        相关资源
        最近更新 更多