bash 如何以编程方式确定 Git checkout 是否为标签,如果是,标签名称是什么
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1593188/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to programmatically determine whether the Git checkout is a tag and if so, what is the tag name
提问by JasonSmith
In a Unix or GNU scripting environment (e.g. a Linux distro, Cygwin, OSX), what is the best way to determine whether the current checkout is a Git tag. If it is a tag, how can I determine the tag name?
在 Unix 或 GNU 脚本环境(例如 Linux 发行版、Cygwin、OSX)中,确定当前检出是否为 Git 标记的最佳方法是什么。如果是标签,如何确定标签名称?
One use of this technique would be automatically labeling a release (like svnversionwould do with Subversion).
这种技术的一个用途是自动标记一个版本(就像svnversionSubversion 一样)。
See my related question about programmatically detecting the Git branch.
请参阅我关于以编程方式检测 Git 分支的相关问题。
回答by Jakub Nar?bski
The solution to your questionis to use
您问题的解决方案是使用
git describe --exact-match HEAD
(which would consider only annotatedtags, but you should use annotated and probably even signed tags for tagging releases).
(这将只考虑带注释的标签,但您应该使用带注释的甚至可能签名的标签来标记版本)。
If you want to consider all tags, also lightweighttags (which are usually used for local tagging), you can use --tagsoption:
如果你想考虑所有标签,还有轻量级标签(通常用于本地标签),你可以使用--tags选项:
git describe --exact-match --tags HEAD
But I think you have "XY problem" here, in that you are asking question about possible solution to the problem, rather than asking question about a problem... which can have better solution.
但是我认为您在这里有“ XY 问题”,因为您是在询问有关该问题的可能解决方案的问题,而不是询问有关某个问题的问题......这可以有更好的解决方案。
The solution to your problemis to take a look how Git does it in GIT-VERSION-GENscript, and how it uses it in its Makefile.
您的问题的解决方案是查看 Git 如何在GIT-VERSION-GEN脚本中执行它,以及它如何在其Makefile 中使用它。
回答by Greg Hewgill
The best way to do this is to use the git describecommand:
最好的方法是使用以下git describe命令:
git-describe - Show the most recent tag that is reachable from a commit
The command finds the most recent tag that is reachable from a commit. If the tag points to the commit, then only the tag is shown. Otherwise, it suffixes the tag name with the number of additional commits on top of the tagged object and the abbreviated object name of the most recent commit.
git-describe - 显示可从提交中访问的最新标签
该命令查找可从提交中访问的最新标记。如果标记指向提交,则仅显示标记。否则,它将在标记对象之上附加提交的数量和最近提交的缩写对象名称作为标记名称的后缀。
回答by Tuxdude
Usage of git-name-revis preferred for scripts, since it is part of git plumbing, whereas git-describeis part of porcelain.
的使用GIT-名称-REV是优选的脚本,因为它是GIT中的一部分的管道,而GIT-描述是的一部分瓷。
Use this command to print the name of the tag if the HEAD points to one, otherwise nothing.
如果 HEAD 指向 1,则使用此命令打印标签的名称,否则不打印。
git name-rev --name-only --tags --no-undefined HEAD 2>/dev/null | sed -n 's/^\([^^~]\{1,\}\)\(\^0\)\{0,1\}$//p'
Notethe redirection of stderr to /dev/null - otherwise you'll get an error message saying:
请注意将 stderr 重定向到 /dev/null - 否则您将收到一条错误消息:
fatal: cannot describe 'SOMESHA'"
EDIT: Fixed the regex in sed to support both lighweight and annotated/signed tags.
编辑:修复了 sed 中的正则表达式以支持轻量级和带注释/签名的标签。
回答by Robert Siemer
You cannot determine if the current checkout “is a tag”. You can only determine if the current checkout was a commit that has tags.
您无法确定当前结帐是否“是标签”。您只能确定当前结帐是否是具有标签的提交。
The difference is: if there are several tags pointing to this commit, git can't tell you which you used to checkout, nor if you actually used one to get there at all.
不同之处在于:如果有多个标签指向这个 commit,git 无法告诉你你曾经用哪个来结账,也无法告诉你是否真的使用了一个来到达那里。
Jakub's answer herebased on git describe --exact-match (--tags)gives you “the first”of all the (annotated) tags.
Jakub 在这里基于的答案git describe --exact-match (--tags)为您提供了所有(带注释的)标签中的“第一个”。
And git describesorts them like this:
并git describe像这样对它们进行排序:
- annotated tags first
- sorted youngest first
- lightweight tags come afterwards
- binary sorted by tag name (that means alphabetically if it's English encoded in ASCII)
- git doesn't store meta-data with lightweight tags, so “youngest-first” can not be realized
- 首先注释标签
- 先排序最年轻
- 轻量级标签随后出现
- 按标签名称排序的二进制(如果它是用 ASCII 编码的英文,则意味着按字母顺序)
- git 不存储带有轻量标签的元数据,因此无法实现“年轻优先”
回答by JasonSmith
A better solution (from Greg Hewgill's answer in the other question) would be:
更好的解决方案(来自 Greg Hewgill 在另一个问题中的回答)是:
git name-rev --name-only --tags HEAD
If it returns "undefined" then you are not on a tag. Otherwise it returns the tag name. So a one-liner to do something like my other answer would be:
如果它返回“undefined”,那么你就不是一个标签。否则它返回标签名称。因此,像我的其他答案一样做一些事情的单行代码是:
git_tag=`git name-rev --name-only --tags HEAD | sed 's/^undefined$//'`
Interactive shell example of how it works:
其工作原理的交互式 shell 示例:
$ git checkout master
Already on "master"
$ git name-rev --name-only --tags HEAD
undefined
$ git checkout some-tag
Note: moving to "some-tag" which isnt a local branch
If you want to create a new branch from this checkout, you may do so
(now or later) by using -b with the checkout command again. Example:
git checkout -b <new_branch_name>
HEAD is now at 1234567... Some comment blah blah
$ git name-rev --name-only --tags HEAD
some-tag
回答by JasonSmith
Here is a brief shell script (tested in Bash, not confirmed if it works on ash, etc.). It will set the git_tagvariable to the name of the currently checked-out tag, or leave it blank if the checkout is not tagged.
这是一个简短的 shell 脚本(在 Bash 中测试,未确认它是否适用于 ash 等)。它将将该git_tag变量设置为当前签出标签的名称,或者如果签出未标记,则将其留空。
git_tag=''
this_commit=`git log --pretty=format:%H%n HEAD^..`
for tag in `git tag -l`; do
tag_commit=`git log --pretty=format:%H%n tags/$tag^..tags/$tag`
if [ "$this_commit" = "$tag_commit" ]; then
# This is a tagged commit, so use the tag.
git_tag="$tag"
fi
done
Comment by Jakub Nar?bski:
Jakub Nar?bski 的评论:
This solution reduces to looping over all tags, and checking if they point to corrent commit, i.e. object pointed by HEAD. Using plumbing commands, i.e. commands meant for scripting, this can be written as:
该解决方案简化为遍历所有标签,并检查它们是否指向正确的提交,即 HEAD 指向的对象。使用管道命令,即用于脚本的命令,可以写成:
this_commit=$(git rev-parse --verify HEAD)
git for-each-ref --format="%(*objectname) %(refname:short)" refs/tags/ |
while read tagged_object tagname
do
if test "$this_commit" = "$tagged_object"
then
echo $tagname
fi
done
This would print all tags that point to current commit.
这将打印所有指向当前提交的标签。

