通常,1 origin/somebranch
不是分支名称,因此git checkout origin/somebranch
会导致分离的 HEAD,正如您所看到的那样。
在 Git 中,分支名称并没有真正起到任何作用,首先是近似的。2 所以没有必要使用它们。要了解这种情况的发生方式和原因,请注意在 Git 中,名称有很多种。
分支名称只是一个名称,当完整拼写时,以 . 开头refs/heads/
。例如,分支名称master
或main
是真正的refs/heads/master
和refs/heads/main
,相应地。
标签名称是一个名称,当完整拼写时,以 . 开头refs/tags/
。v2.1
确实如此refs/tags/v2.1
。
Git 将这些东西称为这些东西——通常是这些名称,在它们被分成某些特定的分类之前——<em>refs 或references。每个引用包含一 (1) 个哈希 ID。哈希 ID 对 Git 来说才是真正重要的。这就是 Git需要的。这就是git checkout
需要的:哈希 ID。你可以给它任何有效的提交哈希 ID,它会检查那个提交。
然而,哈希 ID 又大又丑,而且看起来很随机(尽管它们不是)。它们完全令人难忘。无论如何提交是什么225365fb5195e804274ab569ac3cc4919451dc7f
?如果我说v2.31.0-rc0
,那对你来说可能意味着什么——或者至少,似乎暗示着什么;但是如果我说2253blah
你可能2253
在我开始之前很久就忘记了这个dc7f
部分。所以refs是为人类服务的。它们不适用于 Git,它只关心哈希 ID。
如果您是人类,则只需要一个 ref(例如分支名称)。如果您是构建系统,则哈希 ID 很好。如果您正在编写构建系统的一部分,只需使用哈希 ID。如果您正在编写供人类使用的东西……嗯,人类很难。
Git 有一个特殊的东西,它称为“DWIM”,或按我的意思做,模式。如果你运行:
git checkout foobranch
并且现在没有命名的分支foobranch
,Git 会假设你的意思是:给我找一个类似 foobranch
的名字,比如origin/foobranch
. 然后使用该名称为我创建一个分支名称。 您可以禁用此功能git checkout --no-guess
,有时这是个好主意。但有时这种 DWIM 模式正是您想要的。
但是请注意,如果讨厌的人早先去制造他自己 foobranch
的,与 无关origin/foobranch
,这git checkout foobranch
将得到他的 foobranch
,与 无关origin/foobranch
。所以要小心:人类是狡猾和怪异的。他们做不合逻辑的、意想不到的事情。
现在,人们经常想要使用分支名称而不是导致分离头模式的任何其他名称是有原因的。他们喜欢这个的主要原因是,如果他们进行新的提交,Git 将更改存储在分支名称中的哈希 ID。新提交将自动向后链接到存储在引用中的任何提交。然后 Git 将更新分支名称,以便它现在存储新提交的哈希 ID。
此功能是分支名称独有的。没有其他名称具有此特殊功能。使用分支名称时,您可以git checkout --detach foobranch
选择分离 HEAD 模式,例如运行。但默认情况下,当您使用git checkout
分支名称时——即使是 DWIM 模式必须创建的名称——Git 将改为进入附加 HEAD模式。3 这就是人类喜欢分支名称的原因,这就是 Git 对它们所做的事情,它与任何其他参考名称无关。
如果你需要容纳人类,你可以通过让 DWIM 模式在这里完成它的事情来做到这一点。这不会满足所有人类,所以要小心。在某些情况下它也不起作用,所以要小心。不过,分离式 HEAD 模式始终有效。
特别是在 NodeGit 中,你有Branch.create
一个Branch
. . 你也有Branch.lookup
。如果这是您的目标,您可以使用它来查找远程跟踪名称,如origin/branchname
,并使用它来创建新的本地分支。但和以前一样,请注意所有这些不同的边缘情况。
1可以创建一个名为 的(本地)分支origin/somebranch
,因此它是一个分支名称。除非您使用完整拼写仔细地调用所有名称,否则结果会非常混乱。不要这样做!
2当然,它们确实有一些好处,所以第一个近似值相当粗糙。
3 Git 没有这样称呼它,但是“与分离的 HEAD 相反”模式的正确短语还有什么?