Git中的HEAD是什么?


Answers:


774

您可以将HEAD视为“当前分支”。当您使用切换分支时git checkout,HEAD版本将更改为指向新分支的尖端。

您可以通过执行以下操作查看HEAD指向的内容:

cat .git/HEAD

就我而言,输出为:

$ cat .git/HEAD
ref: refs/heads/master

HEAD可能引用与分支名称不相关的特定修订版。这种情况称为HEAD分离


52
所以git HEAD取决于上下文,对吗?更进一步,作为开发人员?我想我想问的是,Git HEAD是一个存储库范围的全球性产品,还是每个开发人员都需要的个人产品?
bobobobo 2010年

90
@bobobobo:是的,HEAD就像一个指向当前分支的指针。当您签出其他分支时,HEAD更改为指向新分支。当前的HEAD对于每个存储库都是本地的,因此对于每个开发人员而言都是单独的。
Greg Hewgill'2

16
@Meng这个人对我有帮助,希望对我有帮助:marklodato.github.com/visual-git-guide/index-en.html
raphael

53
@动静能量:HEAD可以指向任何提交,而不必是任何分支中的最后一个提交。(当HEAD指向不是分支中的最后一个提交的提交时,即为“分离的HEAD”)。
格雷格·休吉尔

126
HEAD 不是 “当前分支”。是为从中初始化工作树的当前状态的提交提供的名称。实际上,可以将其视为对已签出提交的符号引用。
Ben Collins

184

引用其他人

头仅仅是对提交对象的引用。每个头都有一个名称(分支名称或标签名称等)。默认情况下,每个存储库中都有一个称为master的头。存储库可以包含任意数量的头。在任何给定时间,都会选择一个头作为“当前头”。该头别名为HEAD,始终以大写字母开头。”

注意这种区别:“头”(小写)是指存储库中任何已命名的头;“ HEAD”(大写)专门指当前活动的head。这种区别在Git文档中经常使用。

这里可以找到另一个快速介绍git内部工作原理的好资料(因此可以更好地理解heads / HEAD)。引用(ref :)或标题或分支可以视为粘贴在提交历史中的提交上的便利贴。通常,它们指向一系列提交的尖端,但是可以使用git checkoutor git reset等来移动它们。


从此:“每个头都有名字”。并且“将一个头选为”当前头”。该头别名为“ HEAD”。因此,我由此得出结论,“ HEAD”不涉及“分离的HEAD”状态的情况。
gxyd 2015年

1
@gxyd,如果HEAD不指向“ head”,则为分离的HEAD。它指向您指定的提交的提交ID(例如,使用git checkout HEAD~2),而不是已知磁头的提交ID。有关更详尽的解释,请参阅eagain.net/articles/git-for-computer-scientists上的文章。
Silfheed

1
@Silfheed:一般而言,我认为这个答案在概念上比公认的答案更合理(即使使用小写的“ head”来表示分支也使很多人感到困惑)。但是git revert,并不是将分支移到最末端的一个好例子,因为git revert只是创建了一些新的提交,而仍然将当前分支留在了(新)末端。
LarsH

1
“这不是已知头的提交ID”-实际上,分离的HEAD 可以指向提交ID,该提交ID也是已知头(或多个头)的提交ID。使它分离的原因是HEAD直接指向提交ID,而不是头部。这将影响未来的行为,commitS,resetS等
LarsH

1
@LarsH:分离的HEAD上的好点指向提交ID而不是引用。您实际上可以通过查看.git / HEAD来验证这一点。如果它是分离的,则它将包含提交的哈希,即使它与已知的头部相同。如果已连接,它将包含头部的路径(即“ ref:refs / heads / bob”)。至于还原命令,八年后我再也没有发现错字。Git重置是允许您调整特定头以指向特定提交的工具。
西尔弗希德(Silfheed)

62

我从github开发人员Scott Chacon [ 视频参考 ] 推荐此定义:

头是您当前的分支。它是一个符号参考。它是对分支的引用。您始终具有HEAD,但是HEAD将指向这些其他指针之一,您所在的分支之一。它是您下次提交的父项。这应该是最后签出到您的工作目录中的内容。这是您的工作目录的最新已知状态。

整个视频将公平地介绍整个git系统,因此,如果有时间,我也建议您观看所有视频。


34
因此,真正的定义就是“下一次提交的父项”
nicolas

1
以及“指向下一个将要移动的分支的东西”
nicolas

@nicolas-我认为那不是真的。HEAD可以指向任何提交,它不必指向分支-否则,您将处于“分离式HEAD”模式。
scubbo 2013年

23
该视频很棒,但不幸的是,它为Stack Overflow给出了不合适的答案。如果将来某个时候删除视频怎么办?然后,您的链接将指向任何内容。更好的答案应该包括斯科特在视频中说的文字记录。

2
斯科特说HEAD是指向分支的指针。但是HEAD也可以指向旧提交。这太令人困惑了。
Fixee 2014年

60

HEAD只是一个特殊的指针,它指向您当前所在的本地分支。

Pro Git书籍的第3.1Git分支-坚果壳中的分支,创建新分支一节中:

如果创建一个新分支会怎样?好吧,这样做会创建一个新的指针供您移动。假设您创建了一个名为testing的新分支。您可以使用git branch命令执行此操作:

$ git branch testing 

这将在您当前正在执行的同一提交处创建一个新的指针

在此处输入图片说明

Git如何知道您当前在哪个分支?它保留一个称为HEAD的特殊指针。请注意,这与您可能习惯的其他VCS中的HEAD概念有很大不同,例如Subversion或CVS。在Git中,这是指向您当前所在的本地分支的指针。在这种情况下,您仍处于掌握状态。git branch命令仅创建一个新分支,但未切换到该分支。

在此处输入图片说明


4
不错,虽然可以使用显示分离的HEAD案件的图片
Don Hatch

@DonHatch,分离的HEAD的好解释stackoverflow.com/a/35301963/1074179
Alexandr

3
好答案。分支不过是带有标签的提交,当您进行新提交时,此标签将移至新的新提交。当您签出没有标签的提交时,它处于分离的HEAD状态。这意味着HEAD指向的是没有分支标签的提交。如果您34ac2在上面的示例中签出,那么HEAD将指向该提交,这称为分离的HEAD。在这种状态下,您也可以进行更改,试验和提交更改,但是一旦签出其他分支,您将丢失所有更改,除非您当然创建了一个新分支。
sleepwalkerfx

1
@sleepwalkerfx,但是您可以签出具有分支标签但仍处于分离头状态的提交,因为您的HEAD不再指向分支标签而是分支的提交ID
Marc

1
@sleepwalkerfx我认为我们现在正在谈论语义。您是正确的,分支标签是对特定提交的文本引用。但是,这不是提交。因此,如果您执行了a git log并得到了类似的信息commit ad0265... HEAD -> foo ...,则意味着该foo分支是对commit id的引用ad0265。签出文本参考foo不是一个独立的头。对提交ID进行检出ad0265将导致头部分离。可能是我错过了您所传达的内容的一些微妙之处。我希望这堵文字墙有助于发现我迷路的地方。
Marc

40

假设这不是称为“分离的头”的特殊情况,那么,如O'Reilly Git的书第二版,第69页中所述,HEAD意味着:

HEAD总是指当前分支上的最新提交。更改分支时,HEAD将进行更新以引用新分支的最新提交。

所以

HEAD当前分支的“提示”

注意,我们可以HEAD用来引用最新的提交,并HEAD~用作技巧之前的提交,HEAD~~或者HEAD~2甚至更早的提交,依此类推。


26

这些答案在许多方面都有一个,也许是微妙但重要的误解。我以为我会添加我的答案来清除它。

什么HEAD

头是你

HEAD是一个符号引用,指向您在提交历史记录中的任何位置。无论您走到哪里,无论做什么,它都会跟随您,就像阴影一样。如果您提交,HEAD将移动。如果您结帐,HEAD将会移动。无论您做什么,如果您在提交历史记录HEAD中移到了新的位置,都会与您一起移动。要解决一个常见的误解:您不能脱离HEAD。那不是分离的HEAD状态。如果您发现自己在想:“哦,不,我处于HEAD分离状态!我迷失了HEAD!” 记住,这是你的头。HEAD是你。您尚未与HEAD分离,您和您的HEAD已与其他物体分离。

HEAD可以附加什么?

HEAD可以指向一个提交,是的,但是通常不是。让我再说一遍。通常HEAD不指向提交。它指向分支引用。它附属于该分支,并且当您执行某些操作(例如commitreset)时,附属的分支将与一起移动HEAD。您可以通过在引擎盖下查看来查看其指向的内容。

cat .git/HEAD

通常,您会得到以下内容:

ref: refs/heads/master

有时您会得到如下信息:

a3c485d9688e3c6bc14b06ca1529f0e78edd3f86

这就是当HEAD直接指向提交时发生的情况。这称为分离的HEAD,因为HEAD它指向的是分支引用以外的内容。如果您在这种状态下进行提交master,不再被附加到HEAD,将不再与您一起移动。提交在哪里都没有关系。您可能与主分支位于同一提交上,但是如果HEAD指向的是提交而不是分支,则它是分离的,并且新的提交不会与分支引用关联。

如果尝试以下练习,则可以以图形方式查看。从git存储库中运行此程序。您会得到一些稍微不同的东西,但是它们的关键部分就在那里。是时候直接签出提交了,只需使用从第一个输出(这里是a3c485d)中获得的任何缩写哈希即可。

git checkout master
git log --pretty=format:"%h:  %d" -1
# a3c485d:   (HEAD -> master)

git checkout a3c485d -q # (-q is for dramatic effect)
git log --pretty=format:"%h:  %d" -1   
# a3c485d:   (HEAD, master)

好的,因此此处的输出存在微小差异。直接检出提交(而不是分支)会给我们一个逗号而不是箭头。您认为我们处于独立的HEAD状态吗?HEAD仍指与分支名称关联的特定修订版。我们仍然 master分支上,不是吗?

现在尝试:

git status
# HEAD detached at a3c485d

不。我们处于“分离头”状态。

你可以看到相同的表示(HEAD -> branch)(HEAD, branch)git log -1

结论

HEAD是你。无论您身在何处,它都指向您签出的所有内容。通常,这不是提交,而是分支。如果HEAD 确实指向一个提交(或标签),即使它与分支也指向同一提交(或标签),则您(和HEAD)已与该分支分离。由于您没有附加分支,因此在您进行新提交时,该分支也不会跟随您。HEAD但是会。


1
我喜欢这个答案,因为尽管文档描述了事实,但软件定义了事实。.git/HEAD该软件认为是HEAD。
唐·布兰森

2
仅就其概念定义而言,这应该是公认的答案。
ATA

22

HEAD指的是您的工作副本指向的当前提交,即您当前已签出的提交。从官方的Linux内核文档中获取有关指定Git修订版的信息

HEAD 在工作树中命名所做更改的提交。

但是请注意,在即将发布的Git 1.8.4版本中,@也可以用作Git 的简写HEAD,正如Git贡献者Junio C Hamano在其Git Blame博客中指出的那样

不用输入“ HEAD”,也可以说“ @”,例如“ git log @”。

Stack Overflow用户VonC 在回答另一个问题时还发现了一些有趣的信息,@这些信息说明了为什么选择为什么速记

同样令人感兴趣的是,在某些环境中,不必大写HEAD,特别是在使用不区分大小写的文件系统的操作系统中,尤其是Windows和OSX。


17

看看创建和使用分支

HEAD实际上是一个文件,其内容确定HEAD变量引用的位置:

$ cat .git/HEAD
ref: refs/heads/master
$ cat .git/refs/heads/master
35ede5c916f88d8ba5a9dd6afd69fcaf773f70ed

在此存储库中,HEAD文件的内容引用了另一个名为refs / heads / master的文件。文件refs / heads / master包含master分支上最近提交的哈希。

结果是HEAD指向.git / refs / heads / master文件中的master分支提交。

在此处输入图片说明


1
注意:gitguys.com链接似乎指向一个托管域名。
MKesper '18

14

我想详细介绍Greg Hewgil接受的答案中的一些内容。根据Git Pocket Guide

科:

分支本身定义为提交图中从命名提交(分支的“尖端”)到达的所有点。

HEAD:特殊类型的Ref

特殊的ref HEAD决定了您所在的分支...

参考

Git定义了两种引用或命名的指针,它们称为“引用”:

  • 一个简单的ref,直接指向对象ID(通常是提交或标记)
  • 一个符号引用(或symref),它指向另一个引用(简单或符号)

如Greg所述,HEAD可以处于“分离状态”。因此,HEAD可以是简单的ref(对于分离的HEAD),也可以是symref。

如果HEAD是现有分支的符号引用,则您位于该分支上。另一方面,如果HEAD是直接通过其SHA-1 ID命名提交的简单引用,则您不是“在”任何分支上,而是在“分离的HEAD”模式下,这种情况在您较早签出时会发生。致力于检查。


谢谢@mike!这是第一个答案,它阐明了您签出较早的提交时会发生什么。看着git网站上的,我给人的印象是,“分离头”是一种病理状态,只有在您进行了一些奇怪的基础操作时您才会陷入这种状态。但是签出较早的提交并不是一件奇怪的事情,并且当您这样做时,HEAD并不是“当前分支的尖端”。所以这是我第一次真正理解。
纳·库恩

7

我认为“ HEAD”是当前的检出提交。换句话说,“ HEAD”指向当前已签出的提交。

如果您只是克隆但没有签出,我可能不知道它指向什么,可能是某个无效的位置。


是的,特殊参考HEAD是您当前已签出的所有提交。有关详细信息,请参见手册(相关段落紧接图3.4)。
Calrion

1
如果您克隆存储库,则默认情况下git将检出master分支-HEAD将指向master。
sleske 2013年

1
@sleske如果您克隆没有特殊选项的存储库,则git将检出远程头。通常是master,但并非总是如此。见remote set-head
从头

我之前的评论是正确的,除了对的引用remote set-head,该引用仅影响本地默认分支,不会更改服务器上的默认值。
De Novo

5

Head指向当前已签出分支的尖端。

在此处输入图片说明

在您的存储库中,有一个.git文件夹。在以下位置打开文件:.git \ refs \ heads。该文件(在大多数情况下为master)中的(sha-1哈希)代码将是最近的提交,即在命令输出中看到的提交git log。有关.git文件夹的更多信息:http : //gitready.com/advanced/2009/03/23/whats-inside-your-git-directory.html


1
一个普遍的误解是当前分支的尖端指向最近的提交。通常,这是正确的,但也并非不常见git reset HEAD^,然后分支的尖端不再指向最近的提交(前一个尖端)。
LarsH

4

正确答案所指向的一种很好的方法是运行 git reflog HEAD,您可以获得HEAD所指向的所有位置的历史记录。


4

阅读完所有先前的答案后,我仍然希望更加清晰。这个官方git网站http://git-scm.com/blog上的博客为我提供了我想要的东西:

HEAD:指向上一个提交快照,下一个父级的指针

Git中的HEAD是指向当前分支引用的指针,而该分支引用又是指向您进行的最后一次提交或签出到工作目录中的最后一次提交的指针。这也意味着它将成为您下次提交的父项。通常认为它是最简单的,因为HEAD是您最后一次提交的快照。


1
HEAD:上次提交快照,下一个父级不正确。HEAD不是提交;它指向一个。
jub0bs 2014-09-26

无需讽刺;在您进行编辑之前,即使引用是准确的,但大胆的粗体字母还是一种简化,并且具有误导性。现在,更好。
jub0bs 2014年

1
如果您读了下一行:Git中的HEAD是指向当前分支引用的指针,而该分支引用又是指向您上一次提交或最后签出到工作目录中的提交的指针。-请注意在此使用“指针”一词。
user3751385 2014年

尽管“最后一次提交快照”描述确实提供了通常应该使用HEAD的概念性感觉,但实际上并不准确。如果我进行提交,然后切换到另一个分支,则HEAD不再指向最后的提交快照。它指向我刚切换到的分支上的最后一个提交快照。如果是I checkout HEAD^,那么HEAD甚至都不会指向任何分支上的最后一个提交快照。
LarsH

“下一次提交的父级(如果您现在要提交)”更准确,但是git中还有许多其他操作受HEAD影响。说真的,到了最后,HEAD是HEAD,其性质由它如何影响像命令定义的commitmergerebaselog,等,但在概念上,也许“(指针)的当前位置”是一个很好的总结。
LarsH

3

感觉这HEAD只是您签出的最后一次提交的标签。

这可以是特定分支的提示(例如“ master”),也可以是某个分支的中间提交(“ headed”)


1

除了所有定义之外,我想到的是,当您进行提交时,GIT在存储库中创建一个提交对象。提交对象应具有一个父对象(如果是合并提交,则应具有多个父对象)。现在,git如何知道当前提交的父级?因此HEAD是指向最后提交的(引用)最后一个指针,它将成为当前提交的父级。


0

这两个可能会使您感到困惑:

指向命名引用是最近提交的分支。除非使用软件包引用,否则磁头通常存储在$ GIT_DIR / refs / heads /中。

当前分支或您的工作树通常是从HEAD指向的树生成的。HEAD必须指向一个头,除非您使用的是分离的HEAD。


0

看看http://git-scm.com/book/en/Git-Branching-What-a-Branch-Is

图3-5。HEAD文件指向您所在的分支。


4
在Stackoverflow上,通常仅链接的答案不被接受,请在答案中内联相关信息。
HaskellElephant 2012年

2
这并不完全正确。什么HEAD是指取决于是否你在谈论裸VS非裸露的回购协议。在非裸仓库中,它实际上是指当前已签出的提交,不需要在其上附加分支(即,处于分离HEAD状态时)。

0

分支实际上是保持提交ID诸如指针17a5HEAD是指向用户当前正在处理的分支的指针。

HEAD的参考档案如下所示:

参考:

您可以通过访问.git/HEAD .git/refs正在使用的存储库中的文件来检查这些文件 。


0

Git都是关于提交的。
Head指向您当前签出的提交。

$ git cat-file -t HEAD
commit

每当您签出分支时,HEAD都指向该分支上的最新提交。HEAD的内容可以按以下方式检查(对于master分支):

$ cat .git/refs/heads/master
  b089141cc8a7d89d606b2f7c15bfdc48640a8e25

-5

从概念上讲,头部是分支中的最新版本。如果每个命名分支有多个头,则可能在执行本地提交而不合并时创建了它,从而有效地创建了一个未命名分支。

要拥有一个“干净的”存储库,每个命名分支应该有一个头,并且在本地工作后始终合并到一个命名分支。

对于Mercurial来说也是如此。


4
这对于Mercurial来说是正确的,但对于Git则不是
恢复莫妮卡-notmaynard 2014年
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.