Git Diff 与 Blame — 查看变更与追溯历史
掌握 git diff 和 git blame 的用法,快速定位代码变更、追溯修改历史,成为排查问题的高手。
Diff 与 Blame — 看清楚每一行代码是谁改的、怎么改的
代码出了问题,第一件事不是改代码,而是搞清楚:改了什么?谁改的?为什么改?diff 和 blame 就是回答这两个问题的利器。
一、
git diff — 查看代码差异
三种 diff 场景
1 2 3 4 5 6
| 工作区 ──→ 暂存区 ──→ 仓库(最近提交) │ │ │ │ git diff │ diff │ │ │ --cached │ └───────────┼───────────┘ diff HEAD(全部差异)
|
| 命令 | 比较什么 | 场景 |
|---|
git diff | 工作区 vs 暂存区 | 看还没 add 的改动 |
git diff --cached | 暂存区 vs 仓库 | 看 add 了但没 commit 的改动 |
git diff HEAD | 工作区 vs 仓库 | 看所有未提交的改动 |
输出解读
1 2 3 4 5 6 7 8 9 10 11
|
@@ -10,7 +10,8 @@ ← 从第 10 行开始,旧版 7 行,新版 8 行 function login(user, pass) { - if (pass === "123") { ← 删除的行(红色) + const hash = md5(pass); + if (hash === storedHash) { ← 新增的行(绿色) return true; } }
|
| 符号 | 含义 |
|---|
--- | 旧版本文件 |
+++ | 新版本文件 |
@@ | 变更范围(行号和行数) |
- | 被删除的行 |
+ | 新增的行 |
二、
diff 常用用法
比较两个提交
1 2 3 4 5
| git diff abc1234 def5678
git diff HEAD~2 HEAD
|
比较分支
1 2 3 4 5
| git diff main develop
git diff main origin/develop
|
只看文件名
1 2 3 4 5
| git diff --name-only
git diff --stat
|
输出示例:
1 2 3
| src/login.js | 15 +++++++++------ src/style.css | 3 ++- 2 files changed, 11 insertions(+), 7 deletions(-)
|
只看某个文件
1 2
| git diff HEAD -- src/login.js
|
提示
-- 用来分隔选项和文件路径,避免文件名和分支名冲突导致歧义。
三、
diff 高级用法
忽略空白变更
1 2 3 4 5
| git diff -w
git diff -b
|
单词级别 diff
输出示例:
1
| function login(user, [-pass-] {+password+}) {
|
比较目录树
1 2
| git diff --stat main develop
|
diff 选项速查
| 选项 | 作用 |
|---|
--stat | 显示文件名和改动行数统计 |
--name-only | 只列出文件名 |
--name-status | 文件名 + 状态(A/M/D) |
-w | 忽略空白变更 |
--word-diff | 单词级别差异 |
-U0 | 不显示上下文行 |
-- <path> | 只看指定路径 |
四、
git blame — 追溯每一行的修改者
git blame 给文件的每一行标注:谁、在什么时候、哪个提交中修改了它。
基本用法
输出示例:
1 2 3 4 5 6 7
| a1b2c3d4 (John Doe 2026-06-01 10:30:00 +0800 1) function login(user, pass) { a1b2c3d4 (John Doe 2026-06-01 10:30:00 +0800 2) const hash = md5(pass); e5f6g7h8 (Jane Smith 2026-06-05 14:20:00 +0800 3) if (hash === storedHash) { a1b2c3d4 (John Doe 2026-06-01 10:30:00 +0800 4) return true; a1b2c3d4 (John Doe 2026-06-01 10:30:00 +0800 5) } i9j0k1l2 (Bob Lee 2026-06-08 09:15:00 +0800 6) logger.info("登录失败"); a1b2c3d4 (John Doe 2026-06-01 10:30:00 +0800 7) }
|
可以看出:第 3 行是 Jane 改的,第 6 行是 Bob 新加的。
常用选项
| 选项 | 缩写 | 作用 |
|---|
-L start,end | — | 只看指定行范围 |
-w | — | 忽略空白变化 |
-C | — | 检测跨文件的代码移动 |
-M | — | 检测文件内的代码移动 |
--line-porcelain | — | 机器可读的详细输出 |
1 2 3 4 5
| git blame -L 10,20 src/login.js
git blame -w src/login.js
|
五、
git log 追踪文件历史
除了 blame,git log 也能查看某个文件的完整修改历史。
查看文件的提交历史
1 2 3 4 5 6 7
| git log --oneline -- src/login.js
|
查看每次提交的具体改动
1 2
| git log -p -- src/login.js
|
查看某个函数的历史
1 2
| git log -L :login:src/login.js
|
查看谁修改了哪些行
1 2 3 4 5 6 7
| git blame --line-porcelain src/login.js | grep "^author " | sort | uniq -c | sort -rn
|
六、
实战:排查一个 Bug 的来源
场景:线上报错,要找到谁引入了问题代码
1 2 3 4 5 6 7 8 9 10 11 12 13
| git blame -L 42,42 src/payment.js
git show x1y2z3d
git diff x1y2z3d~1 x1y2z3d
|
场景:查看某段代码为什么被这么写
1 2 3 4 5 6 7 8
| git blame -L 15,30 src/config.js
git log -1 abc1234
git show abc1234
|
七、
IDEA 中的对应操作
| IDEA 功能 | 等价命令 | 操作方式 |
|---|
| 查看文件差异 | git diff | 双击 Git 面板中的文件 |
| 逐行追溯 | git blame | 右键编辑器左侧行号区域 → Annotate |
| 文件历史 | git log -- file | 右键文件 → Git → Show History |
| 提交详情 | git show | 双击 Git 面板中的提交 |
总结:Diff 与 Blame 速查卡
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| ┌──────────────────────────────────────────────────────────┐ │ Git Diff & Blame 速查 │ ├────────────────┬─────────────────────────────────────────┤ │ 工作区差异 │ git diff │ │ 暂存区差异 │ git diff --cached │ │ 所有未提交差异 │ git diff HEAD │ │ 两个提交差异 │ git diff <hash1> <hash2> │ │ 两个分支差异 │ git diff <branch1> <branch2> │ ├────────────────┼─────────────────────────────────────────┤ │ 只看文件名 │ git diff --name-only │ │ 文件+统计 │ git diff --stat │ │ 单词级别 │ git diff --word-diff │ ├────────────────┼─────────────────────────────────────────┤ │ 追溯每一行 │ git blame <file> │ │ 指定行范围 │ git blame -L 10,20 <file> │ │ 文件提交历史 │ git log --oneline -- <file> │ │ 带 diff 的历史 │ git log -p -- <file> │ └────────────────┴─────────────────────────────────────────┘
|