ऐसा करने का एक तरीका उलटा है - सब कुछ हटा दें लेकिन वह फ़ाइल जिसे आप रखना चाहते हैं।
मूल रूप से, रिपॉजिटरी की एक प्रति बनाएं , फिर git filter-branchसब कुछ हटाने के लिए उपयोग करें लेकिन वह फ़ाइल / फ़ोल्डर जिसे आप रखना चाहते हैं।
उदाहरण के लिए, मेरे पास एक प्रोजेक्ट है जिसमें से मैं tvnamer.pyएक नई रिपॉजिटरी में फाइल निकालना चाहता हूं :
git filter-branch --tree-filter 'for f in *; do if [ $f != "tvnamer.py" ]; then rm -rf $f; fi; done' HEAD
यह git filter-branch --tree-filterप्रत्येक कमिट के माध्यम से जाने, कमांड चलाने और परिणामी निर्देशिका सामग्री को फिर से जोड़ने का उपयोग करता है। यह बेहद विनाशकारी है (इसलिए आपको केवल अपनी रिपॉजिटरी की कॉपी पर ही ऐसा करना चाहिए!), और 300 कमिट और लगभग 20 फाइलों के साथ रिपॉजिटरी पर लगभग 1 मिनट का समय लग सकता है।
उपरोक्त आदेश प्रत्येक संशोधन पर केवल निम्नलिखित शेल-स्क्रिप्ट चलाता है, जिसे आपको निश्चित रूप से संशोधित करना होगा (इसके बजाय अपनी उप-निर्देशिका को बाहर करने के लिए tvnamer.py):
for f in *; do
if [ $f != "tvnamer.py" ]; then
rm -rf $f;
fi;
done
सबसे बड़ी समस्या यह है कि यह सभी प्रतिबद्ध संदेशों को छोड़ देता है, भले ही वे शेष फ़ाइल से असंबंधित हों। स्क्रिप्ट git-remove-blank-commits , इसे ठीक करता है ।।
git filter-branch --commit-filter 'if [ z$1 = z`git rev-parse $3^{tree}` ]; then skip_commit "$@"; else git commit-tree "$@"; fi'
आपको कुछ भी (जो मूल रूप से एक बैकअप है) के साथ फिर से -fचलने वाले बल तर्क का उपयोग करने की आवश्यकता हैfilter-branchrefs/original/
बेशक, यह कभी भी सही नहीं होगा, उदाहरण के लिए यदि आपके प्रतिबद्ध संदेशों में अन्य फ़ाइलों का उल्लेख है, लेकिन यह लगभग वर्तमान स्थिति की अनुमति देता है (जहाँ तक मुझे पता है)।
फिर से, केवल कभी इसे अपने भंडार की प्रति पर चलाएं! - लेकिन सारांश में, सभी फ़ाइलों को हटाने के लिए लेकिन "thisismyfilename.txt":
git filter-branch --tree-filter 'for f in *; do if [ $f != "thisismyfilename.txt" ]; then rm -rf $f; fi; done' HEAD
git filter-branch -f --commit-filter 'if [ z$1 = z`git rev-parse $3^{tree}` ]; then skip_commit "$@"; else git commit-tree "$@"; fi'