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

Mas*_*eri 5 git git-commit git-tag

我了解人们总是需要一条消息来提交更改,但是何时以及为什么还需要标记一次提交?假设我进行了一些更改并使用

git add -A
git commit -m "add feature 1"
Run Code Online (Sandbox Code Playgroud)

现在

git tag -a -m "includes feature 1" v0.1
Run Code Online (Sandbox Code Playgroud)

问题是,何时才有意义。

tor*_*rek 17

首先,让我们定义commitbranch nametag name之间的区别。然后,我会将其余部分外包给现有的问题和出色的答案,注释和未注释标签之间的区别是什么? 请注意,轻量级标签(未注释)不接受消息;只有带注释的标签才会接收消息。

定义提交

提交是一个对象在一个Git仓库。Git 存储库对象大多是永久性的且完全只读的,并且经过一致性检查,因此它们不会损坏。有四种对象:提交(我们将在稍后详细描述)、blob和带注释的标记对象。所有四种都由哈希 ID 标识。

一个blob是 Git 存储文件内容的地方:如果你的README文件显示为I am a readme file,则该字符串I am a readme file将存储为blob。一个对象,稍微过于简单的事情,存储文件的名称与该文件的内容的BLOB哈希ID一起。因此,为了提交1234567...存储您的README文件,Git 有一棵树,上面写着“文件README包含来自 blob 的内容c3c2a8983de728ffcf8f0ccaad014349925f23e6”。1

在任何情况下,每个提交都会存储一个哈希 ID,它是您提交时源文件2的保存快照。它还存储此提交的提交的哈希 ID ,以便 Git 可以通过历史向后查找所有提交。它存储您的姓名和电子邮件地址以及时间戳,作为提交的人和时间。3

在这些必需的项目(树、父项、作者和提交者)之后,Git 添加您的日志消息,就 Git 本身而言,这完全是任意的。您根本不必提供任何日志消息,如果您确实提供了一条,它也没有任何意义。它将,但是,被显示给你,并给其他人,当他们探索历史的提交,存储在仓库中。

提交表单链,这是历史

因为每个提交都记录了它之前的提交,所以提交集形成了一个可以向后读取的链:

A  <-B  <-C   <--master
Run Code Online (Sandbox Code Playgroud)

Git 可以以名称开头,例如分支名称master,以获取提交的哈希 ID C(无论其真正的哈希 ID 是什么:我C在这里使用速记而不是实际的哈希)。这个哈希 ID 对提交是唯一的C:任何其他提交都没有相同的哈希 ID。4 CommitC本身存储了commit的hash ID B,所以从这里C我们可以找到B. B存储 commit 的哈希 ID A,因此B我们可以找到A.

这个特定的存储库只有三个提交:A提交,我们做过的第一个提交,所以它没有父提交,这让我们停止跟踪历史。

分支和标签名称查找提交

但是,这也告诉我们一个分支的名字是和作用:一个分支名是一个标识提交的名称,由提交的哈希ID。一个标签名做同样的事情。 所以现在我们可能想知道:有什么区别?我们什么时候应该使用分支名称,什么时候应该使用标签名称?

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

A--B--C--D   <-- master
Run Code Online (Sandbox Code Playgroud)

该名称master现在指向新提交D,指向回C,指向回B,依此类推。分支已经增长,分支名称指向最新的提交。每个提交都指向前一个提交。

你不能“贴上”这样的标签。该标签名 v1.0,一旦它的设置为指向承诺C,会继续指向承诺C,永远。所以这是 Git 中分支名称和标签名称之间的主要区别:分支名称会随着时间而变化,甚至在您进行提交时会自动更改。标签名称永远不应该7改变。


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

$ echo 'I am a readme file' | git hash-object -t blob --stdin
c3c2a8983de728ffcf8f0ccaad014349925f23e6
Run Code Online (Sandbox Code Playgroud)

请注意,Universe 中任何 Git 存储库中任何位置的任何 blob 对象都具有此哈希 ID(如果它包含此内容)!内容必须仅包含这 19 个字节,包括终止的换行符(没有回车符)。

2更确切地说,它是保存指数,又名候区又名缓存,通过写出来git write-tree

3 Git 将这些存储两次,一次作为提交的作者,另一次作为提交者。如果您是,例如,接受他们通过电子邮件发送给您的其他人的提交,并将其插入到存储库中,则两者将变得不同:那么作者是向您发送提交的人,而您是提交者。在其他情况下,两者会变得不同。在大多数情况下,没有人关心,而是跑去git log --pretty=fuller看看两者。

4 Hash ID可以不同的存储库中重复,但前提是这两个存储库永远不会放在一起。为了确保提交哈希 ID 是唯一的,Git 包含这些时间戳。这可以确保即使您使用相同的树、相同的父级和相同的日志消息进行与之前相同的提交,如果您在不同的时间进行提交,也会是不同的提交。(如果你在使同一时间,那么它真的一模一样,为什么你关心,如果你做一次或使其两次?5

5有一个潜在的需要关心的理由,但它很模糊,而且大多无关紧要。

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

7嗯,几乎没有。有些人真的想要一个“浮动标签”。如果您小心并知道自己在做什么,您可以在 Git 中执行此操作。不过,这没有实际意义:如果您想要一个可移动的名称,请使用分支名称。这就是他们所做的。如果您想要一个不会移动的名称,请使用标签名称。这就是他们所做的。


dim*_*mal 5

在发布所生产软件的版本时,指定标签是很有意义的。

然后,您可以执行以下操作:

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

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

git tag v1.0

希望这可以帮助。