Git dalları ve Rails geçişleriyle nasıl çalışılır


131

Birkaç git dalı olan bir ray uygulaması üzerinde çalışıyorum ve bunların çoğu db geçişleri içeriyor. Dikkatli olmaya çalışıyoruz, ancak bazen master'daki bir kod parçası başka bir dalda kaldırılan / yeniden adlandırılan bir sütun ister.

  1. Git şubelerini DB devletleriyle "birleştirmek" için güzel bir çözüm ne olabilir?

  2. Bu "durumlar" aslında ne olurdu?

    Birkaç GB boyutundaysa bir veritabanını kopyalayamayız.

  3. Ve birleşmelerde ne olmalı?

  4. Çözüm noSQL veritabanlarına da çevrilebilir mi?

    Şu anda MySQL, mongodb ve redis kullanıyoruz


DÜZENLEME: Görünüşe göre çok önemli bir noktadan bahsetmeyi unutmuşum, sadece geliştirme ortamıyla ilgileniyorum ama büyük veri tabanlarıyla (birkaç GB boyutunda).


Veritabanı diğer şubeler tarafından değiştirilebilen ana şubenizi çalıştıran bir ortama sahip olduğunuz için ne yapıyorsunuz? İş akışınızın ne olduğunu veya şubeleri belirli veritabanları ile senkronize tutmanızın neden gerekli olduğunu düşündüğünüzü anlamıyorum.
Jonah

3
Veritabanımızda müşterilerle (ad, e-posta, telefon) bir tablomuz olduğunu ve bir şubede sütunlardan birini (ad -> ad_ad + soyad) böldüğümüzü varsayalım. Şubeyi master ile birleştirene kadar, master, master ve ona bağlı diğer tüm şubeler başarısız olacaktır.
Kostas

Yanıtlar:


64

Eğer herhangi bir dalı vadede yeni bir göç eklediğinizde rake db:migrateve hem göç işlemek ve db/schema.rb

Bunu geliştirme aşamasında yaparsanız, farklı bir geçiş kümesine sahip başka bir dala geçebilir ve basitçe çalıştırabilirsiniz rake db:schema:load.

Bunun tüm veritabanını yeniden oluşturacağını ve mevcut verilerin kaybolacağını unutmayın .

Muhtemelen çok dikkatli olduğunuz tek bir şubeden üretim yapmak isteyeceksiniz, bu nedenle bu adımlar orada geçerli değildir (sadece rake db:migrateorada her zamanki gibi çalıştırın ). Ancak geliştirme aşamasında, veritabanını şemadan yeniden oluşturmak büyük bir sorun olmamalı, ki rake db:schema:loadyapacak olan budur .


5
Bunun sadece şema problemini çözeceğini düşünüyorum, veriler bir daha görülmeyecek her aşağı geçişte kaybolacak. Bir daldan çıkarken kaydedilen ve başka bir dala taşınırken yüklenen başka bir db veri yaması kaydetmek iyi bir fikir olur mu? Yamalar, yalnızca aşağı inerken kaybolacak verileri (geçişler) içermelidir.
Kostas

4
Veri yüklemek istiyorsanız, db/seeds.rb orada bazı makul tohum verileri ayarlarsanız geliştirme DB'nizi sıfırlamak çok yıkıcı olmamalıdır.
Andy Lindeman

hiçbir şeyi bombalamaya gerek yok. aşağıdaki çözümüme bakın. Sadece birçok örneğinizin olacağını ve dalları değiştirdiğinizde verilerin orada olmayacağını unutmayın. Testlerle geliştiriyorsanız bu tamamen iyidir.
Adam Dymitruk

Teşekkür ederim Andy, bu cevap da benim sorum. Ve db/seeds.rbkayıp veri tabanını kopyalamak için kullanmayı kabul edin
pastullo

Gerçek hayattaki hataları yerel olarak yeniden üretmeniz gereken büyük karmaşık uygulamalar için, bir tohum dosyası kullanmak kesinlikle imkansızdır, üretimden (veya aşamalandırmadan) gerçek verilere ihtiyacınız vardır. Ve bir veritabanını geri yüklemek oldukça uzun sürebilir, bu yüzden hayır bu benim durumum için iyi bir çözüm değil.
Joel_Blum

21

Kolayca yeniden üretemeyeceğiniz büyük bir veritabanınız varsa, normal taşıma araçlarını kullanmanızı öneririm. Basit bir işlem istiyorsanız, bunu tavsiye ederim:

  • Dalları değiştirmeden rake db:rollbackönce, dallanma noktasından önceki duruma geri alın ( ). Ardından, dalları değiştirdikten sonra çalıştırın db:migrate. Bu matematiksel olarak doğrudur ve downsenaryo yazdığınız sürece çalışacaktır.
  • Dalları değiştirmeden önce bunu yapmayı unutursanız, genel olarak güvenli bir şekilde geri dönebilir, geri alabilir ve tekrar geçiş yapabilirsiniz, bu yüzden bir iş akışı olarak düşünüyorum, bu uygulanabilir.
  • Farklı dallardaki göçler arasında bağımlılıklarınız varsa ... iyi, çok düşünmeniz gerekecek.

2
Tüm geçişlerin geri döndürülemeyeceğini aklınızda bulundurmalısınız, bununla birlikte önerilen ilk adımın başarılı olacağının garantisi yoktur. Ben geliştirme ortamı en iyi bir fikir kullanmak olacağını düşünüyorum rake db:schema:loadve rake db:seed@noodl dediği gibi.
pisaruk

@pisaruk Bunu altı yıl önce yanıtladığınızı biliyorum, ancak okurken tersine çevrilemez bir göç örneğinin ne olacağını merak ediyorum. Bir durumu hayal etmekte zorlanıyorum. Sanırım en basit olanı, bir grup veri içeren bırakılmış bir sütun olurdu, ancak bu, boş bir sütuna veya bazı varsayılan değerlere sahip bir sütuna sahip olmak için "tersine çevrilebilir". Başka davalar mı düşünüyordun?
Luke Griffiths

1
Sanırım Kendi Sorunu Kendin Cevapladın! Evet, bırakılmış bir sütun iyi bir örnektir. Veya yıkıcı bir veri geçişi.
ndp

13

İşte farklı geçişler içeren dallar arasında geçiş yapmak için yazdığım bir komut dosyası:

https://gist.github.com/4076864

Bahsettiğiniz tüm sorunları çözmeyecek, ancak bir şube adı verildiğinde:

  1. Mevcut şubenizdeki, belirtilen şubede bulunmayan tüm geçişleri geri alın
  2. Db / schema.rb dosyasındaki tüm değişiklikleri atın
  3. Verilen şubeye göz atın
  4. Belirtilen dalda mevcut olan tüm yeni geçişleri çalıştırın
  5. Test veritabanınızı güncelleyin

Kendimi projemizde her zaman manuel olarak yaparken buluyorum, bu yüzden süreci otomatikleştirmenin güzel olacağını düşündüm.


1
Bu komut dosyası tam olarak yapmak istediğimi yapıyor, otomatik bir ödeme kancasına yerleştirildiğini görmek isterim.
brysgo

1
Bu kısa süre önce, özetinizi aldım ve
brysgo

Senaryonuzda gerçekten söylemek git checkout db/schema.rbmi istediniz yoksa bunu mu demek istediniz git checkout -- db/schema.rb? (yani çift çizgilerle)
user664833

1
Şey evet ... O zamanlar çift çizgi hakkında bir şey bilmiyordum. Ancak, çağrılan bir şubeniz yoksa komut aynı şekilde çalışacaktır db/schema.rb. :)
Jon Lemmon

@ brysgo'nun gelişmiş git_rails komutu ( github.com/brysgo/git-rails ) harika çalışıyor. Teşekkürler Jon :)
Zia Ul Rehman Mughal

7

Her Şube için Ayrı Veritabanı

Uçmanın tek yolu bu.

Güncelleme 16 Ekim 2017

Bir süre sonra buna geri döndüm ve bazı iyileştirmeler yaptım:

  • Bir dal oluşturmak ve veritabanını tek seferde klonlamak için başka bir ad alanı komisyon görevi ekledim bundle exec rake git:branch.
  • Şimdi, ustadan klonlamanın her zaman yapmak istediğiniz şey olmadığını anlıyorum, bu yüzden db:clone_from_branchgörevin bir SOURCE_BRANCHve bir TARGET_BRANCHortam değişkeni almasını daha açık hale getirdim . Kullanırken git:branchotomatik olarak geçerli dalı SOURCE_BRANCH.
  • Yeniden düzenleme ve basitleştirme.

config/database.yml

Ve işinizi kolaylaştırmak database.ymliçin, mevcut dala göre veritabanı adını dinamik olarak belirlemek için dosyanızı nasıl güncelleyeceğiniz aşağıda açıklanmıştır .

<% 
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

Veritabanınızı bir şubeden diğerine kolayca klonlamak için bir Rake görevi. Bu a SOURCE_BRANCHve bir TARGET_BRANCHortam değişkenlerini alır. Kapalı göre @spalladino 'ın görevi.

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

Bu görev, geçerli şubeden (ana veya başka türlü) bir git dalı oluşturacak, teslim alacak ve mevcut şubenin veritabanını yeni şubenin veritabanına klonlayacaktır. Bu kaygan 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

Şimdi tek yapmanız gereken koşmak bundle exec git:branch, yeni şube adını girmek ve zombileri öldürmeye başlamak.


4

Belki de bunu geliştirme veritabanınızın çok büyük olduğuna dair bir ipucu olarak almalısınız? Geliştirme için db / seeds.rb ve daha küçük bir veri kümesini kullanabilirseniz, o zaman sorununuz mevcut daldan schema.rb ve seeds.rb kullanılarak kolayca çözülebilir.

Bu, sorunuzun geliştirmeyle ilgili olduğunu varsayar; Üretimde neden düzenli olarak şubeleri değiştirmeniz gerektiğini hayal edemiyorum.


Bilmiyordum db/seeds.rb, içine bir göz atacağım.
Kostas

3

Ben de aynı sorunla mücadele ediyordum. İşte benim çözümüm:

  1. Hem schema.rb hem de tüm geçişlerin tüm geliştiriciler tarafından kontrol edildiğinden emin olun.

  2. Üretime dağıtım için bir kişi / makine olmalıdır. Bu makineye birleştirme makinesi diyelim. Değişiklikler birleştirme makinesine çekildiğinde, schema.rb için otomatik birleştirme başarısız olur. Sorun yok. İçeriği schema.rb'nin önceki içeriğiyle değiştirin (bir kopyasını bir kenara koyabilir veya kullanırsanız github'dan alabilirsiniz ...).

  3. İşte önemli adım. Tüm geliştiricilerin taşıma işlemleri artık db / migrate klasöründe mevcut olacak. Devam edin ve bundle exec rake db: migrate komutunu çalıştırın. Birleştirme makinesindeki veritabanını tüm değişikliklerle eşit hale getirecektir. Ayrıca schema.rb'yi yeniden oluşturacaktır.

  4. Değişiklikleri tüm depolara işleyin ve itin (uzaktan kumandalar ve uzaktan kumandalar da kişiler). Bitirmelisin!


3

Yaptığım şey bu ve tüm temelleri kapladığımdan pek emin değilim:

Geliştirme aşamasında (postgresql kullanarak):

  • sql_dump db_name> tmp / branch1.sql
  • git ödeme şube2
  • dropdb db_name
  • oluşturulanb db_name
  • psql db_name <tmp / branch2.sql # (önceki şube anahtarından)

Bu, yaklaşık 50 bin kayıt içeren bir veritabanındaki komisyon araçlarından çok daha hızlıdır.

Üretim için, ana dalı sakrosanct olarak koruyun ve tüm geçişler kontrol edilir, shema.rb uygun şekilde birleştirilir. Standart yükseltme prosedürünüzü uygulayın.


Yeterince küçük veritabanı boyutları için ve bir dalı kontrol ederken bunun arka planda yapılması çok güzel bir çözüm gibi görünüyor.
Kostas

2

Dal başına bir "db ortamı" korumak istiyorsunuz. Farklı örnekleri işaret etmek için leke / temiz komut dosyasına bakın. Eğer db örnekleriniz biterse, betiğin geçici bir örneği döndürmesini sağlayın, böylece yeni bir dala geçtiğinizde, zaten oradadır ve sadece komut dosyası tarafından yeniden adlandırılması gerekir. DB güncellemeleri, testlerinizi yürütmeden hemen önce çalışmalıdır.

Bu yardımcı olur umarım.


Bu çözüm yalnızca "geçici" dallar için iyidir. Örneğin, bir dal "uç" a sahipsek, her tür çılgın şeyi (muhtemelen diğer alt dallarla) test edip, zaman zaman ana ile birleştirdiğimizde, 2 veritabanı birbirinden uzaklaşacaktır (verileri aynı Ol).
Kostas

Bu çözüm tam tersi için iyidir. Veritabanı sürüm komut dosyanızı sürümlerseniz bu çok iyi bir çözümdür.
Adam Dymitruk

2

Burada yediğin pideyi tamamen tecrübe ediyorum. Düşündüğüm kadarıyla asıl sorun, tüm şubelerin belirli dalları geri almak için koda sahip olmamasıdır. Ben django dünyasındayım, bu yüzden komisyonu o kadar iyi bilmiyorum. Göçlerin dallanmayan kendi repolarında yaşadığı fikri ile oynuyorum (yakın zamanda öğrendiğim git-submodule). Bu şekilde tüm şubeler tüm göçlere sahip olur. Yapışkan kısım, her bir dalın yalnızca ilgilendikleri geçişlerle sınırlı olmasını sağlıyor. Bunu elle yapmak / takip etmek bir pide olur ve hataya meyillidir. Ancak geçiş araçlarının hiçbiri bunun için tasarlanmadı. İleriye gidemediğim nokta budur.


Bu güzel bir fikir ama bir dal bir sütunu yeniden adlandırdığında ne olur? Dalların geri kalanı kırık bir masaya bakıyor olacak.
Kostas

um - bu yapışkan kısım - hangi dal hangi göçlerle ilgileniyor. böylece "senkronizasyona" gidebilirsiniz ve "bu geçişi geri al" bilir, böylece sütun geri döner.
JohnO

1

İki seçenekten birini öneririm:

seçenek 1

  1. Verilerinizi girin seeds.rb. İyi bir seçenek, tohum verilerinizi FactoryGirl / Fabrication gem ile oluşturmaktır. Bu şekilde, fabrikaların sütunların eklenmesi / kaldırılmasıyla birlikte güncellendiğini varsayarsak verilerin kodla senkronize olduğunu garanti edebilirsiniz.
  2. Bir daldan diğerine geçtikten sonra rake db:reset, veritabanını etkin bir şekilde düşüren / oluşturan / tohumlayan çalıştırın .

seçenek 2

El ile sürekli çalışarak veritabanının durumlarını korumak rake db:rollback/ rake db:migrateşube kasada önce / sonra. Uyarı, tüm geçişlerinizin tersine çevrilebilir olması gerektiğidir, aksi takdirde bu işe yaramaz.


0

Geliştirme ortamında:

rake db:migrate:redoBetiğinizin tersine çevrilebilir olup olmadığını test etmek için birlikte çalışmalısınız , ancak her zaman seed.rbveri popülasyonunda olması gerektiğini unutmayın .

Git ile çalışıyorsanız, seed.rb bir geçiş değişikliği ile değiştirilmeli ve db:migrate:redobaşlangıç ​​için yürütülmelidir ( yeni bir geliştirme için verileri başka bir makineye veya yeni veritabanına yükleyin)

"Değişim" dışında, sizinki yukarı ve aşağı yöntemleriyle kodunuz her zaman bu andaki ve sıfırdan başlayan "değişim" için kapak senaryoları olur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.