Як працювати з гілками Git та міграціями Rails


131

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

  1. Що було б приємним рішенням "з'єднати" гіти git зі станами DB?

  2. Якими були б ці "держави" насправді?

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

  3. А що має відбуватися зі злиттями?

  4. Чи може рішення також перекладатися на бази даних noSQL?

    Зараз ми використовуємо MySQL, mongodb та redis


EDIT: Схоже, я забув згадати дуже важливий момент, мене цікавить лише середовище розробки, але з великими базами даних (розміром декілька ГБ).


Що ви робите, щоб у вас було середовище, де працює ваша головна гілка, базу даних якої можна змінювати іншими гілками? Я не розумію, що таке ваш робочий процес або чому ви вважаєте, що вам потрібно підтримувати гілки в синхронізації з певними базами даних.
Йона

3
Скажімо, у нашій базі даних є таблиця з клієнтами (ім’я, електронна пошта, телефон), а у відділенні ми розділили один із стовпців (ім'я -> ім'я_іменне прізвище). Поки ми не з’єднаємо гілку з майстром, майстер та всі інші гілки, засновані на ній, не зможуть.
Костас

Відповіді:


64

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

Якщо ви це зробите, у процесі розробки ви зможете перейти до іншої гілки, яка має інший набір міграцій та просто запуститись rake db:schema:load.

Зауважте, що це відтворить всю базу даних, а наявні дані будуть втрачені .

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


5
Я думаю, що це вирішить лише проблему схеми, дані втрачаються з кожною міграцією вниз, щоб її більше не побачили. Було б гарною ідеєю зберегти якийсь патч даних-db, який зберігається під час переміщення з гілки та інший, який завантажується при переході в іншу гілку? Патчі повинні містити лише ті дані, які були б втрачені під час руху вниз (міграції).
Костас

4
Якщо ви хочете завантажити дані, використовуйте db/seeds.rb Це не повинно бути занадто руйнівним, щоб запустити ваш DB з розробки, якщо ви налаштували там якісь розумні насінні дані.
Енді Ліндеман

не потрібно нічого пустувати. дивіться моє рішення нижче. Просто пам’ятайте, що у вас буде багато примірників, і коли ви переходите на гілки, даних немає. Це абсолютно добре, якщо ви розробляєте тести.
Адам Дімітрук

Дякую Енді, ця відповідь також і на моє запитання. І домовтеся про використання db/seeds.rbдля рипопуляції втрачених даних про db
pastullo

Для великих складних додатків, де потрібно відтворювати помилки в реальному житті на локальному рівні, використовувати насіннєвий файл абсолютно неможливо, потрібні реальні дані від виробництва (або постановки). А відновлення бази даних може зайняти досить багато часу, тому жодне це не є гарним рішенням для мого випадку.
Joel_Blum

21

Якщо у вас є велика база даних, яку ви не можете легко відтворити, я рекомендую використовувати звичайні інструменти міграції. Якщо ви хочете простий процес, я рекомендую ось що:

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

2
Ви повинні мати на увазі, що не всі міграції є оборотними, але, сказав, перший запропонований крок не гарантується для успіху. Я думаю, що в середовищі розробки гарною ідеєю було б користуватися rake db:schema:loadі rake db:seedяк сказав @noodl.
писарук

@pisaruk Я знаю, що ви відповіли на це шість років тому, але читаючи мені цікаво, яким може бути приклад незворотної міграції. Мені важко уявити ситуацію. Я думаю, найпростішим був би стовпчик, що випав, що містить купу даних, але це може бути "зворотним", щоб мати порожній стовпець або стовпець з деяким значенням за замовчуванням. Чи думали ви про інші випадки?
Люк Гріффітс

1
Я думаю, ти відповів на власне запитання! Так, випав стовпчик - хороший приклад. Або руйнівна міграція даних.
ndp

13

Ось сценарій, який я написав для перемикання між гілками, які містять різні міграції:

https://gist.github.com/4076864

Це не вирішить усі проблеми, про які ви згадали, але, давши назву філії, вона:

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

Мені здається, що ми робимо це вручну весь наш проект, тому я подумав, що було б непогано автоматизувати процес.


1
Цей сценарій робить саме те, що я хочу зробити, я хотів би бачити його, що його вклали в гачок автоматичної каси.
brysgo

1
Цього разу, я відправив вашу суть і зробив це гак після оформлення замовлення: gist.github.com/brysgo/9980344
brysgo

У вашому сценарії ви справді мали намір сказати, git checkout db/schema.rbчи ви мали на увазі git checkout -- db/schema.rb? (тобто з подвійними тире)
user664833,

1
Ну так ... Я тоді не знав про подвійні тире. Але команда працюватиме так само, якщо ви не отримали назву гілки db/schema.rb. :)
Джон Леммон

@ brysgo розвинута команда git_rails ( github.com/brysgo/git-rails ) чудово працює. Дякую тобі Йон :)
Зія Уль Рехман Магхал

7

Окрема база даних для кожної філії

Це єдиний спосіб літати.

Оновлення 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

Це завдання дозволить створити гіт гілки поточної гілки (головного чи іншим чином), перевірити її та клонувати базу даних поточної гілки в базу даних нового відділення. Це гладка 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

Можливо, ви повинні сприймати це як натяк на те, що база даних вашої розробки занадто велика? Якщо ви можете використовувати db / seed.rb та менший набір даних для розробки, то вашу проблему можна легко вирішити, використовуючи schema.rb та seed.rb з поточної гілки.

Це передбачає, що ваше питання стосується розвитку; Я не уявляю, чому вам потрібно регулярно перемикати філії у виробництві.


Я про це не знав db/seeds.rb, я розберуся.
Костас

3

Я боровся з тим же питанням. Ось моє рішення:

  1. Переконайтеся, що і schema.rb, і всі міграції зареєстровані усіма розробниками.

  2. Для розгортання у виробництві повинна бути одна людина / машина. Назвемо цю машину машиною злиття. Коли зміни перетягнуті на машину злиття, автоматичне злиття для schema.rb не вдасться. Немає питань. Просто замініть вміст будь-яким попереднім вмістом для schema.rb (ви можете залишити копію в сторону або отримати її від github, якщо ви її використовуєте ...).

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

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


3

Це я зробив, і я не зовсім впевнений, що я охопив усі основи:

У розробці (використовуючи postgresql):

  • sql_dump db_name> tmp / branch1.sql
  • git checkout відділення2
  • dropdb db_name
  • createdb db_name
  • psql db_name <tmp / branch2.sql # (від попереднього перемикача гілки)

Це набагато швидше, ніж утиліти рейку в базі даних, що містить близько 50 тис. Записів.

Для виробництва підтримуйте головну гілку як сакрасант і всі міграції перевіряються, shema.rb належним чином об'єднується. Пройдіть стандартну процедуру оновлення.


Для досить невеликих розмірів баз даних, і це робити у фоновому режимі під час перевірки філії виглядає як дуже приємне рішення.
Костас

2

Ви хочете зберегти "db середовище" на галузь. Подивіться на сценарій розмазання / очищення, щоб вказати на різні випадки. Якщо у вас не вистачає примірників db, сценарій відкручує тимчасовий екземпляр, тому, коли ви переходите на нову гілку, вона вже є і просто повинна бути перейменована скриптом. Оновлення БД повинні запускатися безпосередньо перед виконанням тестів.

Сподіваюся, це допомагає.


Це рішення добре лише для «тимчасових» гілок. Наприклад, якщо у нас є гілка "край", якщо ми перевіряли всілякі шалені речі (можливо, з іншими підгалузями), а потім періодично об'єднували їх у майстер, 2 бази даних будуть розходитися (їхні дані не будуть бути однаковим).
Костас

Це рішення добре для прямо протилежного. Це дуже хороше рішення, якщо ви версите свій сценарій версії бази даних.
Адам Димітрук

2

Я повністю відчуваю ласунок, який ви маєте тут. Як я думаю про це, справжнє питання полягає в тому, що всі гілки не мають коду для відкату певних гілок. Я в світі джанго, тому не знаю, що граблі так добре. Я граю з думкою, що міграції живуть у власній репо, яка не розгалужується (git-підмодуль, про який я нещодавно дізнався). Таким чином, всі гілки мають усі міграції. Клейка частина гарантує, що кожна гілка обмежується лише міграціями, які їх хвилюють. Виконувати / відстежувати це вручну було б питанням і схильним до помилок. Але жоден інструмент міграції для цього не побудований. Це той момент, коли я не маю шляху вперед.


Це гарна ідея, але що відбувається, коли гілка перейменує стовпець? Решта гілок будуть дивитись на розбитий стіл.
Костас

гм - це клейка частина - яка гілка піклується про які міграції. тож ви можете перейти "синхронізувати", і він знає, "повернути цю міграцію", щоб стовпець повернувся назад.
JohnO

1

Я б запропонував один із двох варіантів:

Варіант 1

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

Варіант 2

Вручну підтримуйте стани бази даних, завжди виконуючи rake db:rollback/ rake db:migrateперед / після виписки відділення. Застереження полягає в тому, що всі ваші міграції повинні бути зворотніми, інакше це не спрацює.


0

Про середовище розробки:

Вам слід попрацювати з rake db:migrate:redoтестуванням того, чи є ваш скрипт зворотним, але пам’ятайте, що завжди має бути seed.rbз набором даних.

Якщо ви працюєте з git, ви seed.rb повинні бути змінені зі зміною міграції та виконанням db:migrate:redo для початку (завантажте дані для нової розробки на іншій машині або новій базі даних)

Окрім „змінити”, за допомогою ваших методів вгору та вниз ваш код завжди буде охоплювати сценарії «зміни» в цей момент і коли починати з нуля.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.