对象库里的 commit 只有 SHA,人类可读的
master、v1.0
来自引用(ref):.git/refs/
下的文本文件,或合并进 packed-refs
的一行记录。HEAD
则是「当前检出位置」的特殊引用。搞不清 ref
文件格式,就无法理解 detached HEAD、远程跟踪分支
refs/remotes/origin/main 从哪来。
本文说明 ref 的磁盘表示、git pack-refs 后的
packed-refs 格式,以及 peeled annotated tag 的
^ 后缀。reflog 在 第 05 篇。
一、引用是什么
引用是指向对象 ID 的命名指针。规则(gitrepository-layout):
- 普通 ref 文件:纯文本,内容为 40 字符十六进制 SHA-1(或 64 字符 SHA-256),末尾可选换行。
- 符号引用:内容为
ref: <path>,指向另一个 ref 文件。
示例:refs/heads/master 在一次提交后:
2b24b26a117ef5cfdbf88040e282ec86085e6b1f
git rev-parse master
读的就是这个文件(或通过 packed-refs
解析)。
二、HEAD:符号引用与 detached
初始 HEAD:
ref: refs/heads/master
git checkout 到某分支时,HEAD
仍常为符号引用,指向
refs/heads/<branch>。
git checkout <commit-sha> 进入
detached HEAD:HEAD 直接写
SHA,不再是 ref:
行。此时新提交若无分支指向,reflog 仍可找回(第 05 篇),但
refs/heads/* 不会自动前进。
三、refs 目录布局
| 路径 | 含义 |
|---|---|
refs/heads/<name> |
本地分支 tip |
refs/tags/<name> |
标签(轻量或指向 tag 对象) |
refs/remotes/<remote>/<branch> |
远程跟踪分支 |
refs/stash |
git stash 栈(特殊 ref) |
git show-ref 列出解析后的 ref 与 SHA。fetch
更新 refs/remotes/…;push 更新远端服务器上的
refs(本机不自动改 remote 以外的分支,除非配置跟踪)。
四、packed-refs
引用文件过多时,每次解析都要打开大量小文件。git pack-refs --all
把可打包的 ref 合并到
.git/packed-refs,并删除已打包的松散 ref
文件(HEAD 等符号引用除外)。
实测 packed-refs 内容(Git 2.54.0):
# pack-refs with: peeled fully-peeled sorted
2b24b26a117ef5cfdbf88040e282ec86085e6b1f refs/heads/master
| 部分 | 含义 |
|---|---|
首行 # pack-refs with: … |
元数据:是否 peeled、排序方式 |
| 后续行 | <sha> <refname> |
行首 ^ |
annotated tag 被 peel 后的 peeled object SHA |
查找顺序:先读松散 refs/… 文件;不存在再查
packed-refs。松散文件覆盖
packed 中同名 ref(用于正在更新的引用)。
五、轻量标签与附注标签
- 轻量:
refs/tags/v1.0内容为 commit SHA。 - 附注:内容为 tag 对象
SHA;
git show-ref --tags -d可显示 peel 后的 commit。
packed-refs 的 peeled 选项会在
tag 行后追加 ^<commit-sha>,避免每次访问
tag 再解 tag 对象。
六、本文边界
复现:
git pack-refs --all
cat .git/packed-refs
ls .git/refs/heads/ # 分支 ref 可能已被移除参考资料
- Git documentation, gitrepository-layout
git pack-refsmanual page- 实验环境:Git 2.54.0
系列索引:Git 内部结构 · 上篇:对象图 · 下篇:reflog
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【Git 内部】.git 目录全景:三棵树与仓库布局
git init 之后 .git 里每个路径干什么?对照 gitrepository-layout 与本地 find 清单,建立 bare/non-bare、三棵树、objects/refs/index 的磁盘级地图。
【Git 内部】对象图:tree、commit、tag 的链式结构
一次提交在对象库里如何连成链?tree 条目 mode/name/hash、commit 的 tree/parent 字段、annotated tag,用 git cat-file -p 展开并画对象图。
【Git 内部】Git 内部结构:对象库与磁盘文件格式
从 .git 目录布局、松散对象与 packfile 格式,到 refs、index、reflog、gc/fsck 与 fetch/push 落地——用官方 format 文档与本地实测 dump 系统讲清 Git 把版本历史存在哪、每个命令改写了哪些文件。全 16 篇。
【Git 内部】松散对象:zlib 载荷与 SHA-1 路径
blob/tree/commit 在磁盘上如何编码?对象头 type size、zlib 压缩、objects/ab/cdef 路径命名,对照 git hash-object 与手工 SHA-1 验证。