मैं एक उप निर्देशिका को Git में कैसे मिलाऊँ?


84

क्या एक स्थानीय Git शाखा से दूरस्थ Git शाखा में उप-निर्देशिका के लिए केवल परिवर्तनों को मर्ज करना संभव है या यह "सभी या कुछ भी नहीं" है?

उदाहरण के लिए, मेरे पास:

branch-a
 - content-1
 - dir-1
   - content-2

तथा

branch-b
 - content-1
 - dir-1
   - `content-2

मैं केवल शाखा-बी dir-१ की सामग्री के साथ शाखा-ए-डीआईआर -१ की सामग्री को मर्ज करना चाहता हूं।


1
मुझे लगता है कि यह एक डुप्लिकेट है: stackoverflow.com/questions/449541/…
कार्ल Voigtland

जवाबों:


81

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

  • मेरा भंडार => cookbooks
    मेरा भंडार लक्ष्य निर्देशिका =>cookbooks/cassandra
  • दूरस्थ रिपॉजिटरी => infochimps
    दूरस्थ रिपॉजिटरी स्रोत जिसे मैं cookbooks/cassandra=> में मर्ज करना चाहता हूंinfochimps/cookbooks/cassandra

यहां वे कमांड हैं जिनका उपयोग मैंने उन्हें मर्ज करने के लिए किया था

  • भंडार जोड़ें और इसे लाएं
git Remote add -f infochimps git: //github.com/infochimps/cluster_chef.it
  • मर्ज करें
git मर्ज --allow-unrelated-histories -s ours --no-प्रतिबद्ध infochimps / master

(यह 'हमारी' रणनीति ( -s ours) का उपयोग करके एक मर्ज करता है , जो स्रोत शाखा से परिवर्तन को दिखाता है। यह इस तथ्य को रिकॉर्ड करता है जिसे infochimps/masterविलय कर दिया गया है, वास्तव में लक्ष्य शाखा में किसी भी फाइल को संशोधित किए बिना)

  • में ही मिला infochimps/cookbooks/cassandraलेंcassandra
git वाच-ट्री - उपसर्ग = cassandra / -u infochimps / master: cookbooks / cassandra

यह केवल आवश्यक स्रोत उपनिर्देशिका यानी के लिए पेड़ पढ़ता है cookbooks/cassandra, की नदी के ऊपर शाखा पर स्रोत भंडार।

ध्यान दें कि लक्ष्य उपनिर्देशिका नाम भी होना चाहिए cookbooks/cassandra, या आप देखेंगे:

fatal: Not a valid object name
  • बदलाव को कमिट करें
 git कमिट -m 'इनचेकिंग कैसेंड्रा में विलय'

परिशिष्ट

यह विचित्र है, [मुझे संपादित करें] - लेकिन read-treeकदम संभवतः इस तरह विफल हो सकता है:

error: Entry 'infochimps/cookbooks/cassandra/README' overlaps with 'cookbooks/cassandra/README'. Cannot bind.

... तब भी जब दोनों फाइलें समान हैं । यह मदद कर सकता है:

git rm -r cassandra
git read-tree --prefix=cassandra/ -u infochimps/master:cookbooks/cassandra

लेकिन बेशक, मैन्युअल रूप से सत्यापित करें कि यह वही करता है जो आप चाहते हैं।


3
@Martin git-scm.com/docs/git-rev-parse#_specifying_revisions के लिए देखो <rev>:<path>, जैसे HEAD:README, :README,master:./README
VonC

6
यह git read-treeकदम मेरे लिए विफल है:error: Entry 'foo/bar/baz.php' overlaps with 'bar/baz.php'. Cannot bind.
वेस्टन राउटर

1
@VonC लेकिन नहीं, मुझे इतिहास की जरूरत है। यह जवाब उस मामले के लिए जिम्मेदार नहीं है जहां पेड़ के भीतर फाइलों में स्थानीय संशोधन हैं। इसलिए इसे विलय करने की जरूरत है।
वेस्टन रटर

मेरे लिए, overlaps withऊपर उल्लिखित त्रुटि, समान फ़ाइलों पर भी पॉप अप करती है । कितना अजीब है?
१०'१६ को

1
@ChrisHalcrow उस तथ्य को रिकॉर्ड करने के लिए infochimps/masterजिसे विलय कर दिया गया है, लेकिन वास्तव में लक्ष्य शाखा में किसी भी फाइल को संशोधित किए बिना। क्योंकि अगला चरण git read-tree --prefix=cassandraसंशोधन करेगा। अंतिम प्रतिबद्ध वास्तविक "मर्ज" सामग्री रिकॉर्ड करेगा।
VonC

29

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

git checkout destination
git checkout source newFeature/
git commit -am "Merged the new feature from source to destination branch."
git pull --rebase
git push

मैंने जो कुछ भी देखा है, उसकी तुलना में यह काफी कम है और यह मेरे लिए पूरी तरह से काम करता है

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


2
क्या यह इतिहास को संरक्षित करता है?
Bibrak

2
@Bibrak यह दृष्टिकोण इतिहास को संरक्षित नहीं करता है। कम से कम वर्तमान कमांड के साथ नहीं।
रवि गिदवानी

6

मुझे ग्रहण के मंच सूत्र से यह मिला और इसने एक आकर्षण की तरह काम किया:

git checkout source-branch
git checkout target-branch <directories-or-files-you-do-**NOT**-want> 
git commit
git checkout target-branch
git merge source-branch

1
मैंने यह कोशिश की और लक्ष्य-शाखा में स्रोत-शाखा से एक निर्देशिका के साथ समाप्त हुआ जो मुझे नहीं चाहिए था। डायर के सेट के साथ निर्दिष्ट होने के बावजूद मैं उस 2 डी कमांड पर नहीं चाहता था।
मैराथन

2
यह विलय नहीं करता है, यह स्रोत शाखा से एक के साथ फ़ोल्डर को बदलता है।
Gp2mv3

@ Gp2mv3 मुझे लगता है कि यह ठोस दिखता है। checkoutफ़ोल्डर्स को समान बनाता है => अंतर केवल un- checkoutफ़ोल्डर => mergeअंतर है। यह एक मान्य रणनीति है।
गुफा

5

ओपी के परिदृश्य जहां वे दो शाखाएं हैं, लेकिन का केवल इतिहास मर्ज करना चाहते हैं को देखते हुए dir -1 से शाखा-एक में शाखा-बी :

# Make sure you are in the branch with the changes you want
git checkout branch-a

# Split the desired folder into its own temporary branch
# This replays all commits, so it could take a while
git subtree split -P dir-1 -b temp-branch

# Enter the branch where you want to merge the desired changes into
git checkout branch-b

# Merge the changes from the temporary branch
git subtree merge -P dir-1 temp-branch

# Handle any conflicts
git mergetool

# Commit
git commit -am "Merged dir-1 changes from branch-a"

# Delete temp-branch
git branch -d temp-branch

0

शाखा-अ और शाखा-ब दोनों को समाहित करने के लिए Git रिपॉजिटरी बनाएँ:

git checkout branch-a
git diff branch-b dir-1 > a.diff
patch -R -p1 < a.diff

14
इस उत्तर के लिए अधिक जानकारी की आवश्यकता है। यह वास्तविक कोड बनाम टिप्पणी क्या है?
कोडीनिजा

2
अनुरोधकर्ता विलय करना चाहता है। परिवर्तनों को ले जाने के लिए एक पैच का उपयोग करने से स्वचालित रूप से सभी पैच एक पैच में आ जाते हैं और इतिहास खो जाता है।
एरिक

0

git cherry-pickअपने इच्छित कमिट करने के लिए उपयोग करें और केवल इन कमिट्स को मर्ज करें। यहां मुख्य चाल यह है कि इन तरीकों को आसान तरीके से प्राप्त करें (ताकि आपको मैन्युअल रूप से गिट लॉग की जांच करके और उन्हें हाथ से दर्ज करके पता लगाने की आवश्यकता नहीं है)। यहां बताया गया है: इस तरह git logसे कमिट की SHA-1 आईडी प्रिंट करने के लिए उपयोग करें:

git log ^<commit-a> <commit-b> --pretty=format:"%h" --reverse -- <subdir>

'कमिट-ए' शाखा के विलय के शुरुआती बिंदु से ठीक पहले की प्रतिबद्धता है, और 'कमिट-बी' विलय करने के लिए शाखा पर अंतिम प्रतिबद्धता है। '--reverse' ये बाद में चेरी-पिकिंग के लिए रिवर्स ऑर्डर में प्रिंट करता है।

फिर इसे पसंद करें:

git cherry-pick $(git log ^<commit-a> <commit-b> --pretty=format:"%h" --reverse -- <subdir>)

यह दो चरणों, सरल और स्थिर है!


उत्कृष्ट और एकमात्र तरीका एक शाखा से दूसरी शाखा को मर्ज करना और इतिहास को संरक्षित करना है। लेकिन ... ... यदि आप सिर्फ एक कमिट चाहते हैं, तो पहले कमांड से सभी कमिट्स से एक ब्रांच बनाएं, फिर उस नई ब्रांच को एक स्क्वैश मर्ज में मिला दें ....
tom

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

Two steps, simple and stable!बिल्कुल सरल नहीं है :)
रफा

तो आपको कौन सा तरीका आसान लगता है? @ राफा
रॉबर्ट

@ रोबर्ट का मतलब यह नहीं था कि आपका जवाब आसान नहीं है; दोष सभी पर है git, जिसमें एक भयानक इंटरफ़ेस और भयानक मानसिक मॉडल है जो रहस्यों और यादृच्छिक नामों और अर्थों से भरा है।
राफा
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.