从历史中移除大文件
有时候,有人不小心把几百兆的 database.dump 或 node_modules.zip 提交到了仓库中。即使你后来用 git rm 删除了它们,它们依然存在于 Git 的历史记录(.git 目录)中,导致克隆变慢。
要彻底清除它们,你需要重写历史。
为什么不能只用 git rm?
Section titled “为什么不能只用 git rm?”git rm 只会从当前工作区和索引中删除文件,并创建一个新的提交记录“删除了文件”。历史提交中依然完整保留着该文件的物理副本。
虽然 Git 自带 filter-branch 命令,但它极其缓慢且容易出错。官方强烈建议使用第三方专用工具。
1. BFG Repo-Cleaner (推荐入门)
Section titled “1. BFG Repo-Cleaner (推荐入门)”BFG 是一个基于 Java 的工具,比 filter-branch 快 10-50 倍(在某些场景下可能更快),且使用更简单。
安装: 需先安装 Java,然后下载 jar 包或通过包管理器:
brew install bfg使用步骤:
-
克隆裸仓库(为了安全和速度):
Terminal window git clone --mirror https://github.com/your-org/some-big-repo.git -
执行清理: 假设我们要删除所有大于 100MB 的文件:
Terminal window bfg --strip-blobs-bigger-than 100M some-big-repo.git或者按文件名删除:
Terminal window bfg --delete-files *.zip some-big-repo.git -
物理清理: BFG 更新了提交历史,但物理文件还在。需要运行 GC 清理:
Terminal window cd some-big-repo.gitgit reflog expire --expire=now --all && git gc --prune=now --aggressive -
推送到远程: 由于是
--mirror克隆,需要推送所有引用:Terminal window git push --mirror如果是普通克隆,则需要:
Terminal window git push --force --all && git push --force --tags
2. git-filter-repo (Python 编写,功能最强)
Section titled “2. git-filter-repo (Python 编写,功能最强)”这是目前 Git 官方文档推荐的现代化工具。
安装:
pip install git-filter-repo使用步骤:
-
分析仓库:
Terminal window git filter-repo --analyze这会在
.git/filter-repo/analysis下生成详细的报告,告诉你哪些文件占用了最多空间。 -
执行清理: 删除特定路径:
Terminal window git filter-repo --path path/to/large/file --invert-paths
传统方法:git filter-branch (已废弃)
Section titled “传统方法:git filter-branch (已废弃)”虽然已废弃,但为了应对遗留脚本,了解一下也无妨。
git filter-branch --force --index-filter \ "git rm --cached --ignore-unmatch path/to/large/file" \ --prune-empty --tag-name-filter cat -- --all缺点:
- 极慢(对于大仓库可能跑几天)。
- 参数复杂,容易搞坏 Tag 和合并提交。
完成清理并强制推送(Force Push)后,你需要通知团队所有成员:
- 不要拉取(Pull)代码,这会把脏历史重新合并回来。
- 强烈建议重新克隆(Clone)仓库;高级用户可按安全流程重置到新历史。
作为系统管理员,此时可以考虑开启远程仓库的“保护分支”功能,短时间内禁止非快进(Non-fast-forward)推送,防止有人不小心把旧历史推回来。
敏感数据泄露的额外处理
Section titled “敏感数据泄露的额外处理”如果你清理的是密码、API 密钥等敏感数据,仅重写历史是不够的。即使本仓库已清理干净,数据可能仍存在于:
- Forks:其他用户 fork 的仓库不会自动更新。
- Pull Request 缓存:GitHub 等平台可能缓存了 PR 中的提交内容。
- CI/CD 日志:构建日志可能记录了敏感信息。
- 本地克隆:团队成员的本地仓库。
必要的补救措施:
- 立即轮换凭据:更改所有泄露的密码、API 密钥、Token 等。这是最重要的一步。
- 联系平台支持:向 GitHub/GitLab 提交请求,要求清理缓存和 fork 中的敏感数据。
- 通知相关方:告知团队成员和安全团队此次事件。
- 审计访问日志:检查凭据是否已被滥用。