“git clone”后默认分支是由什么决定的?

58

我的理解是,克隆库的默认分支应该是指向被克隆仓库中HEAD所指向的分支。

现在我遇到了一个例外情况。我的理解显然是有误的,那么在克隆(bare)仓库时,什么确定了默认的检出分支呢?

该仓库上最后一次提交是将裸仓库HEAD所引用的分支与我在克隆中获取的检出分支合并。

运行git remote show origin返回:

Fetch URL: ...
Push  URL: ...
HEAD branch (remote HEAD is ambiguous, may be one of the following):
  <bad-branch>
  live
Remote branches:
  ...

裸仓库使用 Git 版本 1.8.2.1,客户端使用 1.7.12.4,传输方式为 SSH。

也许答案实际上是这个这个回答证实了这一点。如果有多个符号引用指向与 HEAD 相同的修订版本,则客户端将会猜测要使用哪个分支。


你能设置一个复现器吗?涉及哪些版本的git(在克隆者和被克隆者上)?使用了什么传输方式? - torek
是的,我也遇到了同样的问题。看起来客户端选择了一个指向远程HEAD所指向的相同提交的分支。这是在我删除master分支并将另一个新分支设置为默认分支后发生的。目前还有一些其他分支也指向这个新默认分支的最新提交。 - Vicro
5个回答

35

Git 1.8.5开始,服务器将在“symref”功能中发送HEAD所指向的实际分支名称。如果您的客户端和服务器均高于Git 1.8.5,则会正确更新HEAD

在此之前,客户端将通过将HEAD(最终)指向的对象ID与所有分支的对象ID进行比较来猜测HEAD可能指向的位置。它更喜欢名为refs/heads/master的分支:如果HEADmaster指向相同的对象ID,则克隆操作将把新存储库中的默认分支设置为master

否则,当分支按字母数字排序时,第一个具有匹配OID的分支将成为默认分支。如果没有分支具有匹配的OID,则HEAD将直接设置为该对象ID(即分离的HEAD)。


从Git 1.8.5开始,服务器将发送HEAD指向的实际分支名称。我不太理解。我的理解是HEAD是当前检出分支中最后一次提交的引用。这句话意味着HEAD与已检出的分支无关。那么从Git 1.8.5开始将使用哪个分支? - Rob Bednark
4
HEAD实际上不是指向提交的指针,而是指向一个“分支”的指针,这决定了“当前检出的分支”是什么。因此,要确定最后一次提交,首先查看指向(例如)masterHEAD,而master实际上指向一个提交。 - Edward Thomson
2
(请注意,为了技术上的正确性,应该说 HEAD 通常不是指向提交的指针。如果你进入了“分离 HEAD 状态”,即直接检出提交而不是分支,则 HEAD 实际上将指向一个提交。) - Edward Thomson
1
这种方法对我很有效 - 我登录到保存Git仓库的远程服务器上,并更新了仓库文件夹中的HEAD文件。我将其从“ref:refs/heads/master”更改为“ref:refs/heads/develop”。然后在我的本地机器上进行了新的checkout,Git clone后默认选择了“develop”分支。 - Harri

17

当我研究这个问题时,我偶然发现了那个网站 - 正如我在其他回答中评论的那样,这是一个例子,一般情况下并不适用。由于我明显没有得到裸版本库HEAD中引用的分支,所以可能会涉及更多内容。 - Christian Goetze

7
一个裸仓库也有一个HEAD。当您克隆它时,就会得到这个。
git clone 文档中了解到:
将存储库克隆到新创建的目录中,为克隆存储库中的每个分支创建远程跟踪分支(可使用 git branch -r 查看),并创建并检出一个初始分支,该分支从克隆存储库的当前活动分支分叉而来。
关于“当前活动分支”的部分是指远程的HEAD修订版。
如果您想要不同的行为,可以使用--branch-b--branch <name>
-b <name>
代替将新创建的HEAD指向克隆存储库的HEAD所指向的分支,而是将其指向<name>分支。在非裸仓库中,这是将被检出的分支。--branch也可以接受标签,并在生成的存储库中卸载该提交的HEAD

3
我的问题是看起来似乎不是真的。在远程裸仓库中,HEAD 包含 "ref: refs/heads/live"。当我克隆时,我被指向了另一个分支。现在,事实证明该分支的最后一次提交是从“远程跟踪分支'origin/live'”合并到该分支的。有些奇怪。 - Christian Goetze
没有访问您的代码库,我无法进一步评论,但默认情况下确实会获取HEAD。 - Carl Norum

4

它是origin/HEAD。但是,如果你想要像“origin/master”这样的名称,你需要像这样解析文件。

cat .git/refs/remotes/origin/HEAD | awk '{ print $2 }'

git目录并不总是.git(例如在子模块中),因此您应该使用rev-parse --git-dir来查找它。 - xeruf

2
如果想手动检查远程仓库的默认分支,以下方法应该可靠:
git switch $(cat $(git rev-parse --git-dir)/refs/remotes/origin/HEAD | cut -d'/' -f4)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接