मेरे git रेपो से अपरिचित ब्लॉब्स को कैसे निकालें


124

मेरे पास एक GitHub रेपो है जिसकी दो शाखाएँ थीं - मास्टर और रिलीज़।

रिलीज़ ब्रांच में बाइनरी डिस्ट्रीब्यूशन फाइलें थीं जो बहुत बड़े रेपो साइज़ (> 250 एमबी) में योगदान कर रही थीं, इसलिए मैंने चीजों को साफ करने का फैसला किया।

पहले मैंने रिमोट रिलीज़ ब्रांच को डिलीट किया git push origin :release

फिर मैंने स्थानीय रिलीज़ शाखा को हटा दिया। पहले मैंने कोशिश की git branch -d release, लेकिन गिट ने कहा "त्रुटि: शाखा 'रिलीज' आपके वर्तमान हेड का पूर्वज नहीं है।" जो सच है, तो फिर मैंने git branch -D releaseइसे हटाने के लिए मजबूर किया।

लेकिन मेरा भंडार आकार, दोनों स्थानीय और GitHub पर, अभी भी बहुत बड़ा था। तो फिर मैं git gc --prune=today --aggressiveकोई आदेश के साथ, जैसे , गिट कमांड की सामान्य सूची के माध्यम से भाग गया ।

एसओ 1029969 में चार्ल्स बेली के निर्देशों का पालन करके मैं सबसे बड़ी बूँद के लिए SHA1s की एक सूची प्राप्त करने में सक्षम था। मैंने तब एसओ 460331 से स्क्रिप्ट का इस्तेमाल करके ब्लब्स को खोजा ... और पांच सबसे बड़ी मौजूद नहीं हैं, हालांकि छोटे ब्लब्स पाए जाते हैं, इसलिए मुझे पता है कि स्क्रिप्ट काम कर रही है।

मुझे लगता है कि ये ब्लॉग रिलीज़ शाखा से बायनेरिज़ हैं, और वे किसी तरह उस शाखा को हटाने के बाद चारों ओर से निकल गए। इनसे छुटकारा पाने का सही तरीका क्या है?


आप किस संस्करण का उपयोग कर रहे हैं? और क्या आपने stackoverflow.com/questions/1106529/… की कोशिश की ?
वॉन

git संस्करण 1.6.2.3 मैंने gc और prune w / विभिन्न तर्कों की कोशिश की। मैं repack -a -d -l की कोशिश नहीं की थी, बस इसे चलाया, कोई बदलाव नहीं।
krrugler

2
नई जानकारी - GitHub के एक ताजा क्लोन में अब अपरिचित बूँदें नहीं हैं, और 250MB से "केवल" 84MB तक नीचे है।
क्रुकलर १५'०

जवाबों:


219

... और आगे की हलचल के बिना, मैं आपके लिए यह उपयोगी कमांड "git-gc-all" प्रस्तुत कर सकता हूं, आपके सभी गिट कचरे को हटाने की गारंटी देता हूं जब तक कि वे अतिरिक्त कॉन्फ़िगरेशन चर नहीं ला सकते:

git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 -c gc.rerereresolved=0 -c gc.rerereunresolved=0 -c gc.pruneExpire=now gc

आपको भी कुछ इस तरह से चलाने की आवश्यकता हो सकती है, ओह प्रिय, गिट जटिल है !!

git remote rm origin
rm -rf .git/refs/original/ .git/refs/remotes/ .git/*_HEAD .git/logs/
git for-each-ref --format="%(refname)" refs/original/ | xargs -n1 --no-run-if-empty git update-ref -d

आपको कुछ टैग हटाने की आवश्यकता हो सकती है, धन्यवाद Zitrax:

git tag | xargs git tag -d

मैंने यह सब एक स्क्रिप्ट में रखा है: git-gc-all-ferocious


1
दिलचस्प। मेरे अधिक सामान्य उत्तर के लिए एक अच्छा विकल्प। +1
VonC

10
यह अधिक वोटों का हकदार है। यह अंत में बहुत सारे गिट वस्तुओं से छुटकारा दिलाता है जो अन्य तरीके रखेंगे। धन्यवाद!
जीन-फिलिप पेलेट

1
Upvoted। वाह, मुझे नहीं पता कि मैंने अभी क्या किया है, लेकिन यह बहुत साफ लगता है। क्या आप इस बारे में विस्तार से बता सकते हैं कि यह क्या करता है? मुझे लग रहा है कि यह मेरे सभी को साफ कर देगा objects। वे क्या हैं और वे (जाहिरा तौर पर) अप्रासंगिक क्यों हैं?
रेड्सनड्रो

1
@ रोदसंद्रो, जैसा कि मैं समझता हूं, उन "गिट आरएम उत्पत्ति", "आरएम" और "गिट अपडेट-रेफ-डी" कमांड रिमॉड्स के लिए पुराने कमिट के संदर्भ को हटा देते हैं और ऐसे, जो कचरा संग्रह को रोक सकते हैं। "Git gc" के विकल्प यह बताते हैं कि विभिन्न पुराने कमिट्स पर होल्ड न करें, अन्यथा यह कुछ समय के लिए उन पर होल्ड रहेगा। उदाहरण के लिए gerrereresolved "विरोधाभासी मर्ज के रिकॉर्ड जिसे आपने पहले हल किया था", डिफ़ॉल्ट रूप से 60 दिनों के लिए रखा गया है। वे विकल्प git-gc manpage में हैं। मैं git का विशेषज्ञ नहीं हूं और यह नहीं जानता कि ये सभी चीजें क्या करती हैं। मैं उन्हें manpages से मिला, और grepping .िट कम रिफ के लिए।
सैम वाटकिंस

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

81

जैसा कि यहां बताया गया है , यदि आप केवल संदर्भित सभी चीज़ों को स्थायी रूप से हटाना चाहते हैं , तो बस उपयोग करें

git reflog expire --expire-unreachable=now --all
git gc --prune=now

git reflog expire --expire-unreachable=now --allअप्राप्य के सभी संदर्भों को हटा देता है reflog

git gc --prune=now खुद को हटा देता है।

ध्यान दें : केवल उपयोग git gc --prune=nowकरने से काम नहीं चलेगा क्योंकि उन कमिटों को अभी भी रिफ्लॉग में संदर्भित किया गया है। इसलिए, रिफ्लग को साफ़ करना अनिवार्य है। यह भी ध्यान रखें कि यदि आप इसका उपयोग करते हैं rerereतो इन सन्दर्भों से साफ़ नहीं किए गए अतिरिक्त संदर्भ हैं। git help rerereअधिक जानकारी के लिए देखें। इसके अलावा, स्थानीय या दूरस्थ शाखाओं या टैग द्वारा संदर्भित किसी भी तरह के कमिट को हटाया नहीं जाएगा क्योंकि उन लोगों को गिट द्वारा मूल्यवान डेटा माना जाता है।


14
यह काम किया है, लेकिन किसी तरह मैं इस प्रक्रिया में मेरे सहेजे गए नुकसान को खो दिया (मेरे मामले में कुछ भी बड़ा नहीं है, दूसरों के लिए सिर्फ एक सावधानी)
अमरो

1
क्यों नहीं - प्रगतिशील?
जोएलफैन

2
मुझे लगता है कि इस उत्तर को स्पष्ट चेतावनी की जरूरत है, अधिमानतः शीर्ष पर। मेरा संपादन सुझाव अस्वीकार कर दिया गया था, क्योंकि मुझे लगता है कि मुझे एक टिप्पणी में लेखक को सुझाव देना चाहिए? कृपया या तो इस संपादित करें stackoverflow.com/review/suggested-edits/26023988 को स्वीकार करें या अपने तरीके से चेतावनी जोड़ें। इसके अलावा, यह आपके सभी बाधाओं को छोड़ देता है । कि चेतावनी में भी याद किया जाना चाहिए!
Inigo

मैंने git संस्करण 2.17 के साथ परीक्षण किया है और उपरोक्त आदेशों के अनुसार चरणबद्ध तरीके से हटाया नहीं जाएगा। क्या आप वाकई कोई अतिरिक्त कमांड नहीं चला रहे हैं?
मिको रानाल्टेन

1
git fetch --pruneस्थानीय ब्लब्स को हटाने के कारण आकार को और कम करना।
हेक्टरपाल

33

जैसा कि इस SO उत्तर में बताया गया है , git gcवास्तव में रेपो के आकार को बढ़ा सकता है!

इस धागे को भी देखें

अब git के पास एक सुरक्षा तंत्र है जो ' ' 'रनिंग के दौरान अपरिचित वस्तुओं को तुरंत नहीं हटाता है git gc
डिफ़ॉल्ट रूप से अप्रतिबंधित वस्तुओं को लगभग 2 सप्ताह की अवधि के लिए रखा जाता है। यह आपके लिए गलती से हटाई गई शाखाओं या कमिट्स को पुनर्प्राप्त करना या दौड़ से बचने के लिए आसान है, जहां एक प्रक्रिया बनाई गई है, लेकिन अभी तक संदर्भित नहीं की गई git gcप्रक्रिया समानांतर में चल रही ' ' प्रक्रिया द्वारा हटा दी जा सकती है ।

तो उस ग्रेस पीरियड को पैक्ड लेकिन अनरिफाइंड ऑब्जेक्ट्स को देने के लिए, रीपैक प्रक्रिया उन अपरिचित ऑब्जेक्ट्स को पैक से उनके ढीले रूप में धकेल देती है ताकि वे वृद्ध हो सकें और अंत में प्राउड हो सकें।
अप्रतिबंधित होने वाली वस्तुएं आमतौर पर इतनी अधिक नहीं होती हैं। 404855 अप्रतिबंधित वस्तुएँ होना बहुत अधिक है, और क्लोन के माध्यम से उन वस्तुओं को पहली जगह पर भेजना बेवकूफी है और नेटवर्क बैंडविड्थ की पूरी बर्बादी है।

वैसे भी ... अपनी समस्या को हल करने के लिए, आपको बस उस ग्रेस पीरियड को निष्क्रिय करने git gcके --prune=nowतर्क के साथ ' ' चलाने की जरूरत है और उन अप्रतिबंधित वस्तुओं से तुरंत छुटकारा पाएं (केवल तभी सुरक्षित रहें जब कोई अन्य कार्य नहीं हो रहा हो कार्य केंद्र पर सुनिश्चित करना आसान हो)।

और BTW, git gc --aggressiveबाद के गिट संस्करण के साथ ' ' का उपयोग कर (या ' git repack -a -f -d --window=250 --depth=250')

एक ही सूत्र का उल्लेख है :

 git config pack.deltaCacheSize 1

यह 0 के डिफ़ॉल्ट के बजाय डेल्टा कैश आकार को एक बाइट (प्रभावी रूप से अक्षम करना) तक सीमित करता है जिसका अर्थ है असीमित। इसके साथ मैं 486 git repackRAM के साथ x86-64 सिस्टम पर उपर्युक्त कमांड का उपयोग करके और 4 थ्रेड्स (यह एक क्वाड कोर है) का उपयोग करके उस रिपॉजिटरी को वापस करने में सक्षम हूं । निवासी स्मृति उपयोग लगभग 3.3GB तक बढ़ता है।

यदि आपकी मशीन एसएमपी है और आपके पास पर्याप्त रैम नहीं है, तो आप थ्रेड्स की संख्या केवल एक तक कम कर सकते हैं:

git config pack.threads 1

इसके अतिरिक्त, आप मेमोरी उपयोग --window-memory argumentको ' git repack' तक सीमित कर सकते हैं ।
उदाहरण के लिए, --window-memory=128Mडेल्टा खोज मेमोरी के उपयोग पर एक उचित ऊपरी सीमा का उपयोग करना चाहिए , हालांकि इसके परिणामस्वरूप कम इष्टतम डेल्टा मैच हो सकता है यदि रेपो में बहुत सारी फाइलें होती हैं।


फ़िल्टर-शाखा के मोर्चे पर, आप इस स्क्रिप्ट पर (सावधानी से) विचार कर सकते हैं

#!/bin/bash
set -o errexit

# Author: David Underhill
# Script to permanently delete files/folders from your git repository.  To use 
# it, cd to your repository's root and then run the script with a list of paths
# you want to delete, e.g., git-delete-history path1 path2

if [ $# -eq 0 ]; then
    exit 0
fi

# make sure we're at the root of git repo
if [ ! -d .git ]; then
    echo "Error: must run this script from the root of a git repository"
    exit 1
fi

# remove all paths passed as arguments from the history of the repo
files=$@
git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch $files" HEAD

# remove the temporary history git-filter-branch otherwise leaves behind for a long time
rm -rf .git/refs/original/ && git reflog expire --all &&  git gc --aggressive --prune

stackoverflow.com/questions/359424/…filter-branch कमांड उपयोग के लिए भी एक अच्छी शुरुआत है ।
वॉन

हाय VonC - NI कोई किस्मत के साथ अब जीसी जीएन prune = की कोशिश की। यह वास्तव में एक गिट बग की तरह दिखता है, जिसमें मैं एक शाखा विलोपन के बाद स्थानीय रूप से अप्रतिबंधित बूँद के साथ घाव करता हूं, लेकिन ये गिटहब रेपो के एक ताजा क्लोन के साथ नहीं हैं ... इसलिए यह सिर्फ एक स्थानीय रेपो समस्या है। लेकिन मेरे पास अतिरिक्त फाइलें हैं जिन्हें मैं खाली करना चाहता हूं, इसलिए आपने जो संदर्भ ऊपर दिया है वह महान है - धन्यवाद!
krrugler


12

जब भी आपका HEAD चलता है, git इसे ट्रैक करता है reflog। यदि आपने कमिट्स को हटा दिया है, तो आपके पास "झूलने वाले कमिट्स" हैं, क्योंकि वे अभी भी reflog~ 30 दिनों के लिए संदर्भित हैं । यह सुरक्षा-जाल है जब आप दुर्घटना के द्वारा हटाते हैं।

आप git reflogकमांड को हटाने के लिए विशिष्ट कमिट्स, रीपैक आदि का उपयोग कर सकते हैं , या बस उच्च स्तरीय कमांड:

git gc --prune=now

5

आप उपयोग कर सकते हैं git forget-blob

उपयोग बहुत सरल है git forget-blob file-to-forget। आप यहाँ अधिक जानकारी प्राप्त कर सकते हैं

https://ownyourbits.com/2017/01/18/completely-remove-a-file-from-a-git-repository-with-git-forget-blob/

यह आपके इतिहास के सभी कमिट्स, रीफ़्लॉग, टैग आदि से गायब हो जाएगा

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

सैम वाटकिंस जैसे योगदानकर्ताओं को श्रेय


2

गिट-फिल्टर-ब्रांच का उपयोग करने की कोशिश करें - यह बड़े ब्लब्स को नहीं हटाता है, लेकिन यह बड़ी फ़ाइलों को हटा सकता है जिन्हें आप पूरे रेपो से निर्दिष्ट करते हैं। मेरे लिए यह रेपो साइज को सैकड़ों एमबी से घटाकर 12 एमबी कर देता है।


6
अब है कि एक डरावनी आदेश है :) मैं इसे एक कोशिश देने के लिए जब मेरे Git फू मजबूत महसूस करता होगा।
क्रकगलर

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

1

कभी-कभी, इसका कारण यह है कि "जीसी" बहुत अच्छा नहीं करता है कि एक पुरानी प्रतिबद्ध पर आधारित अधूरा छूट या स्टैश है।


या पुरानी कमेटी को HEAD, ORIG_HEAD, FETCH_HEAD द्वारा संदर्भित किया जाता है, या किसी अन्य चीज को अस्वीकार कर दिया जाता है जो अपने आप ही यह सुनिश्चित करने का प्रयास करती रहती है कि यह कभी भी मूल्यवान न हो। यदि आप वास्तव में उन सभी को खोना चाहते हैं, तो आपको ऐसा करने के लिए अतिरिक्त मील पर जाना होगा।
मिक्को रेंटालीनें

1

एक और टिप जोड़ने के लिए, git gc का उपयोग करने से पहले अपने रीमोट की अप्रचलित शाखाओं को हटाने के लिए git रिमोट प्रून का उपयोग करना न भूलें

आप उन्हें git Branch -a के साथ देख सकते हैं

यह अक्सर उपयोगी होता है जब आप जीथब से प्राप्त करते हैं और रिपॉजिटरी का उपयोग करते हैं ...


1

करने से पहले git filter-branchऔर git gc, आपको उन टैग की समीक्षा करनी चाहिए जो आपके रेपो में मौजूद हैं। कोई भी वास्तविक प्रणाली जिसमें निरंतर एकीकरण और तैनाती जैसी चीजों के लिए स्वचालित टैगिंग होती है, जो अवांछित वस्तुओं को अभी भी इन टैग द्वारा संदर्भित करती है, इसलिए gcउन्हें हटा नहीं सकती है और आप अभी भी सोचेंगे कि रेपो का आकार अभी भी इतना बड़ा क्यों है।

सबसे अच्छा तरीका है सब अन-चाहता था सामान से छुटकारा पाने के चलाने के लिए है git-filterऔर git gcऔर फिर एक नई नंगे रेपो के लिए मास्टर धक्का। नए नंगे रेपो में साफ किया हुआ पेड़ होगा।

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