为什么我的git存储库这么大?

Ian*_*ing 131 git

145M = .git/objects/pack /

我编写了一个脚本来添加每个提交和提交的差异大小,然后再从每个分支的尖端向后移动.我得到129MB,没有压缩,没有分支机构的相同文件和分支机构之间的共同历史记录.

Git考虑了所有这些因素,所以我期望更小的存储库.那么为什么.git这么大?

我弄完了:

git fsck --full
git gc --prune=today --aggressive
git repack
Run Code Online (Sandbox Code Playgroud)

要回答有多少文件/提交,我有19个分支,每个文件大约有40个文件.287次提交,发现使用:

git log --oneline --all|wc -l
Run Code Online (Sandbox Code Playgroud)

它不应该使用10兆字节来存储有关此信息.

Vi.*_*Vi. 150

我使用的一些脚本:

混帐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
Run Code Online (Sandbox Code Playgroud)
...
89076 images/screenshots/properties.png
103472 images/screenshots/signals.png
9434202 video/parasite-intro.avi
Run Code Online (Sandbox Code Playgroud)

如果您想要更多行,请参阅相邻答案中的Perl版本:https://stackoverflow.com/a/45366030/266720

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
Run Code Online (Sandbox Code Playgroud)

注意:第二个脚本旨在完全从Git中删除信息(包括来自reflogs的所有信息).谨慎使用.

  • 最后......具有讽刺意味的是,我在搜索的早些时候看到了这个答案,但它看起来太复杂了......在尝试其他事情之后,这个开始变得有意义,瞧! (2认同)

pgs*_*pgs 64

我最近把错误的远程存储库拉到了本地(git remote add ...git remote update).删除不需要的远程引用,分支和标签后,我的存储库中仍然有1.4GB(!)的浪费空间.我只能通过克隆来摆脱它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
Run Code Online (Sandbox Code Playgroud)

  • @vonbrand如果你硬链接到一个文件并删除原始文件,除了引用计数器从2递减到1之外没有任何反应.只有当该计数器减少到0时,才会释放fs上其他文件的空间.所以不,即使文件是硬连接的,如果原件被删除也不会发生任何事情. (3认同)
  • 我愚蠢地在我的仓库中添加了一堆视频文件,不得不重置 --soft HEAD^ 并重新提交。.git/objects 目录在那之后变得很大,这是让它恢复原状的唯一方法。但是,我不喜欢一个班轮更改我的分支名称的方式(它显示了来源/分支名称,而不仅仅是分支名称)。所以我更进一步,执行了一些粗略的手术——我从原始目录中删除了 .git/objects 目录,并从克隆中放入了一个。这确实成功了,保留了所有原始分支、参考等完整无缺,并且一切似乎都有效(交叉手指)。 (2认同)

CB *_*ley 63

git gc已经做了git repack所以没有任何意义在手动重新包装,除非你要传递一些特殊的选项.

第一步是查看大多数空间(通常情况下)是否是对象数据库.

git count-objects -v
Run Code Online (Sandbox Code Playgroud)

这应该会报告存储库中有多少个解压缩的对象,它们占用了多少空间,有多少包文件以及它们占用了多少空间.

理想情况下,在重新打包之后,您将没有解压缩的对象和一个打包文件,但是当前分支不能直接引用的某些对象仍然存在和解压缩是完全正常的.

如果您有一个大包装并且想知道占用空间的是什么,那么您可以列出构成包装的对象以及它们的存储方式.

git verify-pack -v .git/objects/pack/pack-*.idx
Run Code Online (Sandbox Code Playgroud)

请注意,verify-pack它采用索引文件而不是包文件本身.这给出了包中每个对象的报告,它的真实大小和包装大小,以及关于它是否已经"完整"的信息,如果是,那么三角链的起源.

要查看存储库中是否存在任何异常大的对象,您可以在第四列的第三列(例如| sort -k3n)上以数字方式对输出进行排序.

通过此输出,您将能够使用该git show命令查看任何对象的内容,尽管无法准确查看引用该对象的存储库的提交历史记录中的位置.如果您需要这样做,请尝试这个问题.

  • 根据linus torvalds,git gc和git repack之间的区别.http://metalinguist.wordpress.com/2007/12/06/the-woes-of-git-gc-aggressive-and-how-git-deltas-work/ (2认同)

Joh*_*zen 29

仅供参考,你最终可能会留下不需要的对象的最大原因是git维护了一个reflog.

当您意外删除主分支或以某种方式灾难性地损坏您的存储库时,reflog可以保存您的屁股.

解决这个问题的最简单方法是在压缩之前截断你的reflog(只是确保你永远不想回到reflog中的任何提交).

git gc --prune=now --aggressive
git repack
Run Code Online (Sandbox Code Playgroud)

这不同于git gc --prune=today它立即使整个reflog过期.

  • 这个是为我做的!我从大约 5gb 到 32mb。 (2认同)

nac*_*ker 10

如果要查找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,并运行垃圾收集以释放空间.


pio*_*ojo 7

如果你想看到所有blob的大小,Vi的答案中的git-fatfiles脚本是可爱的,但是它太慢而无法使用.我删除了40行输出限制,它试图使用我所有的计算机RAM,而不是完成.所以我重写了它:它快了几千倍,添加了功能(可选),并删除了一些奇怪的bug - 如果你将输出相加以查看文件使用的总空间,那么旧版本会给出不准确的计数.

#!/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];
}
Run Code Online (Sandbox Code Playgroud)

将此命名为git-fatfiles.pl并运行它.要查看文件的所有修订使用的磁盘空间,请使用该--sum选项.要查看相同的内容,但对于每个目录中的文件,请使用该--directories选项.如果安装Number :: Bytes :: Human cpan模块(运行"cpan Number :: Bytes :: Human"),则将格式化大小:"21M /path/to/file.mp4".