去年,我的日常风投工作从Subversion转向了Git,现在我仍在努力把握“Git思维”的精髓。

最近困扰我的一个问题是“轻量级”、带注释的标签和签名标签。在所有实际应用中,带注释的标签都优于轻量级标签,这似乎是被普遍接受的,但我发现为什么会出现这种情况的解释似乎总是归结为“因为最佳实践”或“因为它们不同”。不幸的是,如果不知道为什么这是最佳实践,或者这些差异与我的Git使用有什么关系,这些都是非常不令人满意的论点。

当我第一次切换到Git时,轻量级标签似乎是自切片面包以来最好的东西;我可以指向一个提交并说“那是1.0”。我很难理解一个标签怎么可能需要更多,但我当然不能相信Git专家们随意地喜欢带注释的标签!那么,这些喧嚣是关于什么的呢?

(附加提示:为什么我需要在标签上签名?)

EDIT

我已经成功地相信带注释的标签是一件好事——知道谁在什么时候做了标记是很重要的!作为后续,关于好的标记注释有什么建议吗?无论是git标记-am“标记1.0”1.0,还是尝试总结提交日志,因为之前的标记感觉像是丢失了策略。


默认情况下,Git只将带注释的标记作为Git describe等命令的基线。将带注释的标签视为对自己和他人具有持久意义的标志,而轻量级标签更像书签,供日后自己寻找。因此,带注释的标记值得作为参考,而轻量级标记则不应该。

在标签上签名是签名者身份的保证。例如,它可以让用户验证他们获得的Linux内核代码是否与Linus Torvalds实际发布的代码相同。签名也可以是签名者在提交时担保软件质量和完整性的断言。


The big plus of an annotated tag is that you know who created it. Just like with commits, sometimes it's nice to know who did it. If you're a developer and you see that v1.7.4 has been tagged (declared ready) and you're not so sure, who do you talk to? The person whose name is in the annotated tag! (If you live in a distrustful world, this also keeps people from getting away with tagging things they shouldn't.) If you're a consumer, that name is a stamp of authority: that's Junio Hamano saying this version of git is hereby released.

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

签名标签和其他任何东西都差不多——它为偏执狂提供了更高一级的安全性。我们大多数人都不会使用它,但如果你真的想在把软件安装到电脑上之前验证一切,你可能会需要它。

编辑:

As for what to write in a tag annotation, you're right - there's not always much useful to say. For a version number tag, it's implicitly understood that it marks that version, and if you're happy with your changelogs elsewhere, there's no need to put one there. In this case, it's really the tagger and date that are the most important. The only other thing I can think of is some sort of stamp of approval from a test suite. Have a look at git.git's tags: they all just say something like "Git 1.7.3 rc1"; all we really care about is Junio Hamano's name on them.

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


为标签签名是断言发布的真实性的一种简单方法。

这在DVCS中特别有用,因为任何人都可以克隆存储库并修改历史(例如通过git-filter-branch)。如果标记已签名,则签名将无法在git-filter-branch操作中存活,因此如果您有一种策略,即每个版本都由提交者标记并签名,那么就有可能在存储库中检测到虚假的发布标记。

如果不是为了签名,我也不会认为带注释的标记有多大意义。


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

带注释的标记是那些打算为其他开发人员发布的标记,很可能是新版本(也应该签名)。不仅可以看到谁被标记,什么时候被标记,还可以看到为什么被标记(通常是一个变更日志)。 轻量级更适合私人使用,这意味着标记特殊的提交,以便能够再次找到它们。可能是为了复习它们,检查它们来测试一些东西或其他什么。


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

Git的某些行为确实在某些方面有所区别,这个建议是有用的,例如:

带注释的标记可以包含与它们所指向的提交不同的消息、创建者和日期。因此,您可以使用它们来描述一个发布,而不进行发布提交。 轻量级标签没有这些额外的信息,也不需要它,因为您只会在开发过程中使用它。 Git push——follow-tags只会推送带注释的标签 没有命令行选项的Git描述只能看到带注释的标记

男人说:

带注释的标记用于发布,而轻量级标记用于私有或临时对象标签。

内部差异

both lightweight and annotated tags are a file under .git/refs/tags that contains a SHA-1 for lightweight tags, the SHA-1 points directly to a commit: git tag light cat .git/refs/tags/light prints the same as the HEAD's SHA-1. So no wonder they cannot contain any other metadata. annotated tags point to a tag object in the object database. git tag -as -m msg annot cat .git/refs/tags/annot contains the SHA of the annotated tag object: c1d7720e99f9dd1d1c8aee625fd6ce09b3a81fef and then we can get its content with: git cat-file -p c1d7720e99f9dd1d1c8aee625fd6ce09b3a81fef sample output: object 4284c41353e51a07e4ed4192ad2e9eaada9c059f type commit tag annot tagger Ciro Santilli <your@mail.com> 1411478848 +0200 msg -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) <YOUR PGP SIGNATURE> -----END PGP SIGNAT And this is how it contains extra metadata. As we can see from the output, the metadata fields are: the object it points to the type of object it points to. Yes, tag objects can point to any other type of object like blobs, not just commits. the name of the tag tagger identity and timestamp message. Note how the PGP signature is just appended to the message A more detailed analysis of the format is present at: What is the format of a git tag object and how to calculate its SHA?

奖金

判断一个标签是否带注释: Git cat-file -t标签 输出提交为轻量级,标签为注解。 只列出轻量级标签:如何列出所有轻量级标签?


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

我们确实发布了我们的软件,我们有必要的提交,我们只是没有费心去维护GitHub上的“发布”部分。当我们注意到这一点时,我们意识到我们也想添加一些以前的版本,并为它们提供正确的旧发布日期。

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

似乎也可以为带注释的提交指定你想要的日期,但在我看来并不那么简单: https://www.kernel.org/pub/software/scm/git/docs/git-tag.html#_on_backdating_tags


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

Git标记-a v1.0.0

轻量级标记是向git存储库添加标记的最简单方法,因为它们只存储它们引用的提交的哈希值。它们可以充当提交的“书签”,因此,它们非常适合私人使用。

Git标记v1.0.0

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


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

git tag v1
git tag v2
git tag v3

然后,也许稍后,你想要最后添加轻量级标签。没有办法做到这一点。“git描述”和“git标签”都不会按时间顺序给出最后一个轻量级标签。"git tag -l"可以返回它们的全部或按lex顺序排序,但不能按日期/时间排序。"git describe——tags"将返回"v1",这肯定不是最后添加的标签。

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

git tag v1 -m v1
git tag v2 -m v1
git tag v3 -m v1

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