如何在多个标签上过滤git日志



在我提交到master之后,我运行了几个标记提交的CI,它们成功完成了提交。假设我有两个CI单元测试和集成测试,它们都在提交时创建标记。假设unittest-signoff/{number}integrationtest-signoff/{number},其中{number}是自动递增数,以确保唯一性。

如果我执行git log -n1 --tags="unittest-signoff",这将给我最近的提交,它已经从单元测试中注销。与git log -n1 --tags="integrationtest-signoff"相同

我的问题是,什么命令会给我同时具有两个标记的最新提交。

git log允许您选择要查看的装饰,因此这应该是:

git log --no-walk --tags  --pretty=%H %d --decorate-refs=refs/tags/*-signoff 
| grep integrationtest-signoff | grep -m1 unittest-signoff

我本以为git会为此做好准备,但我没有找到。尽管如此,我仍然相信我不知何故错过了它,也许是使用了一些我不知道的glob模式?这是另一种方法:

git rev-list --all | while read cmt
do
cmt_tags=""
while read tag
do
cmt_tags+="$(echo "$tag" | awk -F'/' '{ print $1; }') "
done <<< "$(git tag --points-at "$cmt" "integrationtest-signoff/*" "unittest-signoff/*")"

test "$cmt_tags" = "integrationtest-signoff unittest-signoff " && echo "$cmt" && break
done

假设您正在标记master分支,我基本上会遍历每个提交,直到找到同时带有这两个标记的提交。git tag --points-at按字母顺序返回所有标签(这就是我观察到的),但我不想要/之后的部分,所以我只使用awk的第一个标记。由于提供给git tag的模式,我确信它只返回那些与模式匹配的标签,最后我只需将cmt_tags字符串与预期字符串进行比较,并在找到提交后立即将break进行比较。

我想说,不是很优雅,但足够简单,可以解决你的问题。


@torek提出了一个有趣的使用git for-each-ref的性能增强。上一个脚本的第一行可以替换为:

git for-each-ref --format="%(committerdate)|%(objectname)" --sort=-committerdate "refs/tags/integrationtest-signoff/*" "refs/tags/unittest-signoff/*" | sort -u -r | awk -F '|' '{ print $2; }' | while read cmt

现在,我不再循环提交,而是只循环特定的标记提交。当然,性能取决于有多少提交被标记为integrationtest-/unittest-

[编辑:我可能误解了这个问题。请参阅Marco Luzzara的答案,找到一种方法来查看不同解释的答案。]

考虑--no-walk标志到git log,例如git log --no-walk tag1 tag2

等等,我用的是-n 1,不是一样的吗

没有。CCD_ 19和CCD_。git log-n参数告诉它在打印一些修订后完全退出。对于-n 1,一旦git log显示一个特定的提交,它就会退出。

git log工作方式是这里的关键。运行时:

git log [options] starting-point-1 starting-point-2 starting-point-3

git log命令将三个选定的起始点提交插入队列(特别是优先级队列,尽管我们在这里不担心优先级部分)。尝试在名称(例如分支名称、远程跟踪名称或标记名称)上运行git rev-parse

$ git rev-parse origin/maint
48bf2fa8bad054d66bd79c6ba903c89c704201f7
$ git rev-parse v2.23.0
cb715685942260375e1eb8153b0768a376e4ece7

这些散列ID——第二个实际上是标记散列ID,而不是提交的散列ID,但git log知道如何处理它——可以充当";起点";对于CCD_ 29。或者,给定没有起始点,git log使用git rev-parse HEAD或等效方法来查找要插入到该队列中的提交哈希ID,这样队列中只有一个提交。如果您为git log提供一个提交说明符,则该提交就是进入队列的提交。

一旦队列准备就绪——通过命令行起始点,或者通过使用HEADgit log——真正的工作就开始了。

git log的实际工作,作为一个循环,一遍又一遍地运行

此时,git log开始从队列中取出一个提交。如果队列中只有一个提交,那么该队列现在是空的。如果队列已经为空,git log现在退出,因为没有什么可取出的。

从队列中取出提交后,git log现在从Git保存所有提交的大数据库中取出提交。它检查提交。如果您提供了git log选项,这些选项可能会决定是否打印提交。如果您给没有选项,git log现在应该打印提交。

如果git log应该打印提交,git log现在打印提交。如果存在-n限制,则会递减剩余计数,当其变为零时,git log会立即退出。如果没有-n,或者数量足够大,我们就会继续前进。

在任何情况下git log现在都有选项将提交的父提交放入队列。此选项是默认选项。普通提交只有一个父级,因此对于大多数提交,这会将一个父项放入队列中。合并提交有两个或多个父级,通常只有两个,因此对于合并提交,这会将所有父级放入队列中。

这就完成了真正的工作。现在我们回到循环,以便继续处理队列。

在大多数情况下,这会产生你习惯看到的东西

假设我们有一个很好的简单线性提交字符串,以当前提交结束,即HEAD,位于的当前分支上,如下所示:

... <-F <-G <-H   <-- main (HEAD)

在没有参数的情况下运行git log可以让Git确定哪个提交是当前的提交,即提交H。队列中有一个提交。

日志程序现在从变为空的队列中提取一个提交。那就是提交H。它打印提交H的内容,并将H的父级G放入队列中。队列中现在有一个提交。

日志程序现在从变为空的队列中提取一个提交。这一次是提交G,所以git log打印G的内容,并将G的父级F放入队列中。

对于F重复此操作,这将导致返回另一个提交,git log将打印该提交,依此类推——一直到第一个提交,该提交没有父级。此时,git log已超出队列并停止。

--no-walk选项,第1部分

使用--no-walk,我们指示git log在其处理队列外提交步骤中,将无父项放入队列。如果我们将其与我们的沼泽标准git log一起使用,当前分支为main,当前提交为提交H,那么会发生什么很简单:

  • git logHEAD,即H放入队列
  • git logH弹出队列
  • git log打印提交H,并且不向队列中放入任何内容
  • 并且队列现在是空的并且CCD_ 75退出

-n 1选项的比较,第1部分

-n 1和一个起点,对打印内容没有限制:

  • git logHEAD,即H放入队列
  • git logH弹出队列
  • git log打印提交H并将其父G放入队列,但已打印一个提交,因此退出

此处的输出与相同。

与例如git log --no-walk HEAD HEAD~2进行比较

在这里,我们给了git log两个提交以放入队列:HEADH,以及HEAD~2F

  • git log从队列中弹出其中一个提交——可能是H
  • git log打印此提交,但不添加父项
  • git log从队列中弹出剩余的提交——可能是F
  • git log打印此提交,但再次不添加父项

并且队列现在是空的,所以我们打印这两个提交并退出。

使用-n 2是否有效

试试HEAD HEAD~2。我们从队列中的HF开始。让我们进一步假设队列顺序是这样的,最新的提交总是首先打印(这是默认的)。因此:

  • git logH弹出队列并打印出来,将G放入队列
  • git log从队列中弹出G——与F相比,它是最新的——并打印它

这是允许打印的两个提交,因此它现在退出。它根本没有打印提交F

结论:--no-walk是这方面的标志

如果您希望git log只打印您在命令行上指定的提交,那么,这正是--no-walk的用途。把它用于它设计的目的,你就完了。

这就是我在纯bash:中想到的

comm -12 <(git log --no-walk --tags=unittest-signoff --format="format:%H %ct"|sort) <(git log --no-walk --tags=integrationtest-signoff --format="format:%H %ct"|sort) | sort -k 2 -r | head -1 | cut -d ' ' -f 1

分解:

git log --no-walk --tags=unittest-signoff --format="format:%H %ct"

打印带有提交时间戳的哈希。CCD_ 112,因为CCD_。在comm找到两个标签集之间的公共散列后,根据时间戳再次sort,最后headcut从两个标签集中获得最近的提交。

[编辑]仍需--no-walk

最新更新