如何列出所有轻量级标签?

27
我想列出我的仓库中所有轻量级标签;我能想到的最好方法是结合git for-each-refgrepcut命令,但似乎这个方法很琐碎...
(顺便说一句,我们也可以讨论一下如何查找注释标签:有人肯定会在某个时候想知道这个。) 编辑: 通过“轻量级”标签,我指的是那些不引用标记对象的标记引用。(换句话说,就是未注解的标签。)
5个回答

29

所有轻量级标签都在 refs/tags/ 命名空间中,可以通过以下方式枚举:

git for-each-ref --format '%(refname:short)' refs/tags/
或:
git show-ref --tags

关于注释标签,要知道的是——这也涉及到“轻量级”标签部分——注释标签实际上是git仓库中的一个对象,但是有一个指向该对象的轻量级标签,使得您可以通过标签名称使用注释标签1。因此,它实际上是一对东西:一个轻量级标签,再加上存储在仓库中的注释标签对象,这使它成为“非轻量级标签”,除了那个顽固的事实,它同时又是一个轻量级标签!

因此,问题就变成了:查找所有轻量级标签,然后根据您想要的行为选择只指向提交或标签对象的标签,接着输出标签名称。

git-for-each-ref文档中有一个长篇例子,在--format字符串中编写整个脚本,并使用eval来执行它(或者您可以将其传输到sh进行执行,这会多出一个进程)。我通常发现将 git for-each-ref 的输出管道传输到while read ...循环中更简单:

git for-each-ref refs/tags/ --format '%(objecttype) %(refname:short)' |
    while read ty name; do [ $ty = commit ] && echo $name; done

打印所有仅包含轻量级标签的标签。

与之相比:

git for-each-ref refs/tags/ --format '%(objecttype) %(refname:short)' |
    while read ty name; do [ $ty = tag ] && echo $name; done

输出所有已注释的标签(或更准确地说,“已注释”的轻量级标签)。

请注意,标签可以(可能会——就目前而言,据我所知,没有实际用例)指向除提交或标签以外的其他内容;您可以自行决定是否对指向treeblob的标签进行处理。


1如果没有轻量级标签,您将无法使用名称annotag引用已注释的标签annotag——至少不是通过git fsck用于查找悬空对象的全部搜索努力。此外,如果删除轻量级标签,则可以垃圾回收注释标签对象。您可以使一个标签对象指向另一个标签对象以使其保留在仓库中(即抑制GC),而无需为第二个标签对象提供外部名称,只要第一个标签对象具有外部名称即可。虽然这肯定是一件奇怪的事情。

有趣的是,已注释标签的内部格式包含外部名称,因此可以使用此技术来保护“旧”注释标签,通过删除它们的轻量级标签进行隐藏,然后稍后恢复原始的轻量级标签。但是,是否有人可以想出这样做的用途呢... :-)


我必须承认,对于git-for-each-ref(1)中那个--shell示例的目的,我感到困惑;为什么有人会希望在内存中构建一个庞大而独立的shell脚本,而不是像这样逐步使用输出结果在管道/循环中进行操作呢? - SamB
我不是很确定。也许只是为了演示引用方面的内容(您可以获得带引号的输出,以供perl、python和shell使用)......有些情况下,shell会将循环分离到子进程中,导致在循环终止后保持变量值时出现问题。也许它是为了解决这些问题而设计的。 - torek
2
我会用 awk 替换那些 while 循环:git for-each-ref refs/tags/ --format '%(objecttype) %(refname:short)' | awk '$1 == "tag" {print $2}' - Ciro Santilli OurBigBook.com
1
@CiroSantilli:是的,对于这种情况来说,那样做更快/更好。(假设有awk,一些Windows用户可能没有。) - torek
假设一个人有awk,一些Windows用户可能没有。只要他们将C:\path\to\PortableGit-2.6.3-64-bit\usr\bin添加到他们的路径中即可获得它们。虽然在某些地方需要使用双引号: git for-each-ref refs/tags/ --format "%(objecttype) %(refname:short)" | awk '$1 == "tag" {print $2}'。这在我的普通CMD会话中完美运行。 - VonC
1
@Shalomi90 我会在今天稍后的时间里浏览新问题时处理它。 - torek

13

只列出轻量级标签:

git for-each-ref refs/tags | grep commit

仅列出 已注释的 标签:

git for-each-ref refs/tags | grep -v commit

说明:

git for-each-ref 列出所有引用: headsremotesstashtags

git for-each-ref refs/tags 仅列出标签引用。

| grep commit 仅列出包含单词 commit 的行。这些是指向提交的标签,因此是轻量级标签。

| grep -v commit 仅列出不包含单词 commit 的行。这些是指向标签的标签,因此是注释标签。


1

总结其他答案及其评论,如果您使用的是bash:

function git-lightweight-tags() { 
    git for-each-ref refs/tags/ --format '%(objecttype) %(refname:short)' | awk '$1 == "commit" {print $2}' ; 
}

0
使用git for-each-refawk

带注释的标签

git for-each-ref refs/tags |
  awk '$2~/tag/{print $3}'

轻量级标签
git for-each-ref refs/tags |
  awk '$2~/commit/{print $3}'

第一个字段是哈希值,第二个字段是类型,第三个字段是引用的名称。

0

请注意,您也可以标记(轻量级和注释)blob和tree。

因此,git for-each-ref refs/tags | grep -v commit不仅会列出带注释的标签,还会列出指向blob和tree的标签。

我建议使用grep查找单词“tag”以查找带注释的标签:

git for-each-ref refs/tags | grep -w tag

不要忘记使用-w,否则您将在轻量级标签中也找到子字符串tag


嗯...我认为这仍然会匹配像foo/tag这样的标签。(而且,这实际上并不是我的问题的答案。) - SamB
@SamB:好的,对不起,我的评论不是针对你最初的问题的反应。我的评论是针对建议使用grep搜索“commit”的答案的。 - Christian Halstrick

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接