चेरी किस तरह से कमिट्स की रेंज चुनती है और दूसरी ब्रांच में मर्ज होती है?


640

मेरे पास निम्नलिखित रिपॉजिटरी लेआउट है:

  • मास्टर शाखा (उत्पादन)
  • एकीकरण
  • काम कर रहे

मैं जो हासिल करना चाहता हूं, वह है कि काम करने वाली शाखा से कई प्रकार के कमिटमेंट चुनें और इसे एकीकरण शाखा में मिला दें। मैं बहुत नया हूँ और मैं समझ नहीं पा रहा हूँ कि यह कैसे किया जाए (एक ऑपरेशन में कमिटरी की चेरी पिकिंग में विलय नहीं) रिपॉजिटरी को गड़बड़ किए बिना। इस पर कोई संकेत या विचार? धन्यवाद!


जवाबों:


808

जब यह आवागमन की एक सीमा की बात आती है, तो चेरी-पिकिंग है व्यावहारिक नहीं था

जैसा कि कीथ किम द्वारा नीचे उल्लेख किया गया है , Git 1.7.2+ ने कमिट की एक श्रृंखला को चेरी-पिक करने की क्षमता पेश की (लेकिन आपको अभी भी भविष्य के विलय के लिए चेरी-पिकिंग के परिणाम के बारे में पता होना चाहिए )

git चेरी-पिक "ने कई प्रकार के कमिट
(जैसे" cherry-pick A..B"और" cherry-pick --stdin") को चुनना सीखा , इसलिए" git revert"; ये nicer अनुक्रमण नियंत्रण का समर्थन नहीं करते" rebase [-i]"है, हालाँकि।

डेमियन टिप्पणियाँ और हमें चेतावनी देता है:

" cherry-pick A..B" रूप में, Aसे पुराना होना चाहिएB
यदि वे गलत आदेश हैं तो कमांड चुपचाप विफल हो जाएगी

यदि आप (समावेशी) के माध्यम से सीमाBD को चुनना चाहते हैं जो होगा B^..D। एक उदाहरण के रूप में " पिछले कमिट की सीमा से शाखा बनाएं
" देखें ।

जैसा कि जुबब्स ने टिप्पणियों में उल्लेख किया है :

यह मानता है कि Bजड़ नहीं है; unknown revisionअन्यथा आपको " " त्रुटि मिलेगी ।

नोट: Git 2.9.x / 2.10 (Q3 2016) के रूप में, आप एक अनाथ शाखा (खाली सिर) पर सीधे प्रतिबद्ध की एक श्रृंखला को चुन सकते हैं: " मौजूदा शाखा को git में एक अनाथ कैसे बनाएं " देखें।


मूल उत्तर (जनवरी 2010)

एक rebase --ontoबेहतर होगा, जहाँ आप अपने एकीकरण शाखा के शीर्ष पर प्रतिबद्ध की दी गई श्रेणी को पुन: चलाने, के रूप में चार्ल्स बेली यहाँ वर्णित
(यह भी देखें, "यहाँ आप एक शाखा के आधार पर एक विषय शाखा को दूसरे शाखा में कैसे रोपित करेंगे " git rebase man पेज में , व्यावहारिक उदाहरण देखें git rebase --onto)

यदि आपकी वर्तमान शाखा एकीकरण है:

# Checkout a new temporary branch at the current location
git checkout -b tmp

# Move the integration branch to the head of the new patchset
git branch -f integration last_SHA-1_of_working_branch_range

# Rebase the patchset onto tmp, the old location of integration
git rebase --onto tmp first_SHA-1_of_working_branch_range~1 integration

के बीच सब कुछ फिर से खेलना होगा:

  • first_SHA-1_of_working_branch_range(इसलिए ~1) के माता-पिता के बाद : पहली बार आप फिर से खेलना चाहते हैं
  • " integration" तक (जो कि अंतिम बार आपको workingशाखा से फिर से खेलना चाहते हैं ) की ओर इशारा करता है।

को " tmp" (जो integrationइंगित करता है कि पहले कहां इंगित किया गया था)

यदि कोई संघर्ष तब होता है, जब उनमें से एक फिर से शुरू होता है:

  • या तो इसे हल करें और " git rebase --continue" चलाएँ ।
  • या इस पैच को छोड़ें, और इसके बजाय " git rebase --skip" चलाएँ
  • या " git rebase --abort" के साथ सभी चीज़ों को रद्द करें (और integrationशाखा को शाखा में वापस रखें tmp)

उसके बाद rebase --onto, integrationएकीकरण शाखा के अंतिम प्रतिबद्ध पर वापस आ जाएगा (यह " tmp" शाखा + सभी पुनरावृत्त कमिट है)

चेरी-पिकिंग के साथ या rebase --onto, यह मत भूलो कि बाद के मर्ज पर इसके परिणाम हैं, जैसा कि यहां वर्णित है


एक शुद्ध " cherry-pick" समाधान पर यहां चर्चा की गई है , और इसमें कुछ शामिल होगा:

यदि आप एक पैच दृष्टिकोण का उपयोग करना चाहते हैं तो "git format-पैच | git am" और "git cherry" आपके विकल्प हैं।
वर्तमान में, git cherry-pickकेवल एक ही प्रतिबद्ध स्वीकार करता है, लेकिन आप रेंज लेने के लिए चाहते हैं, तो Bके माध्यम से Dहै कि हो सकता है B^..DGit शब्दावली में ऐसा है,

git rev-list --reverse --topo-order B^..D | while read rev 
do 
  git cherry-pick $rev || break 
done 

लेकिन वैसे भी, जब आपको कई प्रकार के कमानों को "रीप्ले" करने की आवश्यकता होती है, तो "रीप्ले" शब्द को आपको rebaseगिट की " " सुविधा का उपयोग करने के लिए धक्का देना चाहिए ।


1
यदि आपके पास ऐसे कमेंट्स हैं, जिनके माता-पिता के पास -mविकल्प की आवश्यकता है , तो आप उन कमेंट्स को कैसे हैंडल करते हैं? या फिर इन कमेंट्स को फिल्टर करने का कोई तरीका है?
अगस्त

@ आप को इस चेरी-पिकिंग के लिए आपके द्वारा चुने -mगए -mपैरामीटर द्वारा संदर्भित मेनलाइन का चयन करके, उन्हें आपके लिए संभालना चाहिए ।
VonC

बात यह है कि यदि आप चेरी को कमिट्स की श्रेणी में रखते हैं, तो यह चेरी को पेरेंट कमिट्स को सही ढंग से चुनता है, लेकिन तब जब यह एक सामान्य कमिट करता है, तो यह विफल हो जाता है और कहता है कि कमिट मर्ज नहीं है। मुझे लगता है कि मेरा सवाल बेहतर ढंग से है कि कैसे यह -mविकल्प पास करने के लिए है जब यह एक माता-पिता को हिट करता है, जब चेरी की रेंज कमिट होती है? अभी अगर मैं इस -mतरह से पास git cherry-pick a87afaaf..asfa789 -m 1होता हूं तो यह सीमा के भीतर सभी कमिटों पर लागू होता है।
अगस्त

@ अजीब बात है, मैं इस मुद्दे को पुन: पेश नहीं किया। आपका git संस्करण क्या है और whayt क्या आप देख रहे सटीक त्रुटि संदेश है?
VonC

आह मैं git संस्करण 2.6.4 (Apple Git-63) चला रहा हूं। मुझे जो त्रुटि दिखाई दे रही है वह कुछ ऐसी होगी जैसे error: Commit 8fcaf3b61823c14674c841ea88c6067dfda3af48 is a merge but no -m option was given.मुझे वास्तव में एहसास हुआ कि आप बस कर सकते हैं git cherry-pick --continueऔर यह ठीक होगा (लेकिन इसमें माता-पिता की प्रतिबद्धता शामिल नहीं होगी)
अगस्त

136

Git के रूप में v1.7.2 चेरी पिक कमिट की एक सीमा को स्वीकार कर सकता है:

git cherry-pickकई प्रकार के कमिट (जैसे cherry-pick A..Bऔर cherry-pick --stdin) लेने के लिए सीखा , ऐसा किया git revert; rebase [-i]हालांकि, नेक्सस अनुक्रमण नियंत्रण का समर्थन नहीं करता है ।


103
ध्यान दें कि cherry-pick A..Bकमिट नहीं मिलेगा A (आपको इसके लिए आवश्यकता होगी A~1..B), और अगर कोई संघर्ष होता है तो git अपने आप रिबेट नहीं करता है (कम से कम 1.7.3.1 के रूप में)
गैबी मुथार्ट

3
यह नोट करना भी अच्छा है कि git cherry-pick A..B Cआप इस तरह से काम नहीं करेंगे जैसे कि आप यह अपेक्षा करते हैं, भोलेपन से। यह सीमा में सब कुछ नहीं उठाएगा A..Bऔर प्रतिबद्ध होगा C! ऐसा करने के लिए, आपको दो लाइनों में विभाजित करने की आवश्यकता है, पहले git cherry-pick A..Bऔर फिर git cherry-pick C। इसलिए, जब भी आपके पास एक सीमा होती है, तो आपको इसे अलग से निष्पादित करने की आवश्यकता होती है।
माइक्रो वायरस

42

मान लें कि आपकी 2 शाखाएँ हैं,

"शाखा": इसमें शामिल हैं कि आप कॉपी करना चाहते हैं ("कमेंट" से "कमिट"

"ब्रांच": वह शाखा जिसे आप चाहते हैं कि "ब्रांच" से स्थानांतरित किया जाए

1)

 git checkout <branchA>

2) "कमिट" और "कमिट" की आईडी प्राप्त करें

3)

git checkout <branchB>

4)

git cherry-pick <commitA>^..<commitB>

5) यदि आपके पास कोई संघर्ष है, तो इसे हल करें और टाइप करें

git cherry-pick --continue

चेरी लेने की प्रक्रिया जारी रखने के लिए।


आकर्षण की तरह काम किया! आपका बहुत बहुत धन्यवाद!
snukone

28

क्या आप वाकई शाखाओं को मर्ज नहीं करना चाहते हैं? यदि काम करने वाली शाखा के पास कुछ हाल के काम हैं जो आप नहीं चाहते हैं, तो आप बस उस बिंदु पर HEAD के साथ एक नई शाखा बना सकते हैं जो आप चाहते हैं।

अब, यदि आप वास्तव में किसी भी कारण से चेरी की एक सीमा को उठाना चाहते हैं, तो ऐसा करने का एक सुंदर तरीका यह है कि आप एक पैचसेट को खींच लें और इसे अपनी नई एकीकरण शाखा में लागू करें:

git format-patch A..B
git checkout integration
git am *.patch

यह अनिवार्य रूप से गिट-रिबास वैसे भी कर रहा है, लेकिन गेम खेलने की आवश्यकता के बिना। आप जोड़ सकते हैं --3wayकरने के लिए git-amयदि आप मर्ज करने के लिए की जरूरत है। सुनिश्चित करें कि निर्देशिका में कोई अन्य * .patch फ़ाइलें पहले से ही नहीं हैं जहाँ आप ऐसा करते हैं, यदि आप निर्देशों का पालन करते हैं ...


1
ध्यान दें कि, अन्य संशोधन श्रेणियों के साथ भी, इसे A^शामिल करने की आवश्यकता है A
गीनो मेम्पिन

9

मैंने VONC के कोड को एक शॉर्ट बैश स्क्रिप्ट में लपेटा git-multi-cherry-pick, आसान रनिंग के लिए:

#!/bin/bash

if [ -z $1 ]; then
    echo "Equivalent to running git-cherry-pick on each of the commits in the range specified.";
    echo "";
    echo "Usage:  $0 start^..end";
    echo "";
    exit 1;
fi

git rev-list --reverse --topo-order $1 | while read rev 
do 
  git cherry-pick $rev || break 
done 

मैं वर्तमान में इसका उपयोग कर रहा हूं क्योंकि मैं एक ऐसे प्रोजेक्ट के इतिहास का पुनर्निर्माण करता हूं जिसमें 3-पार्टी कोड और अनुकूलन दोनों एक ही svn ट्रंक में एक साथ मिश्रित थे। अब मैं आगे जाने वाले अनुकूलन की बेहतर समझ के लिए अपनी स्वयं की गिट शाखाओं पर कोर 3 पार्टी कोड, 3 पार्टी मॉड्यूल और अनुकूलन को अलग कर रहा हूं। git-cherry-pickइस स्थिति में सहायक है क्योंकि मेरे पास एक ही भंडार में दो पेड़ हैं, लेकिन एक साझा पूर्वज के बिना।


3

उपरोक्त सभी विकल्प आपको मर्ज संघर्ष को हल करने के लिए संकेत देंगे। यदि आप किसी टीम के लिए किए गए परिवर्तनों को मर्ज कर रहे हैं, तो डेवलपर्स से मर्ज संघर्ष को हल करना और आगे बढ़ना मुश्किल है। हालांकि, "गिट मर्ज" एक शॉट में मर्ज करेगा लेकिन आप तर्क के रूप में कई संशोधन पारित नहीं कर सकते। हमें रेव्स की मर्ज रेंज करने के लिए "git diff" और "git apply" कमांड का उपयोग करना होगा। मैंने देखा है कि यदि पैच फ़ाइल बहुत अधिक फ़ाइल के लिए अलग है, तो हम विफल हो जाएंगे, इसलिए हमें प्रति फ़ाइल एक पैच बनाना होगा और फिर आवेदन करना होगा। ध्यान दें कि स्क्रिप्ट स्रोत शाखा में हटा दी गई फ़ाइलों को हटाने में सक्षम नहीं होगी। यह एक दुर्लभ मामला है, आप मैन्युअल रूप से ऐसी फ़ाइलों को लक्ष्य शाखा से हटा सकते हैं। यदि यह पैच लागू करने में सक्षम नहीं है, तो "गिट लागू" की निकास स्थिति शून्य नहीं है,

नीचे स्क्रिप्ट है।

enter code here



  #!/bin/bash

    # This script will merge the diff between two git revisions to checked out branch
    # Make sure to cd to git source area and checkout the target branch
    # Make sure that checked out branch is clean run "git reset --hard HEAD"


    START=$1
    END=$2

    echo Start version: $START
    echo End version: $END

    mkdir -p ~/temp
    echo > /tmp/status
    #get files
    git --no-pager  diff  --name-only ${START}..${END} > ~/temp/files
    echo > ~/temp/error.log
    # merge every file
    for file in `cat  ~/temp/files`
    do
      git --no-pager diff --binary ${START}..${END} $file > ~/temp/git-diff
      if [ $? -ne 0 ]
      then
#      Diff usually fail if the file got deleted 
        echo Skipping the merge: git diff command failed for $file >> ~/temp/error.log
        echo Skipping the merge: git diff command failed for $file
        echo "STATUS: FAILED $file" >>  /tmp/status
        echo "STATUS: FAILED $file"
    # skip the merge for this file and continue the merge for others
        rm -f ~/temp/git-diff
        continue
      fi

      git apply  --ignore-space-change --ignore-whitespace  --3way --allow-binary-replacement ~/temp/git-diff

      if [ $? -ne 0 ]
       then
#  apply failed, but it will fall back to 3-way merge, you can ignore this failure
         echo "git apply command filed for $file"
       fi
       echo
       STATUS=`git status -s $file`


       if [ ! "$STATUS" ]
       then
#   status is null if the merged diffs are already present in the target file
         echo "STATUS:NOT_MERGED $file"
         echo "STATUS: NOT_MERGED $file$"  >>  /tmp/status
       else
#     3 way merge is successful
         echo STATUS: $STATUS
         echo "STATUS: $STATUS"  >>  /tmp/status
       fi
    done

    echo GIT merge failed for below listed files

    cat ~/temp/error.log

    echo "Git merge status per file is available in /tmp/status"

2

मैंने कुछ दिनों पहले वॉनक के बहुत स्पष्ट स्पष्टीकरण को पढ़ने के बाद परीक्षण किया है।

मेरे कदम

शुरू

  • शाखा dev: ABCDEFGHIJ
  • शाखा target: एबीसीडी
  • मैं नहीं करना चाहती Eहै और न हीH

शाखा में चरण ई और एच के बिना सुविधाओं को कॉपी करने के लिए कदम dev_feature_wo_E_H

  • git checkout dev
  • git checkout -b dev_feature_wo_E_H
  • git rebase --interactive --rebase-merges --no-ff Dजहाँ मैं और dropसामने के संपादक में सामने रखाEH
  • संघर्षों को हल करें, जारी रखें और commit

शाखा dev_feature_wo_E_Hको लक्ष्य पर कॉपी करने के लिए कदम ।

  • git checkout target
  • git merge --no-ff --no-commit dev_feature_wo_E_H
  • संघर्षों को हल करें, जारी रखें और commit

कुछ टिप्पणी

  • मैंने ऐसा इसलिए किया है क्योंकि cherry-pickपहले के दिनों में बहुत ज्यादा था
  • git cherry-pick शक्तिशाली और सरल है लेकिन

    • यह डुप्लिकेट बनाता है
    • और जब मैं चाहता हूं कि mergeमुझे प्रारंभिक कमिट्स और डुप्लिकेट कॉम्पट के संघर्षों को हल करना है, तो एक या दो के लिए cherry-pick, यह "चेरी-पिकिंग" के लिए ठीक है, लेकिन अधिक के लिए यह बहुत क्रिया है और शाखा बहुत जटिल हो जाएगी
  • मेरे दिमाग में मैंने जो कदम उठाए हैं, वे उससे ज्यादा स्पष्ट हैं git rebase --onto

1
अच्छी पोस्ट। Upvoted। यह मुझे stackoverflow.com/a/38418941/6309 की याद दिलाता है । मैंने 2012 में चेरी-पिकिंग की कमियां वापस लीं: stackoverflow.com/a/13524494/6309
वॉन

1

एक अन्य विकल्प यह हो सकता है कि सीमा से पहले हमारी रणनीति को कमेटी में विलय कर दिया जाए और फिर उस सीमा (या शाखा जब यह अंतिम हो) के अंतिम प्रतिबद्ध के साथ एक 'सामान्य' मर्ज हो जाए। तो मान लें कि केवल 2345 और 3456 मास्टर ऑफ कमेंट्स को फीचर शाखा में विलय कर दिया जाए:

गुरुजी:
1234
2345
3456
4567

सुविधा शाखा में:

git मर्ज -s हमारा ४५६s
git मर्ज 2345
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.