Git Internals
提交对象、父提交与提交说明教程
说明提交对象如何把 tree、父提交和说明文本连接成历史图。
- 想建立稳定 Git 心智模型的学习者
- 经常遇到历史、引用、恢复问题的开发者
- 会看基础命令输出
- 知道提交、分支、HEAD 这些名词
- 只背底层术语却不连接到实际命令
- 把对象、引用、工作区混成一层理解
一句话理解
commit 对象不是“写一句提交说明”那么简单,它真正做的是把一次项目快照、父子关系和元数据固定成历史节点。
1. 提交对象里至少有什么
一个 commit 对象通常会包含:
- 指向当前快照根 tree 的信息
- 一个或多个父提交
- author / committer 信息
- 提交说明
所以 commit 的价值是把“内容状态”和“历史位置”同时固定下来。
2. 为什么父提交很关键
如果没有 parent,Git 就无法表达历史图。
父提交关系决定了:
- 当前提交是从哪里接出来的
- merge commit 为什么会有多个父节点
- rebase 为什么会生成新的提交对象
你看到的日志线条、分支汇合、祖先关系,本质上都依赖 parent 字段。
3. 提交说明为什么不是附属品
提交说明不仅是给人看的文字,它也是 commit 对象内容的一部分。
这意味着:
- 只改提交说明,提交对象就变了
- 对象一变,提交 ID 也会变
所以 amend message 不是“只改了备注”,而是生成了新的 commit 对象。
4. 为什么 commit ID 会变
因为 commit 对象里保存的不只是 tree,还包括 parent 和 message。
只要以下任一项变化:
- 当前 tree 不同
- parent 不同
- message 不同
- 作者信息不同
commit 对象就不再是同一个对象,ID 也就跟着变化。
5. merge commit 和普通提交有何不同
普通提交大多只有一个父提交。
merge commit 往往有两个父提交。
这意味着 merge commit 不只是“有新的内容状态”,它还在历史结构上明确记录了“两条线在这里汇合”。
6. 为什么这能帮助你理解 rebase
rebase 之所以被称为“改写历史”,不是因为它偷偷改了旧提交,而是因为:
- 新基底变了
- parent 关系变了
- 因而必须生成新的 commit 对象
这就是为什么 rebase 后同样内容的提交,ID 也会不一样。
7. 从 commit 对象角度重新看常见操作
git commit
新增一个 commit 对象,并让当前分支引用移动到它。
git commit --amend
不是给原提交“补充说明”,而是重新生成一个新的 commit 对象来替换当前位置。
git merge
通常会新增一个有多个父提交的 commit。
常见误区
commit 主要就是一段 message
不是。message 只是 commit 对象里最容易被人直接看到的一部分。
amend 不算改写历史
从对象模型上看,算。因为新的 commit 对象已经不是原来那个了。
merge commit 只是把代码合进来
还不止。它也把“两边历史在这里汇合”的结构写进了图里。
一个最值得记住的结论
commit 不是日志条目,而是一个把快照、父链和说明一起固定下来的历史节点。