नामित शाखाएं बनाम एकाधिक रिपोजिटरी


130

वर्तमान में हम अपेक्षाकृत बड़े कोडबेस पर तोड़फोड़ का उपयोग कर रहे हैं। प्रत्येक रिलीज की अपनी शाखा हो जाती है, और ट्रंक के खिलाफ फिक्स का उपयोग किया जाता है और उपयोग करते हुए रिलीज शाखाओं में माइग्रेट किया जाता हैsvnmerge.py

मेरा मानना ​​है कि बेहतर स्रोत नियंत्रण के लिए आगे बढ़ने का समय आ गया है, और मैं कुछ समय के लिए मर्क्यूरियल के साथ रहा हूँ।

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

या तो मामले में ऐसा लगता है कि मैं रिलीज शाखाओं में शामिल करने के लिए चेरी के बदलाव के लिए प्रत्यारोपण जैसे कुछ का उपयोग कर सकता हूं।

मैं तुमसे पूछता हूं; प्रत्येक दृष्टिकोण के सापेक्ष गुण क्या हैं?

जवाबों:


129

सबसे बड़ा अंतर यह है कि इतिहास में शाखा के नाम कैसे दर्ज किए जाते हैं। नामित शाखाओं के साथ शाखा का नाम प्रत्येक बदलाव में अंतर्निहित है और इस प्रकार यह इतिहास का एक अपरिवर्तनीय हिस्सा बन जाएगा। क्लोनों के साथ कोई स्थायी रिकॉर्ड नहीं होगा जहां एक विशेष परिवर्तन आया था।

इसका मतलब है कि क्लोन त्वरित प्रयोगों के लिए महान हैं जहां आप एक शाखा का नाम रिकॉर्ड नहीं करना चाहते हैं, और नामित शाखाएं दीर्घकालिक शाखाओं ("1.x", "2.x" और इसी तरह) के लिए अच्छी हैं।

यह भी ध्यान दें कि एकल भंडार आसानी से मर्क्यूरियल में कई प्रकाश-भार शाखाओं को समायोजित कर सकता है। ऐसी-रिपॉजिटरी शाखाओं को बुकमार्क किया जा सकता है ताकि आप उन्हें आसानी से दोबारा पा सकें। मान लीजिए कि आपने कंपनी रिपॉजिटरी को क्लोन किया है जब यह इस तरह दिखता था:

[a] --- [b]

आप दूर हैक और बनाने [x]और [y]:

[a] --- [b] --- [x] --- [y]

किसी को कहते हैं, जबकि मीन [c]और [d]भंडार में, इसलिए जब आप खींच आप इस प्रकार का इतिहास ग्राफ मिलती है:

            [x] --- [y]
           /
[ऐ बी सी डी]

यहाँ एक एकल भंडार में दो प्रमुख हैं। आपकी वर्किंग कॉपी हमेशा एक सिंगल चेंज को दर्शाती है, तथाकथित वर्किंग कॉपी पैरेंट चेंजेस। इस के साथ की जाँच करें:

% hg parents

मान लीजिए कि यह रिपोर्ट करता है [y]। आप के साथ सिर देख सकते हैं

% hg heads

और इस रिपोर्ट करेंगे [y]और [d]। यदि आप अपने रिपॉजिटरी को स्वच्छ चेकआउट के लिए अपडेट करना चाहते हैं [d], तो बस करें ( [d]इसके लिए संशोधन संख्या के साथ विकल्प [d]):

% hg update --clean [d]

फिर आपको वह hg parentsरिपोर्ट दिखाई देगी [d]। इसका मतलब है कि आपकी अगली प्रतिबद्धता [d]माता-पिता के रूप में होगी । आप मुख्य शाखा में देखे गए बग को ठीक कर सकते हैं और बदलाव कर सकते हैं [e]:

            [x] --- [y]
           /
[a] --- [b] --- [c] --- [d] --- [e]

[e]केवल बदलाव को आगे बढ़ाने के लिए , आपको करने की आवश्यकता है

% hg push -r [e]

जहाँ [e]हैश हैश है। डिफ़ॉल्ट रूप से hg pushबस खजाने की तुलना करें और देखें कि होगा [x], [y]और [e]याद कर रहे हैं, लेकिन आप साझा करने के लिए नहीं चाहते हो सकता है [x]और [y]अभी तक।

यदि बगफिक्स भी आपको प्रभावित करता है, तो आप इसे अपनी सुविधा शाखा में मर्ज करना चाहते हैं:

% hg update [y]
% hg merge

इस तरह से यह देखने के लिए आपका रिपॉजिटरी ग्राफ निकल जाएगा:

            [x] --- [y] ----------- [z]
           / /
[a] --- [b] --- [c] --- [d] --- [e]

जहाँ और के [z]बीच मर्ज है । आप शाखा को फेंकने का विकल्प भी चुन सकते हैं:[y][e]

% hg strip [x]

इस कहानी का मेरा मुख्य बिंदु यह है: एक एकल क्लोन आसानी से विकास के कई मार्गों का प्रतिनिधित्व कर सकता है। यह हमेशा बिना किसी एक्सटेंशन के "सादे hg" के लिए सही रहा है। बुकमार्क विस्तार एक बहुत मदद, हालांकि है। यह आपको नाम (बुकमार्क) को बदलने के लिए असाइन करने की अनुमति देगा। ऊपर के मामले में आप अपने विकास के प्रमुख पर एक बुकमार्क और ऊपर की तरफ एक सिर चाहते हैं। बुकमार्क्स को मर्क्यूरियल 1.6 के साथ धकेला और खींचा जा सकता है और मर्क्यूरियल 1.8 में बिल्ट-इन फीचर बन गया है।

यदि आपने दो क्लोन बनाने का विकल्प चुना था, तो आपके विकास क्लोन बनाने के बाद इस तरह दिखेंगे [x]और [y]:

[a] --- [b] --- [x] --- [y]

और आपके अपस्ट्रीम क्लोन में होगा:

[a] --- [b] --- [c] --- [d]

अब आप बग को नोटिस करते हैं और उसे ठीक करते हैं। यहाँ आप के hg updateबाद से नहीं है क्योंकि नदी के ऊपर क्लोन उपयोग करने के लिए तैयार है। आप प्रतिबद्ध और बनाएँ [e]:

[a] --- [b] --- [c] --- [d] --- [e]

अपने विकास क्लोन में बगफिक्स को शामिल करने के लिए आप इसे वहां खींचते हैं:

[a] --- [b] --- [x] --- [y]
           \
            [c] --- [d] --- [e]

और मर्ज करें:

[a] --- [b] --- [x] --- [y] --- [z]
           \ /
            [c] --- [d] --- [e]

ग्राफ अलग दिख सकता है, लेकिन इसकी संरचना समान है और अंतिम परिणाम समान है। क्लोन का उपयोग करके आपको कम मानसिक बहीखाता करना पड़ता था।

नामांकित शाखाएं वास्तव में यहां तस्वीर में नहीं आईं क्योंकि वे काफी वैकल्पिक हैं। नामांकित शाखाओं का उपयोग करने से पहले हम वर्षों तक दो खंडों का उपयोग करके Mercurial का विकास किया गया था। हम 'डिफ़ॉल्ट' शाखा के अलावा 'स्थिर' नामक शाखा को बनाए रखते हैं और 'स्थिर' शाखा के आधार पर अपनी रिलीज़ करते हैं। अनुशंसित वर्कफ़्लो के विवरण के लिए विकी में मानक शाखा पृष्ठ देखें ।


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

2
संदर्भित: 'क्लोन त्वरित प्रयोगों के लिए महान हैं' - नहीं, वे नहीं हैं! क्या होगा अगर आपको रेपो में कुछ हज़ारों फाइलें मिली हैं? क्लोनिंग में बस एक पल (<1 सेकंड) में स्विच करते समय उम्र (1 मिनट से ऊपर कभी भी) लगेगी। अभी भी नामित शाखाओं के उपयोग से चैंज को प्रदूषित किया जाएगा। क्या यह एक मरा हुआ अंत नहीं है? या मुझे कुछ याद आ रहा है?
seler

ठीक है सेलेर; अपने मूल तर्क में संशोधन की तरह लगता है; क्लोन अच्छे हैं जहां कई पूर्ण प्रतियों का ओवरहेड आपके लिए महत्वपूर्ण नहीं है, या जब आप प्रति शाखा अलग-अलग स्थानीय कामकाजी प्रतियों की लागत को कम करने के लिए hg के सिम्बलिंक / हार्डलिंक का उपयोग कर सकते हैं।
वॉरेन पी

@ सलामी बल्लेबाज: आप काफी सही हैं कि यदि कोड बड़ा है तो क्लोन अव्यावहारिक हैं। बुकमार्क तो समाधान हैं।
मार्टिन गिस्लर

29

मुझे लगता है कि आप एक रेपो में पूरा इतिहास चाहते हैं। एक अल्पकालिक रेपो को बंद करना अल्पकालिक प्रयोगों के लिए है, न कि रिलीज जैसी बड़ी घटनाओं के लिए।

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


20
आप बहुत आसानी से ऐसी सुविधा शाखा बना सकते हैं: "hg update" को अपनी शाखा बिंदु पर, दूर संपादित करें और "hg कमिट" करें। आपने नया विकास की एक अलग रेखा बनाई है - नए आवागमन इस शाखा का विस्तार करेंगे। इससे छुटकारा पाने के लिए "hg क्लोन -r" का उपयोग करें, या इसे "hg strip" द्वारा इनलाइन हटा दें। तो कृपया निराश न हों, या अपने फीचर अनुरोधों के साथ मर्क्यूरियल मेलिंग सूचियों में आएं।
मार्टिन गिस्लर

8
ऐसा लग रहा hg stripहै कि मैं क्या चाहता हूं। ऑनलाइन प्रलेखन दावा शाखाएं क्यों नहीं हटाई जा सकतीं?
नॉर्मन रैमसे

11
मर्कुरियल ने एक तरह से सस्ती-से-गिट शाखाओं के बारे में स्पष्टीकरण के
मार्टिन

9
आप एक नामित शाखा को बंद कर सकते हैं hg ci --close-branch
एंड्रे व्लास्लोविच शेख

3
@ नोर्मन रामसे: जब लोग कहते हैं कि शाखाएँ नहीं हटाई जा सकतीं, तो उनका मतलब है कि आप बदलावों में एम्बेडेड शाखा का नाम नहीं बदल सकते। एक नहीं हमें ChangeSet पर एक शाखा है, यह परिभाषित करता है एक शाखा। यदि आप एक अलग शाखा में "स्थानांतरित" करना चाहते हैं, तो आपको परिवर्तन को हटाना होगा और इसे एक अलग शाखा के नाम से दोबारा बनाना होगा।
मार्टिन गिस्लर

14

आपको दोनों करना चाहिए ।

@ नोर्मन से स्वीकृत उत्तर से शुरू करें: प्रति रिलीज एक नामित शाखा के साथ एक रिपॉजिटरी का उपयोग करें।

फिर, निर्माण और परीक्षण के लिए प्रति रिलीज शाखा एक क्लोन है।

एक महत्वपूर्ण बात यह है कि यदि आप कई रिपॉजिटरी का उपयोग करते हैं, तो भी आपको transplantउन दोनों के बीच परिवर्तन करने के लिए उपयोग करने से बचना चाहिए क्योंकि 1) यह हैश बदलता है, और 2) यह उन बगों को पेश कर सकता है, जो आपके द्वारा किए गए परिवर्तन के बीच परस्पर विरोधी परिवर्तन का पता लगाना बहुत मुश्किल है। प्रत्यारोपण और लक्ष्य शाखा। आप इसके बजाय सामान्य मर्ज करना चाहते हैं (और पहले से बिना: हमेशा नेत्रहीन मर्ज का निरीक्षण करें), जिसके परिणामस्वरूप @mg ने अपने जवाब के अंत में कहा:

ग्राफ अलग दिख सकता है, लेकिन इसकी संरचना समान है और अंतिम परिणाम समान है।

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

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

लेकिन फिर भी आपको प्रति शाखा / रिलीज में एक क्लोन बनाए रखने की आवश्यकता है जिसे आपको निर्माण और परीक्षण करने की आवश्यकता है। यह तुच्छ है जैसा कि आप कर सकते हैं hg clone <main repo>#<branch> <branch repo>, और फिर hg pullशाखा रेपो में केवल उस शाखा पर नए बदलावों को खींचेगा (इसके अलावा पूर्व शाखाओं में विलय किए गए पूर्वजों में परिवर्तन)।

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


इस सेटअप के लिए यहाँ @ mg का उदाहरण दिया गया है। प्रस्थान बिंदू:

[a] - [b]

रिलीज़ संस्करण के लिए एक नामांकित शाखा बनाएं, "1.0" कहें, जब आप अल्फा रिलीज़ करें। उस पर बग फिक्स करें:

[a] - [b] ------------------ [m1]
         \                 /
          (1.0) - [x] - [y]

(1.0)जब तक आप प्रतिबद्ध नहीं हैं, तब तक शाखा नाम का कोई वास्तविक बदलाव नहीं है। (आप एक तुच्छ प्रतिबद्धता कर सकते हैं, जैसे कि एक टैग जोड़ना, यह सुनिश्चित करने के लिए कि नामित शाखाएं ठीक से बनाई गई हैं।)

मर्ज [m1]इस सेटअप की कुंजी है। एक डेवलपर रिपॉजिटरी के विपरीत जहां असीमित संख्या में सिर हो सकते हैं, आप अपने मुख्य रेपो (पुराने, मृत रिलीज शाखा को छोड़कर) में कई सिर नहीं रखना चाहते हैं। इसलिए जब भी आपके पास रिलीज़ शाखाओं पर नए परिवर्तन होते हैं, तो आपको उन्हें तुरंत डिफ़ॉल्ट शाखा (या बाद में रिलीज़ शाखा) में मर्ज करना होगा। यह गारंटी देता है कि एक रिलीज में किसी भी बग फिक्स को बाद के सभी रिलीज में शामिल किया गया है।

इस बीच डिफ़ॉल्ट शाखा पर विकास अगली रिलीज की ओर जारी है:

          ------- [c] - [d]
         /
[a] - [b] ------------------ [m1]
         \                 /
          (1.0) - [x] - [y]

और हमेशा की तरह, आपको दो शाखाओं को डिफ़ॉल्ट शाखा में मर्ज करने की आवश्यकता है:

          ------- [c] - [d] -------
         /                         \
[a] - [b] ------------------ [m1] - [m2]
         \                 /
          (1.0) - [x] - [y]

और यह 1.0 शाखा क्लोन है:

[a] - [b] - (1.0) - [x] - [y]

अब यह अगली रिलीज शाखा को जोड़ने की कवायद है। अगर यह 2.0 है तो यह निश्चित रूप से डिफ़ॉल्ट रूप से शाखा करेगा। अगर यह 1.1 है तो आप 1.0 या डिफ़ॉल्ट शाखा को चुन सकते हैं। भले ही, 1.0 पर किसी भी नए बदलाव को पहले अगली शाखा में विलय कर दिया जाए, फिर डिफ़ॉल्ट रूप से। यह स्वचालित रूप से किया जा सकता है यदि कोई संघर्ष नहीं है, जिसके परिणामस्वरूप केवल एक खाली मर्ज है।


मुझे आशा है कि उदाहरण से मेरे पहले के बिंदु स्पष्ट हो जाएंगे। सारांश में, इस दृष्टिकोण के फायदे हैं:

  1. एकल आधिकारिक रिपॉजिटरी जिसमें पूरा बदलाव और संस्करण इतिहास शामिल है।
  2. स्पष्ट और सरलीकृत रिलीज प्रबंधन।
  3. डेवलपर्स और इंटीग्रेटर के लिए स्पष्ट और सरलीकृत वर्कफ़्लो।
  4. वर्कफ़्लो पुनरावृत्तियों (कोड समीक्षाएं) और स्वचालन (स्वचालित खाली मर्ज) की सुविधा दें।

UPDATE hg स्वयं ऐसा करता है : मुख्य रेपो में डिफ़ॉल्ट और स्थिर शाखाएँ होती हैं, और स्थिर रेपो स्थिर शाखा क्लोन होता है। यह संस्करण शाखा का उपयोग नहीं करता है, हालांकि, स्थिर शाखा के साथ संस्करण टैग इसके रिलीज प्रबंधन उद्देश्यों के लिए पर्याप्त हैं।


5

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


2

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


0

मैं वास्तव में संस्करणों के लिए नामित शाखाओं का उपयोग करने के खिलाफ सलाह दूंगा। यह वास्तव में टैग के लिए क्या है। नामित शाखाएं लंबे समय तक चलने वाली विविधताओं के लिए होती हैं, एक stableशाखा की तरह ।

तो क्यों न केवल टैग का उपयोग करें? एक मूल उदाहरण:

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

यह defaultशाखा पर एक नया, अनाम शीर्षक बनाएगा , उर्फ। एक अनाम शाखा, जो hg में पूरी तरह से ठीक है। फिर आप किसी भी बिंदु पर बगफिक्स को मुख्य विकास ट्रैक में वापस मर्ज कर सकते हैं। नामित शाखाओं के लिए कोई ज़रूरत नहीं है।


यह आपकी प्रक्रिया पर बहुत हद तक निर्भर करता है। एक वेब ऐप, उदाहरण के लिए, एक स्थिर / परीक्षण / डेवेल शाखा पदानुक्रम के साथ अच्छी तरह से काम करता है। डेस्कटॉप सॉफ़्टवेयर का निर्माण करते समय, हमारे पास आमतौर पर एक विकास शाखा (डिफ़ॉल्ट) के साथ-साथ रखरखाव में एक से तीन (!) शाखाएं होती हैं। यह अनुमान लगाना मुश्किल है कि हमें एक शाखा को फिर से देखने की आवश्यकता हो सकती है, और एक शाखा ट्रैक करने के बारे में एक निश्चित शान है।
जेम्स एमर्टन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.