3.2 log与diff:指纹比对与版本考古


3.2 log与diff:指纹比对与版本考古

本节摘要:log 是在提交图上做遍历,diff 是在任意两个快照间做比对。本节把两组命令的常用形态整理成考古工具箱,并讲清 ^~、范围语法与 ../... 的差别——这些符号是侦探读案卷的页码系统。

学习目标

  1. 能用 log 的过滤与格式化选项快速定位提交
  2. 能精确使用 ^~ 及双点三点范围语法
  3. 能选择正确的 diff 比对对象(工作区、index、提交、区间)
  4. 能用 -S/-G/blame 完成一次代码溯源

一、log:提交图的遍历器

第 1 章说过历史就是 parent 指针连成的图,log 本质是图遍历加过滤器。日常最值钱的几个形态:

git log --oneline --graph --all # 全分支拓扑一屏尽收 git log -3 # 只要最近三条 git log --stat # 附每提交文件级增删行数 git log -p f.txt # 只看某文件的演变史 含每步补丁 git log --author=detective # 按作者过滤 git log --grep="登录" # 按说明关键字过滤 git log --since="2 weeks ago" # 按时间过滤

其中 -p 文件路径 是考古利器:不改文件名的前提下,一份文件的所有前世今生按时间倒序排列,每一步是谁改的、为什么改(看提交说明)一目了然。配合 --follow 还能穿透重命名继续追踪——再次呼应上节"rename 是推断"的机制。

二、页码系统:^、~ 与范围

读 log 常见 HEAD~2v1.0^2 这类表达式,规则其实极简:

  • ~ 沿第一个 parent 往前走:HEAD~2 是"当前提交的爸爸的爸爸"。
  • ^ 指 parent 序号:HEAD^HEAD~1;merge commit 有双 parent,HEAD^2 取第二个(被合入那一方)。
  • 组合合法:HEAD~2^2 先走两步再取第二父。

范围语法是另一套页码:A..B 表示"在 B 而不在 A 的提交"(B 独有);A...B 表示"双方各自独有的提交"(对称差),配合 merge-base 理解最稳:A...B = 从公共祖先分别到 A、到 B 的两段。用在 diff 上含义又不同(见下),同一符号在 log 与 diff 里的差别是面试经典坑:

git log main..dev # dev 有 main 没有的提交 推送前的自查清单 git log dev..main # 反过来 main 独有的 git diff main...dev # 从公共祖先到 dev 的总变化 才是你功能分支的净工作量

main..dev 是推送前最重要的自查命令:它列出的正是将要被 push 出去的提交,逐条过目再推,比任何事后补救都便宜。

三、diff:任意两点间的指纹比对

diff 的比对对象有四个层级,分别回答不同问题:

git diff # 工作区 vs index 还没入袋的改动 git diff --staged # index vs HEAD 已入袋待归档的改动 git diff HEAD # 工作区 vs HEAD 全部未提交改动 git diff a1b2c3d e5f6a7b # 任意两个提交的快照比对 git diff main dev -- src/ # 限目录路径比对

值得强调 --staged(旧写法 --cached):只显示已入袋部分,是 commit 前最后确认"袋里到底装了什么"的正规动作。字级差异用 --word-diff,行内小改(改个变量名)时比行级 diff 可读得多。

diff 的底层机理呼应第 1 章:两棵 tree 逐层比对哈希,同哈希即跳过整棵子树,所以比对大项目也飞快——差异是"算出来的"不是"存着的",对象库里任何提交都不存 diff,只存快照。

四、溯源三件套:-S、-G、blame

找"这行代码什么时候出现的"

git log -S "OAuthToken" --oneline # 检索内容增删含该串的提交 pickaxe git log -G "token.*expire" --oneline# 正则版本 git blame f.txt -L 20,30 # 第20到30行逐行标注最后一次修改的提交与作者

-S 的内部机制很"侦探":它逐提交比对相邻快照中该字符串的出现次数,次数变化即命中。重构排查"某配置项是谁引入又何时被改坏的",-Sblame 组合几乎无往不利——blame 给你"最后一手",log -p 给你"全部前史"。

统计与归档git diff --stat main...dev 给出功能分支净变更的文件行数摘要,附在合并请求描述里是低成本高收益的团队习惯;git shortlog -sn 按作者统计提交数,写周报时省事。

考古工具速查矩阵

问题 命令 比对/遍历对象
这文件怎么演变过来的 git log -p 文件 提交链
袋里装了什么 git diff --staged index 对 HEAD
分支净工作量 git diff main...dev 公共祖先对 dev
即将推送什么 git log main..dev dev 独有提交
这行谁最后改的 git blame -L 起点,终点 文件 单文件逐行
某字符串何时引入 git log -S 字符串 相邻快照计数

⚠️ 常见坑:把 git diff main...devgit diff main..dev 当同义词。后者(两 commit 间)等价于直接 git diff main dev,比的是两个端点快照;前者比的是"公共祖先到 dev",才是功能分支的实际增量。差一个点,含义天差地别。

💡 关键直觉:diff 的三个点两个点记不住时,回到对象模型——A..B 用于 log(集合差:B 有 A 没有),A...B 用于 diff(以 merge-base 为基线的净变更)。需要"哪段范围"就想想你到底要"哪两个快照"比对。

本节要点回顾

  • log 是图遍历:过滤、格式化、--follow 穿透重命名。
  • 页码系统~ 走第一父链、^n 取第 n 父,merge 提交的分叉口靠 ^2 进入。
  • diff 四层级:工作区、index、HEAD、任意提交,先想清楚要比哪两个快照。
  • 推送前自查git log main..dev 逐条过目,是最便宜的质量闸门。
  • 溯源组合拳:blame 定最后一手,-S/-G 找引入点,log -p 展开前史。

看懂历史之后,下一节处理每个人都遇到过的问题——做错了怎么撤。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U