git - पृथक गिट भंडार में उपनिर्देशिका को अलग करें(स्थानांतरित करें)




git-subtree git-filter-branch (15)

आसान तरीका ™

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

  1. पुराने रेपो तैयार करें

    pushd <big-repo>
    git subtree split -P <name-of-folder> -b <name-of-new-branch>
    popd
    

    नोट: <name-of-folder> में अग्रणी या पिछला वर्ण नहीं होना चाहिए। उदाहरण के लिए, ./subproject/ नामक फ़ोल्डर को ./subproject/ रूप में पास किया जाना चाहिए, नहीं ./subproject/

    विंडोज उपयोगकर्ताओं के लिए नोट: जब आपकी फ़ोल्डर गहराई> 1, <name-of-folder> होना चाहिए * निक्स शैली फ़ोल्डर विभाजक (/)। उदाहरण के लिए, path1\path2\subproject नामक फ़ोल्डर को path1\path2\subproject path1/path2/subproject रूप में पास किया जाना चाहिए

  2. नया रेपो बनाएं

    mkdir <new-repo>
    pushd <new-repo>
    
    git init
    git pull </path/to/big-repo> <name-of-new-branch>
    
  3. नए रेपो को जिथूब या कहीं भी लिंक करें

    git remote add origin <[email protected]:my-user/new-repo.git>
    git push origin -u master
    
  4. अगर वांछित , सफाई

    popd # get out of <new-repo>
    pushd <big-repo>
    
    git rm -rf <name-of-folder>
    

    नोट : यह भंडार में सभी ऐतिहासिक संदर्भों को छोड़ देता है। यदि आप वास्तव में पासवर्ड करने के बारे में चिंतित हैं या आपको अपने .git फ़ोल्डर के फ़ाइल आकार को कम करने की आवश्यकता है, तो नीचे परिशिष्ट देखें।

...

पूर्वाभ्यास

ये उपरोक्त के समान चरण हैं , लेकिन <meta-named-things> का उपयोग करने के बजाय मेरे भंडार के लिए मेरे सटीक चरणों का पालन करना।

नोड में जावास्क्रिप्ट ब्राउज़र मॉड्यूल को लागू करने के लिए मेरे पास एक प्रोजेक्ट है:

tree ~/Code/node-browser-compat

node-browser-compat
├── ArrayBuffer
├── Audio
├── Blob
├── FormData
├── atob
├── btoa
├── location
└── navigator

मैं एक अलग गिट भंडार में एक फ़ोल्डर, btoa को विभाजित करना चाहता हूं

pushd ~/Code/node-browser-compat/
git subtree split -P btoa -b btoa-only
popd

अब मेरे पास एक नई शाखा है, btoa-only , जो केवल btoa लिए प्रतिबद्ध है और मैं एक नया भंडार बनाना चाहता हूं।

mkdir ~/Code/btoa/
pushd ~/Code/btoa/
git init
git pull ~/Code/node-browser-compat btoa-only

इसके बाद मैं गिथब या बिटबकेट पर एक नया रेपो बना देता हूं, या जो कुछ भी जोड़ता है और origin जोड़ता है (बीटीडब्ल्यू, "उत्पत्ति" केवल एक सम्मेलन है, कमांड का हिस्सा नहीं है - आप इसे "रिमोट-सर्वर" या जो भी चाहें उसे कॉल कर सकते हैं)

git remote add origin [email protected]:node-browser-compat/btoa.git
git push origin -u master

शुभ दिन!

नोट: यदि आपने README.md , README.md और LICENSE साथ रेपो बनाया है, तो आपको पहले खींचने की आवश्यकता होगी:

git pull origin -u master
git push origin -u master

अंत में, मैं बड़े रिपो से फ़ोल्डर को हटाना चाहता हूं

git rm -rf btoa

...

अनुबंध

ओएस एक्स पर नवीनतम गिट

गिट का नवीनतम संस्करण प्राप्त करने के लिए:

brew install git

ओएस एक्स के लिए ब्रू प्राप्त करने के लिए:

http://brew.sh

उबंटू पर नवीनतम गिट

sudo apt-get update
sudo apt-get install git
git --version

अगर यह काम नहीं करता है (आपके पास उबंटू का एक पुराना संस्करण है), कोशिश करें

sudo add-apt-repository ppa:git-core/ppa
sudo apt-get update
sudo apt-get install git

अगर वह अभी भी काम नहीं करता है, तो कोशिश करें

sudo chmod +x /usr/share/doc/git/contrib/subtree/git-subtree.sh
sudo ln -s \
/usr/share/doc/git/contrib/subtree/git-subtree.sh \
/usr/lib/git-core/git-subtree

टिप्पणियों से rui.araujo के लिए धन्यवाद।

अपने इतिहास को साफ़ करना

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

git filter-branch --prune-empty --tree-filter 'rm -rf <name-of-folder>' HEAD

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

git log -- <name-of-folder> # should show nothing

हालांकि, आप github और इसी तरह के हटाए गए "धक्का" नहीं कर सकते हैं। यदि आप कोशिश करते हैं तो आपको एक त्रुटि मिल जाएगी और आपको git push git pull पहले git pull होगा - और फिर आप अपने इतिहास में सबकुछ रखने के लिए वापस आ गए हैं।

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

छोटे से बनाते हैं

उपरोक्त हटाए गए इतिहास कमांड अभी भी बैकअप फ़ाइलों के समूह के पीछे छोड़ देता है - क्योंकि गिट दुर्घटना से अपने रेपो को बर्बाद नहीं करने में आपकी मदद करने में बहुत दयालु है। अंततः यह अनाथ फ़ाइलों को दिनों और महीनों में हटा देगा, लेकिन अगर आप महसूस करते हैं कि आपने गलती से कुछ ऐसा हटा दिया है जिसे आप नहीं चाहते थे तो यह उन्हें थोड़ी देर के लिए छोड़ देता है।

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

rm -rf .git/refs/original/ && \
git reflog expire --all && \
git gc --aggressive --prune=now

git reflog expire --all --expire-unreachable=0
git repack -A -d
git prune

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

श्रेय

मेरे पास एक Git भंडार है जिसमें कई उपनिर्देशिकाएं हैं। अब मुझे पता चला है कि उपनिर्देशिका में से एक दूसरे से असंबंधित है और इसे एक अलग भंडार से अलग किया जाना चाहिए।

उपनिर्देशिका के भीतर फ़ाइलों का इतिहास रखते हुए मैं यह कैसे कर सकता हूं?

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

बस इसे स्पष्ट करने के लिए, मेरे पास निम्न संरचना है:

XYZ/
    .git/
    XY1/
    ABC/
    XY2/

लेकिन मुझे इसके बजाय यह पसंद आएगा:

XYZ/
    .git/
    XY1/
    XY2/
ABC/
    .git/
    ABC/

आसान तरीका

  1. git splits स्थापित करें। मैंने इसे जिकेटिंग के समाधान के आधार पर गिट एक्सटेंशन के रूप में बनाया है।
  2. निर्देशिकाओं को #change into your repo's directory cd /path/to/repo #checkout the branch git checkout XYZ
    #split multiple directories into new branch XYZ git splits -b XYZ XY1 XY2
    शाखा की निर्देशिका में स्थानीय शाखा #change into your repo's directory cd /path/to/repo #checkout the branch git checkout XYZ
    #split multiple directories into new branch XYZ git splits -b XYZ XY1 XY2
    #change into your repo's directory cd /path/to/repo #checkout the branch git checkout XYZ
    #split multiple directories into new branch XYZ git splits -b XYZ XY1 XY2

  3. कहीं खाली रिको रेपो बनाएं। हम मान लेंगे कि हमने [email protected]:simpliwp/xyz.git पर xyz नामक एक खाली रेपो बनाया है जिसमें पथ है: [email protected]:simpliwp/xyz.git

  4. नए रेपो को पुश करें। #add a new remote origin for the empty repo so we can push to the empty repo on GitHub git remote add origin_xyz [email protected]:simpliwp/xyz.git #push the branch to the empty repo's master branch git push origin_xyz XYZ:master

  5. नव निर्मित रिमोट रेपो को एक नई स्थानीय निर्देशिका में क्लोन करें
    #change current directory out of the old repo cd /path/to/where/you/want/the/new/local/repo #clone the remote repo you just pushed to git clone [email protected]:simpliwp/xyz.git


इसके लायक होने के लिए, यहां एक विंडोज मशीन पर गिटहब का उपयोग करना है। मान लें कि आपके पास C:\dir1 में रहने में क्लोन रेपो है। निर्देशिका संरचना इस तरह दिखती है: C:\dir1\dir2\dir3dir3 निर्देशिका वह है जिसे मैं एक नया अलग रेपो बनना चाहता हूं।

Github:

  1. अपना नया भंडार बनाएं: MyTeam/mynewrepo

बैश प्रॉम्प्ट:

  1. $ cd c:/Dir1
  2. $ git filter-branch --prune-empty --subdirectory-filter dir2/dir3 HEAD
    लौटाया गया: Ref 'refs/heads/master' was rewritten (fyi: dir2 / dir3 केस संवेदनशील है।)

  3. $ git remote add some_name [email protected]:MyTeam/mynewrepo.git
    git remote add origin etc । काम नहीं किया, लौटा " remote origin already exists "

  4. $ git push --progress some_name master


इसे अपने gitconfig में रखें:

reduce-to-subfolder = !sh -c 'git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter cookbooks/unicorn HEAD && git reset --hard && git for-each-ref refs/original/ | cut -f 2 | xargs -n 1 git update-ref -d && git reflog expire --expire=now --all && git gc --aggressive --prune=now && git remote rm origin'

ऐसा प्रतीत होता है कि यहां उत्तर के अधिकांश (सभी?) git filter-branch --subdirectory-filter कुछ रूपों पर निर्भर हैं git filter-branch --subdirectory-filter और इसके जैसे। यह "ज्यादातर बार" काम कर सकता है हालांकि कुछ मामलों के लिए, उदाहरण के लिए जब आप फ़ोल्डर का नाम बदलते हैं, तो पूर्व:

 ABC/
    /move_this_dir # did some work here, then renamed it to

ABC/
    /move_this_dir_renamed

यदि आप "move_me_renamed" निकालने के लिए सामान्य गिट फ़िल्टर शैली करते हैं तो आप फ़ाइल परिवर्तन इतिहास खो देंगे जो प्रारंभ में move_this_dir ( ref ) था।

ऐसा लगता है कि वास्तव में सभी परिवर्तन इतिहास को रखने का एकमात्र तरीका (यदि आपका ऐसा कोई मामला है), संक्षेप में, भंडार की प्रतिलिपि बनाने के लिए (एक नया रेपो बनाएं, जो मूल होने के लिए सेट करें), फिर सब कुछ नूक करें और इस तरह के माता-पिता को उपनिर्देशिका का नाम बदलें:

  1. स्थानीय रूप से बहु-मॉड्यूल परियोजना क्लोन करें
  2. शाखाएं - जांचें कि वहां क्या है: git branch -a
  3. अपने वर्कस्टेशन पर स्थानीय प्रति प्राप्त करने के लिए प्रत्येक शाखा को विभाजित करने के लिए git checkout --track origin/branchABC : git checkout --track origin/branchABC
  4. एक प्रतिलिपि को एक नई निर्देशिका में बनाएं: cp -r oldmultimod simple
  5. नई परियोजना प्रतिलिपि में जाओ: cd simple
  6. इस परियोजना में आवश्यक अन्य मॉड्यूल से छुटकारा पाएं:
  7. git rm otherModule1 other2 other3
  8. अब केवल लक्ष्य मॉड्यूल का उपनिर्माण बनी हुई है
  9. मॉड्यूल उपदिर से छुटकारा पाएं ताकि मॉड्यूल रूट नई परियोजना रूट बन जाए
  10. git mv moduleSubdir1/* .
  11. अवशेष subdir हटाएं: rmdir moduleSubdir1
  12. किसी भी बिंदु पर परिवर्तन की जांच करें: git status
  13. नया गिट रेपो बनाएं और इस यूआरएल को इस परियोजना को इंगित करने के लिए कॉपी करें:
  14. git remote set-url origin http://mygithost:8080/git/our-splitted-module-repo
  15. सत्यापित करें कि यह अच्छा है: git remote -v
  16. रिमोट रेपो में परिवर्तन पुश करें: git push
  17. रिमोट रेपो पर जाएं और यह सब वहाँ जांचें
  18. किसी भी अन्य शाखा के लिए इसे दोहराएं: git checkout branch2

मॉड्यूल को एक नए रेपो में धक्का देने के लिए चरण 6-11 "gifub doc" को एक सबफ़ोल्डर को एक नए भंडार में विभाजित करना " चरण 6-11 का पालन करता है।

यह आपको आपके .git फ़ोल्डर में कोई भी स्थान नहीं बचाएगा, लेकिन यह उन फ़ाइलों के लिए भी आपके सभी परिवर्तन इतिहास को पुनर्नामित करेगा। और यदि इतिहास खोने के "बहुत सारे" नहीं हैं, तो यह इसके लायक नहीं हो सकता है, लेकिन कम से कम आप पुराने कामों को खोने की गारंटी नहीं देते हैं!


जैसा कि मैंने उपर्युक्त उल्लेख किया है , मुझे रिवर्स समाधान का उपयोग करना था (सभी dir/subdir/targetdir को हटाना मेरे dir/subdir/targetdir छूना नहीं था) जो लगभग 95% कामों (वांछित) को अच्छी तरह से हटाने के लिए काम करता था। हालांकि, दो छोटे मुद्दे शेष हैं।

सबसे पहले , filter-branch ने कोड को शुरू करने या संशोधित करने के लिए एक बैंग अप जॉब किया था, लेकिन स्पष्ट रूप से, विलय विविधता गिटवियर में अपने स्टेशन के नीचे हैं।

यह एक कॉस्मेटिक मुद्दा है जिसे मैं शायद साथ रह सकता हूं (वह कहता है ... आंखों के साथ धीरे-धीरे पीछे हटना)

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

एकमात्र चीज जिसे मैं कल्पना कर सकता हूं वह यह है कि हटाए गए कामों में से एक शायद, एक विलय प्रतिबद्ध था कि filter-branch वास्तव में हटा दी गई थी , और इसने समांतर समयरेखा बनाई क्योंकि प्रत्येक अब-अनमोल स्ट्रैंड ने अपनी खुद की प्रतिलिपि बनाई। (शर्ट मेरी टार्डी कहां है?) मुझे पूरा यकीन है कि मैं इस मुद्दे को ठीक कर सकता हूं, हालांकि मुझे यह समझना अच्छा लगेगा कि यह कैसा हुआ।

पागल मर्जफेस्ट-ओ-रैमा के मामले में, मैं शायद उस अकेले को छोड़ दूंगा क्योंकि यह मेरे प्रतिबद्ध इतिहास में इतनी दृढ़ता से जुड़ा हुआ है-जब भी मैं निकट आती हूं- मुझ पर खतरे में पड़ता है- ऐसा लगता है कि यह वास्तव में नहीं होता है कोई गैर-कॉस्मेटिक समस्याएं और क्योंकि यह Tower.app में काफी सुंदर है।


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

इसमें git_filter का शानदार नाम है और यहां रहता है:

https://github.com/slobobaby/git_filter

गिटहब पर

मुझे आशा है कि यह किसी के लिए उपयोगी होगा।


मूल प्रश्न XYZ / एबीसी / (* फाइलें) एबीसी / एबीसी / (* फाइलें) बनना चाहता है। अपने कोड के लिए स्वीकृत उत्तर को लागू करने के बाद, मैंने देखा कि यह वास्तव में एक्सबीजेड / एबीसी / (* फाइलें) को एबीसी / (* फाइलों) में बदल देता है। फ़िल्टर-शाखा मैन पेज भी कहता है,

परिणाम में उस प्रोजेक्ट रूट के रूप में वह निर्देशिका (और केवल वह) होगी। "

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

प्रश्न का मेरा जवाब तब भंडार की 2 प्रतियां बनाना है और प्रत्येक फ़ोल्डर में मैन्युअल रूप से उस फ़ोल्डर को हटा देना है जिसे आप रखना चाहते हैं। मैन पेज मुझे इसके साथ बैक करता है:

[...] [इस आदेश] का उपयोग करने से बचें यदि आपकी समस्या को ठीक करने के लिए एक साधारण एकल प्रतिबद्धता पर्याप्त होगी


मैंने पाया है कि नए भंडार से पुराने इतिहास को सही ढंग से हटाने के लिए, आपको filter-branch चरण के बाद थोड़ा और काम करना होगा।

  1. क्लोन और फ़िल्टर करें:

    git clone --no-hardlinks foo bar; cd bar
    git filter-branch --subdirectory-filter subdir/you/want
    
  2. पुराने इतिहास के हर संदर्भ को हटा दें। "उत्पत्ति" आपके क्लोन का ट्रैक रख रही थी, और "मूल" वह जगह है जहां फ़िल्टर-शाखा पुरानी चीजें बचाती है:

    git remote rm origin
    git update-ref -d refs/original/refs/heads/master
    git reflog expire --expire=now --all
    
  3. अब भी, आपका इतिहास एक पैकफाइल में फंस सकता है जो fsck स्पर्श नहीं करेगा। इसे टुकड़ों में फाड़ें, एक नया पैकफाइल बनाएं और अप्रयुक्त वस्तुओं को हटा दें:

    git repack -ad
    

फ़िल्टर-शाखा के लिए मैनुअल में इसका एक स्पष्टीकरण है


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

git filter-branch --prune-empty --subdirectory-filter <YOUR_SUBDIR_TO_KEEP> master
git push <MY_NEW_REMOTE_URL> -f .

https://github.com/vangorra/git_split पर git_split प्रोजेक्ट https://github.com/vangorra/git_split

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

./git_split.sh <src_repo> <src_branch> <relative_dir_path> <dest_repo>
        src_repo  - The source repo to pull from.
        src_branch - The branch of the source repo to pull from. (usually master)
        relative_dir_path   - Relative path of the directory in the source repo to split.
        dest_repo - The repo to push to.

संपादित करें: बैश स्क्रिप्ट जोड़ा गया।

यहां दिए गए उत्तरों ने मेरे लिए आंशिक रूप से काम किया; कैश में बहुत सी बड़ी फाइलें बनीं। अंततः क्या काम किया (Freenode पर #git में घंटों के बाद):

git clone --no-hardlinks file:///SOURCE /tmp/blubb
cd blubb
git filter-branch --subdirectory-filter ./PATH_TO_EXTRACT  --prune-empty --tag-name-filter cat -- --all
git clone file:///tmp/blubb/ /tmp/blooh
cd /tmp/blooh
git reflog expire --expire=now --all
git repack -ad
git gc --prune=now

पिछले समाधानों के साथ, भंडार आकार लगभग 100 एमबी था। यह इसे 1.7 एमबी तक लाया। शायद यह किसी की मदद करता है :)

निम्नलिखित बैश स्क्रिप्ट कार्य को स्वचालित करती है:

!/bin/bash

if (( $# < 3 ))
then
    echo "Usage:   $0 </path/to/repo/> <directory/to/extract/> <newName>"
    echo
    echo "Example: $0 /Projects/42.git first/answer/ firstAnswer"
    exit 1
fi


clone=/tmp/${3}Clone
newN=/tmp/${3}

git clone --no-hardlinks file://$1 ${clone}
cd ${clone}

git filter-branch --subdirectory-filter $2  --prune-empty --tag-name-filter cat -- --all

git clone file://${clone} ${newN}
cd ${newN}

git reflog expire --expire=now --all
git repack -ad
git gc --prune=now

अपडेट करें : यह प्रक्रिया इतनी आम है कि गिट टीम ने इसे एक नए टूल, git subtree साथ बहुत आसान बना दिया। यहां देखें: अलग-अलग गिट भंडार में उपनिर्देशिका को अलग करें (स्थानांतरित करें)

आप अपने भंडार को क्लोन करना चाहते हैं और फिर सब कुछ चिह्नित करने के लिए git filter-branch का उपयोग करें, लेकिन उपनिर्देशिका जिसे आप अपने नए रेपो में कचरा-संग्रहित करना चाहते हैं।

  1. अपने स्थानीय भंडार को क्लोन करने के लिए:

    git clone /XYZ /ABC
    

    (नोट: भंडार हार्ड लिंक का उपयोग करके क्लोन किया जाएगा, लेकिन यह कोई समस्या नहीं है क्योंकि हार्ड-लिंक्ड फ़ाइलों को स्वयं में संशोधित नहीं किया जाएगा - नए बनाए जाएंगे।)

  2. अब, हम उन रोचक शाखाओं को संरक्षित करते हैं जिन्हें हम फिर से लिखना चाहते हैं, और उसके बाद वहां धक्का देने से बचने के लिए उत्पत्ति को हटा दें और यह सुनिश्चित करने के लिए कि पुराने कामों को मूल द्वारा संदर्भित नहीं किया जाएगा:

    cd /ABC
    for i in branch1 br2 br3; do git branch -t $i origin/$i; done
    git remote rm origin
    

    या सभी दूरस्थ शाखाओं के लिए:

    cd /ABC
    for i in $(git branch -r | sed "s/.*origin\///"); do git branch -t $i origin/$i; done
    git remote rm origin
    
  3. अब आप उन टैग को भी हटाना चाहेंगे जिनके पास उपप्रोजेक्ट से कोई संबंध नहीं है; आप इसे बाद में भी कर सकते हैं, लेकिन आपको फिर से अपने रेपो को फिर से शुरू करने की आवश्यकता हो सकती है। मैंने ऐसा नहीं किया और WARNING: Ref 'refs/tags/v0.1' is unchanged मिली WARNING: Ref 'refs/tags/v0.1' is unchanged सभी टैग्स के लिए WARNING: Ref 'refs/tags/v0.1' is unchanged (क्योंकि वे सब सबप्रोजेक्ट से संबंधित नहीं थे); इसके अतिरिक्त, ऐसे टैग को हटाने के बाद और जगह पुनः प्राप्त की जाएगी। स्पष्ट रूप से git filter-branch अन्य टैग को फिर से लिखने में सक्षम होना चाहिए, लेकिन मैं इसे सत्यापित नहीं कर सका। यदि आप सभी टैग को हटाना चाहते हैं, तो git tag -l | xargs git tag -d उपयोग करें git tag -l | xargs git tag -d

  4. फिर फ़िल्टर-शाखा का उपयोग करें और अन्य फ़ाइलों को बाहर करने के लिए रीसेट करें, ताकि उन्हें काटा जा सके। चलो --tag-name-filter cat --prune-empty को हटाने और टैग को फिर से लिखने के लिए - टैग --tag-name-filter cat --prune-empty भी जोड़ें (ध्यान दें कि इसे उनके हस्ताक्षर को पट्टी करना होगा):

    git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter ABC -- --all
    

    या वैकल्पिक रूप से, केवल हेड शाखा को फिर से लिखना और टैग और अन्य शाखाओं को अनदेखा करना:

    git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter ABC HEAD
    
  5. फिर बैकअप रीफ्लॉग हटाएं ताकि अंतरिक्ष को वास्तव में पुनः दावा किया जा सके (हालांकि अब ऑपरेशन विनाशकारी है)

    git reset --hard
    git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
    git reflog expire --expire=now --all
    git gc --aggressive --prune=now
    

    और अब आपके पास एबीसी उप-निर्देशिका का स्थानीय गिट भंडार है जो इसके सभी इतिहास संरक्षित है।

नोट: अधिकांश उपयोगों के लिए, git filter-branch वास्तव में जोड़ा पैरामीटर होना चाहिए -- --all । हां यह वास्तव में डैश डैश स्पेस डैश डैश है। यह आदेश के लिए अंतिम पैरामीटर होने की जरूरत है। जैसा कि मातली ने पाया, यह प्रोजेक्ट शाखाओं और टैग को नए रेपो में शामिल करता है।

संपादित करें: नीचे टिप्पणियों के विभिन्न सुझावों को सुनिश्चित करने के लिए शामिल किया गया था, उदाहरण के लिए, कि भंडार वास्तव में संकुचित है (जो हमेशा पहले मामला नहीं था)।


कई नए फ़ोल्डरों को विभाजित करने के लिए के "द इज़ी वे ™" उत्तर में एक छोटा सा संशोधन है (चलो सब sub1 और उप 2 ) को एक नए गिट भंडार में विभाजित करें।

आसान तरीका ™ (एकाधिक उप फ़ोल्डर्स)

  1. पुराने रेपो तैयार करें

    pushd <big-repo>
    git filter-branch --tree-filter "mkdir <name-of-folder>; mv <sub1> <sub2> <name-of-folder>/" HEAD
    git subtree split -P <name-of-folder> -b <name-of-new-branch>
    popd
    

    नोट: <name-of-folder> में अग्रणी या पिछला वर्ण नहीं होना चाहिए। उदाहरण के लिए, ./subproject/ नामक फ़ोल्डर को ./subproject/ रूप में पास किया जाना चाहिए, नहीं ./subproject/

    विंडोज उपयोगकर्ताओं के लिए नोट: जब आपकी फ़ोल्डर गहराई> 1, <name-of-folder> होना चाहिए * निक्स शैली फ़ोल्डर विभाजक (/)। उदाहरण के लिए, path1\path2\subproject नामक फ़ोल्डर को path1\path2\subproject path1/path2/subproject रूप में पास किया जाना चाहिए। इसके अलावा mv कमांड का उपयोग न करें लेकिन move

    अंतिम नोट: मूल उत्तर के साथ अद्वितीय और बड़ा अंतर स्क्रिप्ट " git filter-branch... " की दूसरी पंक्ति है

  2. नया रेपो बनाएं

    mkdir <new-repo>
    pushd <new-repo>
    
    git init
    git pull </path/to/big-repo> <name-of-new-branch>
    
  3. नए रेपो को जिथूब या कहीं भी लिंक करें

    git remote add origin <[email protected]:my-user/new-repo.git>
    git push origin -u master
    
  4. अगर वांछित , सफाई

    popd # get out of <new-repo>
    pushd <big-repo>
    
    git rm -rf <name-of-folder>
    

    नोट : यह भंडार में सभी ऐतिहासिक संदर्भों को छोड़ देता है। यदि आप वास्तव में पासवर्ड करने के बारे में चिंतित हैं या आपको अपने .git फ़ोल्डर के फ़ाइल आकार को कम करने की आवश्यकता है, तो परिशिष्ट को मूल उत्तर में देखें।


पौलुस के जवाब में जोड़ने के लिए, मैंने पाया कि अंत में अंतरिक्ष को पुनर्प्राप्त करने के लिए, मुझे हेड को एक स्वच्छ भंडार में धक्का देना है और जो कि .git / ऑब्जेक्ट / पैक निर्देशिका के आकार को कम करता है।

अर्थात

$ mkdir ...ABC.git
$ cd ...ABC.git
$ git init --bare

जीसी प्रुन के बाद, यह भी करें:

$ git push ...ABC.git HEAD

फिर आप कर सकते हैं

$ git clone ...ABC.git

और एबीसी / .git का आकार कम हो गया है

दरअसल, रिपोजिटरी को साफ करने के लिए धक्का के साथ कुछ समय लेने वाले कदम (जैसे गिट जीसी) की आवश्यकता नहीं होती है, यानी:

$ git clone --no-hardlinks /XYZ /ABC
$ git filter-branch --subdirectory-filter ABC HEAD
$ git reset --hard
$ git push ...ABC.git HEAD






git-filter-branch