掌握 git diff 和 git blame 的用法,快速定位代码变更、追溯修改历史,成为排查问题的高手。

Diff 与 Blame — 看清楚每一行代码是谁改的、怎么改的

代码出了问题,第一件事不是改代码,而是搞清楚:改了什么?谁改的?为什么改?diffblame 就是回答这两个问题的利器。


一、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
diff --git a/src/login.js b/src/login.js
--- a/src/login.js ← 旧版本
+++ b/src/login.js ← 新版本
@@ -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

# 比较最近 2 次提交
git diff HEAD~2 HEAD

比较分支

1
2
3
4
5
# main 和 develop 的差异
git diff main develop

# 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
2
# 按单词高亮差异,而不是按整行
git diff --word-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
git blame src/login.js

输出示例:

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
# 只看第 10-20 行
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
# 查看 login.js 的所有提交
git log --oneline -- src/login.js

# 输出:
# i9j0k1l fix: 添加登录失败日志
# e5f6g7h fix: 改用 md5 加密
# a1b2c3d feat: 初始登录功能

查看每次提交的具体改动

1
2
# -p 显示每次提交的 diff
git log -p -- src/login.js

查看某个函数的历史

1
2
# 追踪 login 函数的所有改动
git log -L :login:src/login.js

查看谁修改了哪些行

1
2
3
4
5
6
7
# 带行号的 blame
git blame --line-porcelain src/login.js | grep "^author " | sort | uniq -c | sort -rn

# 输出:
# 4 John Doe
# 1 Jane Smith
# 1 Bob Lee

六、实战:排查一个 Bug 的来源

场景:线上报错,要找到谁引入了问题代码

1
2
3
4
5
6
7
8
9
10
11
12
13
# 1. 定位到出问题的代码行(比如第 42 行)
git blame -L 42,42 src/payment.js

# 输出:
# x1y2z3d (张三 2026-05-20) const amount = price * quantity;

# 2. 查看这个提交的详细信息
git show x1y2z3d

# 3. 查看这次提交的完整改动
git diff x1y2z3d~1 x1y2z3d

# 4. 联系张三了解当时的修改意图,确认修复方案

场景:查看某段代码为什么被这么写

1
2
3
4
5
6
7
8
# 追溯第 15-30 行
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> │
└────────────────┴─────────────────────────────────────────┘