什么是 git gc
?
gc
= Garbage Collection
= 垃圾回收
git gc
用于整理 Git 仓库资源,减少仓库体积。
它的核心作用是将大量松散对象 (Loose Objects)压缩为pack 文件,从而提升存储和索引效率。
objects目录
Git 中的每个对象(包括 tree、blob、commit、tag)都会被序列化
- 使用双向摘要算法生成唯一Hash值
然后为序列化后的内容,生成唯一SHA-1 哈希值(索引)
Git 对象包括:
-
blob:存储文件的内容
-
tree:存储目录结构
- 一个tree对象表示当前目录和目录下的文件和子目录
- 子目录又是另一个 tree对象对应的目录索引
- 通过拼接这些对象,可以还原目录结构
-
commit:存储一次提交的信息(如作者、提交信息、指向的 tree 和父 commit 等)
-
tag:存储标签信息
.git/objects
目录下会有许多以两位十六进制命名的子目录。每个子目录中包含文件,这些文件的文件名是剩余的38位十六进制字符。子目录名和文件名拼接在一起,组成完整的 SHA-1 哈希值。
bash
# 存在目录 02
cat 02 # 3b8b53a06506ea46dd954af6149697816cfcbf
# 则实际 SHA-1 是 023b8b53a06506ea46dd954af6149697816cfcbf
refs 目录
.git/refs
目录用于存储 标签、分支等相关信息
进入 .git/refs
目录,可以看到三个重要子目录:
heads
:本地分支remotes
:远程分支tags
:标签
heads(本地分支)
里面每个文件名对应一个本地分支
diff
total 16
drwxr-xr-x@ 4 klaus staff 128B 8 26 16:49 .
drwxr-xr-x@ 5 klaus staff 160B 8 25 00:24 ..
-rw-r--r--@ 1 klaus staff 41B 8 26 16:49 dev
-rw-r--r--@ 1 klaus staff 41B 8 24 23:58 main
文件内容为该分支最新提交的 SHA-1 哈希值
bash
cat main # 8a935ca1991f4e28c6d63e2fc8248e19a09cc452
remotes(远程分支)
目录下有远程仓库别名(如 origin)
kotlin
total 0
drwxr-xr-x@ 3 klaus staff 96B 8 25 00:24 .
drwxr-xr-x@ 5 klaus staff 160B 8 25 00:24 ..
drwxr-xr-x@ 5 klaus staff 160B 8 27 02:22 origin
仓库别名里面是远程分支名和 HEAD 文件
diff
total 24
drwxr-xr-x@ 5 klaus staff 160B 8 27 02:22 .
drwxr-xr-x@ 3 klaus staff 96B 8 25 00:24 ..
-rw-r--r--@ 1 klaus staff 41B 8 26 16:51 dev
-rw-r--r--@ 1 klaus staff 30B 8 25 00:25 HEAD
-rw-r--r--@ 1 klaus staff 41B 8 25 00:24 main
对应的文件内容如下
HEAD
⇒ 远程仓库主分支- 远程分支名 ⇒ 内容同样是 SHA-1 或引用
bash
cat HEAD # ref: refs/remotes/origin/main
cat main # 8a935ca1991f4e28c6d63e2fc8248e19a09cc452
tags(标签)
进入 tags
目录,会发现每个标签对应一个文件
diff
total 16
drwxr-xr-x@ 4 klaus staff 128B 8 27 02:32 .
drwxr-xr-x@ 5 klaus staff 160B 8 25 00:24 ..
-rw-r--r--@ 1 klaus staff 41B 8 27 02:30 v1.0
-rw-r--r--@ 1 klaus staff 41B 8 27 02:32 v1.1
对应的文件内容是
-
如果是轻量级标签 ⇒ 文件值是 最新提交ID
-
如果是带注释标签 ⇒ 文件值是 标签对象对应的SHA-1索引
⇒ 标签对象存在属性描述注释,也存在属性通过 SHA-1索引找到最新提交节点
执行 git gc
后发生了什么?
此时我们在项目工作目录执行 git gc
此时再依次查看 heads
、remotes
、tags
会发现,除了remotes
还存在一个 origin/head
其余文件都消失了,其实他们都被压缩了
此时回到 .git
目录,查看后会发现多了一个目录 packed-refs
,这是一个压缩文件
如果此时我们执行 cat packed-refs
bash
# pack-refs with: peeled fully-peeled sorted
5e76ca292f3844a7a455ab9d11e3ee405e579171 refs/heads/dev
8a935ca1991f4e28c6d63e2fc8248e19a09cc452 refs/heads/main
5e76ca292f3844a7a455ab9d11e3ee405e579171 refs/remotes/origin/dev
8a935ca1991f4e28c6d63e2fc8248e19a09cc452 refs/remotes/origin/main
5e76ca292f3844a7a455ab9d11e3ee405e579171 refs/tags/v1.0
# 提交对象SHA-1 refs/tags/注释名
# ^带注释标签实际对应的提交对象的SHA-1索引
69cd0e5bfdec620cb878b19137ad52122ebf7b39 refs/tags/v1.1
^5e76ca292f3844a7a455ab9d11e3ee405e579171
这个文件里面包含了之前refs目录下的所有SHA-1值,相当于把分散的文件打包成一个压缩文件。
其实简单来说就是原本SHA-1索引存在于各个文件中,执行git gc
后被整合到一个文件中了
这样即减少了文件存储数量,也提高了索引效率
一般情况下, git gc
是 git底层帮我们调用的,如果项目过大,我们也可以手动进行调用