运行 "git branch -r" 命令时为什么会显示 "origin/HEAD"?

186

当你运行git branch -r命令时,为什么会列出origin/HEAD呢?例如,在GitHub上有一个远程仓库,其中包含两个分支:master和awesome-feature。如果我使用git clone命令将其复制到本地并进入新目录并列出分支,我会看到以下内容:

$ git branch -r
origin/HEAD
origin/master
origin/awesome-feature

无论按什么顺序排列(按字母排序?我在模拟这个示例以保护一个无辜的存储库的身份)。那么什么是HEAD呢?它是上一个进行push操作时其HEAD所指向的位置吗?那不会永远是他们进行push操作时所指向的位置吗?HEAD会移动……我为什么要关心其他计算机上的某个人的HEAD指向了什么?

我正在掌握远程跟踪等知识,因此这是一个持续存在的困惑。谢谢!

编辑:我曾认为专用的远程存储库(比如GitHub,在那里没有人会ssh登录并在该代码上工作,而只会拉取或推送等)没有且不应该有HEAD,因为基本上没有工作副本。这种说法对吗?


如何设置 "origin/head"? - leonbloy
这个SuperUser SE网站上的答案也相关且有帮助:https://superuser.com/a/1192881/96618 - Stephen
7个回答

166

@robinst 是正确的。

在 Git 中,您可以选择默认选择哪个分支(即克隆时)。默认情况下,origin/HEAD 将指向它。

在 GitHub 上,您可以通过管理设置更改此设置。您也可以通过命令行进行更改:

git remote set-head origin trunk

或者通过删除它来完全删除

git remote set-head origin -d

示例。看一下“Switch Branches”下拉菜单。 trunk 被选中,所以 origin/HEAD 紧随其后。


我将另一个远程重命名为“origin”,但我的“otherremote/HEAD -> master”让我感到困扰。运行您的命令解决了这个问题。 - Felipe Alvarez
我猜这让人困惑的地方在于,在这种情况下,HEAD 似乎指向整个分支,而在本地克隆中它将指向特定的提交...这是错误的吗? - Stephen
尝试回答自己的问题,从这个答案(https://dev59.com/tWox5IYBdhLWcg3w_ZR0#8841024)来看,远程 HEAD 实际上指向一个提交(也许是其分支中的最新提交?只是猜测),即使在实践中它用于确定默认分支(https://superuser.com/a/1192881/96618 也很有用)。 - Stephen

69
一个裸仓库可以有HEAD的原因是:它确定了在克隆存储库后最初检出哪个分支。 通常,HEAD指向主分支(master),当人们克隆存储库时,该分支被检出。将其设置为另一个分支(通过编辑裸仓库中的HEAD)会导致该分支在克隆时被检出。

2
因为可以在不进行推送的情况下删除此引用,所以 origin/HEAD 是一个本地引用,对 origin 的删除是否有影响? - Zach Olivare
@zposten:不,就像删除origin/master不会影响远程一样。 - robinst
这意味着,在克隆之后,引用只是一个无用的信息片段。 - Bachsau
@Bachsau 参考对象没有被克隆。 - robinst
对于像我一样感到困惑的人,可以将“裸仓库”替换为“GitHub或类似的远程仓库”,以获得大致预期的含义。我不确定为什么它被认为是“裸”的,结果发现这是一个很大的话题(请搜索“git裸仓库”了解更多信息...)。 - Stephen

29

我原本认为专门的远程仓库(比如GitHub,没有人会通过ssh进入并在那个代码上工作,只会拉取或推送等)不应该有HEAD,因为基本上没有工作副本。是这样吗?

我和你说的一模一样。

我甚至无法通过执行命令从github中删除origin/HEAD远程跟踪分支。

git branch -d -r origin/HEAD

这没有任何影响。

有人可以告诉我如何删除那个 origin/HEAD 远程跟踪分支吗?

更新

虽然我没有找到为什么从 GitHub 克隆时会创建 origin/HEAD,但我找到了一种方法来删除它。

Git 的新版本提供了

git remote set-head <name> -d

删除远程跟踪分支的无用HEAD指针。

我们还可以使用以下方法将愚蠢的默认名称“origin”更改为任何我们想要的名称

git remote rename origin <new_name>

希望这能帮到你。:)


我也遇到了同样的问题(甚至在GitHub上),并且set-head也没有起作用。我应该运行“git remote set-head HEAD -d”吗? - Joost Schuur
5
@Joost: 这是 git remote set-head origin -d 命令。我将其翻译为“设置远程仓库的HEAD指针为分离状态”。 - znq

13
您说得对,将内容推送到专用远程仓库时,最好使用“裸的”(即没有工作目录)仓库。 Git的架构是为通过补丁或拉取(获取)更新而设计的,这在分布式版本控制系统中很有意义。正如文档中所说,将内容推送到当前检出的分支可能会导致“意外结果”。
HEAD是有效存储库的要求之一。Git Repository Layout部分提到:
HEAD

A symref (see glossary) to the refs/heads/ namespace describing the currently active  
branch. It does not mean much if the repository is not associated with any working tree  
(i.e. a bare repository), but a valid git repository must have the HEAD file; some  
porcelains may use it to guess the designated "default" branch of the repository  
(usually master). It is legal if the named branch name does not (yet) exist.

所以,即使“它不是很重要...”,你也会在分支列表中看到HEAD。


这没有意义。仓库一开始是空的,但是一旦你向它们推送了东西,它们就不再是空的了,如果你在它们上运行“git branch”,它们将显示当前检出的分支。 - geoidesic
@geoidesic 即使您已经将代码推送到仓库中,该仓库仍然可以是裸仓库。以下命令:mkdir foobar; cd foobar; git init --bare; cd ..; git clone foobar foobar_clone; cd foobar_clone; touch file; git add file; git config --global user.email "you@example.com"; git config --global user.name "Your Name"; git commit -m "test"; git push origin master; cd ..; cd foobar; git config core.bare 输出 true。此外,在这些命令中,foobar 仓库中没有被推送文件的工作副本。 - Anders Lindén
@geoidesic 即使您已将内容推送到存储库中,该存储库仍可能是裸存储库。以下命令:mkdir foobar; cd foobar; git init --bare; cd ..; git clone foobar foobar_clone; cd foobar_clone; touch file; git add file; git config user.email "you@example.com"; git config user.name "Your Name"; git commit -m "test"; git push origin master; cd ..; cd foobar; git config core.bare 输出 true。此外,在这些命令中,foobar 存储库中没有被推送文件的工作副本。 - Anders Lindén
@geoidesic A --bare git repo 意思是一个没有工作树的存储库,即仅包含 .git 目录的存储库,但根本不能有任何已检出的文件。由于它不能有任何已检出的文件,实际上它甚至没有 .git 目录,而是直接将所有 .git 文件放在主目录中。创建一个你就会明白! - 00prometheus

7
如果“origin”是一个远程仓库,那么 “origin/HEAD” 标识该远程仓库上的默认分支。
例如:
$ git remote show
origin
$ git remote show origin
* remote origin
  Fetch URL: git@github.com:walkerh/pipe-o-matic.git
  Push  URL: git@github.com:walkerh/pipe-o-matic.git
  HEAD branch: master
  Remote branch:
    master tracked
  Local branch configured for 'git pull':
    master merges with remote master
  Local ref configured for 'git push':
    master pushes to master (fast-forwardable)

请注意,其中一行写着“HEAD branch: master”。这是远程代码库让客户端默认检出哪个分支的标识。请不要删除HTML标签。

1

远程仓库上始终有一个指向当前检出分支的HEAD(它可能是master,也可能不是)。即使是远程仓库也有当前分支。通常情况下是master,我想不出为什么会想要更改它,但实际上是可以改变的。


2
GitHub仓库没有检出的分支。我不明白为什么会这样。 - Dustin
远程仓库不应该有工作目录。远程仓库应该是“裸”的,因此不能有当前检出的分支。 - n4rzul

-16

我猜测有人推送了一个分支并将其称为HEAD:

git push origin HEAD

我能得到一些关于这个有什么问题的评论吗?如果你想在Github上获取一个起点/HEAD,那是我知道的唯一方法。 - Dustin
远程 HEAD 是一个符号引用(通常是 refs/heads/master)。您将使用当前分支提交的哈希 ID 替换符号引用。 - Daniel Fanjul
6
难道猜测不应该在评论中讨论,而不是作为不精确的答案呈现吗? - Luciano

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