gpt4 book ai didi

git - 如何列出未包含在任何分支中的提交中的所有标签?

转载 作者:行者123 更新时间:2023-12-05 02:48:17 25 4
gpt4 key购买 nike

我们有一堆存储库,其中许多提交不包含在任何分支中,但仅由于标记而保持事件状态。我想列出所有这些标签。还没有弄清楚,如何做到这一点。有没有人有想法,如何实现?

最佳答案

标签不是来自 提交,它们只是指向 提交。但是你的问题确实有答案——只是措辞有点奇怪。更准确的措辞让我们找到了答案:

How, for each tag, can I test whether the commit the tag identifies is contained within any branch?

因此我们想对每个标签进行操作并进行一些测试。有枚举每个标签的命令。出于脚本目的,git for-each-ref 是最好的1 工具。所以我们开始:

git for-each-ref refs/tags

它打印出所有标签(到它的标准输出)以及关于每个标签的目标的额外信息:

$ git for-each-ref refs/tags
04c6e9e9ca34226db095bbaa1218030f99f0b7c6 commit refs/tags/a
d5aef6e4d58cfe1549adef5b436f3ace984e8c86 tag refs/tags/b

例如。 a 标签直接进入提交,即是一个轻量级标签; b 标记转到带注释的标记对象。

这还不是解决方案,但它让我们到达了那里。接下来我们要做的是找出带注释的标记的目标是否是提交对象,如果是,则找到提交对象的哈希值。事实证明 git for-each-ref 本身可以做到这一点,使用 --format 指令 %(*objecttype)%(*对象名称)。令人恼火的是,当标签是轻量级标签时,这些 %(*...) 指令什么都不会,这需要一些小技巧:

git for-each-ref \
--format='%(refname) %(objecttype) %(objectname) %(*objecttype) %(*objectname)' \
refs/tags

(出于发布目的,我已将其分成多行;在脚本中,我们可以只有一个长行而没有反斜杠换行符序列)。

这会生成一系列行作为其输出,每行三列或五列。前三列是引用名称、对象类型(可能是“标签”)、初始标签哈希 ID,如果存在最后两列,则是目标类型和最终目标 ID。我们需要将这些提供给 shell 脚本:

git for-each-ref \
--format='%(refname) %(objecttype) %(objectname) %(*objecttype) %(*objectname)' \
refs/tags |
while read name dtype dobj itype iobj; do
...
done

现在,在 ... 部分,我们实现测试:直接或间接对象是提交,如果是,是否可以通过任何分支名称访问它?

“对象是否提交”测试非常简单。不过,首先,让我们使用间接对象和名称(如果存在),否则使用直接对象和名称:

    if [ $dtype = tag ]; then
otype=$itype obj=$iobj
else
otype=$dtype obj=$dobj
fi

现在我们将跳过非提交对象:

    [ $otype == commit ] || continue

最后,我们将测试是否可以从某个分支名称访问对象的哈希 ID:

    n=$(git for-each-ref refs/heads --contains $obj | wc -l)

for-each-ref 打印出到达给定对象的每个分支名称(以及 for-each-ref 通常的其他数据)。我们不关心实际名称,只关心是否有 任何名称,所以让我们计算内部 for-each-ref 打印了多少行。如果它为零,则此标记使此提交保持事件状态,所以让我们打印标记:

    if [ $n -eq 0 ]; then
echo "tag $name keeps $obj alive"
fi

当我们运行整个过程时,有一个小缺陷:例如打印 tag refs/tags/a。我们可以通过在初始 --format 中使用 %(refname:short) 来解决这个问题,我们将得到 tag a

因此,最终脚本如下:

git for-each-ref --format='%(refname:short) %(objecttype) %(objectname) %(*objecttype) %(*objectname)' refs/tags |
while read name dtype dobj itype iobj; do
if [ $dtype = tag ]; then
otype=$itype obj=$iobj
else
otype=$dtype obj=$dobj
fi
[ $otype == commit ] || continue
n=$(git for-each-ref refs/heads --contains $obj | wc -l)
if [ $n -eq 0 ]; then
echo "tag $name keeps $obj alive"
fi
done

(我已经将它添加到 GitHub here。该脚本可以进行一些改进以使其采用 Git 选项等,但现在我不太在意。它也很慢,这可能是通过将其编写为非常简单的 shell 脚本以外的东西来改进,但请参阅前面的评论。)


1Best 是那些难以衡量的事物之一,但至少发现它是最好的。

关于git - 如何列出未包含在任何分支中的提交中的所有标签?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64620708/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com