如何使用Git分支和Rails迁移

Kos*_*tas 126 database git ruby-on-rails

我正在使用具有相当多git分支的rails应用程序,其中许多包括数据库迁移.我们尽量小心,但有时主人的一些代码要求在另一个分支中删除/重命名的列.

  1. 什么是与DB状态"耦合"git分支的好方法?

  2. 这些"状态"究竟是什么?

    如果数据库的大小为几GB,我们不能只复制数据库.

  3. 合并会发生什么?

  4. 该解决方案是否也会转换为noSQL数据库?

    我们目前使用MySQL,mongodb和redis


编辑:看起来我忘了提到一个非常重要的一点,我只对开发环境感兴趣,但对大型数据库(大小几GB)感兴趣.

And*_*man 62

在任何分支中添加新迁移时,请运行rake db:migrate并提交迁移 db/schema.rb

如果您这样做,在开发中,您将能够切换到具有不同迁移集并且只是运行的另一个分支rake db:schema:load.

请注意,这将重新创建整个数据库,现有数据将丢失.

你可能只想在一个你非常小心的分支上运行生产,所以这些步骤不适用于那里(只是rake db:migrate像往常那样运行).但是在开发过程中,从架构中重新创建数据库应该没什么大不了的,这就是rake db:schema:load它的作用.

  • 我认为这只会解决架构问题,每次向下迁移都会丢失数据,永远不会再被看到.保存某些db-data-patch是一个好主意,这个db-data-patch在移出分支时会被保存,而另一个在移动到另一个分支时会被加载?补丁应该只包含在下载过程中丢失的数据(迁移). (5认同)
  • 如果你想加载数据,请使用`db/seeds.rb`如果你在那里设置了一些合理的种子数据,那么破坏你的开发数据库不应该太糟糕. (4认同)

ndp*_*ndp 20

如果您有一个无法轻易复制的大型数据库,那么我建议您使用普通的迁移工具.如果你想要一个简单的过程,这就是我建议的:

  • 在切换分支之前,rollback(rake db:rollback)到分支点之前的状态.然后,在切换分支后,运行db:migrate.这在数学上是正确的,只要你编写down脚本,它就可以工作.
  • 如果您在切换分支之前忘记执行此操作,通常可以安全地切换回,回滚和再次切换,因此我认为作为工作流程,它是可行的.
  • 如果你在不同分支的迁移之间存在依赖关系......那么,你必须努力思考.

  • 您必须记住,并非所有迁移都是可逆的,也就是说,第一个建议的步骤不能保证成功.我认为在开发环境中,一个好主意是使用`rake db:schema:load`和`rake db:seed`,正如@noodl所说的那样. (2认同)

Jon*_*mon 13

这是我为在包含不同迁移的分支之间切换而编写的脚本:

https://gist.github.com/4076864

它不会解决你提到的所有问题,但给定一个分支名称它将:

  1. 回滚当前分支上在给定分支上不存在的任何迁移
  2. 放弃对db/schema.rb文件的任何更改
  3. 看看给定的分支
  4. 运行给定分支中存在的任何新迁移
  5. 更新您的测试数据库

我发现自己一直在我们的项目中手动执行此操作,所以我认为自动化该过程会很好.


Jos*_*ter 6

每个分支都有独立的数据库

这是唯一的飞行方式。

2017年10月16日更新

一段时间后,我返回到此页面并进行了一些改进:

  • 我添加了另一个名称空间rake任务来创建一个分支,并使用来一次克隆数据库bundle exec rake git:branch
  • 现在我意识到,从master克隆并不总是您想要做的,因此我更加明确地说明了该db:clone_from_branch任务采用SOURCE_BRANCHTARGET_BRANCH环境变量。使用git:branch时会自动将当前分支用作SOURCE_BRANCH
  • 重构和简化。

config/database.yml

为了使您更轻松,这里介绍了如何更新database.yml文件以根据当前分支动态确定数据库名称。

<% 
database_prefix = 'your_app_name'
environments    = %W( development test ) 
current_branch  = `git status | head -1`.to_s.gsub('On branch ','').chomp
%>

defaults: &defaults
  pool: 5
  adapter: mysql2
  encoding: utf8
  reconnect: false
  username: root
  password:
  host: localhost

<% environments.each do |environment| %>  

<%= environment %>:
  <<: *defaults
  database: <%= [ database_prefix, current_branch, environment ].join('_') %>
<% end %>
Run Code Online (Sandbox Code Playgroud)

lib/tasks/db.rake

这是一项Rake任务,可以轻松地将数据库从一个分支克隆到另一个分支。这需要一个SOURCE_BRANCHTARGET_BRANCH环境变量。基于@spalladino的任务。

namespace :db do

  desc "Clones database from another branch as specified by `SOURCE_BRANCH` and `TARGET_BRANCH` env params."
  task :clone_from_branch do

    abort "You need to provide a SOURCE_BRANCH to clone from as an environment variable." if ENV['SOURCE_BRANCH'].blank?
    abort "You need to provide a TARGET_BRANCH to clone to as an environment variable."   if ENV['TARGET_BRANCH'].blank?

    database_configuration = Rails.configuration.database_configuration[Rails.env]
    current_database_name = database_configuration["database"]

    source_db = current_database_name.sub(CURRENT_BRANCH, ENV['SOURCE_BRANCH'])
    target_db = current_database_name.sub(CURRENT_BRANCH, ENV['TARGET_BRANCH'])

    mysql_opts =  "-u #{database_configuration['username']} "
    mysql_opts << "--password=\"#{database_configuration['password']}\" " if database_configuration['password'].presence

    `mysqlshow #{mysql_opts} | grep "#{source_db}"`
    raise "Source database #{source_db} not found" if $?.to_i != 0

    `mysqlshow #{mysql_opts} | grep "#{target_db}"`
    raise "Target database #{target_db} already exists" if $?.to_i == 0

    puts "Creating empty database #{target_db}"
    `mysql #{mysql_opts} -e "CREATE DATABASE #{target_db}"`

    puts "Copying #{source_db} into #{target_db}"
    `mysqldump #{mysql_opts} #{source_db} | mysql #{mysql_opts} #{target_db}`

  end

end
Run Code Online (Sandbox Code Playgroud)

lib/tasks/git.rake

该任务将在当前分支(主分支或其他分支)的基础上创建一个git分支,将其检出并将当前分支的数据库克隆到新分支的数据库中。光滑的AF。

namespace :git do

  desc "Create a branch off the current branch and clone the current branch's database."
  task :branch do 
    print 'New Branch Name: '
    new_branch_name = STDIN.gets.strip 

    CURRENT_BRANCH = `git status | head -1`.to_s.gsub('On branch ','').chomp

    say "Creating new branch and checking it out..."
    sh "git co -b #{new_branch_name}"

    say "Cloning database from #{CURRENT_BRANCH}..."

    ENV['SOURCE_BRANCH'] = CURRENT_BRANCH # Set source to be the current branch for clone_from_branch task.
    ENV['TARGET_BRANCH'] = new_branch_name
    Rake::Task['db:clone_from_branch'].invoke

    say "All done!"
  end

end
Run Code Online (Sandbox Code Playgroud)

现在,您所需要做的就是运行bundle exec git:branch,输入新的分支名称并开始杀死僵尸。