दिलचस्प पोस्ट
Matplotlib का उपयोग करके छवि को ग्रेस्केल के रूप में प्रदर्शित करें Const और const अस्थिर के बीच का अंतर c ++ getline () कंसोल से इनपुट के लिए इंतजार नहीं कर रहा है, जिसे कई बार कहा जाता है परीक्षण stream.good () या! Stream.eof () पिछली पंक्ति को दो बार पढ़ता है गैर धारावाहिक भागों के साथ जावा सीरियलाइज़ेशन शेबांग नोटेशन: विंडोज और लिनक्स पर पायथन स्क्रिप्ट्स? कैसे पर्यावरण क्रॉन अनुकरण के साथ एक स्क्रिप्ट कार्यान्वित? आईईईई 754 के एनएएन मानों के लिए झूठे लौटने की सभी तुलना के लिए तर्क क्या है? जावास्क्रिप्ट विंडो। केवल तभी खिड़की मौजूद नहीं है जावास्क्रिप्ट कूड़ा संग्रह क्या है? PHP फ़ंक्शन के साथ अपरिभाषित चर समस्या HTML में Base64 छवियों को कैसे प्रदर्शित किया जाए? ओवरराइडिंग बनाम छुपा जावा – उलझन में कैसे iPhone फोटो लाइब्रेरी के लिए तस्वीर को बचाने के लिए? मैं मौजूदा निष्पादित फाइल का पथ पायथन में कैसे प्राप्त करूं?

जीआईटी के "रीबेस – पेरर्स-विलीन" क्या करता है (और क्यों?)

rebase कमांड के लिए गिट का दस्तावेज काफी संक्षिप्त है:

 --preserve-merges Instead of ignoring merges, try to recreate them. This uses the --interactive machinery internally, but combining it with the --interactive option explicitly is generally not a good idea unless you know what you are doing (see BUGS below). 

तो क्या होता है जब आप --preserve-merges उपयोग करते हैं? यह डिफ़ॉल्ट व्यवहार (उस ध्वज के बिना) से कैसे अलग है? एक मर्ज "आदि" को पुनः बनाने का क्या अर्थ है?

वेब के समाधान से एकत्रित समाधान "जीआईटी के "रीबेस – पेरर्स-विलीन" क्या करता है (और क्यों?)"

सामान्य जीआईटी रिबेस के साथ --preserve-merges साथ git सबसे पहले प्रतिबद्ध ग्राफ के एक भाग में किए गए कमिट की एक सूची को पहचानता है, और फिर उन घटकों को दूसरे भाग के शीर्ष पर --preserve-merges करता है। --preserve-merges चिंता के साथ मतभेद जो --preserve-merges लिए चुने गए हैं और मर्ज के लिए काम करने के तरीके को --preserve-merges हैं।

सामान्य और मर्ज-संरक्षण रिबेस के बीच मुख्य अंतर के बारे में और अधिक स्पष्ट होने के लिए:

  • मर्ज-रिजर्व रिबेस रिले (कुछ) मर्ज करने के लिए तैयार है, जबकि सामान्य रीबेस पूरी तरह से मर्ज कमिट की उपेक्षा करते हैं
  • क्योंकि यह मर्ज कमियों को फिर से चलाने के लिए तैयार है, विलय को संरक्षित करने के लिए इसे परिभाषित करना है कि उसे मर्ज कमिट को फिर से चलाने का क्या मतलब है, और कुछ अतिरिक्त झुर्रियों से निपटना है
    • सबसे दिलचस्प हिस्सा, अवधारणात्मक रूप से यह चुनने में है कि नए प्रतिबद्धों की मर्ज करने वाले माता-पिता क्या हो सकते हैं।
    • मर्ज के पुन: चलाने के लिए भी विशेष रूप से विशेष प्रतिबद्धता ( git checkout <desired first parent> ) की जांच करने की आवश्यकता होती है, जबकि सामान्य रीबेस के बारे में चिंता करने की आवश्यकता नहीं होती है
  • मर्ज-रिजर्व रिज़बैक रीप्ले के लिए कमी के सेट को समझता है:
    • विशेष रूप से, यह केवल हाल ही में मर्ज बेस (एस) के बाद से किए गए बदलावों पर विचार करेगा – यानी सबसे हाल ही में दो शाखाएं अलग-थलग हैं – जबकि सामान्य रिजैब फिर से दोबारा शुरू हो सकती है, जब पहली बार दो शाखाएं अलग हो जाएंगी।
    • अनंतिम और अस्पष्ट होने के लिए, मेरा मानना ​​है कि यह अंततः "पुरानी प्रतिबद्धता" को फिर से चलाने के लिए स्क्रीन के माध्यम से एक माध्यम है, जो पहले से ही एक मर्ज कमिट में शामिल किया गया है।

सबसे पहले मैं "पर्याप्त रूप से ठीक" का वर्णन करने के लिए कोशिश --preserve-merges क्या --preserve-merges होता है, और फिर कुछ उदाहरण होंगे एक उदाहरण के साथ शुरू कर सकता है, अगर यह अधिक उपयोगी लगता है

"संक्षिप्त" में एल्गोरिदम

यदि आप वास्तव में मातम में जाना चाहते हैं, तो git स्रोत डाउनलोड करें और फ़ाइल का पता लगाएं git-rebase--interactive.sh (रिबेस गिट के सी कोर का हिस्सा नहीं है, बल्कि इसे बाश में लिखा गया है। और, पर्दे के पीछे, यह "इंटरैक्टिव रिबेस" के साथ कोड साझा करता है।)

लेकिन यहां मैं जो कुछ सोच रहा हूं, उसका संक्षिप्त वर्णन करूँगा। के बारे में सोचने के लिए चीजों की संख्या को कम करने के लिए, मैंने कुछ स्वतंत्रताएं ली हैं (उदाहरण के तौर पर मैं 100% शुद्धता के साथ सटीक आदेश को हासिल करने की कोशिश नहीं करता है, जिसमें कम्प्यूटेशन होते हैं, और कुछ कम-केंद्रीय विषयों को नजरअंदाज करते हैं, उदाहरण के लिए, जो पहले से ही शाखाओं के बीच चेरी उठाए गए हैं, उनके बारे में क्या करना है)।

सबसे पहले, ध्यान दें कि एक गैर-मर्ज-संरक्षण रिबेस बल्कि सरल है यह अधिक या कम है:

 Find all commits on B but not on A ("git log A..B") Reset B to A ("git reset --hard A") Replay all those commits onto B one at a time in order. 

--preserve-merges अपेक्षाकृत जटिल है। यह उतना आसान है जितना मैं इसे बहुत महत्वपूर्ण लगने वाली चीजों को खोने के बिना बनाने में सक्षम हूं:

 Find the commits to replay: First find the merge-base(s) of A and B (ie the most recent common ancestor(s)) This (these) merge base(s) will serve as a root/boundary for the rebase. In particular, we'll take its (their) descendants and replay them on top of new parents Now we can define C, the set of commits to replay. In particular, it's those commits: 1) reachable from B but not A (as in a normal rebase), and ALSO 2) descendants of the merge base(s) If we ignore cherry-picks and other cleverness preserve-merges does, it's more or less: git log A..B --not $(git merge-base --all AB) Replay the commits: Create a branch B_new, on which to replay our commits. Switch to B_new (ie "git checkout B_new") Proceeding parents-before-children (--topo-order), replay each commit c in C on top of B_new: If it's a non-merge commit, cherry-pick as usual (ie "git cherry-pick c") Otherwise it's a merge commit, and we'll construct an "equivalent" merge commit c': To create a merge commit, its parents must exist and we must know what they are. So first, figure out which parents to use for c', by reference to the parents of c: For each parent p_i in parents_of(c): If p_i is one of the merge bases mentioned above: # p_i is one of the "boundary commits" that we no longer want to use as parents For the new commit's ith parent (p_i'), use the HEAD of B_new. Else if p_i is one of the commits being rewritten (ie if p_i is in R): # Note: Because we're moving parents-before-children, a rewritten version # of p_i must already exist. So reuse it: For the new commit's ith parent (p_i'), use the rewritten version of p_i. Otherwise: # p_i is one of the commits that's *not* slated for rewrite. So don't rewrite it For the new commit's ith parent (p_i'), use p_i, ie the old commit's ith parent. Second, actually create the new commit c': Go to p_1'. (ie "git checkout p_1'", p_1' being the "first parent" we want for our new commit) Merge in the other parent(s): For a typical two-parent merge, it's just "git merge p_2'". For an octopus merge, it's "git merge p_2' p_3' p_4' ...". Switch (ie "git reset") B_new to the current commit (ie HEAD), if it's not already there Change the label B to apply to this new branch, rather than the old one. (ie "git reset --hard B") 

एक --onto C तर्क के साथ --onto C बहुत समान होना चाहिए। बस के HEAD पर प्लेबैक शुरू करने के बजाय, आप सी के HEAD पर प्लेबैक करना शुरू करते हैं। (और B_new के बजाय C_new का उपयोग करें।)

उदाहरण 1

उदाहरण के लिए, ग्राफ को ले जाएं

  B---C <-- master / A-------D------E----m----H <-- topic \ / F-------G 

मी अभिभावक ई और जी के साथ एक मर्ज प्रतिबद्ध है

मान लीजिए हम मास्टर (सी) के शीर्ष पर विषय (एच) को एक सामान्य, गैर-मर्ज-संरक्षण रिबेस का उपयोग करके रिसाव किया। (उदाहरण के लिए, चेकआउट विषय; रिबैस मास्टर ।) उस मामले में, git फिर से चलाने के लिए निम्नलिखित कमानों का चयन करेगा:

  • डी चुनें
  • ई चुनें
  • एफ चुनें
  • जी चुनें
  • एच चुनें

और फिर प्रतिबद्ध ग्राफ को इस प्रकार अपडेट करें:

  B---C <-- master / \ A D'---E'---F'---G'---H' <-- topic 

(डी 'डी के पुनरावृत्त समकक्ष है, आदि।)

नोट करें कि मर्ज कमांड मी को पुनरावृत्ति के लिए चुना नहीं गया है

अगर हम इसके बजाय सी के शीर्ष पर एच के --preserve-merges (उदाहरण के लिए, चेकआउट विषय; रिबेस –प्रेसर-मर्ज मास्टर ।) इस नए मामले में, git पुनरावृत्ति के लिए निम्नलिखित कमानों का चयन करेगा:

  • डी चुनें
  • ई चुनें
  • एफ चुनें ('उप-विषय' शाखा में डी 'पर)
  • जी चुनें ('उप-विषय' शाखा में 'एफ' पर)
  • विषय में मर्ज शाखा 'उप-विषय' चुनें
  • एच चुनें

अब एम रिप्ले के लिए चुना गया था यह भी ध्यान रखें कि विलय करने से पहले माता-पिता ई और जी को मर्ज करने के लिए शामिल किए गए थे।

यहाँ परिणामस्वरूप ग्राफ है:

  B---C <-- master / \ A D'-----E'----m'----H' <-- topic \ / F'-------G' 

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

उदाहरण 2

सामान्य रीबेस के विपरीत, विलय-संरक्षण रिबेस अपस्ट्रीम सिर के कई बच्चे बना सकते हैं।

उदाहरण के लिए, विचार करें:

  B---C <-- master / A-------D------E---m----H <-- topic \ | ------- F-----G--/ 

यदि हम (मास्टर) के शीर्ष पर एच (विषय) को रिसाव करते हैं, तो रिबेस के लिए चुने गए कमेट्स निम्न हैं:

  • डी चुनें
  • ई चुनें
  • एफ चुनें
  • जी चुनें
  • मी चुनें
  • एच चुनें

और परिणाम इसी तरह है:

  B---C <-- master / | \ A | D'----E'---m'----H' <-- topic \ | F'----G'---/ 

उदाहरण 3

उपरोक्त उदाहरणों में, मर्ज कमिट और उसके दो माता-पिता दोनों मूल माता-पिता की बजाय कमिट में दोबारा प्रदर्शन करते हैं, मूल मर्ज कमिट में। हालांकि, अन्य रिवाज़ों में एक पुन: चलाया गया मर्ज कमिट माता-पिता के साथ खत्म हो सकता है जो मर्ज से पहले पहले से ही प्रतिबद्ध ग्राफ में थे।

उदाहरण के लिए, विचार करें:

  B--C---D <-- master / \ A---E--m------F <-- topic 

यदि हम मास्टर पर विषय को पुन: प्रस्तुत करते हैं (विलय के संरक्षण के लिए), तो फिर से फिर से खेलना होगा

  • मर्ज कमिट मी चुनें
  • एफ चुनें

रेखांकित प्रतिबद्ध ग्राफ ऐसा दिखेगा:

  B--C--D <-- master / \ A-----E---m'--F'; <-- topic 

यहां मर्ज कमेटी को पुनः चलाया जाता है, जो कि माता-पिता के लिए प्रतिबद्ध ग्राफ में पहले से मौजूद थे, अर्थात् डी (मास्टर की हेड) और ई (मूल मर्ज के माता-पिता में से एक को एम)।

उदाहरण 4

विलय-संरक्षित रिबेस कुछ "खाली प्रतिबद्ध" मामलों में भ्रमित हो सकता है। कम से कम यह केवल git के कुछ पुराने संस्करणों (जैसे 1.7.8।) के लिए सच है

यह प्रतिबद्ध ग्राफ़ लें:

  A--------B-----C-----m2---D <-- master \ \ / E--- F--\--G----/ \ \ ---m1--H <--topic 

ध्यान दें कि दोनों एम 1 और एम 2 के लिए बी और एफ से सभी परिवर्तन शामिल किए होना चाहिए।

अगर हम डी (मास्टर) पर जी (विषय) के git rebase --preserve-merges को करने की कोशिश करते हैं, तो फिर से चलाया जाने के लिए निम्नलिखित कमिट का चयन किया जाता है:

  • एम 1 चुनें
  • एच चुनें

ध्यान दें कि एम 1 में संयुक्त रूप से परिवर्तन (बी, एफ) को डी में शामिल किया जाना चाहिए। (उन बदलावों को पहले से ही एम 2 में शामिल किया जाना चाहिए, क्योंकि एम 2 बी और एफ के बच्चों को मिलाकर मिल जाती है) इसलिए, अवधारणा के अनुसार, एम 1 शीर्ष पर डी शायद या तो कोई नो-ऑप होना चाहिए या एक रिक्त प्रतिबद्ध बनाना होगा (यानी एक जहां लगातार संशोधन के बीच अंतर है)।

इसके बजाय, हालांकि, git डी के शीर्ष पर एम 1 को फिर से चलाने की कोशिश को अस्वीकार कर सकता है। आप ऐसा त्रुटि प्राप्त कर सकते हैं:

 error: Commit 90caf85 is a merge but no -m option was given. fatal: cherry-pick failed 

ऐसा लगता है कि किसी ने गिट को झंडा देना भूल गया, लेकिन अंतर्निहित समस्या यह है कि git खाली कमिट बनाने का नापसंद है