掌握Git垃圾回收,实现极致性能

了解何时运行git gc、它清理什么内容,以及如何避免在活跃仓库中执行危险的激进清理。

掌握Git垃圾回收,实现极致性能

Git垃圾回收能防止仓库无限积累松散对象、过时不可达提交和低效的包文件。如果你的仓库运行缓慢、占用过多磁盘空间,或者经历了大量变基和分支清理操作,git gc 是你需要了解的首要维护工具之一。

通常你不需要每天运行它。当某些阈值达到时,Git 会在正常命令执行期间自动进行维护。不过,了解它的作用有助于避免两个常见错误:数月忽视臃肿的仓库,或在未了解影响的情况下对共享仓库执行激进清理。

Git垃圾回收的作用

Git 将数据存储为对象:提交、树、二进制大对象和标签。新对象最初可能以松散文件形式存放在 .git/objects/ 下。随着时间的推移,Git 可以将多个对象打包成紧凑的包文件。打包后的对象磁盘利用率更高,Git 扫描速度通常也更快。

git gc 执行多项维护任务,包括:

  • 将松散对象打包成包文件。
  • 在必要时合并现有包文件。
  • 删除足够陈旧的可修剪不可达对象。
  • 清理因中断操作留下的临时文件。
  • 在配置了现代 Git 设置时,更新辅助数据(如提交图文件)。

不可达并不意味着可以立即安全删除。在变基、修改、重置或删除分支后,提交可能变为不可达。Git 通常会为最近不可达的对象保留一段宽限期,以便你有时间通过 git reflog 恢复。

清理前检查仓库大小

首先测量仓库大小,而不是猜测:

git count-objects -vH

有用的字段包括 countsizein-packpackssize-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 作为维护工具,而不是仓库卫生的替代品。当对象数量增长时运行正常清理,除非你测量到需求,否则避免激进清理,并将大型跟踪工件视为需要从源头解决的工作流程问题。