首页 > Technology > 正文

Git 误提交大文件:filter-repo 清理手册

fenij 2026-09-15 3 Technology

把 1.8GB 的 data.tar.gz 误提交进 Git 仓库,git rm 再提交一次根本没用——那个大文件还躺在历史里,别人一克隆照样把 1.8GB 全拉下来。要彻底清除,得用 git filter-repo 重写提交历史。下面是一套我实测能跑通的流程,照着做能避开绝大多数坑。

为什么 git rm 清不干净

Git 把每个文件版本存成不可变的 blob,靠 SHA 寻址。git rm 只是让最新提交不再引用那个 blob,可旧提交里还指着它,.git/objects 里的数据块原封不动。克隆时 Git 会把整条历史的所有 blob 全部拉回本地,所以仓库体积一点没少,克隆也照样慢。

动手前先做两件事

第一,整库备份。重写历史是不可逆操作,先 git clone --mirror 仓库地址 backup.git 留一份底,万一改坏还能还原。第二,在群里吼一声。强制推送之后,所有同事都得重新 git clone,否则他们本地的旧历史会和远端对不上,推送时直接冲突。

三步重写历史

关键原则:在全新的镜像克隆里操作,不要碰正在用的仓库。

# 1. 拉一份镜像克隆(含全部分支与标签)
git clone --mirror git@github.com:you/repo.git repo-rewrite.git
cd repo-rewrite.git

# 2. 删掉指定文件或目录
git filter-repo --path data.tar.gz --invert-paths

# 2b. 不想逐个列文件名,按体积一刀切:
git filter-repo --strip-blobs-bigger-than 50M

# 3. 强制推送覆盖远端
git push --force --all
git push --force --tags

--invert-paths 的意思是「保留除此之外的所有东西」,把目标路径从每个提交里抠掉。--strip-blobs-bigger-than 50M 则按大小无差别清理,适合「这几年攒了一堆二进制」的场景。两步选其一即可。

① 镜像备份
② 重写历史
③ 强制推送

踩坑实录

我第一次直接在天天用的仓库里跑 git filter-repo --path data.tar.gz --invert-paths,当场报错:Aborting: Refusing to destructively overwrite repo history since this is not a fresh clone. 翻了文档才懂,filter-repo 默认只认全新镜像克隆,怕你手滑覆盖正在工作的仓库;而且我上周误跑过一次,.git/filter-repo 目录还在,它直接拒绝执行。最后老老实实 git clone --mirror 重新拉一份,在镜像克隆里重跑,才把那个 1.8GB 文件从全部 312 个提交里抹掉。教训:别省镜像克隆这一步,把它当沙箱。

三种清理工具怎么选

别再照着十年前的 StackOverflow 用 git filter-branch 了,Git 官方自己都不推荐——又慢又容易出隐蔽错误。

工具 适用场景 结论
git filter-repo 绝大多数重写历史场景 首选
BFG Repo-Cleaner 只按大小批量删、不想写规则 备选
git filter-branch 几乎不再需要 弃用
1.8GB
大文件已从历史清除

312
个提交被重写

3 步
备份→重写→强推

常见问题

清理完远程仓库怎么还是那么大?
强制推送只是改了引用,对象还在服务端等垃圾回收。GitHub 或 GitLab 要在设置里点一次「Repository cleanup / 仓库清理」,等 GC 跑完体积才真正降下来,通常几分钟到几小时。

同事的本地仓库怎么办?
让他们删掉旧 clone 重新拉。如果手头有未推送的本地提交,先把改动 git cherry-pick 到新克隆的分支上,再推送,避免改动丢在强制推送里。

Windows 上装不上 filter-repo?
一条命令:pip install git-filter-repo。装完执行 git filter-repo --version,能看到版本号就说明环境好了。Python 没装的话先去装 Python 3。

如果你也在折腾仓库瘦身、迁移,或者 CI 卡在克隆慢,欢迎在 fenij.com 留言,我把踩过的坑继续整理出来。

相关完整手册

系统化的排查与配置思路,建议顺手收藏这几篇完整手册: