나는 꽤 많은 git 브랜치로 rails 앱을 만들고 있는데 많은 것들이 db 마이그레이션을 포함합니다. 우리는 조심하려고하지만 때로는 마스터의 일부 코드 조각이 다른 지점에서 제거 / 이름이 바뀐 열을 요청합니다.
-
자식 브랜치를 DB 상태와 “커플 링”하는 좋은 솔루션은 무엇입니까?
-
이 “상태”는 실제로 무엇입니까?
크기가 몇 GB 인 데이터베이스 만 복제 할 수는 없습니다.
-
병합은 어떻게됩니까?
-
솔루션이 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
언급 한 모든 문제를 해결할 수는 없지만 지점 이름이 주어지면 다음과 같이됩니다.
- 주어진 브랜치에 존재하지 않는 현재 브랜치에서 마이그레이션을 롤백
- db / schema.rb 파일에 대한 변경 사항을 폐기하십시오.
- 주어진 지점을 확인하십시오
- 주어진 브랜치에 존재하는 새로운 마이그레이션을 실행합니다
- 테스트 데이터베이스 업데이트
프로젝트에서 항상 수동 으로이 작업을 수행하므로 프로세스를 자동화하는 것이 좋을 것이라고 생각했습니다.
답변
각 지점에 대한 별도의 데이터베이스
비행하는 유일한 방법입니다.
2017 년 10 월 16 일 업데이트
꽤 오랜 시간이 지나서 이것으로 돌아와서 약간의 개선을했습니다.
- 와 함께 네임 스페이스 레이크 작업을 추가하여 지점을 만들고 데이터베이스를 한 번에 복제했습니다
bundle exec rake git:branch
. - 마스터에서 복제하는 것이 항상 원하는 것이 아니라는 것을 알고 있으므로
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
다음은 한 지점에서 다른 지점으로 데이터베이스를 쉽게 복제하는 레이크 작업입니다. 이것은 소요 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
이제 당신이해야 할 일은 run bundle exec git:branch
, 새로운 브랜치 이름을 입력하고 좀비를 죽이기 시작합니다.
답변
아마도 개발 데이터베이스가 너무 크다는 힌트로 이것을 사용해야합니까? db / seeds.rb와 더 작은 데이터 세트를 개발에 사용할 수 있으면 현재 분기에서 schema.rb 및 seed.rb를 사용하여 문제를 쉽게 해결할 수 있습니다.
귀하의 질문은 개발과 관련이 있다고 가정합니다. 프로덕션에서 분기를 정기적으로 전환해야하는 이유를 상상할 수 없습니다.
답변
나는 같은 문제로 고심하고 있었다. 내 해결책은 다음과 같습니다.
-
모든 개발자가 schema.rb 및 모든 마이그레이션을 체크인했는지 확인하십시오.
-
프로덕션 환경에 배포 할 사람 / 기계가 하나 있어야합니다. 이 머신을 병합 머신이라고합니다. 변경 내용을 병합 시스템으로 가져 오면 schema.rb에 대한 자동 병합이 실패합니다. 문제 없습니다. schema.rb의 이전 내용으로 내용을 바꾸십시오 (사본을 사용하거나 github에서 사용하면 …).
-
중요한 단계는 다음과 같습니다. 모든 개발자의 마이그레이션은 이제 db / migrate 폴더에서 사용할 수 있습니다. 계속해서 번들 실행 db : migrate를 실행하십시오. 병합 시스템의 데이터베이스를 모든 변경 사항과 동일하게 가져옵니다. 또한 schema.rb를 재생성합니다.
-
모든 저장소 (원격 및 원격 인 원격 저장소)에 변경 사항을 적용하고 적용하십시오. 완료해야합니다!
답변
이것이 내가 한 일이며 모든 기초를 다뤘는지 확실하지 않습니다.
개발 중 (postgresql 사용) :
- sql_dump db_name> tmp / branch1.sql
- 자식 체크 아웃 branch2
- dropdb db_name
- createdb db_name
- psql db_name <tmp / branch2.sql # (이전 분기 스위치에서)
약 50K 레코드가있는 데이터베이스의 레이크 유틸리티보다 훨씬 빠릅니다.
프로덕션의 경우 마스터 분기를 성사로 유지하고 모든 마이그레이션이 체크인되고 shema.rb가 올바르게 병합됩니다. 표준 업그레이드 절차를 수행하십시오.