Git 中 diff 查看不同版本的文件差异
Git diff:查看不同版本间的文件差异
Git 的核心能力之一就是追踪文件的每一次变更。而 git diff 命令,就是用来精确比较这些差异的利器。无论你想知道工作区改了什么、暂存区里有什么、或者两个提交之间到底哪里不同,git diff 都能给你清晰、详细的答案。本教程将从零开始,带你掌握这个最常用的 Git 命令。
理解三个关键区域
在深入 diff 之前,先快速回顾一下 Git 中文件所处的三个区域,这是理解所有比较逻辑的基础:
- 工作区(Working Directory):你电脑上能直接看到的项目文件夹,正在编辑的文件就在此处。
- 暂存区(Staging Area / Index):一个隐式的“预备区”,通过
git add命令,你告诉 Git 希望在下个提交中包含哪些修改。 - 本地仓库(Repository):通过
git commit,暂存区的快照就被永久保存为一个提交对象(commit)。
git diff 的魔力就在于,它能灵活地选取这三个区域中的任意两个进行比对。
基本用法:查看工作区与暂存区的差异
这是你日常使用最频繁的操作。当你修改了文件,但还没执行 git add 时,用下面的命令就能看到“从上次暂存到现在,你到底改了些什么”。
git diff
这个命令比较的是 当前工作区 和 暂存区 之间的差异。如果暂存区是空的(没有执行过 git add),那么它将自动比较最新的提交(HEAD)。
让我们看一个简单的输出示例。假设你将 hello.txt 文件中的 “Hello, World” 改成了 “Hello, Git”,运行 git diff 会显示:
diff --git a/hello.txt b/hello.txt
index 557db03..263ecaf 100644
--- a/hello.txt
+++ b/hello.txt
@@ -1 +1 @@
-Hello, World
+Hello, Git
关键部分解读:
diff --git a/hello.txt b/hello.txt:指明正在比较的文件。--- a/hello.txt和+++ b/hello.txt:a表示变更前的版本,b表示变更后的版本。@@ -1 +1 @@:差异块的位置信息,表示从第一行开始,旧版本共1行,新版本也共1行。-Hello, World:以-开头的行表示被删除的内容。+Hello, Git:以+开头的行表示被新增的内容。
比较暂存区与最新提交的差异
你已经用 git add 将修改放入了暂存区,但在提交前还想确认一下暂存区里究竟放了什么内容。这时可以使用 --staged 或 --cached 参数。
git diff --staged
(--cached 参数在 Git 中与 --staged 完全等价,你可以根据习惯选用。)
这个命令比较的是 暂存区 和 最近一次提交(HEAD) 之间的差异。它展示的是你即将通过 git commit 提交的所有内容。如果输出为空,说明暂存区干净,可以安全提交。
比较两个提交之间的差异
当你想查看项目历史中某两个版本之间的具体代码变动时,就需要比较提交。Git 支持多种灵活的方式来指定提交。
1. 比较两个明确提交
直接使用两个提交的哈希值(或分支、标签)。
git diff commit1 commit2
示例:比较提交 a1b2c3d 和 e4f5g6h 的差异。
git diff a1b2c3d e4f5g6h
2. 比较当前提交与另一个提交
使用 HEAD 指代当前提交。以下命令比较的是 HEAD 的父提交和 HEAD 之间的差异。
git diff HEAD^ HEAD
或者更简单地,查看上次提交带来的改变:
git diff HEAD^
3. 比较某个提交与它的父提交
这个技巧可以让你快速查看某次提交到底引入了什么变更。
git diff a1b2c3d^ a1b2c3d
或者使用更简洁的写法:
git diff a1b2c3d^!
4. 查看最近几次提交的整体差异
将 HEAD 与多个提交前的版本比较。
# 比较最近两次提交(HEAD^ 与 HEAD 之间的差异)
git diff HEAD^^ HEAD
# 更清晰的方法:比较当前提交与3个提交之前的版本
git diff HEAD~3 HEAD
比较工作区与任意提交的差异
有时你想知道,自己当前在工作区的未保存修改,相对于过去某个历史版本究竟变了多少。
git diff <commit>
这个命令比较 工作区 和 指定的提交。它不会考虑暂存区的状态,只看你实际编辑了哪些内容。例如,查看工作区相对于上一次提交的变更:
git diff HEAD
注意: 这与 git diff 不同。如果暂存区为空,它们效果相同;但如果暂存区里有东西,git diff 显示的是工作区 vs 暂存区,而 git diff HEAD 显示的是工作区 vs 最新提交,把暂存区里的改动也包含在内了。
限定比较范围:只看特定文件
在所有上述比较场景中,你都可以在命令末尾添加文件路径,将差异范围限定到指定文件。
# 只查看 app.js 在工作区与暂存区之间的差异
git diff app.js
# 比较暂存区中 main.py 文件与最近提交的差异
git diff --staged main.py
# 比较两个提交中 docs/ 目录下的所有文件
git diff v1.0 v2.0 -- docs/
-- 是一个分隔符,用来明确后面的参数是文件路径而非提交名称。在处理文件名和分支名可能冲突时非常有用。
常用差异输出选项
git diff 的输出不仅可以阅读,还有许多参数帮你调整输出格式,提取更关键的信息。
简洁模式:只显示文件名与状态
光看代码改动细节太冗长?用 --name-status 只看哪些文件被增删改。
git diff --name-status HEAD^ HEAD
输出示例:
M src/main.c
A README.md
D old_script.sh
状态字母表示:M 修改,A 新增,D 删除。
仅显示文件名
如果你只需一个被修改文件的列表,使用 --name-only。
git diff --name-only HEAD~2 HEAD
统计概览
用 --stat 获得一个带增删行数统计的总结。
git diff --stat master feature-branch
输出类似:
app/config.py | 12 ++++----
src/utils.js | 5 +++--
2 files changed, 11 insertions(+), 6 deletions(-)
图形化差异工具
命令行输出的 diff 对初学者可能不够直观。你可以配置 Git 调用外部图形化差异工具。
常见的外部工具包括 meld、kdiff3、vimdiff 等。以配置 meld 为例:
git config --global diff.tool meld
配置完成后,使用 git difftool 代替 git diff,就会弹出图形界面进行比对。
git difftool HEAD^
同样,git difftool 支持所有 git diff 的参数。图形化工具让合并冲突、对比补丁变得一目了然,是提升效率的好帮手。
掌握 git diff 不仅仅是记住几个命令,更是理解了 Git 数据模型的精髓。现在,打开你的终端,用你自己的项目去亲手实验每一个命令,很快你就能精确地追踪代码的每一次呼吸。