Git में किसी अन्य शाखा से परिवर्तनों का चयन या विलय कैसे करें?


1449

मैं एक नई परियोजना पर git का उपयोग कर रहा हूं जिसमें दो समानांतर हैं - लेकिन वर्तमान में प्रयोगात्मक - विकास शाखाएं:

  • master: मौजूदा कोडबेस के आयात के साथ-साथ कुछ मॉड जो कि मैं आमतौर पर सुनिश्चित करता हूं
  • exp1: प्रयोगात्मक शाखा # 1
  • exp2: प्रयोगात्मक शाखा # 2

exp1और exp2दो बहुत अलग वास्तु दृष्टिकोणों का प्रतिनिधित्व करते हैं। जब तक मैं आगे नहीं बढ़ूंगा, मेरे पास यह जानने का कोई तरीका नहीं है कि कौन सा (यदि या तो) काम करेगा। जैसा कि मैं एक शाखा में प्रगति करता हूं, मेरे पास कभी-कभी ऐसे संपादन होते हैं जो दूसरी शाखा में उपयोगी होंगे और बस उन लोगों को मर्ज करना चाहेंगे।

सब कुछ पीछे छोड़ते हुए एक विकास शाखा से दूसरे में चुनिंदा परिवर्तनों को मर्ज करने का सबसे अच्छा तरीका क्या है?

मेरे विचार से:

  1. git merge --no-commit बड़ी संख्या में संपादन के मैनुअल के बाद मैं शाखाओं के बीच आम नहीं बनाना चाहता।

  2. एक अस्थायी निर्देशिका में आम फाइलों की मैनुअल कॉपी git checkoutऔर उसके बाद दूसरी शाखा में जाने के लिए काम करने वाले पेड़ में अस्थायी निर्देशिका की नकल करना।

  3. उपरोक्त पर एक भिन्नता। expअभी के लिए शाखाओं का त्याग करें और प्रयोग के लिए दो अतिरिक्त स्थानीय रिपोजिटरी का उपयोग करें। यह फ़ाइलों की मैन्युअल प्रतिलिपि को और अधिक सरल बनाता है।

ये तीनों दृष्टिकोण थकाऊ और त्रुटि-प्रवण लगते हैं। मुझे उम्मीद है कि एक बेहतर दृष्टिकोण है; एक फिल्टर पथ पैरामीटर के समान कुछ जो git-mergeअधिक चयनात्मक होगा।


5
यदि आपकी प्रयोगात्मक शाखाओं में परिवर्तन अलग-अलग कमिट में व्यवस्थित हैं, तो चयनात्मक फ़ाइलों के बजाय चयनात्मक कमिट को मर्ज करने के मामले में सोचना बेहतर है । नीचे दिए गए अधिकांश उत्तर यह मानते हैं कि यह मामला है।
एकैहौला

2
क्या git merge -s ours --no-commitइसके बाद कुछ का संयोजन git read-treeअच्छा समाधान नहीं होगा? देखें stackoverflow.com/questions/1214906/…
VONC

34
अधिक हाल के प्रश्न में एक-पंक्ति, अच्छी तरह से लिखित उत्तर है: stackoverflow.com/questions/10784523/…
brahn

केवल विशिष्ट फ़ाइलों को मर्ज करने के लिए इस ब्लॉग को चेकआउट करें jasonrudolph.com/blog/2009/02/25/…
Ashutosh Chamoli

जवाबों:


475

आप एक शाखा से अलग - अलग कमिट प्राप्त करने के लिए चेरी-पिक कमांड का उपयोग करते हैं ।

यदि आप जो बदलाव चाहते हैं, वह व्यक्तिगत कमिट्स में नहीं है, तो कमिट को अलग-अलग कमिट में विभाजित करने के लिए यहां दिखाए गए तरीके का उपयोग करें । मोटे तौर पर, आप git rebase -iसंपादित करने के लिए मूल प्रतिबद्धता प्राप्त करने के लिए उपयोग करते हैं, फिर git reset HEAD^चुनिंदा परिवर्तनों को वापस git commitकरने के लिए , फिर उस बिट को इतिहास में एक नई प्रतिबद्धता के रूप में लागू करने के लिए।

Red Hat मैगज़ीन में यहाँ एक और अच्छा तरीका है , जहाँ वे उपयोग करते हैं git add --patchया संभवतः git add --interactiveजो आपको हंक के सिर्फ कुछ हिस्सों को जोड़ने की अनुमति देते हैं, यदि आप अलग-अलग बदलावों को अलग-अलग फ़ाइल में विभाजित करना चाहते हैं ("विभाजन" के लिए उस पृष्ठ में खोजें)।

परिवर्तनों को विभाजित करने के बाद, अब आप अपने इच्छित लोगों को चुन सकते हैं।


14
मेरी समझ से, यह उच्च-मत वाले उत्तर की तुलना में अनावश्यक रूप से अधिक जटिल है।
अलेक्जेंडर बर्ड

54
यह तकनीकी रूप से सही उत्तर है, सही उत्तर "दृढ़" दिखाई देता है। --- उच्च मतदान का जवाब सिर्फ एक त्वरित और गंदा "चाल है" जवाब है, जो ज्यादातर लोगों के लिए है वे सभी के बारे में हैं:
जैकब

3
@akaihola: HEAD ^ सही है। मैन गेट-रेव-पार्स देखें: संशोधन पैरामीटर में एक प्रत्यय ^ का अर्थ है कि उस प्रतिबद्ध वस्तु का पहला अभिभावक। उपसर्ग ^ संकेतन का उपयोग एक प्रतिबद्ध से आने वाले आवागमन को बाहर करने के लिए किया जाता है।
टायलर रिक

13
: मैं सिर्फ एक और दृष्टिकोण है जो साफ और कम उन सब की घुमावदार लगता साझा करना चाहते थे jasonrudolph.com/blog/2009/02/25/... कुल सादगी और भयानक
superuseroi

14
'सही' किस दृष्टिकोण पर बहस से भ्रमित है? फ़ाइलों और कमिट्स के बीच के अंतर पर विचार करें (नीचे देखें रिमार्क्स) । OP FILES को मर्ज करना चाहता है और COMMITS का उल्लेख नहीं करता है। उच्च-मतदान का जवाब फाइलों के लिए विशिष्ट है; स्वीकृत उत्तर चेरी-पिक का उपयोग करता है, जो कि कमिट के लिए विशिष्ट है। चेरी-पिक चयनात्मक रूप से मर्ज करने के लिए महत्वपूर्ण हो सकता है, लेकिन यह एक शाखा से दूसरी शाखा में फ़ाइलों को स्थानांतरित करने के लिए बहुत दर्दनाक हो सकता है। हालांकि कमिट गिट की ताकत के दिल हैं, मत भूलना अभी भी एक भूमिका है!
Kay V

970

जैसा कि आपने ऊपर बताया था, मुझे ठीक वैसी ही समस्या थी। लेकिन मुझे उत्तर स्पष्ट करने में यह स्पष्ट लगा।

सारांश:

  • जिस शाखा में आप विलय करना चाहते हैं, वहां से पथ चेक करें

    $ git checkout source_branch -- <paths>...
    

    संकेत: यह --लिंक की गई पोस्ट में देखे बिना भी काम करता है ।

  • या चुनिंदा रूप से मर्जों को मर्ज करने के लिए

    $ git checkout -p source_branch -- <paths>...
    

    वैकल्पिक रूप से, रीसेट का उपयोग करें और फिर विकल्प के साथ जोड़ें -p,

    $ git reset <paths>...
    $ git add -p <paths>...
    
  • अंत में कमिट करें

    $ git commit -m "'Merge' these changes"
    

9
बार्ट जे का जुड़ा हुआ लेख सबसे अच्छा तरीका है। स्पष्ट, सरल, एक आदेश। यह एक मैं उपयोग करने वाला हूं। :)
पिस्टन '

256
यह एक वास्तविक मर्ज नहीं है। आप कमिट के बजाय फाइल द्वारा बदलाव कर रहे हैं, और आप किसी भी मौजूदा जानकारी (लेखक, संदेश) को खो देंगे। दी, यह अच्छा है यदि आप कुछ फ़ाइलों में सभी परिवर्तनों को मर्ज करना चाहते हैं और यह ठीक है कि आपको सभी कमिट्स को फिर से करना होगा। लेकिन अगर फ़ाइलों को मर्ज करने के लिए और दूसरों को छोड़ने के लिए दोनों परिवर्तन होते हैं, तो अन्य उत्तरों में दिए गए तरीकों में से एक आपको बेहतर सेवा देगा।
एकैहौला

10
@ ओमखल और अन्य: यह फाइलों को इंडेक्स में स्वचालित रूप से चरणबद्ध foo.cकरता है, इसलिए यदि आपने चेक आउट किया है तो git reset HEAD foo.cउस फाइल को अनस्टेज करें और आप इसे अलग कर सकते हैं। मैंने इसे आजमाने के बाद इसका पता लगाया और इसका जवाब देखने के लिए यहां
आया

12
उन परिवर्तनों को देखने के लिए जिनका आप उपयोग कर सकते हैं:git diff --cached
OderWat

9
इस उत्तर के अनुसार git checkout -p <revision> -- <path>आपके द्वारा वर्णित पहले तीन आदेशों को जारी करने जैसा ही होगा :)
7hi4g0

337

चुनिंदा रूप से फ़ाइलों को एक शाखा से दूसरी शाखा में मर्ज करने के लिए, चलाएं

git merge --no-ff --no-commit branchX

branchXवह शाखा कहां है जिसे आप वर्तमान शाखा में विलय करना चाहते हैं।

--no-commitविकल्प वास्तव में उन्हें करने के बिना फ़ाइलों को Git से मिला दिया गया मंच होगा। यह आपको मर्ज की गई फ़ाइलों को संशोधित करने का अवसर देगा, जो आप चाहते हैं और फिर उन्हें स्वयं करें।

आप फ़ाइलों को कैसे मर्ज करना चाहते हैं, इसके आधार पर, चार मामले हैं:

1) आप एक सही मर्ज चाहते हैं।

इस स्थिति में, आप मर्ज किए गए फ़ाइलों को स्वीकार करते हैं जिस तरह से Git ने उन्हें स्वचालित रूप से मर्ज किया और फिर उन्हें प्रतिबद्ध किया।

2) कुछ फाइलें हैं जिन्हें आप मर्ज नहीं करना चाहते हैं।

उदाहरण के लिए, आप वर्तमान शाखा में संस्करण को बनाए रखना चाहते हैं और जिस शाखा से आप विलय कर रहे हैं, उस संस्करण की उपेक्षा करें।

वर्तमान शाखा में संस्करण का चयन करने के लिए, दौड़ें:

git checkout HEAD file1

यह file1वर्तमान शाखा के संस्करण को पुनः प्राप्त करेगा और file1गिट द्वारा ऑटोमैटरेड को अधिलेखित करेगा ।

3) यदि आप ब्रांच में संस्करण चाहते हैं (और एक सही मर्ज नहीं)।

Daud:

git checkout branchX file1

इस के संस्करण प्राप्त करेंगे file1में branchXऔर अधिलेखित file1Git रूप से स्वत: विलय कर दिया।

4) आखिरी मामला यह है कि क्या आप केवल विशिष्ट मर्ज का चयन करना चाहते हैं file1

इस स्थिति में, आप file1सीधे संशोधित कर सकते हैं, इसे अपडेट कर सकते हैं जो भी आप चाहते हैं कि संस्करण file1बन जाए, और फिर प्रतिबद्ध हो।

यदि Git स्वचालित रूप से किसी फ़ाइल को मर्ज नहीं कर सकता है, तो यह फ़ाइल को " अनमैरिड " के रूप में रिपोर्ट करेगा और एक प्रति उत्पन्न करेगा जहाँ आपको मैन्युअल रूप से विरोधों को हल करने की आवश्यकता होगी।



एक उदाहरण के साथ आगे समझाने के लिए, मान लें कि आप branchXवर्तमान शाखा में विलय करना चाहते हैं :

git merge --no-ff --no-commit branchX

फिर आप git statusसंशोधित फ़ाइलों की स्थिति देखने के लिए कमांड चलाते हैं ।

उदाहरण के लिए:

git status

# On branch master
# Changes to be committed:
#
#       modified:   file1
#       modified:   file2
#       modified:   file3
# Unmerged paths:
#   (use "git add/rm <file>..." as appropriate to mark resolution)
#
#       both modified:      file4
#

कहाँ file1, file2और file3फ़ाइलें हैं git सफलतापूर्वक ऑटो-मर्ज किए गए हैं।

इसका मतलब यह है कि उन सभी फ़ाइलों के लिए masterऔर branchXबिना किसी संघर्ष के संयुक्त रूप से बदलाव किए गए हैं ।

आप यह निरीक्षण कर सकते हैं कि मर्ज को कैसे चलाया गया था git diff --cached;

git diff --cached file1
git diff --cached file2
git diff --cached file3

यदि आपको कुछ मर्ज अवांछनीय लगता है तो आप कर सकते हैं

  1. फ़ाइल को सीधे संपादित करें
  2. सहेजें
  3. git commit

यदि आप विलय नहीं करना चाहते हैं file1और वर्तमान शाखा में संस्करण को बनाए रखना चाहते हैं

Daud

git checkout HEAD file1

यदि आप मर्ज नहीं करना चाहते हैं file2और केवल संस्करण चाहते हैंbranchX

Daud

git checkout branchX file2

यदि आप file3स्वचालित रूप से मर्ज होना चाहते हैं , तो कुछ भी न करें।

इस बिंदु पर Git ने पहले ही विलय कर दिया है।


file4ऊपर Git द्वारा एक विफल मर्ज है। इसका मतलब है कि दोनों शाखाओं में एक ही लाइन पर होने वाले बदलाव हैं। यह वह जगह है जहां आपको मैन्युअल रूप से संघर्षों को हल करने की आवश्यकता होगी। आप फ़ाइल को सीधे संपादित करके या आप जिस शाखा में file4बनना चाहते हैं, उसके संस्करण के लिए चेकआउट कमांड चलाकर मर्ज कर सकते हैं ।


अंत में, के लिए मत भूलना git commit


10
हालांकि सावधान: अगर git merge --no-commit branchXसिर्फ एक फास्ट-फॉरवर्ड है, तो पॉइंटर को अपडेट किया जाएगा, और --नो-कमिट इस प्रकार चुपचाप नजरअंदाज कर दिया जाता है
cfi

16
@cfi --no-ffउस व्यवहार को रोकने के लिए क्या जोड़ना है?
एडुआर्डो कोस्टा

5
मैं निश्चित रूप से एडुआर्डो के "-नो-एफएफ" विकल्प के साथ इस उत्तर को अपडेट करने का सुझाव देता हूं। मैंने पूरी बात पढ़ी (जो अन्यथा बहुत अच्छी थी) केवल मेरा विलय तेजी से आगे बढ़ने के लिए हुआ।
फनक्राटून

7
यह समाधान सर्वोत्तम परिणाम और लचीलापन देता है।
थियागो मकदूनियो

20
अधिकांश मतों के उत्तर के विपरीत, इस समाधान ने मेरे मर्ज के इतिहास को संरक्षित किया, जो मेरे लिए महत्वपूर्ण है क्योंकि मैं शाखाओं के पीछे आंशिक रूप से बुनाई करता हूं। मैंने अन्य सभी सुझाए गए समाधानों की कोशिश नहीं की, इसलिए शायद उनमें से कुछ भी ऐसा करते हैं।
ws_e_c421 12

107

मुझे उपरोक्त दृष्टिकोण पसंद नहीं है। चेरी-पिक का उपयोग करना एकल परिवर्तन को चुनने के लिए बहुत अच्छा है, लेकिन यह एक दर्द है यदि आप कुछ बुरे लोगों को छोड़कर सभी परिवर्तनों को लाना चाहते हैं। यहाँ मेरा दृष्टिकोण है।

कोई --interactiveतर्क नहीं है जिसे आप मर्ज करने के लिए पास कर सकते हैं।

यहाँ विकल्प है:

आपके पास शाखा 'फीचर' में कुछ बदलाव हैं और आप कुछ नहीं बल्कि सभी को 'मास्टर' तक लाना चाहते हैं, न कि फूहड़ तरीके से (यानी आप चेरी को चुनना और हर एक को कमिट नहीं करना चाहते)

git checkout feature
git checkout -b temp
git rebase -i master

# Above will drop you in an editor and pick the changes you want ala:
pick 7266df7 First change
pick 1b3f7df Another change
pick 5bbf56f Last change

# Rebase b44c147..5bbf56f onto b44c147
#
# Commands:
# pick = use commit
# edit = use commit, but stop for amending
# squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

git checkout master
git pull . temp
git branch -d temp

तो बस इतना है कि एक शेल स्क्रिप्ट में, मास्टर को $ में बदलें और फीचर को $ में बदलें और आप जाने के लिए अच्छे हैं:

#!/bin/bash
# git-interactive-merge
from=$1
to=$2
git checkout $from
git checkout -b ${from}_tmp
git rebase -i $to
# Above will drop you in an editor and pick the changes you want
git checkout $to
git pull . ${from}_tmp
git branch -d ${from}_tmp

मैं तय स्वरूपण - यह एक बहुत अच्छा तरीका है, अगर आप प्रतिबद्ध की एक चयन करना चाहते हैं
1800 जानकारी

मैं अब इस तकनीक का उपयोग कर रहा हूँ और ऐसा लगता है कि वास्तव में अच्छी तरह से काम किया है।
dylanfm

4
आप को बदलने के लिए चाहते हो सकता है git rebase -i $toके लिए git rebase -i $to || $SHELL, ताकि उपयोगकर्ता कॉल कर सकते हैं git --skipआदि यदि रिबेस विफल रहता है आवश्यक के रूप में,। इसके अलावा &&newlines के बजाय एक साथ लाइनों का पीछा करने लायक ।
sircolinton

2
दुर्भाग्य से, यह प्रतीत होता है कि उत्तर में लिंक मृत है।
थॉमसडब्ल्यू

न केवल लिंक मृत है, बल्कि इसमें WOT की खराब प्रतिष्ठा चेतावनी है। इसलिए मैंने इसे हटा दिया।
जीन-फ्रांकोइस कॉर्बेट

93

एक और तरीका है:

git checkout -p

यह के बीच एक मिश्रण है git checkoutऔर git add -pऔर काफी हो वास्तव में क्या आप देख रहे हैं हो सकता है:

   -p, --patch
       Interactively select hunks in the difference between the <tree-ish>
       (or the index, if unspecified) and the working tree. The chosen
       hunks are then applied in reverse to the working tree (and if a
       <tree-ish> was specified, the index).

       This means that you can use git checkout -p to selectively discard
       edits from your current working tree. See the “Interactive Mode”
       section of git-add(1) to learn how to operate the --patch mode.

10
यह अब तक का सबसे आसान, सरल तरीका है, जब तक कि आप में विलय करने के लिए केवल परिवर्तन करने योग्य संख्या नहीं है। मुझे आशा है कि अधिक लोग इस उत्तर को नोटिस करेंगे और इसे अपग्रेड करेंगे। उदाहरण: git चेकआउट
टायलर रिक

1
इसी सवाल का जवाब इस पोस्ट पर पोस्ट किया गया: stackoverflow.com/a/11593308/47185
टायलर रिक

ओह, मुझे नहीं पता था कि चेकआउट में पैच था! मैंने इसके बजाय चेकआउट / रीसेट / ऐड-पी किया।
डैनियल सी। सोबरल

2
सचमुच सबसे सरल विधि। git चेकआउट -p फीचरbranch फ़ाइल नाम। और सबसे अच्छी बात यह है कि जब कमांड चलाया जाता है, तो यह आपको ay / n / e /? / ... आदि देता है। फ़ाइल को मर्ज करने का निर्णय लेने का विकल्प। मैं ई के साथ की कोशिश की और मैं भी लागू करने से पहले पैच संपादित कर सकते हैं ... यह कितना अच्छा है। अन्य शाखाओं से चयनात्मक फ़ाइलों को मर्ज करने के लिए एक सच्चे एक लाइनर।
संक्रमित किया

55

हालांकि इनमें से कुछ उत्तर बहुत अच्छे हैं, मुझे ऐसा लगता है कि वास्तव में किसी ने भी ओपी के मूल अवरोध का जवाब नहीं दिया है: विशेष शाखाओं से विशेष फ़ाइलों का चयन करना। यह समाधान ऐसा करता है, लेकिन कई फाइलें होने पर थकाऊ हो सकता है।

कहते हैं कि आप की सुविधा देता है master, exp1और exp2शाखाओं। आप प्रायोगिक शाखाओं में से प्रत्येक में से एक फ़ाइल को मास्टर में मर्ज करना चाहते हैं। मैं ऐसा कुछ करूंगा:

git checkout master
git checkout exp1 path/to/file_a
git checkout exp2 path/to/file_b

# save these files as a stash
git stash
# merge stash with master
git merge stash

यह आपको उन प्रत्येक फाइलों के लिए इन-फाइल में अंतर देगा जो आप चाहते हैं। और कुछ नहीं। कुछ भी कम नहीं। यह उपयोगी है कि आपके पास संस्करणों के बीच मौलिक रूप से भिन्न फ़ाइल परिवर्तन हैं - मेरे मामले में, रेल 2 से रेल 3 में एक ऐप को बदलना।

EDIT : यह फ़ाइलों को मर्ज करेगा, लेकिन एक स्मार्ट मर्ज करता है। मैं यह पता लगाने में सक्षम नहीं था कि इन-फाइल अंतर जानकारी प्राप्त करने के लिए इस पद्धति का उपयोग कैसे करें (शायद यह अभी भी चरम मतभेदों के लिए होगा। जब तक कि आप -s recursive -X ignore-all-spaceविकल्प का उपयोग नहीं करते, व्हाट्सएप जैसी छोटी चीजें वापस विलय हो जाती हैं )


4
यह भी ध्यान दें: आप किसी दिए गए ब्रांच की इनलाइन से कई फाइलें कर सकते हैं, जैसेgit checkout exp1 path/to/file_a path/to/file_x
EMiller

2
ये सुन्दर है। मैंने git checkout feature <path>/*फ़ाइलों के समूह प्राप्त करने के लिए किया ।
isherwood

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

@MightyPork तुम सही हो। दुर्भाग्य से, जब से मैंने इसे बहुत पहले लिखा था, मुझे अब यकीन नहीं है कि "गिट स्ट्रैश" और "गिट मर्ज स्टैश" कदम एक "गिट कमिट" के बजाय वहां क्यों हैं।
एरिक हू

2
ओह, यह स्पष्ट है, मुझे लगता है। इस तरह यह एक फाइल को मर्ज कर देता है, जरूरी नहीं कि टार्गेट ब्रांच पर पिछले बदलावों को ओवरराइट किया जाए।
माइटपॉर्क

48

1800 सूचना का जवाब पूरी तरह से सही है। हालांकि, एक git noob के रूप में, "git cherry-pick का उपयोग करें" मेरे लिए इंटरनेट पर कुछ और अधिक खुदाई के बिना यह पता लगाने के लिए पर्याप्त नहीं था, इसलिए मुझे लगा कि मैं किसी और मामले में अधिक विस्तृत मार्गदर्शिका पोस्ट करूंगा। समान नाव।

मेरे उपयोग का मामला चुनिंदा परिवर्तनों को किसी और की गिथब शाखा से अपने में खींच लेना चाहता था। यदि आपके पास पहले से ही परिवर्तन के साथ एक स्थानीय शाखा है तो आपको केवल चरण 2 और 5-7 करने की आवश्यकता है।

  1. जो परिवर्तन आप लाना चाहते हैं, उसके साथ एक स्थानीय शाखा बनाएँ (यदि नहीं बनाई गई है)।

    $ git branch mybranch <base branch>

  2. इसमें स्विच करें।

    $ git checkout mybranch

  3. दूसरे व्यक्ति के खाते से आपके द्वारा वांछित परिवर्तन नीचे खींचो। यदि आप पहले से नहीं हैं, तो आप उन्हें रिमोट के रूप में जोड़ना चाहेंगे।

    $ git remote add repos-w-changes <git url>

  4. उनकी शाखा से सब कुछ नीचे खींचो।

    $ git pull repos-w-changes branch-i-want

  5. आप कौन से परिवर्तन चाहते हैं, यह देखने के लिए कमिट लॉग देखें:

    $ git log

  6. उस शाखा पर वापस लौटें जिसे आप परिवर्तनों को खींचना चाहते हैं।

    $ git checkout originalbranch

  7. चेरी अपने कमिट्स को, एक-एक करके हैश के साथ चुनें।

    $ git cherry-pick -x hash-of-commit

हैट टिप: http://www.sourcemage.org/Git_Guide


3
युक्ति: पहले git cherryकमांड का उपयोग करें (पहले मैनुअल देखें) यह पहचानने के लिए कि आपने अभी तक विलय नहीं किया है।
एकैहौला

यह काम करता है .. 1. एक नई शाखा बनाई गई। कुछ फ़ाइलों को बनाया / कुछ परिवर्तन किए। 3. प्रतिबद्ध 4. मास्टर शाखा की जाँच करें। 5. चाल चेरी-पिक-एक्स हैश-ऑफ़-कमिट और हल मर्ज संघर्ष आप अच्छे हैं जाना।
रामप्रसाद बिस्मिल

आपका लिंक अब काम नहीं कर रहा है। क्या आप कृपया इसे अपडेट कर सकते हैं?
creep3007

42

यहाँ कैसे आप की जगह ले सकता है Myclass.javaमें फ़ाइल masterके साथ शाखा Myclass.javaमें feature1शाखा। यहां तक ​​कि Myclass.javaमौजूद नहीं होने पर भी यह काम करेगा master

git checkout master
git checkout feature1 Myclass.java

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


6
यह विलय नहीं होगा। यह सिर्फ फीचर 1 शाखा से परिवर्तन के साथ मास्टर पर हुए बदलावों को अधिलेखित करेगा।
स्कंकवॉफले

3
पूरी तरह से, मैं मर्ज की जहां इस तरह के लिए देख रहा था theirsअधिलेखित ours); => +1 चीयर्स
olibre

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

1
सबसे अच्छा समाधान, यह देखते हुए कि ओपी विशेष रूप से पूरी फाइल को दूसरी शाखा पर समकक्ष के साथ बदलना चाहता था:2. Manual copying of common files into a temp directory followed by ...copying out of the temp directory into the working tree.
ब्रेंट फस्ट

29

सरल तरीका, वास्तव में दो शाखाओं से विशिष्ट फ़ाइलों को मर्ज करना , न केवल विशिष्ट फ़ाइलों को किसी अन्य शाखा से लोगों के साथ बदलना।

एक कदम: शाखाओं को फैलाना

git diff branch_b > my_patch_file.patch

वर्तमान शाखा और Branch_b के बीच अंतर का एक पैच फ़ाइल बनाता है

चरण दो: पैटर्न से मेल खाती फाइलों पर पैच लागू करें

git apply -p1 --include=pattern/matching/the/path/to/file/or/folder my_patch_file.patch

विकल्पों पर उपयोगी नोट्स

*शामिल पैटर्न में आप वाइल्डकार्ड के रूप में उपयोग कर सकते हैं ।

स्लैश से बचने की जरूरत नहीं है।

इसके अलावा, आप इसके बजाय --exclude का उपयोग कर सकते हैं और इसे पैटर्न से मेल खाने वाली फ़ाइलों को छोड़कर हर चीज पर लागू कर सकते हैं, या पैच को -RR के साथ उल्टा कर सकते हैं

-P1 विकल्प * यूनिक्स पैच आदेश से एक पकड़ मिली थी और तथ्य यह है कि पैच फ़ाइल की सामग्री के साथ प्रत्येक फ़ाइल नाम पहले जोड़ें है a/या b/(या अधिक कैसे पैच फ़ाइल जनरेट किया गया था पर निर्भर करता है), जो आपको लगता है कि यह पता लगा सकते हैं, ताकि पट्टी की जरूरत है पैच करने के लिए लागू किया जाना चाहिए फ़ाइल के लिए पथ के लिए असली फ़ाइल।

अधिक विकल्पों के लिए git-apply के लिए मैन पेज देखें।

चरण तीन: कोई चरण तीन नहीं है

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


1
यह बहुत उपयोगी था जहां current_branch में बहुत सारे "अतिरिक्त" परिवर्तन थे जिन्हें संरक्षित करने की आवश्यकता थी। केवल ब्रांच_ बी द्वारा लाए गए परिवर्तनों के रूप को इस रूप में समझें: git diff HEAD ... ब्रांच_ब (हाँ - तीन अवधि मैजिक करता है)।
साद मलिक

@masukomi, चरण 2 पर, क्या आपको चरण 1 में बनाई गई पैच-फ़ाइल को एक तर्क के रूप में नहीं जोड़ना चाहिए?
स्पिरालिस

मेरे लिए, सभी परिवर्तनों को अस्वीकार कर दिया जाता है। कोई विचार क्यों?
LinusGeffarth

प्रारंभिक विचार @LinusGeffarth यह है कि शायद आपको पैच बनाते समय शाखाएं पीछे की ओर मिली थीं? यह देखने के लिए कि क्या हम इसे समझ सकते हैं, एसओ के बाहर फॉलोअप करेंगे।
मसुकोमी

24

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

सबसे पहले, आप पहले से घोषित करने का असामान्य कदम उठाएंगे कि आप क्या करने जा रहे हैं, यह एक मर्ज है, बिना अपनी कार्यशील निर्देशिका में फ़ाइलों को कुछ भी किए बिना:

git merge --no-ff --no-commit -s ours branchname1

। । । जहाँ "ब्रांचनाम" ​​आप से विलय करने का दावा करते हैं। यदि आप तुरंत ही अपराध करना चाहते हैं, तो यह कोई बदलाव नहीं करेगा, लेकिन यह अभी भी दूसरी शाखा से वंश को दिखाएगा। आप अधिक शाखाएँ / टैग / आदि जोड़ सकते हैं। कमांड लाइन के लिए यदि आप की जरूरत है, साथ ही। इस बिंदु पर, हालांकि, कोई बदलाव करने के लिए नहीं हैं, इसलिए अन्य संशोधनों से फाइलें प्राप्त करें, अगले।

git checkout branchname1 -- file1 file2 etc

यदि आप एक से अधिक अन्य शाखा से विलय कर रहे थे, तो आवश्यकतानुसार दोहराएं।

git checkout branchname2 -- file3 file4 etc

अब दूसरी ब्रांच की फाइलें इंडेक्स में हैं, जो इतिहास के साथ प्रतिबद्ध होने के लिए तैयार हैं।

git commit

और आपको उस प्रतिबद्ध संदेश में करने के लिए बहुत कुछ समझाना होगा।

कृपया ध्यान दें, हालांकि यह स्पष्ट नहीं था, कि यह करने के लिए गड़बड़ है। यह इस बात की भावना में नहीं है कि "शाखा" किसके लिए है, और चेरी-पिक एक अधिक ईमानदार तरीका है जो आप कर रहे हैं, यहाँ। यदि आप उसी शाखा पर अन्य फ़ाइलों के लिए एक और "मर्ज" करना चाहते थे जिसे आप पिछली बार नहीं लाए थे, तो यह आपको "पहले से ही अद्यतित" संदेश के साथ रोक देगा। जब हम "से" शाखा में एक से अधिक विभिन्न शाखाएँ होनी चाहिए, तो यह शाखा न होने का लक्षण है।


3
आपकी पहली कमांड ( git merge --no-ff --no-commit -s outs branchname1) वही है जो मैं देख रहा था! धन्यवाद!
रॉब नोव

1
कई शाखाओं के साथ, आवश्यक इतिहास, एकल फ़ाइल (एस) को मर्ज करने की आवश्यकता है और धक्का देने से पहले फ़ाइल की सामग्री को बदलना होगा, यह एक अच्छा विकल्प लगता है। उदाहरण के लिए देव => मास्टर, लेकिन आप मास्टर को धक्का देने से पहले एक मेजबान परिभाषा या समान बदलना चाहते हैं।
समयसीमा

15

मुझे पता है कि मुझे थोड़ी देर हो गई है लेकिन चयनात्मक फ़ाइलों को मर्ज करने के लिए यह मेरा वर्कफ़्लो है।

#make a new branch ( this will be temporary)
git checkout -b newbranch
# grab the changes 
git merge --no-commit  featurebranch
# unstage those changes
git reset HEAD
(you can now see the files from the merge are unstaged)
# now you can chose which files are to be merged.
git add -p
# remember to "git add" any new files you wish to keep
git commit

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

15

सबसे आसान तरीका है कि आप उस शाखा को अपने रेपो को सेट करें जिसे आप फिर से चलाना चाहते हैं,

git checkout [branch with file] [path to file you would like to merge]

अगर तुम दौड़ते हो

git status

आप देखेंगे कि फ़ाइल पहले ही मंचित है ...

फिर भागो

git commit -m "Merge changes on '[branch]' to [file]"

सरल।


3
यह लगभग सबसे अच्छा जवाब मुझे मिला। कृपया देखें jasonrudolph.com/blog/2009/02/25/… इतना स्पष्ट, संक्षिप्त और यह सिर्फ काम करता है!
सुपरूसोई

1
विलय के बजाय स्रोत शाखा से फ़ाइलों की सामग्री को पूरी तरह से बदल देगा
Amare

मैं बस इस तरह का जवाब देने वाला था, मैंने सोचा कि मैं नई चीजों का आविष्कार करता हूं जो अभी तक उत्तर नहीं दिया गया है! लेकिन यह इसे करने का सबसे सरल तरीका है। यह शीर्ष पर होना चाहिए!
इरफैंडी जिप

15

मुझे यह पोस्ट सबसे सरल उत्तर मिला। केवल करते हैं:

$ #git checkout <branch from which you want files> <file paths>

उदाहरण:

$ #pulling .gitignore file from branchB into current branch
$ git checkout branchB .gitignore

अधिक जानकारी के लिए पोस्ट देखें।


3
यह वास्तव में विलय नहीं करता है, यह वर्तमान शाखा पर फ़ाइल को अधिलेखित करता है।
इगोर रालिक

1
@igrali यह एक उपयोगी टिप्पणी है, लेकिन इसे करने के लिए "उचित" तरीकों की कठिनाई की तुलना में, यह एक अच्छा समाधान है। एक बस बहुत सावधान रहना होगा।
ओवेन्समार्टिन

12

यह अजीब है कि गिट के पास अभी भी ऐसा सुविधाजनक उपकरण नहीं है "बॉक्स से बाहर"। वर्तमान संस्करण शाखा के कुछ बगफिक्स द्वारा कुछ पुराने संस्करण शाखा (जिसमें अभी भी बहुत सारे सॉफ्टवेयर उपयोगकर्ता हैं) को अपडेट करने पर मैं इसका अत्यधिक उपयोग करता हूं । इस मामले में अक्सर ट्रंक में फ़ाइल से कोड की कुछ पंक्तियों को जल्दी से प्राप्त करने की आवश्यकता होती है , बहुत सारे अन्य परिवर्तनों को अनदेखा करते हुए (जो पुराने संस्करण में नहीं जाना चाहिए) ... और निश्चित रूप से इंटरैक्टिव थ्री-वे मर्ज इस मामले में जरूरत है, git checkout --patch <branch> <file path>इस चयनात्मक मर्ज उद्देश्य के लिए उपयोग करने योग्य नहीं है।

आप इसे आसानी से कर सकते हैं:

इस लाइन को [alias]अपने वैश्विक .gitconfigया स्थानीय .git/configफ़ाइल में अनुभाग में जोड़ें :

[alias]
    mergetool-file = "!sh -c 'git show $1:$2 > $2.theirs; git show $(git merge-base $1 $(git rev-parse HEAD)):$2 > $2.base; /C/BCompare3/BCompare.exe $2.theirs $2 $2.base $2; rm -f $2.theirs; rm -f $2.base;' -"

इसका मतलब है कि आप बियॉन्ड तुलना का उपयोग करते हैं। अगर जरूरत हो तो बस अपनी पसंद के सॉफ्टवेयर में बदलाव करें। यदि आप संवादात्मक चयनात्मक विलय की आवश्यकता नहीं है, तो आप इसे तीन-तरफा ऑटो-मर्ज में बदल सकते हैं:

[alias]
    mergetool-file = "!sh -c 'git show $1:$2 > $2.theirs; git show $(git merge-base $1 $(git rev-parse HEAD)):$2 > $2.base; git merge-file $2 $2.base $2.theirs; rm -f $2.theirs; rm -f $2.base;' -"

तो इस तरह का उपयोग करें:

git mergetool-file <source branch> <file path>

यह आपको दूसरे ब्रांच में किसी भी फाइल के सही सेलेक्टिव ट्री-वे मर्ज का मौका देगा।


10

यह वैसा नहीं है जैसा आप देख रहे थे, बल्कि यह मेरे लिए उपयोगी था:

git checkout -p <branch> -- <paths> ...

यह कुछ उत्तरों का मिश्रण है।


2
यह वास्तव में उपयोगी है और मेरे लिए सबसे अच्छा उत्तर, @ एल्विनाबाद के उत्तर में जोड़ा जा सकता है। करते समय: git checkout HEAD file1वर्तमान संस्करण को बनाए रखने के लिए और फ़ाइल को अनमर्ज करने के लिए file1, किसी को मर्ज किए जाने वाले फ़ाइल के भाग का -pचयन करने के लिए विकल्प का उपयोग कर सकते हैं । चाल के लिए धन्यवाद!
साइमन C.

यह मेरा fav जवाब है। सिंपल टू द पॉइंट एंड वर्क्स
जेसी रजा खोरासानि

8

मैं एक

git diff प्रतिबद्ध1..commit2 filepattern | git-apply --index && git कमिट

इस तरह से आप किसी शाखा से फ़ाइलपार्टन के लिए आवागमन की सीमा को सीमित कर सकते हैं।

से चोरी: http://www.gelato.unsw.edu.au/archives/git/0701/37964.html


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

बार्ट जेएस कौन है?
काला

8

जैसा कि आपने ऊपर बताया था, मुझे ठीक वैसी ही समस्या थी। लेकिन मुझे उत्तर को समझाने में यह स्पष्ट ब्लॉग स्पष्ट लगा।

उपरोक्त लिंक से कमांड:

#You are in the branch you want to merge to
git checkout <branch_you_want_to_merge_from> <file_paths...>

क्या आपने यह परीक्षण किया? मुझे यकीन है कि फ़ाइलें <branch_you_want_to_merge_from> जा रहा विलय कर के बजाय से बदल दिया जाएगा रहा हूँ
खुशी के लिए खोज

7

मुझे 'git-इंटरैक्टिव-मर्ज' उत्तर पसंद है, ऊपर, लेकिन एक आसान है। चलो आप के लिए यह एक इंटरैक्टिव का एक rebase संयोजन का उपयोग कर और:

      A---C1---o---C2---o---o feature
     /
----o---o---o---o master

तो मामला यह है कि आप C1 और C2 को 'सुविधा' शाखा (शाखा बिंदु 'A') से चाहते हैं, लेकिन बाकी के लिए अभी कोई भी नहीं है।

# git branch temp feature
# git checkout master
# git rebase -i --onto HEAD A temp

जो, जैसा कि ऊपर है, आपको इंटरेक्टिव एडिटर में ड्रॉप करता है जहां आप C1 और C2 (ऊपर के रूप में) के लिए 'पिक' लाइन्स चुनते हैं। सहेजें और छोड़ें, और फिर यह रिबेस के साथ आगे बढ़ेगा और आपको शाखा 'अस्थायी' देगा और मास्टर + C1 +2 पर HEAD:

      A---C1---o---C2---o---o feature
     /
----o---o---o---o-master--C1---C2 [HEAD, temp]

तब आप बस हेड को मास्टर अपडेट कर सकते हैं और अस्थायी शाखा को हटा सकते हैं और आप जाने के लिए अच्छे हैं:

# git branch -f master HEAD
# git branch -d temp

7

किस बारे में git reset --soft branch? मुझे आश्चर्य है कि किसी ने भी अभी तक इसका उल्लेख नहीं किया है।

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


6

मुझे पता है कि यह प्रश्न पुराना है और कई अन्य उत्तर भी हैं, लेकिन मैंने अपनी स्क्रिप्ट को 'pmerge' लिखा था, जो आंशिक रूप से निर्देशिकाओं को मर्ज करने के लिए है। यह प्रगति पर काम है और मैं अभी भी गिट और बैश स्क्रिप्टिंग दोनों सीख रहा हूं।

इस कमांड का उपयोग करता है git merge --no-commit और फिर अनपेक्षित परिवर्तन प्रदान करता है जो प्रदान किए गए पथ से मेल नहीं खाता है।

उपयोग: git pmerge branch path
उदाहरण:git merge develop src/

मैंने इसका बड़े पैमाने पर परीक्षण नहीं किया है। काम करने वाली निर्देशिका को किसी भी तरह के अनियोजित परिवर्तन और अनट्रैक की गई फ़ाइलों से मुक्त होना चाहिए।

#!/bin/bash

E_BADARGS=65

if [ $# -ne 2 ]
then
    echo "Usage: `basename $0` branch path"
    exit $E_BADARGS
fi

git merge $1 --no-commit
IFS=$'\n'
# list of changes due to merge | replace nulls w newlines | strip lines to just filenames | ensure lines are unique
for f in $(git status --porcelain -z -uno | tr '\000' '\n' | sed -e 's/^[[:graph:]][[:space:]]\{1,\}//' | uniq); do
    [[ $f == $2* ]] && continue
    if git reset $f >/dev/null 2>&1; then
        # reset failed... file was previously unversioned
        echo Deleting $f
        rm $f
    else
        echo Reverting $f
        git checkout -- $f >/dev/null 2>&1
    fi
done
unset IFS

4

read-treeउदाहरण के लिए, आप वर्तमान सूचकांक में दूरस्थ पेड़ को पढ़ने या मर्ज करने के लिए उपयोग कर सकते हैं :

git remote add foo git@example.com/foo.git
git fetch foo
git read-tree --prefix=my-folder/ -u foo/master:trunk/their-folder

मर्ज करने के लिए, -mइसके बजाय उपयोग करें ।

यह भी देखें: मैं गिट में एक उप निर्देशिका को कैसे मिलाऊँ?


3

फ़ाइल द्वारा चयनात्मक विलय / कमिटिंग के लिए एक सरल तरीका:

git checkout dstBranch git merge srcBranch // make changes, including resolving conflicts to single files git add singleFile1 singleFile2 git commit -m "message specific to a few files" git reset --hard # blow away uncommitted changes


3

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

1. अस्थायी रूप से डुप्लीकेट शाखा
$ git checkout -b temp_branch

2. पिछले वांछित कमिट के लिए रीसेट करें
$ git reset --hard HEAD~n , nआपको वापस जाने के लिए कितने कमिट की आवश्यकता है

3. मूल शाखा से प्रत्येक फ़ाइल की जाँच करें
$ git checkout origin/original_branch filename.ext

अब आप जरूरत पड़ने पर रिमोट को आगे बढ़ाने के लिए कमिट और बल दे सकते हैं।


3

आप केवल किसी विशेष निर्देशिका और छुट्टी सब कुछ बाकी बरकरार विलय करने के लिए और अभी तक इतिहास को संरक्षित की जरूरत है, तो आप संभवतः इस कोशिश कर सकते ... एक नया बनाने target-branchके बंदmaster प्रयोग से पहले ।

नीचे दिए गए चरणों से आपको लगता है कि आपकी दो शाखाएँ target-branchऔर हैं source-branch, और जिस निर्देशिका dir-to-mergeको आप मर्ज करना चाहते हैं वह है source-branch। यह भी मान लें dir-to-retainकि आपके पास लक्ष्य में अन्य निर्देशिकाएं हैं जिन्हें आप इतिहास को बदलना और बनाए रखना नहीं चाहते हैं। इसके अलावा, मानता है कि में विलय संघर्ष हैं dir-to-merge

git checkout target-branch
git merge --no-ff --no-commit -X theirs source-branch
# the option "-X theirs", will pick theirs when there is a conflict. 
# the options "--no--ff --no-commit" prevent a commit after a merge, and give you an opportunity to fix other directories you want to retain, before you commit this merge.

# the above, would have messed up the other directories that you want to retain.
# so you need to reset them for every directory that you want to retain.
git reset HEAD dir-to-retain
# verify everything and commit.

2

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

git difftoll <branch-1>..<branch-2>

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