每次打开终端准备拉取代码时,等待进度条的时间都够冲一杯咖啡?别急着怪网络,很可能是你的Git仓库悄悄"发福"了。我最近就遇到一个12GB的仓库,实际代码才几百MB,罪魁祸首就是.git/objects/pack里那些被遗忘的"脂肪"。
Git的objects目录就像个永不删除的回收站。你每次git add一个文件,Git就会创建对应的blob对象;执行commit时又会生成tree和commit对象。这些对象被打包成.pack文件后,即使你删除了原始文件,它们依然顽固地占据着空间。我见过最夸张的案例是某团队把node_modules误提交后,仓库直接膨胀到20GB+。
常见"增重元凶"包括:
bash复制# 快速检查仓库体积
du -sh .git # 查看.git目录大小
git count-objects -v # 查看对象统计
要解决这个问题,首先得找到那些占用空间的历史文件。我习惯用组合命令来场"仓库体检":
bash复制# 找出体积最大的3个文件
git verify-pack -v .git/objects/pack/pack-*.idx |
sort -k 3 -n |
tail -3
这个命令链的工作原理是:
verify-pack解析pack文件内容sort -k 3按文件大小排序(第3列为压缩前大小)tail显示最大的几个对象拿到文件哈希后,再用侦探命令追溯真身:
bash复制git rev-list --objects --all |
grep 可疑文件哈希
最近帮某电商团队排查时,发现他们3年前的一次活动页打包文件(1.2GB的zip)竟然还在历史记录里。虽然早就不需要了,但每次克隆都要拖这个"僵尸文件"。
找到目标后,就该用filter-branch这个"手术刀"了。这是最关键的步骤,建议先在备份分支操作:
bash复制git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch 目标文件路径' \
--prune-empty --tag-name-filter cat -- --all
参数解析:
--index-filter:直接修改暂存区,比--tree-filter快10倍--ignore-unmatch:防止文件不存在时报错--prune-empty:自动清理空提交有个坑要注意:某次我清理完发现仓库反而变大了。原来filter-branch会备份原始引用到refs/original/,必须手动清理:
bash复制rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now
完成清理后,强制推送到远程仓库:
bash复制git push origin --force --all
git push origin --force --tags
为了防止"二次发胖",这些措施很有效:
git lfs管理大文件bash复制# 示例pre-commit钩子,限制单个文件不超过10MB
#!/bin/sh
MAX_SIZE=10485760
for file in $(git diff --cached --name-only)
do
size=$(git cat-file -s ":${file}" 2>/dev/null || wc -c <"$file")
[ $size -gt $MAX_SIZE ] && {
echo "错误: ${file} 超过10MB限制"
exit 1
}
done
记得通知所有协作者重新克隆仓库,否则他们的本地历史可能会把已删除的文件重新推回来。有次我们团队清理后,某同事的旧分支又把2GB的日志文件带回来了...
对于特别顽固的案例,可以试试这些进阶方法:
BFG Repo-Cleaner工具:
bash复制java -jar bfg.jar --delete-files 大文件名称.后缀 仓库路径
按目录清理(适合node_modules这种):
bash复制git filter-branch --tree-filter 'rm -rf 目录名' HEAD
时间范围清理:
bash复制git filter-branch --index-filter \
'git rm --cached --ignore-unmatch 文件名' \
--since="2020-01-01" --until="2022-12-31" \
-- --all
有个开源项目维护者告诉我,他们用BFG工具把仓库从8GB减到300MB,CI时间从45分钟降到3分钟。不过要注意,修改历史后所有提交ID都会变更,可能会影响依赖特定commit hash的自动化流程。
清理完的仓库就像整理好的衣柜——找东西更快,维护更轻松。上周刚帮一个React组件库瘦身成功,现在他们的新人 onboarding 时间缩短了70%。记住定期给仓库"称体重",别等到clone要半小时才想起优化。