Git - 是否可以添加标签并将其作为提交?与 Mercurial 完全一样

Git - is it possible to add tag and have it as commit? Exactly as in Mercurial

当我使用 Mercurial 时,我曾经有一个标记作为提交 - 至少在 TortoiseHG 中它在添加标记时创建了一个提交。当我尝试使用 Git 时,我很失望 - 它没有为标签创建提交,而且 - 当我从 Intellij IDEA 提交时,我必须选中一个复选框以将标签提交到存储库。是否可以在 Git 中添加标记并将其作为提交,就像在 Mercurial 中一样?非常感谢您的每一个回答。

, this seems like an XY problem。但是 Git 和 Mercurial 中的标签有一个根本的区别,因为 Mercurial 标签是文件中的一个 条目 ,而 Git 标签是一个 位于存储库外部的名称 space(尽管带注释的标记也包含存储库对象)。

特别是,Mercurial 将标签作为条目存储在名为 .hgtags 的文件中。该条目给出了标记的名称和任何其他有用的数据,包括标记提交的哈希 ID。为了将更新的 .hgtags 文件放入存储库,Mercurial 必须在将条目添加到 .hgtags 文件后进行 new 提交。

这有一个基本的(尽管很小)缺点:提取标记的提交会导致 .hgtags 文件缺少标记,从而使标记消失。为了弥补这一点,现代 Mercurial 会找到 .hgtags 的多个版本,包括一个来自晚于当前提交的提交,以便在给定标签名称的情况下找到正确的提交。

Git,相比之下,将标签存储为 refs/tags/<em>name</em>[=79= 形式的轻量级名称] 直接指向提交,或作为指向类型 <code>tag 的存储库对象的相同形式的轻量级名称,存储库对象保存标签目标的哈希 ID。这意味着创建标签不会干扰现有的存储库内容;没有包含标签的存储库 文件

标签的正常设计目标是标签永远不会改变,也永远不会消失:它们充当 的仅附加存储池对(可能有额外的数据)。如果实际上以这种方式使用标签,则 Git 和 Mercurial 方法的行为相同,除了 Mercurial 需要额外提交而 Git 不需要的怪癖。

在实践中,人们会犯错误:他们不小心移动标签,甚至故意移动标签以试图掩盖早先发生的事故。因此,与 Git 标签相比,Mercurial 的方法也有一个基本的审计跟踪优势:我们可以在任何提交时查看标签 是什么,即使有人从那以后 改变了 它们。 Git的方法的优点是我们无法看到这一点,因此不会被它混淆:标签v2.1无法命名both commit a93fc12... and e07c1c4...,这取决于我们目前检出的提交。 (请注意,由于提交仅提供部分顺序,而不是全部顺序,因此在 Mercurial 中存在歧义的情况下,我们可能无法使用 "commit order" 来选择最终获胜者。)

综上所述,如果您希望在 Git 中创建一个 new 提交以便有一个唯一的提交哈希来标记,只需创建一个新的提交。 1 虽然 Git 默认会拒绝提交与当前提交相同内容的尝试,但 git commit 有一个标志来强制这样的提交:--allow-empty. (这个标志有点命名错误:新提交不是 empty,它是由 comparing[=75] 产生的 change-set =] 对其父项的新提交是空的。)创建新的提交对象后,您将拥有一个新的唯一哈希 ID。

不过,使用 annotated 标签具有指向新注释标签对象的轻量级名称这一事实可能会更好。这个新的标签对象,就像一个新的提交一样,保证是唯一的(再次参见脚注 1)。您可以像使用提交 ID 一样使用标记对象的哈希 ID,只要系统的其余部分准备好处理标记对象并通过它间接查找提交即可。


1请注意,每个提交都有一个时间戳(或更准确地说,两个个时间戳,但默认情况下,新提交有它们都设置为相同的值)。只要我们假设时间是单调递增的,这就意味着即使一个新的提交是现有提交的副本——也就是说,它有相同的 tree、相同的 authorcommitter,与某些现有提交相同的 parent 和相同的日志消息——它将具有不同的 时间戳 ,因此是不同的提交。

然而,当我们通过一些自动化机器进程进行提交时,我们可以每秒进行多次提交,即使时间表现良好,时间戳的粒度也是一秒。这意味着在某些情况下——特别是当使用 --allow-empty 并使用 相同的父级 进行提交时,例如,通过更改我们的机器进程提交时的分支名称——可以使用 与旧提交完全相同的数据 进行 "new" 提交,因此据称新提交具有 相同的哈希 ID。在这种情况下,我们假设每个提交哈希 ID 都是唯一的:它对于提交的内部数据是唯一的,但是由于提交的内部数据与先前提交的内部数据匹配,所以这两个提交 相同 在基本意义上,所以当我们期望它们获得不同的哈希 ID 时,它们获得相同的提交哈希 ID。

这意味着当我们编写代码进行提交时,我们必须仔细检查我们的假设。这同样适用于机器制造的带注释标签:我们可以让机器每秒制造很多这样的标签,所以我们应该小心确保它们的内部数据不同,而不仅仅是依赖单调递增的时间戳。