土法炼钢兴趣小组的算法知识备份

【Git 内部】Git 内部结构:对象库与磁盘文件格式

文章导航

分类入口
opensource
标签入口
#git#git-internals#packfile#objects#refs#index#reflog#fsck#sha256

目录

Git 内部结构:对象库与磁盘文件格式

git commit 之后,工作区文件看似没变,但 .git 里已经多出了对象、引用和日志。中文资料多讲命令用法,少有一份把「磁盘上到底长了什么」按官方 format 规范讲透的系统性资料。本系列填补这个空白:以 gitrepository-layoutgitformat-* 文档为 A 级主来源,每章用本地仓库 + hexdump / git cat-file / git verify-pack 等真实执行钉住结论。

系列定位:格式规范级拆解,不是 Git 命令教程。如果你只想学 rebase -i,Pro Git 前九章足够;如果你想搞懂 clone 之后 .git 里每个路径的职责、pack delta 在字节里怎么编码、git gc 会删掉哪些松散对象——这是为你写的。

推荐入口

一、这个系列要回答的五个问题

  1. .git 里每个目录/文件职责是什么?工作区、索引、HEAD 与对象库如何对应? 三棵树不是比喻——它们分别对应工作区文件、.git/indexHEAD 指向的 commit tree。bare 仓库没有工作区和 index,但对象库与 refs 布局一致。 → 第 1、2、3 篇。

  2. 分支、标签、HEAD、reflog 在磁盘上长什么样?packed-refs 何时出现? 分支是 refs/heads/<name> 里 40 字节(或 64 字节 SHA-256)的十六进制串;reflog 是 logs/ 下的追加式二进制日志,与 reflog 命令读的是同一份文件。 → 第 4、5 篇。

  3. 松散对象与 packfile 的格式边界在哪?delta 压缩如何体现在字节布局里? 松散对象 = zlib(ASCII 头 + 载荷);pack 把多个对象串进单个文件,相似 blob 可链成 REF_DELTA。git repack 后松散文件可被 prune。 → 第 2、7、8 篇。

  4. git gc / repack / fsck 会改写或删除哪些路径?损坏通常表现为什么? gc 触发 repack、写 info/packs、可选 prune 悬空松散对象;fsck 能检出坏 zlib、哈希不匹配与悬空对象,修复边界因损坏类型而异。 → 第 10、11 篇。

  5. commit/merge/fetch/push 各自触发了哪些文件变化?SHA-256 与 reftable 会改变什么? merge 冲突时 index 出现 stage 2/3 条目,.git 根下出现 MERGE_HEAD;fetch 接收 pack 写入 objects/pack/ 并更新 refs/remotes/;SHA-256 仓库对象 ID 为 64 十六进制字符,路径仍为 objects/xx/...。 → 第 12–14、16 篇。

二、篇目依赖关系与推荐阅读路径

全系列六部分、16 篇。版本锚定 Git 2.45+(本站实验环境 Git 2.54.0);SHA-256 / reftable 在第 16 篇单列并标注实验性边界。

强依赖图

flowchart TD
  A["01 .git layout"] --> B["02 loose objects"]
  B --> C["03 object graph"]
  A --> D["04 refs / packed-refs"]
  D --> E["05 reflog"]
  A --> F["06 index"]
  B --> G["07 pack + idx"]
  G --> H["08 pack-objects delta"]
  G --> I["09 commit-graph / bitmap"]
  H --> J["10 gc / repack"]
  B --> K["11 fsck"]
  D --> L["12 porcelain effects"]
  C --> M["13 merge / rebase files"]
  G --> N["14 fetch / push"]
  A --> O["15 worktree / submodule"]
  B --> P["16 SHA-256 / reftable"]

推荐阅读路径

三、目录与每篇一句话价值

第一部分:磁盘全景与对象基座

  1. .git 目录全景:三棵树与仓库布局 git init 后默认文件清单、bare 与 non-bare 差异、objects/refs/hooks/info 各目录职责——建立后续逐字节读格式的地图。

  2. 松散对象:zlib 载荷与 SHA-1 路径 对象头 type size\0、zlib 压缩、objects/ab/cdef... 命名规则;git hash-object 与手工计算 SHA-1 的对照。

  3. 对象图:tree、commit、tag 的链式结构 tree 条目 mode name hash、commit 的 tree parent author 字段、annotated tag 如何指向 commit——从 git cat-file -p 展开到 Mermaid 对象图。

第二部分:引用与暂存区

  1. refs、HEAD 与 packed-refs refs/heads|tags|remotes 文本格式、符号引用、git pack-refs 后的 packed-refs 文件头与 peeled tag 行。

  2. reflog:logs/ 下的追加式历史 每条 reflog 记录的旧/新 SHA、提交者、时间戳、消息;git refloghexdump -C logs/HEAD 的一一对应。

  3. index 暂存区:dircache v2 与扩展节 DIRC 魔数、条目 stat/SHA/stage、冲突时的 stage 2/3;TREE/REUC 等扩展节的角色。

第三部分:Pack 与可达性加速

  1. pack 与 idx 文件格式 pack 头 PACK、对象类型字节、OFS_DELTA/REF_DELTA 偏移;idx v2 扇区与 git verify-pack -v 输出字段含义。

  2. pack-objects 与 delta 压缩 相似 blob 如何链成长度为 1 的 delta 链;thin pack 与 git repack 窗口启发式(格式视角,不拆 C 源码)。

  3. commit-graph 与 reachability bitmap objects/info/commit-graph 的 generation number;pack 旁路的 .bitmap 文件如何加速 git rev-list(描述机制,不编造未实测倍率)。

第四部分:维护与完整性

  1. gc、repack 与 prune git gc 触发的 repack、info/packs 清单、--prune=now 删除可达 pack 之外的松散对象;git count-objects -v 各字段含义。

  2. fsck:校验规则与损坏形态 坏 zlib、哈希不匹配、悬空对象、dangling commitlost-found 的修复边界——含故意截断松散对象的实测 fsck 输出。

第五部分:命令与协议的文件级落地

  1. 日常 porcelain 命令改写了哪些文件 add→index、commit→objects+refs+logs、checkout→HEAD/index、reset 三种模式各自触及的路径快照对比。

  2. merge/rebase 的临时文件与 index stage MERGE_HEADORIG_HEADCHERRY_PICK_HEADMERGE_MSG;冲突时 git ls-files -u 的 stage 1/2/3。

  3. fetch/push 与 pack 传输落地 smart 协议边界上 pack 如何写入 objects/pack/FETCH_HEADrefs/remotes/shallow 文件与浅克隆的关系。

第六部分:扩展与演进

  1. worktree、submodule 与 alternates 链接工作树的 gitdir: 指针、.git/worktrees/ 清单、.git/modules/ 子模块对象库、info/alternates 共享对象。

  2. SHA-256 对象格式与 reftable 演进 git init --object-format=sha256 下 64 字符对象 ID;reftable 相对 packed-refs 的设计定位与当前默认边界。

四、与其他系列的关联

本站已有系列 与本系列的关系
存储工程 小文件问题、页缓存、fsync——解释松散对象膨胀与 pack 的工程动机;建议先读 小文件问题
开源之道 分布式协作与许可证语境;本系列补对象库磁盘语义
架构百科 IaC 篇 Git 作状态存储时的文件级心智模型

五、承诺与不承诺

承诺

不承诺

延伸阅读

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。


By .