学会 Git 命令不等于知道磁盘副作用。排查「提交后对象库没涨」「切换分支 index 乱了」,需要把 add / commit / branch / checkout / reset 映射到具体路径。本系列前几篇讲了 format;本篇把命令串起来。
一、总览
二、git add
git add <path>:
- 读工作区文件,算
blob(或复用已有对象),可能写
objects/xx/…松散对象。 - 更新
.git/index对应条目(SHA、stat、stage=0)。
实测仅 git add f.txt 后(Git 2.54.0):
.git/index
.git/objects/78/981922613b2afb6025042ff6bd878ac1994e85
尚未写 refs 与 logs。
三、git commit
git commit:
- 由 index 写 tree 对象(可能新建多级 tree)。
- 写 commit 对象(含 tree、parent、author、message)。
- 更新
refs/heads/<当前分支>为新 commit SHA。 - 追加
logs/HEAD与logs/refs/heads/<branch>。 - 刷新 index 与 HEAD tree 一致(通常)。
实测 git commit 后新增:
.git/logs/HEAD
.git/logs/refs/heads/master
.git/objects/2a/… .git/objects/5f/… # tree + commit(示例 SHA)
.git/refs/heads/master
blob 对象 78/… 与 add 时相同,被 commit
复用。
四、git branch
git branch <name>
仅创建
refs/heads/<name>,指向当前 HEAD
commit;不改
index、工作区、objects(除非配合 checkout)。
git branch -d 删除
refs/heads/<name> 文件;对象仍在,直至 gc
prune。
五、git checkout(切换分支)
切换已有分支:
- 写
HEAD为ref: refs/heads/<branch>(或已是符号引用则只改指向)。 - 用目标 commit 的 tree 填充 index 并重写工作区。
- 追加 reflog(
checkout:消息)。
git checkout <commit> detached:HEAD
直接写 SHA。
六、git reset
| 模式 | HEAD/ref | index | 工作区 |
|---|---|---|---|
--soft |
移动 | 不变 | 不变 |
--mixed(默认) |
移动 | 匹配新 HEAD | 不变 |
--hard |
移动 | 匹配新 HEAD | 匹配新 HEAD |
均写
reflog(reset:)。不立即删除旧
commit 对象;若成为悬空,待 gc。
git reset 不删 objects/ 里已有
blob——历史提交中的文件内容仍可被其他 commit 引用。
七、对比快照方法
snapshot() { find .git -type f | sort > "/tmp/git-$1.list"; }
git add .
snapshot add
git commit -m 'c1'
snapshot commit
diff -u /tmp/git-add.list /tmp/git-commit.list或用 find .git -newer .git/index
粗查最近改动(时间戳不可靠时应用快照 diff)。
八、本文边界
参考资料
- Chacon & Straub, Pro Git, ch.10(B 级)
- 实验环境:Git 2.54.0
系列索引:Git 内部结构 · 上篇:fsck · 下篇:merge/rebase 文件
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【Git 内部】对象图:tree、commit、tag 的链式结构
一次提交在对象库里如何连成链?tree 条目 mode/name/hash、commit 的 tree/parent 字段、annotated tag,用 git cat-file -p 展开并画对象图。
【Git 内部】.git 目录全景:三棵树与仓库布局
git init 之后 .git 里每个路径干什么?对照 gitrepository-layout 与本地 find 清单,建立 bare/non-bare、三棵树、objects/refs/index 的磁盘级地图。
【Git 内部】松散对象:zlib 载荷与 SHA-1 路径
blob/tree/commit 在磁盘上如何编码?对象头 type size、zlib 压缩、objects/ab/cdef 路径命名,对照 git hash-object 与手工 SHA-1 验证。
【Git 内部】refs、HEAD 与 packed-refs
分支和标签在磁盘上只是一行 SHA?refs/heads、符号引用 HEAD、packed-refs 文件头与 peeled tag 的格式与生成时机。