卷 VI · 落地CH 24深度 24/24

出事了,先看这张表

最后一章,把全书压成一张表。但真正该被记住的不是这张表——是它最后一列背后那个你现在已经能自己推的判据。

决策表三个字判风险全书收尾

那张表

▶ 动手 · 决策表

按「你想干什么」查,不是按命令名查。红色的那几条,敲之前先想三秒。

它其实只有一列是重要的

那就是最后一列,风险。而那一列的判据,你现在已经能自己推了——问一句:这个操作动的是什么?

◆ 三个字,判掉所有风险

动贴纸branchswitchreset --softtag

随便来。贴纸是 41 个字节(第 6 章),reflog 记着它去过哪儿(第 9 章)。没有任何东西会丢。

造对象addcommitstashmergecherry-pickrevert

安全。对象只增不改(第 5 章)。最坏的结果是多了几个没人要的对象,等着被 gc。

动工作区restorereset --hardcheckout -fclean

停三秒。那是整个系统里唯一一个 Git 没有替你备份的地方(第 12、20 章)。

而「停三秒」之后该做的事,永远是同一句:

$ git stash --include-untracked

它把你的工作区写成提交对象——那一瞬间,你的改动从第三类跳到了第二类。成本一条命令,收益是把「可能永久丢失」变成「一定找得回来」。

三条能救命的命令

如果这本书你只记住三条命令,应该是这三条:

# 1. 我在哪、发生了什么(90% 的「出事了」在这里就有答案)
$ git reflog

# 2. 那个东西到底是什么(绕过一切美化,直接读对象)
$ git cat-file -p <哈希或引用>

# 3. 图上是什么关系(分叉了没有、能不能快进)
$ git log --graph --oneline --all

它们的共同点:都在问「客观状态是什么」,而不是「我该敲哪条命令」。

这也是这本书想给你的那个转变——从「记住怎么做」变成「看得懂发生了什么」。后者一旦有了,前者自己就来了。

回到开头那六个问题

首页问过六个「你能说出为什么吗」。现在逐条对答案,每条一句话:

问题答案
为什么 checkout 一个分支是瞬间的?切分支只改一个 41 字节的文件;工作区靠 Merkle 剪枝,只写真正有差异的那些路径,代价与仓库大小无关3、6
为什么 rebase 之后提交号全变了?哈希由内容决定,而 parent 就在内容里——改一个,后面全部连锁改名2、4、18
为什么删掉大文件仓库没变小?提交是快照,删除只是「下一张快照里没有它」;那个 blob 还被之前每个提交的树指着,完全可达1、5、21
为什么 reset --hard 后提交能救、改动不能?提交被写成过对象,reflog 引用着它;没 add 过的改动从没进过对象库,Git 手上没有那份数据9、12、20
为什么改了不同文件也会冲突?目录本身也是对象。两边都动了同一棵 TREE 的结构,冲突发生在树这一层3、17
git status 那两列字母在比什么?三棵树之间的两道缝:左列 = 索引↔HEAD,右列 = 工作区↔索引10

六个看起来分属六个话题的问题,答案全都落在同样那几句话上。这就是「有模型」和「靠背命令」的区别。

◆ 全书两句话

Git 不存 diff,存快照。

每个提交指向那一刻整棵目录树的完整样子。而对象的名字就是它内容的哈希,所以没改过的东西天然只存一份——去重不是一个功能,是一个不可违反的性质。

分支只是一张贴纸。

41 个字节,写着一个哈希。你怕的所有命令——resetrebasecheckout、强推——都只是在撕贴纸、贴贴纸,外加往那座只增不改的对象库里再扔几个新对象。

合起来就是 Git 的全部形状:一座只增不改的对象库,加上一把随手可以撕来贴去的贴纸。

接下来读什么

这本书讲的是模型。想再往下走,三个方向:

  • 《Pro Git》第 10 章 Git Internals——官方的内部原理章节。你现在读它会觉得轻松得多,因为所有概念都已经有画面了。
  • Git 源码里的 Documentation/technical/——packfile 格式、index 格式、协议规范的一手文档。比想象中好读。
  • 自己写一个——用任何语言实现 hash-objectcat-filewrite-treecommit-tree。这本书里那台迷你 Git 就是这么来的,加起来不到三百行。当你写出的哈希第一次和真 git 对上时,那种「原来就这样」的感觉很值得体验一次。
↩ 最后一次回到你的仓库

把这八行配置贴进终端,然后就可以合上这本书了:

git config --global merge.conflictStyle zdiff3
git config --global rerere.enabled true
git config --global diff.algorithm histogram
git config --global diff.colorMoved zebra
git config --global pull.rebase true
git config --global fetch.prune true
git config --global rebase.autosquash true
git config --global alias.pushf 'push --force-with-lease'

然后养成两个动作:

危险操作之前——

git stash --include-untracked
git branch backup-$(date +%m%d-%H%M)

不知道发生了什么的时候——

git reflog

这两个动作加起来,能覆盖你未来 95% 的 Git 惊魂时刻。

这本书的最后一句话

Git 从来没打算吓唬你。它底下只有一座按内容寻址的键值库,和几张 41 字节的贴纸——那个「一不小心就完蛋」的名声,绝大部分是模型不清楚带来的错觉。现在模型有了:看见任何一条命令,先问它动的是贴纸、是对象、还是工作区。

剩下的,去仓库里试就行了。反正只要 commit 过,它就几乎不可能真的消失。