git - गिट विलय के बजाय आप गिट रिबेस का उपयोग कब करते हैं?




version-control git-merge (10)

git rebase बनाम git merge का उपयोग करने की सिफारिश कब की जाती है?

क्या मुझे अभी भी एक सफल रिबेस के बाद विलय करने की ज़रूरत है?


टी एल; डॉ

यदि आपको कोई संदेह है, तो विलय का उपयोग करें।

संक्षिप्त जवाब

एक रिबेस और विलय के बीच केवल अंतर हैं:

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

तो संक्षिप्त जवाब यह है कि आप अपने इतिहास को किस तरह दिखाना चाहते हैं उसके आधार पर रीबेस या विलय करना है

लंबा जवाब

उपयोग करने के लिए कौन सा ऑपरेशन चुनते समय आपको कुछ कारकों पर विचार करना चाहिए।

क्या आपकी शाखा के बाहर अन्य डेवलपर्स के साथ साझा की जाने वाली शाखा (जैसे ओपन सोर्स, पब्लिक)?

यदि ऐसा है, तो rebase मत करो। Rebase शाखा को नष्ट कर देता है और उन डेवलपर्स टूटा / असंगत भंडार होगा जब तक वे git pull --rebase उपयोग नहीं करते हैं। यह अन्य डेवलपर्स को जल्दी परेशान करने का एक अच्छा तरीका है।

आपकी विकास टीम कितनी कुशल है?

रीबेस एक विनाशकारी ऑपरेशन है। इसका मतलब है, यदि आप इसे सही तरीके से लागू नहीं करते हैं, तो आप प्रतिबद्ध काम खो सकते हैं और / या अन्य डेवलपर की रिपॉजिटरीज़ की स्थिरता को तोड़ सकते हैं।

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

क्या शाखा स्वयं उपयोगी जानकारी का प्रतिनिधित्व करती है

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

मैंने टीमों पर भी काम किया है जो शाखा-प्रति-डेवलपर मॉडल का इस्तेमाल करते हैं (हम सब वहाँ रहे हैं)। इस मामले में शाखा स्वयं ही कोई अतिरिक्त जानकारी नहीं देती है (प्रतिबद्धता में पहले से ही लेखक है)। रिबेसिंग में कोई नुकसान नहीं होगा।

क्या आप किसी भी कारण से विलय को वापस करना चाहते हैं?

एक विलय को वापस करने की तुलना में रिवर्टिंग (पूर्ववत करने के रूप में) एक विद्रोह काफी कठिन और / या असंभव है (अगर रिबेस में संघर्ष था)। यदि आपको लगता है कि एक मौका है तो आप वापस करना चाहते हैं तो मर्ज का उपयोग करें।

क्या आप एक टीम पर काम करते हैं? यदि हां, तो क्या आप इस शाखा पर सभी या कुछ भी नहीं लेना चाहते हैं?

रीबेस ऑपरेशन को संबंधित git pull --rebase साथ खींचा जाना चाहिए। यदि आप स्वयं से काम कर रहे हैं तो आप याद कर सकते हैं कि आपको उचित समय पर किस का उपयोग करना चाहिए। यदि आप एक टीम पर काम कर रहे हैं तो समन्वय करना बहुत कठिन होगा। यही कारण है कि अधिकांश रीबेस वर्कफ़्लो सभी विलय के git pull --rebase का उपयोग करने की सलाह देते हैं (और सभी git pull --rebase लिए git pull --rebase )।

सामान्य मिथक

इतिहास नष्ट कर देता है (squashes करता है)

मान लें कि आपके पास निम्न विलय है:

    B -- C
   /      \
  A--------D

कुछ लोग बताएंगे कि विलय प्रतिबद्धता इतिहास को "नष्ट कर देता है" क्योंकि यदि आप केवल मास्टर शाखा (ए-डी) के लॉग को देखना चाहते हैं तो आप बी और सी में निहित महत्वपूर्ण प्रतिबद्ध संदेशों को याद करेंगे।

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

रीबेस सुरक्षित / सरल विलय के लिए अनुमति देता है

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

Rebase कूलर / sexier / अधिक पेशेवर है

यदि आप rm -rf को "समय बचाने" के लिए rm -rf को उपनाम करना चाहते हैं तो शायद आपके लिए रीबेस हो।

मेरे दो सेंट

मैं हमेशा सोचता हूं कि किसी दिन मैं एक परिदृश्य में आऊंगा जहां गिट रिबेस एक अद्भुत उपकरण है जो समस्या को हल करता है। मुझे लगता है कि मुझे लगता है कि मैं एक परिदृश्य में आऊंगा जहां गिट रीफ्लॉग एक शानदार उपकरण है जो मेरी समस्या हल करता है। मैंने अब पांच साल से गिट के साथ काम किया है। ऐसा नहीं हुआ है।

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

अद्यतन (4/2017)

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


लघु संस्करण

  • विलय एक शाखा में सभी परिवर्तन लेता है और उन्हें एक प्रतिबद्धता में एक और शाखा में विलीन करता है।
  • Rebase का कहना है कि मैं उस बिंदु को चाहता हूं जिस पर मैंने एक नए शुरुआती बिंदु पर जाने के लिए ब्रांच किया था

तो आप कब एक का उपयोग करते हैं?

मर्ज

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

rebase

  • एक दूसरा परिदृश्य होगा यदि आपने कुछ विकास करना शुरू किया और फिर एक अन्य डेवलपर ने एक असंबंधित परिवर्तन किया। आप शायद रेपो से वर्तमान संस्करण से अपने परिवर्तनों को आधारित करने के लिए खींचें और फिर पुन : प्रयास करना चाहते हैं।

यह आसान है, रिबेस के साथ आप अपने काम के लिए नए आधार के रूप में एक और शाखा का उपयोग करने के लिए कहते हैं।

यदि आपके पास उदाहरण के लिए एक शाखा master और आप एक नई सुविधा को लागू करने के लिए एक शाखा बनाते हैं, तो कहें कि आप इसे cool-feature नाम cool-feature , बेशक मास्टर शाखा आपकी नई सुविधा का आधार है।

अब एक निश्चित बिंदु पर आप master शाखा में लागू की गई नई सुविधा को जोड़ना चाहते हैं। आप बस master स्विच कर सकते हैं और cool-feature शाखा मर्ज कर cool-feature :

$git checkout master
$git merge cool-feature

लेकिन इस तरह एक नया डमी प्रतिबद्धता जोड़ा जाता है, यदि आप स्पेगेटी-इतिहास से बचना चाहते हैं तो आप रीबेस कर सकते हैं:

$git checkout cool-feature
$git rebase master

और फिर इसे master में विलय करें:

$git checkout master
$git merge cool-feature

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


यह वाक्य यह हो जाता है:

आम तौर पर दोनों दुनिया के सर्वश्रेष्ठ प्राप्त करने का तरीका आपके द्वारा किए गए स्थानीय परिवर्तनों को पुनर्जीवित करना है, लेकिन अपनी कहानी को साफ करने के लिए उन्हें धक्का देने से पहले साझा नहीं किया गया है, लेकिन आपने कहीं भी कहीं भी धक्का नहीं दिया है।

स्रोत: http://www.git-scm.com/book/en/v2/Git-Branching-Rebasing#Rebase-vs.-Merge ब्रांचिंग- रीबेसिंग http://www.git-scm.com/book/en/v2/Git-Branching-Rebasing#Rebase-vs.-Merge Rebase-vs.- http://www.git-scm.com/book/en/v2/Git-Branching-Rebasing#Rebase-vs.-Merge


विलय का अर्थ है: एक नई प्रतिबद्धता बनाएं जो गंतव्य में मेरे परिवर्तनों को विलीन करे।

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

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

उस ने कहा, अगर आप पहले ही शाखा को धक्का दे चुके हैं तो आप अपस्ट्रीम पर काम कर रहे हैं, तो आपको रीबेस नहीं करना चाहिए, बल्कि बदले में विलय करना चाहिए। उन शाखाओं के लिए जिन्हें अपस्ट्रीम, रीबेज, टेस्ट और मर्ज नहीं किया गया है।

एक बार जब आप पुनर्विचार करना चाहते हैं तो वह है जब आप अपस्ट्रीम को धक्का देने से पहले अपनी शाखा से काम करना पसंद करते हैं। उदाहरण के लिए: कम से कम कुछ डिबगिंग कोड पेश करने वाली प्रतिबद्धताएं और अन्य उस कोड को साफ़ करने के लिए आगे बढ़ती हैं। ऐसा करने का एकमात्र तरीका एक इंटरेक्टिव रीबेज कर रहा है: git rebase -i <branch/commit/tag>

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

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

अद्यतन 3: Does one still need to merge after a successful rebase? हाँ आप कीजिए। इसका कारण यह है कि एक रिबेस में अनिवार्य रूप से काम करने का "स्थानांतरण" शामिल होता है। जैसा कि मैंने उपरोक्त कहा है, इन कामों की गणना की जाती है, लेकिन यदि आपके पास शाखाओं के बिंदु से 14 काम करता है, तो मान लें कि आपके रिबेस के साथ कुछ भी गलत नहीं है, तो आप आगे 14 काम करेंगे (जिस बिंदु पर आप पुन: प्रयास कर रहे हैं) rebase किया जाता है। आपके पास एक रिबेस से पहले एक शाखा थी। आपके पास एक ही लंबाई की एक शाखा होगी। आपके परिवर्तनों को प्रकाशित करने से पहले आपको अभी भी विलय करने की आवश्यकता है। दूसरे शब्दों में, जितनी बार चाहें उतनी बार पुन: प्रयास करें (फिर से, केवल तभी जब आपने अपने परिवर्तन अपस्ट्रीम को धक्का नहीं दिया है)। रिबेस के बाद ही विलय करें।


विलय होने पर निश्चित रूप से परिवर्तनों को एकीकृत करने का सबसे आसान और सबसे आम तरीका है, यह केवल एकमात्र नहीं है: रीबेस एकीकरण का वैकल्पिक साधन है।

एक बेहतर बेहतर विलय समझना

जब गिट एक विलय करता है, तो यह तीन काम करता है:

  • (1) आम पूर्वज प्रतिबद्ध यदि आप किसी परियोजना में दो शाखाओं के इतिहास का पालन करते हैं, तो उनके पास हमेशा कम से कम एक प्रतिबद्धता होती है: इस समय, दोनों शाखाओं में एक ही सामग्री थी और फिर अलग-अलग विकसित होती थी।
  • (2) + (3) प्रत्येक शाखा के अंतराल एकीकरण का लक्ष्य दो शाखाओं के मौजूदा राज्यों को गठबंधन करना है। इसलिए, उनके संबंधित नवीनतम संशोधन विशेष रुचि के हैं। इन तीनों कामों का संयोजन करने के परिणामस्वरूप हम एकीकरण का लक्ष्य रखेंगे।

फास्ट फॉरवर्ड या मर्ज कमेट

बहुत ही सरल मामलों में, शाखाओं के बाद से दोनों शाखाओं में से कोई भी नई प्रतिबद्धता नहीं है - इसकी नवीनतम प्रतिबद्धता अभी भी आम पूर्वज है।

इस मामले में, एकीकरण करना मृत सरल है: गिट आम ​​पूर्वजों की प्रतिबद्धता के शीर्ष पर दूसरी शाखा के सभी कामों को जोड़ सकता है। गिट में, एकीकरण के इस सबसे सरल रूप को "फास्ट-फॉरवर्ड" मर्ज कहा जाता है। दोनों शाखाएं तब एक ही इतिहास साझा करती हैं।

हालांकि, कई मामलों में, दोनों शाखाएं व्यक्तिगत रूप से आगे बढ़ीं।

एकीकरण करने के लिए, गिट को एक नई प्रतिबद्धता बनाना होगा जिसमें उनके बीच मतभेद शामिल हों - विलय प्रतिबद्धता।

मानव प्रतिबद्धता और मर्ज कमेटीज़

आम तौर पर, एक इंसान द्वारा एक प्रतिबद्धता सावधानी से बनाई जाती है। यह एक सार्थक इकाई है जो केवल संबंधित परिवर्तनों को लपेटती है और उन्हें टिप्पणी के साथ टिप्पणी करती है।

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

रीबेस के साथ एकीकृत

कुछ लोग इस तरह के स्वचालित विलय प्रतिबद्धताओं के बिना जाना पसंद करते हैं। इसके बजाए, वे परियोजना के इतिहास को देखना चाहते हैं जैसे कि यह एक एकल, सीधी रेखा में विकसित हुआ हो। कोई संकेत नहीं है कि इसे किसी बिंदु पर कई शाखाओं में विभाजित किया गया था।

चलो कदम से एक रिबेस ऑपरेशन चरण के माध्यम से चलते हैं। परिदृश्य पिछले उदाहरणों जैसा ही है: हम शाखा-बी से शाखा-ए में परिवर्तनों को एकीकृत करना चाहते हैं, लेकिन अब रीबेस का उपयोग करके।

हम इसे तीन चरणों में करेंगे

  1. git rebase branch-A // syncs the history with branch-A
  2. git checkout branch-A // change the current branch to branch-A
  3. git merge branch-B // merge/take the changes from branch-B to branch-A

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

इसके बाद, यह शाखा-बी से काम करता है जिसे हम एकीकृत करना चाहते हैं। इस बिंदु पर, दोनों शाखाएं बिल्कुल वही दिखती हैं।

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

आखिरकार आपको एक साफ शाखा शाखा-ए मिलती है जिसमें कोई अवांछित और ऑटो जेनरेट नहीं होता है।

नोट: git-tower द्वारा भयानक post से लिया गया। उसी पद में rebase नुकसान भी एक अच्छा पठन है।


रीबिंग पेज पर वास्तव में अच्छी व्याख्या के रूप में प्रो गिट बुक।

असल में एक विलय 2 काम करेगा और उन्हें गठबंधन करेगा।

एक rebase 2 पर आम पूर्वजों के पास जाएगा और वृद्धि एक दूसरे के शीर्ष पर परिवर्तन लागू करें। यह एक 'क्लीनर' और अधिक रैखिक इतिहास के लिए बनाता है।

लेकिन जब आप रिबेज करते हैं तो आप पिछले कामों को त्याग देते हैं और नए बनाते हैं। तो आपको सार्वजनिक रूप से एक रिपो को कभी भी पुनर्जीवित नहीं करना चाहिए। The other people working on the repo will hate you.

For that reason alone I almost exclusively merge. 99% of the time my branches don't differ that much, so if there are conflicts it's only in one or two places.


Git rebase is used to make the branching paths in history cleaner and repository structure linear.

It is also used to keep the branches created by you private, as after rebasing and pushing the changes to server, if you delete your branch, there will be no evidence of branch you have worked upon. So your branch is now your local concern.

After doing rebase we also get rid of an extra commit which we used to see if we do normal merge.

And yes one still needs to do merge after a successful rebase as rebase command just puts your work on top of the branch you mentioned during rebase say master and makes the first commit of your branch as a direct descendant of the master branch. This means we can now do a fast forward merge to bring changes from this branch to master branch.


This answer is widely oriented around Git Flow . The tables have been generated with the nice ASCII Table Generator , and the history trees with this wonderful command ( aliased as git lg ):

git log --graph --abbrev-commit --decorate --date=format:'%Y-%m-%d %H:%M:%S' --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%ad%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n''          %C(white)%s%C(reset) %C(dim white)- %an%C(reset)'

Tables are in reverse chronological order to be more consistent with the history trees. See also the difference between git merge and git merge --no-ff first (you usually want to use git merge --no-ff as it makes your history look closer to the reality):

git merge

Commands:

Time          Branch "develop"             Branch "features/foo"
------- ------------------------------ -------------------------------
15:04   git merge features/foo
15:03                                  git commit -m "Third commit"
15:02                                  git commit -m "Second commit"
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

परिणाम:

* 142a74a - YYYY-MM-DD 15:03:00 (XX minutes ago) (HEAD -> develop, features/foo)
|           Third commit - Christophe
* 00d848c - YYYY-MM-DD 15:02:00 (XX minutes ago)
|           Second commit - Christophe
* 298e9c5 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git merge --no-ff

Commands:

Time           Branch "develop"              Branch "features/foo"
------- -------------------------------- -------------------------------
15:04   git merge --no-ff features/foo
15:03                                    git commit -m "Third commit"
15:02                                    git commit -m "Second commit"
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

परिणाम:

*   1140d8c - YYYY-MM-DD 15:04:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/foo' - Christophe
| * 69f4a7a - YYYY-MM-DD 15:03:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * 2973183 - YYYY-MM-DD 15:02:00 (XX minutes ago)
|/            Second commit - Christophe
* c173472 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git merge vs git rebase

First point: always merge features into develop, never rebase develop from features . This is a consequence of the Golden Rule of Rebasing :

The golden rule of git rebase is to never use it on public branches.

In other words :

Never rebase anything you've pushed somewhere.

I would personally add: unless it's a feature branch AND you and your team are aware of the consequences .

So the question of git merge vs git rebase applies almost only to the feature branches (in the following examples, --no-ff has always been used when merging). Note that since I'm not sure there's one better solution ( a debate exists ), I'll only provide how both commands behave. In my case, I prefer using git rebase as it produces a nicer history tree :)

Between feature branches

git merge

Commands:

Time           Branch "develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- --------------------------------
15:10   git merge --no-ff features/bar
15:09   git merge --no-ff features/foo
15:08                                                                    git commit -m "Sixth commit"
15:07                                                                    git merge --no-ff features/foo
15:06                                                                    git commit -m "Fifth commit"
15:05                                                                    git commit -m "Fourth commit"
15:04                                    git commit -m "Third commit"
15:03                                    git commit -m "Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

परिणाम:

*   c0a3b89 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 37e933e - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| *   eb5e657 - YYYY-MM-DD 15:07:00 (XX minutes ago)
| |\            Merge branch 'features/foo' into features/bar - Christophe
| * | 2e4086f - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | |           Fifth commit - Christophe
| * | 31e3a60 - YYYY-MM-DD 15:05:00 (XX minutes ago)
| | |           Fourth commit - Christophe
* | |   98b439f - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \ \            Merge branch 'features/foo' - Christophe
| |/ /
|/| /
| |/
| * 6579c9c - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * 3f41d96 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* 14edc68 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git rebase

Commands:

Time           Branch "develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10   git merge --no-ff features/bar
15:09   git merge --no-ff features/foo
15:08                                                                    git commit -m "Sixth commit"
15:07                                                                    git rebase features/foo
15:06                                                                    git commit -m "Fifth commit"
15:05                                                                    git commit -m "Fourth commit"
15:04                                    git commit -m "Third commit"
15:03                                    git commit -m "Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

परिणाम:

*   7a99663 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 708347a - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| * 949ae73 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * 108b4c7 - YYYY-MM-DD 15:05:00 (XX minutes ago)
| |           Fourth commit - Christophe
* |   189de99 - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \            Merge branch 'features/foo' - Christophe
| |/
| * 26835a0 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * a61dd08 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* ae6f5fc - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

From develop to a feature branch

git merge

Commands:

Time           Branch “develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10   git merge --no-ff features/bar
15:09                                                                    git commit -m “Sixth commit"
15:08                                                                    git merge --no-ff development
15:07   git merge --no-ff features/foo
15:06                                                                    git commit -m “Fifth commit"
15:05                                                                    git commit -m “Fourth commit"
15:04                                    git commit -m “Third commit"
15:03                                    git commit -m “Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m “First commit"

परिणाम:

*   9e6311a - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 3ce9128 - YYYY-MM-DD 15:09:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| *   d0cd244 - YYYY-MM-DD 15:08:00 (XX minutes ago)
| |\            Merge branch 'develop' into features/bar - Christophe
| |/
|/|
* |   5bd5f70 - YYYY-MM-DD 15:07:00 (XX minutes ago)
|\ \            Merge branch 'features/foo' - Christophe
| * | 4ef3853 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | |           Third commit - Christophe
| * | 3227253 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ /            Second commit - Christophe
| * b5543a2 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * 5e84b79 - YYYY-MM-DD 15:05:00 (XX minutes ago)
|/            Fourth commit - Christophe
* 2da6d8d - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git rebase

Commands:

Time           Branch “develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10   git merge --no-ff features/bar
15:09                                                                    git commit -m “Sixth commit"
15:08                                                                    git rebase development
15:07   git merge --no-ff features/foo
15:06                                                                    git commit -m “Fifth commit"
15:05                                                                    git commit -m “Fourth commit"
15:04                                    git commit -m “Third commit"
15:03                                    git commit -m “Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m “First commit"

परिणाम:

*   b0f6752 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 621ad5b - YYYY-MM-DD 15:09:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| * 9cb1a16 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * b8ddd19 - YYYY-MM-DD 15:05:00 (XX minutes ago)
|/            Fourth commit - Christophe
*   856433e - YYYY-MM-DD 15:07:00 (XX minutes ago)
|\            Merge branch 'features/foo' - Christophe
| * 694ac81 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * 5fd94d3 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* d01d589 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

Side notes

git cherry-pick

When you just need one specific commit, git cherry-pick is a nice solution (the -x option appends a line that says " (cherry picked from commit...) " to the original commit message body, so it's usually a good idea to use it - git log <commit_sha1> to see it):

Commands:

Time           Branch “develop"              Branch "features/foo"                Branch "features/bar"           
------- -------------------------------- ------------------------------- -----------------------------------------
15:10   git merge --no-ff features/bar                                                                            
15:09   git merge --no-ff features/foo                                                                            
15:08                                                                    git commit -m “Sixth commit"             
15:07                                                                    git cherry-pick -x <second_commit_sha1>  
15:06                                                                    git commit -m “Fifth commit"             
15:05                                                                    git commit -m “Fourth commit"            
15:04                                    git commit -m “Third commit"                                             
15:03                                    git commit -m “Second commit"                                            
15:02   git checkout -b features/bar                                                                              
15:01   git checkout -b features/foo                                                                              
15:00   git commit -m “First commit"                                                                              

परिणाम:

*   50839cd - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 0cda99f - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| * f7d6c47 - YYYY-MM-DD 15:03:00 (XX minutes ago)
| |           Second commit - Christophe
| * dd7d05a - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * d0d759b - YYYY-MM-DD 15:05:00 (XX minutes ago)
| |           Fourth commit - Christophe
* |   1a397c5 - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \            Merge branch 'features/foo' - Christophe
| |/
|/|
| * 0600a72 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * f4c127a - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* 0cf894c - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git pull --rebase

Not sure I can explain it better than Derek Gourlay ... Basically, use git pull --rebase instead of git pull :) What's missing in the article though, is that you can enable it by default :

git config --global pull.rebase true

git rerere

Again, nicely explained here . But put simple, if you enable it, you won't have to resolve the same conflict multiple times anymore.


When do I use git rebase ? Almost never, because it rewrites history. git merge is almost always the preferable choice, because it respects what actually happened in your project.







git-rebase