有没有办法显示从 HEAD 到特定用户提交的 git 日志图?

Is there a way to show the git log graph from the HEAD to a commit that was made by a specific user?

我们的日常构建由自动用户完成,这将使用消息中的构建信息对回购进行空提交。

我想知道我是否可以:

  1. 从我当前所在的自动用户提交的回购中获取最后一个日志条目(或 n 日志条目)and/or
  2. 显示从 HEAD 到同一自动用户提交的图表,其中显示了在这期间完成的所有用户提交。

是否可以仅使用 git 命令,或者我是否必须进行一些外部处理?

编辑:我在下面添加了一些(长)背景,以供一般使用。

(要查找特定用户所做的提交,请使用 --author=。这适用于大多数 revision-walking 操作,因为它由 git loggit rev-list 和其他 Git 命令使用这些。)

考虑使用git log --ancestry-path --graph <em>[options]</em> <em>automated-commit</em>..HEAD,但有一些注意事项:

  • 在自动提交和 HEAD 提交之间可能没有 路径。
  • 如果有路径,如果 HEAD 提交在自动提交之后,它可能会走另一条路。

还要注意 Git 将省略边界 (stop-point) 提交——也就是说,在 A..B 中,Git 确实在做 B ^A,所以它包括提交 B 但不包括提交 A。如果你想提交 A 也包括在内,你有几个选择:

  • 为 stop-point 备份一个提交:使用 ^A^,假设 A 只有一个 parent,或者 ^A^@如果 A 可能是合并提交(A^@ 表示“A 的所有 parent,并且领先的 ^ 来自扩展 A..B 形式转换为其内部 B ^A 形式以在此处通用)。

  • 或者,使用 --boundary 让 Git 包含边界提交。根据我的经验,Git 倾向于添加太多边界提交,但是 --ancestry-path 可能会消除这种情况,因为 --ancestry-path 通过要求显示的提交具有 A 来增加通常的 A..B ]作为祖先。

(底线:只要有路径并且顺序正确,这就应该有效。让它真正有用并处理各种边缘情况更难。)

背景:git log 及其姐妹 git rev-list 是如何工作的

Git 中的提交是通过其真实名称(即它们的哈希 ID)已知和找到的。每个提交的哈希 ID 是一个丑陋的大字符串,例如 8a0ba68f6dab2c8b1f297a0d46b710bb9af3237a(即 a commit in the Git repository for Git itself。)每个 ID 都是唯一的:没有其他提交可以拥有此 ID。它们实际上不是随机的,但它们看起来是随机的并且对人类没有用,所以我们使用masterdevelop。 Git 保留一个 table,不断更新,例如,master 表示 8a0ba68f6...,等等。

使用这些 table 条目,我们说 master 指向 一些提交。假设 master 指向某个提交,我们已将其哈希 ID 缩短为一个大写字母,G:

G   <--master

(你马上就会明白为什么我把 master 放在右边)。

向分支添加新提交只会更新 name-to-hash-ID 映射:您创建一个新提交,Git 为其分配一个唯一的哈希 ID,如果您在 master, Git 更新 master 的 table 条目以保存新的哈希 ID:

H   <--master

这意味着某些分支名称指向的提交——存储在分支名称中的箭头——随时间变化。这就是 Git 找到该分支的最新提交的方式。根据定义,无论为该分支名称保存什么提交哈希,该提交 都是 该分支的尖端。

现在,每个提交 持有一定数量的 parent 哈希 ID——通常只有一个。 this 的意思是,给定一个 table 表示 *mastera1234...,并且一个提交 a1234... 表示 我的parent是0f987...,Git知道a1234...是master上的最新提交。 Git 然后 读取 提交 a1234... 以找到 second-latest master 上的提交,即 0f987....所以 master 指向最新的提交,a1234...,那个提交指向它的 parent,它的 parent 指向 grandparent,等等.

这意味着从结束开始,Git可以通过提交链向后工作:

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

名称 master 让 Git 找到提交 H,找到提交 G,找到 F,依此类推,通过历史向后.因此,History 只是 所有提交的字符串,从末尾开始向后计算。

特殊名称HEAD通常包含分支的名称。有两种相当明显的方式来绘制它,一种是 HEAD 指向分支名称,然后分支名称指向提交:

                      HEAD
                       |
                       v
... <-F <-G <-H   <--master

这在某些方面更准确,但不是很紧凑。为了紧凑,我喜欢省略提交本身内的箭头。这些永远不会改变(与分支名称箭头不同)——关于 any 提交的任何内容都不会改变。所以如果我们看到:

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

我们知道是H指向GG指向F,依此类推。然后我有来自 master 的箭头找到 H:

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

附加这个词HEAD表示这是当前分支,所以tha如果我们有更多的分支,我们可以看到发生了什么:

...--F--G--H   <-- master (HEAD)
         \
          I--J   <-- develop

在这里,我们有两个分支;名称 develop 指向提交 J,其 parent 是 I,这导致返回 GF 等等,而名称 master 指向 H,这又指向 GF 等等。

旁白:哪个分支是某个提交 "on"?

如果我们看上面的内容,我们可以说提交 Hmaster 上并且 Jdevelop 上。这很自然,因为这些名称直接指向那些提交。但是提交G,它在哪个或哪个分支上呢?

有些系统会选择一个答案并坚持下去。 Git 不同。 Git 表示 G 每个 可以到达 G 的分支上,所以它在 bothmasterdevelop。要从 master 到达 G,我们返回一跳。要从 develop 到达 G,我们返回两跳。无论哪种方式,我们降落在 G.

git loggit rev-list 只需跟随这些箭头

给定一些起点,例如 masterdevelop 甚至 HEADgit log 所做的是,简单地说:

  • 显示它现在的提交,不管是什么。
  • 继续 parent 提交。
  • 重复直到我们 运行 没有提交。

这个描述没有错误,但它缺少很多重要的细节。第一个并发症出现在合并中。让我们把 graph-so-far 和 合并 develop 回到 master,使用:

$ git checkout master
$ git merge develop

无需深入探讨 git merge 的工作原理——这是它自己单独的问题和答案(但已经问过很多次了)——我们最终得到了这张图:

...--F--G--H---K   <-- master (HEAD)
         \    /
          I--J   <-- develop

提交K是一个合并提交,这意味着它至少有两个 parent。 K 的两个 parent 是 H(和往常一样)和 J(因为我们合并了提交 J,通过名称 develop).

git log 显示提交 K 之后,它应该转到哪个提交?它可以选择任何一个。它真正做的是将 both 提交到一个队列中,然后选择一个并显示它并将那个 parent 放入队列,如果它还没有这样做的话。然后它从队列中选择另一个,并重复:

  • 最初,将命令行中列出的提交放入队列中。如果您没有指定任何特定的提交,git log 使用 HEAD。然后,在一个循环中:
    • 显示队列前面的提交。
    • 如果提交的 parent 尚未排队且尚未显示,请将它们全部放入队列中。
  • 重复循环直到队列为空(或用户退出)。

因为有一个队列,所以有一些魔法可以管理谁在前面。默认情况下,这由 sorting-by-date/time-stamp 处理,但您可以使用各种排序选项进行更改。

这意味着 Git 默认情况下 git log 首先 显示提交 K,然后 一个HJ,然后HI之一,然后另一个 HI,现在队列中只有 G,所以顺序很清楚(G 然后 F) .注意Git不经过J就不能到I,所以J肯定先于I出来,但是Git可以得到到 H 有两种方式,所以我们不知道 H 的确切位置。

对排队内容的限制 and/or 显示

无论你做什么,git loggit rev-list 总是 必须遍历这个优先级队列,选择下一个要显示的提交,添加parent 提交到队列,并循环。但是你可以控制添加了哪些parentand/or实际显示了哪些提交.

parents控制旋钮是:

  • --first-parent:这表示当步行代码遇到合并提交时,它应该只添加 first parent合并。在我们的示例中,合并提交 K 有两个 parent,第一个是 H,因此 --first-parentgit logK 走到 HG,忽略我们从侧分支合并的提交。

  • --no-walk:这表示行走代码不应该做任何事情:永远不要添加任何 parent。这使得循环很快停止:我们只看到命令行上列出的提交。

要显示的 旋钮要复杂得多,因为它们有很多。在这里,我将忽略所有面向 pathspec 的那些,只看 --author--committer,以及 --max-count / -n 数字。前两个告诉 Git:仅当列出了作者或提交者时才显示提交。(您可以列出多个 --author--committer;Git 将显示与您指定的任何名称匹配的提交。)

请注意,步行仍然基于图表。只是您没有看到 没有正确的作者或提交者的提交。

同时,--max-count 又名 -n 数字告诉 Git 它应该在 显示 一些提交后退出循环。例如,对于 -n 5 --author automatic@local,Git 将像往常一样遍历所有提交,显示由 automatic@local 创作的任何提交,但一旦显示五个这样的提交,就停止。当然commit少了会提前停止

何时使用 git loggit rev-list

git log命令就是Git所说的瓷器:它应该是干净、闪亮的,对用户有吸引力。因此,这是用户可以自定义的东西。您可以设置输出颜色、log.decorate 等选项以及其他(对人类)有用的项目。

git rev-list命令更加严格和乏味。这就是 Git 所说的 plumbing: 一个旨在产生不一定对人类有益但对其他 计算机程序有用的输出的程序.它的行为方式相同,无论 运行s 它是谁,因此需要 git rev-list 可以提供的某些信息的程序可以一致地获取它方法。 (如果你愿意,该程序可以继续变得很花哨 human-oriented。)默认情况下,git rev-list 产生的只是一系列提交哈希,它们是提交的哈希 ID同样的 git log 命令会显示。

无论出于何种原因,默认情况下 git log 将从 HEAD 开始,而 git rev-list 则不会。因此,要将 git log 命令(您正在测试以查看是否获得正确的提交)转换为 git rev-list 命令(您将在其他程序中使用),您有时需要将 HEAD 添加到参数中。

Get the last log entry (or n log entries) from where I am currently in the repo that was committed by that automated user

考虑 git log--author--committer 选项:

--author=<pattern>, --committer=<pattern>

Limit the commits output to ones with author/committer header lines that match the specified pattern (regular expression). With more than one --author=<pattern>, commits whose author matches any of the given patterns are chosen (similarly for multiple --committer=<pattern>).

因此,要显示 that-user 在您当前签出的分支上的最后 5 次提交,您可以

git log --pretty=fuller --author='that-user' -5