Git Internals
Tree 对象与目录快照教程
说明 tree 对象如何表达目录层级,以及提交为何能表示完整文件树快照。
- 想建立稳定 Git 心智模型的学习者
- 经常遇到历史、引用、恢复问题的开发者
- 会看基础命令输出
- 知道提交、分支、HEAD 这些名词
- 只背底层术语却不连接到实际命令
- 把对象、引用、工作区混成一层理解
一句话理解
如果说 blob 负责“内容本身”,那 tree 负责的就是“这些内容在目录结构里如何组织”。
1. 为什么 tree 很重要
很多人知道 Git 会保存文件内容,但不容易说清楚:
- 一个提交为什么能表示整个项目状态
- Git 是怎么知道某个文件在哪个目录里
- 重命名和移动路径为什么更多像结构变化而不是内容变化
这些问题都要回到 tree。
2. tree 保存的到底是什么
tree 不直接保存文件内容,它保存的是目录条目。每个条目通常包括:
- 名字
- 模式
- 指向哪个 blob 或子 tree
所以可以把 tree 理解成“目录层级快照”。
3. 根 tree 为什么重要
一个 commit 最终会指向一个根 tree。
这个根 tree 再向下连接更多 tree 和 blob,于是就能把“整个项目当前是什么样”表达出来。
这也是 Git 更接近“快照系统”而不是“纯补丁列表”的根本原因。
4. tree 和 blob 的分工
可以把它们这样记:
- blob:文件内容
- tree:目录结构
举个最实用的理解:
- 文件改内容,通常更多影响 blob
- 文件改路径,通常更多影响 tree
- 目录结构变了,本质上一定会影响 tree
5. 为什么 Git 更像保存快照
很多人会把 Git 想成“每次只保存差异”。
从阅读体验上,这样想有时方便;但从对象模型上,更准确的理解是:
- 一个提交会指向一个完整项目快照
- 这个快照由 tree 层级表达
- 底层存储再进一步做对象复用和压缩优化
也就是说,“逻辑上是快照,物理上可以高效复用”。
6. tree 如何帮助你理解常见操作
重命名
如果文件内容没变,只是路径和名字改了,变化重点往往在 tree,而不是 blob。
新增目录
本质上是 tree 层级结构里多了一段新的目录组织。
checkout / switch
它们最终会让工作区去匹配目标提交所指向的 tree 结构。
7. 为什么一个提交能“恢复整个项目”
因为 commit 指向的是根 tree,而根 tree 又把目录和内容全串起来了。
所以 checkout 到某个提交时,Git 不需要靠“从头把所有补丁重放一遍”才能知道项目状态,而是能直接根据那棵 tree 所表达的结构恢复出对应工作区。
常见误区
tree 就是普通文件夹
不准确。tree 是 Git 里的目录结构对象,不是你文件系统里的真实目录实体本身。
Git 只保存修改过的几行
从逻辑表达上,更贴近 Git 本质的说法仍然是“提交表示一个快照”,而 tree 正是快照结构的核心部分。
文件名保存在 blob 里
不是。文件名和路径属于 tree 层。
一个最值得记住的结论
blob 让 Git 知道“内容是什么”,tree 让 Git 知道“这些内容如何组成一个项目”。