如何在树中找到所有 "active" git 提交?

How to find all the "active" git commits in a tree?

我想获取目录树的“活动”git 提交的快照,这意味着 git 提交确实是构建的一部分,而不是已完全提交的提交被更新的提交取代。

我可以通过 运行 git blame 在每个文件上执行此操作并以这种方式提取提交,但在大型存储库中太慢而不实用。

git blame 所做的几乎是找到所需信息的唯一方法。但是,您 可以 稍微简化操作,这可能足以满足您的目的,也许速度也足够快。

记住,每次提交都有每个文件的完整快照。分支名称标识某些提交链中的 last 提交。所以当你有:

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

名称 branch 包含提交 H 的原始哈希 ID。在commit H中,有很多文件,每个文件都有很多行。这些文件采用它们在提交 H 中的形式,这就是它的全部内容 - 除了 提交 H 包含早期提交的哈希 ID G.

您可以使用哈希 ID 定位提交 G 并提取所有 它的 文件,并且当 G 中的文件与该文件完全匹配时在 H 中,这意味着 - 至少在 git blame 中 - G 中文件中的所有行都归因于 G,如果不是某些较早的提交的话。因此 GH 不同 的文件应归于 Hgit blame 命令在 line-by-line 基础上工作,将个别 归因于提交 H 如果它们不同,但也许出于您的目的,归因于整个文件到 H 就足够了。

如果您决定该文件应该归因于提交 G,现在是时候从提交 G 中提取提交 F 的哈希 ID,并使用它从提交 F 中读取所有文件。如果 F 中的任何给定文件与 G 中的副本匹配,则属性移回 F;否则它保持在 G.

您必须重复此过程,直到 运行 完全没有提交:

A <-B <-C ... <-H

由于提交 Ano 父级,A 中的所有文件在 last 提交归因于提交 A。但是,一旦将 H 中存在的所有文件完全归因于链中稍后的某个提交,就可以停止向后遍历。将此与 git blame 进行比较,只要至少有一个 归因于某个较早的提交,它就必须继续向后看:您可能会在 git blame 之前很久就停下来必须。

此外,由于 Git 的内部数据结构,可以非常快速地判断某个较早提交中的文件是否与较晚提交中的同名文件完全匹配:每个文件中的每个文件提交由哈希 ID 表示。如果哈希 ID 相同,则文件内容在两次提交中 bit-for-bit 相同。如果不是,他们就不是。

没有方便的 in-Git 命令来完全按照您的意愿执行操作,1 如果您打算像这样遍历历史,则必须决定要做什么做合并。请记住,合并提交有一个快照,但与 non-merge 不同,它有 两个或更多 个父项:

...--o--K
         \
          M--o--o--...--o   <-- last
         /
...--o--L

如果 M 中的文件与 K and/or L 中的一个或多个文件匹配,您应该遵循哪个提交? git log 命令有它自己的方法来做到这一点——git log <start-point> -- <path> 将通过跟踪一个父代来简化历史,该父代是从一组这样的父代中随机选择的,它对给定文件具有相同的哈希 ID。

请注意,您可以使用 git rev-list,或许与 --parents 一起使用来生成您可以选择检查的哈希 ID 集。 rev-list 命令是大多数其他 Git 命令的主力,包括 git blame 本身,用于跟踪这样的历史。 (注意:git log 命令是从与 git rev-list 相同的源构建的,有一些小的 command-line-option 差异和不同的默认输出。)


1这里虽然git log <start-point> -- <path>有用,但是运行每条路径都这样一次就太慢了,而且运行 它没有给出单独的路径。