Skip to content

打包与垃圾回收

Git 会随着使用积累大量对象文件。打包和垃圾回收机制帮助优化存储效率,保持仓库健康。

git gc 垃圾回收

git gc(Garbage Collect)是 Git 的维护命令,执行多个优化操作:

bash
# 执行垃圾回收
git gc

# 更激进的清理
git gc --aggressive

# 安静模式(不显示进度)
git gc -q

# 立即清理(不等待过期时间)
git gc --prune=now

git gc 执行的操作:

  1. 压缩松散对象为打包对象(pack files)
  2. 清理不可达的对象(超过保留期限的)
  3. 清理过期的 reflog 记录
  4. 打包引用(pack-refs)
  5. 清理临时文件

Git 也会自动触发 gc:

  • 当松散对象超过 6700 个(gc.auto 配置)
  • 当 pack 文件超过 50 个(gc.autoPackLimit
  • 执行 git push 时(在远程端)

git prune 清理不可达对象

git prune 清理不可达的对象(没有任何引用指向的对象):

bash
# 清理不可达对象(默认保留 2 周内的对象)
git prune

# 立即清理所有不可达对象(谨慎!)
git prune --expire=now

# 预览哪些对象会被清理(不实际执行)
git prune -n
git prune --dry-run

# 详细输出
git prune -v

什么是不可达对象:

  • 被 reset 丢弃的提交(reflog 过期后)
  • 被 rebase 重写的旧提交
  • 被 amend 替换的旧提交
  • 未完成的合并产生的临时对象

打包文件(.pack / .idx)

Pack 文件结构

.git/objects/pack/
├── pack-abc123.idx    ← 索引文件:存储 SHA-1 到 pack 内偏移量的映射
└── pack-abc123.pack   ← 数据文件:所有对象的压缩数据

Pack 文件的优化原理:

松散对象(低效):
Commit A: 完整快照(5MB)
Commit B: 完整快照(5.1MB)  ← 只比 A 多 0.1MB,但存了 5.1MB

Pack 文件(高效):
Commit B: 完整快照(5.1MB)
Commit A: delta(B 与 A 的差异)(0.1MB)  ← 大量节省空间

Git 选择相似度高的对象作为 delta 基准,而不一定是"较新版本存 delta"。实际上,通常存储最近版本的完整对象,旧版本存差异(因为最新版本最频繁访问)。

手动操作 Pack 文件

bash
# 手动创建 pack 文件
git pack-objects .git/objects/pack/pack << 'EOF'
abc123
def456
ghi789
EOF

# 对所有对象重新打包(激进优化)
git repack -a -d -f --depth=250 --window=250

# -a:将所有对象打包(包括已有 pack 中的)
# -d:删除旧的 pack 文件
# -f:强制重打包
# --depth:delta 链的最大深度
# --window:计算 delta 时比较的窗口大小

git verify-pack 查看打包内容

bash
# 查看 pack 文件中的对象列表
git verify-pack -v .git/objects/pack/pack-abc123.idx

# 输出格式:
# SHA-1 类型 大小 压缩大小 [偏移量 [delta基准SHA-1]]
# abc123 commit 423 290 12
# def456 blob   102400 1024 302  ghi789  ← delta 对象

# 按大小排序,找出最大的对象
git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -20

git count-objects 统计对象

bash
# 简单统计
git count-objects
# 42 objects, 1024 kilobytes

# 详细统计
git count-objects -v
# count: 42
# size: 1024
# in-pack: 1500
# packs: 3
# size-pack: 2048
# prune-packable: 0
# garbage: 0
# size-garbage: 0

# 以 MB 为单位显示
git count-objects -v -H

git maintenance 自动维护(Git 2.31+)

新版 Git 提供了更现代的维护机制:

bash
# 启动后台自动维护
git maintenance start

# 停止自动维护
git maintenance stop

# 手动运行维护(所有任务)
git maintenance run --auto

# 运行特定任务
git maintenance run --task=gc
git maintenance run --task=commit-graph
git maintenance run --task=prefetch
git maintenance run --task=loose-objects
git maintenance run --task=incremental-repack

自动维护的任务:

  • loose-objects:将松散对象打包
  • incremental-repack:增量重打包
  • commit-graph:更新提交图(加速 git log 等操作)
  • prefetch:后台预获取远程更新
  • gc:完整的垃圾回收

仓库健康检查

bash
# 检查对象完整性
git fsck

# 详细检查
git fsck --full --strict

# 输出示例(有问题时):
# error: object file .git/objects/ab/cd... is empty
# error: sha1 mismatch ab...
# dangling blob abc123  ← 不可达但未过期的对象
# dangling commit def456

常见问题处理:

bash
# 修复损坏的对象(通常需要从备份或远程恢复)
git fsck --full
git fetch --all
git gc --prune=now

# 完整恢复流程
git remote -v
git fetch origin
# 从远程重新克隆(极端情况)
cd ..
git clone <url> repo-recovered

总结

操作命令效果
垃圾回收git gc打包、清理、优化
清理不可达对象git prune删除孤立对象
查看 pack 内容git verify-pack -v分析 pack 文件
统计对象git count-objects -v查看存储使用
启动自动维护git maintenance start后台定期维护
仓库健康检查git fsck验证数据完整性

定期执行 git gc 或启用自动维护,可以保持仓库高效运行,特别是对于历史悠久、活跃度高的大型仓库。