Skip to content
This page has been auto-translated and may contain errors.View in English

शाखाओं को मर्ज करना और conflicts को हल करना

docs.scrimba.com

आपकी feature branch पूरी हो गई है। toggle काम कर रहा है, आपने changes को commit कर दिया है, और अब आप उस काम को main में चाहते हैं जहाँ बाकी टीम का कोड रहता है। ज्यादातर समय इसे लाना तेज़ और शांत होता है: Git दोनों branches की तुलना करता है, कोई overlap नहीं खोजता है, और काम को कोई अतिरिक्त कदम के बिना डाल देता है। कभी-कभी, हालांकि, आप और एक टीम सदस्य अलग-अलग branches पर एक ही लाइनों को बदलते हैं, और Git यह नहीं जान सकता कि आप कौन सा version रखना चाहते हैं। यह स्थिति लगभग हर project में एक से अधिक व्यक्ति के committing में दिखाई देती है। यह branching का एक सामान्य, रोज़मर्रा का हिस्सा है, और इसका मतलब है कि Git को एक ही लाइनों के बारे में दो विचार मिले हैं और वह आपका फैसला चाहता है कि कौन सा जीते।

git merge से एक branch को वापस लाना

मान लें कि आपने Fahrenheit toggle को अपनी स्वयं की branch add-fahrenheit-toggle पर बनाया, और main उस समय के बाद नहीं हिला जब आपने इससे branch बनाई। main पर स्विच करें और git merge को उस branch के नाम के साथ चलाएं जिसे आप लाना चाहते हैं:

bash
$ git switch main
$ git merge add-fahrenheit-toggle
Updating 4f2a891..8c3d1a0
Fast-forward
 src/index.js | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

git merge <branch> हमेशा नामित branch को उस branch में merge करता है जिस पर आप वर्तमान में खड़े हैं, इसलिए पहले main पर स्विच करना महत्वपूर्ण है। जिस branch पर आप खड़े हैं वह वह है जो merge को प्राप्त करता है। इसके चलने के बाद, main के पास add-fahrenheit-toggle का प्रत्येक commit है। feature branch स्वयं untouched है: आप इस पर काम करना जारी रख सकते हैं या अब इसे delete कर सकते हैं क्योंकि इसका काम main पर भी रहता है।

आउटपुट में वह Fast-forward लाइन बारीकी से पढ़ने के लायक है। इसका मतलब है कि main को आपके branch बनाने के बाद से कोई नया commit नहीं मिला, इसलिए Git को कुछ भी combine करने की जरूरत नहीं थी: इसने main लेबल को आगे move कर दिया ताकि यह उसी commit की ओर point करे जो add-fahrenheit-toggle पहले से point कर रहा था। एक fast-forward merge Git है जो एक लेबल को उस जगह पर पकड़ता है जहां इसे पहले से होने की जरूरत थी, अधिक कुछ नहीं।

अगर main को आपके काम करने के समय अन्य commits मिले, मान लीजिए एक टीम सदस्य ने एक bug fix merge किया, तो Git अब लेबल को आगे नहीं बढ़ा सकता, क्योंकि main और आपकी branch आपके अलग होने के बाद अलग-अलग दिशाओं में गई हैं। इसके बजाय यह एक नया commit बनाता है जो दोनों histories को एक साथ जोड़ता है, जिसे merge commit कहा जाता है:

bash
$ git switch main
$ git merge add-fahrenheit-toggle
Merge made by the 'ort' strategy.
 src/index.js | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

इस तरह एक merge के बाद git log --graph --oneline fork और join को दिखाता है: दो history की लाइनें side by side चल रही हैं, merge commit पर वापस मिल रही हैं। न ही outcome आपसे कोई अतिरिक्त चीजें माँगता है। Git तय करता है कि कौन सा लागू होता है इस आधार पर कि branches diverge हुई हैं या नहीं, और किसी भी तरह से आपकी feature अब main का हिस्सा है।

उपरोक्त दोनों results एक ही विचार पर आते हैं: 3-way merge। दो branches को combine करने के लिए, Git उनके दो tips से अधिक की तुलना करता है। यह पहले एक commit खोजता है जो दोनों branches एक सामान्य starting point के रूप में साझा करते हैं, merge base, फिर तीन snapshots देखता है: base, और प्रत्येक branch का tip। साझा base के विरुद्ध प्रत्येक tip की तुलना करना Git को बताता है कि प्रत्येक side ने कौन सी लाइनों को बदला, जो इसे automatically दो sets के edits को combine करने देता है हर बार आपसे पूछने के बजाय।

एक fast-forward उस case है जहां उन तीन snapshots में से एक redundant निकलता है: base और एक tip एक ही commit हैं, इसलिए उस side पर combine करने के लिए कुछ नहीं है, और Git कुछ नया बनाए बिना लेबल को move करता है। एक merge commit सामान्य case है, जहां दोनों sides ने base के बाद कुछ बदला है, और Git एक नया snapshot records करता है जिसके दो parents हैं, एक प्रत्येक branch के history में वापस pointing करता है। हर merge conflict जो आप अगले section में पूरा करते हैं वही same 3-way comparison से आता है जो पाता है कि दोनों sides ने एक ही लाइनों को छुआ है, उन्हें automatically combine करने का कोई तरीका नहीं है।

Junogit merge से एक branch को वापस लानाgit merge branch-name उस branch के commits को उस branch में लाता है जिस पर आप वर्तमान में हैं, इसलिए पहले main पर स्विच करें। ज्यादातर merges silently background में होते हैं और आप अपने दिन के साथ आगे बढ़ते हैं। feature branch में कुछ भी नहीं बदलता; आप इसे use करना जारी रख सकते हैं या एक बार delete कर सकते हैं main के पास काम है।
Junogit merge से एक branch को वापस लाना एक fast-forward का मतलब है main नहीं हिला, इसलिए Git केवल लेबल को आगे बढ़ा दिया। एक बार main को meantime में अन्य commits मिल जाएं, merging एक असली merge commit बनाता है जिसके दो parents हैं। कमांड हर तरह से एक ही git merge branch-name है; Git तय करता है कि कौन सा kind of merge फिट बैठता है।
Junogit merge से एक branch को वापस लाना एक 3-way merge shared base commit की तुलना प्रत्येक branch tip के विरुद्ध करता है ताकि यह काम कर सके कि प्रत्येक side पर क्या बदला गया, जो अधिकांश समय दो branches को combine करना automatic बनाता है। Fast-forward special case है जहां base और एक tip पहले से ही match करते हैं। मैं अभी भी अपने आप को pause करते हुए पकड़ता हूँ एक messy graph पर कौन सा commit base गिनता है यह काम करने के लिए, इसलिए draw it out करें यदि आप अनिश्चित हैं।

एक merge conflict क्या दिखता है

एक conflict तब होता है जब एक merge के दोनों sides पर एक ही लाइनें बदलती हैं, और Git के पास कोई तरीका नहीं है यह बताने के लिए कि आप कौन सा version चाहते हैं। मान लीजिए एक टीम सदस्य एक loading spinner को main में merge करता है जो src/index.js में एक function को बदलता है, और आपकी add-fahrenheit-toggle branch ने toggle जोड़ने के लिए एक ही function को बदल दिया। अब merging halfway through रुक जाता है बजाय समाप्त होने के:

bash
$ git switch main
$ git merge add-fahrenheit-toggle
Auto-merging src/index.js
CONFLICT (content): Merge conflict in src/index.js
Automatic merge failed; fix conflicts and then commit the result.

यह एक merge conflict है। फ़ाइल खोलें और आप पाएंगे कि Git ने ठीक उस जगह को mark किया है जहां दोनों versions असहमत हैं:

<<<<<<< HEAD
  showLoadingSpinner(true);
=======
  const tempF = celsiusToFahrenheit(tempC);
>>>>>>> add-fahrenheit-toggle

<<<<<<< HEAD चिह्नित करता है आपकी branch पर वर्तमान है (इस case में main)। ======= दोनों versions को divide करता है। >>>>>>> add-fahrenheit-toggle incoming branch के version के अंत को चिह्नित करता है। markers के बीच सब कुछ एक ही handful of lines है, दो अलग-अलग तरीकों से लिखी गई।

एक conflict का मतलब Git को आपके judgment की जरूरत है; कुछ भी broken नहीं है। Git को एक ही लाइनों में दो changes मिले और कोई तरीका नहीं है यह अनुमान लगाने का कि आप कौन सा चाहते हैं, इसलिए यह रुकता है और आपसे decide करने के लिए पूछता है। फ़ाइल को edit करें जब तक यह उस तरीके से न पढ़े जो आप चाहते हैं, किसी भी version को रखते हुए, दोनों, या कुछ नया जो उन्हें combine करता है, फिर marker lines को delete करें:

  showLoadingSpinner(true);
  const tempF = celsiusToFahrenheit(tempC);

एक बार फ़ाइल सही लगने लगे, stage और commit करें इसे ठीक किसी अन्य change की तरह:

bash
$ git add src/index.js
$ git commit

यहाँ कोई message के बिना git commit चलाना आपके editor को खोलता है एक message के साथ Git पहले से prepare किया गया है, merge का वर्णन करते हुए। save और close करें, और merge पूरा है।

जब एक conflict open है, git status पहली चीज़ worth checking है। यह हर फ़ाइल को list करता है जिसे अभी भी "Unmerged paths" के अंतर्गत attention की जरूरत है, इसलिए एक बड़े merge पर कई conflicting files के साथ आप exactly जानते हैं कि कितने fix बचे हैं:

bash
$ git status
On branch main
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
	both modified:   src/index.js

git add Git को बताता है एक फ़ाइल का conflict resolve है। यह check नहीं करता कि आपने actually markers को remove किया है, इसलिए इसे stage करने से पहले फ़ाइल को read करें। अगर merge आपकी उम्मीद से messier लगता है, या आपने गलत branch picked किया, git merge --abort completely backs out करता है और आपकी working directory को return करता है कि यह कैसा दिखता था git merge चलाने से पहले, कुछ भी half-finished नहीं बचा।

Conflicts git merge के लिए unique नहीं हैं। Rebase एक line of history को दूसरे के साथ up to date लाने का दूसरा तरीका है, और यह same kind का clash hit करता है, एक अलग outcome के साथ एक बार यह resolve हो जाता है। एक merge दो histories को एक merge commit के साथ tie करता है जिसके दो parents हैं, preserving the fact कि एक branch existed और ठीक कब यह rejoin हुआ। एक rebase इसके बजाय आपके branch के commits को replay करता है, एक समय में, दूसरी branch के tip पर, एक straight line of history produce करते हुए कोई merge commit के साथ नहीं और कोई trace नहीं कि दोनों कभी diverge हुए:

bash
$ git switch add-fahrenheit-toggle
$ git rebase main

trade-off real है। एक linear history from rebase git log में cleanly reads करता है, एक commit के बाद एक, जो कुछ teams prefer करते हैं एक tidy story के लिए। एक merge true shape को keep करता है कि क्या हुआ, including the exact point एक feature branch main में rejoin हुआ, जो कुछ teams prefer करते हैं the accuracy के लिए। न ही choice गलत है; एक convention pick करें per team और consistent रहें।

एक rule hold करता है regardless जो convention आप pick करते हैं: never rebase एक branch अन्य लोगों ने already pulled या उस पर work built किया। Rebase rewrites करता है commits को नए ones में नए IDs के साथ, और एक shared branch का history अगर changes होता है एक collaborator के नीचे, उनकी local copy और rewritten remote एक दूसरे को agree नहीं करते, forcing a manual fix उनके end पर। Rebase freely अपनी स्वयं की branch पर इससे पहले कोई और इसे pull कर ले। एक बार यह shared है, merge करें।

Junoएक merge conflict क्या दिखता है एक merge conflict का मतलब है दो branches ने एक ही लाइनों को बदल दिया, और Git को आपको result pick करने की जरूरत है। फ़ाइल खोलें, <<<<<<<, =======, और >>>>>>> के लिए देखें, edit करें जब तक यह read न करे कि आप कैसे चाहते हैं, फिर उन marker lines को delete करें। git add और git commit के साथ finish करें। मेरा पहला conflict एक emergency की तरह महसूस हुआ; यह Git asking out करता था मुझसे एक fairly ordinary question।
Junoएक merge conflict क्या दिखता हैgit status unmerged paths के अंतर्गत हर unresolved file को list करता है, handy the moment एक conflict से अधिक एक को touch करता है। git add एक file को mark resolve करता है बिना आपके work को check किए, इसलिए staging से पहले इसे read करें। अगर एक merge sideways जाता है, git merge --abort आपको एक clean state में वापस लाता है कुछ भी half-done के साथ नहीं।
Junoएक merge conflict क्या दिखता है Rebase merge के same clashes में run करता है; यह commits को एक नए base पर replay करता है histories को tie करने के बजाय, एक preserved branch shape को trade करते हुए एक straight line के लिए। उस trade को keep करें branches को छोड़कर केवल आप use कर रहे हैं। the moment एक branch shared है, rebase के साथ इसके commits को rewrite करना जीवन को मुश्किल बनाता है किसी के लिए जो पहले से ही इसे pull कर चुका है, इसलिए merge की जगह reach करें।

इसे एक साथ वापस लाना

Merging वह है जो branching को worth करता है: आप safely अपनी स्वयं की line of history पर experiment करते हैं, Branches में covered, फिर उस काम को main में fold करते हैं एक बार यह ready है, conflicts और सभी। GitHub पर, same operation आमतौर पर एक pull request के through होता है बजाय आपकी machine पर local git merge के; pull request flow chapter propose, review, और merge करने को cover करता है एक shared project पर एक change। अगर एक merge कभी आपने intended से कहीं और land करता है आपने पहले से commit किए बाद, undoing things cover करता है कैसे safely back out करें।