2016-02-10 13 views
6

git pull --rebase origin master की मेरी समझ के अनुसार, यह निम्न कमांड चलाने का बराबर होना चाहिए:समझौता "Git पुल --rebase" बनाम "Git rebase"

(from branch master): $ git fetch origin 
(from branch master): $ git rebase origin/master 

मैं इस जहां कुछ मामले पाया है लगते हैं उम्मीद के रूप में काम नहीं करता है।

  • शाखा origin/master संदर्भ शाखा master दूरस्थ origin
  • शाखा master पर origin/master ट्रैक करने के लिए सेट किया गया है, और कई प्रतिबद्ध द्वारा गुरु के पीछे है: मेरे कार्यक्षेत्र में, मैं निम्नलिखित सेटअप है।
  • शाखा feature स्थानीय शाखा master, और master के कई प्रतिबद्धताओं को ट्रैक करने के लिए सेट की गई है।

कभी कभी, मैं करता चरणों

(from branch master): $ git pull --rebase 
(from branch master): $ git checkout feature 
(from branch feature): $ git pull --rebase 

इस बिंदु पर की निम्न क्रम चलाकर, कुछ आगे करता है मैं feature पर था अब खो गया है खो देंगे। अब, अगर मैं अपने स्थिति रीसेट, और बदले निम्न करें:

(from branch feature): $ git reset --hard [email protected]{2} # rewind to before second git pull 
(from branch feature): $ git rebase master 

प्रतिबद्ध सही ढंग से लागू किया गया है और feature पर मेरी नई प्रतिबद्ध अभी भी मौजूद हैं। ऐसा लगता है कि git pull काम करता है, जब तक कि git fetch . मेरी अपेक्षा से कुछ अजनबी नहीं करता है, इस बारे में मेरी समझ का सीधे विरोध करता है।

दुर्भाग्य से, यह सभी कामों के लिए 100% पुनरुत्पादित नहीं है। जब यह प्रतिबद्धता के लिए काम करता है, हालांकि, यह हर बार काम करता है।

नोट: मेरा git pull --rebase वास्तव में --rebase=preserve के रूप में पढ़ा जाना चाहिए, यदि यह महत्वपूर्ण है। मैं अपने ~/.gitconfig में निम्नलिखित है:

[pull] 
    rebase = preserve 
+0

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

+1

मुझे लगता है कि यहां कुछ भ्रम है। मैं 'उत्पत्ति/मास्टर' का पुन: उपयोग नहीं कर रहा हूं, लेकिन मौजूदा शाखा 'मास्टर' को 'मूल/मास्टर' पर पुनर्जीवित कर रहा हूं। मेरी समझ के मुताबिक, अनिवार्य रूप से 'मूल/मास्टर 'की नोक पर' हेड 'लाया जाना चाहिए, और फिर से काम करना चाहिए जो' मास्टर 'की नोक पर शाखा में वापस आ गया था। अनिवार्य रूप से, 'मास्टर' पर नए कामों को दोबारा लिखना जैसे कि वे 'उत्पत्ति/मास्टर' के परिवर्तनों के बाद हुआ। – ashays

+0

गिट का आपका (स्थानीय) संस्करण क्या है? मैं पूछता हूं क्योंकि मुझे याद है (कुछ हद तक अस्पष्ट और अभी तक जांचने के लिए वापस नहीं गए हैं) कि कई 2.x रिलीज के लिए 'गिट पुल' में एक स्वचालित फोर्क पॉइंट रीबेस बग था और संस्करण को जानना थोड़ा आसान हो सकता है। – torek

उत्तर

8

(संपादित करें, 30 नवंबर 2016: भी Why is git rebase discarding my commits? को this answer देखना अब यह कांटा सूत्री विकल्प की वजह से लगभग निश्चित है कि है।।)

वहाँ मैनुअल और pull आधारित git rebase (कम अब 2.7 की तुलना में वहाँ Git git merge-base में --fork-point विकल्प predating के संस्करणों में थे) के बीच कुछ मतभेद हैं। और, मुझे संदेह है कि आपके स्वचालित संरक्षित-विलय शामिल हो सकते हैं। यह सुनिश्चित करना थोड़ा मुश्किल है लेकिन तथ्य यह है कि आपकी स्थानीय शाखा आपकी अन्य स्थानीय शाखा का पालन करती है जो कि पुनः प्राप्त हो रही है, काफी सुझावशाली है। इस बीच, पुराने git pull स्क्रिप्ट को हाल ही में सी में भी लिखा गया था, इसलिए यह देखना मुश्किल है कि यह क्या करता है (हालांकि आप पर्यावरण परिवर्तनीय GIT_TRACE को 1 पर सेट कर सकते हैं ताकि गिट आपको कमांड दिखाए क्योंकि यह आंतरिक रूप से चलता है)।

किसी भी मामले में, वहाँ दो या तीन प्रमुख आइटम यहाँ (आप कैसे गिनती के आधार पर मैं इसे 3 में बना देंगे और इन अलग,) कर रहे हैं:

  • git pull रन git fetch, तो या तो git merge या git rebase प्रति निर्देश, लेकिन जब यह git rebase चलाता है तो यह "अपस्ट्रीम रीबेस से पुनर्प्राप्त" करने के लिए नई फोर्क-पॉइंट मशीनरी का उपयोग करता है।

  • जब git rebase कोई तर्क नहीं है तो इसमें एक विशेष मामला है जो फोर्क-पॉइंट मशीनरी का आह्वान करता है। तर्कों के साथ चलने पर, फोर्क-पॉइंट मशीनरी को तब तक अक्षम कर दिया जाता है जब तक कि --fork-point के साथ स्पष्ट रूप से अनुरोध नहीं किया जाता है।

  • जब git rebase को विलय को संरक्षित करने के लिए निर्देश दिया जाता है, तो यह इंटरैक्टिव रीबेस कोड (गैर-इंटरैक्टिव) का उपयोग करता है। मुझे यकीन नहीं है कि यह वास्तव में यहां मायने रखता है (इसलिए ऊपर "शामिल हो सकता है)। आम तौर पर यह विलय को दूर करता है और केवल इंटरैक्टिव रीबेस स्क्रिप्ट में उन्हें संरक्षित करने के लिए कोड होता है (यह कोड वास्तव में विलय करता है क्योंकि उनके साथ सौदा करने का कोई अन्य तरीका नहीं है)।

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

... - A - B - C - D - E <-- origin/foo 
      \ 
       I - J - K <-- foo 

जहां A और B हैं आप था जब आप अपने शाखा (ताकि B merge- है शुरू कर दिया:

एक सामान्य (जरूरत नहीं कांटा बिंदु सामान) rebase मामले में आप कुछ इस तरह है आधार), CEgit fetch के माध्यम से रिमोट से उठाए गए नए काम हैं, और IK के माध्यम से आपकी खुद की प्रतिबद्धताएं हैं। रीबेस कोड IK के माध्यम से प्रतिलिपि बनाता है, पहली प्रति को E पर जोड़ता है, दूसरा प्रतिलिपि I, और तीसरा से प्रति-0 -।

Git बाहर या आंकड़े के लिए इस्तेमाल किया, वैसे भी जोgit rev-list origin/foo..foo उपयोग करते हुए, यानी, अपने वर्तमान शाखा (foo) के नाम का उपयोग K खोजने के लिए और पीछे की ओर काम करने के लिए नकल करने के लिए प्रतिबद्ध है, और इसकी नदी के ऊपर के नाम (origin/foo) E खोजने के लिए और पीछे की ओर काम करें। पीछे की ओर मार्च मर्ज आधार पर रुक जाता है, इस मामले B में, और की नकल की परिणाम इस प्रकार है:

... - A - B - C - D - E <-- origin/foo 
      \   \ 
      \    I' - J' - K' <-- foo 
      \ 
       I - J - K [[email protected]{1}: reflog for foo] 

इस विधि के साथ समस्या तब होती है जब upstream- origin/foo यहाँ-है ही रिबेस। आइए, उदाहरण के लिए, origin पर किसी ने बल-धक्का दिया ताकि B को एक नई प्रति B' द्वारा अलग-अलग प्रतिबद्ध शब्दों के साथ प्रतिस्थापित किया गया हो (और शायद एक अलग पेड़ भी हो, लेकिन, हमें आशा है कि कुछ भी नहीं जो हमारे I -through- K को प्रभावित करता है)।प्रारंभिक बिंदु अब इस तरह दिखता है:

  B' - C - D - E <-- origin/foo 
     /
... - A - B <-- [origin/[email protected]{n}] 
      \ 
       I - J - K <-- foo 

git rev-list origin/foo..foo का उपयोग करना, हम चुनेंगे करता B, I, J, और K कॉपी करने के लिए, और E हमेशा की तरह के बाद उन पर पेस्ट करने की कोशिश; लेकिन हम B की प्रतिलिपि बनाने के लिए नहीं चाहते हैं क्योंकि यह वास्तव में origin से आया है और इसकी अपनी प्रति B' से प्रतिस्थापित किया गया है।

origin के लिए रीफ्लॉग को देखने के लिए फोर्क पॉइंट कोड क्या होता है यह देखने के लिए कि B कुछ समय तक पहुंच योग्य था या नहीं। यही कारण है, यह नहीं की जाँच करता है बस origin/master, लेकिन यह भी origin/[email protected]{1} (E और B' वापस करने के लिए और फिर A स्कैनिंग खोजने) (B के लिए सीधे ओर इशारा करते हुए, शायद, आप कितनी बार git fetch चलाने के आधार पर), origin/[email protected]{2}, और इतने पर। कोई भी foo पर पहुंचता है जो से पहुंच योग्य हैorigin/[email protected]{n} ग्राफ में सबसे कम आम पूर्वज नोड खोजने में विचार के लिए शामिल किया गया है (यानी, वे सभी मर्ज बेस बनने के विकल्प के रूप में माना जाता है जो git merge-base प्रिंट आउट करता है)।

(यहां एक प्रकार का दोष दिखने लायक है: यह स्वचालित फोर्क पॉइंट डिटेक्शन केवल उन चीजों को ढूंढ सकता है जो रिफ्लॉग प्रविष्टि बनाए रखा गया है, जो इस मामले में 30 दिनों तक डिफ़ॉल्ट है। हालांकि, यह विशेष रूप से नहीं है आपकी समस्या के लिए प्रासंगिक)


आपके मामले में, आप तीन शाखा के नाम (और इसलिए तीन reflogs) शामिल है:।

  • origin/master, जोसे अद्यतन किया जाता है(का पहला कदम अपने git pull जबकि शाखा master)
  • master है, जो (सामान्य प्रतिबद्ध के माध्यम से) दोनों आप से अद्यतन किया जाता है और git rebase (अपने git pull के दूसरे चरण के), और
  • feature, जो दोनों के द्वारा अद्यतन किया जाता है आप (सामान्य प्रतिबद्धताओं के माध्यम से) और git rebase (आपके दूसरेgit pull का दूसरा चरण: आप अपने आप से "लांच" करते हैं, एक नो-ऑप, फिर master पर रीबेस करें)।

दोनों rebases --preserve-merges (इसलिए गैर बातचीत इंटरैक्टिव मोड) और --onto new-tipfork-point, जहां fork-point आईडी प्रतिबद्ध के साथ चलाए जा रहे हैं git merge-base --fork-point upstream-name HEAD चलाकर पाया जाता है। के लिए दूसरा रिबेस master (refs/heads/master) है upstream-name पहले रिबेस के लिएorigin/master (अच्छी तरह से, refs/remotes/origin/master) और upstream-name है।

यह सभी जस्ट वर्क होना चाहिए।अपने पूरी प्रक्रिया के शुरू में ग्राफ प्रतिबद्ध हैं कि तुम क्या वर्णन किया है की तरह कुछ है:

... - A - B <-- master, origin/master 
      \ 
       I - J - K <-- feature 

तो पहले fetch कुछ करता में लाता है और नई टिप करने के लिए origin/master बिंदु बनाता है:

   C - D - E <-- origin/master 
      /
... - A - B <-- master, origin/[email protected]{1} 
      \ 
       I - J - K <-- feature 

और पहली रिबेस तो कॉपी करने के लिए कुछ भी नहीं पाता है (master के मर्ज आधार और B - B = कांटा सूत्री (मास्टर, मूल/गुरु) अभी B -is तो नकल की कोई बात नहीं है), दे रही है:

   C - D - E <-- master, origin/master 
      /
... - A - B <-- [email protected]{1}, origin/[email protected]{1} 
      \ 
       I - J - K <-- feature 

दूसरा fetch स्वयं से है और एक नो-ऑप/पूरी तरह से छोड़ दिया गया है, इसे दूसरे रिबेस में इनपुट के रूप में छोड़ दिया गया है। --onto लक्ष्य master जो प्रतिबद्ध E और HEAD (feature) और master का कांटा सूत्री भी B प्रतिबद्ध है, E हमेशा की तरह के बाद कॉपी करने के लिए I के माध्यम से K करता छोड़ने है।

अगर कुछ प्रतिबद्धताओं को छोड़ दिया जा रहा है, तो इस प्रक्रिया में कुछ गलत हो रहा है, लेकिन मैं नहीं देख सकता।

+2

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

+0

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

+0

@ashays अंतर्निहित समस्या क्या आपको कम करने का कारण बनती है? – mschuett

संबंधित मुद्दे