Как работать с ветвями Git и Rails

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

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

  • Что бы эти "состояния" на самом деле были?

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

  • И что должно произойти слияниями?

  • Будет ли решение переходить на базы данных noSQL?

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


EDIT: Похоже, я забыл упомянуть очень важный момент, меня интересует только среда разработки, но с большими базами данных (размером в несколько ГБ).

Ответ 1

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

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

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

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

Ответ 2

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

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

Ответ 3

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

https://gist.github.com/4076864

Он не решит все проблемы, о которых вы упомянули, но с учетом имени ветки он будет:

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

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

Ответ 4

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

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

Ответ 5

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

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

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

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

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

Ответ 6

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

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

  • sql_dump db_name > tmp/branch1.sql
  • git checkout branch2
  • dropdb db_name
  • createdb db_name
  • psql db_name < tmp/branch2.sql # (из предыдущего переключателя ветки)

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

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

Ответ 7

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

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

Ответ 8

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

Ответ 9

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

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

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

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

  • Я добавил еще одну задачу рейка пространства имен, чтобы создать ветвь и клонировать базу данных одним махом, с 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, ввести новое имя ветки и начать убивать зомби.

Ответ 10

В среде разработки:

Вы должны работать с rake db:migrate:redo, чтобы проверить, являются ли ваши script обратимыми, но имейте в виду, что всегда следует иметь seed.rb с совокупностью данных.

Если вы работаете с git, вы должны изменить change.rb с изменением миграции и выполнением db:migrate:redo для начала (загрузить данные для новой разработки на другой машине или новой базе данных)

Помимо "обмена", с вашими методами вверх и вниз ваш код всегда будет сценарием для "изменения" в этот момент и при запуске с нуля.

Ответ 11

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

Вариант 1

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

Вариант 2

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