8. Git diff与日志:看透每一次变更

说实话,Git 最让我着迷的地方,就是它把「变化」这件事记录得清清楚楚。你改了什么、谁改的、为什么改,全都能追溯。这一章,我就带你把这几个看家本领学透。

8.1 git diff:对比差异的瑞士军刀

git diff 说白了就是「找不同」。我在项目里几乎每天都要用,尤其是 code review 的时候。

8.1.1 工作区 vs 暂存区

你改完代码还没 git add 的时候,想看看改了啥?

git diff

这个命令比较的是工作区和暂存区的差异。嗯,这里要注意:如果你已经 git add 了,再改文件,git diff 只会显示新改的部分,不会显示已经暂存的内容。

8.1.2 暂存区 vs 最近提交

想看看你准备提交的内容和上一次提交有啥区别?

git diff --staged
# 或者
git diff --cached

我个人习惯用 --staged,语义更清晰。有一次我差点把调试代码提交上去,就是靠这个命令发现的。

8.1.3 任意两次提交的对比

你可以比较任意两个 commit:

git diff <commit1> <commit2>

比如:

git diff abc123 def456

它会按时间顺序显示差异。如果你只想看某个文件的变更:

git diff abc123 def456 -- src/main.js

8.1.4 只看文件名

有时候我只想知道哪些文件变了,不想看具体内容:

git diff --name-only
git diff --name-status  # 还会显示变更类型(M/A/D)
小技巧: 搭配 --stat 参数,可以看每个文件改了多少行:git diff --stat

8.2 git log 高级用法:不只是看历史

git log 默认输出太啰嗦了。我刚开始用的时候,满屏的 commit 信息看得头疼。后来发现,加几个参数就能让它变得清爽。

8.2.1 美化输出

git log --oneline --graph --all --decorate

这个组合我几乎天天用。--oneline 只显示一行,--graph 画出分支图,--all 显示所有分支,--decorate 标出分支和标签的位置。

8.2.2 按作者筛选

git log --author="张三"

想看看某个同事最近在忙啥?或者复盘自己这周干了啥?这个命令很实用。

8.2.3 按时间筛选

git log --since="2024-01-01" --until="2024-06-30"
git log --after="2 weeks ago"  # 两周内的提交

8.2.4 按内容搜索

你想想看,有时候你只记得改过某个关键词,但不知道是哪个 commit:

git log -S "某个函数名"

这个 -S 参数会搜索每次提交中新增或删除了该字符串的 commit。我曾经用它找回过一个被误删的配置项。

8.2.5 查看某个文件的修改历史

git log --follow -p src/utils.js

--follow 会跟踪文件重命名,-p 会显示每次修改的具体内容。

核心要点: git log 不是只能看列表,它是个强大的查询工具。学会组合参数,效率翻倍。

8.3 git blame:谁动了我的代码?

这个命令的名字挺有意思——「追责」。不过别想歪了,它不是为了甩锅,而是为了搞清楚某行代码的来龙去脉。

git blame src/app.js

输出结果会显示每一行代码是谁、在哪个 commit、什么时间写的。比如:

abc12345 (张三 2024-03-15 10:30:00 +0800 42) const MAX_RETRIES = 3;

我曾经遇到过一个 bug,某行代码的逻辑明显有问题。用 git blame 一看,发现是三个月前一次紧急修复引入的。找到当事人一问,原来当时漏了一个边界条件。

8.3.1 只看某几行

git blame -L 42,60 src/app.js

只看第 42 到 60 行,省得翻半天。

8.3.2 忽略空白变更

git blame -w src/app.js

有些人改代码喜欢顺手格式化,-w 参数会忽略空白字符的变更,直接找到真正改逻辑的人。

注意: git blame 显示的是「最后修改」的人,不一定是「最初编写」的人。如果某行被多次修改,它只显示最后一次。

8.4 git reflog:后悔药在这里

git reflog 是我最爱的命令之一。它记录了你在本地仓库的所有操作——包括那些「我以为我删掉了」的东西。

git reflog

输出类似这样:

abc1234 HEAD@{0}: commit: 修复登录bug
def5678 HEAD@{1}: reset: moving to HEAD~1
789abcd HEAD@{2}: commit: 添加新功能
...

看到了吗?即使你 reset 了、rebase 了、甚至删除了分支,只要操作还在 reflog 里,就能找回来。

8.4.1 恢复误删的提交

有一次我不小心 git reset --hard 丢了一个重要的提交。当时冷汗都出来了。后来用 reflog 找到了那个 commit 的 hash,然后:

git cherry-pick abc1234

完美恢复。嗯,从那以后我再也不怕误操作了。

8.4.2 reflog 的保质期

reflog 不是永久保存的。默认情况下,90 天内的「可达」提交和 30 天内的「不可达」提交会被保留。你可以配置:

git config gc.reflogExpire 180  # 不可达提交保留180天
git config gc.reflogExpireUnreachable 90  # 可达提交保留90天
记住: reflog 是本地仓库的「操作日志」,不会推送到远程。它是你个人的后悔药。

知识体系总览

下面这张图,帮你把这一章的核心逻辑串起来:

Git 变更追溯工具全景 git diff • 工作区 vs 暂存区 • 暂存区 vs 最近提交 • 任意两次提交对比 • 只看文件名/统计信息 git log • 美化输出 (--oneline --graph) • 按作者/时间筛选 • 按内容搜索 (-S) • 文件修改历史 (--follow) git blame • 查看每行代码的归属 • 指定行范围 (-L) • 忽略空白变更 (-w) • 用于代码溯源和问题排查 git reflog • 本地操作日志 • 恢复误删的提交 • 找回 reset/rebase 丢失的内容 • 注意:本地仓库,不推送远程 核心:看变化 → 查历史 → 追来源 → 找后悔药

这四个工具各有侧重:diff 看「变化内容」,log 看「变化历史」,blame 看「变化来源」,reflog 看「操作记录」。配合使用,基本能覆盖日常开发中所有的追溯需求。

我的习惯: 每天下班前跑一次 git log --oneline --since="today",看看今天提交了啥。每周用 git diff --stat HEAD~7 回顾一周的工作量。养成习惯后,你会对项目的变化了如指掌。

公众号:蓝海资料掘金营,微信deep3321