掌握Git垃圾回收,实现极致性能
了解何时运行git gc、它清理什么内容,以及如何避免在活跃仓库中执行危险的激进清理。
掌握Git垃圾回收,实现极致性能
Git垃圾回收能防止仓库无限积累松散对象、过时不可达提交和低效的包文件。如果你的仓库运行缓慢、占用过多磁盘空间,或者经历了大量变基和分支清理操作,git gc 是你需要了解的首要维护工具之一。
通常你不需要每天运行它。当某些阈值达到时,Git 会在正常命令执行期间自动进行维护。不过,了解它的作用有助于避免两个常见错误:数月忽视臃肿的仓库,或在未了解影响的情况下对共享仓库执行激进清理。
Git垃圾回收的作用
Git 将数据存储为对象:提交、树、二进制大对象和标签。新对象最初可能以松散文件形式存放在 .git/objects/ 下。随着时间的推移,Git 可以将多个对象打包成紧凑的包文件。打包后的对象磁盘利用率更高,Git 扫描速度通常也更快。
git gc 执行多项维护任务,包括:
- 将松散对象打包成包文件。
- 在必要时合并现有包文件。
- 删除足够陈旧的可修剪不可达对象。
- 清理因中断操作留下的临时文件。
- 在配置了现代 Git 设置时,更新辅助数据(如提交图文件)。
不可达并不意味着可以立即安全删除。在变基、修改、重置或删除分支后,提交可能变为不可达。Git 通常会为最近不可达的对象保留一段宽限期,以便你有时间通过 git reflog 恢复。
清理前检查仓库大小
首先测量仓库大小,而不是猜测:
git count-objects -vH
有用的字段包括 count、size、in-pack、packs 和 size-pack。松散对象数量过多可能会拖慢日常 Git 操作。size-pack 很大可能仅仅意味着仓库包含大量真实历史、大型二进制文件或供应商资源。
要直接检查磁盘使用情况,运行:
du -sh .git
如果 .git 很大是因为有人提交了构建产物或大型归档文件,仅靠垃圾回收可能无法解决根本问题。你可能需要从未来提交中移除大文件,将其迁移到 Git LFS,或在团队协调后使用 git filter-repo 等工具重写历史。
运行常规垃圾回收
对于日常清理,使用:
git gc
这是安全的默认选项。它让 Git 决定哪些维护工作值得执行,并遵循正常的修剪规则。
你可以要求 Git 仅在阈值表明需要时才执行自动维护:
git gc --auto
大多数用户无需手动调用 --auto,因为 Git 已经在后台自动执行。但在脚本中,当你希望进行低成本的清理而不每次都强制完全重新打包时,它仍然有用。
如果你想使用标准宽限期删除旧的不可达对象,运行:
git gc --prune=now
谨慎使用 --prune=now。它可能会删除 git reflog 可能帮助你找到的恢复点。在复杂的变基、分支删除或重置操作后,除非你确定不再需要旧对象,否则避免使用它。
谨慎使用 --aggressive
git gc --aggressive 告诉 Git 花费更多 CPU 时间来优化对象打包:
git gc --aggressive
它并非神奇的加速按钮。在许多仓库中,与常规 git gc 相比,额外的工作带来的收益很小,而且在大型历史记录上可能需要很长时间。仅在你测量到确实存在仓库大小或性能问题,并且能够承担维护窗口期时使用它。
对于日常工作,优先使用普通的 git gc。如果你的仓库经常需要激进清理,深层问题通常是大型文件、生成的产物,或产生大量不可达历史的工作流程。
使用现代 Git 维护进行持续管理
近期的 Git 版本包含 git maintenance,可以根据你的平台和配置安排后台任务,如预取、提交图更新和增量重新打包。
要运行一次维护:
git maintenance run
要为你的用户账户启用定期维护:
git maintenance start
在自动化中依赖定期维护之前,请检查你的 Git 版本和本地文档,因为具体的调度器集成因操作系统和 Git 构建而异。
实用的清理工作流程
本地仓库的安全清理流程如下:
git status
git count-objects -vH
git gc
git count-objects -vH
确保在维护前工作树是干净的。Git 可以在存在本地更改的情况下运行垃圾回收,但干净的工作树可以在后续排查问题时消除疑虑。
对于服务器上的共享裸仓库,请在安静时段安排维护。避免在 CI 活动高峰期执行繁重的重新打包,因为克隆、获取和推送操作可能会竞争磁盘和 CPU 资源。
垃圾回收无法解决的问题
垃圾回收无法解决所有 Git 仓库缓慢的问题。它不会删除历史记录中仍然可达的文件。如果活跃历史记录确实包含多年的大型资源,它无法让单体仓库变小。它本身也无法修复损坏的仓库。
如果正常清理后性能仍然不佳,请检查以下原因:
- 直接提交到 Git 的大型二进制文件。
- 仓库中跟踪了太多生成的文件。
- 防病毒软件或文件系统索引在每次操作时扫描
.git。 - 托管工作树的慢速网络存储。
- 非常大的工作树,此时稀疏检出可能有所帮助。
将 git gc 作为维护工具,而不是仓库卫生的替代品。当对象数量增长时运行正常清理,除非你测量到需求,否则避免激进清理,并将大型跟踪工件视为需要从源头解决的工作流程问题。