Git 核心原理:三种状态与对象模型

说实话,我刚接触 Git 的时候,也觉得它就是个「高级版 Ctrl+Z」。但用着用着就发现,不理解底层原理,迟早会踩坑。有一次我手滑执行了 git reset --hard,差点把同事三天的代码弄丢……嗯,从那以后,我老老实实把 Git 的对象模型啃了一遍。

这一章,我们就来聊聊 Git 最核心的三个概念:三种状态、对象模型,以及它们怎么串成一条工作流。

Git 的三种状态

你想想看,一个文件在 Git 仓库里,其实可以处于三种状态:

  • 已修改(Modified)——文件改了,但还没告诉 Git 我要记下来。
  • 已暂存(Staged)——我告诉 Git:「这个版本我准备保存了」,但还没真正存进仓库。
  • 已提交(Committed)——文件已经安全地存到了 Git 的本地数据库里。

这三种状态对应着 Git 的三个工作区域:工作目录、暂存区、Git 仓库。我个人习惯把暂存区想象成一个「购物车」——你先挑要买的商品(暂存),最后统一结账(提交)。

核心要点:只有已提交的数据才是真正安全的。已修改和已暂存的数据,一旦丢失就很难恢复。我见过太多人以为 git add 之后就万事大吉了……其实不是。

Git 对象模型:Blob、Tree、Commit

Git 本质上是一个内容寻址文件系统。说白了,它用哈希值(SHA-1)来定位每一个对象。Git 内部有三种核心对象:

对象类型 存储内容 类比
Blob 文件内容(二进制数据) 文件本身,不包含文件名
Tree 目录结构(文件名 + 权限 + 指向 Blob 或子 Tree 的指针) 文件夹清单
Commit 快照信息(指向 Tree + 父 Commit + 作者 + 时间 + 提交信息) 一次「拍照」记录

我举个例子你就明白了。假设你有一个项目,结构是这样的:

project/
├── README.md
└── src/
    └── main.c

当你执行 git add 和 git commit 后,Git 内部会生成:

  • 两个 Blob:分别存储 README.md 和 main.c 的内容。
  • 一个 Tree 对应 src/ 目录,里面记录 main.c 的文件名和它对应的 Blob 哈希。
  • 一个 Tree 对应根目录,里面记录 README.md 和 src/ 子目录。
  • 一个 Commit 指向根目录的 Tree,并记录提交信息、作者和时间。

小技巧:你可以用 git cat-file -p <哈希值> 查看任意 Git 对象的内容。我曾经用这个命令帮同事找回了一个被误删的分支——只要提交还在,数据就丢不了。

Git 的工作流程

理解了三种状态和对象模型,工作流程就顺理成章了。日常开发中,你基本就在这三个区域之间来回切换:

  1. 在工作目录中修改文件——状态变为「已修改」。
  2. 将修改添加到暂存区(git add)——状态变为「已暂存」。
  3. 将暂存区的内容提交到仓库(git commit)——状态变为「已提交」。

这里有个容易混淆的点:git commit 只提交暂存区的内容,不会包含工作目录中未暂存的修改。我刚开始用 Git 时,经常以为改了文件直接提交就行,结果发现提交的版本还是旧的……

避坑指南:我曾经在项目上线前,直接 git commit -a 提交了所有修改,结果把调试用的日志代码也提交上去了。建议养成习惯:先 git status 看看哪些文件变了,再用 git diff 确认改动内容,最后才 git add 和 git commit。

核心逻辑:一张图看懂

下面这张 SVG 图,把 Git 的三种状态、三个区域和对象模型串在了一起。你可以把它当作 Git 的「心法口诀」:

Git 核心原理:三种状态与对象模型 Git 核心原理:三种状态与对象模型 工作目录 已修改 你正在编辑的文件 暂存区 已暂存 准备提交的快照 Git 仓库 已提交 对象数据库 git add git commit git checkout / git switch Git 对象模型 Blob 文件内容 Tree 目录结构 Commit 快照信息 Commit 指向 Tree → Tree 包含 Blob 和子 Tree → 形成完整的版本快照

这张图里,上半部分是三个区域和状态转换,下半部分是 Git 内部的对象模型。你每次 git commit,Git 都会生成一个 Commit 对象,它指向一个 Tree,Tree 又指向若干 Blob 和子 Tree。这就是 Git 为什么能瞬间切换分支——它只是换了一个 Commit 指针而已。

总结一下:Git 的三种状态对应三个工作区域,对象模型是 Git 存储数据的底层机制。理解这两点,你就掌握了 Git 的「内功心法」。后面讲分支、合并、变基,都是在这个基础上展开的。