Git शाखाओं और रेल माइग्रेशन के साथ कैसे काम करें


131

मैं एक रेल एप पर काम कर रहा हूं जिसमें काफी कुछ शाखाएं हैं और उनमें से कई में डीबी माइग्रेशन शामिल हैं। हम सावधान रहने की कोशिश करते हैं, लेकिन कभी-कभी मास्टर का कुछ टुकड़ा एक कॉलम के लिए पूछता है जो हटा दिया गया / दूसरी शाखा में नाम बदल दिया गया।

  1. DB राज्यों के साथ "युगल" git शाखाओं का एक अच्छा समाधान क्या होगा?

  2. ये "राज्य" वास्तव में क्या होंगे?

    अगर यह आकार में कुछ जीबी है तो हम सिर्फ एक डेटाबेस की नकल नहीं कर सकते।

  3. और मर्ज के साथ क्या होना चाहिए?

  4. समाधान NoSQL डेटाबेस के लिए भी अनुवाद करेंगे?

    वर्तमान में हम MySQL, मोंगोडब और रेडिस का उपयोग करते हैं


संपादित करें: ऐसा लगता है कि मैं एक बहुत महत्वपूर्ण बिंदु का उल्लेख करना भूल गया, मुझे केवल विकास के माहौल में दिलचस्पी है, लेकिन बड़े डेटाबेस (आकार में कुछ जीबी) के साथ।


आप क्या कर रहे हैं कि आपके पास अपनी मास्टर शाखा चलाने वाला एक वातावरण है जिसका डेटाबेस अन्य शाखाओं द्वारा संशोधित किया जा सकता है? मुझे समझ में नहीं आ रहा है कि आपका वर्कफ़्लो क्या है या आपको क्यों लगता है कि आपको विशेष डेटाबेस के साथ शाखाएँ रखने की आवश्यकता है।
जोनाह

3
मान लें कि हमारे पास हमारे डेटाबेस में क्लाइंट्स (नाम, ईमेल, फोन) के साथ एक टेबल है और एक शाखा में हम एक कॉलम को विभाजित करते हैं (नाम -> first_name + last_name)। जब तक हम शाखा को गुरु के साथ विलय नहीं करते, तब तक गुरु और उसके आधार पर अन्य सभी शाखाएं विफल हो जाएंगी।
कोस्टास

जवाबों:


64

जब आप किसी शाखा में एक नया माइग्रेशन जोड़ते हैं, rake db:migrateतो माइग्रेशन और रन दोनों को चलाएं और db/schema.rb

यदि आप ऐसा करते हैं, तो विकास में, आप एक अन्य शाखा में स्विच करने में सक्षम होंगे, जिसमें माइग्रेशन का एक अलग सेट होता है और बस चलता है rake db:schema:load

ध्यान दें कि यह पूरे डेटाबेस को फिर से बनाएगा , और मौजूदा डेटा खो जाएगा

आप शायद केवल एक शाखा के उत्पादन को चलाना चाहते हैं, जिसके बारे में आप बहुत सावधान हैं, इसलिए ये चरण वहाँ लागू नहीं होते हैं (बस rake db:migrateहमेशा की तरह वहाँ चलें )। लेकिन विकास में, स्कीमा से डेटाबेस को फिर से बनाने के लिए कोई बड़ी बात नहीं होनी चाहिए, जो कि क्या rake db:schema:loadकरेगी।


5
मुझे लगता है कि यह केवल स्कीमा समस्या को हल करेगा, डेटा हर डाउन माइग्रेशन के साथ खो जाएगा कभी भी फिर से नहीं देखा जाएगा। क्या किसी प्रकार की db-data-पैच को सहेजना अच्छा होगा जो एक शाखा से बाहर जाने पर बच जाता है और दूसरी शाखा में जाने पर लोड हो जाता है? पैच में केवल वह डेटा होना चाहिए जो नीचे (माइग्रेशन) रास्ते में खो जाए।
कोस्टा

4
यदि आप डेटा लोड करना चाहते हैं, तो इसका उपयोग db/seeds.rb अपने विकास DB को शून्य करने के लिए बहुत विनाशकारी नहीं होना चाहिए यदि आप कुछ उचित बीज डेटा सेट करते हैं।
एंडी लिंडमैन

कुछ भी नहीं की जरूरत है। नीचे मेरा समाधान देखें। बस इस बात से अवगत रहें कि आपके पास कई उदाहरण होंगे और जब आप शाखाओं को स्विच करेंगे, तो डेटा नहीं होगा। यह पूरी तरह से ठीक है अगर आप परीक्षणों के साथ विकसित कर रहे हैं।
एडम डिमिट्रुक

धन्यवाद एंडी, यह जवाब भी मेरा सवाल है। और db/seeds.rbखोए हुए db डेटा को रिपॉप करने के लिए उपयोग करने पर सहमत हैं
पास्टुलो

बड़े जटिल ऐप्स के लिए, जहां आपको स्थानीय रूप से वास्तविक जीवन कीड़े को पुन: पेश करने की आवश्यकता होती है, बीज फ़ाइल का उपयोग करना बिल्कुल असंभव है, आपको उत्पादन (या मंचन) से वास्तविक डेटा की आवश्यकता होती है। और एक डेटाबेस को पुनर्स्थापित करने में काफी समय लग सकता है, इसलिए नहीं यह मेरे मामले का अच्छा समाधान नहीं है।
जोएल_ब्लम

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
यह स्क्रिप्ट ठीक वही करती है जो मैं करना चाहता हूं, मैं इसे एक स्वचालित चेकआउट हुक में देखना पसंद करूंगा।
ब्रिस्गो

1
यह सिर्फ में, मैंने आपके जिस्ट को
brysgo

आपकी स्क्रिप्ट में, क्या वास्तव में आपके कहने का git checkout db/schema.rbमतलब था या आपका मतलब था git checkout -- db/schema.rb? (यानी डबल डैश के साथ)
user664833

1
खैर, हाँ ... मैं उस समय डबल-डैश के बारे में नहीं जानता था। जब तक आपको एक शाखा नहीं मिलती है, तब तक कमांड एक ही काम करेगा db/schema.rb। :)
जॉन लेमन सामन

@ ब्रिस्गो का विकसित 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

अपने डेटाबेस को एक शाखा से दूसरी शाखा में आसानी से क्लोन करने के लिए यहां एक रेक कार्य है। यह एक 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

यह कार्य वर्तमान शाखा (मास्टर, या अन्यथा) से एक गिट शाखा बनाएगा, इसे जांचें और वर्तमान शाखा के डेटाबेस को नई शाखा के डेटाबेस में क्लोन करें। यह एएफ चालाक है।

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 / seeds.rb और विकास के लिए निर्धारित छोटे डेटा का उपयोग कर सकते हैं, तो आपकी समस्या को आसानी से हल किया जा सकता है। मौजूदा शाखा से schema.rb और seeds.rb का उपयोग करके।

यह मानता है कि आपका प्रश्न विकास से संबंधित है; मैं कल्पना नहीं कर सकता कि आपको नियमित रूप से उत्पादन में शाखाओं को बदलने की आवश्यकता क्यों होगी।


मैं इसके बारे में नहीं जानता था db/seeds.rb, मैं इस पर एक नज़र डालूँगा।
कोस्टा

3

मैं उसी मुद्दे से जूझ रहा था। यहाँ मेरा समाधान है:

  1. सुनिश्चित करें कि स्कीमा.आरबी और सभी माइग्रेशन दोनों सभी डेवलपर्स द्वारा जांचे जाते हैं।

  2. उत्पादन के लिए तैनाती के लिए एक व्यक्ति / मशीन होनी चाहिए। इस मशीन को मर्ज-मशीन कहते हैं। जब मर्ज मशीन में परिवर्तन खींच लिया जाता है, तो स्कीमा के लिए ऑटो-मर्ज विफल हो जाएगा। कोई बात नहीं। स्कीमा के लिए पिछली सामग्री जो भी थी, उसके साथ ही सामग्री को बदलें (आप एक कॉपी अलग रख सकते हैं या इसे जीथब से प्राप्त कर सकते हैं यदि आप इसका उपयोग करते हैं ...)।

  3. यहाँ महत्वपूर्ण कदम है। सभी डेवलपर्स से माइग्रेशन अब db / माइग्रेट फ़ोल्डर में उपलब्ध होगा। आगे बढ़ो और बंडल निष्पादित करें रेक डीबी चलाएं: माइग्रेट करें। यह सभी परिवर्तनों के साथ डेटाबेस को मर्ज मशीन पर बराबर लाएगा। यह भी स्कीमा को पुन: उत्पन्न करेगा।

  4. सभी रिपॉजिटरी (रिमोट और व्यक्ति, जो कि रिमोट भी हैं) के परिवर्तनों को कमिट करें और धकेलें। आपको किया जाना चाहिए!


3

मैंने यही किया है और मुझे पूरा यकीन नहीं है कि मैंने सभी आधारों को कवर कर लिया है:

विकास में (postgresql का उपयोग करके):

  • sql_dump db_name> tmp / branch1.sql
  • git चेकआउट ब्रांच २
  • dropdb db_name
  • createb db_name
  • psql db_name <tmp / branch2.sql # (पिछली शाखा स्विच से)

यह लगभग 50K रिकॉर्ड वाले डेटाबेस पर रेक उपयोगिताओं की तुलना में बहुत तेज है।

उत्पादन के लिए, मास्टर शाखा को पवित्र के रूप में बनाए रखें और सभी माइग्रेशन की जाँच की जाए, shema.rb को ठीक से मर्ज किया जाए। अपनी मानक अपग्रेड प्रक्रिया से गुजरें।


छोटे पर्याप्त डेटाबेस साइज़ के लिए और बैकग्राउंड में ऐसा करने पर ब्रांच की जाँच करना बहुत अच्छा समाधान लगता है।
कोस्टा

2

आप प्रति शाखा एक "डीबी वातावरण" संरक्षित करना चाहते हैं। अलग-अलग उदाहरणों को इंगित करने के लिए स्मज / क्लीन स्क्रिप्ट देखें। यदि आप db उदाहरणों से बाहर निकलते हैं, तो स्क्रिप्ट को एक अस्थायी उदाहरण से स्पिन करें, जब आप एक नई शाखा पर जाते हैं, तो यह पहले से ही है और बस स्क्रिप्ट द्वारा इसका नाम बदलने की आवश्यकता है। आपके परीक्षणों को निष्पादित करने से ठीक पहले DB अपडेट चलना चाहिए।

उम्मीद है की यह मदद करेगा।


यह समाधान केवल "अस्थायी" शाखाओं के लिए अच्छा है। उदाहरण के लिए, यदि हमारे पास एक शाखा है "बढ़त" तो क्या हम सभी प्रकार के पागल सामान (शायद अन्य उप-शाखाओं के साथ) का परीक्षण करते हैं और फिर इसे समय-समय पर मास्टर में विलय कर देते हैं, 2 डेटाबेस अलग हो जाएंगे (उनका डेटा नहीं होगा ऐसे ही बनें)।
कोस्टास

यह समाधान सटीक विपरीत के लिए अच्छा है। यह एक बहुत अच्छा समाधान है अगर आप अपने डेटाबेस संस्करण स्क्रिप्ट को संस्करण देते हैं।
एडम डिमिट्रुक

2

मुझे पूरी तरह से आपके यहाँ होने वाले चिता का अनुभव है। जैसा कि मैं इसके बारे में सोचता हूं, असली मुद्दा यह है कि सभी शाखाओं के पास कुछ शाखाओं को रोलबैक करने के लिए कोड नहीं है। मैं django की दुनिया में हूं, इसलिए मुझे अच्छी तरह से पता नहीं है। मैं इस विचार के साथ कर रहा हूं कि माइग्रेशन अपने स्वयं के रेपो में रहते हैं जो ब्रांचेड (गिट-सबमॉड्यूल, जिसे मैंने हाल ही में सीखा है) नहीं मिलता है। इस तरह सभी शाखाओं में सभी माइग्रेशन हैं। चिपचिपा हिस्सा यह सुनिश्चित कर रहा है कि प्रत्येक शाखा केवल उन माइग्रेशनों तक ही सीमित है जिनके बारे में वे परवाह करते हैं। मैन्युअल रूप से उस पर नज़र रखना / करना और त्रुटि के लिए प्रवण होगा। लेकिन इसके लिए कोई भी माइग्रेशन टूल नहीं बनाया गया है। यह वह बिंदु है जिस पर मैं आगे के रास्ते के बिना हूं।


यह एक अच्छा विचार है लेकिन क्या होता है जब एक शाखा एक कॉलम का नाम बदल देती है? बाकी शाखाएं टूटी हुई टेबल को देख रही होंगी।
कोस्टा

उम - वह चिपचिपा हिस्सा है - किस शाखा को कौन से प्रवास की परवाह है। तो आप "सिंक" पर जा सकते हैं और यह जानता है, "इस माइग्रेशन को वापस लाएं" ताकि कॉलम वापस आ जाए।
जॉन

1

मैं दो विकल्पों में से एक का सुझाव दूंगा:

विकल्प 1

  1. अपना डेटा डालें seeds.rb। एक अच्छा विकल्प FactoryGirl / निर्माण मणि के माध्यम से अपने बीज डेटा बनाने के लिए है। इस तरह से आप गारंटी दे सकते हैं कि डेटा कोड के साथ तालमेल में है अगर हम मान लें, कि कारखानों को स्तंभों को जोड़ने / हटाने के साथ एक साथ अपडेट किया गया है।
  2. एक शाखा से दूसरी शाखा में जाने के बाद, rake db:resetडेटाबेस को प्रभावी ढंग से ड्रॉप / क्रिएट / सीड करता है।

विकल्प 2

शाखा चेकआउट के बाद rake db:rollback/ rake db:migrateपहले / बाद में डेटाबेस की स्थिति को मैन्युअल रूप से बनाए रखें । चेतावनी यह है कि आपके सभी प्रवासों को प्रतिवर्ती होने की आवश्यकता है, अन्यथा यह काम नहीं करेगा।


0

विकास के माहौल पर:

rake db:migrate:redoयदि आपकी स्क्रिप्ट प्रतिवर्ती है, तो आपको परीक्षण करने के लिए काम करना चाहिए , लेकिन ध्यान रखें seed.rbकि डेटा आबादी के साथ हमेशा होना चाहिए ।

यदि आप git के साथ काम करते हैं, तो आपको seed.rb को माइग्रेशन परिवर्तन के साथ बदलना चाहिए, और भीख के db:migrate:redoलिए निष्पादन (अन्य मशीन या नए डेटाबेस पर नए विकास के लिए डेटा लोड करना)

Ofchange´ के अलावा, आपके अप और डाउन के तरीकों के साथ आपका कोड हमेशा इस क्षण में "परिवर्तन" के लिए कवर परिदृश्य होता है और जब शून्य से शुरू होता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.