एक डीवीसीएस में मर्जिंग बेहतर क्यों है, इसका दावा सबवर्सन में काफी हद तक इस बात पर आधारित था कि कुछ समय पहले सबवर्सन में ब्रांचिंग और मर्ज कैसे काम करता था। 1.5.0 से पहले की तोड़फोड़ ने किसी भी जानकारी को संग्रहीत नहीं किया था कि कब शाखाओं का विलय किया गया था, इस प्रकार जब आप विलय करना चाहते थे, तो आपको यह निर्दिष्ट करना था कि किस संशोधन को विलय करना था।
तो क्यों तोड़फोड़ मलबे चूसना था ?
इस उदाहरण को रखें:
1 2 4 6 8
trunk o-->o-->o---->o---->o
\
\ 3 5 7
b1 +->o---->o---->o
जब हम b1 के बदलाव को ट्रंक में मर्ज करना चाहते हैं, तो हम निम्नलिखित कमांड जारी करेंगे, जबकि ट्रंक की जाँच करने वाले फ़ोल्डर पर खड़े हैं:
svn merge -r 2:7 {link to branch b1}
… जो b1
आपके स्थानीय कार्यशील निर्देशिका से परिवर्तनों को मर्ज करने का प्रयास करेगा । और फिर आप किसी भी संघर्ष को हल करने और परिणाम का परीक्षण करने के बाद परिवर्तन करते हैं। जब आप संशोधन करते हैं तो वृक्ष इस तरह दिखेगा:
1 2 4 6 8 9
trunk o-->o-->o---->o---->o-->o "the merge commit is at r9"
\
\ 3 5 7
b1 +->o---->o---->o
हालांकि, संशोधन की श्रेणियों को निर्दिष्ट करने का यह तरीका हाथ से जल्दी निकल जाता है जब संस्करण ट्री बढ़ता है क्योंकि तोड़फोड़ का कोई मेटा डेटा नहीं था कि कब और क्या संशोधन एक साथ विलय हो गए। बाद में क्या होता है इस पर विचार:
12 14
trunk …-->o-------->o
"Okay, so when did we merge last time?"
13 15
b1 …----->o-------->o
यह काफी हद तक रिपॉजिटरी डिज़ाइन का एक मुद्दा है जो कि सबवर्सन के पास एक शाखा बनाने के लिए आपको एक नई वर्चुअल निर्देशिका बनाने की आवश्यकता है रिपॉजिटरी में है, जो ट्रंक की एक कॉपी तैयार करेगी लेकिन यह कब और क्या के बारे में कोई जानकारी संग्रहीत नहीं करती है चीजों को वापस विलय कर दिया गया। इससे कई बार बुरा विलय हो जाएगा। इससे भी बुरी बात यह थी कि तोड़फोड़ ने डिफ़ॉल्ट रूप से दो तरफा विलय का इस्तेमाल किया, जिसमें दो शाखा प्रमुखों की तुलना उनके सामान्य पूर्वजों के साथ नहीं होने पर स्वचालित विलय में कुछ भद्दी सीमाएँ हैं।
इस तोड़फोड़ को कम करने के लिए अब शाखा और विलय के लिए मेटा डेटा संग्रहीत करता है। यह सभी समस्याओं को हल करेगा?
और ओह, वैसे, तोड़फोड़ अभी भी बेकार है ...
एक केंद्रीकृत प्रणाली पर, तोड़फोड़ की तरह, आभासी निर्देशिका चूसना। क्यों? क्योंकि हर कोई उन्हें देखने के लिए उपयोग किया है ... यहां तक कि कचरा प्रयोगात्मक हैं। अगर आप प्रयोग करना चाहते हैं तो ब्रांचिंग अच्छा है लेकिन आप हर किसी को और उनके चाची प्रयोग को नहीं देखना चाहते हैं । यह गंभीर संज्ञानात्मक शोर है। आप जितनी अधिक शाखाएँ जोड़ेंगे, आपको उतना अधिक बकवास देखने को मिलेगा।
जितनी अधिक सार्वजनिक शाखाएं होंगी, सभी विभिन्न शाखाओं का ध्यान रखना उतना ही कठिन होगा। तो सवाल आपके पास होगा कि क्या शाखा अभी भी विकास में है या यदि यह वास्तव में मर चुका है जो किसी भी केंद्रीकृत संस्करण नियंत्रण प्रणाली में बताना मुश्किल है।
ज्यादातर समय, मैंने जो देखा है, उससे एक संगठन वैसे भी एक बड़ी शाखा का उपयोग करने के लिए डिफ़ॉल्ट होगा। जो एक शर्म की बात है क्योंकि बदले में परीक्षण और रिलीज संस्करणों का ट्रैक रखना मुश्किल होगा, और जो कुछ भी अच्छा है वह ब्रांचिंग से आता है।
तो DVCS, जैसे Git, Mercurial और Bazaar, ब्रांचिंग और मर्जिंग में सबवर्सन से बेहतर क्यों हैं?
एक बहुत ही सरल कारण है: ब्रांचिंग एक प्रथम श्रेणी की अवधारणा है । हैं कोई वर्चुअल निर्देशिका डिजाइन और शाखाओं द्वारा DVCS में कठोर वस्तुओं जो यह बस खजाने के तुल्यकालन (यानी के साथ काम करने के लिए इस तरह के होने की जरूरत है कर रहे हैं धक्का और पुल )।
जब आप DVCS के साथ काम करते हैं तो पहली चीज रिपॉजिटरी (git's clone
, hg's clone
और bzr's branch
) को क्लोन करना है । संस्करण नियंत्रण में एक शाखा बनाने के रूप में क्लोनिंग वैचारिक रूप से एक ही बात है। कुछ लोग इसे फोर्किंग या ब्रांचिंग कहते हैं (हालांकि बाद का उपयोग अक्सर सह-स्थित शाखाओं को संदर्भित करने के लिए भी किया जाता है), लेकिन यह केवल एक ही बात है। प्रत्येक उपयोगकर्ता अपना स्वयं का भंडार चलाता है जिसका अर्थ है कि आपके पास प्रति उपयोगकर्ता शाखा चल रही है।
संस्करण संरचना एक पेड़ नहीं है , बल्कि इसके बजाय एक ग्राफ है । अधिक विशेष रूप से एक निर्देशित चक्रीय ग्राफ (DAG, जिसका अर्थ है एक ग्राफ जिसमें कोई चक्र नहीं है)। आपको वास्तव में एक डीएजी की बारीकियों में ध्यान केंद्रित करने की आवश्यकता नहीं है, क्योंकि प्रत्येक कमिट में एक या एक से अधिक माता-पिता के संदर्भ हैं (जो कि प्रतिबद्ध था)। तो निम्नलिखित रेखांकन इस वजह से उलट फेरों के बीच के तीरों को दिखाएगा।
विलय का एक बहुत ही सरल उदाहरण यह होगा; कहा जाता है origin
और एक उपयोगकर्ता, ऐलिस, एक केंद्रीय रिपॉजिटरी की कल्पना करें, रिपॉजिटरी को उसकी मशीन पर क्लोन कर रहा है।
a… b… c…
origin o<---o<---o
^master
|
| clone
v
a… b… c…
alice o<---o<---o
^master
^origin/master
एक क्लोन के दौरान क्या होता है कि हर संशोधन को ऐलिस के साथ कॉपी किया जाता है, जैसा कि वे थे (जो कि विशिष्ट रूप से पहचानने योग्य हैश-आईडी द्वारा मान्य है), और निशान जहां मूल की शाखाएं हैं।
इसके बाद ऐलिस अपने रेपो पर काम करती है, अपने ही भंडार में काम करती है और अपने बदलावों को आगे बढ़ाने का फैसला करती है:
a… b… c…
origin o<---o<---o
^ master
"what'll happen after a push?"
a… b… c… d… e…
alice o<---o<---o<---o<---o
^master
^origin/master
समाधान बल्कि सरल है, केवल एक चीज जो origin
रिपॉजिटरी को करने की ज़रूरत है, वह है सभी नए संशोधनों को लेने और इसे नए संशोधन में शाखा में स्थानांतरित करने के लिए (जिसे गिट "फास्ट-फॉरवर्ड" कहते हैं):
a… b… c… d… e…
origin o<---o<---o<---o<---o
^ master
a… b… c… d… e…
alice o<---o<---o<---o<---o
^master
^origin/master
उपयोग मामला, जिसे मैंने ऊपर चित्रित किया था, को कुछ भी विलय करने की आवश्यकता नहीं है । इसलिए समस्या वास्तव में विलय एल्गोरिदम के साथ नहीं है क्योंकि तीन-तरफा मर्ज एल्गोरिदम सभी संस्करण नियंत्रण प्रणालियों के बीच बहुत समान है। मुद्दा संरचना से अधिक कुछ भी नहीं है ।
तो कैसे आप के बारे में मुझे एक उदाहरण दिखाते हैं जिसमें एक वास्तविक मर्ज है?
निस्संदेह उपरोक्त उदाहरण एक बहुत ही सरल उपयोग मामला है, इसलिए एक अधिक आम एक के साथ बहुत अधिक मुड़ जाने देता है। याद है कि origin
तीन संशोधनों के साथ शुरू हुआ? ठीक है, जो लड़का उन्हें करता है, उसे बॉब कहते हैं , वह अपने दम पर काम कर रहा है और अपने स्वयं के भंडार पर एक प्रतिबद्ध बना है:
a… b… c… f…
bob o<---o<---o<---o
^ master
^ origin/master
"can Bob push his changes?"
a… b… c… d… e…
origin o<---o<---o<---o<---o
^ master
अब बॉब origin
रिपॉजिटरी में सीधे अपने बदलावों को आगे नहीं बढ़ा सकता । अगर सिस्टम यह जाँचता है कि बॉब के संशोधन सीधे तौर पर उतरते हैं origin
, जो इस मामले में नहीं आता है, तो यह पता लगाता है । पुश करने के किसी भी प्रयास के परिणामस्वरूप सिस्टम में कुछ उकसाया जाएगा " उह ... मुझे डर है कि आप उसे बॉब नहीं कर सकते ।"
(Git के साथ तो बॉब पुल में करने के लिए और फिर परिवर्तन मर्ज है pull
, या एचजी के pull
और merge
, या BzR के merge
)। यह दो-चरणीय प्रक्रिया है। पहले बॉब को नए संशोधन लाने होंगे, जो उनकी नकल करेंगे क्योंकि वे origin
भंडार से हैं। अब हम यह देख सकते हैं कि ग्राफ में परिवर्तन होता है:
v master
a… b… c… f…
bob o<---o<---o<---o
^
| d… e…
+----o<---o
^ origin/master
a… b… c… d… e…
origin o<---o<---o<---o<---o
^ master
पुल प्रक्रिया का दूसरा चरण डायवर्जिंग युक्तियों को मर्ज करना और परिणाम के लिए प्रतिबद्ध करना है:
v master
a… b… c… f… 1…
bob o<---o<---o<---o<-------o
^ |
| d… e… |
+----o<---o<--+
^ origin/master
उम्मीद है कि मर्ज संघर्ष में नहीं चलेगा (यदि आप उन्हें अनुमान लगाते हैं कि आप दो चरणों को मैन्युअल रूप से fetch
और साथ में कर सकते हैं merge
)। बाद में जो करने की आवश्यकता है, उन परिवर्तनों को फिर से origin
आगे बढ़ाने के लिए है , जिसके परिणामस्वरूप विलय के बाद तेजी से आगे विलय होगा, origin
भंडार में नवीनतम का प्रत्यक्ष वंशज है:
v origin/master
v master
a… b… c… f… 1…
bob o<---o<---o<---o<-------o
^ |
| d… e… |
+----o<---o<--+
v master
a… b… c… f… 1…
origin o<---o<---o<---o<-------o
^ |
| d… e… |
+----o<---o<--+
गिट और एचजी में विलय करने का एक और विकल्प है, जिसे रिबेस कहा जाता है , जो बॉब के परिवर्तनों को नवीनतम परिवर्तनों के बाद स्थानांतरित करेगा। चूँकि मैं इस उत्तर को किसी और क्रिया के लिए नहीं चाहता हूँ इसलिए मैं आपको इसके बारे में git , मर्क्यूरियल या बाज़ार डॉक्स पढ़ने दूंगा ।
पाठक के लिए एक अभ्यास के रूप में, यह ड्राइंग करें कि इसमें शामिल किसी अन्य उपयोगकर्ता के साथ कैसे काम करेंगे। यह बॉब के साथ उपरोक्त उदाहरण के समान किया जाता है। रिपॉजिटरी के बीच विलय करना आपके विचार से आसान है क्योंकि सभी संशोधन / कमिट विशिष्ट पहचान हैं।
प्रत्येक डेवलपर के बीच पैच भेजने का मुद्दा भी है, जो कि तोड़फोड़ में एक बहुत बड़ी समस्या थी, जिसे विशिष्ट पहचान योग्य संशोधनों द्वारा git, hg और bzr में कम किया जाता है। एक बार जब किसी ने अपने बदलावों को मर्ज कर लिया (यानी मर्ज कमिटमेंट) कर लिया और उसे टीम में बाकी सभी के लिए भेज दिया या तो केंद्रीय भंडार में धकेलने या पैच भेजने के लिए उपभोग करने के लिए भेजा तो उन्हें मर्ज के बारे में चिंता करने की ज़रूरत नहीं है, क्योंकि यह पहले से ही हुआ है । मार्टिन फाउलर ने इस तरह के काम को एकीकृत एकीकरण कहा ।
चूँकि संरचना Dvb को नियोजित करने के बजाय, Subversion से भिन्न होती है, इसलिए यह न केवल सिस्टम के लिए बल्कि उपयोगकर्ता के लिए भी आसान तरीके से शाखाबद्ध और विलय करने में सक्षम बनाता है।