2

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

如果我执行git log -n1 --tags="unittest-signoff"这将给我已经从单元测试中签名的最新提交。同样适用git log -n1 --tags="integrationtest-signoff"

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

4

4 回答 4

3

git log让您选择要查看的装饰,因此应该可以:

git log --no-walk --tags  --pretty=%H\ %d --decorate-refs=refs/tags/*-signoff \
| grep integrationtest-signoff | grep -m1 unittest-signoff
于 2021-04-24T03:44:31.937 回答
1

我预计 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-

于 2021-04-23T23:33:29.177 回答
0

这就是我想在纯 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"

打印带有提交时间戳的哈希。sort因为comm需要排序输入。在comm找到两个标签集之间的公共哈希后,sort他们再次根据时间戳,最后headcut从两个标签集中获取最近的提交。

[编辑] 仍然需要--no-walk

于 2021-04-24T02:09:49.503 回答
0

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

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

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

--no-walk不,和之间有天壤之别-n 1-n参数git log告诉它在打印一些修订后完全退出。使用-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知道如何处理它——可以作为git log. 或者,在没有起点的情况下,git log使用git rev-parse HEAD或等效项来查找要插入此队列的提交哈希 ID,以便队列中只有一个提交。如果你给git log 一个提交说明符,那就是进入队列的一个提交。

一旦队列被启动——通过你的命令行起点,或者通过git log使用HEAD——真正的工作就开始了。

的真正工作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 找出哪个提交是当前提交,即 commit H。队列中有一个提交。

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

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

这重复 for F,这导致另一个提交,git log打印,等等 - 一直到第一个提交,它没有父母。那时git log队列已用完并停止。

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

有了--no-walk,我们指示git log处理提交离开队列的步骤中,不要将父母放入队列中。如果我们将它与我们的沼泽标准git log一起使用,当前分支是main并且当前提交是 commit H,发生的事情很简单:

  • git logHEAD, 即 ,H放入队列中;
  • git log退出H队列;
  • git log打印提交H并将任何内容放入队列;
  • 队列现在为空并git log退出。

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

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

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

这里的输出是一样的

比较,例如,git log --no-walk HEAD HEAD~2

在这里,我们给出了git log 两个提交放入队列:HEADor H, and HEAD~2or F

  • git log将其中一个提交(可能)H从队列中弹出;
  • git log打印这一提交,但不添加父母;
  • git log将剩余的提交(可能F)从队列中弹出;
  • git log打印此提交,但再次不添加父母;

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

会使用-n 2工作吗?

试试看HEAD HEAD~2。我们从队列H开始F。让我们进一步假设队列顺序总是最先打印最新的提交(这是默认值)。所以:

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

这些是允许打印的两个提交,所以它现在退出了。它根本没有打印提交F

结论:--no-walk是为此目的的标志

如果您只想git log打印您在命令行上指定的提交,那么这正是您想要--no-walk的。将其用于其设计目的,您就完成了。

于 2021-04-24T00:03:09.097 回答