列出分支包含的标签。

90

如何列出给定分支包含的标签,与以下相反:

git tag --contains <commit>

如何“仅列出包含指定提交的标签”?

如果这样的功能不存在,我该如何测试一个提交是否被另一个提交所包含,以便编写脚本实现此功能?

我可以这样做:

commit=$(git rev-parse $branch)
for tag in $(git tag)
do
    git log --pretty=%H $tag | grep -q -E "^$commit$"
done

但是我希望有更好的方法,因为在一个有许多标签和提交的代码库中,这可能需要很长时间。


1
请参考此重复帖子的答案,了解另一种不错的实现方式。 - CharlesB
11个回答

147
git tag --merged <branch>

从手册页中得知:

--[no-]merged <commit>

Only list tags whose tips are reachable, or not reachable if --no-merged is used, from the specified commit (HEAD if not specified).

我相信这个选项是最近添加的 - 当原始问题被提出并且上面的答案被建议时,它绝对是不可用的。由于这个线程仍然是谷歌搜索中该问题的第一个结果,我想为任何向下滚动查找涉及较少打字的答案(以及当我下周再次忘记这个答案时)的人提供帮助。


4
似乎是在2015年9月添加的,可以参考此链接。我认为现在应该采纳这个答案。 - Arnaud P
同意,这正是我正在寻找的。 - Mobius
3
在一个分支中列出标签,但在另一个分支中不列出也是可能的: git tag --merged debian --no-merged upstream(当一个分支合并到另一个分支时很有用)。 - Franklin Piat
1
@FranklinPiat:"错误:选项“no-merged”与--merged不兼容"。 - ingyhere
1
@FranklinPiat - 我也以为可以,但是根据这个错误报告,它实际上完全忽略了第一个选项: https://github.com/git/git/commit/17d6c744dc0d5ed4cd0f228da14239ea2654f05b - JamHandy
简短、易懂且准确的回答。谢谢@JamHandy! - provisota

46

这可能接近你想要的:

git log --simplify-by-decoration --decorate --pretty=oneline "$committish" | fgrep 'tag: '

但是,更常见的情况是只查找最近的标签:

git describe --tags --abbrev=0 "$committish"
  • --tags 参数将搜索轻量级标签,如果您只想考虑带注释的标签,请不要使用它。
  • 如果您想同时查看通常的“顶部提交次数和简写哈希值”后缀(例如v1.7.0-17-g7e5eb8),请勿使用--abbrev=0参数。

2
从Git 1.7.10开始,--pretty=format:%d无法正常工作,它会列出引用但不会说明它是标签还是分支。 - CharlesB
1
@CharlesB: 编辑以更改为 log。 我没有正确地分割它,但看起来这个更改(回归?)可能发生在1.7.2中:[a7524128](https://github.com/git/git/commit/a7524128750ebf34fe0639e1e5d7abd03aff0302)更改了内部装饰文本,但仅调整了一个格式化函数以进行补偿(log-tree.c:show_decoration已进行调整,而pretty.c:format_decoration受到(意外的?)更改的影响)。 - Chris Johnsen
对我来说,这个错误信息是:fatal: ambiguous argument '': unknown revision or path not in the working tree. Use '--' to separate paths from revisions (git version 1.7.9.5)。 - rooby
@rooby:该错误信息表明您在命令中包含了一个空字符串。您是否替换了要调查的提交/分支/标签的哈希字符串(即我使用的占位符“$committish”)? - Chris Johnsen
1
这并没有真正回答问题,它只显示了最近的标签...而不是“包含在分支中”的“标签”(复数)。 - masukomi
显示剩余2条评论

14

列出当前分支可达的所有标签:

git log --decorate=full --simplify-by-decoration --pretty=oneline HEAD | \
sed -r -e 's#^[^\(]*\(([^\)]*)\).*$#\1#' \
       -e 's#,#\n#g' | \
grep 'tag:' | \
sed -r -e 's#[[:space:]]*tag:[[:space:]]*##'

1
在 OS X 中,将 sed -r 替换为 sed -E - CharlesB
自从这个答案被撤回以来,git log --decorate=full --simplify-by-decoration --pretty=oneline HEAD的格式有了一些变化。 - CharlesB
git log --decorate --oneline | egrep '^[0-9a-f]+ \(tag: ' | sed -r 's/^.+tag: ([^ ]+)[,\)].+$/\1/g' - shkschneider
shkschneider的评论如果在最新提交上,则不包括标签。 - Josiah Kiehl

7

我没有足够的声望来评论别人的帖子,但这是对https://dev59.com/3HE95IYBdhLWcg3wRLwt#7698213答案及其评论的回应。为了显示当前分支可达的所有标签,包括HEAD提交上的标签,您可以使用以下命令:

git log --decorate --oneline | egrep '^[0-9a-f]+ \((HEAD, )?tag: ' | ssed -r 's/^.+tag: ([^ ]+)[,\)].+$/\1/g'

有一个注意点 - 我使用的是超级sed,所以你可能需要将我的“ssed”更改为sed。

还有为了好玩,这是PowerShell的代码:

git log --decorate --oneline | % { if ($_ -match "^[0-9a-f]+ \((HEAD, )?tag: ") { echo $_} } | % { $_ -replace "^.+tag: ([^ ]+)[,\)].+$", "`$1" }

-- -a


1
你为什么不考虑使用sed而不是ssed来改变你的答案呢?因为这样更符合其他用户的使用习惯。 - rooby
我同意,但需要注意的是在OS X上默认的sed没有-r选项,需要通过Homebrew切换到gnu-sed或其他方式。 - masukomi

4

所有答案只列出标签,但如果您想按时间顺序排序,需要添加 --sort=taggerdate

例如:

 git tag --merged release/11.x --sort=taggerdate
studio-1.4
llvmorg-10-init
llvmorg-11-init
llvmorg-11.0.0-rc1
llvmorg-11.0.0-rc2
llvmorg-11.0.0-rc3
llvmorg-11.0.0-rc4
llvmorg-11.0.0-rc5
llvmorg-11.0.0-rc6
llvmorg-11.0.0

2

针对寻找Windows特定答案的任何人。

(Powershell最近已经开源并跨平台,因此下面给出的命令也可以在Windows以外的系统上运行。)

注意:以下内容适用于旧版本的git或特定用例!

对于powershell:

git log --simplify-by-decoration --decorate --pretty=oneline "$committish" | Select-String 'tag: '

您还可以使用-CaseSensitive标志使Select-String区分大小写。 对于cmd:
git log --simplify-by-decoration --decorate --pretty=oneline | findstr -i "tag: "

您可以删除-i以使搜索区分大小写

注意:对于更新的版本和跨平台、跨终端,只要支持git命令即可:

git tag --merged <branchname>

你可以使用格式、颜色、排序等多种选项来操作。在这里查看所有内容:https://git-scm.com/docs/git-tag


1
你可以使用这个:
# get tags on the last 100 commits:
base_rev=master~100
end_rev=master
for rev in $(git rev-list $base_rev..$end_rev)
do 
    git describe --exact-match $rev 2> /dev/null
done

只有当您的代码库有超过100个提交并且您需要的标签比100个提交更旧时,此方法才有效。如果不符合这些条件,那就没有办法了。 - Josiah Kiehl

1
这里是如何以逆时间顺序列出匹配模式(TAG_PREFIX*)的已注释标签的方法。此方法使用git-describe。
#!/usr/bin/env bash

tag=$(git describe --abbrev=0 --match TAG_PREFIX*)
until [ -z $tag ]; do
    echo $tag
    tag=$(git describe --abbrev=0 --match TAG_PREFIX* $tag^ 2>/dev/null);
done

如果多个匹配模式的标签指向同一个提交,这种方法就不起作用。为此,这里有另一种方法,它使用git-rev-list和git-tag列出从一个提交(在本例中是HEAD)开始的所有匹配TAG_PREFIX*的标签。
#!/usr/bin/env bash

git rev-list HEAD | while read sha1; do
    tags=( "$(git tag -l --points-at $sha1 TAG_PREFIX*)" )
    [[ ! -z ${tags[*]} ]] && echo "${tags[@]}" | sort -r
done

0

适用于大量标签和易于格式灵活性的高效处理:

{ git rev-list --first-parent ${1:-HEAD}
  git for-each-ref --format='%(objectname) %(objecttype)  %(refname)
                             %(*objectname) *(%(objecttype)) %(refname)' 
} \
| awk '
  NF==1   { revs[$1]=1; next }
          { if ( $1 in revs ) print $1,$2,$3 }
'

获取所有引用,将refs/tags添加到f-e-r以进行限制。


0

有一个 git branch --contains 命令(至少自 Git 1.5.7 起可用)


1
这根本没有做到要求。"使用 --contains 选项,只显示包含指定提交的分支" ... 他并没有要求包含某个提交的分支,他要求的是分支中的标签。 - masukomi
实际上,它根本没有回答 OP 的问题,但对于一个常见情况非常有用:检查分支上是否存在标签(例如,如果不在主分支上,则不进行部署)[[ $(git branch --contains $(git rev-parse $TAG)) =~ '\bmaster|main$' ]]; echo $? - afirth

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