web-dev-qa-db-ja.com

GitブランチとRails移行の操作方法

私はRailsかなりの数のgitブランチを持つアプリに取り組んでおり、それらの多くはdb移行を含んでいます。 /別のブランチで名前を変更しました。

  1. gitブランチをDB状態と「結合」するための素敵なソリューションは何でしょうか?

  2. これらの「状態」は実際にはどうなりますか?

    数GBのサイズのデータ​​ベースを複製することはできません。

  3. そして、マージで何が起こるべきですか?

  4. ソリューションはnoSQLデータベースにも変換されますか?

    現在、MySQL、mongodb、およびredisを使用しています


編集:私は非常に重要な点に言及するのを忘れたように見えます。私は開発環境にのみ興味がありますが、大きなデータベース(数GBのサイズ)を使用します。

124
Kostas

ブランチに新しい移行を追加する場合、rake db:migrateを実行し、両方の移行をコミットしますanddb/schema.rb

これを行うと、開発中に、異なる移行セットを持つ別のブランチに切り替えて、rake db:schema:loadを実行することができます。

データベース全体を再作成すると、既存のデータは失われますになります。

たぶん、あなたは非常に注意している1つのブランチからのみ本番を実行したいので、これらの手順はそこでは適用されません(そこでrake db:migrateを実行するだけです)。しかし、開発では、スキーマからデータベースを再作成することは大したことではありません。これは、rake db:schema:loadが行うことです。

61
Andy Lindeman

すぐに再現できない大きなデータベースがある場合は、通常の移行ツールを使用することをお勧めします。簡単なプロセスが必要な場合、これがお勧めです。

  • 分岐を切り替える前に、分岐点の前の状態にロールバック(rake db:rollback)します。次に、ブランチを切り替えた後、db:migrateを実行します。これは数学的には正しく、downスクリプトを記述している限り機能します。
  • ブランチを切り替える前にこれを行うことを忘れた場合、一般的に安全に切り替えて、ロールバックして、再び切り替えることができるので、ワークフローとしては実現可能だと思います。
  • 異なるブランチの移行間に依存関係がある場合は...まあ、一生懸命に考える必要があります。
19
ndp

以下は、異なる移行を含むブランチ間を切り替えるために書いたスクリプトです。

https://Gist.github.com/4076864

あなたが言及したすべての問題を解決するわけではありませんが、ブランチ名を指定すると:

  1. 指定されたブランチに存在しない現在のブランチの移行をロールバックします
  2. Db/schema.rbファイルへの変更を破棄します
  3. 指定されたブランチをチェックアウトします
  4. 指定されたブランチに存在する新しい移行を実行します
  5. テストデータベースを更新する

私たちのプロジェクトでは常にこれを手動で行っているので、プロセスを自動化するのは良いことだと思いました。

13
Jon Lemmon

ブランチごとに個別のデータベース

それが唯一の飛行方法です。

2017年10月16日更新

しばらくしてからこれに戻り、いくつかの改善を行いました。

  • bundle exec rake git:branchを使用して、ブランチを作成し、データベースを一度に複製する別の名前空間のrakeタスクを追加しました。
  • マスターからのクローン作成が常にあなたがしたいことではないことに気付いたので、db:clone_from_branchタスクがSOURCE_BRANCHおよびTARGET_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 %>

lib/tasks/db.rake

これは、あるブランチから別のブランチにデータベースを簡単に複製するためのRakeタスクです。これは、SOURCE_BRANCHおよびTARGET_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

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

あとは、bundle exec git:branchを実行し、新しいブランチ名を入力して、ゾンビの殺害を開始するだけです。

5
Joshua Pinter

おそらく、開発データベースが大きすぎるというヒントとしてこれを使用する必要がありますか?開発にdb/seeds.rbと小さなデータセットを使用できる場合、現在のブランチのschema.rbとseeds.rbを使用することで問題を簡単に解決できます。

それはあなたの質問が開発に関係していると仮定しています。運用環境でブランチを定期的に切り替える必要がある理由は想像できません。

4
noodl

私は同じ問題に苦労していました。ここに私の解決策があります:

  1. Schema.rbとすべての移行の両方がすべての開発者によってチェックインされていることを確認してください。

  2. 本番環境への展開には1人/マシンが必要です。このマシンをマージマシンと呼びましょう。変更がマージマシンにプルされると、schema.rbの自動マージは失敗します。問題ありません。 schema.rbの以前のコンテンツが何であれ、コンテンツを置き換えるだけです(コピーを保存するか、使用する場合はgithubから取得できます...)。

  3. ここに重要なステップがあります。これで、すべての開発者からの移行がdb/migrateフォルダーで利用可能になります。先に進んでbundle exec rake db:migrateを実行します。すべての変更と同等のマージマシン上のデータベースを使用します。また、schema.rbも再生成します。

  4. 変更をコミットして、すべてのリポジトリ(リモートであるリモートおよび個人)にプッシュします。これで完了です!

3
Tabrez

これは私がやったことであり、すべてのベースをカバーしたかどうかはわかりません:

開発中(postgresqlを使用):

  • sql_dump db_name> tmp/branch1.s​​ql
  • git checkout branch2
  • dropdb db_name
  • createdb db_name
  • psql db_name <tmp/branch2.sql#(前のブランチスイッチから)

これは、約5万件のレコードを持つデータベースのrakeユーティリティよりもはるかに高速です。

本番環境では、masterブランチをsacrosanctとして維持し、すべての移行をチェックインし、shema.rbを適切にマージします。標準のアップグレード手順を実行します。

3
Paul Carmody

私はあなたがここで持っているピタを完全に体験します。私が考えているように、本当の問題は、すべてのブランチに特定のブランチをロールバックするコードがないことです。私はDjangoの世界にいるので、熊手がよくわからない。移行は分岐しない独自のリポジトリにあるという考えをいじっている(git -サブモジュール、私は最近学びました。そのように、すべてのブランチはすべての移行を持っています。スティッキーな部分は、各ブランチが関心のある移行のみに制限されていることを確認しています。エラーが発生しやすいですが、このための移行ツールはどれも作成されていません。

2
JohnO

ブランチごとに「db環境」を保持する必要があります。汚れ/クリーンスクリプトを見て、異なるインスタンスをポイントします。 dbインスタンスを使い果たした場合、スクリプトに一時インスタンスをスピンオフさせて、新しいブランチに切り替えたときに既に存在し、スクリプトによって名前を変更するだけでよいようにします。 DB更新は、テストを実行する直前に実行する必要があります。

お役に立てれば。

2
Adam Dymitruk

次の2つのオプションのいずれかをお勧めします。

オプション1

  1. データをseeds.rbに配置します。素敵なオプションは、FactoryGirl/Fabrication gemを介してシードデータを作成することです。この方法により、列の追加/削除とともにファクトリが更新されると想定した場合に、データがコードと同期していることを保証できます。
  2. あるブランチから別のブランチに切り替えた後、rake db:resetを実行します。これにより、データベースが効果的にドロップ/作成/シードされます。

オプション2

ブランチチェックアウトの前後に常にrake db:rollback/rake db:migrateを実行することにより、データベースの状態を手動で維持します。注意点は、すべての移行を元に戻す必要があることです。そうしないと機能しません。

1
Alex Popov

開発環境:

rake db:migrate:redoスクリプトがリバーシブルかどうかをテストしますが、常にseed.rbデータ入力。

Gitを使用している場合、seed.rbは移行の変更に伴い変更され、db:migrate:redo開始(他のマシンまたは新しいデータベースでの新しい開発のためのデータのロード)

「変更」とは別に、アップとダウンのメソッドを使用すると、コードは常に、この瞬間とゼロから開始する「変更」のシナリオをカバーします。