第 6 章 · 03 提交与快照:`git commit` 的真相


文档摘要

第 6 章 · 03 提交与快照: 的真相 本节摘要:上一节讲了 add 把文件登记进索引(草稿),这一节讲 commit——把草稿定稿。 干三件事:把当前索引建成一棵 tree 对象(项目根的完整快照)、创建一个 commit 对象(指向这棵 tree + 父 commit + 信息)、移动当前分支指针到新 commit。理解这三步,你就理解「commit 是一次项目状态的不可变快照」,以及为什么 Git 历史是一条「快照链」。 内容来源:基于 Git 内部模型整理的导读。 学习目标 阅读完本节,你应当能够: 说清 的三步:建 tree、建 commit、移分支指针。 理解 tree 对象如何从索引构造(项目根的完整快照)。 解释 commit 的「父指针」如何把历史串成一条链。

第 6 章 · 03 提交与快照:git commit 的真相

本节摘要:上一节讲了 add 把文件登记进索引(草稿),这一节讲 commit——把草稿定稿。git commit 干三件事:把当前索引建成一棵 tree 对象(项目根的完整快照)、创建一个 commit 对象(指向这棵 tree + 父 commit + 信息)、移动当前分支指针到新 commit。理解这三步,你就理解「commit 是一次项目状态的不可变快照」,以及为什么 Git 历史是一条「快照链」。

内容来源:基于 Git 内部模型整理的导读。

学习目标

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

  1. 说清 git commit 的三步:建 tree、建 commit、移分支指针。
  2. 理解 tree 对象如何从索引构造(项目根的完整快照)。
  3. 解释 commit 的「父指针」如何把历史串成一条链。
  4. 实现基础的 commit 与 log。

一、学习价值:commit 是 Git 历史的原子单元

commit 是 Git 历史的基本单元——每次 commit 是「项目在某一刻的完整状态 + 指向上一状态的指针」。理解 commit 的结构,你就理解:

  • 为什么 Git 历史不可篡改(改历史 = 创建新 commit 链)。
  • 为什么 git log 能回溯历史(沿父指针)。
  • 为什么分支合并会产生多父 commit(每个父是一条支线)。

二、子系统拆解:commit 的三步

第 1 步:从索引构建 tree

索引是扁平的「文件名→blob 哈希」列表。commit 时,要把它组织成「层次化的 tree 结构」(目录树):

索引(扁平): { "README.md": blob1, "src/main.py": blob2, "src/util.py": blob3 } 构建 tree(层次): 根 tree: "README.md" → blob1 "src" → 子 tree: "main.py" → blob2 "util.py" → blob3

把扁平路径按 / 切分,递归构建嵌套的 tree 对象。每个 tree 对象算哈希、存对象库。

第 2 步:创建 commit 对象

commit: tree: <根tree哈希> # 这次提交的项目状态 parent: <上次commit哈希> # 父(可能多个, 合并时) author/committer: 名字 <邮箱> 时间 message: "提交信息"

commit 对象算哈希、存对象库。它的核心是「一个 tree(状态)+ 一个或多个 parent(历史链)」。

第 3 步:移动当前分支指针

Git 的「当前分支」是个指针(存在 .git/HEAD 指向分支、分支文件指向 commit)。commit 后,把当前分支指针移到新 commit:

commit 前: main → commit2 commit 后: main → commit3(新), commit3.parent → commit2

这就是为什么「分支只是一个指针」——它指向某个 commit,commit 后指针前移。

历史是一条快照链

commit3 (tree: 现在状态) → parent → commit2 (tree: 上次状态) → parent → commit1 (tree: 初始状态)

每个 commit 持有完整状态(tree),父指针把它们串成链。git log 就是沿父指针从当前 commit 一直回溯。历史不可篡改——改任何 commit 都会产生新哈希(新对象),原链路不变。

三、上手第一步:实现 commit 与 log

  1. commit:从索引建 tree(递归按目录组织)→ 建 commit 对象(指 tree + parent 当前分支指向的 commit)→ 移动分支指针。
  2. log:从当前 commit 出发,沿 parent 不断回溯,打印每个 commit 信息。
  3. 验证:几次 commit 后 log 能看到完整链。

本节要点回顾

  1. commit 三步:从索引建根 tree(项目完整快照)→ 建 commit 对象(tree + parent + 信息)→ 移当前分支指针。
  2. tree 是层次化的:把扁平索引按目录组织成嵌套 tree。
  3. parent 把历史串成链:每个 commit 指向父,log 沿父回溯。
  4. 分支只是指向 commit 的指针,commit 后指针前移——这就是「分支」的全部真相。
  5. 历史不可篡改:改任何 commit 产生新哈希,原链不变。

推荐上手顺序

  1. 实现「扁平索引 → 嵌套 tree」的构建(按路径切分递归)。
  2. 实现 commit:建 tree + 建 commit + 移分支指针。
  3. 实现 log:沿 parent 回溯打印。
  4. 多次 commit,用 log 验证历史链。

下一节讲分支与 HEAD——本质都是指针。


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