688

我在理解如何在标签分支时遇到了一些困难。

我刚刚将我们代码的当前版本从移动到,现在我将针对特定功能处理该代码的子集。其他一些开发人员也将致力于此,但并非我们小组中的所有开发人员都会关心此功能。我应该创建分支还是标签?在什么情况下我应该使用一种与另一种?

4

13 回答 13

581

理论上讲

  • 标签是给定版本的符号名称。它们总是指向同一个对象(通常:指向同一个版本);他们不会改变。
  • 分支是发展线的象征性名称。新的提交是在分支之上创建的。分支指针自然地前进,指向越来越新的提交。

技术角度:

  • 标签驻留在refs/tags/命名空间中,并且可以指向标签对象(带注释的和可选的 GPG 签名标签)或直接指向提交对象(用于本地名称的较少使用的轻量级标签),或者在极少数情况下甚至指向树对象blob 对象(例如 GPG 签名)。
  • 分支驻留在refs/heads/命名空间中,并且只能指向提交对象HEAD指针必须指向一个分支(符号引用)或直接指向一个提交(分离的 HEAD 或未命名的分支)。
  • 远程跟踪分支驻留在refs/remotes/<remote>/命名空间中,并遵循远程存储库中的普通分支<remote>

另请参阅gitglossary联机帮助页:

分支

“分支”是一条活跃的发展路线。分支上的最新提交称为该分支的尖端。分支的尖端由分支头引用,随着在分支上完成额外的开发,它会向前移动。单个 git 存储库可以跟踪任意数量的分支,但您的工作树仅与其中一个关联(“当前”或“签出”分支),并且 HEAD 指向该分支。

标签

指向标签或提交对象的 ref。与头相比,提交不会更改标签。标签(不是标签对象)存储在$GIT_DIR/refs/tags/. [...]。标签最常用于标记提交祖先链中的特定点。

标记对象

包含指向另一个对象的 ref 的对象,该对象可以像提交对象一样包含消息。它还可以包含(PGP)签名,在这种情况下,它被称为“签名标签对象”。

于 2009-09-22T00:12:24.757 回答
577

一个标签代表一个特定分支在某一时刻的一个版本。一个分支代表一个单独的开发线程,它可以与同一代码库上的其他开发工作同时运行。对分支的更改最终可能会合并回另一个分支以统一它们。

通常你会标记一个特定的版本,以便你可以重新创建它,例如,这是我们发给 XYZ Corp 的版本。一个分支更多的是一种策略,在继续对其进行开发的同时,对特定版本的代码进行持续更新。您将创建交付版本的分支,继续在主线上进行开发,但对代表交付版本的分支进行错误修复。最终,您会将这些错误修复合并回主线。通常你会同时使用分支和标记。您将拥有各种标签,这些标签可能适用于主线及其分支,标记您可能想要重新创建的每个分支的特定版本(例如,那些交付给客户的版本)——用于交付、错误诊断等。

它实际上比这更复杂——或者像你想要的那样复杂——但这些例子应该让你了解它们之间的区别。

于 2009-09-21T22:03:52.940 回答
158

如果您将存储库视为记录项目进度的书...

分支机构

您可以将分支视为那些粘性书签之一:

在此处输入图像描述

一个全新的存储库只有其中一个(称为master),它会自动移动到您编写的最新页面(想想commit )。但是,您可以自由创建和使用更多书签,以便标记书中的其他兴趣点,以便您快速返回它们。

此外,您始终可以将特定书签移动到书籍的其他页面(git-reset例如,使用 );兴趣点通常会随着时间而变化。

标签

您可以将标签视为章节标题

书签

它可能包含标题(想想带注释的标签)或不包含。标签与分支相似但不同,因为它标志着书中的历史兴趣点。为了保持它的历史特征,一旦你共享了一个标签(即把它推送到一个共享的遥控器上),你就不应该把它移到书中的其他地方。

于 2014-09-16T17:05:10.263 回答
43

来自 CVS 的您需要意识到的是,您在设置分支时不再创建目录。
不再有“粘性标签”(只能应用于一个文件)或“分支标签”。
分支和标签是 Git 中的两个不同对象,它们始终适用于所有repo。

您将不再(这次使用 SVN)必须明确地构建您的存储库:

branches
   myFirstBranch
     myProject
       mySubDirs
   mySecondBranch
     ...
tags
   myFirstTag
     myProject
       mySubDirs
   mySecondTag
   ...

这种结构源于 CVS 是修订系统而不是版本系统这一事实(请参阅源代码控制与修订控制?)。
这意味着通过 CVS 的标签和 SVN 的目录副本来模拟分支。

如果您习惯于签出标签并开始在其中工作,那么您的问题是有意义的。
您不应该这样做;)
标签应该代表不可变的内容,仅用于访问它并保证每次都获得相同的内容。

在 Git 中,修订历史是一系列提交,形成一个图表。
分支是该图的一条路径

x--x--x--x--x # one branch
    \ 
     --y----y # another branch
       1.1
        ^
        |
        # a tag pointing to a commit
  • 如果你签出一个标签,你需要创建一个分支来开始工作。
  • 如果您签出一个分支,您将直接看到该分支的最新提交它('HEAD')。

有关所有技术细节,请参阅Jakub Narębski 的回答,但坦率地说,在这一点上,您不需要(还)所有细节;)

要点是:标签是指向提交的简单指针,您将永远无法修改其内容。你需要一个分支。


就您而言,每个开发特定功能的开发人员:

  • 应该在各自的存储库中创建自己的分支
  • 从他们同事的存储库中跟踪分支(使用相同功能的存储库)
  • 拉/推,以便与同行分享您的工作。

您可以只跟踪一个“官方”中央存储库的分支,而不是直接跟踪您的同事的分支,每个人都将他/她的工作推送到该分支,以便集成和共享每个人针对该特定功能所做的工作。

于 2009-09-22T07:10:08.713 回答
38

树枝是用木头做的,从树干上长出来。标签由纸(木材的衍生物)制成,像圣诞装饰品一样悬挂在树上的各个地方。

您的项目就是树,您将添加到项目中的功能将在一个分支上生长。答案是分支。

于 2015-10-16T20:50:43.603 回答
17

看起来最好的解释方式是标签充当只读分支。您可以将分支用作标签,但您可能会无意中使用新提交对其进行更新。只要标签存在,就保证它们指向同一个提交。

于 2012-08-28T23:32:11.280 回答
17

我喜欢把分支想象成你要去的地方,把标签想象成你去过的地方

一个标签感觉就像是过去某个特定重要点的书签,例如版本发布。

而分支是项目正在下降的特定路径,因此分支标记会随着您前进。完成后,您合并/删除分支(即标记)。当然,此时您可以选择标记该提交。

于 2018-12-02T14:41:29.360 回答
16

标签可以是有符号或无符号的;分支永远不会签名。

签名标签永远不能移动,因为它们被加密绑定(带有签名)到特定的提交。未签名的标签未绑定并且可以移动它们(但移动标签不是正常的用例)。

分支不仅可以移动到不同的提交,而且应该这样做。您应该为本地开发项目使用分支。将工作提交到“标签上”的 Git 存储库是没有意义的。

于 2009-09-21T22:03:04.190 回答
11

简单的答案是:

分支:当前分支指针随着每次提交到存储库而移动

标签:标签指向的提交不会改变,实际上标签是该提交的快照。

于 2019-08-25T10:00:52.387 回答
10

Git Parable解释了一个典型的DVCS 是如何创建的,以及为什么他们的创建者做了他们所做的事情。此外,您可能想看看Git for Computer Scientist;它解释了 Git 中每种类型的对象的作用,包括分支和标签。

于 2009-09-22T06:03:33.513 回答
6

标签用于标记版本,更具体地说,它引用分支上的时间点。分支通常用于向项目添加功能。

于 2016-05-08T20:54:41.427 回答
4

简单的:

预计标签始终指向项目的同一版本,而负责人预计会随着开发的进展而前进。

Git 用户手册

于 2017-11-12T12:25:22.787 回答
0

我们用

  • branchesdev功能开发或错误修复的环境中
  • lightweight tags对于test功能分支上的环境
  • annotated tags对于发布/prd(主分支)

在每个带注释的标签之后,所有功能分支都从主分支变基。

正如其他人所说,abranch是一条发展路线,head随着新提交的到来而向前发展。这是功能开发的理想选择。

Lightweight tag固定到特定的提交,这使得创建内部版本并让 qa 团队在开发完成后测试功能非常理想。

Annotated tag非常适合发布到生产,因为我们可以在将测试的功能分支合并到主分支(稳定)时添加正式消息和其他注释。

使用 Git 进行发布管理

于 2021-12-08T09:54:37.703 回答