Git中的HEAD是什么?

bob*_*obo 956 git

你看到Git文档说的话

分支必须在HEAD中完全合并.

但究竟Git HEAD究竟是什么?

Gre*_*ill 722

您可以将HEAD视为"当前分支".切换分支时git checkout,HEAD修订版更改为指向新分支的提示.

您可以通过以下方式查看HEAD指出的内容:

cat .git/HEAD
Run Code Online (Sandbox Code Playgroud)

在我的例子中,输出是:

$ cat .git/HEAD
ref: refs/heads/master
Run Code Online (Sandbox Code Playgroud)

HEAD可以引用与分支名称无关的特定修订.这种情况称为分离的HEAD.

  • HEAD不是*"当前分支".是为工作树的当前状态初始化的提交指定的名称.在更实际的术语中,它可以被认为是签出提交的符号引用. (116认同)
  • @bobobobo:没错,HEAD就像一个指向当前分支的指针.当您签出另一个分支时,HEAD将更改为指向新分支.当前HEAD对于每个存储库是本地的,因此对于每个开发人员而言是个体的. (81认同)
  • 所以git HEAD是依赖于你所在BRANCH的上下文,对吗?更进一步,__you__作为开发人员?我想我问,Git HEAD会成为整个存储库的全球性事物,还是每个开发人员的个人? (48认同)
  • @动静能量:HEAD可以指向*any*commit,它不需要是任何分支中的最后一次提交.(当HEAD指向不是分支中最后一次提交的提交时,这是一个"分离的HEAD"). (48认同)
  • @Meng这个帮助了我,希望它有所帮助:http://marklodato.github.com/visual-git-guide/index-en.html (14认同)
  • 投票下来.我同意@BenCollins.在我看来,第一句话很混乱,可以改为:"你可以把HEAD想象成当前分支的当前提交" (8认同)
  • Git HEAD是指向给定提交的指针,就像分支名称一样,唯一的区别是虽然分支名称在概念上指向分支中的最新提交,但HEAD可用于在同一分支内的提交之间跳转或跨分支机构.您还可以尝试将HEAD可视化为鼠标指针,以便您选择要签出的提交. (6认同)
  • @MalteSkoruppa的不同之处在于,根本不需要在分支上.工作副本可以来自任何提交,无论你在哪个分支,在这种情况下,你将处于一个独立的头上. (6认同)
  • @GregHewgill这个问题应该更新为"您可以将HEAD视为'当前提交'"而不是"当前分支".当我发现在具有许多提交的交互式rebase期间,git更新了`HEAD`而不是分支(由`git reset --hard branchname`证明)时,这个定义使我感到困惑.它还解释了为什么`git reflog HEAD`显示了包含许多提交的rebase期间的所有步骤,而`git reflog branchname`显示只有一个rebase提交. (5认同)
  • @ dalvarezmartinez1 - 绝对.也投了票.Git足够复杂,可以接受一些错误的答案. (4认同)
  • 除了`HEAD`是当前分支,**它必须是当前分支中的最后一个提交**吗? (3认同)
  • @BenCollins谢谢.不幸的是,接受的答案(上图)给出了错误的答案. (3认同)
  • @BenCollins引自[Git Branching - What a a branch](http://git-scm.com/book/en/Git-Branching-What-a-Branch-Is),关于`HEAD`:_"在Git中,这是指向您当前所在的本地分支的指针."_此外,请注意,分支本身只是一个指针.引用相同的来源:_"Git中的一个分支只是一个指向[提交]的轻量级可移动指针.(...)Git中的一个分支实际上是一个包含40个字符的SHA-1校验和的简单文件.承诺指出."_所以我认为接受的答案是好的.你的也是.差异在哪里? (2认同)
  • @dalvarezmartinez1:你所说的一切对我来说都有意义,但这是其他 VCS 使用的术语;git 不这么认为,并且在 git 术语中“分支”并不意味着您列出的所有有意义的事物;它只是意味着对提交的引用。我*希望* git 以您所描述的明智方式思考——根据我的经验,git 基本上不可能检查您所说的提交数组——它只是不记住该信息。对我来说,这是 git 的一个非常严重的失败。 (2认同)
  • 只是敲一下它:Greg(OP),再做一次:“(当HEAD指向不是分支中的最后一个提交的提交时,即为“分离的HEAD”)。不。如果“ HEAD”直接指向一个提交,则不管是什么提交(即使它是分支中的最后一个提交),它都是分离的。 (2认同)

Sil*_*eed 173

引用其他人:

头只是对提交对象的引用.每个头都有一个名称(分支名称或标签名称等).默认情况下,每个存储库中都有一个名为master的头.存储库可以包含任意数量的头.在任何给定的时间,一个头被选为"当前头部".这个头部别名为HEAD,总是以大写字母".

注意这个区别:"head"(小写)指的是存储库中任何一个指定的头; "HEAD"(大写)仅指当前活动的头部.这种区别在Git文档中经常使用.

可以在这里找到另一个很好的来源,它可以快速覆盖git的内部工作方式(以便更好地理解head/HEAD).引用(ref :)或头或分支可以被视为在提交历史记录中粘贴到提交的便利贴.通常它们指向一系列提交的顶端,但他们可以用左右移动git checkoutgit reset等.

  • @gxyd 如果 HEAD 不指向“头”,那么它就是一个分离的 HEAD。它指向您指定的提交的提交 ID(例如,使用 `git checkout HEAD~2`),这不是已知头的提交 ID。请参阅 http://eagain.net/articles/git-for-computer-scientists/ 上的文章以获得更全面的解释。 (2认同)
  • @Silfheed:总的来说,我认为这个答案在概念上比公认的更合理(即使使用小写的“head”来指代分支会让很多人感到困惑)。然而,`git revert` 并不是一个将分支移到不在尖端的好例子,因为 `git revert` 只是创建了一些新的提交,并且仍然将当前分支留在(新的)尖端。 (2认同)
  • “这不是已知头部的提交 ID”——实际上,一个分离的 HEAD *可以*指向一个提交 ID,它也是一个已知头部(或多个头部)的提交 ID。使它分离的是 HEAD 直接指向提交 ID,而不是头部。这将影响未来`commit`s、`reset`s等的行为。 (2认同)
  • @LarsH:关于指向提交 ID 而不是引用的分离 HEAD 的好点。您实际上可以通过查看 .git/HEAD 来验证这一点。如果它是分离的,它将包含提交的哈希值,即使它与已知头部的提交相同。如果它被附加,它将包含头部的路径(即'ref: refs/heads/bob')。至于 revert 命令,8 年后我从未发现过那个错字。Git reset 允许您调整特定的头部以指向特定的提交。 (2认同)

jas*_*res 56

我推荐github开发人员Scott Chacon的这个定义[ 视频参考 ]:

Head是您目前的分支.这是一个象征性的参考.它是对分支的引用.你总是有HEAD,但是HEAD将指向其中一个指针,指向你所在的一个分支.它是您下次提交的父级.它应该是最后签出到您的工作目录中的内容......这是您的工作目录的最后已知状态.

整个视频将对整个git系统进行公平的介绍,所以如果有时间的话,我也建议你全部观看.

  • 所以真正的def是"你下次提交的父" (29认同)
  • 该视频非常棒,但不幸的是,它为Stack Overflow提供了一个不合适的答案.如果视频将在某个时间被取消怎么办?然后你的链接将指向什么.一个更好的答案将包括斯科特在视频中所说的成绩单. (22认同)
  • 斯科特说HEAD是指向分支的指针.但是HEAD也可以指出旧的提交.这太令人困惑了. (2认同)

Ale*_*ndr 52

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

Pro Git书中,第3.1Git分支 - 坚果壳中的分支,在创建新分支部分:

如果您创建一个新分支会发生什么?好吧,这样做会创建一个新的指针供你四处走动.假设您创建了一个名为testing的新分支.您可以使用git branch命令执行此操作:

$ git branch testing 
Run Code Online (Sandbox Code Playgroud)

这会在您当前所在的同一提交中创建一个新指针

在此输入图像描述

Git如何知道你目前在哪个分支?它保留了一个名为HEAD的特殊指针.请注意,这与您可能习惯使用的其他VCS中的HEAD概念有很大不同,例如Subversion或CVS.在Git中,这是指向您当前所在的本地分支的指针.在这种情况下,你仍然在掌握.git branch命令只创建了一个新分支 - 它没有切换到该分支.

在此输入图像描述

  • 不错,虽然可以使用显示分离的HEAD案例的图片 (4认同)
  • 很好的答案.分支只是标记提交,当您进行新提交时,此标签将移动到新的提交.签出没有标签的提交时,它处于分离的HEAD状态.这意味着HEAD指向没有分支标签的提交.如果你在上面的例子中签出了'34ac2`,现在HEAD将指向该提交,它被称为分离的HEAD.在这种状态下,您也可以进行更改,试验和提交更改,但是一旦您签出其他分支,您将丢失所有更改,除非您创建新分支. (3认同)
  • @sleepwalkerfx,但是您可以签出具有分支标签的提交,并且仍然处于分离头状态,因为您的 HEAD 不再指向分支标签,而是指向分支的提交 id (2认同)
  • @sleepwalkerfx 我认为我们现在正在讨论语义。您是对的,分支标签是对特定提交的文本引用。然而,这不是提交。因此,如果您执行“git log”并得到类似“commit ad0265... HEAD -> foo ...”的内容,则意味着“foo”分支是对提交 ID“ad0265”的引用。对文本引用“foo”进行检查并不是一个分离的头。签出提交 ID“ad0265”将导致分离的头。可能我忽略了你所传达的一些微妙之处。我希望这面文字墙能帮助我发现我迷失的地方。 (2认同)

nop*_*ole 37

假设它不是一个称为"分离的HEAD"的特殊情况,那么,如O'Reilly Git书中所述,第二版,第69页,HEAD意思是:

HEAD始终引用当前分支上的最新提交.更改分支时,HEAD会更新以引用新分支的最新提交.

所以

HEAD当前分支的"提示".

请注意,我们可以使用它HEAD来引用最近的提交,并HEAD~在提示之前用作提交,HEAD~~或者HEAD~2甚至更早地用作提交,依此类推.


Ale*_*ler 22

Git 中的 HEAD 是什么?(概念上)

HEAD是指向当前签出的分支或提交的指针,它回答了以下问题:我现在在存储库中的什么位置?或者,换句话说,它是 Git 知道在哪个提交上镜像本地工作树,以及您当前是否在分支(附加)或不在分支(分离)上工作的方式。

分离头

HEAD可以处于两种状态之一:Attacheddetached,具体取决于您是否签出分支。默认状态是Attach,其中对历史记录的任何操作都会自动记录到HEAD当前引用的分支。

分离状态下,可以进行实验性更改,而不会影响任何现有分支。请参阅下面的信息图,说明在附加状态和分离状态下提交之间的差异。

处于连接和分离状态的 HEAD 插图。

一个常见的误解是,消息You are in 'detached HEAD' state的语气是错误的,而实际上它只是描述了如何HEAD引用当前快照。

可以使 HEAD 处于分离状态的操作:

从分离状态转变为附着状态

要从分离状态转变为附加状态,您可以从您所在的位置创建一个新分支,也可以切换回现有分支。

注意:如果您切换到另一个现有分支,而不首先将更改保留在新分支中,则在分离状态下创建的任何提交最终都将被丢弃(垃圾收集后)。

检查 HEAD 的状态

HEAD可以通过不同的方式来确定当前所处的状态,这里有两个选项。

HEAD到底是什么?(技术上)

如果您想明确查看HEAD引用的内容,您可以随时检查该.git/HEAD文件,这是 Git 在内部使用来管理的实际文件HEAD。该文件包含分支或提交哈希的名称,具体取决于HEAD是否分离。

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

# If detached, the output would have been
14ko36e295f1a98ec57397b3acc7bc247da61ff5
Run Code Online (Sandbox Code Playgroud)

资料来源:以上摘录自这篇主题为: What is HEAD in Git? 的完整文章。


小智 21

HEAD指的是您的工作副本指向的当前提交,即您当前已签出的提交.从有关指定Git修订官方Linux内核文档:

HEAD 命名您基于工作树中的更改的提交.

但请注意,在即将到来的版本的Git 1.8.4,@也可以用作简写HEAD,如通过Git的贡献者JUNIOÇ滨野在他的混帐惹的祸博客指出:

而不是输入"HEAD",你可以改为说"@",例如"git log @".

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

同样有趣的是,在某些环境中,没有必要大写HEAD,特别是在使用不区分大小写的文件系统,特别是Windows和OS X的操作系统中.


onm*_*133 16

看一下创建和玩分支

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

$ cat .git/HEAD
ref: refs/heads/master
$ cat .git/refs/heads/master
35ede5c916f88d8ba5a9dd6afd69fcaf773f70ed
Run Code Online (Sandbox Code Playgroud)

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

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

在此输入图像描述


use*_*385 15

在阅读了之前的所有答案后,我仍然想要更清晰。git 官方网站http://git-scm.com/blog上的这个博客给了我想要的东西:

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

Git 中的 HEAD 是指向当前分支引用的指针,它又是指向您所做的最后一次提交或检出到您的工作目录中的最后一次提交的指针。这也意味着它将成为您下一次提交的父项。通常将其视为最简单的方式,因为 HEAD 是您上次提交的快照。

  • *HEAD:最后提交快照,下一个父级*不准确。`HEAD` 不是提交;它*指向*一。 (3认同)
  • 如果你读到下一行:Git 中的 HEAD 是指向当前分支引用的**指针**,而它又是指向你所做的最后一次提交或签出到你的文件中的最后一次提交的**指针**。工作目录。-- 请注意此处使用了“指针”一词。 (2认同)
  • 虽然“最后提交快照”描述确实给出了 HEAD 通常应该如何使用的概念感觉,但它实际上并不准确。如果我进行提交,然后切换到另一个分支,HEAD 不再指向最后一个提交快照。它指向我刚刚切换到的分支上的最后一个提交快照。如果我“签出 HEAD^”,现在 HEAD 甚至不指向任何分支上的最后一个提交快照。 (2认同)
  • “你的下一个提交的父级(如果你现在要提交)”更准确,但是除了提交之外,git 中还有许多其他操作受到 HEAD 的影响。实际上,归根结底,HEAD 就是 HEAD,它的本质是由它如何影响 `commit`、`merge`、`rebase`、`log` 等命令来定义的。但从概念上讲,可能是“(指向)当前位置” ”是一个很好的总结。 (2认同)

mik*_*ike 14

我想在Greg Hewgil接受的答案中详述一些事情.根据Git袖珍指南

科:

分支本身被定义为提交图中可从命名提交(分支的"提示")到达的所有点.

头部:特殊类型的参考

特殊参考HEAD决定你在哪个分支......

参考文献

Git定义了两种引用,或者命名为指针,它们称之为"refs":

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

正如格雷格所说,HEAD可能处于"超脱状态".因此HEAD可以是简单的ref(对于分离的HEAD)或symref.

如果HEAD是现有分支的符号引用,那么您就在那个分支上".另一方面,如果HEAD是一个简单的引用直接通过其SHA-1 ID命名提交,那么你不是"在"任何分支上,而是在"分离的HEAD"模式,这发生在你早先检查一些时承诺检查.


De *_*ica 12

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

什么HEAD

头是你

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

HEAD可以附加什么?

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

cat .git/HEAD
Run Code Online (Sandbox Code Playgroud)

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

ref: refs/heads/master
Run Code Online (Sandbox Code Playgroud)

有时您会得到如下信息:

a3c485d9688e3c6bc14b06ca1529f0e78edd3f86
Run Code Online (Sandbox Code Playgroud)

这就是当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)
Run Code Online (Sandbox Code Playgroud)

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

现在尝试:

git status
# HEAD detached at a3c485d
Run Code Online (Sandbox Code Playgroud)

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

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

结论

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

  • 我真的认为这是最好的答案。其他人暗示“HEAD”是树枝的尖端,但事实并非如此,它就像磁带头。查看此操作的一种非常简单的方法是“git checkout HEAD~1”返回一个提交,然后“git checkout HEAD~1”返回另一个提交。如果“HEAD”始终引用分支上的最新提交,则第二个命令将与第一个命令相同 - 但事实并非如此。第二个命令将您的“HEAD”再次移回,即您现在距离分支尖端有两次提交。这很微妙但很重要。 (11认同)
  • 我喜欢你的表达“HEAD is YOU”。 (7认同)
  • 我喜欢这个答案,因为虽然文档描述了事实,但软件定义了事实。`.git/HEAD` 是软件认为是 HEAD 的内容。 (6认同)
  • 仅就其概念定义而言,这应该是公认的答案。 (6认同)
  • 这个答案应该被接受,它解释得很好! (4认同)

小智 6

我认为'HEAD'是当前的结账提交.换句话说,'HEAD'指向当前已检出的提交.

如果您刚刚克隆而未检出,我不知道它指向的是什么,可能是一些无效的位置.


tjb*_*tjb 5

将正确答案中的观点带回家的一个好方法是运行 git reflog HEAD,您将获得 HEAD 指出的所有地点的历史记录。


sta*_*ck1 5

头指向当前检出的分支的尖端.

在此输入图像描述

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

  • 一个常见的误解是当前分支的尖端指向最近的提交。通常情况下确实如此,但“git reset HEAD^”也并不罕见,然后最新的提交(前一个提示)不再由分支的提示指向。 (3认同)