Git:如何在同一次提交时获得2个/多个标签时检出标签的名称

时间:2015-03-09 09:47:29

标签: git git-tag git-describe

  1. 我有一个包含2个标签的git提交,如下所示:commit1-----tagA,tagB
  2. git checkout tagA
  3. 结帐“tagA”
  4. 问题:如何获取当前结帐的代码名称?我试过git describe,但它总是返回名称“tagB”,期望返回“tagA”。

    似乎git describe只能返回最新的标记名称,请参阅git manual

      

    该命令查找可从提交访问的最新标记。   如果标记指向提交,则仅显示标记。   否则,它将标签名称后缀为附加数量   提交在标记对象和缩写对象名称之上   最近的提交。

  5. 还有其他方法吗?

    目的与此问题相关:

    我想让文件自动构建标签名称的版本号,{1}}在1提交1个标签时运行良好,但在上述情况下它没用。

2 个答案:

答案 0 :(得分:3)

tagAtagB都指向一个特定的提交,因此就git而言,如果要查看或查看该名称,则其中一个名称同样好(或同样差)特别提交。

文档的短语"最新标记"这可能会误导(虽然这可能是你输出tagB的原因。)


如何获得您想要的结果

如果你想知道你给git checkout的标记名称,你可以自己保存,或者查阅HEAD的reflog:

8004647 HEAD@{0}: checkout: moving from master to v2.3.1

reflog方法的优点是它已经实现了;但是reflogs只会保留一段时间(可配置,默认90天可达参考),然后过期以防止reflogs永远增长。


如何" git描述"提出了你不想要的答案

"最近"意味着如果标签具有关联的日期和时间标记 - 带标注的标签,那么轻量级标签就不会 - 那些具有较晚时间的标签被认为是#34;更好",如下所述。

请注意,任何时候,任何git命令都可以轻松查找所有外部引用并将它们转换为SHA-1。要查看其工作原理,只需运行git for-each-ref(您可能希望将其传输到类似less的寻呼机)。输出看起来像这样:

c2e8e4b9da4d007b15faa2e3d407b2fd279f0572 commit refs/heads/maint
9ab698f4000a736864c41f57fbae1e021ac27799 commit refs/heads/master
[snip]
74d2a8cf12bf102a8cedaf66736503bb3fe88dfb tag    refs/tags/v2.2.0
[more snippage]

这些是分支和标签 - 在这个git存储库中(对于git本身)所有标签都有注释 - 以及它们对应的SHA-1。如果存在活动存储,它也会显示(在refs/stash下)。

在任何情况下,假设git describe此时具有其中一个提交ID(SHA-1),describe也找到了两个或多个解析为该ID的名称。这些可能只是带注释的标签名称,这是您没有选项的结果,或者它们可能是--all允许的另一个名称(如分支名称);但重要的是假设有两个或更多名称,都指向同一个提交。

describe命令可以尝试记住所有这些名称,但它并没有。相反,它通过一种两次一次的比赛来运行名称,以查看哪一个赢得比赛":

  • 如果两个名称都是带注释的标签,请使用两个名称上的日期戳来选择要保留的标签以及要丢弃的标签。这里的想法似乎是,如果给同一个提交两个或多个带注释的标签,那么后来创建的标签可能是#34;更好"并且是git describe应该使用的。
  • 如果一个名称是带注释的标签而另一个名称不是,请保留带注释的标签;丢掉另一个名字。换句话说,任何带注释的标签都优于任何轻量级标签。
  • 如果两个名称都不是带注释的标签,但是一个是(轻量级)标签而另一个不是,请保留标签;抛弃非标签。换句话说,任何标签都比其他任何标签都好。
  • 否则(两个名字都不是任何类型的标签),请保持最早遇到的" name(这取决于git的内部名称行走机制,因此不一定是可预测的)。

一旦这个提交的所有名称都相互竞争,选择一个赢得名字","获胜名称"与提交SHA-1一起保存。


现在,我们如何首先获得该提交ID?答案是git describe从你的论点开始:

$ git describe       # no args, means ...
$ git describe HEAD  # use HEAD to get the SHA-1

您的参数(或HEAD)使用git rev-parse转换为适当的原始SHA-1(嗯,其C代码等效):

$ git rev-parse HEAD
9ab698f4000a736864c41f57fbae1e021ac27799

然后,git describe调用git for-each-ref(或其等效的C代码)将您允许使用的所有名称(默认情况下,所有带注释的标记)转换为SHA-1 ID。如果其中任何一个与 SHA-1匹配,则会保存它们。如果有多场比赛,他们会通过比赛选出一名获胜者。

对于您的特定情况,此部分成功:tagAtagB都是完全匹配,因此在选择这两者之间的获胜标记后,整个事情就会停止。在你的情况下,你没有想要的标签。

一般而言,git describe通常必须坚持下去。例如,考虑git项目本身的以下提交:

088c9a8 strbuf.h: format asciidoc code blocks as 4-space indent
aa07cac strbuf.h: drop asciidoc list formatting from API docs
6afbbdd strbuf.h: unify documentation comments beginnings
bdfdaa4 strbuf.h: integrate api-strbuf.txt documentation
eae6953 tests: correct misuses of POSIXPERM
1767c51 t/lib-httpd: switch SANITY check for NOT_ROOT
b4a56a3 "log --pretty" documentation: do not forget "tformat:"

现在假设我们创建一个标记X指向提交b4a56a3,一个标记Y指向提交eae6953,并且一个标记Z指向提交aa07cac。如果我们再问git"描述"提交088c9a8,可以将其描述为以下任何一种:

  • 提交X
  • 后六个步骤发生的提交
  • 提交Y
  • 后四个步骤发生的提交
  • 提交Z
  • 后一步发生的提交

git describe的输出将使用标记Z,因为它需要更少的步骤来标记Z" (提交aa07cac)到有问题的提交(088c9a8)。这实际上是如何发生的(可能是不必要的,虽然这是一个价值判断:-))复杂。

这里git describe的作用是遍历(部分)提交图(如果指定则应用--first-parent)以找到附近的""具有名称的提交。搜索顺序有点难以描述:它部分基于日期(la git log的日期排序提交列表),但如果它遇到带注释的标签则会提前停止。否则它会累积一个"候选名称列表" (使用上述竞赛方法),当累积了足够的(默认10个)候选名称时停止,然后对列表进行排序。排序基于"图形距离",因此假设XYZ都是轻量级标记 - 如果有任何标注标记,则它应该是现在被选中并且搜索停止了 - Z在这里获胜。

最后,找到一个指向合适提交的名称,该提交实际上不是作为参数的给定提交,git describe打印名称,远离步数("深度" ),以及g和实际SHA-1的一部分:

v2.3.3-220-g9ab698f

(虽然深度和g可以被抑制,如果根本找不到任何名字或者你只是要求完全匹配,整个事情都可能失败,等等。 / p>

答案 1 :(得分:2)

您至少可以获得给定提交的所有标记:

git tag --points-at HEAD

来自git tag man page

--points-at <object>
  

仅列出给定对象的标签。

从那里,你可以提取你想要的那个。