Почему мой репозиторий Git такой большой? - PullRequest
124 голосов
/ 23 июня 2009

145M = .git / objects / pack /

Я написал скрипт для суммирования размеров различий каждого коммита и коммита до того, как он вернется назад от вершины каждой ветви. Я получаю 129 МБ без сжатия и без учета одних и тех же файлов в филиалах и общей истории между филиалами.

Git принимает во внимание все эти вещи, поэтому я бы ожидал гораздо меньшего размера хранилища. Так почему .git такой большой?

Я сделал:

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

Чтобы ответить, сколько файлов / коммитов, у меня есть 19 веток по 40 файлов в каждой. 287 коммитов, найдено с использованием:

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

Для хранения информации об этом не требуется 10 мегабайт.

Ответы [ 12 ]

142 голосов
/ 15 января 2013

Некоторые скрипты, которые я использую:

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

Если вам нужно больше строк, см. Также версию Perl в соседнем ответе: https://stackoverflow.com/a/45366030/266720

уничтожение мерзавца (для 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

Примечание: второй скрипт предназначен для полного удаления информации из Git (включая всю информацию из reflogs). Используйте с осторожностью.

61 голосов
/ 24 июня 2009

Я недавно вытащил неправильный удаленный репозиторий в локальный (git remote add ... и git remote update). После удаления ненужных удаленных ссылок, веток и тегов в моем хранилище все еще оставалось 1,4 ГБ (!) Потерянного пространства. Я смог избавиться от этого, только клонировав его с 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
60 голосов
/ 24 июня 2009

git gc уже выполняет git repack, поэтому нет смысла переупаковывать вручную, если вы не собираетесь передавать ему какие-то специальные опции.

Первый шаг - выяснить, является ли большая часть пространства (как это обычно бывает) базой данных вашего объекта.

git count-objects -v

Это должно дать отчет о том, сколько распакованных объектов имеется в вашем хранилище, сколько места они занимают, сколько у вас файлов пакета и сколько места они занимают.

В идеале, после перепаковки у вас не должно быть распакованных объектов и одного файла пакета, но вполне нормально, что некоторые объекты, на которые нет прямой ссылки из текущих веток, все еще присутствуют и распаковываются.

Если у вас есть одна большая упаковка, и вы хотите знать, что занимает место, вы можете перечислить объекты, которые составляют пакет, вместе с тем, как они хранятся.

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

Обратите внимание, что verify-pack принимает индексный файл, а не сам файл пакета. Это дает отчет о каждом объекте в пакете, его истинном размере и упакованном размере, а также информацию о том, был ли он «разграничен» и, если это так, происхождение дельта-цепи.

Чтобы увидеть, есть ли какие-либо необычно большие объекты в вашем хранилище, вы можете отсортировать результаты численно по третьему четвертому столбцу (например, | sort -k3n).

Из этого вывода вы сможете увидеть содержимое любого объекта с помощью команды git show, хотя невозможно точно определить, где в истории фиксации хранилища ссылается на объект. Если вам нужно сделать это, попробуйте что-нибудь из этого вопроса .

27 голосов
/ 06 января 2013

Только к вашему сведению, главная причина, по которой вы можете получить нежелательные объекты, заключается в том, что git поддерживает reflog.

Reflog существует для того, чтобы сохранить ваш зад, когда вы случайно удалили свою основную ветку или каким-то иным образом катастрофически повредили свой репозиторий.

Самый простой способ исправить это - обрезать ваши reflogs перед сжатием (просто убедитесь, что вы никогда не захотите вернуться к любому из коммитов в reflog).

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

Это отличается от git gc --prune=today тем, что он немедленно истекает весь reflog.

8 голосов
/ 23 января 2017

Если вы хотите узнать, какие файлы занимают место в вашем git-репозитории, запустите

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

Затем извлеките ссылку на BLOB-объект, занимающий наибольшее количество места (последняя строка), и проверьте имя файла, которое занимает столько места

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

Это может быть даже файл, который вы удалили с помощью git rm, но git запомнил его, потому что на него все еще есть ссылки, такие как теги, удаленные и reflog.

Как только вы знаете, от какого файла вы хотите избавиться, я рекомендую использовать 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

Это удалит все ссылки из git, удалит BLOB-объект из каждого коммита в истории и запустит сборку мусора, чтобы освободить место.

7 голосов
/ 28 июля 2017

Сценарий git-fatfiles из ответа Ви прекрасен, если вы хотите увидеть размер всех ваших объектов, но он настолько медленный, что его невозможно использовать. Я снял ограничение на 40 строк, и он попытался использовать всю оперативную память моего компьютера вместо завершения. Поэтому я переписал это: это в тысячи раз быстрее, добавлены функции (необязательно), и была удалена какая-то странная ошибка - старая версия выдает неточные значения, если вы суммируете выходные данные, чтобы увидеть общее пространство, используемое файлом. 1001 *

#!/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. Если вы установите модуль Number :: Bytes :: Human cpan (запустите «cpan Number :: Bytes :: Human»), размеры будут отформатированы: «21M /path/to/file.mp4» .

4 голосов
/ 23 июня 2009

Вы уверены, что считаете только файлы .pack, а не .idx? Они находятся в том же каталоге, что и файлы .pack, но не содержат никаких данных репозитория (как указывает расширение, они являются не чем иным, как индексами для соответствующего пакета - на самом деле, если вы знаете правильную команду, вы может легко воссоздать их из файла пакета, и сам git делает это при клонировании, так как только файл пакета передается с использованием собственного протокола git).

В качестве типичного примера я взглянул на мой локальный клон репозитория linux-2.6:

$ du -c *.pack
505888  total

$ du -c *.idx
34300   total

Что указывает на то, что увеличение на 7% должно быть обычным явлением.

Есть также файлы вне objects/; по моему личному опыту, из них index и gitk.cache, как правило, самые большие (всего 11 миллионов в моем клоне репозитория linux-2.6).

3 голосов
/ 23 июня 2009

Другие объекты git, хранящиеся в .git, включают деревья, коммиты и теги. Коммиты и теги небольшие, но деревья могут стать большими, особенно если в вашем хранилище очень много маленьких файлов. Сколько файлов и сколько коммитов у вас есть?

2 голосов
/ 23 июня 2009

Вы пытались использовать git repack ?

1 голос
/ 09 апреля 2018

Стоит проверить stacktrace.log. Это в основном журнал ошибок для отслеживания коммитов, которые потерпели неудачу. Недавно я обнаружил, что мой stacktrace.log имеет размер 65,5 ГБ, а мое приложение - 66,7 ГБ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...