git diff 比较两提交差异,-表示旧版有新版删,+表示旧版无新版增;顺序错误会导致误读为回退变更;可用分支、标签、相对引用等;--name-only和--stat先看范围,--submodule=diff可深入子模块。

git diff 比较两个 commit 的基本写法
直接用 git diff <commit1><commit2></commit2></commit1> 就能看差异,但要注意顺序:左边是“旧”版本,右边是“新”版本,输出的变更块里,- 表示旧版有、新版删了,+ 表示旧版没有、新版新增了。
常见错误是把两个 commit 写反,结果看到一堆“删除文件”,其实是误把新提交当成了基线。比如想看 abc123 到 def456 的改动,却写了 git diff def456 abc123,那输出就是“从 def456 回退到 abc123 会删哪些东西”,不是你要的增量变更。
- 推荐固定写法:
git diff <old-commit><new-commit></new-commit></old-commit>,像读句子一样:“从 old 到 new 有哪些变化” - commit 可以用完整 SHA、短 SHA(如
a1b2c3d)、分支名(main)、标签(v1.2.0),甚至相对引用(HEAD~2) - 如果只写一个 commit,比如
git diff abc123,默认对比的是工作区和该 commit 的差异,不是两个 commit 之间
git diff --name-only 和 --stat 看概览,别一上来就翻大 patch
两个 commit 差异可能涉及几十个文件,直接 git diff 输出容易淹没重点。先用轻量命令快速定位范围,再深入查具体文件。
典型场景:Code Review 前快速确认这次 PR 改了哪些文件;或者排查某个功能突然失效,想锁定最近一次引入变更的提交范围。
-
git diff --name-only <old><new></new></old>:只列文件路径,不显示内容,适合复制粘贴进编辑器逐个检查 -
git diff --stat <old><new></new></old>:显示每个文件增删行数,一眼看出哪几个文件改得最多 - 加
--compact-summary(Git 2.38+)能合并重命名和修改,避免把重命名当成“删一个+加一个”
git diff 出现 “fatal: ambiguous argument” 错误怎么办
这个错误本质是 Git 不确定你输的字符串到底指什么:是分支名?是 tag?是某个缩写的 commit SHA?还是文件名?尤其当你用短哈希(比如 abcd)时,多个 commit 都可能匹配前缀。
最常踩的坑是:本地没拉最新远程分支,却用 origin/main 当作比较对象,而本地根本没有这个远程跟踪分支,Git 就会报这个错。
- 先运行
git show-ref或git branch -a确认两个 commit 引用确实存在且无歧义 - 短 SHA 至少用 7 位(
git rev-parse --short=7 <commit></commit>),降低冲突概率 - 如果引用带斜杠(如
feature/login),确保没被当作路径——加--显式分隔,例如:git diff main feature/login --
diff 结果里看不到 submodule 变更?需要额外参数
默认 git diff 对 submodule 只显示 commit hash 的变化,比如 “Subproject commit abc123 → def456”,不展开子模块内部改了啥。这在调试依赖库行为异常时很不方便。
真正要查 submodule 里具体改了哪些代码,必须显式启用递归模式。
- 加
--submodule=log:显示子模块 commit message 摘要(默认行为) - 加
--submodule=diff:真正递进子模块,执行一次git diff并内联显示差异(需子模块已检出) - 注意:如果子模块未初始化(
git submodule init)或未更新(git submodule update),--submodule=diff会跳过或报错
复杂点在于,子模块的 diff 还受其自身 Git 配置影响,比如 submodule.<name>.ignore</name> 设为 all 时,即使加了 --submodule=diff 也可能被静默忽略。这种配置容易被遗忘,导致你以为没变,其实子模块里早改了三行关键逻辑。











