为什么我的git仓库如此之大?

145M = .git / objects / pack /

我写了一个脚本来将每个提交和提交之间的差异大小加起来,然后从每个分支的末端往回走。 我得到了129MB,这是没有压缩,没有考虑到分支机构之间的相同文件和分支机构之间的共同历史。

Git把所有这些事情都考虑进去了,所以我会期望更小的存储库。 那为什么.git这么大?

我已经搞定了:

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

要回答多less文件/提交,我有19个分支约40个文件在每个。 287次提交,使用:

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

这不应该花10兆的存储信息。

我最近把错误的远程仓库拉到本地( git remote add ...git remote update )。 删除不需要的远程引用后,分支和标签我仍然有1.4GB(!)的浪费空间在我的仓库。 我只能通过使用git clone file:///path/to/repository来克隆它。 请注意, file://在克隆本地存储库时会产生不同的效果 – 只有被引用的对象被复制,而不是整个目录结构。

编辑:伊恩的一个class轮在新的回购中重新创build所有分支:

 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 

我使用的一些脚本:

混帐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 "-es/$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

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 

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

git gc已经做了一个git repack所以没有意义的手动重新包装,除非你要传递一些特殊的select。

第一步是看大多数的空间是否(通常是这样)你的对象数据库。

 git count-objects -v 

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

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

如果你有一个大包装,你想知道什么是占用的空间,那么你可以列出构成包装的物品以及它们的存储方式。

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

请注意, verify-pack需要一个索引文件,而不是包文件本身。 这给出了包中的每个对象的报告,它的真实大小和包装大小,以及关于它是否被“分离”以及如果是这样的三angular洲链的起源的信息。

要查看版本库中是否有非常大的对象,可以在第四列的第三列(例如| sort -k3n )上对输出进行数字| sort -k3n

从这个输出中,您将能够使用git show命令查看任何对象的内容,但是无法确切地查看引用该对象的存储库的提交历史logging中的哪个位置。 如果你需要这样做,试试这个问题 。

只是供参考,为什么你最终可能会不受欢迎的对象被保留的最大原因是git保持reflog。

reflog是为了节省你的屁股,当你不小心删除你的主分支或以某种方式,否则灾难性的破坏你的仓库。

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

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

这不同于git gc --prune=today ,因为它立即过期了整个reflog。

你确定你只计算.pack文件,而不是.idx文件? 它们和.pack文件在同一个目录中,但是没有任何的存储库数据(正如扩展所指出的,它们只不过是相应包的索引 – 事实上,如果你知道正确的命令,你可以轻松地从包文件中重新创build它们,git本身在克隆的时候做它,因为只有使用本地git协议传输包文件)。

作为一个代表性的例子,我看了一下linux-2.6版本库的本地克隆:

 $ du -c *.pack 505888 total $ du -c *.idx 34300 total 

这表明7%左右的扩张应该是常见的。

还有objects/外的文件objects/ ; 以我个人的经验来看,其中indexgitk.cache往往是最大的(在我的linux-2.6版本库中共计11M)。

Vi的答案中的git-fatfiles脚本是可爱的,如果你想看到你所有的blob的大小,但它是如此缓慢,以至于无法使用。 我删除了40行输出限制,它试图使用我所有的计算机的RAM而不是完成。 所以我重写了它:这是几千倍的速度,增加了function(可选),并删除了一些奇怪的错误 – 旧版本将提供不准确的计数,如果总结输出看到文件使用的总空间。

 #!/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”。

其他存储在.git git对象包括树,提交和标签。 提交和标签很小,但是如果你的仓库中有大量的小文件的话,树会变得很大。 你有多less个文件和多less个提交?

如果你想find什么文件占用你的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,并运行垃圾收集来释放空间。

你尝试使用Git重新包装 ?

在做git filter-branch&git gc之前,你应该检查存在于你的仓库中的标签。 任何真正的系统,如持续集成和部署都会自动标记,这些标记仍然会引用未被引用的对象,因此gc无法删除它们,您仍然不知道为什么回购的大小仍然如此之大。

摆脱所有不想要的东西的最好方法是运行git-filter&git gc,然后将master推到一个新的裸回购。 新的裸回购将有清理树。

如果您不小心添加了一大块文件并将其加载,则不一定提交。 当你运行bundle install --deployment ,然后意外的git add .时候,这可能发生在rails应用程序中git add . 那么你可以看到所有在vendor/bundle下添加的文件,但是他们已经进入了git历史logging,所以你必须应用Vi的答案,并通过vendor/bundle更改video/parasite-intro.avi ,然后运行他提供的第二个命令。

你可以看到与git count-objects -v的区别,在我的情况下,在应用脚本之前,它的大小为52K,应用后为3.8K。