अलग Git रिपॉजिटरी में डिटैच (चालें) उपनिर्देशिका


1758

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

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

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

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

XYZ/
    .git/
    XY1/
    ABC/
    XY2/

लेकिन मैं इसके बजाय यह चाहूंगा:

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

7
git filter-branchनीचे दिए गए मेरे जवाब को देखने के साथ अब यह तुच्छ है ।
jeremyjjbrown

8
@jeremyjjbrown सही है। यह अब करना मुश्किल नहीं है, लेकिन Google पर सही उत्तर खोजना मुश्किल है क्योंकि सभी पुराने उत्तर परिणामों पर हावी हैं।
एगनेल कुरियन

जवाबों:


1228

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


आप अपनी रिपॉजिटरी को क्लोन करना चाहते हैं और फिर 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सभी टैग्स के लिए मिला (क्योंकि वे सभी सबप्रोजेक्ट से संबंधित नहीं थे); इसके अलावा, इस तरह के टैग को हटाने के बाद अधिक स्थान पुनः प्राप्त किया जाएगा। जाहिरा तौर पर git filter-branchअन्य टैग को फिर से लिखने में सक्षम होना चाहिए, लेकिन मैं इसे सत्यापित नहीं कर सका। यदि आप सभी टैग हटाना चाहते हैं, तो उपयोग करें git tag -l | xargs git tag -d

  4. फिर फ़िल्टर-शाखा का उपयोग करें और अन्य फ़ाइलों को बाहर करने के लिए रीसेट करें, ताकि वे छंटनी कर सकें। आइए, --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। हाँ, यह सच है --space-- all। कमांड के लिए यह अंतिम पैरामीटर होना चाहिए। जैसा कि मातली ने खोजा था, यह परियोजना की शाखाओं और टैग को नए रेपो में शामिल करता है।

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


29
बहुत अच्छा जवाब। धन्यवाद! और वास्तव में वास्तव में जो मैं चाहता था पाने के लिए, मैंने फ़िल्टर शाखा शाखा में "- -" जोड़ा।
मटली

12
आपको आवश्यकता क्यों है --no-hardlinks? एक हार्डलिंक को हटाने से दूसरी फाइल प्रभावित नहीं होगी। Git ऑब्जेक्ट अपरिवर्तनीय भी हैं। केवल तभी जब आप अपनी आवश्यकता के स्वामी / फ़ाइल अनुमतियां बदलेंगे --no-hardlinks
vdboor

67
एक अतिरिक्त कदम जो मैं सुझाऊंगा वह होगा "git दूरस्थ rm उत्पत्ति"। अगर मैं गलत नहीं हूँ तो यह मूल भंडार में वापस जाने से धक्का देता रहेगा।
टॉम

13
एक अन्य आदेश में जोड़ने के लिए filter-branchहै --prune-empty, अब खाली प्रतिबद्ध दूर करने के लिए।
सेठ जॉनसन

8
पॉल की तरह, मुझे अपने नए रेपो में प्रोजेक्ट टैग नहीं चाहिए थे, इसलिए मैंने उपयोग नहीं किया -- --all। मैं भी दौड़ा git remote rm origin, और आज्ञा git tag -l | xargs git tag -dसे पहले git filter-branch। इसने मेरी .gitनिर्देशिका को 60M से ~ 300K तक सिकोड़ दिया। ध्यान दें कि मुझे आकार में कमी लाने के लिए इन दोनों आदेशों को चलाने की आवश्यकता थी।
saltycrane

1321

आसान तरीका ™

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

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

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

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

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

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

    mkdir ~/<new-repo> && cd ~/<new-repo>
    git init
    git pull </path/to/big-repo> <name-of-new-branch>
    
  3. नए रेपो को GitHub या जहाँ भी लिंक करें

    git remote add origin <git@github.com:user/new-repo.git>
    git push -u origin master
    
  4. यदि वांछित है<big-repo> , तो अंदर की सफाई करें

    git rm -rf <name-of-folder>
    

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

...

पूर्वाभ्यास

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

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

tree ~/node-browser-compat

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

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

cd ~/node-browser-compat/
git subtree split -P btoa -b btoa-only

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

mkdir ~/btoa/ && cd ~/btoa/
git init
git pull ~/node-browser-compat btoa-only

आगे मैं GitHub या Bitbucket पर एक नया रेपो बनाता हूं, या जो भी हो और इसे के रूप में जोड़ता हूं origin

git remote add origin git@github.com:node-browser-compat/btoa.git
git push -u origin master

शुभ दिन!

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

git pull origin master
git push origin master

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

git rm -rf btoa

...

अनुबंध

MacOS पर नवीनतम गिट

Homebrew का उपयोग कर Git का नवीनतम संस्करण प्राप्त करने के लिए :

brew install git

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

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 से फ़ाइलों को हटाने से वास्तव में उन्हें हटाया नहीं जाता है, यह सिर्फ यह कहता है कि वे अब वहां नहीं हैं। यदि आप वास्तव में ऐतिहासिक संदर्भों को हटाना चाहते हैं (यानी आपके पास कोई पासवर्ड है), तो आपको यह करने की आवश्यकता है:

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

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

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

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

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

बनाना .gitछोटा

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

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

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

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

श्रेय


16
git subtreeअभी भी 'कॉन्ट्रिब' फ़ोल्डर का हिस्सा है और सभी डिस्ट्रोस पर डिफ़ॉल्ट रूप से स्थापित नहीं है। github.com/git/git/blob/master/contrib/subtree
onionjake

11
@krlmlr sudo chmod + x /usr/share/doc/git/contub/subtree/git-subtree.sh sudo ln -s /usr/share/doc/contub/subtree/git-subtree.sh / usr / libr / git-core / git-subtree Ubuntu पर सक्रिय करने के लिए 13.04
rui.araujo

41
यदि आपने किसी पासवर्ड को सार्वजनिक रिपॉजिटरी में धकेल दिया है, तो आपको पासवर्ड को बदलना चाहिए, इसे पब्लिक रेपो से हटाने का प्रयास नहीं करना चाहिए और आशा है कि किसी ने भी इसे नहीं देखा है।
माइल्स राउत

8
यह समाधान इतिहास को संरक्षित नहीं करता है।
कूर

18
popdऔर pushdआदेश कर इस बल्कि निहित है और कठिन grok की यह करने के लिए चाहता है क्या ...
jones77

133

पॉल का जवाब / एबीसी युक्त एक नया भंडार बनाता है, लेकिन / XYZ के भीतर से / एबीसी को नहीं हटाता है। निम्नलिखित आदेश / XYZ के भीतर से एबीसी को हटा देगा:

git filter-branch --tree-filter "rm -rf ABC" --prune-empty HEAD

बेशक, इसे पहले एक 'क्लोन -नो-हार्डलिंक्स' रिपॉजिटरी में टेस्ट करें, और इसे रीसेट, जीसी और प्रून कमांड पॉल लिस्ट के साथ फॉलो करें।


53
बनाओ git filter-branch --index-filter "git rm -r -f --cached --ignore-unmatch ABC" --prune-empty HEADऔर यह बहुत तेज हो जाएगा । इंडेक्स-फिल्टर इंडेक्स पर काम करता है जबकि ट्री-फिल्टर को हर कमिट के लिए सब कुछ चेकआउट और स्टेज करना होता है
19

51
कुछ मामलों में, रिपॉजिटरी XYZ के इतिहास को गड़बड़ाने वाला ओवरकिल है ... बस एक साधारण "rm -rf ABC; git rm -r ABC; git कमिट -m'extracted ABC अपने ही रेपो में" "अधिकांश लोगों के लिए बेहतर काम करेगा।
एवगेनी

2
आप संभवतः इस कमांड पर -f (बल) का उपयोग करना चाहते हैं यदि आप इसे एक से अधिक बार करते हैं, उदाहरण के लिए, दो निर्देशिकाओं को अलग करने के बाद उन्हें हटाने के लिए। अन्यथा आपको "नया बैकअप नहीं बनाया जा सकता है।"
ब्रायन कार्लटन

4
यदि आप --index-filterविधि कर रहे हैं , तो आप इसे बनाना भी चाह सकते हैं git rm -q -r -f, ताकि प्रत्येक आह्वान इसे हटाने वाली प्रत्येक फ़ाइल के लिए एक पंक्ति प्रिंट न करें।
एरिक नेसेथ

1
मैं पॉल के उत्तर को संपादित करने का सुझाव दूंगा, केवल इसलिए कि पॉल बहुत गहन है।
एरिक एरोनिटी

96

मैंने पाया है कि नए भंडार से पुराने इतिहास को ठीक से हटाने के लिए, आपको 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
    

नहीं है इसकी व्याख्या के में फिल्टर शाखा के लिए मैनुअल


3
मुझे लगता है कि somethink git gc --aggressive --prune=nowअभी भी गायब है, है ना?
अल्बर्ट

1
@ एलबर्ट द रेपेक कमांड का ध्यान रखता है, और कोई भी ढीली वस्तु नहीं होगी।
जोश ली

हाँ, git gc --aggressive --prune=nowनए रेपो के बहुत कम
Tomek Wyderka

सरल और सुरुचिपूर्ण। धन्यवाद!
मार्को पेलेग्रिनी

40

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

यहाँ दिए गए उत्तर मेरे लिए आंशिक रूप से काम करते हैं; बड़ी फाइलें कैश में ही रह गईं। आखिरकार क्या काम किया (# घंटों के बाद freenode पर):

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

26

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

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

3
इसने एकदम जादू की तरह काम किया। उपर्युक्त उदाहरण में आपका_सुबिर है कि आप KEEP चाहते हैं, सब कुछ हटा दिया जाएगा
JT Taylor

1
आप टिप्पणी के आधार पर अद्यतन।
jeremyjjbrown

2
इस सवाल का जवाब नहीं है। डॉक्स से यह कहता है The result will contain that directory (and only that) as its project root.और वास्तव में यह वही है जो आपको मिलेगा, अर्थात मूल परियोजना संरचना संरक्षित नहीं है।
निकब्बर

2
@NicBright क्या आप एक्सवाईजेड और एबीसी के साथ अपने मुद्दे को स्पष्ट कर सकते हैं कि क्या गलत है?
एडम

@jeremyjjbrown यह संभव है कि क्लोन किए गए रेपो का पुन: उपयोग किया जाए और एक नए रेपो का उपयोग न किया जाए, अर्थात मेरा प्रश्न यहां है stackoverflow.com/questions/49269602/…
Qiulang

19

अद्यतन : गिट-सबट्री मॉड्यूल इतना उपयोगी था कि गिट टीम ने इसे कोर में खींच लिया और इसे बनाया git subtree। यहाँ देखें: अलग Git रिपॉजिटरी में डिटैच (चालें) उपनिर्देशिका

git-subtree इसके लिए उपयोगी हो सकता है

http://github.com/apenwarr/git-subtree/blob/master/git-subtree.txt (पदावनत)

http://psionides.jogger.pl/2010/02/04/sharing-code-between-projects-with-git-subtree/


1
git-subtree अब Git का हिस्सा है, हालांकि यह कंट्रीब्यूट ट्री में है, इसलिए हमेशा डिफ़ॉल्ट रूप से इंस्टॉल नहीं किया जाता है। मुझे पता है कि यह Homebrew git सूत्र द्वारा स्थापित है, लेकिन इसके मैन पेज के बिना। apenwarr इस प्रकार अपने संस्करण को अप्रचलित कहता है।
इक्रिस्टोफरसन

19

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

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

  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> में अग्रणी या अनुगामी वर्ण नहीं होना चाहिए। उदाहरण के लिए, subprojectMUST नाम के फ़ोल्डर को पास subprojectनहीं किया जाना चाहिए./subproject/

    विंडोज उपयोगकर्ताओं के लिए ध्यान दें: जब आपके फ़ोल्डर की गहराई> 1 है, <name-of-folder>तो * निक्स शैली फ़ोल्डर विभाजक (/) होना चाहिए। उदाहरण के लिए, path1\path2\subprojectMUST नाम के फोल्डर को पास किया जाना चाहिए 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 <git@github.com: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फ़ोल्डर के फ़ाइल आकार को कम करने की आवश्यकता है ।


1
यह मेरे लिए मामूली संशोधन के साथ काम किया। क्योंकि मेरे sub1और sub2फ़ोल्डर्स प्रारंभिक संस्करण के साथ मौजूद नहीं थे, इसलिए मुझे अपनी --tree-filterस्क्रिप्ट को निम्नानुसार संशोधित करना पड़ा "mkdir <name-of-folder>; if [ -d sub1 ]; then mv <sub1> <name-of-folder>/; fi":। दूसरे filter-branchकमांड के लिए मैंने <sub2> को <sub2> से हटा दिया, <name-of-folder> के निर्माण को छोड़ दिया, और एक मौजूदा बैकअप की चेतावनी को ओवरराइड करने के -fबाद शामिल किया filter-branch
प्लीजेन

यह काम नहीं करता है यदि इतिहास में इतिहास के दौरान कोई भी उपप्रकार बदल गया हो। इसे कैसे हल किया जा सकता है?
नीट्रास

@ नीरज रोजरपैक का जवाब देखते हैं। इन अन्य उत्तरों में सारी जानकारी को पढ़ने और अवशोषित करने के बाद मुझे इसे खोजने में थोड़ा समय लगा।
एडम

12

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

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

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

मैंने फिल्टर-ब्रांच के बाद आकस्मिकता खो दी

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

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


1
मुझे उस ग्राफ की शैली पसंद है। क्या मैं पूछ सकता हूं कि आप किस उपकरण का उपयोग कर रहे हैं?
स्लिप डी। थॉम्पसन

3
मैक के लिए टॉवर। मुझे वास्तव में यह पसंद है। यह अपने आप में मैक के लिए स्विच करने लायक है।
एम.एम.

2
हां, हालांकि, मेरे मामले में, मेरे सबफ़ोल्डर targetdirको कुछ बिंदु पर नाम दिया गया था और git filter-branchबस इसे एक दिन कहा जाता था, नाम बदलने से पहले किए गए सभी कमियों को हटा देना! चौंकाने वाली, यह देखते हुए कि कैसे Git ऐसी चीजों पर नज़र रखने और व्यक्तिगत सामग्री विखंडू के प्रवास पर भी है!
जे एलन

1
ओह, यह भी, अगर कोई खुद को एक ही नाव में पाता है, तो यहां मैंने जो आदेश दिया है। मत भूलो कि git rmकई आर्गन लगते हैं, इसलिए प्रत्येक फ़ाइल / फ़ोल्डर के लिए इसे चलाने का कोई कारण नहीं है: BYEBYE="dir/subdir2 dir2 file1 dir/file2"; git filter-branch -f --index-filter "git rm -q -r -f --cached --ignore-unmatch $BYEBYE" --prune-empty -- --all
जे एलन

7

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

अर्थात

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

Gc prune के बाद, यह भी करें:

$ git पुश ... ABC.git HEAD

तब आप कर सकते हैं

$ गिट क्लोन ... एबीसी

और ABC / .गित का आकार कम हो गया है

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

$ git क्लोन -नो-हार्डलिंक्स / XYZ / ABC
$ git फ़िल्टर-शाखा -subdirectory- एबीसी HEAD फ़िल्टर करें
$ जीआईटी रीसेट - भार
$ git पुश ... ABC.git HEAD

6

उचित तरीका अब निम्नलिखित है:

git filter-branch --prune-empty --subdirectory-filter FOLDER_NAME [first_branch] [another_branch]

GitHub के पास अब ऐसे मामलों के बारे में छोटे लेख भी हैं ।

लेकिन पहले अपनी मूल रेपो को अलग निर्देशिका में क्लोन करना सुनिश्चित करें (क्योंकि यह सभी फ़ाइलों और अन्य निर्देशिकाओं को हटा देगा और आपको उनके साथ काम करने की संभावित आवश्यकता होगी)।

तो आपका एल्गोरिदम होना चाहिए:

  1. अपने रिमोट रेपो को किसी अन्य निर्देशिका में क्लोन करें
  2. git filter-branchकुछ उपनिर्देशिका के तहत केवल बाईं फ़ाइलों का उपयोग करके , नए रिमोट पर पुश करें
  3. अपने मूल रिमोट रेपो से इस उपनिर्देशिका को हटाने के लिए प्रतिबद्ध बनाएं

6

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

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

ABC/
    /move_this_dir_renamed

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

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

  1. मल्टी-मॉड्यूल प्रोजेक्ट को स्थानीय स्तर पर क्लोन करें
  2. शाखाएँ - जाँच करें कि वहाँ क्या है: git branch -a
  3. अपने कार्य केंद्र पर एक स्थानीय प्रतिलिपि प्राप्त करने के लिए विभाजन में शामिल होने के लिए प्रत्येक शाखा का एक चेकआउट करें: 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. अवशेष उपखंड हटाएं: rmdir moduleSubdir1
  12. किसी भी बिंदु पर परिवर्तन देखें: git status
  13. इस परियोजना को इंगित करने के लिए नया git रेपो बनाएं और उसके URL को कॉपी करें:
  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 चरणों ।

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


1
गिट हिस्टैक में सुई मिला! अब मैं अपने सभी प्रतिबद्ध इतिहास रख सकता हूं।
एडम

5

मैं GitHub के गाइड को एक नए भंडार में सबफ़ोल्डर्स को विभाजित करने की सलाह देता हूं । कदम पॉल के जवाब के समान हैं , लेकिन मुझे उनके निर्देश समझने में आसान लगे।

मैंने निर्देशों को संशोधित किया है ताकि वे एक स्थानीय रिपॉजिटरी के लिए आवेदन करें, बजाय एक GitHub पर होस्ट किए।


सबफ़ोल्डर को एक नए रिपॉजिटरी में विभाजित करना

  1. गेट बैश खोलें।

  2. वर्तमान कार्यशील निर्देशिका को उस स्थान पर बदलें जहाँ आप अपनी नई रिपॉजिटरी बनाना चाहते हैं।

  3. सबफ़ोल्डर वाले रिपॉजिटरी को क्लोन करें।

git clone OLD-REPOSITORY-FOLDER NEW-REPOSITORY-FOLDER
  1. वर्तमान कार्य निर्देशिका को अपने क्लोन रिपॉजिटरी में बदलें।

cd REPOSITORY-NAME
  1. git filter-branchइस जानकारी की आपूर्ति करते हुए, रिपॉजिटरी में बाकी फ़ाइलों से सबफ़ोल्डर को फ़िल्टर करने के लिए, चलाएं :
    • FOLDER-NAME: आपके प्रोजेक्ट के भीतर का वह फ़ोल्डर जिससे आप एक अलग रिपॉजिटरी बनाना चाहते हैं।
      • युक्ति: विंडोज़ उपयोगकर्ताओं को /फ़ोल्डर्स को सीमांकित करने के लिए उपयोग करना चाहिए ।
    • BRANCH-NAME: आपके वर्तमान प्रोजेक्ट के लिए डिफ़ॉल्ट शाखा, उदाहरण के लिए, masterया gh-pages

git filter-branch --prune-empty --subdirectory-filter FOLDER-NAME  BRANCH-NAME 
# Filter the specified branch in your directory and remove empty commits
Rewrite 48dc599c80e20527ed902928085e7861e6b3cbe6 (89/89)
Ref 'refs/heads/BRANCH-NAME' was rewritten

अच्छी पोस्ट है, लेकिन मुझे लगता है कि आपके द्वारा लिंक किए गए डॉक्टर के पहले पैराग्राफ में कहा गया है, If you create a new clone of the repository, you won't lose any of your Git history or changes when you split a folder into a separate repository.फिर भी सभी उत्तरों पर टिप्पणियों के अनुसार दोनों filter-branchऔर subtreeस्क्रिप्ट का परिणाम इतिहास के नुकसान में है जहां कहीं भी एक उपनिर्देशिका का नाम बदल दिया गया है। क्या ऐसा कुछ है जो इसे संबोधित करने के लिए किया जा सकता है?
एडम

सभी कमिटों को संरक्षित करने के लिए समाधान मिला, जिसमें पूर्ववर्ती निर्देशिका का नाम / चाल शामिल है - यह बहुत ही सवाल का रोजगारपैक का उत्तर है।
एडम

केवल समस्या यह है कि मैं क्लोन रेपो का उपयोग किसी भी अधिक नहीं कर सकता हूं
किउलंग

5

जब चल रहा है git filter-branchके एक नए संस्करण का उपयोग कर git( 2.22+शायद?), यह इस नए उपकरण का उपयोग करने का कहना है Git फिल्टर-रेपो । यह उपकरण निश्चित रूप से मेरे लिए चीजों को सरल बनाता है।

फ़िल्टर-रेपो के साथ फ़िल्टरिंग

XYZमूल प्रश्न से रेपो बनाने की आज्ञा देता है :

# create local clone of original repo in directory XYZ
tmp $ git clone git@github.com:user/original.git XYZ

# switch to working in XYZ
tmp $ cd XYZ

# keep subdirectories XY1 and XY2 (dropping ABC)
XYZ $ git filter-repo --path XY1 --path XY2

# note: original remote origin was dropped
# (protecting against accidental pushes overwriting original repo data)

# XYZ $ ls -1
# XY1
# XY2

# XYZ $ git log --oneline
# last commit modifying ./XY1 or ./XY2
# first commit modifying ./XY1 or ./XY2

# point at new hosted, dedicated repo
XYZ $ git remote add origin git@github.com:user/XYZ.git

# push (and track) remote master
XYZ $ git push -u origin master

मान्यताओं: * दूरस्थ XYZ रेपो धक्का से पहले नया और खाली था

छानना और हिलाना

मेरे मामले में, मैं एक अधिक सुसंगत संरचना के लिए कुछ निर्देशिकाओं को स्थानांतरित करना चाहता था। प्रारंभ में, मैंने उस सरल filter-repoआदेश का पालन किया git mv dir-to-rename, लेकिन मैंने पाया कि मैं --path-renameविकल्प का उपयोग करके थोड़ा "बेहतर" इतिहास प्राप्त कर सकता हूं । 5 hours agoनए रेपो में अब संशोधित फ़ाइलों पर अंतिम संशोधित देखने के बजाय मैं अब last year(GitHub UI में) देखता हूं , जो मूल रेपो में संशोधित समय से मेल खाता है।

के बजाय...

git filter-repo --path XY1 --path XY2 --path inconsistent
git mv inconsistent XY3  # which updates last modification time

मैं आखिरकार भाग गया ...

git filter-repo --path XY1 --path XY2 --path inconsistent --path-rename inconsistent:XY3
टिप्पणियाँ:
  • मुझे लगा कि Git Rev News ब्लॉग पोस्ट ने एक और रीपो-फ़िल्टरिंग टूल बनाने के पीछे तर्क को अच्छी तरह से समझाया है।
  • मैंने शुरू में मूल रिपॉजिटरी में टारगेट रेपो नाम से मेल खाते हुए उप-निर्देशिका बनाने और फिर फ़िल्टरिंग (उपयोग करने git filter-repo --subdirectory-filter dir-matching-new-repo-name) का मार्ग आज़माया । उस आदेश ने प्रतिलिपि किए गए स्थानीय रेपो की जड़ में उस उपनिर्देशिका को सही ढंग से परिवर्तित किया, लेकिन इसके परिणामस्वरूप उपनिर्देशिका बनाने के लिए केवल तीन प्रतिबद्धताओं के इतिहास का परिणाम आया। (मुझे यह एहसास नहीं था कि --pathकई बार निर्दिष्ट किया जा सकता है; इस प्रकार, स्रोत रेपो में एक उपनिर्देशिका बनाने की आवश्यकता को मानते हुए।) जब से किसी ने स्रोत रेपो के लिए प्रतिबद्ध किया था तब तक मैंने देखा था कि मैं आगे ले जाने में विफल रहा। इतिहास, मैंने सिर्फ कमांड के git reset commit-before-subdir-move --hardबाद उपयोग किया clone, और इसे थोड़ा संशोधित स्थानीय क्लोन पर संचालित --forceकरने के लिए filter-repoकमांड में जोड़ा ।
git clone ...
git reset HEAD~7 --hard      # roll back before mistake
git filter-repo ... --force  # tell filter-repo the alterations are expected
  • जब से मैं विस्तार के पैटर्न से अनजान था, तब से मैं स्टॉप पर स्टम्प्ड था git, लेकिन आखिरकार मैंने git-filter-repo को क्लोन किया और इसे सिम्प्लाइड किया $(git --exec-path):
ln -s ~/github/newren/git-filter-repo/git-filter-repo $(git --exec-path)

1
नई सिफारिश करने के लिए upvoted filter-repoउपकरण (जो मैं में पिछले महीने प्रस्तुत stackoverflow.com/a/58251653/6309 )
VonC

का उपयोग करना git-filter-repoनिश्चित रूप से इस बिंदु पर वरीय दृष्टिकोण होना चाहिए। यह बहुत तेजी से और अधिक सुरक्षित है git-filter-branch, और सुरक्षा के लिए बहुत सारे गोचरों के खिलाफ है जब एक के इतिहास को फिर से लिखना हो सकता है। उम्मीद है कि इस जवाब पर कुछ और ध्यान जाता है, क्योंकि यह पता करने वाला है git-filter-repo
जेरेमी कैन

4

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

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

https://github.com/slobobaby/git_filter

GitHub पर।

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


4

अपने टैग और शाखाओं को संरक्षित करते हुए, एक उपनिर्देशिका को हटाने के लिए इस फ़िल्टर कमांड का उपयोग करें:

git filter-branch --index-filter \
"git rm -r -f --cached --ignore-unmatch DIR" --prune-empty \
--tag-name-filter cat -- --all

बिल्ली यहाँ क्या है?
रोज़गारपैक

4

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

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 git@github.com:MyTeam/mynewrepo.git
    git remote add origin etc। काम नहीं किया, " remote origin already exists"

  4. $ git push --progress some_name master


3

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

सबसे पहले , filter-branchकरता जो परिचय या संशोधित कोड लेकिन जाहिरा तौर पर, को दूर करने का काम ऊपर एक धमाके किया मर्ज करता Gitiverse में अपनी स्टेशन के नीचे हैं।

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

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

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

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


3

आसान तरीका है

  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

  3. कहीं एक खाली रेपो बनाएं। हम मान लेंगे कि हमने xyzGitHub पर एक खाली रेपो बनाया है जिसमें पथ है:git@github.com: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 git@github.com: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 git@github.com:simpliwp/xyz.git


"द ईजी वे" की तुलना में इस पद्धति का एक फायदा यह है कि नए रेपो के लिए रिमोट पहले से ही सेट है, इसलिए आप तुरंत सबट्री ऐड कर सकते हैं। वास्तव में यह रास्ता मुझे आसान लगता है (बिना भी git splits)
MM

इस समाधान को पोस्ट करने के लिए एंड्रयूडी को सहारा देता है। मैंने अपने रेपो को OSX पर काम करने के लिए फोर्क किया है ( github.com/ricardoespsanto/git-splits ) अगर यह किसी और के लिए उपयोगी है
ricardoespsanto

2

वास्तव में फ़ाइलों को साफ करने के लिए कचरा संग्रह से पहले आपको "git reflog expire --expire = now --all" जैसी किसी चीज़ की आवश्यकता हो सकती है। git फ़िल्टर-शाखा सिर्फ इतिहास में संदर्भों को हटाती है, लेकिन डेटा को रखने वाली रिफ्लग प्रविष्टियों को नहीं हटाती है। बेशक, यह पहले परीक्षण करें।

ऐसा करने में मेरी डिस्क का उपयोग नाटकीय रूप से कम हो गया, हालांकि मेरी प्रारंभिक शर्तें कुछ अलग थीं। शायद --subdirectory- फ़िल्टर इस आवश्यकता को नकारता है, लेकिन मुझे संदेह है।


2

पर git_split प्रोजेक्ट देखें Https://github.com/vangorra/git_split देखें

अपने स्वयं के स्थान पर git निर्देशिकाओं को अपने स्वयं के रिपॉजिटरी में बदल दें। कोई सबट्री फनी बिजनेस नहीं। यह स्क्रिप्ट आपके गिट रिपॉजिटरी में एक मौजूदा डायरेक्टरी लेगी और उस डायरेक्टरी को खुद के स्वतंत्र रिपॉजिटरी में बदल देगी। साथ ही, यह आपके द्वारा प्रदान की गई निर्देशिका के लिए संपूर्ण परिवर्तन इतिहास की नकल करेगा।

./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.

1

इसे अपने 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'

1

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


3
सबट्री का "ठीक और अद्भुत" हिस्सा यह है कि आपकी उपनिर्देशिका का इतिहास सवारी के लिए आता है। अगर आपको इतिहास की जरूरत नहीं है, तो आपकी दर्द भरी आसान विधि रास्ता है।
प्लीजेन

0

आप आसानी से कोशिश कर सकते हैं https://help.github.com/enterprise/2.15/user/articles/splitting-a-subfolder-out-into-a-new-repository/

इसने मेरे लिए काम किया। ऊपर दिए गए चरणों में मैंने जिन मुद्दों का सामना किया है वे हैं

  1. इस आदेश में है गुरुgit filter-branch --prune-empty --subdirectory-filter FOLDER-NAME BRANCH-NAMEBRANCH-NAME

  2. यदि सुरक्षा समस्या के कारण प्रतिबद्ध होने पर अंतिम चरण विफल रहता है - https://docs.gitlab.com/ee/user/project/protected_branches.html


0

मुझे काफी सीधा फॉरवर्ड सॉल्यूशन मिला है, यह विचार रिपॉजिटरी को कॉपी करना है और फिर अनावश्यक भाग को हटा देना है। यह इस तरह काम करता है:

1) क्लोन एक रिपॉजिटरी जिसे आप विभाजित करना चाहते हैं

git clone git@git.thehost.io:testrepo/test.git

2) गिट फ़ोल्डर में ले जाएँ

cd test/

2) अनावश्यक फ़ोल्डर निकालें और इसे प्रतिबद्ध करें

rm -r ABC/
git add .
enter code here
git commit -m 'Remove ABC'

3) बीएफजी के साथ अनावश्यक फ़ोल्डर (ओं) के इतिहास को हटा दें

cd ..
java -jar bfg.jar --delete-folders "{ABC}" test
cd test/
git reflog expire --expire=now --all && git gc --prune=now --aggressive

बहु फ़ोल्डर के लिए आप अल्पविराम का उपयोग कर सकते हैं

java -jar bfg.jar --delete-folders "{ABC1,ABC2}" metric.git

4) जाँच करें कि इतिहास में आपके द्वारा अभी-अभी हटाई गई फ़ाइलें / फ़ोल्डर शामिल नहीं हैं

git log --diff-filter=D --summary | grep delete

5) अब आपके पास एबीसी के बिना स्वच्छ भंडार है, इसलिए इसे नए मूल में धकेल दें

remote add origin git@github.com:username/new_repo
git push -u origin master

बस। आप एक और रिपॉजिटरी पाने के लिए चरणों को दोहरा सकते हैं,

बस XY1, XY2 को हटा दें और चरण 3 पर XYZ -> ABC का नाम बदलें


लगभग सही ... लेकिन आप सभी पुराने कमिट जो अब खाली हैं, को हटाने के लिए "git फ़िल्टर-शाखा -prune-blank" भूल गए। मूल गुरु को धक्का देने से पहले करने के लिए!
ZettaCircl

यदि आपने गलती की है और अभी भी पुरानी खाली प्रतिबद्ध को हटाने के बाद "पुनर्खरीद" करना चाहते हैं, तो प्रदर्शन करें: "गिट पुश -यू मूल मास्टर --फोर्स-विद-लीज"
ज़ेटासीर्कल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.