标记和提交消息之间的区别

Difference between tag and commit message

我知道人们总是需要一条消息来提交更改,但是什么时候以及为什么我还需要标记一次提交?假设我做了一些更改并承诺使用

git add -A
git commit -m "add feature 1"

现在

git tag -a -m "includes feature 1" v0.1

问题是这什么时候有意义。

当您发布您正在生产的软件版本时指定一个标签是有意义的。

然后你可以这样做:

git tag -a v1.0 -m "Release Version 1.0"

就像我提到的评论一样,您不必在每次提交后都添加标签,就像您在 post 中提到的那样,如果您不想包含消息,也可以创建轻量级标签。这看起来像:

git tag v1.0

希望对您有所帮助。

首先,让我们定义提交分支名称标签名称[=169]之间的区别=].然后,我会将其余部分外包给 What is the difference between an annotated and unannotated tag? 上的现有问题和优秀答案。只有 带注释的 标签接受消息。

定义提交

A commit 是 Git 存储库中的 object。 Git 存储库 object 是 mostly-permanent 并且完全是 read-only,并且是 consistency-checked,因此它们是不可破坏的。 objects 有四种:commits(我们稍后会详细描述),treesblobs,和 注释标签 objects。所有四种都由哈希 ID 标识。

A blob 非常粗略地说,Git 存储文件内容的位置:如果您的 README 文件显示 I am a readme file,则字符串I am a readme file 存储为 blob。一个 tree object 是一个稍微过于简单的东西,它存储文件的 name 以及文件内容的 blob 哈希 ID。因此,为了提交 1234567... 来存储你的 README 文件,Git 有一个树说 "file README has contents from blob c3c2a8983de728ffcf8f0ccaad014349925f23e6".1

无论如何,每次提交存储一个 hash ID,这是你源文件2当时保存的快照你做出了承诺。它还存储此提交的 parent 提交的哈希 ID,以便 Git 可以通过历史向后查找所有提交。它存储您的姓名和电子邮件地址以及时间戳,作为提交人和提交时间。3

在这些必需的项目——树、parent(s)、作者和提交者之后——Git 添加你的 日志消息,这完全是任意的就 Git 本身而言。您根本不必提供任何日志消息,即使您提供了日志消息,也没有任何意义。但是,当您和其他人浏览存储在存储库中的历史记录(提交)时,它会显示

提交表单链,这是历史

因为每个提交都记录了其较早的 parent 提交,所以提交集形成了一个可以向后读取的链:

A  <-B  <-C   <--master

Git 可以以 name 开头,例如分支名称 master,以获取提交 C 的哈希 ID(无论它的真实哈希 ID 可能是:我在这里使用 C 作为 shorthand 而不是实际的哈希)。此哈希 ID 对于提交 C 是唯一的:任何地方都没有其他提交具有相同的哈希 ID。4 提交 C 本身存储提交 [=25 的哈希 ID =],所以从 C 我们可以找到 BB 存储提交 A 的哈希 ID,因此从 B 我们可以找到 A.

这个特定的存储库只有三个提交:Aroot 提交,这是我们所做的第一个提交,所以它没有 parent,这让我们停止追随历史。

分支和标签名称查找提交

但这也告诉我们分支名称是什么以及做什么:A 分支名称 是通过提交的哈希 ID 标识提交的名称。 标签名做同样的事情。所以现在我们可能想知道:有什么区别?什么时候用分支名,什么时候用标签名?

除了名称空间的问题,6 主要区别在于 Git 让我们得到 "on" 一个分支名称,使用 git checkout。一旦我们在这样的分支上,创建 new 提交会产生副作用:它 更改与分支名称 关联的哈希 ID。如果我们签出 master 并进行 新提交 ,则新提交中存储的 parent ID 就是 C 的 ID。无论 new 提交的哈希 ID 是什么,由 Git 计算,新的哈希 ID 进入名称 master,所以我们现在有:

A--B--C--D   <-- master

名称 master 现在 指向 新提交 D,指向 C,指向 [=25] =],等等。分支已经增长,分支名称指向最新提交。每个提交都指向前一个提交。

您无法获得 "on" 这样的标签。 标签名称 v1.0,一旦设置为指向提交 C,将永远指向提交 C。所以这是 Git 中分支名称和标记名称之间的主要区别: 分支名称会随时间变化,甚至在您提交时会自动更改。标签名称不应该7改变。


1c3c2a8983de728ffcf8f0ccaad014349925f23e6是读取I am a readme file的内容的hash ID。您可以通过 运行 执行以下 shell 命令找到它:

$ echo 'I am a readme file' | git hash-object -t blob --stdin
c3c2a8983de728ffcf8f0ccaad014349925f23e6

请注意,宇宙中任何 Git 存储库中任何地方的任何 blob object 都具有此哈希 ID,如果它作为这个内容!内容必须仅包含这 19 个字节,包括终止换行符(没有 carriage-return)。

2更准确地说,它是保存的 index,又名 暂存区 又名 缓存,如git write-tree.

所写

3Git 将这些存储两次,一次作为提交的 author,另一次作为 提交者。如果你是,例如,将别人的提交,他们通过电子邮件发送给你,并将其插入存储库,那么两者就会变得不同:那么 author 就是向你发送提交的人,但是你是提交者。在其他情况下,两者会变得不同。大多数情况下,没人在意,但 运行 git log --pretty=fuller 两者都要看。

4哈希 ID 可以不同的存储库中重复,但前提是两个存储库永远不会聚在一起。为确保提交哈希 ID 是唯一的,Git 包括那些 time-stamps。这确保即使您使用相同的树和相同的 parent 和相同的日志消息进行之前所做的 相同的 提交,如果您在不同的 time,这是一个不同的commit。 (如果你在同一时间做出来,那就真的一模一样了,何必纠结一次还是两次呢?5)

5有一个潜在的理由值得关注,但它相当晦涩,而且大多无关紧要。

6从技术上讲,分支名称是以 refs/heads/ 开头的 reference,例如 refs/heads/mastermaster 分支的完整拼写。标记名称是以 refs/tags/ 开头的引用,例如 refs/tags/v1.0。这些是参考 名称空间 ,其中包括 refs/remotes/refs/notes/refs/replace/refs/stash

7好吧,几乎没有。有些人真的想要一个"floating tag"。你 可以 在 Git 中执行此操作,前提是你小心并且知道自己在做什么。但是,没有实际意义:如果您想要一个移动的名称,请使用分支名称。他们就是这么做的。如果您想要一个不会移动的名称,请使用标签名称。 他们就是这么做的。