我们有很多仓库,其中许多提交不包含在任何分支中,但仅因为标记而保持存活。我想列出所有这样的标记。还没有找到如何实现此目标的方法。是否有任何想法可以帮忙?
我们有很多仓库,其中许多提交不包含在任何分支中,但仅因为标记而保持存活。我想列出所有这样的标记。还没有找到如何实现此目标的方法。是否有任何想法可以帮忙?
标签并非来自提交,而只是指向提交。但是你的问题确实有答案——只是措辞有点奇怪。更准确的措辞将引导我们得出答案:
对于每个标签,如何测试标签所标识的提交是否包含在任何分支中?
因此,我们想要操作每个标签并进行一些测试。有一些命令可以枚举每个标签。对于脚本编写,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)
和 %(*objectname)
来实现这一点。令人恼火的是,当标签是轻量标签时,这些 %(*...)
指令将产生 空值,这需要一些巧妙的处理: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
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 这里。该脚本可能需要改进,以便采用Git选项等,但是目前我并不那么在意。它也非常慢,可以通过编写其他不同于非常简单的Shell脚本的内容来改善,但请参见上述备注。)
1最佳是其中一件难以衡量的事情,但至少我发现它是最好的。