Git 核心概念:三个区域、对象模型与 HEAD

Git 本质是一个内容寻址的文件系统。理解三个区域怎么搬数据、四类对象怎么互相指向、分支与 HEAD 为什么只是指针,绝大多数「Git 为什么这样」都能自己推出来。

最后更新:2026-10-30

Git 命令速查表 → 撤销三件套 → Git 急救手册 →

三句话理解 Git 的内核

理解这三点,绝大多数「Git 为什么这样」都能自己推出来。

三个工作区域

区域存什么相关命令
工作区
Working Tree
你看到的文件,可随意改git status / git diff
暂存区
Index / Staging
下一次提交的快照清单git add / git restore --staged
仓库
Repository(.git)
所有提交与对象,只追加git commit / git log

数据单向流动:工作区 —add→ 暂存区 —commit→ 仓库。反方向用 restore / reset / checkout。

对象模型:四类对象

git cat-file -t <sha>     # 看对象类型
git cat-file -p <sha>     # 看对象内容

内容寻址:同样的内容永远得到同样的哈希。所以相同的两份文件只占一份空间,判断内容是否变化也只需比哈希。

引用与 HEAD

git rev-parse HEAD            # 当前提交
git symbolic-ref HEAD         # 当前分支(detached 时会报错)
cat .git/HEAD                 # 直接看文件内容

暂存区(index)到底是什么

暂存区不是「暂存文件夹」,而是一份待提交的树快照。

理解 index 是快照,就能解释「为什么 add 之后还要再 add」。

三棵树与 diff 的正确用法

命令比较对象
git diff工作区 ↔ 暂存区(还没 add 的改动)
git diff --staged暂存区 ↔ 最后一次提交(准备提交的内容)
git diff HEAD工作区 ↔ 最后一次提交(全部未提交改动)
git diff HEAD~1 HEAD两次提交之间的差异

记住这条线:工作区 — git diff — 暂存区 — git diff --staged — HEAD。

对象存在哪:.git/objects 探秘

git count-objects -vH
git fsck --lost-found        # 找出不可达对象

「Git 丢不了东西」的底气就在这里:只要对象没被 gc,就有机会用 reflog / fsck 找回。

常见问题

为什么 Git 用哈希而不是文件名来标识内容?

内容寻址让比较、去重和完整性校验都变得极廉价:同样内容哈希相同可以自动去重,比哈希就能判断内容是否变化,任何一位损坏都会导致哈希不匹配。文件名会变、会重复,不适合当地址。新版 Git 也支持 SHA-256 仓库格式。

Git 的分支和标签有什么区别?

分支是会移动的指针,每次提交自动前移;标签默认固定指向某个提交,用来标记版本。分支删掉后提交可能变成不可达(可借助 reflog 找回),标签则是给提交起一个稳定别名。

暂存区(index)到底有什么用,能不能跳过?

暂存区是「下一次提交的快照」,让你能挑选性提交(git add -p 只挑部分改动)、提交前预览(git diff --staged)。可以跳过:git commit -a 会跳过 add 直接提交已跟踪文件,git commit <file> 直接提交指定文件;但要做精细的提交拆分,index 是核心工具。