Pracuję nad aplikacją railsową z kilkoma gałęziami git i wiele z nich zawiera migracje db. Staramy się być ostrożni, ale czasami jakiś fragment kodu w module głównym prosi o kolumnę, która została usunięta / zmieniona w innej gałęzi.
Jakie byłoby fajne rozwiązanie „parowania” gałęzi git ze stanami DB?
Czym właściwie byłyby te „stany”?
Nie możemy po prostu powielić bazy danych, jeśli ma ona kilka GB.
A co powinno się stać z połączeniami?
Czy rozwiązanie przełożyłoby się również na bazy danych noSQL?
Obecnie używamy MySQL, mongodb i redis
EDYCJA: Wygląda na to, że zapomniałem wspomnieć o bardzo ważnym punkcie, interesuje mnie tylko środowisko programistyczne, ale z dużymi bazami danych (kilka GB).
ruby-on-rails
database
git
Kostas
źródło
źródło
Odpowiedzi:
Dodając nową migrację w dowolnej gałęzi, uruchom
rake db:migrate
i zatwierdź zarówno migrację, jak idb/schema.rb
Jeśli to zrobisz, w fazie rozwoju będziesz mógł przełączyć się na inną gałąź, która ma inny zestaw migracji i po prostu uruchomić
rake db:schema:load
.Zwróć uwagę, że spowoduje to odtworzenie całej bazy danych, a istniejące dane zostaną utracone .
Prawdopodobnie będziesz chciał uruchomić produkcję tylko z jednej gałęzi, z którą jesteś bardzo ostrożny, więc te kroki nie mają zastosowania tam (po prostu uruchom
rake db:migrate
tam jak zwykle). Jednak w fazie rozwoju odtworzenie bazy danych ze schematu nie powinno być wielkim problemem, co jest tymrake db:schema:load
, co zrobi.źródło
db/seeds.rb
Nie powinno być zbyt niszczycielskie, aby niszczyć twoją deweloperską bazę danych, jeśli ustawisz tam jakieś rozsądne dane początkowe.db/seeds.rb
do ripopulacji utraconych danych dbJeśli masz dużą bazę danych, której nie możesz łatwo odtworzyć, polecam użycie zwykłych narzędzi do migracji. Jeśli chcesz prostego procesu, polecam:
rake db:rollback
) do stanu przed punktem rozgałęzienia. Następnie po zmianie gałęzi biegnijdb:migrate
. Jest to matematycznie poprawne i tak długo, jak piszeszdown
skrypty, będzie działać.źródło
rake db:schema:load
irake db:seed
jak powiedział @noodl.Oto skrypt, który napisałem do przełączania się między gałęziami, które zawierają różne migracje:
https://gist.github.com/4076864
Nie rozwiąże wszystkich problemów, o których wspomniałeś, ale biorąc pod uwagę nazwę gałęzi, będzie:
Często robię to ręcznie w naszym projekcie, więc pomyślałem, że fajnie byłoby zautomatyzować ten proces.
źródło
git checkout db/schema.rb
czy miałeś na myśligit checkout -- db/schema.rb
? (tj. z podwójnymi myślnikami)db/schema.rb
. :)Oddzielna baza danych dla każdego oddziału
To jedyny sposób na latanie.
Aktualizacja z 16 października 2017 r
Po jakimś czasie wróciłem do tego i wprowadziłem kilka poprawek:
bundle exec rake git:branch
.db:clone_from_branch
zadanie trwaSOURCE_BRANCH
i jestTARGET_BRANCH
zmienną środowiskową. Podczas korzystania zgit:branch
niego automatycznie użyje bieżącej gałęzi jako plikuSOURCE_BRANCH
.config/database.yml
Aby ci to ułatwić, oto jak aktualizujesz
database.yml
plik, aby dynamicznie określać nazwę bazy danych na podstawie bieżącej gałęzi.<% 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
Oto zadanie Rake, aby łatwo sklonować bazę danych z jednej gałęzi do drugiej. To wymaga a
SOURCE_BRANCH
iTARGET_BRANCH
zmiennych środowiskowych. Na podstawie zadania @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
To zadanie spowoduje utworzenie gałęzi git z bieżącej gałęzi (głównej lub innej), sprawdzenie jej i sklonowanie bazy danych bieżącej gałęzi do bazy danych nowej gałęzi. To zręczny 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
Teraz wszystko, co musisz zrobić, to uruchomić
bundle exec git:branch
, wpisać nazwę nowej gałęzi i zacząć zabijać zombie.źródło
Może powinieneś potraktować to jako wskazówkę, że twoja programistyczna baza danych jest zbyt duża? Jeśli możesz użyć bazy danych db / seeds.rb i mniejszego zestawu danych do programowania, wówczas problem można łatwo rozwiązać za pomocą schematów schema.rb i seeds.rb z bieżącej gałęzi.
To zakłada, że twoje pytanie dotyczy rozwoju; Nie mogę sobie wyobrazić, dlaczego musiałbyś regularnie zmieniać gałęzie w produkcji.
źródło
db/seeds.rb
, przyjrzę się temu.Zmagałem się z tym samym problemem. Oto moje rozwiązanie:
Upewnij się, że zarówno plik schema.rb, jak i wszystkie migracje są wpisywane przez wszystkich programistów.
Powinna istnieć jedna osoba / maszyna do wdrożeń do produkcji. Nazwijmy tę maszynę maszyną scalającą. Po ściągnięciu zmian do maszyny scalającej automatyczne scalanie pliku schema.rb nie powiedzie się. Nie ma problemów. Po prostu zastąp zawartość tym, czym była poprzednia zawartość schema.rb (możesz odłożyć kopię na bok lub pobrać ją z github, jeśli jej używasz ...).
Oto ważny krok. Migracje od wszystkich programistów będą teraz dostępne w folderze db / migrate. Śmiało i uruchom pakiet exec rake db: migrate. Spowoduje to, że baza danych na maszynie scalającej będzie na równi ze wszystkimi zmianami. Spowoduje również zregenerowanie pliku schema.rb.
Zatwierdź i wypuść zmiany do wszystkich repozytoriów (pilotów i osób, które również są pilotami). Powinno być gotowe!
źródło
Oto, co zrobiłem i nie jestem do końca pewien, czy omówiłem wszystkie podstawy:
W opracowaniu (przy użyciu postgresql):
Jest to o wiele szybsze niż narzędzia rake w bazie danych zawierającej około 50 000 rekordów.
Na potrzeby produkcji utrzymuj gałąź główną jako świętą, a wszystkie migracje są rejestrowane, a shema.rb prawidłowo scalony. Przejdź przez standardową procedurę aktualizacji.
źródło
Chcesz zachować „środowisko db” dla każdej gałęzi. Spójrz na rozmazany / czysty skrypt, aby wskazać różne wystąpienia. Jeśli zabraknie instancji bazy danych, poproś skrypt o wyodrębnienie instancji tymczasowej, aby po przełączeniu się do nowej gałęzi już ona tam była i wystarczy zmienić jej nazwę przez skrypt. Aktualizacje bazy danych powinny być uruchamiane tuż przed wykonaniem testów.
Mam nadzieję że to pomoże.
źródło
Całkowicie doświadczam pity, którą tu masz. Kiedy o tym myślę, prawdziwym problemem jest to, że wszystkie gałęzie nie mają kodu do wycofania niektórych gałęzi. Jestem w świecie django, więc nie znam dobrze rake'u. Bawię się pomysłem, że migracje żyją we własnym repozytorium, które nie jest rozgałęzione (git-submodule, o którym niedawno się dowiedziałem). W ten sposób wszystkie gałęzie mają wszystkie migracje. Lepką częścią jest upewnienie się, że każda gałąź jest ograniczona tylko do migracji, na których im zależy. Wykonywanie / śledzenie tego ręcznie byłoby pita i podatne na błędy. Ale żadne z narzędzi do migracji nie jest do tego stworzone. To jest punkt, w którym nie mam wyjścia.
źródło
Proponuję jedną z dwóch opcji:
opcja 1
seeds.rb
. Fajną opcją jest utworzenie danych nasion za pośrednictwem klejnotu FactoryGirl / Fabrication. W ten sposób możesz zagwarantować, że dane są zsynchronizowane z kodem, jeśli założymy, że fabryki są aktualizowane wraz z dodawaniem / usuwaniem kolumn.rake db:reset
, który efektywnie upuszcza / tworzy / zasysa bazę danych.Opcja 2
Ręcznie utrzymuj stany bazy danych, zawsze uruchamiając
rake db:rollback
/rake db:migrate
przed / po sprawdzeniu oddziału. Zastrzeżenie jest takie, że wszystkie migracje muszą być odwracalne, w przeciwnym razie to nie zadziała.źródło
W środowisku programistycznym:
Powinieneś popracować,
rake db:migrate:redo
aby sprawdzić, czy twój skrypt jest odwracalny, ale pamiętaj, że zawsze powinieneś miećseed.rb
z populacją danych.Jeśli pracujesz z git, seed.rb powinien zostać zmieniony wraz ze zmianą migracji i wykonaniem
db:migrate:redo
na początek (załaduj dane do nowego rozwoju na innym komputerze lub nowej bazie danych)Oprócz „zmiany”, z twoimi metodami w górę iw dół, twój kod zawsze będzie obejmował scenariusze „zmiany” w tym momencie i gdy zaczniesz od zera.
źródło