2012-10-23 6 views
160

मुझे दो गीट भंडारों को एक ब्रांड नए, तीसरे भंडार में विलय करने की आवश्यकता है। मुझे एक उपट्री विलय (उदाहरण के लिए Jakub Narębski's answerHow do you merge two Git repositories? पर) के लिए यह करने के लिए कई विवरण मिल गए हैं और उन निर्देशों का पालन करने के बाद ज्यादातर काम करते हैं, सिवाय इसके कि जब मैं सबट्री विलय करता हूं तो पुरानी भंडारों की सभी फाइलों को नए जोड़े के रूप में दर्ज किया जाता है फ़ाइलें। जब मैं git log करता हूं, तो मैं पुराने भंडारों से प्रतिबद्ध इतिहास देख सकता हूं, लेकिन अगर मैं git log <file> करता हूं तो यह उस फ़ाइल के लिए केवल एक प्रतिबद्धता दिखाता है - उपट्री विलय। उपर्युक्त उत्तर पर टिप्पणियों का जिक्र करते हुए, मैं इस समस्या को देखने में अकेला नहीं हूं लेकिन मुझे इसके लिए कोई प्रकाशित समाधान नहीं मिला है।फ़ाइल इतिहास तोड़ने के बिना दो गीट भंडारों को मर्ज करें

क्या रिपोजिटरी मर्ज करने और व्यक्तिगत फ़ाइल इतिहास को बरकरार रखने का कोई तरीका है?

+0

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

+0

मुझे यह प्रश्न भी उपयोगी पाया गया http://stackoverflow.com/questions/1683531/how-to-import-existing-git-repository-into-another – nacross

+0

मैंने एक फॉलो-अप प्रश्न बनाया है। दिलचस्प हो सकता है: दो गिट भंडारों को मर्ज करें और मास्टर इतिहास रखें: http://stackoverflow.com/questions/42161910/merge-two-git-repositories-and-keep-the-master-history –

उत्तर

205

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

यहाँ दो खजाने एक साथ गोंद के लिए एक उदाहरण PowerShell स्क्रिप्ट है:

# Assume the current directory is where we want the new repository to be created 
# Create the new repository 
git init 

# Before we do a merge, we have to have an initial commit, so we'll make a dummy commit 
dir > deleteme.txt 
git add . 
git commit -m "Initial dummy commit" 

# Add a remote for and fetch the old repo 
git remote add -f old_a <OldA repo URL> 

# Merge the files from old_a/master into new/master 
git merge old_a/master --allow-unrelated-histories 

# Clean up our dummy file because we don't need it any more 
git rm .\deleteme.txt 
git commit -m "Clean up initial file" 

# Move the old_a repo files and folders into a subdirectory so they don't collide with the other repo coming later 
mkdir old_a 
dir -exclude old_a | %{git mv $_.Name old_a} 

# Commit the move 
git commit -m "Move old_a files into subdir" 

# Do the same thing for old_b 
git remote add -f old_b <OldB repo URL> 
git merge old_b/master --allow-unrelated-histories 
mkdir old_b 
dir –exclude old_a,old_b | %{git mv $_.Name old_b} 
git commit -m "Move old_b files into subdir" 

जाहिर है आप के बजाय old_a में old_b मर्ज कर सकते हैं (जो नई संयुक्त रेपो हो जाता है) यदि आप बल्कि ऐसा चाहते हैं - संशोधित सूट करने के लिए लिपि।

आप के रूप में अच्छी तरह से में प्रगति सुविधा शाखाओं पर लाने के लिए चाहते हैं, इस का उपयोग करें:

# Bring over a feature branch from one of the old repos 
git checkout -b feature-in-progress 
git merge -s recursive -Xsubtree=old_a old_a/feature-in-progress 

प्रक्रिया के केवल गैर स्पष्ट हिस्सा है यही कारण है कि - कि एक सबट्री मर्ज नहीं है, बल्कि करने के लिए एक बहस सामान्य रिकर्सिव विलय जो गिट को बताता है कि हमने लक्ष्य का नाम बदल दिया है और इससे गिट लाइन को सबकुछ ठीक से मदद मिलती है।

मैंने थोड़ा और विस्तृत स्पष्टीकरण here लिखा।

+10

'git mv' का उपयोग करके यह समाधान इतना अच्छा काम नहीं करता है। जब आप बाद में किसी एक स्थानांतरित फ़ाइलों पर 'गिट लॉग' का उपयोग करते हैं तो आपको केवल चाल से प्रतिबद्धता मिलती है। सभी पिछले इतिहास खो गया है। ऐसा इसलिए है क्योंकि 'गिट एमवी' वास्तव में 'गिट आरएम है; गिट एड 'लेकिन [एक चरण में] (http://stackoverflow.com/a/1094392/959352)। – mholm815

+11

यह गिट में किसी अन्य चाल/नामकरण ऑपरेशन जैसा ही है: कमांड लाइन से आप 'git log --follow' करके सभी इतिहास प्राप्त कर सकते हैं, या सभी जीयूआई उपकरण आपके लिए स्वचालित रूप से ऐसा करते हैं। एक subtree विलय के साथ ** ** मुझे व्यक्तिगत फ़ाइलों के लिए इतिहास नहीं मिल सकता है, जहां तक ​​मुझे पता है, तो यह विधि बेहतर है। –

+2

@EricLee जब old_b repo विलय हो जाता है तो मुझे विलय विवादों का बहुत कुछ मिलता है। क्या यह उम्मीद है? मुझे CONFLICT (नाम बदलें/हटाएं) – Jon

8

कृपया

git rebase --root --preserve-merges --onto 

का उपयोग कर उनके जीवन में पर जल्दी दो इतिहास से जोड़ने के लिए पर एक नजर है।

आप रास्तों जो आपस में मिलते हैं, तो उन्हें,

git filter-branch --index-filter 

के साथ ठीक है जब आप लॉग का उपयोग सुनिश्चित करें कि आप "कठिन प्रतियां लगता है"

git log -CC 

कि जिस तरह से साथ आप में से किसी आंदोलनों मिलेगा पथ में फाइलें।

105

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

cd firstgitrepo/ 
git remote add secondrepo [email protected]:andsoon 
  • सुनिश्चित करें कि आप secondrepo के प्रतिबद्ध के सभी डाउनलोड किया है::

    1. रिमोट के रूप में दूसरा रेपो जोड़े

      git fetch secondrepo 
      
    2. से एक स्थानीय शाखा बनाएं दूसरी रेपो की शाखा:

      git branch branchfromsecondrepo secondrepo/master 
      
    3. ले जाएँ अपने सभी उप-निर्देशिका में फ़ाइलों:

      git checkout branchfromsecondrepo 
      mkdir subdir/ 
      git ls-tree -z --name-only HEAD | xargs -0 -I {} git mv {} subdir/ 
      git commit -m "Moved files to subdir/" 
      
    4. पहले रेपो के मास्टर शाखा में दूसरी शाखा मर्ज:

      git checkout master 
      git merge --allow-unrelated-histories branchfromsecondrepo 
      

    आपका भंडार एक से अधिक रूट प्रतिबद्ध होगा, लेकिन उसमें कोई समस्या नहीं होनी चाहिए।

  • +1

    चरण 2 मेरे लिए काम नहीं करता है: घातक: वैध ऑब्जेक्ट नाम नहीं: 'secondrepo/master'। – Keith

    +0

    @ किथ: सुनिश्चित करें कि आपने दूसरे रिपो को रिमोट नामक "secondrepo" के रूप में जोड़ा है, और यह कि रेपो में "मास्टर" नाम की एक शाखा है (आप 'रिट रेपो पर शाखाओं को' गीट रिमोट शो सेकंडrepo 'के साथ देख सकते हैं।) – Flimm

    +0

    मुझे इसे नीचे लाने के लिए भी एक fetch करना पड़ा। 1 और 2 के बीच में मैंने गिट fetch secondrepo – monkjack

    5

    मैं एक git alias इस तरह में @Flimm इस से solution बदल गया (मेरे ~/.gitconfig को जोड़ा गया):

    function git-add-repo 
    { 
        repo="$1" 
        dir="$(echo "$2" | sed 's/\/$//')" 
        path="$(pwd)" 
    
        tmp="$(mktemp -d)" 
        remote="$(echo "$tmp" | sed 's/\///g'| sed 's/\./_/g')" 
    
        git clone "$repo" "$tmp" 
        cd "$tmp" 
    
        git filter-branch --index-filter ' 
         git ls-files -s | 
         sed "s,\t,&'"$dir"'/," | 
         GIT_INDEX_FILE="$GIT_INDEX_FILE.new" git update-index --index-info && 
         mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE" 
        ' HEAD 
    
        cd "$path" 
        git remote add -f "$remote" "file://$tmp/.git" 
        git pull "$remote/master" 
        git merge --allow-unrelated-histories -m "Merge repo $repo into master" --edit "$remote/master" 
        git remote remove "$remote" 
        rm -rf "$tmp" 
    } 
    

    कैसे:

    [alias] 
    mergeRepo = "!mergeRepo() { \ 
        [ $# -ne 3 ] && echo \"Three parameters required, <remote URI> <new branch> <new dir>\" && exit 1; \ 
        git remote add newRepo $1; \ 
        git fetch newRepo; \ 
        git branch \"$2\" newRepo/master; \ 
        git checkout \"$2\"; \ 
        mkdir -vp \"${GIT_PREFIX}$3\"; \ 
        git ls-tree -z --name-only HEAD | xargs -0 -I {} git mv {} \"${GIT_PREFIX}$3\"/; \ 
        git commit -m \"Moved files to '${GIT_PREFIX}$3'\"; \ 
        git checkout master; git merge --allow-unrelated-histories --no-edit -s recursive -X no-renames \"$2\"; \ 
        git branch -D \"$2\"; git remote remove newRepo; \ 
    }; \ 
    mergeRepo" 
    
    +6

    बस उत्सुक: क्या आप वास्तव में अक्सर उपनाम की आवश्यकता के लिए ऐसा करते हैं? –

    +1

    नहीं, मुझे नहीं लगता कि यह कैसे करना है, इसलिए उपनाम यह याद रखने का एक तरीका है। –

    +0

    हाँ .. लेकिन कंप्यूटर बदलने और अपने उपनामों को स्थानांतरित करने की भूल करने की कोशिश करें;) – quetzalcoatl

    2

    यह समारोह स्थानीय रेपो dir में दूरस्थ रेपो क्लोन होगा उपयोग करने के लिए:

    cd current/package 
    git-add-repo https://github.com/example/example dir/to/save 
    

    लाभ!

    +0

    मैं बैश के बजाय zsh का उपयोग कर रहा हूं, और git के v2.13.0 का उपयोग कर रहा हूं। कोई फर्क नहीं पड़ता कि मैंने क्या कोशिश की है, मैं काम करने के लिए 'गिट फिल्टर-शाखा-इंडेक्स-फ़िल्टर' प्राप्त करने में सक्षम नहीं हूं। आम तौर पर मुझे एक त्रुटि संदेश मिलता है कि .new अनुक्रमणिका फ़ाइल मौजूद नहीं है। क्या यह किसी भी घंटी बजती है? –

    +0

    @PatrickBeard मुझे zsh नहीं पता है, आप फ़ाइल के अंत में उपरोक्त फ़ंक्शन के साथ अलग फ़ाइल 'git-add-repo.sh' बना सकते हैं, इस पंक्ति को' git-add-repo "$ @" 'रखा है। उसके बाद आप इसे 'सीडी वर्तमान/गिट/पैकेज' और' bash path/to/git-add-repo.sh जैसे zsh से उपयोग कर सकते हैं https://github.com/example/example dir/to/save' –

    +0

    समस्या पर चर्चा की गई: https://stackoverflow.com/questions/7798142/error-combining-git-repositories-into-subdirs 'mv" $ GIT_INDEX_FILE.new "" $ GIT_INDEX_FILE "" कभी-कभी विफल रहता है, इसलिए आपको एक जोड़ना होगा 'अगर परीक्षण'। –

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