Я работаю над приложением rails с несколькими ветвями git, и многие из них включают миграции db. Мы стараемся быть осторожными, но иногда какой-то фрагмент кода у мастера запрашивает колонку, которая удалена/переименована в другую ветку.
Что было бы хорошим решением для "пары" git ветвей с состояниями БД?
Что бы эти "состояния" на самом деле были?
Мы не можем просто дублировать базу данных, если она имеет несколько ГБ в размере.
И что должно произойти слияниями?
Будет ли решение переходить на базы данных noSQL?
В настоящее время мы используем MySQL, mongodb и redis
EDIT: Похоже, я забыл упомянуть очень важный момент, меня интересует только среда разработки, но с большими базами данных (размером в несколько ГБ).
Когда вы добавляете новую миграцию в любую ветвь, запустите rake db:migrate
и зафиксируйте как перенос , так и db/schema.rb
Если вы это сделаете, в процессе разработки вы сможете переключиться на другую ветвь с другим набором миграций и просто запустите rake db:schema:load
.
Обратите внимание, что это будет воссоздать всю базу данных, а существующие данные будут потеряны.
Вероятно, вы хотите только запустить производство из одной ветки, с которой вы очень осторожны, поэтому эти шаги там не применяются (просто запустите rake db:migrate
, как обычно там). Но в разработке не должно быть большого труда воссоздать базу данных из схемы, что будет делать rake db:schema:load
.
db/seeds.rb
Это не должно быть слишком разрушительным, чтобы уничтожить вашу db/seeds.rb
данных разработки, если вы настроите там разумные начальные данные.
Если у вас есть большая база данных, которую вы не можете легко воспроизвести, я бы рекомендовал использовать обычные средства миграции. Если вы хотите простой процесс, я рекомендую:
rake db:rollback
) до состояния до точки ветвления. Затем, после переключения ветвей, запустите db:migrate
. Это математически корректно, и пока вы пишете скрипты down
, это сработает.rake db:schema:load
и rake db:seed
как сказал @noodl.
Здесь script я написал для переключения между ветвями, которые содержат разные миграции:
https://gist.github.com/4076864
Он не решит все проблемы, о которых вы упомянули, но с учетом имени ветки он будет:
Я всегда вручную делаю это в нашем проекте, поэтому я подумал, что было бы хорошо автоматизировать процесс.
Возможно, вы должны принять это как подсказку о том, что ваша база данных разработки слишком велика? Если вы можете использовать db/seeds.rb и меньший набор данных для разработки, тогда ваша проблема может быть легко решена с помощью schema.rb и seeds.rb из текущей ветки.
Это предполагает, что ваш вопрос связан с развитием; Я не могу себе представить, почему вам нужно регулярно переключаться на производство.
db/seeds.rb
, я посмотрю на это.
Это то, что я сделал, и я не совсем уверен, что покрыл все базы:
В разработке (с использованием postgresql):
Это намного быстрее, чем утилиты rake в базе данных с около 50K записями.
Для производства поддерживайте ведущую ветвь как sacrosanct, и все миграции проверяются, shema.rb должным образом сливается. Пройдите стандартную процедуру обновления.
Я боролся с той же проблемой. Вот мое решение:
Убедитесь, что все schema.rb и все миграции отмечены всеми разработчиками.
Для развертывания должен быть один человек/машина. Позвольте называть этот аппарат как машину слияния. Когда изменения вытягиваются на машину слияния, автоматическое слияние для schema.rb не будет выполнено. Без вопросов. Просто замените содержимое каким-либо предыдущим содержимым для schema.rb(вы можете отложить копию или получить ее из github, если вы ее используете...).
Вот важный шаг. Миграции от всех разработчиков теперь будут доступны в папке db/migrate. Идем дальше и запускаем команду exec rake db: migrate. Это приведет к тому, что база данных на машине слияния сравняется со всеми изменениями. Он также будет регенерировать schema.rb.
Зафиксировать и вывести изменения во все репозитории (пульты и индивидуумы, которые также являются пультами). Вы должны быть готовы!
Это единственный способ летать.
Я вернулся к этому через некоторое время и сделал некоторые улучшения:
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
Здесь задача 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 для текущей ветки (master или иначе), проверит ее и клонирует текущую базу данных ветвей в новую базу данных ветвей. Он имеет пятно AF.
namespace :git do
desc "Create a branch off the current branch and clone the current branch 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
, ввести новое имя ветки и начать убивать зомби.
Я полностью ощущаю лаваш, который у вас здесь. Поскольку я думаю об этом, реальная проблема заключается в том, что у всех ветвей нет кода для отката определенных ветвей. Я в мире джанго, поэтому я не знаю, как это хорошо. Я играю с идеей, что миграции живут в своем собственном репо, который не получает разветвленных (git -подмодулей, о которых я недавно узнал). Таким образом, все ветки имеют все миграции. Липкая часть гарантирует, что каждая ветвь ограничена только теми миграциями, которые им нравятся. Выполнение/отслеживание этого вручную было бы лайтом и подвержено ошибкам. Но для этого не созданы никакие инструменты миграции. Это тот момент, когда я без пути.
Вы хотите сохранить "среду db" для каждой ветки. Посмотрите на smudge/clean script, чтобы указать на разные экземпляры. Если у вас закончились экземпляры db, попробуйте script отменить временный экземпляр, поэтому, когда вы переключаетесь на новую ветку, она уже существует и просто должна быть переименована в script. Обновления БД должны выполняться непосредственно перед выполнением ваших тестов.
Надеюсь, что это поможет.
Я бы предложил один из двух вариантов:
seeds.rb
. Хорошим вариантом является создание ваших данных семян с помощью FactoryGirl/Fabrication gem. Таким образом, вы можете гарантировать, что данные синхронизируются с кодом, если мы предположим, что фабрики обновляются вместе с добавлением/удалением столбцов.rake db:reset
, которая эффективно удаляет/создает/семя базы данных.Вручную поддерживать состояния базы данных, всегда запуская rake db:rollback
/rake db:migrate
до/после проверки ветки. Предостережение заключается в том, что все ваши миграции должны быть обратимыми, иначе это не сработает.
В среде разработки:
Вы должны работать с rake db:migrate:redo
, чтобы проверить, являются ли ваши script обратимыми, но имейте в виду, что всегда следует иметь seed.rb
с совокупностью данных.
Если вы работаете с git, вы должны изменить change.rb с изменением миграции и выполнением db:migrate:redo
для начала (загрузить данные для новой разработки на другой машине или новой базе данных)
Помимо "обмена", с вашими методами вверх и вниз ваш код всегда будет сценарием для "изменения" в этот момент и при запуске с нуля.