git diff --check 显示不相关的变化 branch/files

git diff --check shows changes of unrelated branch/files

背景

我正在尝试查看当前分支的空白错误(忽略 CR 在停产)。大多数文件使用 CRLF,而我没有 core.whitespace 配置集。

这是原始命令:

git -c core.whitespace=trailing-space,cr-at-eol diff --check master..HEAD

HEAD 指的是在 master 的旧版本之上创建的分支 ("老大师").

问题是 git diff --check 的行为异常:它是 不仅显示 master..HEAD 中的错误,还显示 老大师..大师

问题

信息

master vs oldmaster(数字巧合):

$ git log --oneline oldmaster..master | wc -l
115

$ git diff --name-only oldmaster..master | wc -l
115

这正确显示了相关提交:

$ git log --oneline master..HEAD | wc -l
4

这显示了正确的文件:

$ git log --oneline --name-only master..HEAD -- | grep -E '^[a-zA-Z]+/' \
  | sort -u | wc -l
4

出于某种原因,这些还包括在 oldmaster..master 中更改的文件:

$ git diff --name-only master..HEAD -- | wc -l
119

$ git -c core.whitespace=trailing-space,cr-at-eol diff --name-only \
  master..HEAD -- | wc -l
119

这两个也显示不相关的文件:

$ git diff --check master..HEAD -- | grep -E '^[a-zA-Z]+/' | cut -d : -f 1 \
  | sort -u | wc -l
30

$ git -c core.whitespace=trailing-space,cr-at-eol diff --check master..HEAD \
  -- | grep -E '^[a-zA-Z]+/' | cut -d : -f 1 | sort -u | wc -l
9

除了组合差异(你在这里没有使用),git diff严格比较两个快照1使用的语法——git diff A B vs git diff A..B——在这里无关紧要。 Git 提取快照 A,提取快照 B,然后比较这两个快照。您使用的任何标志选项,例如 --check,都会应用于此特定比较。提交 A 不一定是 B 的祖先,反之亦然; Git 不查看任何提交 "between" 这两个提交;它只是提取 A,然后提取 B,然后比较它们。2

git log 命令做了一些非常不同的事情:它遍历修订图。给定 git log A..B,Git 找到所有 可从 B 到达但不能 可从 [=14 到达的提交=].有关可达性的明确定义,请参阅 Think Like (a) Git.

请注意,当使用 -pgit log 将提交视为补丁时,git log 会将每个提交与其(单个)父级进行比较。如果在 A..B 范围内有三个提交,例如 git log -p A..B 首先显示 B 并运行 git diff B^ B,然后显示 B^ 并运行 git diff B^^ B^,最后显示 B^^ 并运行 git diff B^^^ B^^。 (这假设范围内没有合并提交,但是 git log 默认情况下忽略合并提交的补丁。)


1要查看合并的差异,请在合并提交上使用 git showgit diff 命令也会产生带有某些特定参数的组合差异,有时是不正确的:特别是 three-dot 语法,git diff A...B,是为了比较合并AB 的基础以提交 B,但有时会做一些不同的事情。此外,当您使用索引并且索引包含冲突合并时,普通 git diff 将产生组合差异。

2从技术上讲,它甚至不必提取这两个快照——它直接从它们的树对象中工作。它确实必须提取不同的斑点,以计算差异。对于相同的 blob,git diff 知道它们是相同的,因为它们的哈希 ID 匹配。但更容易理解为 "extract and compare".