2、Git核心概念:工作区、暂存区、本地仓库、远程仓库、Git对象模型(blob、tree、commit)

好,咱们正式开始聊Git的核心概念。说实话,很多人用Git好几年,其实也就停留在「add、commit、push」三板斧的阶段。一旦遇到合并冲突或者想回滚某个历史版本,立马就懵了。

我个人习惯是,先把这几个核心概念搞透。你想想看,如果连工作区和暂存区都分不清,那后面谈分支策略就是空中楼阁。今天我就带你把这几个概念彻底捋一遍。

2.1 工作区(Working Directory)

工作区,说白了就是你电脑上能看到的那个文件夹。你写代码、改文件、删文件,全在这里发生。这是你直接和代码打交道的地方。

我记得刚带团队那会儿,有个同事问我:「我明明改了代码,为什么git status看不到?」我过去一看,好家伙,他改的是另一个目录下的文件,根本不在Git仓库里。嗯,这就是没搞懂工作区的边界。

小提示:工作区里的文件,Git并不会自动跟踪。你得告诉Git:「嘿,这个文件我要管!」——这就是后面要讲的add命令。

2.2 暂存区(Staging Area / Index)

暂存区这个概念,是Git最巧妙的设计之一。它就像一个「候车室」。你改完代码,先放到候车室(暂存区),检查一遍没问题了,再统一上车(提交到本地仓库)。

为什么要多此一举?我举个例子。你同时改了三个文件,但其中一个还没改完。你可以只把改好的两个文件放到暂存区,先提交。另一个继续改。这种灵活性,SVN那种老古董根本做不到。

核心理解:工作区是你干活的地方,暂存区是你准备提交的地方。两者之间隔着一道「git add」的门。

我曾经犯过一个低级错误:改了一堆配置文件,直接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内部有三种核心对象:blobtreecommit。咱们一个一个说。

2.5.1 blob对象

blob,全称Binary Large Object。但在这里,它存的就是文件内容。注意,是内容,不是文件名。同一个文件内容,不管文件名是什么,Git只存一份blob。

举个例子:你在两个目录下各放了一个内容完全相同的文件,Git只会创建一个blob对象。这设计,省空间吧?

关键点:blob只存文件内容,不存文件名、权限等元数据。这些信息由tree对象来管。

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指针,指向的就是你暂存区里那个目录树的快照。

理解这个,你就懂了:为什么Git回滚那么快?因为它不是把文件复制来复制去,而是把commit指针指回某个历史commit。那个commit里保存着当时的完整快照(通过tree和blob)。

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对象,同步到远程仓库。
避坑指南:我曾经遇到一个团队,所有人都在master上直接commit,从不push到远程。结果某天服务器硬盘坏了,所有人的本地代码都没了……记住,远程仓库不是摆设,它是你的救命稻草。

好,这一章的内容就到这里。核心就一句话:工作区是你干活的地方,暂存区是你准备提交的地方,本地仓库是你存历史的地方,远程仓库是你和团队同步的地方。而blob、tree、commit,就是Git用来管理这一切的三种积木。

下一章,咱们聊聊分支的本质。你猜分支在Git里是怎么实现的?其实就是一个指针,指向某个commit对象。是不是很简单?到时候细说。