
02-Git核心原理工作区、暂存区、本地库、远程库完整机制一、为什么新手用Git总是一头雾水很多新手朋友用Git基本就是git add、git commit、git push三板斧能推上去就万事大吉。但一旦遇到冲突、回退、误删文件就两眼一黑——因为不理解Git的底层机制操作全靠背命令换个场景就不会了。这篇我们不讲命令怎么敲讲Git到底在干什么。搞懂四大区域和对象模型后面所有的Git操作你都能自己推导出来。二、Git四大区域你的代码住在哪Git管理代码的核心是四个区域搞清楚它们的边界和关系是理解一切Git操作的前提区域英文名通俗理解存储位置工作区Working Directory你能看到的文件目录磁盘上的项目文件夹暂存区Staging Area (Index)“待提交清单”.git/index文件本地库Local Repository本地的版本历史.git/objects目录远程库Remote Repository服务器上的版本库GitHub/GitLab/Gitea等工作区就是你git clone下来后看到的那些文件你直接编辑的就是工作区。暂存区是Git独有的设计。为什么要有暂存区因为有时候你改了5个文件但只想提交其中3个暂存区就是让你挑着提交的中间层。git add就是把工作区的改动放进暂存区。本地库是Git最核心的区域。git commit把暂存区的内容快照成一个commit对象存入本地库。本地库就是你本机的版本历史即使断网也能查看历史、切分支、回退版本。远程库是团队协作的中心。git push把本地库的commit推到远程库git pull/git fetch把远程库的commit拉到本地。数据流向工作区 --git add-- 暂存区 --git commit-- 本地库 --git push-- 远程库 远程库 --git fetch-- 本地库 --git merge-- 暂存区 --git checkout-- 工作区三、Git对象模型底层到底存了什么Git本质上是一个内容寻址的文件系统。所有数据都以对象的形式存储在.git/objects目录下用SHA-1哈希值做唯一标识。Git有四种核心对象3.1 Blob对象——存文件内容每个文件的每个版本都对应一个blob对象。注意blob只存文件内容不存文件名、不存路径、不存权限。echo hello world | git hash-object --stdin # 输出: 3b18e512dba79e4c8300dd08aeb37f8e728b8dad这个哈希值就是blob对象的地址。Git用Zlib压缩后存到.git/objects/3b/18e512dba79e4c8300dd08aeb37f8e728b8dad。3.2 Tree对象——存目录结构Tree对象相当于目录记录了某个目录下所有文件和子目录的信息包含三部分文件名、文件权限、指向blob或子tree的哈希指针。tree 5f2f16bfff1a8d6c1de6689b0ae2f2cf3f3a5b18 blob 3b18e512dba79e4c8300dd08aeb37f8e728b8dad hello.txt tree 7ba8c8d3f5e2a1b9c4d6e8f0a2b4c6d8e0f2a4b6 src/3.3 Commit对象——存版本快照Commit对象把Tree、作者、时间、提交信息、父commit指针打包在一起形成一个完整的版本快照commit a1b2c3d4e5f6... tree 5f2f16bfff1a8d6c1de6689b0ae2f2cf3f3a5b18 parent 9f8e7d6c5b4a... author 张三 zhangsanexample.com 1700000000 0800 committer 张三 zhangsanexample.com 1700000000 0800 修复开门接口返回字段命名问题一次commit就是一个完整的项目快照——通过tree递归找到所有文件的内容。这也是为什么Git切换分支那么快它不需要逐个文件比对直接用commit的tree指针替换整个工作区。3.4 Tag对象——存标签信息Tag分轻量标签lightweight和附注标签annotated。附注标签会创建独立的tag对象包含标签名、说明、创建者、时间、指向的committag v1.2.0-firmware object a1b2c3d4e5f6... type commit tag 张三 zhangsanexample.com 1700000000 0800 安卓固件v1.2.0正式版修复开门接口兼容问题3.5 对象关系图Commit ── Tree ── Blob (文件内容) │ └── Tree (子目录) ── Blob │ └── ... └── Parent Commit (前一个版本)关键理解Git不是存增量差异而是每个commit存一个完整的快照。没有改动的文件新commit的tree会直接复用旧的blob指针所以不会浪费空间。这是Git和SVN等增量存储系统的本质区别。四、HEAD指针Git的当前状态导航器HEAD是Git中极其重要的概念它指向当前在哪个分支的哪个commit。HEAD -- refs/heads/develop -- commit a1b2c3d4HEAD指向当前分支如developrefs/heads/develop指向develop分支的最新commitcommit对象里有parent指针形成版本链当你git checkout切分支时本质上是改变HEAD的指向然后把目标commit的tree展开到工作区。detached HEAD游离HEAD当你checkout到一个具体的commit而不是分支名时HEAD直接指向commit不关联任何分支。这时候的提交如果不新建分支保存切换后会丢失实际还在objects里但没有引用指向它最终会被GC回收。五、一次完整提交的底层流程用我们无人售货柜项目的实际场景走一遍你修改了DoorController.java把doorId改成door_id——改动在工作区git add DoorController.java——Git计算文件内容的SHA-1创建blob对象存入.git/objects更新.git/index记录该文件的新版本指针git commit -m 修复开门接口字段命名——Git根据index创建tree对象再创建commit对象parent指向当前HEAD的commit更新refs/heads/develop指向新commitgit push origin develop——Git把本地新增的blob、tree、commit对象传到远程库更新远程的refs/heads/develop整个过程工作区改动 → 暂存区登记 → 本地库快照 → 远程库同步每一步都是确定性的、可追溯的。六、理解原理后的实战价值搞懂这些原理很多高级操作就不再神秘**git reset --hard**为什么危险因为它直接移动HEAD和分支指针工作区和暂存区被覆盖如果commit没有被任何分支/tag引用就只能从git reflog里找回来**git rebase**做了什么它把一系列commit摘下来在目标分支上重新apply生成新的commit对象哈希值变了**.gitignore**在哪个层面生效它影响的是git add——工作区的文件如果不匹配ignore规则才会被加入暂存区git merge冲突的本质两个commit对同一文件的同一区域做了不同修改Git无法自动决定用哪个需要人工介入Git的核心设计哲学就是一切皆对象对象用哈希寻址指针串联历史。理解了这个哲学Git在你手里就不再是背命令而是推导逻辑。下一篇我们进入企业级分支规范讲清楚Master/Develop/Feature/Bugfix/Release每条分支到底怎么用。