Git 仓库越拉越大:历史大文件、pack 膨胀与 gc 的正确姿势
现象:工作区没多大,.git 却占了几个 G
接手老仓库时常见这种情况:du -sh . 只有几百 MB,du -sh .git 却是 3~5 GB,clone 一次要十几分钟。原因是 Git 保存的是快照与历史对象,删除文件并不等于删除历史。下面按「定位大对象 → 清理历史 → 压缩 pack → 日常预防」四步处理。
第一步:找出到底是谁占了空间
不要急着 git gc --aggressive,先定位。列出所有对象及其大小,按体积排序:
git rev-list --objects --all \
| git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' \
| awk '/^blob/ {print $3, $4}' | sort -nr | head -20
能直接看到「哪个历史版本里的哪个文件」最大。另一个视角是看 pack 内部:
git verify-pack -v .git/objects/pack/*.idx | sort -k3 -nr | head -10
第二步:清理历史大文件
如果确认是某个误提交的二进制(镜像、压缩包、数据库备份),普通 git rm 只能去掉最新版本的引用,旧 blob 仍留在历史里。需要重写历史,推荐 git filter-repo:
git filter-repo --path huge.iso --invert-paths
要点:执行前必须备份仓库;重写会改变所有相关 commit 的哈希,需要通知协作者重新 clone;随后强推 git push --force --all。团队共享仓库还要联系平台方清理服务器端缓存(例如合并请求产生的临时引用),否则对象可能被重新带回。
第三步:压缩 pack 与回收松散对象
先看现状:
git count-objects -vH
若 size-garbage 或 count 很大,说明有大量松散对象或残留包:
git reflog expire --expire=now --all
git gc --prune=now
日常不要频繁使用 --aggressive,它耗时极长、收益有限;大仓库更适合用 git repack -Ad 重新打包。
第四步:从源头预防
- 二进制文件交给 Git LFS,仓库只保留指针;
- 补全 .gitignore,构建产物、日志、数据集不要入库;
- 提交前用
git diff --cached --stat看一眼体积; - 只读拉取用 partial clone:
git clone --filter=blob:none,按需下载 blob,CI 里能省下大量时间; - 定期在 CI 中跑
git count-objects -vH做体积巡检。
小结
仓库膨胀基本逃不出三类原因:历史大文件、松散对象与 pack 膨胀、二进制误入库。先用命令量出体积,再决定重写历史还是 gc,比盲目执行 gc 有效得多;重写历史是不可逆操作,务必先备份并同步团队。
- 点赞
- 收藏
- 关注作者
评论(0)