在我的一些存储库中,我看到......
> git branch --all
* master
remotes/origin/master
...而在其他人看来:
> git branch --all
* master
remotes/origin/HEAD -> origin/master
remotes/origin/master
前者让我觉得正确,后者让我感到不安。这里发生了什么?
我之前已经包含一个映射到不同存储库的额外common
分支,并且设置它可能导致了这个问题。这个额外的分支现在已被删除,但后一个存储库中的这个奇怪的设置仍然存在。两个存储库中都没有其他遥控器,只有标准的origin
。
在我看来,在第一个,remotes/origin/master
是remotes/origin/master -> origin/master
的缩写。只有当本地和远程分支在某些方面有所不同时,才需要明确说明映射?所以有这个奇怪的remotes/origin/HEAD -> origin/master
映射,如果这是它的词,它似乎优先?
行remotes/origin/HEAD -> origin/master
只是告诉你哪个分支origin
已经检出 - 这又是在新克隆中检出的默认分支。
(我可能应该说,当最后一个本地origin
ref更新时,哪个分支remotes/origin/HEAD
已经检查过。在我的测试中,这个ref只在最初创建克隆时才更新。可能有些方法我没有想到强制它要更新。)
如果你有一个你没有看到这一行的回购,这可能意味着在制作克隆时没有检出分支 - 例如如果你克隆了一个空的存储库。
Mark Adelsberger's answer介绍了如何获得这些(git clone
制作它们)。但是让我们更一般地看一下分支名称,然后Git调用引用和符号引用。
你已经知道分支名称相对简单:它们只是像master
和develop
这样的字符串。而且,由于git branch --all
输出,你也知道你有Git有时称为远程跟踪分支名称,如origin/master
。我更喜欢称这些远程跟踪名称,以避免使用“分支”这个词太多。
您可能不知道的是,这两者都只是Git如何将所有内容整合在一起的特殊形式。像master
这样的常规分支名称实际上是一个全名拼写为refs/heads/master
的引用。像origin/master
这样的远程跟踪名称是一个全名拼写为refs/remotes/origin/master
的引用。标签也只是引用,其全名以refs/tags/
开头。
如果运行仅列出远程跟踪名称的git branch -r
,您将看到origin/master
而不是remotes/origin/master
。这是因为Git并不总是关于它剥离了多少refs/remotes/
部分。 (为什么Git在这里不一致,我不知道。)一般来说,Git喜欢将这些东西缩小到更容易管理的东西。因为所有引用总是以refs/
开头 - 那就是how Git defines them - 一般来说,你可以放弃refs/
部分,通常更多:你通常可以放弃refs/heads/
,refs/remotes/
和refs/tags/
。
什么参考对你有用 - 嗯,每个引用的一个非常重要的部分 - 是保存你见过的那些丑陋的Git哈希ID之一,例如git log
输出。在内部,Git需要那些哈希ID。但是,对于仅仅是人类来说,它们是不可能的,所以Git给了我们可以用来记住ID的名字。
但是有一个特殊的情况允许任何参考,虽然最明智的做法是保留它用于使用HEAD
这个词。任何引用都可以是符号引用。引用可以包含另一个引用的名称,而不是包含大的丑陋哈希ID。然后Git将名称转换为存储在另一个引用中的哈希ID。
因此,如果refs/remotes/origin/HEAD
包含名称refs/remotes/origin/master
,你可以说origin/HEAD
,你可以说origin/master
。这没什么帮助 - 至少,我发现用全大写origin/HEAD
键入HEAD
更难 - 但Git增加了另一个特殊情况:如果你自己使用名称origin
,在Git“想要”的地方一个哈希ID,Git会注意到origin
对应refs/remotes/origin/
,然后看到refs/remotes/origin/HEAD
存在。 Git会读它,看看refs/remotes/origin/HEAD
是refs/remotes/origin/master
的象征性参考。 Git会读取它并查看哈希ID - 现在Git将知道您的哈希ID。
因此,如果origin/HEAD
(或refs/remotes/origin/HEAD
)“指向”origin/master
,这意味着你可以在一些你通常必须写出origin
的地方写origin/master
。
您可以使用HEAD
操作这些特殊的远程跟踪the git remote
command名称,特别是使用其set-head
子命令。我自己从来没有真正打扰任何这个 - 我只是在我的意思是输入origin/master
,并忽略与这些远程跟踪名称一起使用的符号HEAD
s。但如果你喜欢它们,它们就可以供你使用。
1我在这里说“通常”,因为有一个特殊情况:如果你不小心将foo
这个名称作为分支名称(refs/heads/foo
)和标签名称(refs/tags/foo
),它就会突然变成一个问题,就是说foo
。一个解决方案是拼出heads/foo
和tags/foo
,甚至refs/heads/foo
。在the gitrevisions documentation中有更多细节,还有更多。