Git 如何列出提交中未包含在任何分支中的所有标记?
我们有一组存储库,其中许多提交不包含在任何分支中,但仅由于标记而保持活动状态。我想列出所有这样的标签。我还不知道怎么做。有人有什么想法,如何实现吗?标记不是来自提交,它们只是指向提交。但你的问题确实有答案,只是措辞有点奇怪。更准确的措辞会让我们找到答案: 对于每个标记,如何测试标记标识的提交是否包含在任何分支中 因此,我们希望对每个标签进行操作并执行一些测试。有一些命令枚举每个标记。出于编写脚本的目的,Git 如何列出提交中未包含在任何分支中的所有标记?,git,Git,我们有一组存储库,其中许多提交不包含在任何分支中,但仅由于标记而保持活动状态。我想列出所有这样的标签。我还不知道怎么做。有人有什么想法,如何实现吗?标记不是来自提交,它们只是指向提交。但你的问题确实有答案,只是措辞有点奇怪。更准确的措辞会让我们找到答案: 对于每个标记,如何测试标记标识的提交是否包含在任何分支中 因此,我们希望对每个标签进行操作并执行一些测试。有一些命令枚举每个标记。出于编写脚本的目的,git For each ref是最好的工具。因此,我们从以下方面开始: git for-ea
git For each ref
是最好的工具。因此,我们从以下方面开始:
git for-each-ref refs/tags
它打印出所有标签(到其标准输出)以及关于每个标签目标的额外信息:
$ git for-each-ref refs/tags
04c6e9e9ca34226db095bbaa1218030f99f0b7c6 commit refs/tags/a
d5aef6e4d58cfe1549adef5b436f3ace984e8c86 tag refs/tags/b
比如说。a
标记直接指向提交,即是一个轻量级标记;b
标记指向带注释的标记对象
这还不是一个解决方案,但它正在把我们带到那里。接下来我们要做的事情是找出带注释标记的目标是否是提交对象,如果是,则找到提交对象的哈希。事实证明,使用--format
指令%(*objecttype)
和%(*objectname)
,每个ref的git本身就可以做到这一点。令人烦恼的是,当标记是轻量级标记时,这些%(*…)
指令不会产生任何结果,这需要一些技巧:
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
打印出到达给定对象的每个分支名称(以及每个ref
的的其他数据)。我们不关心实际的名称,只关心是否有任何名称,所以让我们计算每个ref的内部打印多少行。如果为零,则此标记将保持此提交活动,因此让我们打印此标记:
if [ $n -eq 0 ]; then
echo "tag $name keeps $obj alive"
fi
当我们运行整个程序时,有一个小缺陷:例如,这会打印tag refs/tags/a
。我们可以通过在--format
的开头使用%(refname:short)
来解决这个问题,我们将得到标记a
最后的脚本是:
git for each ref--format='%(refname:short)%(objecttype)%(objectname)%(*objecttype)%(*objectname)refs/tags|
读取名称数据类型dobj时,读取类型iobj;做
如果[$dtype=tag];然后
otype=$itype obj=$iobj
其他的
otype=$dtype obj=$dobj
fi
[$otype==commit]| |继续
n=$(每个参考/头部的git——包含$obj | wc-l)
如果[$n-等式0];然后
echo“标记$name使$obj保持活动状态”
fi
完成
(我已经将此添加到GitHub中。该脚本可能会有一些改进,以使其采用Git选项等,但目前我并不太在意。它也非常慢,可以通过将其作为非常简单的shell脚本以外的其他脚本编写来改进,但请参见前面的备注。)
1最佳是难以衡量的事情之一,但至少我发现它是最好的