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


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

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

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

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

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

लेकिन अगर किसी ने उस शाखा में पर्याप्त स्थानीय बदलाव किए हैं तो स्थिति से निपटने में कोई कैसे मदद करता है?


80
2017-11-03 07:08


मूल


साधारण मामला नुस्खा के लिए +1। यह मशीनों के बीच व्यक्तिगत सिंक्रनाइज़ेशन के लिए आदर्श है, खासकर यदि उनके पास अलग-अलग ओएस हैं। यह कुछ ऐसा है जो मैनुअल में उल्लेख किया जाना चाहिए। - Philip Oakley
व्यक्तिगत सिंक्रनाइज़ेशन के लिए आदर्श नुस्खा है git pull --rebase && git push। यदि आप काम करते हैं master केवल तभी, यह आपके लिए सही काम करेगा, भले ही आपने दूसरे छोर पर पश्चाताप किया हो और धक्का दिया हो। - Aristotle Pagaltzis
क्योंकि मैं एक पीसी और एक लिनक्स मशीनों के बीच सिंक्रनाइज़िंग और विकास कर रहा हूं, मुझे लगता है कि हर रिबेस / अपडेट के लिए एक नई शाखा का उपयोग अच्छी तरह से काम करता है। मैं संस्करण का भी उपयोग करता हूं git reset --hard @{upstream}अब मुझे पता है कि "मेरे पास जो कुछ है / भूल गया है, उसके लिए जादू रिफस्पेक इंकेंटेशन, रिमोट से जो मैंने लाया है उसका उपयोग करें" मेरी अंतिम टिप्पणी देखें stackoverflow.com/a/15284176/717355 - Philip Oakley
आप अपनी शाखा की पुरानी उत्पत्ति को खोजने के लिए गिट 2.0 के साथ सक्षम होंगे (अपस्ट्रीम शाखा को एक के साथ फिर से लिखा गया था push -f): देख नीचे मेरा जवाब - VonC


जवाब:


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

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 सबसे हालिया fetch से पहले की ओर इशारा किया जिसने अपना इतिहास बदल दिया।

आप बस बस कर सकते हैं

git rebase --onto origin/foo $ के लिए प्रतिबद्ध foo

72
2017-11-03 07:08



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


मैं कहूंगा अपस्ट्रीम रीबेस से पुनर्प्राप्त गिट-रीबेज मैन पेज के अनुभाग में यह सब कुछ शामिल है।

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


11
2017-11-03 15:39



आह, तो यह करता है। लेकिन हालांकि अब मैं समझता हूं कि यह क्या कहता है, मैं इसे पहले से नहीं ढूंढने से पहले, पहले नहीं था। और कोई कुकबुक नुस्खा नहीं है (शायद इस तरह के दस्तावेज में ठीक है)। मैं यह भी बताऊंगा कि "कठिन मामला" को बुलाकर एफ.यू.डी. मैं प्रस्तुत करता हूं कि पुनर्लेखित इतिहास अधिकांश घर के विकास के पैमाने पर मामूली रूप से प्रबंधनीय है। अंधविश्वासपूर्ण तरीका जिसमें इस विषय का हमेशा इलाज किया जाता है, मुझे परेशान करता है। - Aristotle Pagaltzis
@ एरिस्टोटल: आप सही हैं कि यह बहुत प्रबंधनीय है, यह देखते हुए कि सभी डेवलपर्स जानते हैं कि गिट का उपयोग कैसे करें, और आप सभी डेवलपर्स को प्रभावी रूप से संवाद कर सकते हैं। एक परिपूर्ण दुनिया में, यह कहानी का अंत होगा। लेकिन वहां बहुत सारी परियोजनाएं इतनी बड़ी हैं कि एक अपस्ट्रीम रीबेस वास्तव में एक डरावनी चीज है। (और फिर मेरे कार्यस्थल जैसी जगहें हैं, जहां अधिकांश डेवलपर्स कभी भी नहीं हैं सुना एक रिबेस का।) मुझे लगता है कि "अंधविश्वास" सबसे सुरक्षित, सबसे सामान्य सलाह प्रदान करने का एक तरीका है। कोई भी ऐसा नहीं बनना चाहता जो किसी और के रेपो में आपदा का कारण बनता हो। - Cascabel
हाँ, मैं मकसद समझता हूं। और मैं इसके साथ पूरी तरह से सहमत हूं। लेकिन अगर आप परिणामों को समझ नहीं पाते हैं तो "कोशिश न करें" और "आपको ऐसा कभी नहीं करना चाहिए क्योंकि यह बुरा है", और यह अकेला मैं इसके साथ समस्या उठाता हूं। भय पैदा करने के बजाय निर्देश देना हमेशा बेहतर होता है। - Aristotle Pagaltzis
@ एरिस्टोटल: सहमत मैं यह सुनिश्चित करने की कोशिश करता हूं कि "आप यह सुनिश्चित कर लें कि आप क्या कर रहे हैं" अंत में, लेकिन विशेष रूप से ऑनलाइन, मैं इसे पर्याप्त वजन देने की कोशिश करता हूं ताकि Google का एक आरामदायक विज़िटर ध्यान रखे। आप सही हैं, इसमें से बहुत से शायद नीचे टोन किया जाना चाहिए। - Cascabel


गिट 1.9 / 2.0 क्यू 1 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 अद्यतन के शीर्ष पर rebased किया जा सकता है 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"।


गिट 2.1 (क्यू 3 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*) एक संघर्ष में परिणाम।


10
2017-12-06 11:43



ध्यान दें कि एक गिट पुश - फोर्स अब (गिट 1.8.5) अधिक समझदारी से किया जा सकता है: stackoverflow.com/a/18505634/6309 - VonC