git विलय: एचजी/गिट बनाम एसवीएन




svn mercurial (5)

मैं अक्सर पढ़ता हूं कि एचजी (और गिट और ...) एसवीएन की तुलना में विलय करने में बेहतर हैं लेकिन मैंने व्यावहारिक उदाहरण कभी नहीं देखा है जहां एचजी / गिट कुछ ऐसा विलय कर सकता है जहां एसवीएन विफल रहता है (या जहां एसवीएन को मैन्युअल हस्तक्षेप की आवश्यकता होती है)। क्या आप शाखा / संशोधित / प्रतिबद्ध /.. की कुछ चरण-दर-चरण सूचियां पोस्ट कर सकते हैं.- ऑपरेशन जो दिखाते हैं कि एसवीएन असफल होगा जबकि एचजी / गिट खुशी से आगे बढ़ेगा? प्रैक्टिकल, अत्यधिक असाधारण मामलों में कृपया ...

कुछ पृष्ठभूमि: हमारे पास कुछ प्रोजेक्ट (या इसी तरह की परियोजनाओं के समूह) के साथ अपने स्वयं के भंडार में एसवीएन का उपयोग करके परियोजनाओं पर काम कर रहे कुछ दर्जन डेवलपर्स हैं। हम जानते हैं कि रिलीज- और फीचर-शाखाओं को कैसे लागू किया जाए ताकि हम अक्सर समस्याओं में भाग न सकें (यानी, हम वहां रहे हैं, लेकिन हमने जोएल की समस्याओं को दूर करने के लिए सीखा है "एक प्रोग्रामर पूरी टीम के आघात का कारण बनता है" या "एक शाखा को दोबारा बदलने के लिए दो सप्ताह के लिए छह डेवलपर्स की जरूरत है")। हमारे पास रिलीज-शाखाएं हैं जो बहुत स्थिर हैं और केवल बगफिक्स लागू करने के लिए उपयोग की जाती हैं। हमारे पास ट्रंक हैं जो एक सप्ताह के भीतर रिलीज बनाने में सक्षम होने के लिए पर्याप्त स्थिर होना चाहिए। और हमारे पास फीचर-शाखाएं हैं जो एकल डेवलपर्स या डेवलपर्स के समूह काम कर सकती हैं। हां, वे पुनर्संरचना के बाद हटा दिए जाते हैं ताकि वे भंडार को अव्यवस्थित न करें। ;)

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


सामान्य फायदे (ऑफलाइन काम करता है, प्रकाशन प्रक्रिया , ...) के बारे में बात किए बिना यहां एक "विलय" उदाहरण है जो मुझे पसंद है:

मुख्य परिदृश्य जो मैं देख रहा हूं वह एक शाखा है जिस पर दो असंबंधित कार्य वास्तव में विकसित किए जाते हैं
(यह एक फीचर से शुरू हुआ, लेकिन इससे इस अन्य फीचर के विकास की शुरुआत हुई।
या यह एक पैच से शुरू हुआ, लेकिन यह एक और विशेषता के विकास के लिए नेतृत्व)।

मुख्य शाखा पर केवल दो सुविधाओं में से एक को कैसे विलय करना है?
या आप अपनी खुद की शाखाओं में दो सुविधाओं को अलग कैसे करते हैं?

आप किसी प्रकार के पैच उत्पन्न करने का प्रयास कर सकते हैं, इसके साथ समस्या यह है कि आप निश्चित रूप से कार्यात्मक निर्भरताओं के बारे में निश्चित नहीं हैं जो कि अस्तित्व में हो सकते थे:

  • आपके पैच में उपयोग किया जाता है (या एसवीएन के लिए संशोधन)
  • दूसरा पैच का हिस्सा नहीं है

गिट (और Mercurial भी मुझे लगता है) एक शाखा के हिस्से को पुनर्भुगतान (शाखा की जड़ को रीसेट करने के लिए) rebase --onto विकल्प का प्रस्ताव है:

जेफ्रोमी के पोस्ट से

- x - x - x (v2) - x - x - x (v2.1)
           \
            x - x - x (v2-only) - x - x - x (wss)

आप इस स्थिति को उलझा सकते हैं जहां आपके पास v2 के साथ-साथ एक नई Wss सुविधा के लिए पैच हैं:

- x - x - x (v2) - x - x - x (v2.1)
          |\
          |  x - x - x (v2-only)
           \
             x - x - x (wss)

, आपको अनुमति देता है:

  • अलगाव में प्रत्येक शाखा का परीक्षण करने के लिए जांच करें कि क्या सबकुछ संकलित / काम के रूप में काम करता है
  • केवल वही विलय करें जो आप मुख्य करना चाहते हैं।

दूसरी विशेषता जो मुझे पसंद है (जो विलय प्रभावित करती है) प्रस्तुत करने के लिए प्रतिबद्धताओं को स्क्वैश करने की क्षमता है (एक शाखा में अभी तक किसी अन्य रेपो पर धक्का नहीं है):

  • एक क्लीनर इतिहास
  • जो अधिक सुसंगत है (function1 के लिए प्रतिबद्ध 1 के बजाय, function2 के लिए प्रतिबद्ध 2, function1 के लिए प्रतिबद्ध 3 फिर से ...)

यह विलय सुनिश्चित करता है जो कम संघर्ष के साथ बहुत आसान है।


दूसरों ने इसके अधिक सैद्धांतिक पहलुओं को शामिल किया है। शायद मैं एक और व्यावहारिक परिप्रेक्ष्य उधार दे सकता हूं।

मैं वर्तमान में एक ऐसी कंपनी के लिए काम कर रहा हूं जो "फीचर शाखा" विकास मॉडल में एसवीएन का उपयोग करता है। अर्थात्:

  • ट्रंक पर कोई काम नहीं किया जा सकता है
  • प्रत्येक डेवलपर अपनी शाखा बना सकता है
  • शाखाओं को किए गए कार्य की अवधि के लिए रहना चाहिए
  • प्रत्येक कार्य में अपनी शाखा होनी चाहिए
  • ट्रंक पर वापस विलय की आवश्यकता है (आमतौर पर बगजिला के माध्यम से)
  • कभी-कभी जब नियंत्रण के उच्च स्तर की आवश्यकता होती है, तो विलय द्वारपाल द्वारा किया जा सकता है

सामान्य में, यह काम करता है। इस तरह के प्रवाह के लिए एसवीएन का उपयोग किया जा सकता है, लेकिन यह सही नहीं है। एसवीएन के कुछ पहलू हैं जो मानव व्यवहार के तरीके और आकार में आते हैं। यह कुछ नकारात्मक पहलू देता है।

  • ^/trunk से कम अंक से ब्रांच करने वाले लोगों के साथ हमें कुछ समस्याएं आई हैं। यह लिटर पूरे पेड़ में सूचना रिकॉर्ड मर्ज करते हैं, और अंत में विलय ट्रैकिंग को तोड़ देते हैं। झूठे संघर्ष प्रकट होने लगते हैं, और भ्रम शासन करता है।
  • ट्रंक से शाखा में परिवर्तन उठाकर अपेक्षाकृत सीधे आगे है। svn merge वह करता है जो आप चाहते हैं। अपने परिवर्तनों को वापस विलय करने के लिए आवश्यक है (हमें बताया गया है) - मर्ज कमांड पर --reintegrate । मैंने कभी भी इस स्विच को वास्तव में नहीं समझा है, लेकिन इसका मतलब है कि शाखा को फिर से ट्रंक में विलय नहीं किया जा सकता है। इसका मतलब है कि यह एक मृत शाखा है और आपको काम जारी रखने के लिए एक नया निर्माण करना है। (नोट देखें)
  • शाखाओं को बनाने और हटाने के दौरान सर्वर पर सर्वर पर संचालन करने का पूरा व्यवसाय वास्तव में लोगों को भ्रमित करता है और डरता है। तो वे इससे बचते हैं।
  • शाखाओं के बीच स्विच करना गलत हो जाना आसान है, शाखा ए को देखकर एक पेड़ का हिस्सा छोड़कर, शाखा बी को देखकर एक और हिस्सा छोड़कर। लोग अपने सभी काम एक शाखा में करना पसंद करते हैं।

क्या होता है यह है कि एक इंजीनियर 1 दिन को एक शाखा बनाता है। वह अपना काम शुरू करता है और इसके बारे में भूल जाता है। कुछ समय बाद एक मालिक साथ आता है और पूछता है कि क्या वह अपना काम ट्रंक में छोड़ सकता है। अभियंता इस दिन डर रहा है क्योंकि पुनर्वितरण का अर्थ है:

  • अपनी लंबी जीवित शाखा को वापस ट्रंक में विलय करना और सभी संघर्षों को हल करना, और एक अलग शाखा में होना असंबंधित कोड जारी करना, लेकिन नहीं था।
  • अपनी शाखा हटाना
  • एक नई शाखा बनाना
  • अपनी कार्यशील प्रतिलिपि को नई शाखा में बदलना

... और क्योंकि अभियंता इसे जितना छोटा कर सकता है, वे प्रत्येक चरण को करने के लिए "जादू incantation" याद नहीं कर सकते हैं। गलत स्विच और यूआरएल होते हैं, और अचानक वे एक गड़बड़ में हैं और वे "विशेषज्ञ" प्राप्त करते हैं।

आखिरकार यह सब ठीक हो जाता है, और लोग कमियों से निपटने के तरीके सीखते हैं, लेकिन प्रत्येक नया स्टार्टर एक ही समस्या से गुजरता है। आखिरी वास्तविकता (जैसा कि मैंने शुरू किया था उसके विपरीत) यह है:

  • ट्रंक पर कोई काम नहीं किया जाता है
  • प्रत्येक डेवलपर की एक प्रमुख शाखा है
  • शाखाएं तब तक चलती हैं जब तक काम जारी नहीं किया जाता है
  • टिकट वाले बग फिक्स को अपनी शाखा मिलती है
  • अधिकृत होने पर ट्रंक पर वापस विलय किया जाता है

...परंतु...

  • कभी-कभी काम इसे ट्रंक करने के लिए बनाता है जब ऐसा नहीं होना चाहिए क्योंकि यह किसी अन्य शाखा के समान शाखा में है।
  • लोग सभी विलय (यहां तक ​​कि आसान सामान) से बचते हैं, इसलिए लोग अक्सर अपने छोटे बुलबुले में काम करते हैं
  • बड़े विलय होते हैं, और सीमित अराजकता का कारण बनते हैं।

शुक्र है कि टीम का सामना करने के लिए काफी छोटा है, लेकिन यह स्केल नहीं करेगा। बात यह है कि इनमें से कोई भी सीवीसीएस के साथ कोई समस्या नहीं है, लेकिन अधिक इसलिए क्योंकि विलय DVCS में उतना महत्वपूर्ण नहीं है जितना वे धीमे नहीं हैं। वह "विलय घर्षण" व्यवहार का कारण बनता है जिसका अर्थ है कि "फ़ीचर शाखा" मॉडल टूटना शुरू हो जाता है। अच्छे विलयों को सभी वीसीएस की सुविधा की आवश्यकता नहीं है, न केवल डीवीसीएस।

इसके मुताबिक अब एक --record-only स्विच स्विच है जिसका उपयोग - --reintegrate समस्या को हल करने के लिए किया जा सकता है, और apparently v1.8 स्वचालित रूप से एक बार फिर से होने के लिए चुनता है, और इससे शाखा को बाद में मृत नहीं किया जाता है


मैं भी एक ऐसे मामले की तलाश कर रहा हूं जहां कहें, सबवर्सन शाखा को मर्ज करने में विफल रहता है और मर्कुरियल (और गिट, बाज़ार, ...) सही काम करता है।

एसवीएन बुक वर्णन करता है कि नामित फ़ाइलों को गलत तरीके से कैसे विलय किया जाता है । यह सबवर्जन 1.5 , 1.6 , 1.7 , और 1.8 पर लागू होता है! मैंने नीचे की स्थिति को फिर से बनाने की कोशिश की है:

cd /tmp
rm -rf svn-repo svn-checkout
svnadmin create svn-repo
svn checkout file:///tmp/svn-repo svn-checkout
cd svn-checkout
mkdir trunk branches
echo 'Goodbye, World!' > trunk/hello.txt
svn add trunk branches
svn commit -m 'Initial import.'
svn copy '^/trunk' '^/branches/rename' -m 'Create branch.'
svn switch '^/trunk' .
echo 'Hello, World!' > hello.txt
svn commit -m 'Update on trunk.'
svn switch '^/branches/rename' .
svn rename hello.txt hello.en.txt
svn commit -m 'Rename on branch.'
svn switch '^/trunk' .
svn merge --reintegrate '^/branches/rename'

पुस्तक के मुताबिक, विलय को साफ से खत्म करना चाहिए, लेकिन नामित फ़ाइल में गलत डेटा के साथ trunk पर अद्यतन भूल गया है। इसके बजाय मुझे एक वृक्ष संघर्ष मिलता है (यह सबवर्सन 1.6.17 के साथ है, लेखन के समय डेबियन में नवीनतम संस्करण):

--- Merging differences between repository URLs into '.':
A    hello.en.txt
   C hello.txt
Summary of conflicts:
  Tree conflicts: 1

कोई भी संघर्ष नहीं होना चाहिए - अद्यतन फ़ाइल के नए नाम में विलय किया जाना चाहिए। जबकि सबवर्जन विफल रहता है, Mercurial इसे सही तरीके से संभालता है:

rm -rf /tmp/hg-repo
hg init /tmp/hg-repo
cd /tmp/hg-repo
echo 'Goodbye, World!' > hello.txt
hg add hello.txt
hg commit -m 'Initial import.'
echo 'Hello, World!' > hello.txt
hg commit -m 'Update.'
hg update 0
hg rename hello.txt hello.en.txt
hg commit -m 'Rename.'
hg merge

विलय से पहले, भंडार इस तरह दिखता है ( hg glog ):

@  changeset:   2:6502899164cc
|  tag:         tip
|  parent:      0:d08bcebadd9e
|  user:        Martin Geisler 
|  date:        Thu Apr 01 12:29:19 2010 +0200
|  summary:     Rename.
|
| o  changeset:   1:9d06fa155634
|/   user:        Martin Geisler 
|    date:        Thu Apr 01 12:29:18 2010 +0200
|    summary:     Update.
|
o  changeset:   0:d08bcebadd9e
   user:        Martin Geisler 
   date:        Thu Apr 01 12:29:18 2010 +0200
   summary:     Initial import.

विलय का उत्पादन है:

merging hello.en.txt and hello.txt to hello.en.txt
0 files updated, 1 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)

दूसरे शब्दों में: Mercurial संशोधन 1 से परिवर्तन लिया और इसे संशोधन फ़ाइल ( hello.en.txt ) से नए फ़ाइल नाम में विलय कर दिया। रिफैक्टरिंग और रीफैक्टरिंग का समर्थन करने के लिए इस मामले को संभालना निश्चित रूप से जरूरी है कि आप एक शाखा पर क्या करना चाहते हैं।


विवर्तन 1.5 से पहले (यदि मुझे गलत नहीं है), तो विचलन का एक बड़ा नुकसान था कि इसे विलय इतिहास याद नहीं होगा।

आइए वोनसी द्वारा उल्लिखित मामले को देखें:

- x - x - x (v2) - x - x - x (v2.1)
          |\
          |  x - A - x (v2-only)
           \
             x - B - x (wss)

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

यह मेरे अपने अनुभव से एक उदाहरण है, जहां बी से ए में विलय करने से कोड की मात्रा के कारण कई घंटे लग गए: यह फिर से गुजरने के लिए एक वास्तविक दर्द होता, जो उप-पूर्ववर्ती 1.5 के मामले में होता।

Hginit से विलय व्यवहार में एक और, शायद अधिक प्रासंगिक अंतर : सबवर्जन पुन: शिक्षा :

कल्पना करें कि आप और मैं कुछ कोड पर काम कर रहे हैं, और हम उस कोड को शाखाबद्ध करते हैं, और हम प्रत्येक अलग-अलग कार्यक्षेत्रों में जाते हैं और उस कोड में बहुत सारे बदलाव और अलग-अलग बदलाव करते हैं, इसलिए वे काफी अलग हो गए हैं।

जब हमें विलय करना होता है, तो सबवर्जन दोनों संशोधनों को देखने की कोशिश करता है- मेरा संशोधित कोड, और आपका संशोधित कोड- और यह अनुमान लगाने का प्रयास करता है कि उन्हें एक बड़ी अपवित्र गड़बड़ी में कैसे एक साथ नष्ट करना है। यह आम तौर पर विफल रहता है, "मर्ज विवाद" के पृष्ठों और पृष्ठों का उत्पादन करता है जो वास्तव में संघर्ष नहीं होते हैं, बस ऐसे स्थान जहां सबवर्सन हमारे द्वारा किए गए कार्यों को समझने में असफल रहा।

इसके विपरीत, जब हम Mercurial में अलग से काम कर रहे थे, Mercurial परिवर्तनों की एक श्रृंखला रखने में व्यस्त था। और इसलिए, जब हम अपने कोड को एक साथ मर्ज करना चाहते हैं, तो Mercurial में वास्तव में बहुत सारी जानकारी है: यह जानता है कि हम में से प्रत्येक क्या बदलता है और अंतिम परिवर्तन को देखने और अनुमान लगाने की कोशिश करने के बजाय उन परिवर्तनों को दोबारा लागू कर सकता है साथ में।

संक्षेप में, मतभेदों का विश्लेषण करने के लिए Mercurial का तरीका है (था?) उपversण से बेहतर है।


मैं सबवर्सन का उपयोग नहीं करता हूं, लेकिन सबवर्सन 1.5 के लिए रिलीज नोट्स से : मर्ज ट्रैकिंग (आधारभूत) ऐसा लगता है कि गिट या मर्कुरियल जैसे पूर्ण-डीएजी संस्करण नियंत्रण प्रणाली में ट्रैकिंग कार्य को मर्ज करने के तरीके में निम्नलिखित अंतर हैं।

  • शाखा में ट्रंक विलय करना शाखा को ट्रंक में विलय करने से अलग है: कुछ कारणों से शाखा में ट्रंक विलय करने की आवश्यकता होती है - svn merge करने के लिए विकल्प को कम करें।

    गिट या मर्कुरियल जैसे वितरित संस्करण नियंत्रण प्रणालियों में ट्रंक और शाखा के बीच कोई तकनीकी अंतर नहीं है: सभी शाखाएं बराबर बनाई जाती हैं (यद्यपि सामाजिक अंतर हो सकता है)। किसी भी दिशा में विलय एक ही तरीके से किया जाता है।

  • आपको खाते में ट्रैकिंग मर्ज करने के लिए svn log और svn blame लिए new -g ( --use-merge-history ) विकल्प प्रदान करने की आवश्यकता है।

    गिट और मर्कुरियल मर्ज ट्रैकिंग में इतिहास (लॉग) और दोष प्रदर्शित करते समय स्वचालित रूप से ध्यान में रखा जाता है। गिट में आप केवल पहले माता --first-parent का पालन करने का अनुरोध कर सकते हैं - पहले --first-parent (मुझे लगता है कि --first-parent समान विकल्प मौजूद है) git log में ट्रैकिंग जानकारी को "छोड़ दें"।

  • जो मैं समझता हूं svn:mergeinfo संपत्ति विवादों के बारे में प्रति-पथ जानकारी संग्रहीत करता है (सबवर्जन svn:mergeinfo -आधारित है), जबकि गिट और मर्कुरियल में यह केवल उन वस्तुओं को प्रतिबद्ध करता है जिनमें एक से अधिक माता-पिता हो सकते हैं।

  • सबवर्सन में विलय ट्रैकिंग के लिए "ज्ञात मुद्दे" उपखंड से पता चलता है कि बार-बार / चक्रीय / परावर्तक विलय ठीक से काम नहीं कर सकता है। इसका मतलब है कि निम्नलिखित इतिहास के साथ दूसरा विलय सही काम नहीं कर सकता है ('ए' ट्रंक या शाखा हो सकती है, और 'बी' क्रमशः शाखा या ट्रंक हो सकती है):

    *---*---x---*---y---*---*---*---M2        <-- A
             \       \             /
              --*----M1---*---*---/           <-- B
    

    यदि उपर्युक्त ASCII-कला टूट जाती है: शाखा 'बी' को 'ए' में संशोधन 'एक्स' पर बनाया गया है, फिर बाद में शाखा 'ए' को 'वाई' में विलय 'बी' में विलय कर दिया गया है 'एम 1' विलय करें, और आखिरकार शाखा 'बी' शाखा 'ए' में विलय 'एम 2' के रूप में विलय हो गई है।

    *---*---x---*-----M1--*---*---M2          <-- A
             \       /           / 
              \-*---y---*---*---/             <-- B
    

    यदि उपर्युक्त ASCII-कला टूट जाती है: शाखा 'बी' को 'ए' में संशोधन 'एक्स' से बनाया गया है (इसे '' '' में 'y' में 'एम' के रूप में विलय किया गया है, और बाद में शाखा 'ए' में फिर से 'एम 2' के रूप में विलय हो गया।

  • सबवर्सन क्रिस-क्रॉस विलय के उन्नत मामले का समर्थन नहीं कर सकता है।

    *---b-----B1--M1--*---M3
         \     \ /        /
          \     X        /
           \   / \      /
            \--B2--M2--*
    

    गिट इस स्थिति को "रिकर्सिव" मर्ज रणनीति का उपयोग करके अभ्यास में ठीक कर देता है। मैं Mercurial के बारे में निश्चित नहीं हूँ।

  • "ज्ञात समस्याएं" में चेतावनी है कि ट्रैकिंग माई फ़ाइल नामों के साथ काम नहीं करती है, उदाहरण के लिए जब एक पक्ष फ़ाइल का नाम बदलता है (और शायद इसे संशोधित करता है), और दूसरी तरफ नाम बदलने के बिना फ़ाइल को संशोधित करता है (पुराने नाम के तहत)।

    गिट और मर्कुरियल दोनों ही मामले में इस तरह के मामले को ठीक करते हैं: नाम बदलने का उपयोग करके गिट, नाम बदलने का उपयोग कर Mercurial।

HTH





dvcs