仓库用久了,松散对象堆积、info/packs
过时、reflog 过长——git gc(garbage collect)是
Git
自带的磁盘整理入口。它不等于「删除历史」,而是
repack 对象、修剪过期 reflog、可选 prune
不可达松散对象。搞清 gc 改写了哪些路径,才能解释「gc
后仓库变小」或「gc 跑很久」。
一、git gc 做什么
默认 git gc
大致包括(版本与配置略有差异):
- repack:把松散对象打入
pack(
git repack -d -l一类组合)。 - prune:删除已被 pack
收录且可安全删除的松散对象;
--prune=now立即执行而非延迟。 - reflog 过期:删除超过
gc.reflogExpire的条目。 - 松散不可达对象:prune 悬空对象(无 ref/reflog 指向)。
- 更新
objects/info/packs、可能写 bitmap / commit-graph(配置开启时)。
记录文件:.git/gc.log(若存在)记载上次 gc
时间。
二、count-objects 字段
git count-objects -v实测(repack 后、gc 前,Git 2.54.0):
count: 0
size: 0
in-pack: 3
packs: 1
size-pack: 1
prune-packable: 0
garbage: 0
size-garbage: 0
| 字段 | 含义 |
|---|---|
count / size |
松散对象个数与 KB |
in-pack / size-pack |
pack 内对象数与 pack 体积 |
packs |
pack 文件个数 |
prune-packable |
已在 pack 中、可 prune 的松散对象数 |
garbage |
损坏或异常对象 |
git gc --prune=now 后松散
objects/xx/ 通常清空,仅留
objects/pack/ 与
objects/info/。
三、info/packs
objects/info/packs 列出本仓库使用的 pack
及顺序,例如:
P pack-8f8a6ea89a77b5e25da24dc54481874c20bbcc7a.pack
读取对象时 Git 按此清单定位 pack。repack 合并多个 pack 为一个后,此文件被重写。
四、何时需要手动 gc
- 大量 fetch/推送后松散对象暴涨。
- CI 浅克隆服务器磁盘紧张。
git count-objects -v显示prune-packable很大。
注意:gc 会占用 CPU 与
IO;大仓库应在低峰跑。git repack -Ad 比默认 gc
更激进(单 pack),耗时更长。
五、与可达性
prune 删除的是不可达对象:无 ref、无 reflog、无 stash 等引用能 walk 到的 commit/tree/blob。仍被 reflog 指向的「孤立」提交在 reflog 过期前不会被 prune——见 reflog 与 fsck。
六、本文边界
- 不列
git config gc.*全集。 - 不讨论托管平台自动 gc 策略。
复现:
git count-objects -v
git gc --prune=now
find .git/objects -type f | sort参考资料
- Git documentation,
git-gcmanual page - Git documentation, gitrepository-layout
- 实验环境:Git 2.54.0
系列索引:Git 内部结构 · 上篇:commit-graph · 下篇:fsck
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【Git 内部】.git 目录全景:三棵树与仓库布局
git init 之后 .git 里每个路径干什么?对照 gitrepository-layout 与本地 find 清单,建立 bare/non-bare、三棵树、objects/refs/index 的磁盘级地图。
【Git 内部】松散对象:zlib 载荷与 SHA-1 路径
blob/tree/commit 在磁盘上如何编码?对象头 type size、zlib 压缩、objects/ab/cdef 路径命名,对照 git hash-object 与手工 SHA-1 验证。
【Git 内部】对象图:tree、commit、tag 的链式结构
一次提交在对象库里如何连成链?tree 条目 mode/name/hash、commit 的 tree/parent 字段、annotated tag,用 git cat-file -p 展开并画对象图。
【Git 内部】refs、HEAD 与 packed-refs
分支和标签在磁盘上只是一行 SHA?refs/heads、符号引用 HEAD、packed-refs 文件头与 peeled tag 的格式与生成时机。