Git 브랜치 및 Rails 마이그레이션 작업 방법 링”하는 좋은 솔루션은 무엇입니까? 이 “상태”는

나는 꽤 많은 git 브랜치로 rails 앱을 만들고 있는데 많은 것들이 db 마이그레이션을 포함합니다. 우리는 조심하려고하지만 때로는 마스터의 일부 코드 조각이 다른 지점에서 제거 / 이름이 바뀐 열을 요청합니다.

  1. 자식 브랜치를 DB 상태와 “커플 링”하는 좋은 솔루션은 무엇입니까?

  2. 이 “상태”는 실제로 무엇입니까?

    크기가 몇 GB 인 데이터베이스 만 복제 할 수는 없습니다.

  3. 병합은 어떻게됩니까?

  4. 솔루션이 noSQL 데이터베이스로도 변환됩니까?

    우리는 현재 MySQL, mongodb 및 redis를 사용합니다.


편집 : 나는 매우 중요한 점을 언급하는 것을 잊어 버린 것 같습니다. 개발 환경 에만 관심이 있지만 큰 데이터베이스 (수 GB)가 있습니다.



답변

지점에 새 마이그레이션을 추가 할 때 rake db:migrate마이그레이션 db/schema.rb

이렇게하면 개발 과정에서 다른 마이그레이션 집합이있는 다른 지점으로 전환하고 간단히 실행할 수 rake db:schema:load있습니다.

이렇게하면 전체 데이터베이스다시 작성되고 기존 데이터가 손실됩니다 .

당신은 아마도 당신이 매우 조심하는 하나의 브랜치에서만 프로덕션을 실행하고 싶을 것입니다. 따라서이 단계는 적용되지 않습니다 ( rake db:migrate평소와 같이 실행하십시오 ). 그러나 개발 과정에서 스키마에서 데이터베이스를 재생성하는 것은 별다른 문제가되지 않습니다 rake db:schema:load.


답변

쉽게 재생할 수없는 큰 데이터베이스가있는 경우 일반 마이그레이션 도구를 사용하는 것이 좋습니다. 간단한 프로세스를 원한다면 이것이 좋습니다.

  • 분기를 전환하기 전에 rake db:rollback분기 지점 이전 상태로 롤백 ( )하십시오. 그런 다음 분기를 전환 한 후을 실행하십시오 db:migrate. 이것은 수학적으로 정확하며 down스크립트 를 작성 하는 한 작동합니다.
  • 분기를 전환하기 전에이 작업을 잊어 버린 경우 일반적으로 안전하게 전환, 롤백 및 다시 전환 할 수 있으므로 워크 플로로 생각하면 가능합니다.
  • 다른 지점의 마이그레이션간에 종속성이있는 경우 … 잘 생각해야합니다.

답변

다음은 다른 마이그레이션이 포함 된 분기 간을 전환하기 위해 작성한 스크립트입니다.

https://gist.github.com/4076864

언급 한 모든 문제를 해결할 수는 없지만 지점 이름이 주어지면 다음과 같이됩니다.

  1. 주어진 브랜치에 존재하지 않는 현재 브랜치에서 마이그레이션을 롤백
  2. db / schema.rb 파일에 대한 변경 사항을 폐기하십시오.
  3. 주어진 지점을 확인하십시오
  4. 주어진 브랜치에 존재하는 새로운 마이그레이션을 실행합니다
  5. 테스트 데이터베이스 업데이트

프로젝트에서 항상 수동 으로이 작업을 수행하므로 프로세스를 자동화하는 것이 좋을 것이라고 생각했습니다.


답변

각 지점에 대한 별도의 데이터베이스

비행하는 유일한 방법입니다.

2017 년 10 월 16 일 업데이트

꽤 오랜 시간이 지나서 이것으로 돌아와서 약간의 개선을했습니다.

  • 와 함께 네임 스페이스 레이크 작업을 추가하여 지점을 만들고 데이터베이스를 한 번에 복제했습니다 bundle exec rake git:branch.
  • 마스터에서 복제하는 것이 항상 원하는 것이 아니라는 것을 알고 있으므로 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 %>

lib/tasks/db.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

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 bundle exec git:branch, 새로운 브랜치 이름을 입력하고 좀비를 죽이기 시작합니다.


답변

아마도 개발 데이터베이스가 너무 크다는 힌트로 이것을 사용해야합니까? db / seeds.rb와 더 작은 데이터 세트를 개발에 사용할 수 있으면 현재 분기에서 schema.rb 및 seed.rb를 사용하여 문제를 쉽게 해결할 수 있습니다.

귀하의 질문은 개발과 관련이 있다고 가정합니다. 프로덕션에서 분기를 정기적으로 전환해야하는 이유를 상상할 수 없습니다.


답변

나는 같은 문제로 고심하고 있었다. 내 해결책은 다음과 같습니다.

  1. 모든 개발자가 schema.rb 및 모든 마이그레이션을 체크인했는지 확인하십시오.

  2. 프로덕션 환경에 배포 할 사람 / 기계가 하나 있어야합니다. 이 머신을 병합 머신이라고합니다. 변경 내용을 병합 시스템으로 가져 오면 schema.rb에 대한 자동 병합이 실패합니다. 문제 없습니다. schema.rb의 이전 내용으로 내용을 바꾸십시오 (사본을 사용하거나 github에서 사용하면 …).

  3. 중요한 단계는 다음과 같습니다. 모든 개발자의 마이그레이션은 이제 db / migrate 폴더에서 사용할 수 있습니다. 계속해서 번들 실행 db : migrate를 실행하십시오. 병합 시스템의 데이터베이스를 모든 변경 사항과 동일하게 가져옵니다. 또한 schema.rb를 재생성합니다.

  4. 모든 저장소 (원격 및 원격 인 원격 저장소)에 변경 사항을 적용하고 적용하십시오. 완료해야합니다!


답변

이것이 내가 한 일이며 모든 기초를 다뤘는지 확실하지 않습니다.

개발 중 (postgresql 사용) :

  • sql_dump db_name> tmp / branch1.sql
  • 자식 체크 아웃 branch2
  • dropdb db_name
  • createdb db_name
  • psql db_name <tmp / branch2.sql # (이전 분기 스위치에서)

약 50K 레코드가있는 데이터베이스의 레이크 유틸리티보다 훨씬 빠릅니다.

프로덕션의 경우 마스터 분기를 성사로 유지하고 모든 마이그레이션이 체크인되고 shema.rb가 올바르게 병합됩니다. 표준 업그레이드 절차를 수행하십시오.