Git 的四个区域
add、commit、push 跨越不同边界,不能都当成“保存”。工作区、索引、本地仓库和远程仓库可能保存不同版本;跟踪每个区域的快照,才能理解暂存后再编辑、提交后未推送等状态。
Git 四个区域如何工作
- 工作区是检出的文件集合,编辑器直接读写它。
- 索引也叫暂存区,代表下一次提交的候选树。
- 本地仓库保存提交对象和
main等本地分支引用。 - 远程仓库保存自己的对象和
refs/heads/main等分支引用。本课把服务端分支标成origin: main,以区别本地main。
索引是完整候选快照,不是提交后就清空的待办箱。git add app.py 将当前 app.py 内容写入索引。随后再编辑文件,只改变工作区,不会暗中改写索引。
提交保存的是索引所表示的树,再以当前 HEAD 作父提交(第一个提交没有父提交)并加入消息,创建提交对象,移动当前分支引用。它不是从工作区直接读取全部内容,也不是一袋独立修改。因此同一路径可以同时有已暂存旧版和未暂存新版。
git push 传输远程缺少的提交等对象,并请求推进远程分支引用,不直接上传当前工作文件或索引。
Git 四个区域逐步演示
默认只使用一个文件和一个分支。
edit app.py把print("one")写入工作区,索引、本地仓库和远程仓库仍为空。git add app.py将print("one")写入索引。工作文件仍在原位,这是复制内容而非移走文件。- 再次编辑,把工作文件改为
print("two")。索引仍是print("one"),同一路径出现两份不同快照。 git commit -m "save staged one"从索引创建 C1,因此 C1 保存print("one")。本地main移到 C1,工作区的print("two")仍未提交。git push origin main把 C1 传到远程,远程main移到 C1。两个仓库分支末端相同,但工作区仍与提交不同。
第 4 步不会保存编辑器中的最新版。提交读取的是“已暂存哪棵树”,所以要把新版提交出去,必须先再次 add。
各边界比较什么
动画在相邻区域之间显示比较状态。
| 边界 | 状态 | 含义 |
|---|---|---|
| 工作区与索引 | same | 已跟踪文件内容与索引相同 |
| 工作区与索引 | unstaged | 工作内容与候选快照不同 |
索引与本地 HEAD | nothing staged | 树相同,普通提交没有新树可保存 |
索引与本地 HEAD | staged | 索引与 HEAD 的树不同 |
本地 main 与远程 main | up to date | 指向同一提交 |
本地 main 与远程 main | ahead by N | 本地能到达 N 个远程分支尚不能到达的提交 |
这些是快照和引用的比较,不表示数据永远从左向右流动。真实 Git 还可从索引恢复文件、重置引用、获取远程对象、合并历史。本课只展示日常编辑、暂存、提交、推送的路径。
边界情况
本课允许执行不产生变化的命令,这些结果属于模型的一部分。
app.py不存在时执行 add,索引不变。本课不展开真实 Git 的缺失路径报错和删除暂存区别。- 工作文件与索引相同时,再 add 仍复制相同内容,状态不变。
- 索引与 HEAD 相同时,普通 commit 报告无暂存修改。工作区有未暂存编辑也不改变这个结果。
- 尚无本地提交时 push,没有对象可传。
- 两边 main 已相同时,push 成功但无变化,表示已是最新。
加载快照分叉预设后直接提交,会保存较旧的暂存版。加载未暂存修改预设后不 add 就提交,不会创建提交。两者用来区分索引的作用。
常见错误
- “add 只是告诉 Git 哪些文件改了。” Git 已能比较差异;add 将选中内容写入索引。再次编辑后若要提交新版,需要再次暂存。
- “commit 保存项目目录里的所有内容。” 它保存索引,未跟踪和未暂存内容可能不在其中。
- “提交后暂存区清空。” 索引通常与新 HEAD 相同,不是空了;“无暂存修改”说的是差异为空。
- “push 发送最新文件。” 推送协商、传输提交并更新远程引用,未进入本地提交的文件内容不会随 push 到达远程。
- “origin/main 就是远程本身。” 它是本地的远程跟踪引用,由 fetch 等操作更新。服务端另有自己的
refs/heads/main,本课写作origin: main,两者不是同一个引用。
模型简化
本课只有一个文件、一条线性分支、C1 等合成提交标识,以及始终可用的远程。没有展示 blob/tree 对象细节、分离 HEAD、合并、变基、标签、上游配置、远程跟踪滞后、认证、钩子、打包和网络故障。真实命令可能跨越不止一个边界,但四个区域仍需区分。