परिचय: आपके पास 5 समाधान उपलब्ध हैं
मूल पोस्टर में कहा गया है:
मैंने गलती से एक अनचाहे फ़ाइल को प्रतिबद्ध कर दिया है ... मेरी रिपॉजिटरी में कई कमिट्स पहले ... मैं रिपॉजिटरी हिस्ट्री से फाइल को पूरी तरह से डिलीट करना चाहता हूं।
क्या यह परिवर्तन इतिहास को फिर से लिखना संभव है filename.orig
जो पहले स्थान पर भंडार में नहीं जोड़ा गया था?
पूरी तरह से फ़ाइल से इतिहास को हटाने के कई अलग-अलग तरीके हैं:
- संशोधन करता है।
- हार्ड रीसेट (संभवतः प्लस ए रिबेस)।
- गैर-संवादात्मक छूट।
- परस्पर विद्रोह।
- छानने की शाखाएँ।
मूल पोस्टर के मामले में, कमिट में संशोधन करना वास्तव में अपने आप में एक विकल्प नहीं है, क्योंकि उन्होंने बाद में कई अतिरिक्त कमिट किए, लेकिन पूर्णता के लिए, मैं यह भी बताऊंगा कि यह कैसे करना है, किसी और के लिए जो बस चाहता है अपनी पिछली प्रतिबद्धताओं में संशोधन करने के लिए।
ध्यान दें कि इन सभी समाधानों में परिवर्तन / पुनः लेखन इतिहास शामिल है / एक अन्य तरीके से शुरू होता है, इसलिए कमिट की पुरानी प्रतियों के साथ किसी को भी अपने इतिहास को नए इतिहास के साथ फिर से सिंक करने के लिए अतिरिक्त काम करना होगा।
समाधान 1: संशोधन भेजना
यदि आपने गलती से अपनी पिछली कमिट में कोई परिवर्तन (जैसे कोई फ़ाइल जोड़ना) कर दिया है, और आप नहीं चाहते कि उस परिवर्तन का इतिहास अब मौजूद है, तो आप फ़ाइल को हटाने के लिए पिछले कमिट में संशोधन कर सकते हैं:
git rm <file>
git commit --amend --no-edit
समाधान 2: हार्ड रीसेट (संभवतः प्लस ए रिबेस)
समाधान # 1 की तरह, यदि आप केवल अपनी पिछली प्रतिबद्धताओं से छुटकारा पाना चाहते हैं, तो आपके पास बस इसके लिए एक हार्ड रीसेट करने का विकल्प भी है:
git reset --hard HEAD^
वह कमांड आपकी शाखा को पिछली 1 सेंट पेरेंट कमेटी में हार्ड-रीसेट कर देगा ।
हालाँकि , यदि मूल पोस्टर की तरह, आपने कई बदलाव किए हैं, तो आप जिस बदलाव को पूर्ववत करना चाहते हैं, उसके बाद भी आप इसे संशोधित करने के लिए हार्ड रीसेट का उपयोग कर सकते हैं, लेकिन ऐसा करने में रिबास का उपयोग करना भी शामिल है। यहां वे चरण दिए गए हैं, जिनका उपयोग करके आप इतिहास में एक और संशोधन कर सकते हैं:
# Create a new branch at the commit you want to amend
git checkout -b temp <commit>
# Amend the commit
git rm <file>
git commit --amend --no-edit
# Rebase your previous branch onto this new commit, starting from the old-commit
git rebase --preserve-merges --onto temp <old-commit> master
# Verify your changes
git diff master@{1}
समाधान 3: गैर-इंटरैक्टिव रिबेस
यह काम करेगा यदि आप केवल इतिहास से पूरी तरह से एक प्रतिबद्ध निकालना चाहते हैं:
# Create a new branch at the parent-commit of the commit that you want to remove
git branch temp <parent-commit>
# Rebase onto the parent-commit, starting from the commit-to-remove
git rebase --preserve-merges --onto temp <commit-to-remove> master
# Or use `-p` insteda of the longer `--preserve-merges`
git rebase -p --onto temp <commit-to-remove> master
# Verify your changes
git diff master@{1}
समाधान 4: इंटरएक्टिव छूट
यह समाधान आपको समाधान # 2 और # 3 के रूप में एक ही चीज़ों को पूरा करने की अनुमति देगा, अर्थात अपने तुरंत पिछले प्रतिबद्ध की तुलना में इतिहास में आगे वापस संशोधित या हटाता है, इसलिए आप किस समाधान का उपयोग करना चाहते हैं, यह आपके ऊपर निर्भर करता है। प्रदर्शन के कारणों के लिए इंटरएक्टिव विद्रोह सैकड़ों कॉमा को रिबास करने के लिए अच्छी तरह से अनुकूल नहीं है, इसलिए मैं उन प्रकार की स्थितियों में गैर-इंटरैक्टिव विद्रोह या फ़िल्टर शाखा समाधान (नीचे देखें) का उपयोग करूंगा।
इंटरैक्टिव रिबास शुरू करने के लिए, निम्नलिखित का उपयोग करें:
git rebase --interactive <commit-to-amend-or-remove>~
# Or `-i` instead of the longer `--interactive`
git rebase -i <commit-to-amend-or-remove>~
यह कमिट इतिहास को उस कमिट के माता-पिता को वापस करने का कारण बनेगा जिसे आप संशोधित या हटाना चाहते हैं। इसके बाद आपको जो भी एडिटर git का उपयोग करने के लिए सेट किया गया है (यह डिफ़ॉल्ट रूप से Vim है) में रिवर्स ऑर्डर की एक सूची प्रस्तुत करता है:
pick 00ddaac Add symlinks for executables
pick 03fa071 Set `push.default` to `simple`
pick 7668f34 Modify Bash config to use Homebrew recommended PATH
pick 475593a Add global .gitignore file for OS X
pick 1b7f496 Add alias for Dr Java to Bash config (OS X)
आप जिस कमिट को संशोधित या हटाना चाहते हैं वह इस सूची में सबसे ऊपर होगा। इसे निकालने के लिए, सूची में इसकी लाइन को हटा दें। अन्यथा, "पिक" को 1 सेंट लाइन पर "एडिट" से बदलें , जैसे:
edit 00ddaac Add symlinks for executables
pick 03fa071 Set `push.default` to `simple`
अगला, दर्ज करें git rebase --continue
। यदि आपने पूरी तरह से प्रतिबद्ध को हटाने के लिए चुना है, तो यह है कि आपको यह करने की आवश्यकता है (सत्यापन के अलावा, इस समाधान के लिए अंतिम चरण देखें)। यदि, दूसरी ओर, आप कमिट को संशोधित करना चाहते हैं, तो git दोबारा कमिट करेगा और फिर रिबास को रोक देगा।
Stopped at 00ddaacab0a85d9989217dd9fe9e1b317ed069ac... Add symlinks
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
इस बिंदु पर, आप फ़ाइल को हटा सकते हैं और कमिट कर सकते हैं, फिर रिबास जारी रख सकते हैं:
git rm <file>
git commit --amend --no-edit
git rebase --continue
बस। अंतिम चरण के रूप में, चाहे आपने कमिट को संशोधित किया हो या इसे पूरी तरह से हटा दिया हो, यह सत्यापित करने के लिए हमेशा एक अच्छा विचार है कि रिबेट से पहले इसे अपने राज्य के साथ अलग करके आपकी शाखा में कोई अन्य अप्रत्याशित परिवर्तन नहीं किए गए हैं:
git diff master@{1}
समाधान 5: छानने की शाखाओं
अंत में, यह समाधान सबसे अच्छा है यदि आप इतिहास से फ़ाइल के अस्तित्व के सभी निशानों को पूरी तरह से मिटा देना चाहते हैं, और अन्य समाधानों में से कोई भी कार्य के लिए काफी नहीं है।
git filter-branch --index-filter \
'git rm --cached --ignore-unmatch <file>'
जो <file>
रूट कमिट से शुरू होकर सभी कमिट्स को हटा देगा । तुम सिर्फ पुनर्लेखन के लिए सीमा के लिए प्रतिबद्ध चाहते हैं बजाय HEAD~5..HEAD
, तो आप उस के लिए एक अतिरिक्त तर्क के रूप में पारित कर सकते हैं filter-branch
, में उठाई बाहर के रूप में
इस सवाल का जवाब :
git filter-branch --index-filter \
'git rm --cached --ignore-unmatch <file>' HEAD~5..HEAD
फिर से, filter-branch
पूरा होने के बाद , यह आमतौर पर यह सत्यापित करने के लिए एक अच्छा विचार है कि फ़िल्टरिंग ऑपरेशन से पहले अपनी शाखा को अपनी पिछली स्थिति से अलग करके कोई अन्य अप्रत्याशित परिवर्तन नहीं हैं:
git diff master@{1}
फ़िल्टर-शाखा वैकल्पिक: बीएफजी रेपो क्लीनर
मैंने सुना है कि बीएफजी रेपो क्लीनर उपकरण तेजी से चलता है git filter-branch
, इसलिए आप इसे एक विकल्प के रूप में भी जांच सकते हैं। यह भी एक व्यवहार्य विकल्प के रूप में फिल्टर-शाखा प्रलेखन में आधिकारिक तौर पर उल्लेख किया गया है :
गिट-फिल्टर-शाखा आपको अपने गिट इतिहास के जटिल शेल-स्क्रिप्टेड पुनर्लेखन बनाने की अनुमति देती है, लेकिन आपको संभवतः इस लचीलेपन की आवश्यकता नहीं है यदि आप बड़ी फ़ाइलों या पासवर्ड जैसे अवांछित डेटा को हटा रहे हैं। उन परिचालनों के लिए आप बीएफजी रेपो-क्लीनर पर विचार कर सकते हैं , जो एक जेवीएम-आधारित विकल्प है जो गिट-फिल्टर-ब्रांच, आमतौर पर उन उपयोग के मामलों के लिए कम से कम 10-50x तेज, और काफी भिन्न विशेषताओं के साथ:
किसी फ़ाइल के किसी विशेष संस्करण को बिल्कुल एक बार साफ किया जाता है । बीएफजी, गिट-फिल्टर-शाखा के विपरीत, आपको एक फ़ाइल को अलग से संभालने का अवसर नहीं देता है जहां यह आपके इतिहास में कहां या कब प्रतिबद्ध था। यह बाधा बीएफजी के मुख्य प्रदर्शन का लाभ देती है, और खराब डेटा को साफ करने के कार्य के लिए अच्छी तरह से अनुकूल है - आपको परवाह नहीं है कि खराब डेटा कहां है, आप बस चाहते हैं कि यह चले गए ।
डिफ़ॉल्ट रूप से बीएफजी मल्टी-कोर मशीनों का पूर्ण लाभ उठाते हैं, समानांतर में फाइल-पेड़ों को साफ करते हैं। Git फिल्टर शाखा साफ करता क्रमिक रूप से (यानी एक एकल थ्रेड ढंग से), हालांकि यह है
फिल्टर है कि उनके अपने parallellism शामिल लिखने के लिए संभव है, में स्क्रिप्ट प्रत्येक के खिलाफ निष्पादित करते हैं।
आदेश विकल्प सिर्फ अवांछित डेटा- जैसे हटाने का कार्य करने के लिए Git फिल्टर शाखा की तुलना में बहुत अधिक प्रतिबंधात्मक, और समर्पित कर रहे हैं: --strip-blobs-bigger-than 1M
।
अतिरिक्त संसाधन
- प्रो गिट G 6.4 गिट टूल्स - इतिहास को फिर से लिखना ।
- गिट-फिल्टर-शाखा (1) मैनुअल पेज ।
- git-प्रतिबद्ध (1) मैनुअल पेज ।
- git-reset (1) मैनुअल पेज ।
- git-rebase (1) मैनुअल पेज ।
- बीएफजी रेपो क्लीनर ( खुद निर्माता से यह जवाब भी देखें )।