आप एक खराब मर्ज को कैसे ठीक करते हैं, और एक निश्चित मर्ज पर अपना अच्छा काम फिर से करते हैं?


407

मैंने गलती से एक अवांछित फ़ाइल ( filename.origएक मर्ज को हल करते हुए) मेरे भंडार के लिए कई बार पहले प्रतिबद्ध किया था, मेरे बिना इसे अब तक ध्यान नहीं दिया। मैं फाइल को रिपॉजिटरी हिस्ट्री से पूरी तरह से डिलीट करना चाहता हूं।

क्या यह परिवर्तन इतिहास को फिर से लिखना संभव है filename.origजो पहले स्थान पर भंडार में नहीं जोड़ा गया था?



जवाबों:


297

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

यद्यपि filter-branchआप जो चाहते हैं वह करेंगे, यह काफी जटिल कमांड है और मैं शायद इसके साथ ऐसा करना चुनूंगा git rebase। यह शायद व्यक्तिगत पसंद है। filter-branchएक एकल, थोड़ा और अधिक जटिल कमांड में कर सकते हैं, जबकि rebaseसमाधान एक समय में एक कदम के बराबर तार्किक संचालन कर रहा है।

निम्नलिखित नुस्खा आज़माएं:

# create and check out a temporary branch at the location of the bad merge
git checkout -b tmpfix <sha1-of-merge>

# remove the incorrectly added file
git rm somefile.orig

# commit the amended merge
git commit --amend

# go back to the master branch
git checkout master

# replant the master branch onto the corrected merge
git rebase tmpfix

# delete the temporary branch
git branch -d tmpfix

(ध्यान दें कि आपको वास्तव में एक अस्थायी शाखा की आवश्यकता नहीं है, आप इसे 'अलग-अलग हेड' के साथ कर सकते हैं, लेकिन आपको अस्थायी शाखा का उपयोग git commit --amendकरने के git rebaseबजाय कमांड को आपूर्ति करने के लिए कदम से उत्पन्न प्रतिबद्ध आईडी का ध्यान रखना होगा। नाम दें।)


6
git rebase -iतेजी से और अभी भी आसान नहीं होगा ? $ git rebase -i <sh1-of-merge> सही को "संपादित करें" $ git rm somefile.orig के रूप में चिह्नित करें $ git कमिट --amend $ git rebase --continue हालांकि किसी कारण से अभी भी उस फ़ाइल को कहीं न कहीं अंतिम रूप दिया गया है समय मैंने ऐसा किया। शायद कुछ याद आ रहा है।
वर्नट

12
git rebase -iबहुत उपयोगी है, खासकर जब आपके पास प्रदर्शन करने के लिए कई रिबेस-वाई ऑपरेशन हैं, लेकिन यह सही ढंग से वर्णन करने के लिए एक सही दर्द है जब आप वास्तव में किसी के कंधे पर इशारा नहीं कर रहे हैं और देख सकते हैं कि वे अपने संपादक के साथ क्या कर रहे हैं। मैं विम का उपयोग करता हूं, लेकिन हर कोई इससे खुश नहीं होगा: "ggjcesquash <Esc> jddjp: wq" और निर्देश जैसे "दूसरी पंक्ति के बाद शीर्ष रेखा को स्थानांतरित करें और लाइन चार पर पहला शब्द बदलकर 'संपादित करें' को अब सहेजें और छोड़ दिया "जल्दी से वास्तविक कदम हैं की तुलना में अधिक जटिल लगते हैं। आप सामान्य रूप से कुछ --amendऔर --continueकार्यों के साथ समाप्त होते हैं ।
सीबी बेली

3
मैंने ऐसा किया था लेकिन संशोधित संदेश के शीर्ष पर एक ही संदेश के साथ एक नई प्रतिबद्धता को फिर से लागू किया गया था। जाहिरा तौर पर गिट ने पुरानी फ़ाइल के बीच एक 3 रास्ता मर्ज किया था, जिसमें अवांछित फ़ाइल थी, और दूसरी शाखा से तय की गई प्रतिबद्धता थी, और इसलिए इसने पुराने के ऊपर एक नई प्रतिबद्धता बनाई, जिससे फ़ाइल को फिर से लागू किया जा सके।

6
@UncleCJ: क्या आपकी फ़ाइल मर्ज कमिट में जोड़ी गई थी? यह महत्वपूर्ण है। यह नुस्खा एक खराब मर्ज कमिट के साथ सामना करने के लिए डिज़ाइन किया गया है। अगर इतिहास में आपकी अवांछित फ़ाइल को सामान्य तरीके से जोड़ा गया है तो यह काम नहीं करेगा।
सीबी बेली

1
मुझे आश्चर्य है कि मैं यह सब स्मार्टजी और बिना किसी टर्मिनल का उपयोग किए कैसे कर सकता हूं! नुस्खा के लिए धन्यवाद!
क्रैगॉक्स

209

परिचय: आपके पास 5 समाधान उपलब्ध हैं

मूल पोस्टर में कहा गया है:

मैंने गलती से एक अनचाहे फ़ाइल को प्रतिबद्ध कर दिया है ... मेरी रिपॉजिटरी में कई कमिट्स पहले ... मैं रिपॉजिटरी हिस्ट्री से फाइल को पूरी तरह से डिलीट करना चाहता हूं।

क्या यह परिवर्तन इतिहास को फिर से लिखना संभव है filename.origजो पहले स्थान पर भंडार में नहीं जोड़ा गया था?

पूरी तरह से फ़ाइल से इतिहास को हटाने के कई अलग-अलग तरीके हैं:

  1. संशोधन करता है।
  2. हार्ड रीसेट (संभवतः प्लस ए रिबेस)।
  3. गैर-संवादात्मक छूट।
  4. परस्पर विद्रोह।
  5. छानने की शाखाएँ।

मूल पोस्टर के मामले में, कमिट में संशोधन करना वास्तव में अपने आप में एक विकल्प नहीं है, क्योंकि उन्होंने बाद में कई अतिरिक्त कमिट किए, लेकिन पूर्णता के लिए, मैं यह भी बताऊंगा कि यह कैसे करना है, किसी और के लिए जो बस चाहता है अपनी पिछली प्रतिबद्धताओं में संशोधन करने के लिए।

ध्यान दें कि इन सभी समाधानों में परिवर्तन / पुनः लेखन इतिहास शामिल है / एक अन्य तरीके से शुरू होता है, इसलिए कमिट की पुरानी प्रतियों के साथ किसी को भी अपने इतिहास को नए इतिहास के साथ फिर से सिंक करने के लिए अतिरिक्त काम करना होगा।


समाधान 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

अतिरिक्त संसाधन

  1. प्रो गिट G 6.4 गिट टूल्स - इतिहास को फिर से लिखना
  2. गिट-फिल्टर-शाखा (1) मैनुअल पेज
  3. git-प्रतिबद्ध (1) मैनुअल पेज
  4. git-reset (1) मैनुअल पेज
  5. git-rebase (1) मैनुअल पेज
  6. बीएफजी रेपो क्लीनर ( खुद निर्माता से यह जवाब भी देखें )।

क्या filter-branchहैश के पुनरावर्तन का कारण बनता है? यदि कोई टीम रेपो के साथ काम करती है जहां एक बड़ी फाइल को फ़िल्टर किया जाना चाहिए, तो वे ऐसा कैसे करते हैं कि हर कोई रेपो की एक ही स्थिति के साथ समाप्त हो जाए?
याकॉव

@YakovL। सब कुछ hashesculates। वास्तव में कमिट अपरिवर्तनीय हैं। यह पूरी तरह से नया इतिहास बनाता है, और आपकी शाखा सूचक को इसमें स्थानांतरित करता है। सभी के पास समान इतिहास सुनिश्चित करने का एकमात्र तरीका एक हार्ड रीसेट है।
मैड फिजिसिस्ट

118

यदि आपने कुछ भी नहीं किया है, तो बस git rmफ़ाइल और git commit --amend

यदि आपके पास है

git filter-branch \
--index-filter 'git rm --cached --ignore-unmatch path/to/file/filename.orig' merge-point..HEAD

से प्रत्येक परिवर्तन के माध्यम से जाना जाएगा , फ़ाइल नाम merge-pointको HEADहटा दें। --ignore-unmatchयदि किसी कारण से फ़ाइल का नाम .orig किसी परिवर्तन से अनुपलब्ध है, तो कमांड का उपयोग करना विफल नहीं होगा। Git-फ़िल्टर-शाखा मैन पेज में उदाहरण अनुभाग से अनुशंसित तरीका है ।

विंडोज उपयोगकर्ताओं के लिए ध्यान दें: फ़ाइल पथ को आगे स्लैश का उपयोग करना चाहिए


3
धन्यवाद! git फ़िल्टर-शाखा ने मेरे लिए काम किया, जहाँ एक उत्तर के रूप में दिया गया रिबेज़ उदाहरण नहीं दिया गया: कदम काम करने लग रहे थे, लेकिन फिर धक्का देना विफल हो गया। एक पुल किया, फिर सफलतापूर्वक धक्का दिया, लेकिन फ़ाइल अभी भी आसपास थी। रिबेस चरण को फिर से करने की कोशिश की और फिर मर्ज संघर्ष के साथ यह सब गड़बड़ हो गया। मैंने कुछ भिन्न फ़िल्टर-शाखा कमांड का उपयोग किया, हालांकि, "एन इम्प्रूव्ड मेथड" एक यहाँ दिया गया है: github.com/guides/completely-remove-a-file-from-all-revisions git फ़िल्टर-ब्रांच -f-index- फ़िल्टर 'git अपडेट-इंडेक्स --remove फ़ाइल नाम' <परिचय-संशोधन-sha1> .. HEAD
परमाणुभोज

1
मुझे यकीन नहीं है कि कौन सा बेहतर तरीका है। git-filter-branchपहली बार देने के लिए आधिकारिक दस्तावेज़ीकरण दें।
वर्नट

5
बाहर की जाँच करें zyxware.com/articles/4027/… मुझे लगता है कि यह सबसे पूर्ण और सीधे आगे का समाधान है जिसमें शामिल हैंfilter-branch
leontalbot

2
@atomicules, यदि आप स्थानीय रेपो को दूरस्थ एक पर धकेलने का प्रयास करेंगे, तो गिट पहले रिमोट से खींचने पर जोर देगा, क्योंकि इसमें ऐसे परिवर्तन हैं जो आपके पास स्थानीय रूप से नहीं हैं। आप रिमोट को पुश करने के लिए --force ध्वज का उपयोग कर सकते हैं - यह पूरी तरह से फ़ाइलों को वहां से हटा देगा। लेकिन सावधान रहें, सुनिश्चित करें कि आप केवल फाइलों के अलावा कुछ और लिखने के लिए मजबूर नहीं करेंगे।
sol0mka

1
Windows का उपयोग करते समय उपयोग करना "और याद नहीं करना ', या आपको एक अनपेक्षित रूप से "खराब संशोधन" त्रुटि प्राप्त होगी।
cz

49

यह सबसे अच्छा तरीका है:
http://github.com/guides/completely-remove-a-file-from-all-revisions

बस पहले फाइलों की प्रतियों का बैकअप लेना सुनिश्चित करें।

संपादित करें

नियॉन द्वारा संपादित दुर्भाग्य से समीक्षा के दौरान अस्वीकार कर दिया गया।
नीचे नीन्स पोस्ट देखें, इसमें उपयोगी जानकारी हो सकती है!


उदाहरण के लिए *.gzgit रिपॉजिटरी में गलती से किए गए सभी फाइलों को हटाने के लिए :

$ du -sh .git ==> e.g. 100M
$ git filter-branch --index-filter 'git rm --cached --ignore-unmatch *.gz' HEAD
$ git push origin master --force
$ rm -rf .git/refs/original/
$ git reflog expire --expire=now --all
$ git gc --prune=now
$ git gc --aggressive --prune=now

वह अभी भी मेरे लिए काम नहीं किया? (मैं वर्तमान में जीआईटी संस्करण 1.7.6.1 पर हूं)

$ du -sh .git ==> e.g. 100M

मुझे यकीन नहीं है, क्योंकि मेरे पास केवल एक मास्टर शाखा थी। वैसे भी, मैं अंत में एक नया खाली और नंगे गिट रिपॉजिटरी में धक्का देकर अपने git रेपो को अच्छी तरह से साफ कर लिया, जैसे।

$ git init --bare /path/to/newcleanrepo.git
$ git push /path/to/newcleanrepo.git master
$ du -sh /path/to/newcleanrepo.git ==> e.g. 5M 

(हाँ!)

फिर मैंने इसे एक नई निर्देशिका के लिए क्लोन किया और इसे एक .गित फ़ोल्डर में स्थानांतरित कर दिया। जैसे

$ mv .git ../large_dot_git
$ git clone /path/to/newcleanrepo.git ../tmpdir
$ mv ../tmpdir/.git .
$ du -sh .git ==> e.g. 5M 

(हाँ! अंत में साफ!)

यह सत्यापित करने के बाद कि सब ठीक है, तब आप निर्देशिकाओं ../large_dot_gitऔर ../tmpdirनिर्देशिकाओं को हटा सकते हैं (हो सकता है कि अब से कुछ हफ़्ते या महीने में, बस मामले में ...)


1
यह मेरे लिए काम किया "इससे पहले कि मेरे लिए अभी भी काम नहीं किया?" टिप्पणी
shadi

शानदार उत्तर, लेकिन --prune-emptyफ़िल्टर-शाखा कमांड में जोड़ने का सुझाव दें ।
विचारमेन .42

27

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

इसे जितना संभव हो उतना आसान बनाने के लिए, मैं विशेष रूप से गिट इतिहास से फ़ाइलों को हटाने के लिए डिज़ाइन किए गए बीएफजी रेपो-क्लीनर , एक सरल, तेज़ विकल्प का उपयोग करने की सलाह दूंगाgit-filter-branch । एक तरीका जिसमें यह आपके जीवन को आसान बनाता है, वह यह है कि यह वास्तव में डिफ़ॉल्ट रूप से (सभी टैग, शाखाएं, आदि) सभी रेफल्स को संभालता है , लेकिन यह भी 10 - 50x तेज है।

आपको यहां दिए गए चरणों का सावधानी से पालन करना चाहिए: http://rtyley.github.com/bfg-repo-cleaner/#usage - लेकिन मूल बिट बस यही है: BFG जार डाउनलोड करें (जावा 6 या इसके बाद के संस्करण की आवश्यकता है) और इस कमांड को चलाएं :

$ java -jar bfg.jar --delete-files filename.orig my-repo.git

आपका संपूर्ण रिपॉजिटरी इतिहास स्कैन किया जाएगा, और किसी भी फ़ाइल का नाम filename.orig(जो आपकी नवीनतम कमिट में नहीं है ) को हटा दिया जाएगा। यह एक git-filter-branchही काम करने के लिए उपयोग करने की तुलना में काफी आसान है !

पूरा खुलासा: मैं बीएफजी रेपो-क्लीनर का लेखक हूं।


4
यह एक उत्कृष्ट उपकरण है: एक एकल कमांड, यह बहुत स्पष्ट आउटपुट का उत्पादन करता है और एक लॉग फ़ाइल प्रदान करता है जो हर पुरानी प्रतिबद्ध से नए से मेल खाती है । मुझे जावा स्थापित करना पसंद नहीं है लेकिन यह इसके लायक है।
मिकाकेकाना

यह केवल एक चीज है जो मेरे लिए काम करती है, लेकिन ऐसा इसलिए है क्योंकि मैं git फ़िल्टर-शाखा को सही ढंग से काम नहीं कर रहा था। :-)
केविन लाब्रान्च

14
You should probably clone your repository first.

Remove your file from all branches history:
git filter-branch --tree-filter 'rm -f filename.orig' -- --all

Remove your file just from the current branch:
git filter-branch --tree-filter 'rm -f filename.orig' -- --HEAD    

Lastly you should run to remove empty commits:
git filter-branch -f --prune-empty -- --all

1
जबकि सभी उत्तर फ़िल्टर-शाखा ट्रैक पर प्रतीत होते हैं, यह आपके इतिहास की सभी शाखाओं को साफ़ करने का तरीका बताता है।
कैमरन लोवेल पामर

4

सिर्फ चार्ल्स बैली के समाधान में इसे जोड़ने के लिए, मैंने पहले की प्रतिबद्ध फाइलों से अवांछित फ़ाइलों को हटाने के लिए सिर्फ git rebase -i का उपयोग किया था और यह एक आकर्षण की तरह काम करता था। कदम:

# Pick your commit with 'e'
$ git rebase -i

# Perform as many removes as necessary
$ git rm project/code/file.txt

# amend the commit
$ git commit --amend

# continue with rebase
$ git rebase --continue

4

सबसे आसान तरीका मुझे सुझाया गया leontalbot(एक टिप्पणी के रूप में), जो कि अनूपजोन द्वारा प्रकाशित एक पोस्ट है । मुझे लगता है कि जवाब के रूप में इसकी अपनी जगह है:

(मैंने इसे बैश स्क्रिप्ट में बदल दिया)

#!/bin/bash
if [[ $1 == "" ]]; then
    echo "Usage: $0 FILE_OR_DIR [remote]";
    echo "FILE_OR_DIR: the file or directory you want to remove from history"
    echo "if 'remote' argument is set, it will also push to remote repository."
    exit;
fi
FOLDERNAME_OR_FILENAME=$1;

#The important part starts here: ------------------------

git filter-branch -f --index-filter "git rm -rf --cached --ignore-unmatch $FOLDERNAME_OR_FILENAME" -- --all
rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now
git gc --aggressive --prune=now

if [[ $2 == "remote" ]]; then
    git push --all --force
fi
echo "Done."

सभी क्रेडिट इसे इंगित Annopjohnकरने के leontalbotलिए , और इसके लिए जाते हैं।

ध्यान दें

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


3

निश्चित रूप से, git filter-branchजाने का रास्ता है।

अफसोस की बात है, यह filename.origआपके रेपो से पूरी तरह से हटाने के लिए पर्याप्त नहीं होगा , क्योंकि यह अभी भी टैग, रिफ्लॉग एंट्री, रीमोट्स इत्यादि द्वारा संदर्भित किया जा सकता है।

मैं इन सभी संदर्भों को हटाने की सलाह देता हूं, और फिर कचरा कलेक्टर को बुला रहा हूं। आप इस वेबसाइट git forget-blobसे स्क्रिप्ट का उपयोग एक चरण में यह सब करने के लिए कर सकते हैं ।

git forget-blob filename.orig


1

यदि यह नवीनतम प्रतिबद्धता है जिसे आप साफ करना चाहते हैं, तो मैंने git संस्करण 2.14.3 (Apple Git-98) के साथ प्रयास किया:

touch empty
git init
git add empty
git commit -m init

# 92K   .git
du -hs .git

dd if=/dev/random of=./random bs=1m count=5
git add random
git commit -m mistake

# 5.1M  .git
du -hs .git

git reset --hard HEAD^
git reflog expire --expire=now --all
git gc --prune=now

# 92K   .git
du -hs .git

git reflog expire --expire=now --all; git gc --prune=nowबहुत बुरा काम है। जब तक आप डिस्क स्थान से बाहर नहीं निकल रहे हैं, तो कुछ हफ्तों के बाद गिट कचरा इकट्ठा करें
avmohan

यह बात बताने के लिए धन्यवाद। मेरे रेपो को कई बड़ी बाइनरी फ़ाइलों के साथ प्रस्तुत किया गया था और रेपो को हर रात पूरी तरह से बैकअप दिया जाता है। इसलिए मैं अभी इसके बारे में हर बात चाहता था;)
क्लार्कटफू


-1

आप भी उपयोग कर सकते हैं:

git reset HEAD file/path


3
यदि फ़ाइल को एक कमेट में जोड़ा गया है, तो यह भी फाइल को इंडेक्स से नहीं हटाता है, यह सिर्फ इंडेक्स को फाइल के HEAD संस्करण में रीसेट करता है।
सीबी बेली
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.