git status
比较的是工作区、索引与 HEAD
三处状态;git add 写入的是
.git/index,不是对象库。index 是二进制
dircache
文件,记录路径、元数据(stat)、对象 SHA 和冲突
stage。读不懂 index,就无法解释 merge
冲突时 git ls-files -u 的三行同名路径。
本文对照 gitformat-index 说明 v2 布局与常见扩展。冲突 stage 在 merge 场景的完整例子见 第 13 篇。
一、文件角色
| 操作 | 对 index 的影响 |
|---|---|
git add |
更新或新增条目,stage=0 |
git commit |
用 index 生成 tree,commit 后通常与 HEAD 一致 |
git checkout |
用目标 tree 重写 index |
| merge 冲突 | 同路径多条目,stage 1/2/3 |
index 不进入对象库;但条目里的 SHA 指向 blob
对象(git add 时创建)。
二、头部与魔数
xxd .git/index 前几行(Git
2.54.0,单文件仓库):
00000000: 4449 5243 0000 0002 0000 0001 6a49 509e DIRC........jIP.
| 偏移 | 内容 |
|---|---|
| 0–3 | 魔数 DIRC |
| 4–7 | 版本号 2(常见为 dircache v2) |
| 8–11 | 条目数 |
其后是每个 index entry 和可选 extensions。
三、index entry 概要
每个条目(简化)包含:
- 路径名(NUL 结尾,8 字节对齐)
ctime/mtime(stat 信息)- 设备、inode、模式、uid、gid、文件大小
- SHA-1(20 字节)对象 ID
- flags:路径长度、stage(冲突时 1–3)、assume-unchanged 等
git ls-files -s 显示 stage 与 SHA:
100644 ce013625030ba8dba906f756967f9e9ca394464a 0 hello.txt
100644 为模式,0 为
stage(正常暂存)。
四、冲突 stage
merge 失败时,同一路径可出现三条:
100644 df967b96… 1 shared.txt
100644 c354fa8c… 2 shared.txt
100644 1de5a387… 3 shared.txt
| stage | 含义 |
|---|---|
| 1 | 共同祖先(base) |
| 2 | 当前分支(ours) |
| 3 | 并入分支(theirs) |
磁盘上即 index 中三条独立 entry,同名不同 stage。
五、扩展节(extensions)
常见扩展(四字 tag + 数据):
| Tag | 作用 |
|---|---|
TREE |
缓存的 tree 对象结构,加速
git write-tree |
REUC |
冲突未合并路径的 stage 信息 |
FSMN |
fsmonitor 令牌,加速 status |
EOIE / IEOT |
条目排序索引,加速查找 |
本实验仓库 index 末尾可见 TREE
扩展(xxd 中出现 TREE
ASCII)。扩展可忽略解析仍能正常用 Git
操作——只有写工具时才需完整实现 gitformat-index。
六、index 与工作区一致性
index 存 stat
用于快速判断工作区是否修改(git status 先 stat
再可能读内容)。git update-index --assume-unchanged
等标志在 flags 里。这与对象库不变性正交:blob 一旦写入
objects,内容不因 index 改变。
七、本文边界
- 不实现完整 entry 解析器代码。
- v4 等新版本字段以官方文档为准,实验环境为 v2。
复现:
git add .
xxd .git/index | head -6
git ls-files -s参考资料
- Git documentation, gitformat-index
- 实验环境:Git 2.54.0
系列索引:Git 内部结构 · 上篇:reflog · 下篇:pack 格式
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【Git 内部】.git 目录全景:三棵树与仓库布局
git init 之后 .git 里每个路径干什么?对照 gitrepository-layout 与本地 find 清单,建立 bare/non-bare、三棵树、objects/refs/index 的磁盘级地图。
【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 验证。
【Git 内部】对象图:tree、commit、tag 的链式结构
一次提交在对象库里如何连成链?tree 条目 mode/name/hash、commit 的 tree/parent 字段、annotated tag,用 git cat-file -p 展开并画对象图。