2、Git核心概念:工作区、暂存区、本地仓库、远程仓库、Git对象模型(blob、tree、commit)
好,咱们正式开始聊Git的核心概念。说实话,很多人用Git好几年,其实也就停留在「add、commit、push」三板斧的阶段。一旦遇到合并冲突或者想回滚某个历史版本,立马就懵了。
我个人习惯是,先把这几个核心概念搞透。你想想看,如果连工作区和暂存区都分不清,那后面谈分支策略就是空中楼阁。今天我就带你把这几个概念彻底捋一遍。
2.1 工作区(Working Directory)
工作区,说白了就是你电脑上能看到的那个文件夹。你写代码、改文件、删文件,全在这里发生。这是你直接和代码打交道的地方。
我记得刚带团队那会儿,有个同事问我:「我明明改了代码,为什么git status看不到?」我过去一看,好家伙,他改的是另一个目录下的文件,根本不在Git仓库里。嗯,这就是没搞懂工作区的边界。
2.2 暂存区(Staging Area / Index)
暂存区这个概念,是Git最巧妙的设计之一。它就像一个「候车室」。你改完代码,先放到候车室(暂存区),检查一遍没问题了,再统一上车(提交到本地仓库)。
为什么要多此一举?我举个例子。你同时改了三个文件,但其中一个还没改完。你可以只把改好的两个文件放到暂存区,先提交。另一个继续改。这种灵活性,SVN那种老古董根本做不到。
我曾经犯过一个低级错误:改了一堆配置文件,直接git commit -m "改配置",结果忘了先add。Git提示「nothing to commit」。当时我还骂Git有bug……后来才明白,是我自己没搞懂暂存区。
2.3 本地仓库(Local Repository)
本地仓库,就是藏在项目根目录下那个.git文件夹。这里面存着你所有的提交历史、分支信息、标签等等。说白了,你的版本控制全靠它。
你每次执行git commit,就是把暂存区里的内容,打包成一个快照,存到本地仓库里。这个快照,就是后面要讲的commit对象。
.git文件夹里的内容!我见过有人手欠删了里面的文件,结果整个仓库废了。除非你真的知道自己在干什么,否则别碰它。
2.4 远程仓库(Remote Repository)
远程仓库,就是放在服务器上的那个仓库。比如GitHub、GitLab、Gitee上的项目。它的作用和本地仓库一模一样,只是多了一个「同步」的功能。
你想想看,如果只有本地仓库,你和同事怎么协作?你把代码提交到本地,同事看不到。所以需要远程仓库作为「中央枢纽」。你push上去,同事pull下来。
我个人习惯是:每天下班前至少push一次。为什么?因为笔记本可能会坏,硬盘可能会挂。远程仓库就是你的保险柜。
2.5 Git对象模型(blob、tree、commit)
好,接下来这部分稍微有点抽象,但理解了它,你就真正懂了Git的底层逻辑。Git本质上是一个「内容寻址文件系统」。什么意思?就是它用哈希值(SHA-1)来定位每一个对象。
Git内部有三种核心对象:blob、tree、commit。咱们一个一个说。
2.5.1 blob对象
blob,全称Binary Large Object。但在这里,它存的就是文件内容。注意,是内容,不是文件名。同一个文件内容,不管文件名是什么,Git只存一份blob。
举个例子:你在两个目录下各放了一个内容完全相同的文件,Git只会创建一个blob对象。这设计,省空间吧?
2.5.2 tree对象
tree对象,你可以把它理解成「文件夹的快照」。它记录了:这个目录下有哪些文件(blob),以及这些文件叫什么名字、有什么权限。如果目录下还有子目录,那子目录也是一个tree对象。
所以,一个tree对象里,可能包含多个blob引用,也可能包含多个子tree引用。这样一层层嵌套,就构成了完整的目录结构。
我记得有一次排查一个奇怪的问题:为什么同一个文件,在不同分支里内容不一样?后来发现是tree对象指向了不同的blob。嗯,Git就是这么严谨。
2.5.3 commit对象
commit对象,就是一次提交的快照。它包含三个核心信息:
- 一个指向tree对象的指针(记录当前目录状态)
- 一个或多个指向父commit的指针(记录历史)
- 作者、提交者、时间、提交信息等元数据
你每次执行git commit,Git就创建一个commit对象,里面那个tree指针,指向的就是你暂存区里那个目录树的快照。
2.6 它们之间的关系
咱们用一张表格来总结一下这四个区域和三个对象的关系:
| 概念 | 作用 | 对应命令 |
|---|---|---|
| 工作区 | 你写代码的地方 | 直接编辑文件 |
| 暂存区 | 准备提交的候车室 | git add |
| 本地仓库 | 存commit对象的地方 | git commit |
| 远程仓库 | 团队协作的中央枢纽 | git push / git pull |
| blob对象 | 存文件内容 | 自动创建 |
| tree对象 | 存目录结构 | 自动创建 |
| commit对象 | 存一次提交的快照 | git commit时创建 |
你想想看,理解了这些,再看Git的日常操作,是不是清晰多了?
git add:把工作区的文件内容,打包成blob对象,同时更新暂存区的tree结构。git commit:把暂存区的tree对象,打包成一个commit对象,存到本地仓库。git push:把本地仓库的commit对象,同步到远程仓库。
好,这一章的内容就到这里。核心就一句话:工作区是你干活的地方,暂存区是你准备提交的地方,本地仓库是你存历史的地方,远程仓库是你和团队同步的地方。而blob、tree、commit,就是Git用来管理这一切的三种积木。
下一章,咱们聊聊分支的本质。你猜分支在Git里是怎么实现的?其实就是一个指针,指向某个commit对象。是不是很简单?到时候细说。