第 6 章 · 01 对象模型:内容寻址存储


文档摘要

第 6 章 · 01 对象模型:内容寻址存储 本节摘要:这是第 6 章的地基。Git 最优雅、最核心的设计是它的「对象模型」——所有数据都存成「对象」,每个对象用「内容的 SHA1 哈希」作为键。这叫「内容寻址存储」:相同内容得到相同哈希(键),天然去重、天然校验。本节讲清四类对象(blob 文件内容、tree 目录结构、commit 快照、tag 标签),以及为什么 Git 用快照而非差异存历史。理解对象模型,Git 的所有命令都是它的自然推论。 内容来源:基于「Build your own X」Git 域与 Git 内部模型整理的导读。 学习目标 阅读完本节,你应当能够: 说清「内容寻址存储」:用内容哈希做键,相同内容得相同键。

第 6 章 · 01 对象模型:内容寻址存储

本节摘要:这是第 6 章的地基。Git 最优雅、最核心的设计是它的「对象模型」——所有数据都存成「对象」,每个对象用「内容的 SHA1 哈希」作为键。这叫「内容寻址存储」:相同内容得到相同哈希(键),天然去重、天然校验。本节讲清四类对象(blob 文件内容、tree 目录结构、commit 快照、tag 标签),以及为什么 Git 用快照而非差异存历史。理解对象模型,Git 的所有命令都是它的自然推论。

内容来源:基于「Build your own X」Git 域与 Git 内部模型整理的导读。

学习目标

阅读完本节,你应当能够:

  1. 说清「内容寻址存储」:用内容哈希做键,相同内容得相同键。
  2. 列举 Git 四类对象:blob、tree、commit、tag,各自存什么。
  3. 解释为什么 Git 用快照(每次完整状态)而非差异存历史。
  4. 理解哈希作为键的好处:去重、校验、不可变。

一、学习价值:对象模型是 Git 的灵魂

无数人用 Git 几年,仍说不出「commit 到底存了什么」「分支是什么」。根因是没理解 Git 的对象模型——而它其实是 Git 最优雅的部分。一旦你理解「Git 是一个内容寻址的对象数据库,所有命令都是在这个数据库上读写对象」,git add/commit/branch/log 全部豁然开朗。

本节建立这个心智模型,后续四节(add、commit、分支、合并)都是它的展开。

二、子系统拆解:四类对象

内容寻址存储

传统文件系统用「文件名」做键(你给文件起名)。Git 用「内容的 SHA1 哈希」做键:

内容 "Hello, world!" → SHA1 = 943a... 这个对象存进 .git/objects/94/3a...(哈希前两位做目录) 键 = 哈希, 值 = 内容

好处:

  • 去重:相同内容哈希相同,只存一份。
  • 校验:哈希天然是校验和,数据损坏立刻发现。
  • 不可变:对象一旦存入,永不修改(修改产生新哈希=新对象)。

四类对象

1. blob(文件内容)
存文件的内容字节流,不含文件名

blob: "Hello, world!" 哈希: 943a...

2. tree(目录结构)
存一个目录:它的「文件名 → blob 哈希」映射,以及子目录 → 子 tree 哈希。

tree: README.md → blob aaa1...(内容哈希) src/ → tree bbb2...(子目录的 tree 哈希)

3. commit(提交快照)
存「一次提交」:指向一个顶层 tree(项目根)+ 父 commit(可能多个,合并产生)+ 作者/时间/信息。

commit: tree: ccc3...(项目根的 tree 哈希) parent: ddd4...(上一次 commit) author: alice <...> message: "fix bug"

4. tag(标签,可选)
带标注的指向某个 commit 的引用。

为什么用快照而非差异

很多人误以为「Git 存的是相对上次的差异」(像某些 VCS)。其实 Git 存的是每次 commit 时的完整快照——commit 指向的 tree 描述「这次提交时整个项目的状态」。

commit3 (tree: 描述现在的全部文件) │ parent commit2 (tree: 描述上次的全部文件) │ parent commit1 (tree: 描述最初的全部文件)

如果某文件两次 commit 间没变,它的 blob 哈希相同,两个 tree 都指向同一个 blob——内容寻址天然去重,「存完整快照」并不浪费空间(不变的部分共享)。这就是为什么 Git 切分支这么快(分支只是指针,快照已存在)、为什么历史是快照链而非差异链。

三、上手第一步:实现对象存储

  1. hash_object(类型, 内容):算 SHA1,存到 .git/objects/
  2. read_object(哈希):按哈希取出对象。
  3. 验证:存两个相同内容,确认哈希相同(去重);改一个字,哈希变(不可变)。

本节要点回顾

  1. 内容寻址存储:键 = 内容的 SHA1 哈希;相同内容相同键,去重 + 校验 + 不可变。
  2. 四类对象:blob(文件内容,无文件名)、tree(目录:文件名→blob 哈希)、commit(tree+parent+信息)、tag。
  3. Git 存快照不存差异:每次 commit 是完整项目状态;内容寻址去重,不浪费空间。
  4. 这是 Git 的灵魂:理解对象模型,add/commit/branch 全部豁然开朗。

推荐上手顺序

  1. 实现 hash_object/read_object(存取对象)。
  2. 手动构造几个 blob/tree/commit,理解它们的引用关系。
  3. git cat-file -p 哈希 在真实 Git 仓库里看对象,对照你的实现。
  4. 进入下一节(add),看「工作区文件如何变成 blob」。

下一节讲索引与 staging——git add 到底干了什么。


发布者: 作者: 灏天文库 转发
评论区 (0)
U