我读了很多SO帖子,但没有一个让我理解git标签的真正工作原理,尤其是关于它们与分支的链接。我认为这是由于对 git 原则的误解。也许有人可以帮助我。
假设我有以下两个分支master
和develop
K
合并提交:
-A-B-C-D-E-F-G-K-L-M (master)
-H-I-J-/ (develop)
如果我标记J
提交,则此标记将位于两个分支上(因为合并(。 那么当我checkout
这个标签时,我会有什么版本?包含master
分支的E
、F
、G
提交或来自develop
分支的提交。不确定我是否清楚我想了解的内容。我知道标签不引用分支,而只引用提交。但是签出标签也会恢复提交历史,不是吗?
我假设分支的位置是这样的(反正这并不重要(:
v------- master
-A-B-C--D-E-F--G-K-L-M
-H-I-J-/
^------ develop
如果我标记
J
提交,则此标记将在两个分支上(因为合并(。
标记是指向提交的只读指针。一个分支也指向一个提交,但它被许多Git命令移动到另一个提交(git commit
,git merge
,git rebase
,git pull
,git reset
最常见的(。
鉴于两个分支的当前位置,实际上可以从两个分支访问J
提交。git commit
,git merge
和git pull
不会改变这种现状。但是git reset
或git rebase
可以在不是J
后代的提交上移动分支,在这种情况下,J
无法从移动的分支访问。
因此,当我签出此标签时,我会使用什么版本?包含
master
分支的 E,F,G 提交或来自develop
分支的提交。
git checkout
更改您的工作副本,使其与签出的提交相同。
如果将分支传递给git checkout
则也会使该分支成为当前分支(也称为HEAD
(。如果您传递给git checkout
不是分支的引用(它可以是标签、提交哈希或其他解析为单个提交的修订规范(,则将存储库置于名为"分离HEAD
">的状态。这意味着没有当前分支。
不建议在分离的HEAD
状态下工作(除非您知道自己在做什么(,因为以这种方式创建的提交不会由任何分支指向,并且一旦您签出另一个分支(或标记或提交(就会丢失。
假设您运行:
git tag tagJ J
要在提交J
上创建名为tagJ
的标记,以下两个命令执行相同的操作:
git checkout J
git checkout tagJ
它们更改工作树和索引以匹配提交J
中记录的项目状态。他们将存储库设置为分离的HEAD
状态。
命令:
git checkout develop
更改工作树和索引的方式与上述两个命令相同。但是,它不会将存储库设置为分离的HEAD
状态,而是develop
设置为HEAD
(当前分支(。
但是签出标签也会恢复提交历史,不是吗?
历史记录由分支和标记确定。可从任何分支或标记访问的任何提交都是历史记录的一部分。如果删除master
分支,则存储库的历史记录将仅包含可从develop
分支访问的提交(即A
、B
、C
、H
、I
和J
(。如果删除develop
分支(并保留master
分支(,则不会丢失任何内容,因为图形中可见的所有提交都可以从提交M
(由master
分支指向(访问。
您可以签出标签,但这会使您的存储库处于分离的 HEAD 状态。本质上不在任何分支上。
请参阅 Git 标记。