7、Git工作区与暂存区:工作区、暂存区、版本库关系、git add原理、git commit原理

说实话,我刚用Git那会儿,最困惑的就是这三个区域到底怎么玩的。工作区、暂存区、版本库,听起来像三个黑盒子。后来我踩了不少坑,才真正搞明白它们之间的关系。今天我就用最直白的方式,把这块讲透。

7.1 三个区域,一张图说清楚

先看这张图,我亲手画的。你盯着看30秒,基本就懂了。

Git 三大核心区域关系图 工作区 你写代码的地方 实际文件目录 暂存区 准备提交的变更 .git/index 文件 版本库 历史记录仓库 .git/objects 目录 git add git commit git checkout / git reset --hard 💡 核心要点: 1. 工作区是你眼睛看到的文件,暂存区是「待提交清单」 2. git add 把变更从工作区→暂存区(拍照存底) 3. git commit 把暂存区内容→版本库(永久存档) 4. 只有版本库里的数据,才算真正「安全」了

嗯,这张图我建议你保存下来。每次搞混了就拿出来看一眼。

7.2 工作区:你眼睛看到的文件

工作区,说白了就是你电脑上那个项目文件夹。你打开VS Code、Sublime或者记事本,看到的那些.py.js.md文件,全都在工作区里。

我举个例子。你新建一个项目,里面有个index.html。你改了它,保存了。这时候变化只发生在工作区。Git知道吗?知道。但Git不会自动帮你记录。

关键认知:工作区是「未受Git管理」的区域。你在这里改得翻天覆地,Git也只是默默看着,不会做任何记录。

7.3 暂存区:一个神奇的中间地带

暂存区,英文叫Staging Area,也有人叫Index。它其实就是一个文件,藏在.git/index里。但你别小看它,它是Git设计里最精妙的地方之一。

我个人习惯把暂存区理解成「购物车」。你去超市买东西,看到好的先放购物车里,最后到收银台统一结账。暂存区就是这个购物车——你先git add把文件放进去,最后git commit一次性结账。

我的经验:我刚开始用Git时,总是一次性git add .把所有文件都扔进去。后来发现这样不好。比如你改了A文件(功能代码)和B文件(调试日志),应该分开add、分开commit。这样以后查历史记录时,每个commit的意图才清晰。

7.4 版本库:Git的心脏

版本库就是.git目录里的那一堆东西。你所有提交的历史、所有的分支、所有的标签,全存在这里。它才是Git真正「记住」你的地方。

我记得有一次,同事不小心删了工作区里的文件,急得满头大汗。我说别慌,只要commit过,版本库里就有备份。果然,一个git checkout就全回来了。这就是版本库的价值——它是你的后悔药。

区域 位置 数据安全性 是否被Git跟踪
工作区 项目根目录 低(可被删除) 否(未add前)
暂存区 .git/index 中(可被覆盖) 是(已add后)
版本库 .git/objects 高(不可变) 是(已commit后)

7.5 git add 原理:到底发生了什么?

很多人以为git add就是把文件「复制」到暂存区。其实不是。Git没那么笨,它不会复制整个文件。

git add真正做的事情是:

  1. 计算文件的SHA-1哈希值(一个40位的十六进制字符串)
  2. 把文件内容压缩后存入.git/objects目录
  3. .git/index中记录这个文件的路径、哈希值、修改时间等信息

说白了,git add就是给文件拍了一张「快照」,然后把快照的索引记在暂存区里。文件本身还在工作区,没动。

避坑指南:我曾经犯过一个错——改了文件后忘了git add,直接git commit。结果commit了个寂寞,改的内容根本没进去。记住:git commit只提交暂存区里的内容,工作区里的改动它不管。

7.6 git commit 原理:永久存档

git commit做的事情更简单,但也更关键:

  1. 把暂存区里的所有「快照」打包成一个commit对象
  2. 这个commit对象包含:作者信息、时间戳、提交信息、父commit的哈希值
  3. 把这个commit对象存入.git/objects
  4. 更新当前分支指针,指向这个新commit

你想想看,每次commit,Git都记录了三样东西:什么时候做了什么改动。这就是版本管理的核心。

我的建议:commit信息一定要写清楚。别写什么「fix bug」「update」这种废话。我见过最离谱的commit信息是「111」和「asdf」。三个月后回头看,鬼知道当时改了啥。好的commit信息应该是:「修复用户登录时密码验证失败的bug」——一看就懂。

7.7 三个区域的实战操作

光说不练假把式。我们走一遍实际流程:

# 1. 查看工作区状态
git status

# 2. 把文件加入暂存区
git add index.html
git add src/          # 也可以加整个目录

# 3. 查看暂存区内容
git diff --cached     # 只看暂存区和工作区的差异

# 4. 提交暂存区
git commit -m "添加首页HTML结构"

# 5. 跳过暂存区直接提交(慎用)
git commit -a -m "直接提交所有改动"

警告:git commit -a会跳过暂存区,直接把工作区里所有已跟踪文件的改动提交。新手慎用。我建议你老老实实走add → commit两步,养成好习惯。

7.8 为什么Git要设计暂存区?

你可能会问:为什么不能直接从工作区到版本库?多此一举嘛。

其实不是。暂存区给了你一个「后悔和整理」的空间。比如你改了10个文件,但只想提交其中3个。没有暂存区,你只能要么全提交,要么一个一个提交。有了暂存区,你可以先git add那3个,然后git commit,剩下的7个下次再说。

我个人觉得,这是Git比SVN高明的地方之一。SVN没有暂存区,每次提交都是全量。Git给了你更细粒度的控制权。

一句话总结:工作区是你写代码的地方,暂存区是你挑拣代码的地方,版本库是你保存代码的地方。三个区域各司其职,缺一不可。

好了,这一章就到这里。记住这三个区域的关系,后面的分支、合并、回退操作,你才能玩得转。


公众号:蓝海资料掘金营,微信deep3321