किसी को रिबास या किसी प्रकाशित शाखा को रीसेट करने के बाद मैं कैसे पुनर्प्राप्त / पुन: सिंक्रनाइज़ कर सकता हूं?


88

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

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

एक स्पष्ट समाधान जो मैंने देखा है अगर आपके पास कोई स्थानीय कमिट नहीं है तो यह काम करेगा fooऔर यह छूट देता है:

git fetch
git checkout foo
git reset --hard origin/foo

यह बस fooदूरस्थ रिपॉजिटरी के अनुसार अपने इतिहास के पक्ष में स्थानीय राज्य को दूर फेंक देगा ।

लेकिन अगर कोई उस शाखा पर पर्याप्त स्थानीय परिवर्तन कर चुका है तो स्थिति से कैसे निपटता है?


साधारण केस नुस्खा के लिए +1। यह मशीनों के बीच व्यक्तिगत सिंक्रनाइज़ेशन के लिए आदर्श है, खासकर अगर उनके पास अलग-अलग ओएस हैं। यह कुछ ऐसा है जिसका उल्लेख मैनुअल में किया जाना चाहिए।
फिलिप ओकले

व्यक्तिगत सिंक्रनाइज़ेशन के लिए आदर्श नुस्खा है git pull --rebase && git push। यदि आप masterकेवल काम करते हैं , तो यह बहुत ही निकटता से आपके लिए सही काम करेगा, भले ही आपने विद्रोह किया हो और दूसरे छोर पर धकेल दिया हो।
अरस्तू पगलतज़िस

क्योंकि मैं एक पीसी और एक लिनक्स मशीनों के बीच तालमेल और विकास कर रहा हूं, जो मुझे लगता है कि प्रत्येक रिबास / अपडेट के लिए एक नई शाखा का उपयोग करना अच्छी तरह से काम करता है। मैं भी प्रकार का उपयोग git reset --hard @{upstream}अब मैं के लिए कि जादू refspec जादू जानते हैं कि "भूल मैं क्या है / था, उपयोग मैं से क्या दिलवाया दूरस्थ" करने के लिए अपने अंतिम टिप्पणी देखें stackoverflow.com/a/15284176/717355
फिलिप ओकले

आप अपनी शाखा की पुरानी उत्पत्ति का पता लगाने के लिए, Git2.0 के साथ सक्षम होंगे (अपस्ट्रीम शाखा से पहले फिर से लिखा गया था push -f): नीचे मेरा जवाब देखें
VonC

जवाबों:


75

एक धकेल दिया रिबेस के बाद सिंक में वापस आना वास्तव में ज्यादातर मामलों में जटिल नहीं है।

git checkout foo
git branch old-foo origin/foo # BEFORE fetching!!
git fetch
git rebase --onto origin/foo old-foo foo
git branch -D old-foo

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

रिबासिंग हिंसा की तरह है: यदि यह आपकी समस्या को हल नहीं करता है, तो आपको इसकी अधिक आवश्यकता है। ☺

आप इसे बुकमार्क के बिना कर सकते हैं, यदि आप पूर्व-रीबेज origin/fooकमिट आईडी देखते हैं, और इसका उपयोग करते हैं।

यह भी है कि आप उस स्थिति से कैसे निपटते हैं जहां आप लाने से पहले बुकमार्क बनाना भूल गए थे । कुछ भी नहीं खोया है - आपको बस दूरस्थ शाखा के लिए फिर से जाँच करने की आवश्यकता है:

git reflog show origin/foo | awk '
    PRINT_NEXT==1 { print $1; exit }
    /fetch: forced-update/ { PRINT_NEXT=1 }'

यह उस कमिट आईडी को प्रिंट करेगा, origin/fooजिसने सबसे हाल ही में लाने से पहले अपना इतिहास बदल दिया था।

तुम तो बस कर सकते हो

git rebase --onto origin/foo $commit foo

11
त्वरित ध्यान दें: मुझे लगता है कि यह बहुत सहज है, लेकिन अगर आप अच्छी तरह से नहीं जानते हैं ... तो यह है कि वन-लाइनर git reflog show origin/fooपहली पंक्ति के आउटपुट के माध्यम से देख रहा है, जिसमें कहा गया है: "मजबूर: अद्यतन"; यह तब होता है जब एक ब्रांच रिमोट शाखा को कुछ भी करने के लिए तेजी से आगे बढ़ने के लिए रिकॉर्ड करती है। (आप इसे हाथ से भी कर सकते हैं, - मजबूर अपडेट शायद सबसे हाल की बात है।)
कैसबेल

2
यह हिंसा जैसा कुछ नहीं है। हिंसा कभी-कभी मज़ेदार होती है
Iolo

5
@ वायो सच, रिबासिंग हमेशा मजेदार होता है।
डैन बेचर

1
हिंसा की तरह, लगभग हमेशा पलटाव से बचें। लेकिन एक सुराग है कि कैसे।
बॉब स्टेन

2
खैर, एक रिबेस को आगे बढ़ाने से बचें, जहां दूसरे प्रभावित होंगे।
अरस्तू पगलतज़िस

11

मैं कहूंगा कि गिट-रिबेस मैन पेज के अपस्ट्रीम रिबेज सेक्शन को रिकवर करना इस सब को बहुत कवर करता है।

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


4
आह, तो यह करता है। हालाँकि मैं अब यह समझ गया हूँ कि यह क्या कहता है, मुझे पहले नहीं लगता था, यह पता लगाने से पहले। और कोई कुकबुक नुस्खा नहीं है (शायद इस तरह के प्रलेखन में सही है)। मैं यह भी कहना चाहूंगा कि "कठिन मामला" को कठिन कहना FUD है जो मैं यह कहता हूं कि पुनर्लेखन का इतिहास ज्यादातर घर के विकास के पैमाने पर तुच्छ रूप से प्रबंधनीय है। इस विषय को जिस तरह से अंधविश्वासी माना जाता है, वह मुझे परेशान करता है।
अरस्तू पगलतज़िस

4
@ अरिस्टोटल: आप सही कह रहे हैं कि यह बहुत प्रबंधनीय है, यह देखते हुए कि सभी डेवलपर्स git का उपयोग करना जानते हैं, और यह कि आप सभी डेवलपर्स के लिए प्रभावी रूप से संवाद कर सकते हैं। एक आदर्श दुनिया में, यह कहानी का अंत होगा। लेकिन बहुत सारी परियोजनाएं काफी बड़ी हैं जो वास्तव में एक अपस्ट्रीम रिबेस है जो एक डरावनी बात है। (और फिर मेरे कार्यस्थल जैसी जगहें हैं, जहां अधिकांश डेवलपर्स ने कभी भी रिबास के बारे में नहीं सुना है।) मुझे लगता है कि "अंधविश्वास" सबसे सुरक्षित, सबसे सामान्य सलाह प्रदान करने का एक तरीका है। कोई भी ऐसा नहीं होना चाहता जो किसी और के रेपो में आपदा का कारण बने।
Cascabel

2
हां, मैं मकसद समझता हूं। और मैं इससे पूरी तरह सहमत हूं। लेकिन "यदि आप परिणाम नहीं समझते हैं तो" यह कोशिश न करें और "आपको कभी भी ऐसा नहीं करना चाहिए क्योंकि यह बुराई है", और यह अकेले मैं इस मुद्दे को लेता हूं। डर को भड़काने के बजाय निर्देश देना हमेशा बेहतर होता है।
अरस्तू पगलतज़िस 21

@ एस्ट्रोटल: सहमत। मैं "यह सुनिश्चित करने के लिए कि आप क्या कर रहे हैं, यह सुनिश्चित करने की कोशिश करें कि आप अंत कर रहे हैं", लेकिन विशेष रूप से ऑनलाइन, मैं इसे पर्याप्त वजन देने की कोशिश करता हूं ताकि Google का एक आकस्मिक आगंतुक नोट कर ले। आप सही कह रहे हैं, इसका बहुत कुछ संभवत: टोंड होना चाहिए।
कैसबेल

11

Git 1.9 / 2.0 Q1 2014 के साथ शुरू, आपको अपनी पिछली शाखा की उत्पत्ति को फिर से लिखना होगा इससे पहले कि इसे पुनर्लेखन अपस्ट्रीम शाखा पर लिखा जाए, जैसा कि अरस्तू पगलतज़िस के उत्तर में वर्णित है : प्रतिबद्ध 07d406b
देखें और d96855f प्रतिबद्ध करें :

topicके साथ बनाई गई शाखा पर काम करने के बाद git checkout -b topic origin/master, रिमोट-ट्रैकिंग शाखा का इतिहास origin/masterफिर से निर्मित और पुनर्निर्मित हो सकता है, जिससे इस आकार का इतिहास बन जाएगा:

                   o---B1
                  /
  ---o---o---B2--o---o---o---B (origin/master)
          \
           B3
            \
             Derived (topic)

जहां origin/masterप्रतिबद्ध पर बात करने के लिए इस्तेमाल किया B3, B2, B1और अब यह पर बताते हैं B, और अपने topicसे यह वापस जब शाखा शीर्ष पर शुरू किया गया था origin/masterपर था B3

यह मोड कांटे के बिंदु के रूप में origin/masterखोजने के लिए रिफ्लॉग का उपयोग करता है B3, ताकि topicअपडेट के शीर्ष पर इसे रीबेड किया जा सकेorigin/master :

$ fork_point=$(git merge-base --fork-point origin/master topic)
$ git rebase --onto origin/master $fork_point topic

इसीलिए git merge-baseकमांड में एक नया विकल्प है:

--fork-point::

वह बिंदु ज्ञात करें जिस पर एक शाखा (या कोई इतिहास जो आगे बढ़ता है <commit>) दूसरी शाखा (या किसी संदर्भ) से कांटा गया <ref>
यह केवल दो कॉमन के सामान्य पूर्वजों के लिए नहीं दिखता है, बल्कि यह<ref><commit><ref> देखने के लिए भी ध्यान में रखता है कि क्या इतिहास शाखा के पहले के अवतार से आगे निकल रहा है


" git pull --rebase" कमांड शाखा के कांटे के बिंदु को गणना करता है जिसे " base" शाखा (आमतौर पर एक रिमोट-ट्रैकिंग शाखा) की रिफ्लॉग प्रविष्टियों का उपयोग करके रीबेड किया जा रहा है , शाखा का काम उस स्थिति से निपटने के लिए था जिसमें "आधार" था। शाखा का पुनर्निर्माण और पुनर्निर्माण किया गया है।

उदाहरण के लिए, यदि इतिहास ऐसा दिखता है, जहां:

  • की वर्तमान टिप " base" शाखा में है B, लेकिन पहले मनाया लाना है कि इसकी टिप हुआ करता था B3और फिर B2और फिर B1 , वर्तमान के लिए हो रही करने से पहले और
  • नवीनतम "आधार" के शीर्ष पर पुनरीक्षित होने वाली शाखा प्रतिबद्ध है B3,

यह खोजने की कोशिश करता B3की "उत्पादन के माध्यम से जा द्वारा git rev-list --reflog base" (यानी B, B1, B2, B3) जब तक यह पाता है एक प्रतिबद्ध है कि मौजूदा टिप के एक पूर्वज है " Derived (topic)"।

आंतरिक रूप से, हमारे पास get_merge_bases_many()यह है कि इस की गणना एक बार में की जा सकती है।
हम चाहते हैं कि एक मर्ज-बेस के बीच Derivedऔर एक काल्पनिक मर्ज कमिट हो, जिसके परिणामस्वरूप " base (origin/master)" के सभी ऐतिहासिक सुझावों को मर्ज किया जाएगा ।
जब इस तरह की प्रतिबद्धता मौजूद होती है, तो हमें एक एकल परिणाम प्राप्त करना चाहिए, जो " base" "की रिफ्लॉग प्रविष्टियों में से एक से मेल खाता है ।


Git 2.1 (Q3 2014) इस सुविधा को और अधिक मजबूत बना देगा: जॉन कीपिंग द्वारा प्रतिबद्ध 1e0dacd देखें )johnkeeping

उस परिदृश्य को सही ढंग से हैंडल करें जहां हमारे पास निम्नलिखित टोपोलॉजी है:

    C --- D --- E  <- dev
   /
  B  <- master@{1}
 /
o --- B' --- C* --- D*  <- master

कहाँ पे:

  • B'का एक निश्चित-अप संस्करण है, Bजिसके साथ पैच-समान नहीं है B;
  • C*और D*पैच-समान के लिए कर रहे Cहैं और Dक्रमश: और संघर्ष से टेक्स्ट रूप यदि गलत क्रम में लागू किया;
  • Eपर निर्भर करता है D

का सही परिणाम git rebase master devयह है Bकी कांटा बिंदु के रूप में पहचान की है devऔर master, कि इतने C, D, Eप्रतिबद्ध है कि पर पुनः बजाया कर लिया जाना चाहिए master; लेकिन Cऔर Dपैच-समान के साथ कर रहे हैं C*और D*और इतने छोड़ा जा सकता है, ताकि अंतिम परिणाम है:

o --- B' --- C* --- D* --- E  <- dev

यदि कांटा-बिंदु की पहचान नहीं की जाती है, तो Bएक शाखा में B'परिणाम होता है जिसमें एक संघर्ष होता है और यदि पैच-समान समरूपता की सही पहचान नहीं होती है, तो Cएक शाखा से युक्त D(या समतुल्य D*) एक संघर्ष में परिणाम होता है।


"" का --fork-point"मोड git rebase" वापस आ गया जब कमान को वापस 2.20 युग में सी लिखा गया था, जिसे गिट 2.27 (Q2 2020) के साथ ठीक किया गया है।

देखें f08132f प्रतिबद्ध द्वारा (09 दिसंबर 2019) Junio सी Hamano ( gitster)
(द्वारा विलय Junio सी Hamano - gitster- में fb4175b प्रतिबद्ध , 27 मार्च 2020)

rebase: --fork-pointरिग्रेशन फिक्स

साइन-ऑफ-बाय: एलेक्स टोरोक
[jc: ने सुधार को ठीक किया और एलेक्स के परीक्षणों का उपयोग किया]
हस्ताक्षरित-ऑफ-बाय: जूनियो सी हमानो

" git rebase --fork-point master" मैं ठीक काम करता था, जैसा कि आंतरिक रूप से कहा जाता है " git merge-base --fork-point" यह जानता था कि शॉर्ट रिफनाम को कैसे संभालना है और अंतर्निहित get_fork_point()फ़ंक्शन को कॉल करने से पहले इसे पूर्ण रीनेम पर डाइव करें ।

सी में फिर से लिखे जाने के बाद यह सच नहीं है, क्योंकि इसके इंटरनल कॉल को सीधे तौर पर get_fork_point()छोटा रेफरी नहीं कहा जाता है।

"Git मर्ज-बेस" में उपयोग किए जाने वाले तर्क को "पूर्ण रीफाइन तर्क को dwim डिबेट" में ले जाएं, जो कि अंतर्निहित get_fork_point()फ़ंक्शन के लिए "git मर्ज-बेस" में उपयोग किया जाता है , ताकि "git rebase" के कार्यान्वयन में फ़ंक्शन का अन्य कॉलर ठीक करने के लिए उसी तरह का व्यवहार करता है यह प्रतिगमन।


1
ध्यान दें कि एक git पुश --force अब (git 1.8.5) अधिक विवेकपूर्ण ढंग से किया जा सकता है: stackoverflow.com/a/18505634/6309
VonC
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.