Git वर्कफ़्लो और रिबेज़ बनाम मर्ज प्रश्न


970

मैं एक दूसरे डेवलपर के साथ एक परियोजना पर कुछ महीनों के लिए Git का उपयोग कर रहा हूं। मुझे एसवीएन के साथ कई वर्षों का अनुभव है , इसलिए मुझे लगता है कि मैं रिश्ते में बहुत सारे सामान लाता हूं।

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

मेरा साथी मुझसे कहता है कि मेरी समस्याएं विली-नीली को मर्ज करने की मेरी इच्छा से उपजी हैं, और मुझे कई स्थितियों में मर्ज के बजाय रिबास का उपयोग करना चाहिए। उदाहरण के लिए, यहां वह वर्कफ़्लो है जिसे उसने नीचे रखा है:

clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature
git checkout master
git merge my_new_feature

अनिवार्य रूप से, एक सुविधा शाखा बनाएं, हमेशा मास्टर से शाखा में छूट दें, और शाखा से वापस मास्टर में विलय करें। ध्यान रखना महत्वपूर्ण है कि शाखा हमेशा स्थानीय रहती है।

यहाँ कार्यप्रवाह है कि मैं के साथ शुरू कर दिया है

clone remote repository
create my_new_feature branch on remote repository
git checkout -b --track my_new_feature origin/my_new_feature
..work, commit, push to origin/my_new_feature
git merge master (to get some changes that my partner added)
..work, commit, push to origin/my_new_feature
git merge master
..finish my_new_feature, push to origin/my_new_feature
git checkout master
git merge my_new_feature
delete remote branch
delete local branch

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

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

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

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

इस तरह से कुछ के लिए "सही" वर्कफ़्लो क्या है? जीआईटी को ब्रांचिंग और मर्जिंग को सुपर-आसान बनाना है, और मैं इसे नहीं देख रहा हूं।

अपडेट 2011-04-15

यह एक बहुत ही लोकप्रिय प्रश्न लगता है, इसलिए मैंने सोचा कि मैं अपने दो साल के अनुभव के साथ अपडेट करूंगा क्योंकि मैंने पहली बार पूछा था।

यह पता चला है कि मूल वर्कफ़्लो सही है, कम से कम हमारे मामले में। दूसरे शब्दों में, यह वही है जो हम करते हैं और यह काम करता है:

clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature, commit
git rebase master
git checkout master
git merge my_new_feature

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

clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature, commit
git rebase master
git checkout master
git merge --squash my_new_feature
git commit -m "added my_new_feature"
git branch -D my_new_feature

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

Github और Bitbucket (अन्य?) खींच अनुरोध - मामले में आप सोच रहे हैं कि कैसे मर्ज / रिबास पुल अनुरोधों से संबंधित है, मैं उपरोक्त सभी चरणों का पालन करने की सलाह देता हूं जब तक कि आप मास्टर में वापस विलय करने के लिए तैयार न हों। मैन्युअल रूप से गिट के साथ विलय करने के बजाय, आप बस पीआर स्वीकार करते हैं। ध्यान दें कि यह स्क्वैश मर्ज नहीं करेगा (कम से कम डिफ़ॉल्ट रूप से नहीं), लेकिन गैर-स्क्वैश, नॉन-फास्ट-फॉरवर्ड पुल अनुरोध समुदाय में स्वीकृत मर्ज सम्मेलन है (जहां तक ​​मुझे पता है)। विशेष रूप से, यह इस तरह काम करता है:

clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature, commit
git rebase master
git push # May need to force push
...submit PR, wait for a review, make any changes requested for the PR
git rebase master
git push # Will probably need to force push (-f), due to previous rebases from master
...accept the PR, most likely also deleting the feature branch in the process
git checkout master
git branch -d my_new_feature
git remote prune origin

मुझे गिट से प्यार हो गया है और एसवीएन में वापस जाना नहीं चाहता। यदि आप संघर्ष कर रहे हैं, तो बस इसके साथ रहें और अंततः आप सुरंग के अंत में प्रकाश देखेंगे।


31
दुर्भाग्य से, नई प्रैग्मैटिक प्रोग्रामिंग बुक ज्यादातर एसवीएन में विचार करते समय गिट का उपयोग करने से लिखी गई है, और इस मामले में इसने आपको गुमराह किया है। गिट में, रिबास चीजों को सरल रखता है जब वे हो सकते हैं। आपका अनुभव आपको बता सकता है कि आपके वर्कफ़्लो Git में काम नहीं करते हैं, ऐसा नहीं है कि Git काम नहीं करता है।
पॉल

18
मैं इस मामले में स्क्वैश विलय की सिफारिश नहीं करूंगा, क्योंकि यह विलय के बारे में कोई जानकारी नहीं बचाता है (बस svn की तरह, लेकिन यहां कोई मर्जिनफॉइ नहीं)।
मारियस के

7
नोट को नीचे से प्यार करें, मुझे गिट के साथ संघर्ष का एक समान अनुभव था, लेकिन अब इसका उपयोग नहीं करने की कल्पना करने के लिए संघर्ष। अंतिम स्पष्टीकरण के लिए भी धन्यवाद, rebaseसमझ के साथ बहुत मदद मिली
जॉन फेनोव

6
इससे पहले कि आप इस सुविधा को समाप्त कर लें, क्या आपको मास्टर से new_feature मर्ज करने से पहले पिछली बार एक बार रिबास नहीं करना चाहिए?
सॉफ्टनर

17
आपका वर्कफ़्लो हटाए गए शाखा से सभी प्रतिबद्ध इतिहास खो देता है :(
मैक्स नानसी

जवाबों:


371

"संघर्ष" का अर्थ है "समान सामग्री का समानांतर विकास"। तो अगर यह मर्ज के दौरान "ऑल टू हेल" हो जाता है, तो इसका मतलब है कि आपके पास फ़ाइलों के एक ही सेट पर बड़े पैमाने पर विकास हैं।

एक मर्ज की तुलना में रिबेज के बाद का कारण बेहतर है:

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

मैं इस बात की पुष्टि करता हूं कि उस मामले में सही वर्कफ़्लो (फ़ाइलों के सामान्य सेट पर एवोल्यूशन) पहले रिबास है, फिर मर्ज करें

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


उस विषय पर (फिर से वर्कफ़्लो मर्ज करें), barraponto ने टिप्पणी में दो दिलचस्प पोस्ट किए, दोनों randyfay.com से :

इस तकनीक का उपयोग करते हुए, आपका काम हमेशा सार्वजनिक शाखा के ऊपर एक पैच की तरह चलता है जो वर्तमान के साथ अप-टू-डेट है HEAD

( बाजार के लिए एक समान तकनीक मौजूद है )


27
एक ऐसी तकनीक के लिए जो
रिबासिंग

2
randyfay.com/node/91 और randyfay.com/node/89 अद्भुत रीड हैं। इन लेखों ने मुझे यह समझा दिया कि मेरे वर्कफ़्लो के साथ क्या चिंता थी और एक आदर्श वर्कफ़्लो क्या होगा।
कैपी एथरिएल

बस इसे सीधे प्राप्त करने के लिए, अपने स्थानीय पर मास्टर शाखा से रिबासिंग मूल रूप से किसी भी इतिहास को अपडेट करने के लिए आपके स्थानीय ने याद किया हो सकता है कि मास्टर को किसी भी प्रकार के मर्ज के बाद का ज्ञान है?
नर्कतैन

@dtan जो मैं यहाँ वर्णन करता हूं वह मास्टर के शीर्ष पर स्थानीय को पुन: पेश कर रहा है। आप स्थानीय इतिहास को अपडेट नहीं कर रहे हैं, बल्कि स्थानीय शाखा के भीतर किसी भी संघर्ष को हल करने के लिए मास्टर के शीर्ष पर स्थानीय इतिहास को फिर से लागू कर रहे हैं।
वॉनसी

385

टी एल; डॉ

एक git rebase वर्कफ़्लो उन लोगों से आपकी रक्षा नहीं करता है जो संघर्ष समाधान में बुरे हैं या वे लोग जो SVN वर्कफ़्लो के लिए उपयोग किए जाते हैं, जैसे Git डिजास्टर: ए Gory स्टोरी से बचने में सुझाए गए हैं । यह केवल उनके लिए संघर्ष के समाधान को अधिक थकाऊ बनाता है और बुरे संघर्ष के समाधान से उबरना कठिन बनाता है। इसके बजाय, diff3 का उपयोग करें ताकि यह पहली जगह में इतना मुश्किल न हो।


संघर्ष रिज़ॉल्यूशन के लिए रिबेस वर्कफ़्लो बेहतर नहीं है!

मैं इतिहास की सफाई के लिए बहुत समर्थक हूं। हालाँकि अगर मुझे कभी कोई टकराव आता है, तो मैं तुरंत रिबेट को रद्द कर देता हूं और इसके बजाय मर्ज कर देता हूं! यह वास्तव में मुझे मारता है कि लोग संघर्ष समाधान के लिए मर्ज वर्कफ़्लो के लिए एक बेहतर विकल्प के रूप में एक रिबेट वर्कफ़्लो की सिफारिश कर रहे हैं (जो वास्तव में इस प्रश्न के बारे में था)।

यदि यह एक मर्ज के दौरान "सभी टू हेल" जाता है, तो यह एक रिबेस के दौरान "ऑल टू हेल" जाएगा, और संभावित रूप से बहुत सारे नर्क भी! यहाँ पर क्यों:

कारण # 1: प्रत्येक कमिट के लिए एक बार के बजाय एक बार विवादों को हल करें

जब आप मर्ज करने के बजाय रिबास करते हैं, तो आपको उसी रेजॉल्यूशन के लिए, जितनी बार रिबेट करने की बात होती है, उतने बार आपको रेजोल्यूशन रिजॉल्यूशन करना होगा!

वास्तविक परिदृश्य

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

जब मेरी शाखा को गुरु के साथ मिलाने का समय हो, तो मेरे पास दो विकल्प हैं:

git मर्ज: मुझे एक संघर्ष मिलता है। मैं अपनी शाखा में मास्टर (अंतिम उत्पाद) के साथ इसे मास्टर करने और इसे मर्ज करने के लिए किए गए परिवर्तन को देखता हूं। किया हुआ।

git rebase: मुझे अपने पहले कमिटमेंट के साथ एक संघर्ष मिलता है । मैं संघर्ष को हल करता हूं और छूट जारी रखता हूं। मुझे अपनी दूसरी प्रतिबद्धताओं के साथ संघर्ष करना पड़ता है । मैं संघर्ष को हल करता हूं और छूट जारी रखता हूं। मुझे अपनी तीसरी प्रतिबद्धताओं के साथ संघर्ष करना पड़ता है । मैं संघर्ष को हल करता हूं और छूट जारी रखता हूं। मुझे अपनी चौथी प्रतिबद्धताओं के साथ संघर्ष करना पड़ता है । मैं संघर्ष को हल करता हूं और छूट जारी रखता हूं। मुझे अपनी पाँचवीं प्रतिबद्धता के साथ संघर्ष करना पड़ता है । मैं संघर्ष को हल करता हूं और छूट जारी रखता हूं। मुझे अपनी छठी प्रतिबद्धताओं के साथ संघर्ष करना पड़ता है । मैं संघर्ष को हल करता हूं और छूट जारी रखता हूं। मुझे अपने सातवें के साथ एक संघर्ष मिलता हैप्रतिबद्ध। मैं संघर्ष को हल करता हूं और छूट जारी रखता हूं। मुझे अपनी आठवीं प्रतिबद्धता के साथ संघर्ष करना पड़ता है । मैं संघर्ष को हल करता हूं और छूट जारी रखता हूं। मुझे अपनी नौवीं प्रतिबद्धता के साथ संघर्ष करना पड़ता है । मैं संघर्ष को हल करता हूं और छूट जारी रखता हूं। मुझे अपनी दसवीं प्रतिबद्धता के साथ संघर्ष करना पड़ता है । मैं संघर्ष को हल करता हूं और छूट जारी रखता हूं। मुझे अपनी ग्यारहवीं प्रतिबद्धता के साथ संघर्ष करना पड़ता है । मैं संघर्ष को हल करता हूं और छूट जारी रखता हूं। मुझे अपने बारहवें प्रतिबद्ध के साथ एक संघर्ष मिलता है । मैं संघर्ष को हल करता हूं और छूट जारी रखता हूं। मुझे अपनी तेरहवीं के साथ एक संघर्ष करना है । मैं संघर्ष को हल करता हूं और छूट जारी रखता हूं। मुझे अपने चौदहवें के साथ एक संघर्ष मिलता हैप्रतिबद्ध। मैं संघर्ष को हल करता हूं और छूट जारी रखता हूं। मुझे अपनी पंद्रहवीं प्रतिबद्धता के साथ संघर्ष करना पड़ता है । मैं संघर्ष को हल करता हूं और छूट जारी रखता हूं।

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

आपके द्वारा किए जाने वाले सभी अतिरिक्त संघर्ष समाधान के साथ, यह सिर्फ इस संभावना को बढ़ाता है कि आप एक गलती करेंगे । लेकिन गलतियों को ठीक कर रहे हैं क्योंकि आप पूर्ववत कर सकते हैं, है ना? कोर्स को छोड़कर ...

कारण # 2: छूट के साथ, कोई पूर्ववत नहीं है!

मुझे लगता है कि हम सभी सहमत हो सकते हैं कि संघर्ष समाधान मुश्किल हो सकता है, और यह भी कि कुछ लोग इस पर बहुत बुरे हैं। यह गलतियों के लिए बहुत प्रवण हो सकता है, जो कि यह इतना महान है कि गिट इसे पूर्ववत करना आसान बनाता है!

जब आप एक शाखा को मर्ज करते हैं, तो गिट एक मर्ज कमेट बनाता है जिसे त्याग दिया जा सकता है या संशोधित किया जा सकता है यदि संघर्ष समाधान खराब हो जाता है। यहां तक ​​कि अगर आपने पहले से ही सार्वजनिक / आधिकारिक रेपो के लिए खराब मर्ज कमिटमेंट को धक्का दिया है, तो आप git revertमर्ज द्वारा शुरू किए गए परिवर्तनों को पूर्ववत करने और मर्ज को एक नए मर्ज कमिट में सही तरीके से फिर से करने के लिए उपयोग कर सकते हैं ।

जब आप किसी शाखा को रिब्यू करते हैं, तो संभावित ईवेंट में, जो कि रिज़ॉल्यूशन रिज़ॉल्यूशन गलत किया जाता है, आप खराब हो जाते हैं। हर कमिट में अब ख़राब मर्ज शामिल है, और आप केवल रिबेस * को फिर से नहीं कर सकते। कम से कम, आपको वापस जाना होगा और प्रत्येक प्रभावित कमिट में संशोधन करना होगा। मज़ा नहीं।

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

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

संघर्ष के संकल्प से नरक को बाहर निकालें: diff3 का उपयोग करें

उदाहरण के लिए इस संघर्ष को लें:

<<<<<<< HEAD
TextMessage.send(:include_timestamp => true)
=======
EmailMessage.send(:include_timestamp => false)
>>>>>>> feature-branch

संघर्ष को देखते हुए, यह बताना असंभव है कि प्रत्येक शाखा क्या बदल गई या उसकी मंशा क्या थी। यह मेरी राय में सबसे बड़ा कारण है कि संघर्ष का समाधान भ्रामक और कठिन है।

बचाव के लिए diff3!

git config --global merge.conflictstyle diff3

जब आप diff3 का उपयोग करते हैं, तो प्रत्येक नए संघर्ष में एक 3 खंड होगा, मर्ज किया गया सामान्य पूर्वज।

<<<<<<< HEAD
TextMessage.send(:include_timestamp => true)
||||||| merged common ancestor
EmailMessage.send(:include_timestamp => true)
=======
EmailMessage.send(:include_timestamp => false)
>>>>>>> feature-branch

पहले मर्ज किए गए सामान्य पूर्वजों की जांच करें। फिर प्रत्येक शाखा की मंशा निर्धारित करने के लिए प्रत्येक पक्ष की तुलना करें। आप देख सकते हैं कि HEAD ने EmailMessage को TextMessage में बदल दिया। इसका आशय उसी मापदंडों को पार करते हुए, TextMessage के लिए उपयोग की जाने वाली कक्षा को बदलना है। आप यह भी देख सकते हैं कि फ़ीचर-ब्रांच का इरादा इसके लिए सही के बजाय गलत पास करना है: इन परिवर्तनों को मर्ज करने के लिए, दोनों के इरादे को मिलाएं:

TextMessage.send(:include_timestamp => false)

सामान्य रूप में:

  1. प्रत्येक शाखा के साथ सामान्य पूर्वज की तुलना करें, और निर्धारित करें कि किस शाखा में सबसे सरल परिवर्तन है
  2. कोड की दूसरी शाखा के संस्करण में उस सरल परिवर्तन को लागू करें, ताकि इसमें सरल और अधिक जटिल परिवर्तन दोनों शामिल हों
  3. संघर्ष कोड के सभी वर्गों को एक के अलावा हटा दें जिन्हें आपने केवल एक साथ परिवर्तनों को मर्ज किया है

वैकल्पिक: शाखा के परिवर्तनों को मैन्युअल रूप से लागू करके हल करें

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

कैसे हम जहां विलय एक परिदृश्य में एक संघर्ष का समाधान हो सकता है पर आइए नज़र origin/feature1जहां lib/message.rbविरोध करता है।

  1. यह तय करें कि क्या वर्तमान में हमारी शाखा ( HEADया, --ours) या हमारे द्वारा विलय की जा रही शाखा ( origin/feature1या, --theirs) को लागू करने के लिए एक सरल परिवर्तन है। ट्रिपल डॉट ( git diff a...b) के साथ अंतर का उपयोग करना उन परिवर्तनों को दर्शाता है जो bइसके अंतिम विचलन के बाद से a, या दूसरे शब्दों में, बी के साथ a और b के सामान्य पूर्वज की तुलना करते हैं।

    git diff HEAD...origin/feature1 -- lib/message.rb # show the change in feature1
    git diff origin/feature1...HEAD -- lib/message.rb # show the change in our branch
    
  2. फ़ाइल का अधिक जटिल संस्करण देखें। यह सभी संघर्ष मार्करों को हटा देगा और आपके द्वारा चुने गए पक्ष का उपयोग करेगा।

    git checkout --ours -- lib/message.rb   # if our branch's change is more complicated
    git checkout --theirs -- lib/message.rb # if origin/feature1's change is more complicated
    
  3. जटिल परिवर्तन की जाँच के साथ, सरल परिवर्तन के चरण को बढ़ाएं (चरण 1 देखें)। इसमें से प्रत्येक परिवर्तन को परस्पर विरोधी फ़ाइल में लागू करें।


4
व्यक्तिगत टकरावों की तुलना में एक बार में सभी संघर्षों का विलय कैसे बेहतर होगा? मुझे पहले से ही एकल कमिट्स (विशेषकर ऐसे लोगों से, जो तार्किक भागों में कमिट नहीं करते हैं, और सत्यापन के लिए पर्याप्त परीक्षण प्रदान करते हैं) के विलय से समस्याएं आती हैं। इसके अलावा, रिबेज मर्ज से भी बदतर नहीं है जब बैकअप विकल्पों की बात आती है, तो इंटरएक्टिव रिबेस और इंटेलीजेंट जैसे टूल का उपयोग (जो चयन करने के लिए करता है जिसमें शामिल है) बहुत मदद करेगा।
प्रशान्त

8
मुझे लगता है कि मैंने # 1 में कारण को संबोधित किया। यदि व्यक्तिगत रूप से तार्किक रूप से संगत नहीं है, तो तार्किक रूप से सुसंगत शाखा को मर्ज करने का सभी अधिक कारण है, ताकि आप वास्तव में संघर्ष की भावना बना सकें। अगर कमिट 1 छोटी है और कमिट 2 इसे ठीक करता है, तो कमिट 1 को मर्ज करना भ्रामक होगा। वैध कारण हैं कि आप एक पंक्ति में 15 संघर्ष प्राप्त कर सकते हैं, जैसे कि मैंने ऊपर उल्लिखित किया था। इसके अलावा रिबेज के लिए आपका तर्क कुछ खराब नहीं है। रिबेस खराब मर्ज को अच्छे अच्छे कमिट्स में मिला देता है और फिर से कोशिश करने देने के लिए अच्छे कमिट को इधर-उधर नहीं छोड़ता। मर्ज करता है।
एडवर्ड एंडरसन

6
मैं आपसे पूरी तरह से सहमत हूँ। महान पद; कुछ चीजें साफ करता है। मुझे आश्चर्य है कि अगर फिर भी यहाँ कोई मदद मिलेगी। इसके अलावा, diff3 के उपयोग पर सुझाव के लिए धन्यवाद, मैं निश्चित रूप से उस एक को अभी स्विच करने जा रहा हूं।
Derick

45
+1 मुझे अकेले डिफ 3 के बारे में बताने के लिए - कितनी बार एक असंगत संघर्ष को देख रहा था, जो कोई भी मुझे यह बताने के लिए जिम्मेदार नहीं है कि आम पूर्वज का क्या कहना था। आपका बहुत बहुत धन्यवाद।
जॉन

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

32

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

हालांकि, यहां तक ​​कि ज्यादातर रिबास-आधारित वर्कफ़्लो में, मर्ज के लिए एक जगह है।

याद रखें कि मर्ज वास्तव में एक नोड बनाता है जिसमें दो माता-पिता होते हैं। अब निम्नलिखित स्थिति पर विचार करें: मेरे पास ए और बी दो स्वतंत्र फीचर हैं, और अब फीचर शाखा सी पर सामान विकसित करना चाहते हैं जो ए और बी दोनों पर निर्भर करता है, जबकि ए और बी की समीक्षा की जा रही है।

फिर मैं क्या करता हूं, निम्नलिखित है:

  1. A के ऊपर (और चेकआउट) शाखा C बनाएँ।
  2. इसे B से मिलाएं

अब शाखा सी में ए और बी दोनों से परिवर्तन शामिल हैं, और मैं इस पर विकास जारी रख सकता हूं। यदि मैं A में कोई परिवर्तन करता हूं, तो मैं निम्नलिखित तरीके से शाखाओं के ग्राफ को फिर से बनाता हूं:

  1. A के नए शीर्ष पर शाखा T बनाएं
  2. T को B से मिलाएं
  3. टी पर रिबास सी
  4. शाखा को हटा दें

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


1
आप इसे केवल विद्रोहियों के साथ हासिल कर सकते हैं। मर्ज वास्तव में यहां आवश्यक नहीं है (सिवाय इसके कि अगर आप कमिट्स की नकल नहीं करना चाहते हैं - लेकिन मैं शायद ही एक तर्क के रूप में देखता हूं)।
को'09

1
वास्तव में मैं कमिट की नकल नहीं करना चाहता। मैं अपने काम की इन-फ्लाइट संरचना को यथासंभव स्वच्छ रखना चाहूंगा। लेकिन यह व्यक्तिगत स्वाद की बात है और जरूरी नहीं कि यह हर किसी के लिए सही हो।
एलेक्स गोनमाखेर

मैं पहले पैराग्राफ से 100% सहमत हूं। (@ एडवर्ड का जवाब काम करता है जहां ऐसा नहीं है, लेकिन मैं आपके सुझाव की तरह दुनिया के सभी काम करना चाहूंगा)। उत्तर का बाकी हिस्सा कुछ हद तक समझ में आता है कि A और B प्रगति पर होने पर C पर काम करना पहले से ही जोखिम भरा है (कम से कम यह वास्तव में A और B पर निर्भर करता है), और अंत में भी आप शायद विलय नहीं होगा (सी नवीनतम और सबसे बड़ी के शीर्ष पर छूट मिल जाएगी)।
एलोइस महदाल

22

Git पुश ओरिजनल का उपयोग न करें - किसी भी CIRCUMSTANCE के लिए UNDER ALMOST का उपयोग करें।

यह नहीं पूछता कि क्या आप सुनिश्चित हैं कि आप ऐसा करना चाहते हैं, और आप बेहतर सुनिश्चित होंगे, क्योंकि यह आपकी सभी दूरस्थ शाखाओं को मिटा देगा जो आपके स्थानीय बॉक्स पर नहीं हैं।

http://twitter.com/dysinger/status/1273652486


6
या उन चीजों को न करें जो आप सुनिश्चित नहीं हैं कि परिणाम क्या होगा? एक मशीन Instructions to this machine may lead to unintended consequences, loss of work/data, or even death (at the hands of the sysad). Remember that you are solely responsible for the consequences of your actions जिसे मैं MOTD में प्रशासित करता था।
रिचो

यदि आपके पास मिरर किए गए रेपो हैं, तो इसका उपयोग करें (हालाँकि मेरे मामले में अब इसे पोस्ट-हुक पर स्रोत रेपो में एक विशेष उपयोगकर्ता द्वारा निष्पादित किया जाता है)
prusswan

14

आपके स्पष्टीकरण को पढ़ने के बाद मेरा एक प्रश्न है: क्या ऐसा हो सकता है कि आपने कभी ऐसा नहीं किया हो

git checkout master
git pull origin
git checkout my_new_feature

अपनी सुविधा शाखा में 'गिट रिबेस / मर्ज मास्टर' करने से पहले?

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


13

आपकी स्थिति में मुझे लगता है कि आपका साथी सही है। रिबासिंग के बारे में जो अच्छा है वह यह है कि बाहरी व्यक्ति को आपके परिवर्तन ऐसे लगते हैं जैसे वे सभी एक स्वच्छ अनुक्रम में स्वयं द्वारा किए गए थे। इसका मतलब है की

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

आप अभी भी बैकअप के लिए अपनी निजी विकास शाखा को दूरस्थ रिपॉजिटरी में धकेलना जारी रख सकते हैं, लेकिन दूसरों को यह नहीं मानना ​​चाहिए कि आप "सार्वजनिक" शाखा के रूप में तब से कर रहे हैं जब से आप रिबासिंग करेंगे। BTW, ऐसा करने के लिए एक आसान आदेश है git push --mirror origin

Git का उपयोग करते हुए लेख पैकेजिंग सॉफ्टवेयर एक काफी अच्छा काम करता है जो कि विलय बनाम रिबासिंग में ट्रेड ऑफ की व्याख्या करता है। यह थोड़ा अलग संदर्भ है लेकिन प्रिंसिपल समान हैं - यह मूल रूप से नीचे आता है कि क्या आपकी शाखाएं सार्वजनिक या निजी हैं और आप उन्हें मेनलाइन में कैसे एकीकृत करने की योजना बनाते हैं।


1
Git का उपयोग करके पैकेजिंग सॉफ़्टवेयर का लिंक अब काम नहीं करता है। मुझे मूल उत्तर को संपादित करने के लिए एक अच्छा लिंक नहीं मिला।
चेतन

आपको दर्पण नहीं देना चाहिए origin, आपको तीसरे समर्पित-बैकअप रिपॉजिटरी को दर्पण करना चाहिए।
मिरल

12

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

न तो आपके साथी के और न ही आपके सुझाए गए वर्कफ़्लोज़ में आपको उन संघर्षों के बारे में जानना चाहिए जो समझ में नहीं आया। यहां तक ​​कि अगर आपके पास था, अगर आप सुझाए गए वर्कफ़्लोज़ का पालन कर रहे हैं, तो रिज़ॉल्यूशन के बाद 'मजबूर' पुश की आवश्यकता नहीं होनी चाहिए। यह बताता है कि आपने वास्तव में उस शाखा को मर्ज नहीं किया है, जिस पर आप धक्का दे रहे थे, लेकिन ऐसी शाखा को आगे बढ़ाना पड़ा जो रिमोट टिप का वंशज नहीं थी।

मुझे लगता है कि जो हुआ उसे आपको ध्यान से देखने की जरूरत है। क्या स्थानीय शाखा के निर्माण और उस बिंदु के बीच किसी और (जानबूझकर या नहीं) दूरस्थ मास्टर शाखा को रद्द कर सकते हैं जिस बिंदु पर आपने इसे स्थानीय शाखा में वापस विलय करने का प्रयास किया था?

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


आप अनुमान लगा रहे हैं कि ओपी के पास अपनी प्रक्रिया में कुछ अनदेखा छूट या गलती है, है ना?
क्रोसनवॉल्ड

7

मैंने जो देखा है, उसमें से, मर्ज विलय के बाद भी शाखाओं को अलग रखने के लिए जाता है, जबकि रिबेस तब मर्ज को एक एकल शाखा में जोड़ती है। उत्तरार्द्ध ज्यादा साफ निकलता है, जबकि पूर्व में, यह पता लगाना आसान होगा कि कौन सी शाखा विलय के बाद भी किस शाखा से संबंधित है।


7

"यहां तक ​​कि अगर आप केवल कुछ शाखाओं के साथ एक एकल डेवलपर हैं, तो रिबेट का उपयोग करने और सही तरीके से विलय करने की आदत के लायक है। मूल कार्य पैटर्न जैसा दिखेगा:"

  • मौजूदा शाखा ए से नई शाखा बी बनाएं

  • शाखा B पर परिवर्तन जोड़ें / प्रतिबद्ध करें

  • शाखा ए से अपडेट अपडेट करें

  • शाखा A पर शाखा B से परिवर्तन बदलें "

https://www.atlassian.com/git/tutorials/merging-vs-rebasing/


3

Git के साथ कोई "सही" वर्कफ़्लो नहीं है। अपनी नाव को जो भी तैरता है उसका उपयोग करें। हालाँकि, यदि आप शाखाओं को विलय करते समय लगातार संघर्ष करते हैं तो शायद आपको अपने साथी डेवलपर (ओं) के साथ अपने प्रयासों का बेहतर समन्वय करना चाहिए? लगता है कि आप दोनों एक ही फाइल को संपादित करते रहते हैं। इसके अलावा, व्हॉट्सएप और तोड़फोड़ के कीवर्ड (यानी, "$ Id $" और अन्य)।


0

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

यहां छवि विवरण दर्ज करें

मेरा वर्कफ़्लो आपसे लगभग समान है, लेकिन केवल एक छोटे से अंतर के साथ: मैं squashअपनी स्थानीय शाखा में अपनी शाखा में आने rebaseवाले नवीनतम परिवर्तनों से पहले एक में प्रवेश करता हूं master, क्योंकि:

rebaseप्रत्येक प्रतिबद्ध के आधार पर काम करता है

जिसका अर्थ है, यदि आपके पास 15 उसी तरह की लाइन बदलने के लिए masterहै, जो आपको स्क्वैश नहीं करना है, तो आपको 15 बार जांचना होगा, लेकिन अंतिम परिणाम क्या है?

तो, पूरे वर्कफ़्लो है:

  1. masterयह सुनिश्चित करने के लिए चेकआउट करें और खींचें कि आपके पास नवीनतम संस्करण है

  2. वहां से, एक नई शाखा बनाएं

  3. अपना काम वहां करें, आप स्वतंत्र रूप से कई बार कर सकते हैं, और रिमोट से धक्का दे सकते हैं, कोई चिंता नहीं है, क्योंकि यह आपकी शाखा है।

  4. यदि कोई आपको बताता है, "हे, मेरे पीआर / एमआर को मंजूरी दी गई है, अब इसे मास्टर में विलय कर दिया गया है", तो आप उन्हें ला सकते हैं या उन्हें खींच सकते हैं। आप इसे कभी भी, या चरण 6 में कर सकते हैं।

  5. अपने सभी काम करने के बाद, उन्हें प्रतिबद्ध करें, और यदि आपके पास कई कमिट्स हैं, तो उन्हें स्क्वैश करें (वे आपके सभी काम हैं, और कितनी बार आप कोड की एक पंक्ति को बदलते हैं इससे कोई फर्क नहीं पड़ता; केवल महत्वपूर्ण चीज अंतिम संस्करण है)। इसे धक्का दें या नहीं, इससे कोई फर्क नहीं पड़ता।

  6. चेकआउट करने के लिए master, pullफिर से सुनिश्चित करने के लिए कि आप नवीनतम है masterस्थानीय में। आपका चित्र इस तरह होना चाहिए:

यहां छवि विवरण दर्ज करें

जैसा कि आप देख सकते हैं, आप अपनी स्थानीय शाखा पर हैं, जो एक पुरानी स्थिति से उत्पन्न होती है master, जबकि master(स्थानीय और दूरस्थ दोनों) आपके सहयोगी के परिवर्तनों के साथ आगे बढ़ी है।

  1. अपनी शाखा में वापस चेकआउट करें, और मास्टर को रिबेस करें। अब आपके पास केवल एक ही प्रतिबद्ध होगा, इसलिए आप केवल एक बार संघर्षों को हल करेंगे । (और GitKraken में, आपको केवल अपनी शाखा को master"रेबेस" पर खींचना होगा और एक और कारण चुनना होगा। एक और कारण जो मुझे पसंद है।) उसके बाद, आप होंगे। पसंद:

यहां छवि विवरण दर्ज करें

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

  2. पीआर / एमआर बनाएं और जब तक यह मंजूर न masterहो जाए, तब तक इंतजार करें, इसमें आपका योगदान होगा। बधाई! तो अब आप चेकआउट कर सकते हैं master, अपने परिवर्तनों को खींच सकते हैं, और आरेख को साफ करने के लिए अपनी स्थानीय शाखा को हटा सकते हैं। दूरस्थ शाखा को भी हटा दिया जाना चाहिए, यदि ऐसा नहीं किया जाता है जब आप इसे मास्टर में विलय करते हैं।

अंतिम आरेख साफ और स्पष्ट है:

यहां छवि विवरण दर्ज करें

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