关于git:我为什么要关心轻量级和带注释的标签?

Why should I care about lightweight vs. annotated tags?

去年,我从颠覆转向了Git作为我的日常风投,现在我仍在努力抓住"Git思考"的更细微之处。

最近一直困扰我的是"轻量级"标签与带注释的标签与带签名的标签。对于所有实际用途来说,注释标签都优于轻量级标签,这似乎是一个普遍接受的事实,但是我发现的解释为什么会这样,似乎总是归结为"因为最佳实践"或"因为它们是不同的"。不幸的是,在不知道最佳实践的原因或这些差异如何与我的Git使用相关的情况下,这些论点非常令人不满意。

当我第一次切换到Git时,轻量级标签似乎是自切片面包以来最好的东西;我可以直接指向提交并说"那是1.0"。我很难理解一个标签怎么可能比这更重要,但我肯定不能相信世界上的Git专家更喜欢随意标注的标签!那么吵闹是怎么回事?

(加分:为什么我需要签名?)

编辑

我已经成功地确信带注释的标签是一件好事——知道谁加了标签,什么时候重要!作为后续行动,对好的标签注释有什么建议吗?git tag -am"tagging 1.0" 1.0和试图总结提交日志,因为前一个标签感觉像是在丢失策略。


注释标签的最大优点是您知道是谁创建的。就像承诺一样,有时候知道是谁做的很好。如果您是一个开发人员,并且看到v1.7.4已经被标记(声明为就绪),而且您不确定,那么您会和谁交谈?姓名在批注标签中的人!(如果你生活在一个不信任的世界里,这也会防止人们在不该做的事情上做标记。)如果你是一个消费者,这个名字就是权威的印记:那就是Junio Hamano,他说这个版本的Git已经发布了。

其他元数据也很有帮助——有时候知道该版本何时发布是很好的,而不仅仅是在最终提交时。有时信息甚至是有用的。也许这有助于解释这个特定标签的用途。可能发布候选的标签包含一个状态/待办事项列表。

签名标签和签名任何其他东西都非常相似——它为偏执狂提供了一个更高级别的安全性。我们大多数人都不打算使用它,但是如果你真的想在把软件放到你的计算机上之前验证所有的东西,你可能会想要它。

编辑:

至于在标签注释中写些什么,你是对的——说起来并不总是那么有用。对于版本号标记,它隐式地理解为它标记了该版本,如果您对其他地方的变更日志感到满意,则无需将其放在那里。在这种情况下,最重要的是标签和日期。我能想到的另一件事是从测试套件中获得某种形式的批准。看看Git.Git的标签:他们都会说"Git 1.7.3 RC1";我们真正关心的是Junio Hamano的名字。

然而,对于不太明显的命名标签,消息可能变得更加重要。我可以设想为单个用户/客户机、一些重要的非版本里程碑或(如上所述)包含额外信息的候选发布版本标记特定的专用版本。这样的信息就更有用了。


我个人对这个话题的看法略有不同:

  • 带注释的标记是那些为其他开发人员发布的标记,最有可能是新版本(也应该签名)。不仅要查看标记的对象和标记的时间,还要查看原因(通常是变更日志)。
  • 轻量级更适合私人使用,这意味着标记特殊承诺可以再次找到它们。也许是复习一下,检查一下,测试一下什么东西。


默认情况下,Git只将带注释的标记作为像git describe这样的命令的基线。把带注释的标签想象成对你自己和他人有持久意义的路标,而轻量级的标签更像是供你以后自己找到的书签。因此,带注释的标记值得用作参考,而轻量级标记不应如此。

签署标签是对签署者身份的保证。例如,它允许用户验证他们获取的Linux内核代码是否与LinusTorvalds实际发布的代码相同。签名也可以是一个断言,即签名者在提交时保证软件的质量和完整性。


签署标签是断言发布的真实性的简单方法。

这在DVC中特别有用,因为任何人都可以克隆存储库并修改历史记录(例如,通过Git过滤器分支)。如果一个标签被签名,那么这个签名在Git过滤器分支操作中就不存在了,所以如果您有一个策略,即每个发布都被一个提交者标记和签名,那么就有可能在存储库中检测到一个伪造的发布标签。

如果不是签名,我也不会在带注释的标签中看到太多的意义。


推送带注释的标签,保持轻量级本地

某些Git行为确实以本建议有用的方式区分了它们,例如:

  • 带注释的标记可以包含与它们指向的提交不同的消息、创建者和日期。所以您可以使用它们来描述一个发布,而不需要提交一个发布。

    轻量级标签没有额外的信息,也不需要它,因为您只需要自己使用它来开发。

  • git push——follow标签将只推送带注释的标签
  • 没有命令行选项的git describe只看到带注释的标记

man git-tag说:

Annotated tags are meant for release while lightweight tags are meant for private or temporary object labels.

内部差异

  • 轻量级和带注释的标记都是.git/refs/tags下的一个文件,其中包含一个sha-1

  • 对于轻量级标记,sha-1直接指向提交:

    1
    2
    git tag light
    cat .git/refs/tags/light

    打印与头部的sha-1相同。

    所以难怪它们不能包含任何其他元数据。

  • 带注释的标记指向对象数据库中的标记对象。

    1
    2
    git tag -as -m msg annot
    cat .git/refs/tags/annot

    包含注释标记对象的sha:

    1
    c1d7720e99f9dd1d1c8aee625fd6ce09b3a81fef

    然后我们可以通过以下方式获取其内容:

    1
    git cat-file -p c1d7720e99f9dd1d1c8aee625fd6ce09b3a81fef

    样品输出:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    object 4284c41353e51a07e4ed4192ad2e9eaada9c059f
    type commit
    tag annot
    tagger Ciro Santilli <[email protected]> 1411478848 +0200

    msg
    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.4.11 (GNU/Linux)

    <YOUR PGP SIGNATURE>
    -----END PGP SIGNAT

    这就是它包含额外元数据的方式。从输出中可以看到,元数据字段是:

    • 它指向的对象
    • 它指向的对象类型。是的,标记对象可以指向任何其他类型的对象,如blobs,而不仅仅是提交。
    • 标签的名称
    • 标记器标识和时间戳
    • 消息。注意pgp签名是如何附加到消息的

    对格式的更详细的分析出现在:什么是git标记对象的格式以及如何计算其sha?

奖金

  • 确定标记是否已注释:

    1
    git cat-file -t tag

    输出commit表示轻量级,tag表示注释。

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


我发现了轻量级标签的一个很好的用途——在GitHub的回顾中创建一个版本。

我们确实发布了我们的软件,我们有必要的提交,我们只是不需要维护Github上的"发布"部分。当我们稍微关注一下这一点时,我们已经意识到我们也希望添加一些以前的版本,为它们提供正确的旧版本日期。

如果我们只在旧提交上创建一个带注释的标记,那么Github将从标记对象中获取发布日期。相反,当我们为这个旧提交创建了一个轻量级标记时,发布版开始显示正确的(旧)日期。source@github帮助,"关于发布"

似乎还可以为带注释的提交指定所需的日期,但我觉得这并不简单:https://www.kernel.org/pub/software/scm/git/docs/git tag.html on backdating tags


在我的办公室里,我们会把发布的网页地址放在标签正文中。发布网页详细介绍了自上次发布以来所有不同的新功能和修复。管理层不会在git repo中查找发生了什么变化,而且最好有一个关于该版本中内容的简明列表。


对我来说,重要的区别是轻量级标签没有时间戳。假设您添加了几个轻量级标签:

1
2
3
git tag v1
git tag v2
git tag v3

然后,也许稍后,您希望得到最后添加的轻量级标签。没有办法。"git-describe"和"git-tag"都不会按时间顺序给您最后一个轻量级标签。git tag-l"可以返回所有这些内容,或者按lex顺序对它们进行排序,但不能按日期/时间排序。"git describe--tags"将返回"v1",这绝对不是最后添加的标记。

另一方面,如果添加带注释的标记:

1
2
3
git tag v1 -m v1
git tag v2 -m v1
git tag v3 -m v1

你总是可以得到每个标签的时间戳,而"git-describe"肯定会返回"v3",这是最后添加的标签。


带注释的标记将额外的元数据(如作者姓名、发行说明、标记消息和日期)存储为git数据库中的完整对象。所有这些数据对于项目的公开发布都很重要。

Git标签-A v1.0.0

轻量级标记是向Git存储库添加标记的最简单方法,因为它们只存储它们所引用的提交的散列。它们可以像"书签"一样提交,因此非常适合私人使用。

Git标签v1.0.0

您可以排序、列出、删除、显示和编辑旧标记。所有这些函数都将帮助您识别代码的特定发布版本。我发现这篇文章可以帮助您更好地了解标签可以做什么。