有没有办法比较所有分支的文件?

Is there a way to compare a file over all branches?

我知道我可以使用 git diff 检查两个指定分支中某个文件的差异。
可以在一个命令中对所有分支完成吗?
它是否也包括已删除的分支?

Can it be done for all branches in a single command?

没有

Would it also include the deleted branches?

没有

重要的是要认识到,在某种意义上,Git 并没有真正的 分支 。 (不过,在其他一些意义上,它确实如此。)Git 拥有的是 分支名称 。它们并不像人们最初想象的那么重要,尽管它们确实很重要。

Git 的真正意义在于提交。这与 files 无关,尽管提交包含文件;这与 分支名称 无关,尽管分支名称标识了特定的提交。 Git 就是关于 提交 。当你 运行 git diff <em>br1 br2</em> 时,你是在告诉 Git 到 运行两个特定 提交的差异 .

每次提交都会存储 Git 知道的所有文件的完整快照,或者更确切地说,在您或任何人进行该提交时知道的所有文件。这是每次提交的主要数据。每个提交还存储一些 元数据 ,或有关提交本身的信息,例如提交人(姓名和电子邮件地址)、时间(日期和时间戳)以及原因(他们的日志提交消息)。

提交已编号,但数字是 random-looking 哈希 ID,而不是简单的计数数字。哈希 ID 实际上完全是 随机的,因为它们是提交中 data-and-metadata 的加密校验和。 Git 通过散列 ID 查找提交:存储库中有一个很大的 对象数据库 ,对象由这些散列 ID 编号。 (提交是此对象数据库中的四种对象类型之一。)

因为哈希 ID 校验和,任何提交的任何部分都不能更改。您主要将 new 提交添加到存储库。 (提交 可以 被遗忘,但仅在特定条件下。)

每个提交都将哈希 ID(有时是哈希 ID,复数)作为其元数据的一部分存储其前一个提交的哈希 ID。这样,Git 可以从 last 提交(某个分支的)开始并向后工作,一次提交一个:

... <-F <-G <-H

这里 H 代表某个提交链的 last 提交的哈希 ID。在提交 H 中,Git 可以从对象数据库中读出,其中有较早提交 G 的哈希 ID。这让 Git 在对象数据库中找到 G;在那个对象里面有早期提交的哈希 ID F。这让 Git 找到 F,它有另一个哈希 ID,等等。这 历史,在 Git 存储库中。

但这给 Git 留下了一个问题。如何快速轻松地找到 last 提交的哈希 ID?例如,在上面,Git 将在哪里找到哈希 ID H?

一个分支名解决了这个问题。每个名称都包含一 (1) 个哈希 ID,根据定义,这是链中的 last 提交。因此,如果 master 持有哈希 ID H,我们有:

...--F--G--H   <-- master

如果有另一个分支名称,则该分支名称包含某个提交的哈希 ID——可能是 H,可能是 GF,或者可能是 [= 之后的某个提交=17=]。也许 develop 持有某个提交 I 的哈希 ID,其父项是 G:

...--F--G--H   <-- master
         \
          I   <-- develop

所以现在名字 master 和名字 develop 各自挑出一个特定的提交。

您可以 运行 git diff 并为其提供原始哈希 ID;或者你可以 运行 它并给它分支名称。当你给它分支名称时,Git 只是查找名称并找到哈希 ID,然后 运行 计算两个哈希 ID 的差异。

所以:

Is there a way to compare a file over all branches?

是:枚举所有有趣的提交,然后 运行 git diff 以任何你喜欢的方式。例如:

git for-each-ref --format='%(refname:short)' refs/heads

将打印(到标准输出)每个分支名称,以缩写形式(masterdevelop 等,而不是它们的全名,refs/heads/masterrefs/heads/develop, 等等).

要将提交 C1 中的特定文件的快照与某个提交 C2 中的快照进行比较,您可以使用:

git diff C1 C2 -- path/to/file

-- 之后的 pathspec 参数将 diff 限制为仅那个文件。 (-- 本身在这里是可选的;出于习惯使用它通常是个好主意,以避免在使用更复杂的 git diff 时出现歧义。)

如果您想比较(比如说)由名称 master 标识的提交中的快照与由名称 develop 标识的提交中的快照:

git diff master develop -- path/to/file

会完成这项工作。因此,如果您想一次比较 master 中的提交与每个分支中的提交:

git for-each-ref ... |
    while read branch; do
        git diff master $branch -- path/to/file
    done
例如,

就可以了。如上所示填写for-each-ref

请注意 for-each-ref 将打印 master,因此您将 运行ning 一个 git diff master master -- path/to/file,这将逐字比较 [=24= 的提示提交] 给自己。该文件将匹配,这意味着 git diff 将不打印任何内容,但是这个 有点浪费。如果是你不喜欢这种浪费,添加代码来测试 $branch 是否为 master 如果是,则跳过 git diff 步骤(但请注意,此测试本身也增加了一些计算每个 other 名字的工作有点浪费:TANSTAAFL1).


1世上没有免费的午餐