Git 仓库体积过大如何清理历史大文件优化

文章导读
推荐使用 git filter-repo 或 BFG Repo-Cleaner 重写提交历史来移除大文件,操作前必须备份仓库并通知所有协作者。此操作会改写提交哈希,导致原有克隆失效,仅建议在仓库早期或必要时进行。
📋 目录
  1. A 命令速用版
  2. B 为什么会这样
  3. C 分步处理
  4. D 怎么验证是否生效
  5. E 常见坑
  6. F 常见问题
  7. G 参考来源
A A

推荐使用 git filter-repo 或 BFG Repo-Cleaner 重写提交历史来移除大文件,操作前必须备份仓库并通知所有协作者。此操作会改写提交哈希,导致原有克隆失效,仅建议在仓库早期或必要时进行。

先说结论:清理 Git 历史大文件的核心是重写提交历史,必须使用过滤工具配合垃圾回收,且需团队协同。

  • 先定位:使用 git rev-listgit-scan-tree 找出占用空间最大的文件路径。
  • 先做:本地执行过滤命令清理历史,确认无误后再强制推送到远程。
  • 再验证:推送后检查远程仓库大小,并通知团队成员重新克隆。

命令速用版

以下命令用于检查仓库大小及移除大于指定体积的文件,需在本地仓库根目录执行。

# 查看仓库对象大小分布
git count-objects -vH

# 使用 git-filter-repo 移除大于 10M 的文件
git filter-repo `--strip-blobs-bigger-than` 10M

# 清理无用对象并压缩
git reflog expire `--expire`=now `--all`
git gc `--prune`=now `--aggressive`

为什么会这样

Git 默认保留所有历史对象的完整快照,删除文件不会立即释放空间。

Git 存储的是快照而非差异,即使你在某次提交中删除了大文件,该文件依然存在于之前的提交对象中。普通的 git gc 只能清理未被引用的对象,无法移除历史提交中已引用的大文件,必须重写历史才能彻底清除。

分步处理

按顺序执行以下步骤,每步完成后确认无误再进行下一步。

1. 备份仓库

克隆一份完整备份到本地其他目录,防止操作失误导致数据丢失。

Git 仓库体积过大如何清理历史大文件优化
git clone `--mirror` <repository-url> backup-repo.git

2. 安装过滤工具

推荐使用 git-filter-repo,比传统的 git filter-branch 更快更安全。

pip install git-filter-repo

3. 分析大文件

找出具体是哪个文件或路径占用了空间,避免误删。

git rev-list `--objects` `--all` | git-cat-file `--batch-check`='%(objecttype) %(objectname) %(objectsize) %(rest)' | sed -n 's/^blob //p' | sort -r `--numeric-sort` -k2 | head -n 10

4. 执行清理

根据分析结果,按路径或大小过滤。清理后必须立即执行垃圾回收。

git filter-repo `--strip-blobs-bigger-than` 10M
git reflog expire `--expire`=now `--all`
git gc `--prune`=now `--aggressive`

5. 强制推送

历史已改写,必须强制推送覆盖远程仓库,此操作会影响所有协作者。

Git 仓库体积过大如何清理历史大文件优化
git push `--force` `--all`
git push `--force` `--tags`

怎么验证是否生效

通过本地对象统计和远程仓库页面显示确认体积变化。

本地验证:再次运行 git count-objects -vH,观察 size-pack 是否明显减小。

远程验证:刷新 GitHub 或 GitLab 仓库设置页面的 Size 显示,公开资料中没有看到可靠的量化数据,具体减少比例取决于大文件在历史中的占比。

全新克隆:在临时目录重新克隆仓库,检查下载体积是否符合预期。

常见坑

  • 保护分支限制:远程仓库若开启分支保护,可能拒绝强制推送,需临时关闭保护策略。
  • CI/CD 缓存:流水线缓存可能仍保留旧对象,需手动清除构建缓存。
  • 协作者同步:其他成员必须重新克隆或执行复杂的重置操作,否则推送会被拒绝。
  • 工具选择:避免使用 git filter-branch,官方文档已建议其用于遗留场景,效率较低且易出错。

常见问题

git gc 能直接清理历史大文件吗?

不能,git gc 只能清理未被引用的对象,无法移除历史提交中已引用的大文件。

清理后原来的提交记录还在吗?

不在,重写历史会生成新的提交哈希,原有提交记录会被替换。

只删除最近一次提交的大文件怎么做?

使用 git reset `--hard` HEAD~1 回退版本,或 git commit `--amend` 修改最近提交。

参考来源

  • Git Documentation: git-filter-repo - https://git-scm.com/docs/git-filter-repo
  • GitHub Docs: Removing sensitive data from a repository - https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/removing-sensitive-data-from-a-repository
  • Atlassian Git Tutorial: git push - https://www.atlassian.com/git/tutorials/syncing/git-push