1. 概述
在本篇文章中,我们将学习如何使用多种工具从 Git 仓库的提交历史中删除大文件。这在项目维护过程中非常常见,尤其是当某些大文件(如日志、数据库导出、临时文件等)被误提交后,不仅会拖慢克隆速度,还会占用不必要的存储空间。
2. 使用 git filter-branch
这是最常用的方法之一,可以用来重写提交历史,删除指定文件。
例如,我们不小心提交了一个名为 blob.txt
的大文件,即使后续删除了它,在 Git 历史中依然存在:
$ git log --graph --full-history --all --pretty=format:"%h%x09%d%x20%s"
* 9e87646 (HEAD -> master) blob file removed
* 2583677 blob file
* 34ea256 my first commit
我们可以使用以下命令删除该文件的历史记录:
$ git filter-branch --tree-filter 'rm -f blob.txt' HEAD
✅ --tree-filter
表示对工作树进行操作,rm -f
强制删除文件。
⚠️ 如果文件在某些提交中不存在,不加 -f
可能会导致命令失败。
执行后,Git 会生成一个新的提交历史,但原始历史仍保留在 refs/original/
中:
* 8f39d86 (HEAD -> master) blob file removed
* e99a81d blob file
| * 9e87646 (refs/original/refs/heads/master) blob file removed
| * 2583677 blob file
|/
* 34ea256 my first commit
为了彻底清除这些残留信息,我们可以运行以下命令:
$ git update-ref -d refs/original/refs/heads/master
$ git reflog expire --expire=now --all
$ git gc --prune=now
✅ 这些命令分别用于删除原始引用、清理 reflog、以及压缩仓库。
⚠️ 执行前请确保已经备份,避免误删重要数据。
最终,我们的提交历史将不再包含该文件:
* 6f49d86 (HEAD -> master) my first commit
优化方式:使用 --index-filter
如果只想删除文件但不操作工作目录,可以使用 --index-filter
,速度更快:
$ git filter-branch --index-filter 'git rm --cached --ignore-unmatched blob.txt' HEAD
✅ --cached
只操作索引,不修改文件系统。
✅ --ignore-unmatched
避免因文件不存在而报错。
⚠️ 该方法适用于删除大文件,但如果文件多次提交,效率仍然不高。
3. 使用 git-filter-repo
这是官方推荐的替代 git filter-branch
的工具,速度快、功能丰富,推荐使用。
3.1 安装
要求:
- Python 3 >= 3.5
- Git >= 2.22.0(部分功能需要 2.24.0 或更高)
Linux 安装方式如下:
$ sudo apt install python3-pip
$ pip install --user git-filter-repo
或者手动下载安装:
export PATH="${HOME}/bin:${PATH}"
mkdir -p ~/bin
wget -O ~/bin/git-filter-repo https://raw.githubusercontent.com/newren/git-filter-repo/7b3e714b94a6e5b9f478cb981c7f560ef3f36506/git-filter-repo
chmod +x ~/bin/git-filter-repo
3.2 删除文件
先查看当前提交历史:
$ git log --graph --full-history --all --pretty=format:"%h%x09%d%x20%s"
* ee36517 (HEAD -> master) blob.txt removed
* a480073 project folder
分析仓库内容:
$ git filter-repo --analyze
Processed 5 blob sizes
Processed 2 commits
Writing reports to .git/filter-repo/analysis...done.
然后执行删除命令:
$ git filter-repo --force --invert-paths --path-match blob.txt
✅ --invert-paths
表示删除匹配路径的文件。
✅ --path-match
指定要删除的文件名。
⚠️ 执行后所有相关提交的哈希值都会改变。
最终提交历史如下:
* 8940776 (HEAD -> master) project folder
4. 使用 BRG Repo-Cleaner
这是一个基于 Java 的工具,适合删除大文件、敏感信息等。
✅ 优点:速度快,操作简单。
✅ 适合批量处理大文件。
例如,删除所有大于 200MB 的 blob 文件:
$ java -jar bfg.jar --strip-blob-bigger-than 200M my-repo.git
然后清理仓库:
$ git gc --prune=now --aggressive
⚠️ 使用前建议备份仓库,防止误删。
5. 使用 git rebase
适用于删除最近几次提交中的文件。
查看提交历史:
$ git log --graph --full-history --all --pretty=format:"%h%x09%d%x20%s"
* 535f7ea (HEAD -> master) blob file removed
* 8bffdfa blob file
* 5bac30b index.html
假设我们要删除 blob file
这个提交,可以使用如下命令进入交互式 rebase:
$ git rebase -i 5bac30b
在编辑器中删除对应行:
pick 535f7ea blob file removed
drop 8bffdfa blob file
保存退出后继续 rebase:
$ git rebase --continue
最终提交历史如下:
* 5bac30b (HEAD -> master) index.html
✅ 适用于少量提交的调整。
❌ 不适合处理大量提交,效率较低。
6. 总结
方法 | 优点 | 缺点 |
---|---|---|
git filter-branch |
传统方法,兼容性好 | 慢,维护性差 |
git-filter-repo |
✅ 官方推荐,速度快,功能强 | 需要安装,依赖 Python |
BFG Repo-Cleaner |
快速,适合批量处理 | 依赖 Java |
git rebase |
简单,适合少量提交 | 不适合处理大量历史记录 |
✅ 推荐优先使用 git-filter-repo
,它在性能和易用性方面都优于其他方法。
⚠️ 操作前务必做好备份,避免误删导致数据丢失。