3. Git核心概念:工作区、暂存区、本地仓库、远程仓库的关系
聊Git,绕不开这四个概念。很多新手一开始就被搞晕了——明明我改了文件,怎么git status还提示我没提交?
说白了,Git把代码的流转分成了四个区域。我刚开始用Git时,也经常搞混。后来踩了几个坑,才真正理解它们的关系。
3.1 四个区域,一条流水线
想象一下你在写代码的流程:
- 工作区(Working Directory):你电脑上能看到的文件夹。你在这里改代码、加文件。
- 暂存区(Staging Area / Index):一个临时存放区。你改完代码后,用
git add把改动放进去。 - 本地仓库(Local Repository):你本地的
.git文件夹。用git commit把暂存区的内容永久保存到这里。 - 远程仓库(Remote Repository):服务器上的仓库,比如GitHub、GitLab。用
git push把本地提交推上去。
我见过不少同事,直接在服务器上改代码,改完就跑。结果第二天发现代码丢了——因为没提交到本地仓库,更没推送到远程。嗯,血的教训。
核心关系图:
你想想看,这个流程像不像一条流水线?工作区是原料区,暂存区是质检台,本地仓库是成品库,远程仓库是发货中心。每一步都有它的意义。
我的习惯:每次改完一个功能点,就git add一次。这样提交历史清晰,回滚也方便。别攒一堆再提交,容易出问题。
3.2 Git对象模型:Blob、Tree、Commit
Git底层其实是个内容寻址文件系统。它用三种对象来存储一切:
| 对象类型 | 存储内容 | 类比 |
|---|---|---|
| Blob | 文件内容(二进制数据) | 文件本身 |
| Tree | 目录结构(文件名、权限、指向Blob或子Tree的指针) | 文件夹 |
| Commit | 快照信息(指向Tree、父Commit、作者、时间、消息) | 一次存档记录 |
我记得刚学Git时,一直以为Git存的是文件差异。后来才明白——Git存的是完整快照。每次提交,Git都会把所有文件重新拍一张照片。
你可能会问:那岂不是很占空间?
其实不会。Git会用压缩和增量存储来优化。但概念上,每个Commit都是一个完整的项目状态。
对象关系图:
你看这个结构:Commit指向根Tree,根Tree下面可以挂子Tree和Blob。每个文件内容对应一个Blob,文件名和目录结构由Tree来管理。
避坑指南:我曾经遇到过一个情况——同事在Windows上提交了文件名大小写不同的文件,结果在Linux上拉下来就冲突了。因为Git默认对文件名大小写不敏感。后来我们统一加了git config core.ignorecase false才解决。
3.3 HEAD指针与分支的本质
HEAD是什么?说白了,就是一个指针。它指向你当前所在的提交。
分支又是什么?也是一个指针。指向某个提交。
你想想看,Git的分支其实就是一个可移动的指针。创建分支就是创建一个新的指针,切换分支就是移动HEAD指向不同的指针。
HEAD与分支的关系:
在这个图里:
- main 指向 C4(最新提交)
- feature 指向 C3(从 C3 分出来的)
- HEAD 指向 main(说明当前在 main 分支上)
如果执行 git checkout feature,HEAD 就会指向 feature。然后你再提交,feature 指针会向前移动,main 不动。
我的经验:理解分支是指针后,很多操作就豁然开朗了。比如合并分支,其实就是移动指针。快进合并(fast-forward)就是直接移动指针,三方合并就是创建一个新的提交节点。
3.4 实战:用命令感受一下
光说不练假把式。我们来实际操作一下:
# 初始化仓库
git init my-project
cd my-project
# 查看对象存储
echo "hello" > README.md
git add README.md
git commit -m "first commit"
# 查看对象
git cat-file -p HEAD # 查看当前提交内容
git cat-file -p HEAD^{tree} # 查看根Tree
git ls-tree HEAD # 列出Tree内容
# 查看分支和HEAD
git branch -v # 查看所有分支及指向的提交
git log --oneline --decorate # 查看提交历史,带分支和HEAD信息
你执行一下 git cat-file -p HEAD,会看到类似这样的输出:
tree 3b18e512dba79e4c8300dd08aeb37f8e728b8dad
author Your Name <you@example.com> 1690000000 +0800
committer Your Name <you@example.com> 1690000000 +0800
first commit
看到了吗?Commit 对象里存的就是 Tree 的哈希值、作者信息和提交消息。Tree 对象里存的是文件名和对应的 Blob 哈希。
避坑指南:我曾经在重构项目时,想找回一个删掉的文件。幸好记得那个文件的内容,用 git log --all --full-history -- "文件名" 找到了它所在的提交。Git 的对象模型保证了——只要提交过,数据就不会丢。
好了,Git 的核心概念就这些。工作区、暂存区、本地仓库、远程仓库构成了操作流程;Blob、Tree、Commit 构成了存储模型;HEAD 和分支就是指针游戏。理解这些,Git 对你来说就不再神秘了。
一句话总结:Git 就是个内容寻址的文件系统,加上一个可移动的指针(HEAD)来标记当前位置。分支就是多个指针同时存在,各自指向不同的历史节点。
可可精品资料库