如何设置原点/ HEAD?


144

我有一个分支机构来跟踪原点的引用。 git checkout <branchname>切换到该分支,并且a git status会告诉我该分支距原点的距离是多远或多远,但令我感到惊讶的是,它origin/HEAD仍然指向origin/master,而不是origin/<branchname>

所以我的问题是,在什么情况下原点/ HEAD会移动?

编辑:

我很欣赏有关如何移动原点/ HEAD 的答案,但是我对“有组织地”移动它的方式很感兴趣,因为我明确地告诉它要这样做。

例如,当我切换分支时,git使HEAD指向我要签出的分支,因此令我惊讶的是origin / HEAD不会以相同的方式移动。


请注意,这个问题是关于遥控器上的本地符号引用的refs/origin/HEAD。这与存储库自己的符号引用HEAD的设置无关。
clacke

Answers:


173

首先请注意,您的问题有点误解。origin / HEAD表示远程站点上的默认分支,即您称为origin的远程存储库中的HEAD。当您在存储库中切换分支时,您不会受到影响。远程分支机构也是如此。您的仓库中可能有masterand origin/master,其中origin/master代表master远程存储库中分支的本地副本。

仅当您或其他人在远程存储库中实际更改了origin的HEAD时,才会更改HEAD,这基本上是不会发生的-您希望默认分支是公共仓库中稳定分支(可能是master)上的常数。origin / HEAD是本地引用,表示远程存储库中HEAD的本地副本。(其全名是refs / remotes / origin / HEAD。)

我认为以上内容回答了您实际上想知道的内容,但继续回答您明确提出的问题...克隆存储库时,将自动设置origin / HEAD,仅此而已。奇怪的是,它不是由类似的命令设置的git remote update-我相信它将更改的唯一方法是手动更改它。(通过更改,我的意思是指向另一个分支;很明显,如果该分支发生更改,它所指向的提交将指向更改,这可能发生在获取/拉动/远程更新时。)


编辑:下面讨论的问题已在Git 1.8.4.3中得到纠正;看到这个更新


不过,有一个小小的警告。HEAD是一个符号引用,指向分支而不是直接指向提交,但是git远程传输协议仅报告引用的提交。因此,Git知道HEAD和所有其他引用所指向的提交的SHA1;然后,它必须通过找到指向同一提交的分支来推断HEAD的值。这意味着,如果有两个分支恰好指向那里,那就是模棱两可的。(我相信,如果可能的话,它会选择master,然后按字母顺序退回到第一。)您将在以下输出中看到此报告git remote show origin

$ git remote show origin
* remote origin
  Fetch URL: ...
  Push  URL: ...
  HEAD branch (remote HEAD is ambiguous, may be one of the following):
    foo
    master

奇怪的是,尽管如果远程设备发生了更改(例如,如果foo被删除),以这种方式打印的HEAD的概念将会改变,但实际上并没有更新refs/remotes/origin/HEAD。这可能会导致非常奇怪的情况。假设在上面的示例中origin / HEAD实际上指向foo,然后删除了origin的foo分支。然后我们可以这样做:

$ git remote show origin
...
HEAD branch: master
$ git symbolic-ref refs/remotes/origin/HEAD
refs/remotes/origin/foo
$ git remote update --prune origin
Fetching origin
 x [deleted]         (none)     -> origin/foo
   (refs/remotes/origin/HEAD has become dangling)

因此,即使远程放映知道HEAD是主播,它也不会更新任何内容。正确修剪了陈旧的foo分支,并且HEAD变得悬空了(指向不存在的分支),并且它仍然没有更新它以指向master。如果要解决此问题,请使用git remote set-head origin -a,它会如上所述自动确定原点的HEAD,然后实际将origin / HEAD设置为指向相应的远程分支。


@jefromi很棒的答案!只是一句话:您写道HEAD是一个符号引用,指向分支而不是直接指向提交[...],但为完整起见,可能值得一提的是“分离的HEAD状态”。
jub0bs

2
@Jubobs谢谢!但是,如果我的答案需要更新,请随时对其进行编辑-它肯定会节省人们的时间来阅读有关事情实际运行情况的简要摘要,而不必对两年前的情况和现在的情况进行梳理。 。
卡斯卡贝尔2014年

已经阅读了至少5次,但仍然一点都不懂
krb686

7
git remote set-head origin -a为我做了工作
Shujito

75

这是您作为本地存储库所有者的设置。像这样更改它:

git remote set-head origin some_branch

并且origin / HEAD将指向您的分支而不是master。然后,这将仅适用于您的存储库,而不适用于其他存储库。默认情况下,除非在远程仓库上配置了其他东西,否则它将指向master。

手动输入远程设定头可以提供一些很好的信息。

编辑:要强调:在您不告知的情况下,它“移动”的唯一方法是类似重命名master分支的情况,我认为这不是“ organic”。因此,我自然地说它不会动。


1
编辑重点在这里并不完全正确。如果您从不在master分支上的本地副本克隆,它也会更改。
mphair,2014年

我不认为克隆会“移动”,但我想我们对此表示不同意见:)
eis

24

是什么使原点/ HEAD“有组织地”运动?

  • git clone 一次将其设置为HEAD起源的位置
    • 它是克隆后的默认签出分支 git clone

HEAD原产地代表什么?

  • 在裸存储库(通常是“服务器上”的存储库)上,它用作默认分支的标记,因为git clone以这种方式使用它
  • 在非裸存储库(本地或远程)上,它反映了存储库的当前签出

是什么设定原点/ HEAD?

  • git clone 获取并设置它
  • 如果git fetch像其他任何引用一样对其进行更新,那将是有意义的,但事实并非如此
  • git remote set-head origin -a 获取并设置它
    • 有助于更新有关远程设备认为“默认分支”的本地知识

琐事

  • origin/HEAD 也可以设置为任何其他值,而无需联系遥控器: git remote set-head origin <branch>
    • 除了测试,我没有看到用例
  • 不幸的是,无法在遥控器上设置HEAD
  • 较旧版本的git不知道HEAD指向远程上的哪个分支,而只有它最终拥有的提交哈希:因此,它只是希望选择一个指向相同哈希的分支名称

我失去了参考origin/HEAD,您的解决方案也有所帮助。谢谢!
java_dude 2015年

我不同意对其进行git fetch更新,因为它允许配置(本地)快捷方式。引用文档:“不需要具有远程的默认分支,但是可以指定远程的名称来代替特定的分支”。如果远程更改会更新本地配置的快捷方式,这将很奇怪。
米查·维登曼

@MichaWiedenmann为什么那是本地配置的快捷方式?对于本地配置的快捷方式origin/HEAD是一个不好的名字。并且git clone使用远程名称作为“本地配置分支”的默认名称也与此矛盾。在非裸仓库中,使用remote的current甚至没有意义HEAD
罗伯特·西默

10

免责声明:这是Jefromi回答的更新,为了节省时间,我正在写这本书。

我徒劳地尝试(在Git 2.0.1中)复制remote HEAD is ambiguousJefromi在回答中提到的信息。所以我做了一些挖掘(通过克隆https://github.com/git/git并搜索日志)。曾经是

Determining HEAD is ambiguous since it is done by comparing SHA1s.

In the case of multiple matches we return refs/heads/master if it
matches, else we return the first match we encounter. builtin-remote
needs all matches returned to it, so add a flag for it to request such.

(提交4229f1fa325870d6b24fe2a4c7d2ed5f14c6f771日期为2009年2月27日,发现于git log --reverse --grep="HEAD is ambiguous"

但是,此后的歧义已被消除

One long-standing flaw in the pack transfer protocol used by "git
clone" was that there was no way to tell the other end which branch
"HEAD" points at, and the receiving end needed to guess.  A new
capability has been defined in the pack protocol to convey this
information so that cloning from a repository with more than one
branches pointing at the same commit where the HEAD is at now
reliably sets the initial branch in the resulting repository.

(提交9196a2f8bd46d36a285bdfa03b4540ed3f01f671日期为2013年11月8日,发现于git log --grep="ambiguous" --grep="HEAD" --all-match

编辑(感谢torek):

$ git name-rev --name-only 9196a2f8bd46d36a285bdfa03b4540ed3f01f671
tags/v1.8.4.3~3

这意味着,如果您使用的是Git v1.8.4.3或更高版本,则不应遇到任何模棱两可的远程HEAD问题。


1
根据git源中的标签,此修复程序适用于git版本1.8.4.3及更高版本。
torek

@RobertSiemer我不确定,但是我想是的。
jub0bs 2015年

8

请记住,我们正在讨论两个独立的git repos。您的本地回购代码和远程运行在其他地方。

是的,当您更改分支时,HEAD指向您当前的分支。所有这些都在您本地的git仓库中发生。不是远程仓库,它可以由另一个开发人员拥有,也可以位于您的办公室,github或文件系统上的另一个目录等服务器上,等等。

您的计算机(本地存储库)与更改远程git存储库上的HEAD指针无关。例如,它可以由其他开发者拥有。

还有一件事,您的计算机称为origin / XXX,是您的计算机在最后一次获取时对远程状态的了解。

那么“有组织地”更新源/ HEAD的内容是什么?这将是远程git repo上的活动。不是您的本地仓库。

人们提到

git symbolic-ref HEAD refs / head / my_other_branch

通常,当服务器上有一个共享的中央git存储库供开发团队使用时,将使用该库。这将是在远程计算机上执行的命令。您将在远程git repo上将其视为活动。


1
抱歉,如果我有点重复。我只想指出git是一个分布式版本控制系统的事实,因此这两个仓库都是独立的。
Pablo Maurin 2012年

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.