如何在Git历史logging中查找/识别大文件/提交?

我有一个300 MB的git回购。 我目前签出的文件重2 MB,git repo重298 MB。 这基本上是一个代码回购,不应该超过几MB。

最有可能的是,有人在某些意外事件(video,巨大的图像等)犯了一些沉重的文件,然后删除它们…但不是从混帐,所以我们有一个无用的大文件的历史。 我怎样才能追查在git历史上的大文件? 有400多个提交,所以去一个将是费时。

注意 :我的问题不是关于如何删除文件 ,而是如何find它的第一个地方。

我发现这个脚本在以前用于在git仓库中查找大型(非显而易见的)对象非常有用:


#!/bin/bash #set -x # Shows you the largest objects in your repo's pack file. # Written for osx. # # @see https://stubbisms.wordpress.com/2009/07/10/git-script-to-show-largest-pack-objects-and-trim-your-waist-line/ # @author Antony Stubbs # set the internal field spereator to line break, so that we can iterate easily over the verify-pack output IFS=$'\n'; # list all objects including their size, sort by size, take top 10 objects=`git verify-pack -v .git/objects/pack/pack-*.idx | grep -v chain | sort -k3nr | head` echo "All sizes are in kB's. The pack column is the size of the object, compressed, inside the pack file." output="size,pack,SHA,location" allObjects=`git rev-list --all --objects` for y in $objects do # extract the size in bytes size=$((`echo $y | cut -f 5 -d ' '`/1024)) # extract the compressed size in bytes compressedSize=$((`echo $y | cut -f 6 -d ' '`/1024)) # extract the SHA sha=`echo $y | cut -f 1 -d ' '` # find the objects location in the repository tree other=`echo "${allObjects}" | grep $sha` #lineBreak=`echo -e "\n"` output="${output}\n${size},${compressedSize},${other}" done echo -e $output | column -t -s ', ' 

这会给你的对象名称(SHA1sum)的blob,然后你可以使用这样的脚本:

  • 哪个提交有这个blob?

…find指向每个blob的提交。

我在苏黎世理工学院物理维基页上find了一个单线解决scheme(接近该页的末尾)。 只要做一个git gc去除陈旧的垃圾,然后

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

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

现在还有一个更加懒惰的解决scheme, GitExtensions现在有一个插件,它可以在UI中执行此操作(并处理历史重写)。

GitExtensions“查找大文件”对话框

🚀一个快速的shell单行🚀

此shell脚本显示存储库中的所有blob对象,从最小到最大sorting。

对于我的示例回购,它比其他在这里find的速度快100倍
在我可靠的Athlon II X4系统上,它只需一分钟就可以处理Linux内核版本库中的5.6百万个对象。

基本脚本

 git rev-list --objects --all \ | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' \ | awk '/^blob/ {print substr($0,6)}' \ | sort --numeric-sort --key=2 \ | cut --complement --characters=13-40 \ | numfmt --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest 

当你运行上面的代码,你会得到很好的人类可读的输出,像这样:

 ... 0d99bb931299 530KiB path/to/some-image.jpg 2ba44098e28f 12MiB path/to/hires-image.png bd1741ddce0d 63MiB path/to/some-video-1080p.mp4 

过滤

进一步筛选 ,请sort行之前插入以下任一行

排除HEAD中存在的文件 ,请插入以下行:

 | grep -vF "$(git ls-tree -r HEAD | awk '{print $3}')" \ 

仅显示超过给定大小的文件 (例如1 MiB = 2 20 B),请插入以下行:

 | awk '$2 >= 2^20' \ 

计算机的输出

要生成更适合计算机进一步处理的输出,请省略基本脚本的最后两行。 他们做所有的格式。 这会给你带来这样的事情:

 ... 0d99bb93129939b72069df14af0d0dbda7eb6dba 542455 path/to/some-image.jpg 2ba44098e28f8f66bac5e21210c2774085d2319b 12446815 path/to/hires-image.png bd1741ddce0d07b72ccf69ed281e09bf8a2d0b2f 65183843 path/to/some-video-1080p.mp4 

🚀快速文件删除🚀

假设你想从每个从HEAD可达的提交中移除文件ab ,你可以使用这个命令:

 git filter-branch --index-filter 'git rm --cached --ignore-unmatch ab' HEAD 

你应该使用BFG Repo-Cleaner 。

根据网站:

BFG是一个简单,快捷的替代git-filter-branch的工具,用于清理Git仓库历史logging中的错误数据:

  • 删除疯狂的大文件
  • 删除密码,证件和其他私人数据

减小库的大小的经典过程是:

 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 

步骤1将所有文件SHA1写入文本文件:

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

步骤2从最大到最小sortingblob,并将结果写入文本文件:

 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 / size信息:

 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; 

步骤3b如果您有文件名或包含空格的path名,请尝试步骤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历史logging中删除哪些文件。

第4步要执行删除(注意这部分是缓慢的,因为它将检查您的历史logging中的每个提交有关您标识的文件的数据):

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

资源

步骤1-3a从查找并从Git历史中清除大文件复制

编辑

这篇文章在2017年下半年的某个时候被删除,但是仍然可以使用Wayback Machine访问该文件的存档副本 。

如果你只想要一个大文件列表,那么我想给你提供以下的一行代码 ( 来源于renuo ):

 join -o "1.1 1.2 2.3" <(git rev-list --objects --all | sort) <(git verify-pack -v objects/pack/*.idx | sort -k3 -n | tail -5 | sort) | sort -k3 -n 

谁的输出将是:

 commit file name size in bytes 72e1e6d20... db/players.sql 818314 ea20b964a... app/assetshttp://img.dovov.combackground_final2.png 6739212 f8344b9b5... data_test/pg_xlog/000000010000000000000001 1625545 1ecc2395c... data_development/pg_xlog/000000010000000000000001 16777216 bc83d216d... app/assetshttp://img.dovov.combackground_1forfinal.psd 95533848 

列表中的最后一项指向你的git历史logging中最大的文件。

您可以使用此输出来确保您不会删除您在历史logging中需要使用的BFG 。

如果你在Windows上,这是一个PowerShell脚本,它将打印存储库中最大的10个文件:

 $revision_objects = git rev-list --objects --all; $files = $revision_objects.Split() | Where-Object {$_.Length -gt 0 -and $(Test-Path -Path $_ -PathType Leaf) }; $files | Get-Item -Force | select fullname, length | sort -Descending -Property Length | select -First 10 

我如何追踪git历史logging中的大文件?

从分析,validation和select根本原因开始。 使用git-repo-analysis来帮助。

您也可以在BFG Repo-Cleaner生成的详细报告中find一些价值,通过使用10MiB / s的networking吞吐量将其克隆到数字海洋液滴,可以非常快速地运行。