Как работать с Git-ветками и Rails-миграциями - PullRequest
123 голосов
/ 19 января 2011

Я работаю над приложением rails с несколькими ветками git, и многие из них включают в себя миграцию БД.Мы стараемся быть осторожными, но иногда какой-то фрагмент кода в мастере запрашивает столбец, который был удален / переименован в другой ветви.

  1. Что было бы хорошим решением для "пары""git ветвится с состояниями БД?

  2. Какими на самом деле были бы эти" состояния "?

    Мы не можем просто дублироватьбазы данных, если размер составляет несколько ГБ.

  3. А что должно произойти с объединениями?

  4. Будетрешение перевести также на базы данных noSQL?

    В настоящее время мы используем MySQL, mongodb и redis


РЕДАКТИРОВАТЬ: похоже, я забыл упомянутьочень важный момент, меня интересует только среда разработки 1035 *, но с большими базами данных (размером в несколько ГБ).

Ответы [ 11 ]

60 голосов
/ 19 января 2011

Когда вы добавляете новую миграцию в любую ветку, запустите rake db:migrate и подтвердите миграцию и db/schema.rb

Если вы сделаете это, в процессе разработки вы сможете переключиться на другую ветку с другим набором миграций и просто запустить rake db:schema:load.

Обратите внимание, что при этом будет воссоздана вся база данных, а существующие данные будут потеряны .

Возможно, вы захотите запускать производство только из одной ветки, с которой вы очень осторожны, поэтому эти шаги там не применяются (просто запустите rake db:migrate как обычно там). Но в процессе разработки не составит труда воссоздать базу данных из схемы, что и сделает rake db:schema:load.

19 голосов
/ 20 января 2011

Если у вас есть большая база данных, которую вы не можете легко воспроизвести, то я бы рекомендовал использовать обычные инструменты миграции. Если вы хотите простой процесс, вот что я бы порекомендовал:

  • Перед переключением ветвлений выполните откат (rake db:rollback) до состояния перед точкой ветвления. Затем, после переключения веток, запустите db:migrate. Это математически правильно, и пока вы пишете down сценарии, это будет работать.
  • Если вы забудете сделать это перед переключением ветвей, в общем случае вы можете безопасно переключаться назад, откатываться и снова переключаться, поэтому я считаю, что в качестве рабочего процесса это возможно.
  • Если у вас есть зависимости между миграциями в разных ветвях ... ну, вам придется подумать.
13 голосов
/ 15 ноября 2012

Вот скрипт, который я написал для переключения между ветвями, которые содержат разные миграции:

https://gist.github.com/4076864

Это не решит все проблемы, которые вы упомянули, но с учетом названия ветви:

  1. Откатить любые миграции в вашей текущей ветке, которые не существуют в данной ветке
  2. Отменить любые изменения в файле db / schema.rb
  3. Проверить данную ветку
  4. Запускать любые новые миграции, существующие в данной ветке
  5. Обновите тестовую базу данных

Я обнаружил, что постоянно выполняю это вручную в нашем проекте, поэтому я подумал, что было бы неплохо автоматизировать процесс.

5 голосов
/ 17 ноября 2016

Отдельная база данных для каждой ветви

Это единственный способ летать.

Обновление от 16 октября 2017 года

Через некоторое время я вернулся к этому и сделал некоторые улучшения:

  • Я добавил еще одно задание для разгона пространства имен, чтобы создать ветвь и клонировать базу данных одним махом, с bundle exec rake git:branch.
  • Теперь я понимаю, что клонирование из master - это не всегда то, что вы хотите сделать, поэтому я сделал более ясным, что задача 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, ввести имя новой ветки и начать убивать зомби.

4 голосов
/ 20 января 2011

Возможно, вам следует принять это как намек на то, что ваша база данных для разработки слишком велика? Если вы можете использовать db / seed.rb и меньший набор данных для разработки, тогда ваша проблема может быть легко решена с помощью schema.rb и seeds.rb из текущей ветки.

Это предполагает, что ваш вопрос относится к развитию; Я не могу себе представить, почему вам нужно регулярно переключать филиалы на производстве.

3 голосов
/ 20 мая 2013

Это то, что я сделал, и я не совсем уверен, что охватил все основы:

В разработке (с использованием postgresql):

  • sql_dump db_name> tmp / branch1.sql
  • git checkout branch2
  • dropdb db_name
  • createb db_name
  • psql db_name

Это намного быстрее, чем утилиты rake в базе данных с записями около 50K.

Для производства сохраните ветку master как священную, и все миграции будут отмечены, shema.rb правильно объединен. Пройдите стандартную процедуру обновления.

3 голосов
/ 04 февраля 2012

Я боролся с той же проблемой.Вот мое решение:

  1. Убедитесь, что и schema.rb, и все миграции зарегистрированы всеми разработчиками.

  2. Должен быть одинчеловек / машина для развертывания на производство.Давайте назовем эту машину машиной слияния.Когда изменения переносятся на машину слияния, автоматическое слияние для schema.rb завершится неудачно.Без вопросов.Просто замените содержимое тем, что было предыдущим содержимым для schema.rb (вы можете отложить копию или получить ее от github, если вы ее используете ...).

  3. Вотважный шаг.Миграции от всех разработчиков теперь будут доступны в папке db / migrate.Продолжайте и запустите bundle exec rake db: migrate.Это приведет базу данных на машине слияния вровень со всеми изменениями.Это также восстановит schema.rb.

  4. Зафиксируйте и отправьте изменения во все репозитории (удаленные и отдельные пользователи, которые также являются удаленными).Вы должны быть сделаны!

2 голосов
/ 20 января 2011

Я полностью испытываю питу, которую вы здесь имеете. Как я думаю, реальная проблема заключается в том, что все ветви не имеют кода для отката определенных ветвей. Я нахожусь в мире джанго, так что я не очень хорошо знаю рейк. Я согласен с мыслью, что миграции живут в своем собственном репо, которое не разветвляется (git-submodule, о котором я недавно узнал). Таким образом, все ветви имеют все миграции. Важная часть - убедиться, что каждая ветвь ограничена только теми миграциями, которые им нужны. Выполнение / отслеживание этого вручную будет питой и подвержено ошибкам. Но ни один из инструментов миграции не создан для этого. Это тот момент, когда я не могу двигаться вперед.

2 голосов
/ 19 января 2011

Вы хотите сохранить "среду БД" для каждой ветви.Посмотрите на smudge / clean script, чтобы указать на разные экземпляры.Если у вас заканчиваются экземпляры базы данных, сценарий раскручивает временный экземпляр, поэтому при переключении на новую ветвь он уже существует и его просто нужно переименовать сценарием.Обновления БД должны выполняться непосредственно перед выполнением тестов.

Надеюсь, это поможет.

1 голос
/ 17 мая 2017

Я бы предложил один из двух вариантов:

Вариант 1

  1. Поместите ваши данные в seeds.rb. Хорошим вариантом является создание ваших начальных данных с помощью FactoryGirl / Fabrication gem. Таким образом, вы можете гарантировать, что данные синхронизируются с кодом, если предположить, что фабрики обновляются вместе с добавлением / удалением столбцов.
  2. После переключения с одной ветви на другую, запустите rake db:reset, которая эффективно удалит / создаст / заполнит базу данных.

Вариант 2

Вручную поддерживать состояния базы данных, всегда выполняя rake db:rollback / rake db:migrate до / после проверки ветви. Предостережение заключается в том, что все ваши миграции должны быть обратимыми, иначе это не сработает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...