Почему мой репозиторий git настолько велик?
145M =.git/objects/pack/
Я написал script, чтобы добавить размеры различий каждой фиксации и фиксации до того, как она вернется назад от кончика каждой ветки. Я получаю 129 МБ, который без сжатия и без учета одинаковых файлов по ветвям и общей истории между ветвями.
Git учитывает все эти вещи, поэтому я ожидаю гораздо меньший репозиторий. Так почему же .git настолько большой?
Я сделал:
git fsck --full
git gc --prune=today --aggressive
git repack
Чтобы ответить, сколько файлов/коммитов, у меня есть 19 веток по 40 файлов в каждом.
287 коммитов, найденных с использованием:
git log --oneline --all|wc -l
Не нужно брать 10 мегабайт для хранения информации об этом.
Ответы
Ответ 1
Недавно я вытащил неправильный удаленный репозиторий в локальный (git remote add ...
и git remote update
). После удаления нежелательных удаленных ссылок, ветвей и тегов у меня все еще было 1,4 ГБ (!) Потерянного пространства в моем репозитории. Я смог избавиться от этого путем клонирования его с помощью git clone file:///path/to/repository
. Обратите внимание, что file://
делает мир различием при клонировании локального репозитория - копируются только объекты, на которые ссылаются, а не целая структура каталогов.
Изменить: здесь Ian один лайнер для воссоздания всех ветвей в новом репо:
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
Ответ 2
Некоторые скрипты, которые я использую:
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 в соседнем ответе: fooobar.com/questions/4618/...
git -eradicate (для 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
Примечание. Вторая script предназначена для полного удаления информации из Git (включая всю информацию из журналов). Следует использовать с осторожностью.
Ответ 3
git gc
уже выполняет git repack
, поэтому нет смысла переупаковывать вручную, если вы не собираетесь передавать ему некоторые специальные опции.
Первый шаг - посмотреть, будет ли большая часть пространства (как это обычно бывает) вашей объектной базой данных.
git count-objects -v
Это должно дать отчет о том, сколько распакованных объектов есть в вашем репозитории, сколько места они занимают, сколько у вас пакетов и сколько места они занимают.
В идеале, после переупаковки, у вас не было бы распакованных объектов и одного файла пакета, но вполне нормально иметь некоторые объекты, которые напрямую не ссылаются на текущие ветки, которые все еще присутствуют и распаковываются.
Если у вас есть один большой пакет, и вы хотите знать, что занимает пространство, вы можете перечислить объекты, составляющие пакет, вместе с тем, как они хранятся.
git verify-pack -v .git/objects/pack/pack-*.idx
Обратите внимание, что verify-pack
принимает индексный файл, а не сам файл пакета. Это дает отчет о каждом объекте в пакете, его истинном размере и его упакованном размере, а также информацию о том, была ли она "дефинирована" и если да, то происхождение дельта-цепочки.
Чтобы узнать, есть ли в вашем репозитории какие-либо необычно большие объекты, вы можете сортировать результат численно на третьем из четвертых столбцов (например, | sort -k3n
).
На этом выходе вы сможете увидеть содержимое любого объекта с помощью команды git show
, хотя невозможно точно увидеть, где в истории фиксации репозитория ссылается объект. Если вам нужно это сделать, попробуйте что-нибудь из этого вопроса.
Ответ 4
Просто FYI, самая большая причина, по которой вы можете избежать нежелательных объектов, заключается в том, что git поддерживает reflog.
Если вы случайно удалили свою основную ветку или каким-либо иным образом катастрофически повредили ваш репозиторий, reflog должен сохранить ваш прикладом.
Самый простой способ исправить это - обрезать свои рефлоги перед сжатием (просто убедитесь, что вы никогда не хотите возвращаться к любому из коммитов в рефлоге).
git gc --prune=now --aggressive
git repack
Это отличается от git gc --prune=today
тем, что он немедленно исчерпал весь рефлог.
Ответ 5
Вы уверены, что считаете только файлы .pack, а не файлы .idx? Они находятся в том же каталоге, что и файлы .pack, но не имеют данных репозитория (как указывает расширение, это не что иное, как индексы для соответствующего пакета — на самом деле, если вы знаете правильную команду, вы могут легко воссоздать их из файла пакета, а сам git делает это при клонировании, поскольку только пакетный файл передается с использованием собственного протокола git).
В качестве репрезентативной выборки я взглянул на свой локальный клон репозитория linux-2.6:
$ du -c *.pack
505888 total
$ du -c *.idx
34300 total
Это означает, что расширение должно составлять около 7%.
Существуют также файлы вне objects/
; в моем личном опыте, из них index
и gitk.cache
имеют тенденцию быть самыми большими (всего 11M в моем клоне репозитория linux-2.6).
Ответ 6
Если вы хотите найти, какие файлы занимают место в репозитории 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
git -fatfiles script из ответа Vi прекрасен, если вы хотите видеть размер всех ваших капель, но он настолько медленный, чтобы быть непригодным. Я удалил 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
. Если вы установите модуль Number:: Bytes:: Human cpan (запустите "cpan Number:: Bytes:: Human" ), размеры будут отформатировать: "21M/path/to/file.mp4".
Ответ 8
Другие объекты git, хранящиеся в .git
, включают деревья, коммиты и теги. Записи и теги небольшие, но деревья могут стать большими, особенно если в вашем репозитории имеется очень большое количество небольших файлов. Сколько файлов и сколько коммитов у вас есть?
Ответ 9
Вы пытались использовать git repack?
Ответ 10
перед тем, как сделать git filter-branch и git gc, вы должны просмотреть теги, которые присутствуют в вашем репо. Любая реальная система, которая имеет автоматическую маркировку для таких вещей, как непрерывная интеграция и развертывание, сделает ненужные объекты по-прежнему оговоренными этими тегами, следовательно, gc cant удалит их, и вы все равно будете задаваться вопросом, почему размер репо все еще такой большой.
Лучший способ избавиться от всех ненужных материалов - запустить git -filter и git gc, а затем нажать master для нового голого репо. У нового голого репо будет очищенное дерево.
Ответ 11
Это может произойти, если вы добавили большой кусок файлов случайно и устроили их, не обязательно комментируя их. Это может произойти в приложении rails
, когда вы запускаете bundle install --deployment
, а затем случайно git add .
, тогда вы видите все файлы, добавленные в vendor/bundle
, которые вы несете их, но они уже вошли в историю git, поэтому вам нужно применить Vi answer и измените
video/parasite-intro.avi
на vendor/bundle
, затем запустите вторую команду, которую он предоставляет.
Вы можете увидеть разницу с git count-objects -v
, которая в моем случае перед применением script имела размер-пакет: из 52K, а после применения - 3,8K.