【问题标题】:What is the best way to resolve Rails orphaned migrations?解决 Rails 孤立迁移的最佳方法是什么?
【发布时间】:2013-04-09 03:18:57
【问题描述】:

我一直在一个项目的分支之间切换,每个分支都有不同的迁移......这是场景:

$ rake db:migrate:status

 Status   Migration ID    Migration Name
--------------------------------------------------
   ...
   up     20130307154128  Change columns in traffic capture
   up     20130311155109  Remove log settings
   up     20130311160901  Remove log alarm table
   up     20130320144219  ********** NO FILE **********
   up     20130320161939  ********** NO FILE **********
   up     20130320184628  ********** NO FILE **********
   up     20130322004817  Add replicate to root settings
   up     20130403190042  ********** NO FILE **********
   up     20130403195300  ********** NO FILE **********
   up     20130403214000  ********** NO FILE **********
   up     20130405164752  Fix ap hostnames
   up     20130410194222  ********** NO FILE **********

问题是rake db:rollback 根本无法工作,因为缺少文件...

我应该怎么做才能再次回滚并摆脱 NO FILE 消息?

顺便说一句,rake db:resetrake db:drop 不是一个选项,我不能丢失其他表中的数据...

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 git migration rails-migrations


    【解决方案1】:

    假设您使用的是 Git,那么获取这些迁移并将它们带入您当前的分支应该相对简单。如果你有一个特定的提交,你想要一个文件,你可以使用:

    git checkout <commit hash> <file_name>
    

    (感谢this answer

    或者,您可以从特定分支 HEAD 签出:

    git checkout <branch name> -- <file_name>
    

    据此blog post

    假设这些实际上是在数据库上运行的迁移版本,您应该可以回滚。

    【讨论】:

    • 感谢您的回答。这个问题是我正在一个有很多分支和开发人员的大项目中工作。所以,我不知道哪个分支有孤儿迁移。我终于找到了方法(见我的回答)
    【解决方案2】:

    您可以将两个分支合并回主分支,以便您拥有所有可用的迁移。如果您真的不希望这些迁移在那里,但希望能够回滚,您可以编辑数据库中的 schema_migrations 表以删除与您没有文件的迁移对应的行。但是,如果您随后切换到具有不同迁移的另一个分支,这将导致问题。

    【讨论】:

    • 临时合并分支并回滚直到达到良好状态是个好主意。但是,一些分支没有近祖先提交,因此它们在合并过程中会发生大量冲突......我解决了去每个包含孤儿迁移的分支回滚然后再次回到我的分支。 ..
    【解决方案3】:

    我最终解决了这样的问题:

    (1) 转到有迁移文件的分支并回滚。当您有许多分支时,这并非微不足道,如果您尝试合并它们会导致许多冲突。所以我使用这个命令来找出每个孤儿迁移所属的分支。

    所以,我需要找到上次修改迁移的提交。

    git log --all --reverse --stat | grep <LASTEST_ORPHAN_MIGRATION_ID> -C 10
    

    我获取提交哈希并确定它属于哪个分支,如下所示:

    git branch --contains <COMMIT_HASH>
    

    然后我可以回到那个分支,回滚并为所有丢失的文件重复这个过程。

    (2) 运行迁移:检查您最终要处理的分支并运行迁移,您应该一切顺利。

    疑难解答

    在某些情况下,我还在已删除的分支上运行孤立迁移。

    为了解决这个问题,我创建了具有与丢失文件相同的 migration_id 的虚拟迁移文件并将它们回滚。之后,我能够删除他们的虚拟迁移并拥有干净的迁移状态:)

    另一种选择是直接从数据库中删除丢失的文件:

    delete from schema_migrations where version='<MIGRATION_ID>';
    

    【讨论】:

    • 很好的答案。一定要先给我们更简单、更短、更实用的方法! =] 我压力很大,直到哦。太好了。
    • 你在哪里输入这个? delete from schema_migrations where version='&lt;MIGRATION_ID&gt;';
    • 在您的数据库控制台中...您可以通过键入:rails dbconsole 访问它
    • @Adrian 更短,你可以输入 rails db ;)
    • 如果您像我一样在运行rails db 时遇到问题,您也可以从rails 控制台执行相同操作,例如:sql = "delete from schema_migrations where version='&lt;MIGRATION_ID&gt;';" 然后ActiveRecord::Base.connection.execute(sql)
    【解决方案4】:

    编辑:以下内容将删除您的数据库

    一种对我有用的更简单的方法(请注意,此命令将删除数据库并且您的所有数据都将丢失):

    rake db:migrate:reset

    ..然后:

    rake db:migrate:status

    孤儿应该消失。

    【讨论】:

    • 注意:db:migrate:reset 会删除数据库,导致数据完全丢失!!
    • 请阅读上面的信息 - 不要重置数据库,因为您将丢失所有数据。
    • “我并不总是炸毁我的数据库,但当我这样做时,那是因为我没有先读取 SO cmets。”
    • 从轨道上核弹可以保证消除孤儿。
    • 什么样的施虐狂会赞成这个答案?不要这样做来删除孤立的迁移。
    【解决方案5】:

    迁移存储在您的数据库中。如果您想删除放弃的迁移,请将它们从数据库中删除。

    Postgres 示例:

    1. 打开psql:

      psql
      
    2. 连接到您的数据库:

      \c your_database
      
    3. 如果您好奇,请显示 schema_migrations:

      SELECT * FROM schema_migrations;
      
    4. 如果您好奇,请检查是否存在已放弃的迁移:

      SELECT version FROM schema_migrations WHERE version IN 
      ('20130320144219', '20130320161939', '20130320184628', '20130403190042',
       '20130403195300', '20130403214000', '20130410194222');
      
    5. 删除它们:

      DELETE FROM schema_migrations WHERE version IN (<version list as above>);
      

    现在,如果您运行 bundle exec rake db:migrate:status,您将看到孤立的迁移已成功删除。

    【讨论】:

    • 谢谢,这太棒了,并没有破坏我的暂存数据。
    【解决方案6】:

    如果迁移文件确实丢失(例如,运行迁移,忘记回滚迁移,然后在提交前删除迁移文件),我能够重现丢失的迁移,如下所示:

    1. 返回 git 历史记录以获取 schema.rb 文件的副本并保存在 git repo 之外 (git log; git checkout xxxxxx; cp schema.rb ~/schema_old.rb, git checkout master).
    2. 对这两个文件运行 diff,并将迁移命令复制到与缺少的迁移 ID (diff schema.rb ~/schema_old.rb &gt; migration_file.rb; vi migration_file.rb) 匹配的迁移文件中
    3. 检查您的迁移状态和回滚 (rake db:migrate:status; rake db:rollback; rake db:migrate:status;)

    【讨论】:

      【解决方案7】:

      这是来自@medik 的 psql 答案的 rake 版本,它不会擦除您的数据库或做任何疯狂的事情:

      1) 查找孤立的迁移版本:

      rails db:migrate:status
      

      2) 记下丢失的迁移版本并进入数据库控制台:

      rails dbconsole
      

      3) 现在手动从迁移表中删除版本:

      delete from schema_migrations where version='[version_number]';
      

      【讨论】:

      • 这对我有用,Rails 6.0.0。漂亮、干净、简单。
      • 注意:如果只有 1 个版本号,请从版本中删除 [ ]。
      • 可爱,简单的解决方案。谢谢!
      【解决方案8】:

      创建名称如下的新文件 20130320144219_migration_1 将一些空白代码放入

      class Migration1 < ActiveRecord::Migration 
        def change; end 
      end 
      

      并运行命令rails db:migrate:down VERSION= 20130320144219 最后 - 删除这些文件

      【讨论】:

        【解决方案9】:

        一旦您获得来自失败的rake db:migrate 的版本号或来自rake db:migrate:status 的 NO FILE 条目,则为 Rails 控制台提供一个衬垫

         class SchemaMigration < ActiveRecord::Base; end; SchemaMigration.where(version: %i[the version numbers to delete]).delete_all
        

        这意味着,从终端,你可以

        rails runner "class SchemaMigration < ActiveRecord::Base; end; SchemaMigration.where(version: %i[the version numbers to delete]).delete_all"
        

        不过,到那时,使用先前答案中的直接数据库命令之一可能会更快。

        【讨论】:

          【解决方案10】:

          这是我为此目的编写的一个 rake 任务。它调用 db:migrate:status 在后台使用的相同方法,ActiveRecord::Base.connection.migration_context.migrations_status

          # lib/tasks/cleanup_migration_entries.rake
          
          desc 'Removes schema_migration entries for removed migration files'
          task 'db:migrate:cleanup': :environment do
            migration_context = ActiveRecord::Base.connection.migration_context
            versions_to_delete =
              migration_context.migrations_status
                               .filter_map { |_status, version, name| version if name.include?('NO FILE') }
          
            migration_context.schema_migration.delete_by(version: versions_to_delete)
          
            puts "Cleaned up #{versions_to_delete.size} orphaned migrations."
          end
          

          【讨论】:

          • 如果您不关心缺少迁移的down 影响,那就太好了。由于我的问题是一开始从未检查过版本控制的迁移,因此这个解决方案帮助了我。
          猜你喜欢
          • 1970-01-01
          • 2010-11-08
          • 2019-08-20
          • 1970-01-01
          • 2019-10-05
          • 1970-01-01
          • 2020-04-15
          • 2010-09-15
          • 2020-05-08
          相关资源
          最近更新 更多