使用 git diff 比较变更

比对功能接受两个输入数据集并输出它们之间的变更。git diff 是一个多用途 Git 命令,它在执行时会在 Git 数据源上运行比对功能。这些数据源可以是提交、分支、文件等。本文档将讨论 git diff 的常见调用和比对工作流模式。git diff 命令通常与 git statusgit log 一起使用,用于分析 Git 代码存储库的当前状态。

读取比对:输出

原始输出格式

以下示例将在一个简单的代码存储库中执行。代码存储库是使用以下命令创建的:

$:> mkdir diff_test_repo
$:> cd diff_test_repo
$:> touch diff_test.txt
$:> echo "this is a git diff test example" > diff_test.txt
$:> git init .
Initialized empty Git repository in /Users/kev/code/test/.git/
$:> git add diff_test.txt
$:> git commit -am"add diff test file"
[main (root-commit) 6f77fc3] add diff test file
1 file changed, 1 insertion(+)
create mode 100644 diff_test.txt

如果我们此时执行 git diff,则不会有输出。这是可以预见的,因为比对代码存储库没有变更。创建代码存储库并添加了 diff_test.txt 文件后,我们可以变更该文件的内容以开始尝试比对输出。

$:> echo "this is a diff example" > diff_test.txt

执行此命令将变更 diff_test.txt 文件的内容。修改后,我们可以查看比对并分析输出。现在执行 git diff 将生成以下输出:

diff --git a/diff_test.txt b/diff_test.txt
index 6b0c6cf..b37e70a 100644
--- a/diff_test.txt
+++ b/diff_test.txt
@@ -1 +1 @@
-this is a git diff test example
+this is a diff example

现在我们来看看比对输出的更详细细分。

1. 比较输入

diff --git a/diff_test.txt b/diff_test.txt

此行显示比对的输入源。我们可以看到 a/diff_test.txtb/diff_test.txt 已被传递给比对。

2. 元数据

index 6b0c6cf..b37e70a 100644

此行显示一些内部 Git 元数据。您很可能不需要此信息。此输出中的数字对应于 Git 对象版本哈希标识符。

3. 变更标记

--- a/diff_test.txt
+++ b/diff_test.txt

这些行是为每个比对输入源分配符号的图例。在这种情况下,来自 a/diff_test.txt 的变更用 --- 标记,而来自 b/diff_test.txt 的变更则用 +++ 符号标记。

4. 比对区块

剩下的比对输出是比对“区块”的列表。比对仅显示文件中变更的部分。在我们当前的示例中,我们只有一个区块,因为我们正在处理一个简单的场景。区块有自己的精细输出语义。

@@ -1 +1 @@
-this is a git diff test example
+this is a diff example

第一行是区块标头。每个区块前面都有一个包含 @@ 符号的标头。标头的内容是对文件所做变更的摘要。在我们的简化示例中,我们有 -1 +1,表示第一行发生了变更。在更真实的比对中,您会看到一个标头,如下所示:

@@ -34,6 +34,8 @@

在此标头示例中,从第 34 行开始提取了 6 行。此外,从第 34 行开始,还添加了 8 行。

比对区块的其余内容显示最近的变更。每个变更的行前面都有一个 +- 符号,表示变更来自哪个版本的比对输入。正如我们之前讨论的那样,- 表示与 a/diff_test.txt 相比发生的变更,+ 表示与 b/diff_test.txt 相比发生的变更。

突出显示变更

1. git diff --color-words

git diff 还有一个特殊模式,用于以更好的粒度突出显示变更:-‐color-words。此模式按空格对添加和删除的行进行标记,然后比对这些行。

$:> git diff --color-words
diff --git a/diff_test.txt b/diff_test.txt
index 6b0c6cf..b37e70a 100644
--- a/diff_test.txt
+++ b/diff_test.txt
@@ -1 +1 @@
this is agit difftest example

现在,输出仅显示已变更的用颜色编码的字。

2. git diff-highlight

如果您克隆 git 源代码,就会发现一个名为 contrib 的子目录。它包含了一大堆与 git 相关的工具以及其他尚未升级为 git core 的有趣内容。其中一个是名为 diff-highlight 的 Perl 脚本。diff-highlight 将匹配的比对输出行配对,并突出显示已变更的子字片段。

$:> git diff | /your/local/path/to/git-core/contrib/diff-highlight/diff-highlight
diff --git a/diff_test.txt b/diff_test.txt
index 6b0c6cf..b37e70a 100644
--- a/diff_test.txt
+++ b/diff_test.txt
@@ -1 +1 @@
-this is a git diff test example
+this is a diff example

现在,我们已经将比对缩减到尽可能小的变更。

比对二进制文件

除了我们到目前为止演示的文本文件实用程序外,git diff 还可以在二进制文件上运行。不幸的是,默认输出不是很有用。

$:> git diff
Binary files a/script.pdf and b/script.pdf differ

Git 确实有一个功能,允许您在执行比对之前指定一个 shell 命令将二进制文件的内容转换为文本。不过,它确实需要一些设置。首先,您需要指定一个 textconv 筛选器,描述如何将某种类型的二进制文件转换为文本。我们正在使用一个名为 pdftohtml 的简单实用程序(可通过自制软件获得)将我的 PDF 转换为人类可读的 HTML。您可以通过编辑您的 .git/config 文件为单个存储库设置此设置,或者通过编辑 ~ /.gitconfig 进行全局编辑

[diff "pdfconv"]
textconv=pdftohtml -stdout

然后,您需要做的就是将一个或多个文件模式与我们的 pdfconv 筛选器关联起来。您可以通过在存储库的根目录中创建 .gitattributes 文件来做到这一点。

*.pdf diff=pdfconv

配置完成后,git diff 将首先通过配置的转换器脚本运行二进制文件,然后对转换器输出进行比对。同样的技术可以用来从各种二进制文件中获得有用的比对,例如:zips、jar 和其他归档:使用 unzip-l(或类似文件)代替 pdf2html 将显示在提交图像之间添加或删除的路径:exiv2 可用于显示元数据变更,例如图像尺寸文档:存在用于将 .odf、.doc 和其他文档格式转换为纯文本的转换工具。必要时,字符串通常适用于不存在正式转换器的二进制文件。

比较文件:git diff 文件

可以向 git diff 命令传递明确的文件路径选项。文件路径传递给 git diff 时,比对操作的作用域将限定为指定文件。以下示例演示了这种用法。

git diff HEAD ./path/to/file

调用时,此示例的作用域为 ./path/to/file,它会将工作目录中的具体变更与索引进行比较,显示尚未暂存的变更。默认情况下,git diff 将执行与 HEAD 的比较。在上面的 git diff ./path/to/file 示例中省略了 HEAD 具有同样的效果。

git diff --cached ./path/to/file

使用 --cached 选项调用 git diff 时,比对会将暂存的变更与本地存储库进行比较。--cached 选项与 --staged 同义。

比较所有变更

在没有文件路径的情况下调用 git diff 将比较整个存储库中的变更。以上是文件特定的示例,可以在没有的情况下调用 ./path/to/file 参数,并且在本地代码存储库中的所有文件中具有相同的输出结果。

自上次提交以来的变更

默认情况下,git diff 会显示自上次提交以来所有未提交的变更。

git diff

比较两个不同提交之间的文件

git diff 可以将 Git 引用传递给提交进行比对。一些示例引用包括 HEAD、标记和分支名称。Git 中的每个提交都有一个提交 ID,您可以在执行 GIT LOG 时获得这个提交 ID。您也可以将这个提交 ID 传递给 git diff

git log --pretty=oneline
957fbc92b123030c389bf8b4b874522bdf2db72c add feature
ce489262a1ee34340440e55a0b99ea6918e19e7a rename some classes
6b539f280d8b0ec4874671bae9c6bed80b788006 refactor some code for feature
646e7863348a427e1ed9163a9a96fa759112f102 add some copy to body

$:> git diff 957fbc92b123030c389bf8b4b874522bdf2db72c ce489262a1ee34340440e55a0b99ea6918e19e7a

比较分支

比较两个分支

像所有其他引用输入一样将分支与 git diff 进行比较

git diff branch1..other-feature-branch

此示例引入了点运算符。此示例中的两个点表示比对输入是两个分支的尖端。如果省略点并在分支之间使用空格,也会产生同样的效果。此外,还有一个三点运算符:

git diff branch1...other-feature-branch

三点运算符通过变更第一个输入参数 branch1 来启动比对。它将 branch1 变更为两个比对输入之间共享的共同祖先提交引用,即 branch1 和其他功能分支的共享祖先。最后一个参数输入参数保持不变,就像其他功能分支的尖端一样。

比较来自两个分支的文件

要跨分支比较特定文件,请将该文件的路径作为第三个参数传递给 git diff

git diff main new_branch ./diff_test.txt

摘要

本页讨论了 Git 比对流程和 git diff 命令。我们讨论了如何读取 git diff 输出以及输出中包含的各种数据。提供了有关如何通过突出显示和颜色更改 git diff 输出的示例。我们讨论了不同的比对策略,例如如何比对分支中的文件和特定的提交。除了 git diff 命令外,我们还使用了 git loggit checkout

准备好了解 Git 了吗?

试用本交互式教程。

立即开始