我有一个300mb的git回购。我目前签出的文件的总大小是2 MB,其余的git回购的总大小是298 MB。这基本上是一个只有代码的回购,不应该超过几MB。

我怀疑有人不小心提交了一些大文件(视频、图像等),然后删除了它们……但不是从git,所以历史仍然包含无用的大文件。如何在git历史中找到大文件?有400多个提交,所以一个接一个的提交是不实际的。

注意:我的问题不是关于如何删除文件,而是如何在第一时间找到它。


当前回答

像这样使用git-filter-repo的——analyze特性:

$ cd my-repo-folder
$ git-filter-repo --analyze
$ less .git/filter-repo/analysis/path-all-sizes.txt

其他回答

对于Windows,我写了一个Powershell版本的答案:

function Get-BiggestBlobs {
  param ([Parameter(Mandatory)][String]$RepoFolder, [int]$Count = 10)
  Write-Host ("{0} biggest files:" -f $Count)
  git -C $RepoFolder rev-list --objects --all | git -C $RepoFolder cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | ForEach-Object {
    $Element = $_.Trim() -Split '\s+'
    $ItemType = $Element[0]
    if ($ItemType -eq 'blob') {
      New-Object -TypeName PSCustomObject -Property @{
          ObjectName = $Element[1]
          Size = [int]([int]$Element[2] / 1kB)
          Path = $Element[3]
      }
    }
  } | Sort-Object Size | Select-Object -last $Count | Format-Table ObjectName, @{L='Size [kB]';E={$_.Size}}, Path -AutoSize
}

您可能需要根据自己的情况微调它是显示kB还是MB,还是仅显示Bytes。

可能存在性能优化的潜力,因此,如果您担心这一点,可以自由地进行试验。

要获得所有更改,只需省略| Select-Object -last $Count。 要得到一个更便于机器阅读的版本,只需省略| Format-Table @{L='Size [kB]';E={$_。Size}},路径-AutoSize。

你应该使用BFG Repo-Cleaner。

根据该网站:

BFG是一个更简单、更快的git-filter-branch的替代方案 清除Git存储库历史中的坏数据: 删除疯狂的大文件 删除密码,凭证和其他私人数据

减少存储库大小的经典过程是:

git clone --mirror git://example.com/some-big-repo.git
java -jar bfg.jar --strip-biggest-blobs 500 some-big-repo.git
cd some-big-repo.git
git reflog expire --expire=now --all
git gc --prune=now --aggressive
git push

我在苏黎世联邦理工学院物理系的维基页面上找到了一个简单的解决方案(接近该页的末尾)。只要做个git垃圾收集,把垃圾清除掉,然后

git rev-list --objects --all \
  | grep "$(git verify-pack -v .git/objects/pack/*.idx \
           | sort -k 3 -n \
           | tail -10 \
           | awk '{print$1}')"

将为您提供存储库中最大的10个文件。

现在还有一个更懒的解决方案,GitExtensions现在有一个插件,可以在UI中做到这一点(以及处理历史重写)。

步骤1将所有sha1文件写入文本文件。

git rev-list --objects --all | sort -k 2 > allfileshas.txt

步骤2将blobs从大到小排序,并将结果写入文本文件:

git gc && git verify-pack -v .git/objects/pack/pack-*.idx | egrep "^\w+ blob\W+[0-9]+ [0-9]+ [0-9]+$" | sort -k 3 -n -r > bigobjects.txt

步骤3a结合两个文本文件,得到文件名/sha1/大小信息:

for SHA in `cut -f 1 -d\  < bigobjects.txt`; do
echo $(grep $SHA bigobjects.txt) $(grep $SHA allfileshas.txt) | awk '{print $1,$3,$7}' >> bigtosmall.txt
done;

如果您的文件名或路径名包含空格,请尝试步骤3a的这种变化。它使用cut而不是awk来获得从第7列到行尾的所需列包括空格:

for SHA in `cut -f 1 -d\  < bigobjects.txt`; do
echo $(grep $SHA bigobjects.txt) $(grep $SHA allfileshas.txt) | cut -d ' ' -f'1,3,7-' >> bigtosmall.txt
done;

现在可以查看bigtosmall.txt文件,以决定要从Git历史记录中删除哪些文件。

要执行删除(注意这部分很慢,因为它将检查历史记录中的每个提交,以获取关于您标识的文件的数据):

git filter-branch --tree-filter 'rm -f myLargeFile.log' HEAD

步骤1-3a是从Git历史记录中查找和清除大文件复制的

EDIT

这篇文章在2017年下半年的某个时候被删除了,但它的存档副本仍然可以使用时光倒流机访问。

试试git ls-files | xargs du -hs——threshold=1M。

我们在CI管道中使用下面的命令,如果它在git repo中发现任何大文件,它就会停止:

test $(git ls-files | xargs du -hs --threshold=1M 2>/dev/null | tee /dev/stderr | wc -l) -gt 0 && { echo; echo "Aborting due to big files in the git repository."; exit 1; } || true