3

我有一个远程裸存储库,其中包含两个分支“master”和“testing”,其中 HEAD 指的是“testing”。克隆此存储库时,git 会检查“master”,如果“master”和“testing”在同一修订版上(即 HEAD == testing == master)。只有当 'testing' 是一个(或多个)提交之后或之前, git clone 才会检查本地端的 'testing' 分支。我在 Mac OS X (10.6.8) 上用 git 1.7.5 试过这个。

附录:我刚刚对非裸存储库进行了同样的尝试:

mkdir A
cd A
git init
touch a
git add a
git commit -m "init repo A with a"
git checkout -b testing

现在回到根目录:

cd ..
git clone A B
cd B
git branch -v -a
* master                 28f599b init A
  remotes/origin/HEAD    -> origin/master
  remotes/origin/master  28f599b init A
  remotes/origin/testing 28f599b init A

是“主人”!回到 repo A(我们仍在分支“测试”中):

cd ../A
touch b
git add b
git commit -m "add b in branch testing"

现在“测试”是“大师”之前的一次提交。现在让我们再次克隆 A:

cd ..
git clone A C
cd C
git branch -a -v
* testing                23bca39 add b in branch testing
  remotes/origin/HEAD    -> origin/testing
  remotes/origin/master  28f599b init A
  remotes/origin/testing 23bca39 add b in branch testing

您可以通过返回 A,签出“master”并将其与“testing”合并来重新验证这种奇怪的行为(这样所有分支都具有相同的头部)。现在将 A 克隆到 D 中,并且 D 将在 master 上签出!

4

2 回答 2

1

git clone复制所有分支及其历史记录,以及 SHA1 而不是他们头部的参考。AFAIK refspecs 没有被传输,因为它们比克隆(显然)比 git 更新,并且克隆协议不保留它们......这意味着它猜测(编辑:这已由邮件列表确认)。

在克隆期间通过匹配其 SHA1 来猜测 head 的 ref。在您的情况下,SHA1 是模棱两可的,因为master两者testing都匹配,因此master按惯例选择。据我所知,这在任何地方都没有记录,但应该是。

要查看是这样,请转到您的B示例 repo 并运行git ls-remote。输出将为您提供 SHA1,而不是 refs:

1c3eebcd1bd3659a40f02880918d5fbd5614b51a    HEAD
1c3eebcd1bd3659a40f02880918d5fbd5614b51a    refs/heads/master
1c3eebcd1bd3659a40f02880918d5fbd5614b51a    refs/heads/testing

作为一种解决方法,

git clone -b <branch_name>

将克隆并签出您想要的分支 branch_name,例如 master 或 test。

我认为此时您必须遵守 HEAD 是 master 并且 master 是结帐的默认分支的约定,如果您设置为开发人员克隆使用不同的头,请使用 -b 开关。

于 2011-08-03T14:22:53.443 回答
0

从 git 邮件列表中得到答案 - @Shelhamer:你是对的

是的,这是一个已知问题。

git 协议只发送 ref 列表和它们指向的对象。所以本地克隆被迫猜测 HEAD 指向哪个 ref。例如,有类似的东西:

28f599b... 头 1234abc... 参考/头/主 28f599b... 参考/头/测试

它可以看到 HEAD 可能正在“测试”。但如果它看到:

28f599b... 头 28f599b... 参考/头/主 28f599b... 参考/头/测试

然后它必须任意选择一个。我们当前的启发式方法是更喜欢“master”而不是其他人,否则按字母顺序选择第一个。所以它至少是确定性的,但正如你所注意到的,它并不总是正确的。

真正的解决方案是扩展 git 协议以传递符号 ref 信息(然后等待客户端和服务器都升级)。过去有一些补丁浮出水面,但没有任何结果。也许是时候让他们复活了。

作为一种解决方法,如果您提前知道“测试”是您想要的,您可以使用“git clone -b testing ...”。

看:

1. http://thread.gmane.org/gmane.comp.version-control.git/102039

2. http://article.gmane.org/gmane.comp.version-control.git/113567

于 2011-08-04T13:32:42.493 回答