◆

Gitee 仓库大小超推荐值的 GC 清理方法

2023-02-02 01:370

remote: Warning: this repository(including wiki) size 622.20 MB exceeds 500.00 MB

警告如图

这条警告出现在 git push 的输出里,remote: 前缀表示它来自服务端而不是本地 git。注意它统计的是仓库的完整大小,包括 wiki 和所有历史版本,不是工作区里那些文件的体积——这是理解整件事的关键。

git push 时终端输出的 Gitee 仓库超限警告,显示当前仓库大小和推荐上限

tip

出现此警告说明当前仓库的代码大小已经超出 gitee 的推荐大小了, 如果不做处理,会导致推送不了代码。

为什么工作区明明只有几十兆,仓库却涨到几百兆?因为 git 保存的是每次提交的完整快照链。一个 10MB 的二进制文件(图片、字体、打包产物、依赖包)改过 20 次,git 里就存了 20 份不同的对象,累积 200MB——就算你后来把这个文件删了,历史里的那些对象依然在,磁盘占用一分不少。这是 git 的设计使然:为了能检出任意历史版本,所有对象都要留着。

所以体积失控的仓库,源头几乎总是二进制文件进了版本控制。文本文件的增量压缩效率极高,几千个源码文件改上万次也占不了多少空间。

如何查看查看仓库代码大小

在仓库的管理页面能看到实际占用。下图这个页面会列出仓库大小和上限,超了会标出来:

Gitee 仓库管理页面中显示的仓库存储大小与容量上限

本地也能查。du -sh .git 看 .git 目录的实际大小,git count-objects -vH 更细致,会分别列出松散对象和打包后的体积。想找出到底是哪些大文件占的,这条命令能列出仓库里最大的那些对象:

git rev-list --objects --all |
  git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' |
  awk '/^blob/ {print $3, $4}' | sort -rn | head -20

输出是「字节数 文件路径」,从大到小排。跑一遍基本就知道问题出在哪了。

不删除项目文件的情况下爱减少项目大小

点击管理-存储库 GC-点击存储库 GC按钮进行清理

GC(garbage collection)做的是清理无用对象和重新打包。仓库里会积累一些「不可达对象」——被 reset 丢弃的提交、被 force push 覆盖的分支、rebase 产生的中间提交,这些对象已经没有任何引用指向它们,但仍然占着空间。GC 把它们删掉,同时把散落的松散对象压缩进 packfile,压缩率比单个存储高很多。

下图是 Gitee 上这个功能的入口位置,在仓库管理页面里:

Gitee 仓库管理页面中的存储库 GC 功能入口及执行按钮

GC 之后还是超限怎么办

要清楚 GC 的能力边界:它只清理不可达对象,历史里正常提交过的文件它一个都不会删。如果体积是被历史上真实提交过的大文件占着的,GC 效果非常有限,压缩个百分之十几就到顶了。

彻底解决只能改写历史,把那些大文件从所有历史提交里抹掉。工具用 git filter-repo(官方现在推荐它,比老的 filter-branch 快几十倍):

# 从所有历史中移除指定路径
git filter-repo --path node_modules --invert-paths
# 或者按体积过滤,移除所有大于 10MB 的文件
git filter-repo --strip-blobs-bigger-than 10M

改写历史的代价必须说清楚:所有提交的 hash 都会变,等于整个仓库的历史被重写。这意味着要 force push,所有协作者都得重新 clone(他们本地的分支和远端完全对不上,普通 pull 会一团乱),已有的 PR、issue 里引用的 commit 链接全部失效。多人协作的仓库做这件事之前必须先通知到所有人。操作前也务必先完整备份一份仓库。

预防比治疗容易得多。.gitignore 里从一开始就把 node_modules、dist、build、各种缓存目录排除掉。确实需要版本管理的大文件(设计源文件、模型、素材)用 Git LFS,它把文件本体存到独立的存储,git 里只留一个指针,仓库体积就控制住了。

💬留言板0

还没有留言,来发表第一条吧~

PAGE LOAD / LIVEGitee 仓库大小超推荐值的 GC 清理方法加载中