मेरी गिट रिपॉजिटरी इतनी बड़ी क्यों है?


141

145M = .गित / ऑब्जेक्ट्स / पैक /

मैंने प्रत्येक शाखा के सिरे से पीछे की ओर जाने से पहले प्रत्येक प्रतिबद्ध और अंतर के आकार को जोड़ने के लिए एक स्क्रिप्ट लिखी। मुझे 129MB मिलता है, जो बिना कंप्रेशन के और बिना ब्रांच के एक ही फाइल के लिए और कॉमन हिस्ट्री के बीच के अकाउंट्स के बिना होता है।

Git उन सभी चीजों को ध्यान में रखता है जिससे मुझे बहुत छोटे भंडार की उम्मीद होगी। तो .आज इतना बड़ा क्यों है?

मेरा होगया:

git fsck --full
git gc --prune=today --aggressive
git repack

कितनी फ़ाइलों / कमिट्स के बारे में जवाब देने के लिए, मेरी 19 शाखाएँ हैं, जिनमें से प्रत्येक में लगभग 40 फाइलें हैं। 287 का उपयोग करता है, पाया:

git log --oneline --all|wc -l

इसके बारे में जानकारी संग्रहीत करने के लिए 10 मेगाबाइट का नहीं होना चाहिए।


5
लिनुस आक्रामक जीसी पर निम्नलिखित की सिफारिश करता है। क्या यह एक महत्वपूर्ण अंतर है? git repack -a -d --depth = 250 --विंडो = 250
ग्रेग बेकन

धन्यवाद gbacon, लेकिन कोई अंतर नहीं।
इयान केलिंग

ऐसा इसलिए है क्योंकि आप -f याद कर रहे हैं। metalinguist.wordpress.com/2007/12/06/…
spuder

git repack -a -dमेरे 956MB रेपो को 250MB तक सिकोड़ें । महान सफलता! धन्यवाद!
xanderiel

जवाबों:


68

मैंने हाल ही में गलत रिमोट रिपॉजिटरी को स्थानीय एक ( git remote add ...और git remote update) में खींच लिया है । अवांछित दूरस्थ रेफरी को हटाने के बाद, मेरी रिपॉजिटरी में मेरे पास अभी भी 1.4GB (!) जगह बर्बाद है। मैं केवल इसे क्लोन करके इससे छुटकारा पाने में सक्षम था git clone file:///path/to/repository। ध्यान दें किfile:// स्थानीय रिपॉजिटरी को क्लोन करते समय अंतर की एक दुनिया बन जाती है - केवल संदर्भित ऑब्जेक्ट्स को कॉपी किया जाता है, न कि पूरी निर्देशिका संरचना।

संपादित करें: यहां नई रेपो में सभी शाखाओं को फिर से बनाने के लिए इयान का एक लाइनर है:

d1=#original repo
d2=#new repo (must already exist)
cd $d1
for b in $(git branch | cut -c 3-)
do
    git checkout $b
    x=$(git rev-parse HEAD)
    cd $d2
    git checkout -b $b $x
    cd $d1
done

1
वाह। धन्यवाद। .it = 15M अब !! क्लोनिंग के बाद, यहां अपनी पिछली शाखाओं को संरक्षित करने के लिए थोड़ा 1 लाइनर है। d1 = # मूल रेपो; d2 = # नया रेपो; सीडी $ डी 1; $ में बी के लिए (गिट शाखा | कट -c 3-); git चेकआउट $ b; x = $ (git Rev-parse HEAD); सीडी $ डी 2; git चेकआउट -b $ b $ x; सीडी $ डी 1; किया
इयान केलिंग

यदि आप इसकी जांच करते हैं, तो आप अपने उत्तर में 1 लाइनर जोड़ सकते हैं ताकि कोड के रूप में इसका प्रारूपित किया जा सके।
इयान केलिंग

1
मैंने मूर्खतापूर्ण तरीके से अपने रेपो में वीडियो फ़ाइलों का एक गुच्छा जोड़ा, और रीसेट करना पड़ा - HEAD ^ और फिर से मिलाना। .It / ऑब्जेक्ट्स dir उसके बाद बहुत बड़ा था, और यह एकमात्र तरीका था जो उसे वापस मिला। हालाँकि मुझे यह पसंद नहीं आया कि जिस तरह से एक लाइनर ने मेरी शाखा के नाम बदले (यह सिर्फ ब्रांचनाम के बजाय मूल / ब्रांचनाम दिखाया)। इसलिए मैंने एक कदम और आगे बढ़ाया और कुछ स्केच सर्जरी को अंजाम दिया - मैंने मूल से .गित / ऑब्जेक्ट्स निर्देशिका को हटा दिया, और क्लोन से एक में डाल दिया। यह चाल चली, सभी मूल शाखाओं, रेफरी, आदि को छोड़कर, और सब कुछ काम करने लगता है (उंगलियों को पार करना)।
जैक सेनचेल

1
फ़ाइल के बारे में टिप के लिए धन्यवाद: // क्लोन, कि मेरे लिए चाल किया
adam.wulf

3
@vonbrand यदि आप किसी फ़ाइल के लिए हार्ड लिंक करते हैं और मूल फ़ाइल को हटाते हैं, तो कुछ भी नहीं होता है सिवाय इसके कि एक संदर्भ काउंटर 2 से 1 तक घटाया जाता है। केवल अगर वह काउंटर 0 से घटाया जाता है तो fs पर अन्य फ़ाइलों के लिए स्थान खाली हो जाता है। तो नहीं, भले ही फाइलें हार्ड लिंक की गई हों, अगर ओरिजिनल डिलीट हो जाए तो कुछ नहीं होगा।
स्टेफ्रीक

157

कुछ लिपियों का मैं उपयोग करता हूं:

Git-fatfiles

git rev-list --all --objects | \
    sed -n $(git rev-list --objects --all | \
    cut -f1 -d' ' | \
    git cat-file --batch-check | \
    grep blob | \
    sort -n -k 3 | \
    tail -n40 | \
    while read hash type size; do 
         echo -n "-e s/$hash/$size/p ";
    done) | \
    sort -n -k1
...
89076 images/screenshots/properties.png
103472 images/screenshots/signals.png
9434202 video/parasite-intro.avi

यदि आप अधिक रेखाएँ चाहते हैं, तो पड़ोसी उत्तर में पर्ल संस्करण भी देखें: https://stackoverflow.com/a/45366030/262620

git-eradicate (for video/parasite.avi):

git filter-branch -f  --index-filter \
    'git rm --force --cached --ignore-unmatch video/parasite-intro.avi' \
     -- --all
rm -Rf .git/refs/original && \
    git reflog expire --expire=now --all && \
    git gc --aggressive && \
    git prune

नोट: दूसरी स्क्रिप्ट पूरी तरह से गिट से जानकारी हटाने के लिए डिज़ाइन की गई है (रिफ्लक्स से सभी जानकारी सहित)। सावधानी से प्रयोग करें।


2
अंत में ... विडंबना यह है कि मैंने इसका जवाब अपनी खोज में पहले देखा था लेकिन यह बहुत जटिल लग रहा था ... अन्य चीजों की कोशिश करने के बाद, यह समझदारी और आवाज करने लगा!
msanteler

@msanteler, git-fatfilesIRC (Freenode / # git) पर सवाल पूछने पर पूर्व ( ) स्क्रिप्ट सामने आई है। मैंने एक फ़ाइल के लिए सबसे अच्छा संस्करण बचाया, फिर इसे यहां एक उत्तर के रूप में पोस्ट किया। (हालांकि मैं आईआरसी लॉग्स में मूल लेखक नहीं कर सकता)।
वि।

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

1
@felbo, तो समस्या शायद आपके स्थानीय भंडार में ही नहीं है, बल्कि अन्य रिपॉजिटरी में भी है। हो सकता है कि आपको हर जगह प्रक्रिया करने की ज़रूरत है, या सभी को मूल शाखाओं को त्यागने और फिर से लिखित शाखाओं में बदलने के लिए मजबूर करना होगा। यह एक बड़ी टीम में आसान नहीं है और डेवलपर्स और / या प्रबंधक के हस्तक्षेप के बीच सहयोग की आवश्यकता है। कभी-कभी सिर्फ लोडस्टोन को अंदर छोड़ना बेहतर विकल्प हो सकता है।
वि।

1
यह फ़ंक्शन बहुत अच्छा है, लेकिन यह अकल्पनीय रूप से धीमा है। अगर मैं 40 लाइन की सीमा हटाता हूं तो यह मेरे कंप्यूटर पर भी समाप्त नहीं हो सकता। FYI करें, मैंने अभी इस फ़ंक्शन के अधिक कुशल संस्करण के साथ एक उत्तर जोड़ा है। यदि आप इस तर्क का उपयोग किसी बड़े भंडार पर करना चाहते हैं, या यदि आप प्रति फ़ाइल या प्रति फ़ोल्डर आकार को देखना चाहते हैं, तो इसे देखें।
पीजो

66

git gcपहले से ही ऐसा git repackकरने का कोई अर्थ नहीं है, जब तक कि आप इसके लिए कुछ विशेष विकल्पों को पारित नहीं करेंगे।

पहला कदम यह देखना है कि अंतरिक्ष का अधिकांश हिस्सा (जैसा कि सामान्य रूप से मामला होगा) आपके ऑब्जेक्ट डेटाबेस में है।

git count-objects -v

इससे यह पता लगाना चाहिए कि आपकी रिपॉजिटरी में कितने अनपैक्ड ऑब्जेक्ट हैं, वे कितनी जगह लेते हैं, आपके पास कितनी पैक फाइलें हैं और वे कितनी जगह लेते हैं।

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

यदि आपके पास एक भी बड़ा पैक है और आप जानना चाहते हैं कि अंतरिक्ष क्या ले रहा है तो आप उन वस्तुओं को सूचीबद्ध कर सकते हैं जो पैक के साथ-साथ वे कैसे संग्रहीत हैं।

git verify-pack -v .git/objects/pack/pack-*.idx

ध्यान दें कि verify-packएक इंडेक्स फाइल लेता है न कि पैक फाइल। यह पैक की प्रत्येक वस्तु, उसके वास्तविक आकार और उसके पैक्ड आकार के साथ-साथ यह भी जानकारी देता है कि क्या यह 'सीमांकित' है और यदि डेल्टा श्रृंखला की उत्पत्ति है।

यह देखने के लिए कि आपकी रिपॉजिटरी में कोई असामान्य रूप से बड़ी वस्तुएं हैं या नहीं, आप चौथे कॉलम के तीसरे (जैसे | sort -k3n) आउटपुट को संख्यात्मक रूप से सॉर्ट कर सकते हैं ।

इस आउटपुट से आप git showकमांड का उपयोग करते हुए किसी भी ऑब्जेक्ट की सामग्री को देख पाएंगे , हालांकि यह देखना संभव नहीं है कि रिपॉजिटरी के प्रतिबद्ध इतिहास में ऑब्जेक्ट को कहां संदर्भित किया जाता है। यदि आपको ऐसा करने की आवश्यकता है, तो इस प्रश्न से कुछ प्रयास करें


1
इसने बड़ी वस्तुओं को महान पाया। स्वीकृत उत्तर से उन्हें छुटकारा मिल गया।
इयान केलिंग

2
लाइनस टॉर्वाल्ड्स के अनुसार गिट जीसी और गिट रीपैक के बीच का अंतर। metalinguist.wordpress.com/2007/12/06/…
spuder

31

सिर्फ FYI करें, सबसे बड़ी वजह यह हो सकती है कि आप अवांछित वस्तुओं को खत्म कर सकते हैं।

जब आप गलती से अपने मास्टर ब्रांच को डिलीट कर देते हैं या किसी तरह से अन्यथा आपकी रिपॉजिटरी को नुकसान पहुंचाते हैं, तो रिफ्लॉग आपके बट को बचाने के लिए होता है।

इसे ठीक करने का सबसे आसान तरीका है कि आप अपने रिफ्लॉग्स को कंप्रेस करने से पहले ही काट लें (बस यह सुनिश्चित कर लें कि आप कभी भी रिफ्लेक्स में से किसी भी कमिट में वापस नहीं जाना चाहते)।

git gc --prune=now --aggressive
git repack

इससे अलग है git gc --prune=today है कि यह संपूर्ण रिफ्लोग को तुरंत समाप्त कर देता है।


1
यह एक मेरे लिए किया था! मैं लगभग 5gb से 32mb तक चला गया।
हकीकी

यह उत्तर आसान लग रहा था लेकिन दुर्भाग्य से मेरे लिए काम नहीं आया। मेरे मामले में मैं सिर्फ एक क्लोन रिपोजिटरी पर काम कर रहा था। क्या वह कारण है?
मर्ट

13

यदि आप यह जानना चाहते हैं कि आपके गिट रिपॉजिटरी में कौन सी फाइलें जगह ले रही हैं, तो दौड़ें

git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -5

फिर, सबसे अधिक स्थान (अंतिम पंक्ति) को लेने वाले बूँद संदर्भ को निकालें, और फ़ाइलनाम की जाँच करें जो इतना स्थान ले रहा है

git rev-list --objects --all | grep <reference>

यह एक फाइल भी हो सकती है जिसे आपने हटा दिया है git rm , लेकिन git इसे याद रखता है क्योंकि अभी भी इसके संदर्भ हैं, जैसे टैग, रीमोट और फिर से लिखना।

एक बार जब आप जान जाते हैं कि आप किस फ़ाइल से छुटकारा चाहते हैं, तो मैं उपयोग करने की सलाह देता हूं git forget-blob

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

इसका उपयोग करना आसान है, बस करो

git forget-blob file-to-forget

यह गिट से हर संदर्भ को हटा देगा, इतिहास में हर प्रतिबद्ध से बूँद को हटा देगा, और अंतरिक्ष को खाली करने के लिए कचरा संग्रह को चलाएगा।


7

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

#!/usr/bin/perl
use warnings;
use strict;
use IPC::Open2;
use v5.14;

# Try to get the "format_bytes" function:
my $canFormat = eval {
    require Number::Bytes::Human;
    Number::Bytes::Human->import('format_bytes');
    1;
};
my $format_bytes;
if ($canFormat) {
    $format_bytes = \&format_bytes;
}
else {
    $format_bytes = sub { return shift; };
}

# parse arguments:
my ($directories, $sum);
{
    my $arg = $ARGV[0] // "";
    if ($arg eq "--sum" || $arg eq "-s") {
        $sum = 1;
    }
    elsif ($arg eq "--directories" || $arg eq "-d") {
        $directories = 1;
        $sum = 1;
    }
    elsif ($arg) {
        print "Usage: $0 [ --sum, -s | --directories, -d ]\n";
        exit 1;
    } 
}

# the format is [hash, file]
my %revList = map { (split(' ', $_))[0 => 1]; } qx(git rev-list --all --objects);
my $pid = open2(my $childOut, my $childIn, "git cat-file --batch-check");

# The format is (hash => size)
my %hashSizes = map {
    print $childIn $_ . "\n";
    my @blobData = split(' ', <$childOut>);
    if ($blobData[1] eq 'blob') {
        # [hash, size]
        $blobData[0] => $blobData[2];
    }
    else {
        ();
    }
} keys %revList;
close($childIn);
waitpid($pid, 0);

# Need to filter because some aren't files--there are useless directories in this list.
# Format is name => size.
my %fileSizes =
    map { exists($hashSizes{$_}) ? ($revList{$_} => $hashSizes{$_}) : () } keys %revList;


my @sortedSizes;
if ($sum) {
    my %fileSizeSums;
    if ($directories) {
        while (my ($name, $size) = each %fileSizes) {
            # strip off the trailing part of the filename:
            $fileSizeSums{$name =~ s|/[^/]*$||r} += $size;
        }
    }
    else {
        while (my ($name, $size) = each %fileSizes) {
            $fileSizeSums{$name} += $size;
        }
    }

    @sortedSizes = map { [$_, $fileSizeSums{$_}] }
        sort { $fileSizeSums{$a} <=> $fileSizeSums{$b} } keys %fileSizeSums;
}
else {
    # Print the space taken by each file/blob, sorted by size
    @sortedSizes = map { [$_, $fileSizes{$_}] }
        sort { $fileSizes{$a} <=> $fileSizes{$b} } keys %fileSizes;

}

for my $fileSize (@sortedSizes) {
    printf "%s\t%s\n", $format_bytes->($fileSize->[1]), $fileSize->[0];
}

इस git-fatfiles.pl को नाम दें और इसे चलाएं। किसी फ़ाइल के सभी संशोधनों द्वारा उपयोग किए गए डिस्क स्थान को देखने के लिए, --sumविकल्प का उपयोग करें । एक ही चीज़ को देखने के लिए, लेकिन प्रत्येक निर्देशिका में फ़ाइलों के लिए, --directoriesविकल्प का उपयोग करें । यदि आप संख्या :: बाइट्स :: मानव cpan मॉड्यूल ("cpan संख्या :: बाइट्स :: मानव" चलाते हैं), तो आकार स्वरूपित किए जाएंगे: "21M /path/to/file.mp4"।


4

क्या आप सुनिश्चित हैं कि आप केवल। Px फ़ाइलों की गिनती कर रहे हैं और .idx फ़ाइलों की नहीं? वे .pack फ़ाइलों के समान निर्देशिका में हैं, लेकिन उनके पास रिपॉजिटरी डेटा में से कोई भी नहीं है (जैसा कि विस्तार इंगित करता है, वे संबंधित पैक के लिए अनुक्रमित से अधिक कुछ नहीं हैं - वास्तव में, यदि आप सही कमांड जानते हैं, तो आप कर सकते हैं आसानी से उन्हें पैक फ़ाइल से फिर से बनाएँ, और क्लोनिंग करते समय खुद ही ऐसा करें, क्योंकि केवल एक पैक फ़ाइल को देशी ger प्रोटोकॉल का उपयोग करके स्थानांतरित किया जाता है)।

प्रतिनिधि नमूने के रूप में, मैंने अपने स्थानीय क्लोन लाइनक्स-2.6 रिपॉजिटरी पर एक नज़र डाली:

$ du -c *.pack
505888  total

$ du -c *.idx
34300   total

जो इंगित करता है कि लगभग 7% का विस्तार आम होना चाहिए।

बाहर भी फाइलें हैं objects/; मेरे निजी अनुभव में, उनमें से indexऔर gitk.cacheसबसे बड़ी लोगों (linux-2.6 भंडार की मेरी क्लोन में 11M की कुल मात्रा) हो जाते हैं।


3

अन्य गिट वस्तुओं में संग्रहीत .gitपेड़, कमिट और टैग शामिल हैं। कमिट और टैग छोटे हैं, लेकिन पेड़ विशेष रूप से बड़े हो सकते हैं यदि आपके पास अपनी रिपॉजिटरी में बहुत बड़ी संख्या में छोटी फाइलें हैं। आपके पास कितनी फाइलें और कितने कमिट हैं?


अच्छा प्रश्न। प्रत्येक में लगभग 40 फाइलों के साथ 19 शाखाएँ। गिट काउंट-ऑब्जेक्ट्स -v कहता है "इन-पैक: 1570"। निश्चित रूप से इसका मतलब नहीं है कि मेरे पास कितने साधन हैं या कैसे गिनें। कुछ सौ मुझे लगता है।
इयान केलिंग

ठीक है, यह ऐसा लगता है कि जवाब नहीं है। 145 एमबी की तुलना में कुछ सौ महत्वहीन होंगे।
ग्रेग हेवगिल

2

क्या आपने git repack का उपयोग करने की कोशिश की ?


अच्छा प्रश्न। मैंने किया, मुझे यह भी आभास हुआ कि git gc क्या ऐसा भी करता है?
इयान केलिंग

यह git gc --auto के साथ करता है जो आपके द्वारा उपयोग किए जाने के बारे में निश्चित नहीं है।
बॉडटैक

2

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

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


1

ऐसा तब हो सकता है जब आपने गलती से फ़ाइलों का एक बड़ा हिस्सा जोड़ लिया और उनका मंचन किया, जरूरी नहीं कि उन्हें प्रतिबद्ध किया जाए। यह एक railsऐप में हो सकता है जब आप दौड़ते हैं bundle install --deploymentऔर फिर गलती से git add .तब आप अपने नीचे जोड़ी गई सभी फाइलों को vendor/bundleदेख लेते हैं लेकिन वे पहले से ही गिट इतिहास में शामिल हो जाती हैं, इसलिए आपको वीआई के जवाब को लागू करना होगा और इसके video/parasite-intro.aviद्वारा बदलना होगाvendor/bundle तो दूसरा आदेश वह प्रदान करता है चलाते हैं।

आप अंतर देख सकते हैं कि git count-objects -vस्क्रिप्ट लागू करने से पहले मेरे मामले में 52K का आकार-पैक था और इसे लागू करने के बाद 3.8K था।


1

यह स्टैकट्रेस.लॉग की जाँच के लायक है। यह मूल रूप से एक त्रुटि लॉग है जो विफल हो गया है। मुझे हाल ही में पता चला है कि मेरा स्टैकट्रेस.लॉग 65.5GB का है और मेरा ऐप 66.7GB का है।

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