"git diff" 中的 "diff --git" 输出是指什么?

38

当我运行git diff时,输出以以下内容开头:

diff --git a/foo/bar b/foo/bar

如果我尝试运行普通的diff --git,会提示--git选项不存在(显然,我猜想,对于一个低级工具来说知道特定的DVCS似乎很愚蠢)。在man页面中也没有提到它。这个选项从哪里来?


1
Git 包含这些命令的方式确实很奇怪,让人感到困惑。 - Paul Stelian
4
特定的输出已经添加在这里:https://github.com/git/git/commit/b58f23b38a9a9f28d751311353819d3cdf6a86da,其原因可以在此链接中找到:http://www.gelato.unsw.edu.au/archives/git/0505/3812.html(请注意,该链接为英文网页)。 - nos
有人删除了它,但我最初添加了一个 osx 标签来表示这是 macOS 附带的 diff 工具,而 GNU 工具可能会有所不同。 - JHZ
3个回答

27

这是一个"虚拟差异选项",用于向读者表明它不仅仅是运行diff命令的输出。例如,在git自己的git存储库中:

$ git diff HEAD~1..HEAD | head
diff --git Documentation/git.txt Documentation/git.txt
index bd659c4..7913fc2 100644
--- Documentation/git.txt
+++ Documentation/git.txt
@@ -43,6 +43,11 @@ unreleased) version of Git, that is available from the 'master'
 branch of the `git.git` repository.
 Documentation for older releases are available here:

+* link:v2.10.0/git.html[documentation for release 2.10]
+
$ 

如果你使用相同的文件名称两次调用diff命令,它本身将不会显示任何差异。git假设会创建与Documentation/git.txt的两个不同版本相对应的临时文件,并将它们提供给diff -- 但是这些临时文件的名称并没有用处。我认为git diff会修改diff的输出以使其对读者更有意义。(这种推测并不完全正确,请参见下文。

深入研究git源代码,可以发现diff.c中硬编码了字符串字面值"diff --git"

strbuf_addf(&header, "%s%sdiff --git %s %s%s\n", line_prefix, meta, a_one, b_two, reset);

查看历史记录以找到包含该字符串的最早版本:diff.c

$ git log -n 1 b58f23b3
commit b58f23b38a9a9f28d751311353819d3cdf6a86da
Author: Junio C Hamano <junkio@cox.net>
Date:   2005-05-18 09:10:47 -0700

    [PATCH] Fix diff output take #4.

    This implements the output format suggested by Linus in
    <Pine.LNX.4.58.0505161556260.18337@ppc970.osdl.org>, except the
    imaginary diff option is spelled "diff --git" with double dashes as
    suggested by Matthias Urlichs.

    Signed-off-by: Junio C Hamano <junkio@cox.net>
    Signed-off-by: Linus Torvalds <torvalds@osdl.org>
$ 

假设 <Pine.LNX...> 是邮件列表中某封电子邮件的消息ID。无论如何,此提交消息表明 diff --git 是一种“虚拟差异选项”。

这封电子邮件由nos在评论中引用,似乎是导致此事的讨论的一部分。

更新: 我之前猜测 git diff 会编辑 diff 的输出并添加此信息。我刚刚尝试在 strace 下运行 git diff 。它实际上未调用diff或其他任何命令。相反,所有输出都由git进程本身打印,并且显然它会在内部计算差异。此行为还可能取决于git版本(我使用的是2.23.0),可用的 diff 命令以及所使用的参数。

我注意到GNU diff有一个--label = LABEL 选项,可以用于此类操作:

'-L LABEL'
'--label=LABEL'
     Use LABEL instead of the file name in the context format (*note
     Context Format::) and unified format (*note Unified Format::)
     headers.  *Note RCS::.

但是git diff似乎没有使用它,至少在我尝试的一种情况下,并且我在git源代码中也没有看到对它的引用。

但是 git diff 没有使用它,在我尝试过的一个案例中也没有看到在git源代码中对它的引用。

3
--git 表示 diff 是以 "git" 的格式进行的。它并不是 /usr/bin/diff 命令的选项。您可以在diff格式文档列表中找到其他格式包括:
  • diff --combined
  • diff --cc
  • diff --summary

1

正如Keith所提到的,在GNU diff中(使用diff -v检查您的版本),您可以通过这样使用--label来获得类似于Git风格的补丁:

从备份中恢复单个文件

diff -u --label a/path/to/file.ext --label b/path/to/file.ext path/to/file.ext~ path/to/file.ext

或从标准输入读取。
command_that_outputs_previous_version | diff -u --label a/path/to/file.ext --label b/path/to/file.ext - path/to/file.ext

您可以在循环文件时使用这些命令,例如来自find等。当比较的一侧不存在时,例如新文件,请与/dev/null进行比较。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接