在Unix或GNU脚本环境(例如Linux发行版,Cygwin,OSX)中,确定当前结帐是否为Git标记的最佳方法是什么。如果是标签,我该如何确定标签名称?
这种技术的一个用途是自动标记一个版本(就像svnversion
会对Subversion做的那样)。
请参阅我关于programmatically detecting the Git branch的相关问题。
答案 0 :(得分:51)
问题的解决方案是使用
git describe --exact-match HEAD
(只会考虑带注释的标签,但您应该使用带注释的,甚至可能使用已签名的标签来标记版本)。
如果您想考虑所有标签,还要考虑轻量级标签(通常用于本地标记),您可以使用--tags
选项:
git describe --exact-match --tags HEAD
但我认为你在这里有“XY problem”,因为你问的是问题的可能解决方案,而不是问一个问题......这可以有更好的解决方案。 / em>的
问题的解决方案是查看Git如何在GIT-VERSION-GEN脚本中执行此操作,以及它如何在Makefile中使用它。
答案 1 :(得分:5)
执行此操作的最佳方法是使用git describe
命令:
git-describe - 显示可从提交
访问的最新标记该命令查找可从提交访问的最新标记。如果标记指向提交,则仅显示标记。否则,它将标记名称后缀为标记对象顶部的附加提交数和最近提交的缩写对象名称。
答案 2 :(得分:4)
git-name-rev 的使用是首选脚本,因为它是git plumbing 的一部分,而 git-describe 是其中的一部分瓷器。
如果HEAD指向一个标签,则使用此命令打印标签的名称,否则不打印。
git name-rev --name-only --tags --no-undefined HEAD 2>/dev/null | sed -n 's/^\([^^~]\{1,\}\)\(\^0\)\{0,1\}$/\1/p'
注意将stderr重定向到/ dev / null - 否则您将收到一条错误消息:
fatal: cannot describe 'SOMESHA'"
编辑:修复了sed中的正则表达式,以支持轻量级和带注释/签名的标记。
答案 3 :(得分:3)
您无法确定当前结帐“是否为标记”。您只能确定当前结帐是否是包含标记的提交。
不同之处在于:如果有多个指向此提交的标签,git就无法告诉您过去常常使用哪个标签,也无法告诉您实际使用过哪一个。
基于git describe --exact-match (--tags)
的Jakub’s answer here为您提供所有(带注释的)标记的“第一个”。
而git describe
就像这样对它们进行排序:
答案 4 :(得分:2)
更好的解决方案(来自Greg Hewgill在另一个问题中的答案)将是:
git name-rev --name-only --tags HEAD
如果它返回“未定义”,那么您不在标签上。否则返回标签名称。因此,像我的其他答案那样的单行代码将是:
git_tag=`git name-rev --name-only --tags HEAD | sed 's/^undefined$//'`
交互式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
答案 5 :(得分:-2)
这是一个简短的shell脚本(在Bash中测试,未确认它是否适用于灰烬等)。它会将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
JakubNarębski的评论:
此解决方案简化为循环遍历所有标记,并检查它们是否指向正确提交,即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
这将打印指向当前提交的所有标记。