您可以看到Git文档中说:
分支必须在HEAD中完全合并。
但是Git中的HEAD
究竟是什么?
你可以把HEAD想象成“当前分支”。当你使用git checkout
切换分支时,HEAD修订版会更改为指向新分支的最新版本。
你可以通过以下方式查看HEAD指向:
cat .git/HEAD
在我的情况下,输出结果为:$ cat .git/HEAD
ref: refs/heads/master
HEAD可以指向一个没有分支名称关联的特定版本。这种情况称为游离的HEAD。
引用其他人的话:
一个“head”只是指向提交对象的引用。每个“head”都有一个名称(分支名称或标签名称等)。默认情况下,每个代码库中都有一个名为master的“head”。一个代码库可以包含任意数量的“head”。在任何时候,一个“head”被选定为“当前head”。这个“head”被别名为HEAD,总是大写的。
请注意区别:“head”(小写)是指代码库中的任一命名head,“HEAD”(大写)专门指当前活动的head。这个区别在Git文档中经常使用。
另一个快速了解Git内部工作原理(因此更好地理解heads / HEAD)的良好来源可以在这里找到。 参考(ref:)或head或branch可以被视为粘贴在提交历史记录中的便笺。通常它们指向一系列提交的顶部,但是可以通过git checkout
或git reset
等移动它们。
git checkout HEAD~2
),那么它就是一个分离的HEAD。 它指向的不是已知头部的提交ID。请参阅http://eagain.net/articles/git-for-computer-scientists/上的文章以获取更详尽的说明。 (注意:该翻译仅供参考,对于特定上下文可能不适用或存在更佳翻译。) - Silfheedcommit
、reset
等行为。 - LarsHHEAD
只是一个引用,它将成为你要创建的下一个提交的父提交。 - legends2k这些回答中可能存在一个微妙但重要的误解,我想加上我的回答来澄清。
HEAD
是什么?
HEAD
就是你自己HEAD
是一个符号引用,指向你在提交历史中的位置。它跟随你所做的任何事情,就像一道影子。如果你进行了提交,HEAD
会移动。如果你检出了某个东西,HEAD
也会移动。无论你做什么,只要你在提交历史中移动到了新的位置,HEAD
也随着你移动。针对一个常见的误解:你无法从HEAD
中分离出自己。这就不是分离HEAD
状态的含义。如果你发现自己思考:“哦不,我处于分离状态!我失去了我的HEAD!”请记住,那是你的HEAD。HEAD就是你自己。你没有从HEAD中分离出来,而是你和你的HEAD从其他地方分离出来了。
HEAD
可以指向提交,但通常并不这样。让我再说一遍。通常HEAD
不会指向一个提交。它指向一个分支引用。它被附着在该分支上,当你做某些事情(例如commit
或reset
)时,附着的分支将随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仍然指向与分支名称相关联的特定修订版。我们仍然在主分支上,对吧?
现在尝试:
git status
# HEAD detached at a3c485d
不是。我们处于“分离的HEAD”状态。
你可以通过git log -1
查看(HEAD->分支)
与(HEAD,分支)
的相同表示。
HEAD
代表你自己。它指向你检出的任何位置,通常不是提交,而是一个分支。如果HEAD
指向提交(或标签),即使它是一个分支也指向的相同的提交(或标记),你(和HEAD
)也已经脱离了该分支。由于你没有与你附加的分支,所以该分支不会随着你进行新提交而更新,但是HEAD
会更新。
.git/HEAD
是软件认为的 HEAD。 - Don BransonHEAD
是分支的末端,但实际上它像是磁带头。一个非常简单的方法来证明这一点是使用命令 git checkout HEAD~1
回到前一次提交,然后再使用 git checkout HEAD~1
回到再前一次提交。如果HEAD
总是指向分支上最近的提交,在第二个命令中将与第一个命令相同 - 但实际上并不是。第二个命令会将你的HEAD
向后移动一个更早的提交,也就是说,现在距离该分支的末端有两个提交。这很微妙但也很重要。 - Dave KerrHEAD是一个特殊指针,它指向您当前所在的本地分支。
来自Pro Git书籍,第3.1 Git分支 - 分支概述章节,在创建新分支一节中:
如果创建一个新分支会发生什么?这样做会为您创建一个新的指针来移动。假设您创建了一个名为testing的新分支。您可以使用git branch命令执行此操作:
$ git branch testing
这会在当前提交中创建一个新指针。
Git 如何知道您当前位于哪个分支?它保留了一个特殊的指针,称为 HEAD。请注意,这与其他 VCS(例如 Subversion 或 CVS)中您可能习惯的 HEAD 的概念有很大不同。在 Git 中,这是指向您当前所在本地分支的指针。在此情况下,您仍在主分支上。git branch 命令仅创建了一个新分支 - 它并未切换到该分支。
34ac2
,那么现在 HEAD 就会指向该提交,这就叫做游离 HEAD。在这种状态下,你可以进行更改、实验和提交更改,但是一旦你切换到不同的分支,你将失去所有的更改,除非你创建一个新的分支。 - Rukshangit log
命令,并得到类似于 commit ad0265... HEAD -> foo ...
的输出,那么这意味着 foo
分支是指向提交 ID 为 ad0265
的引用。检出文本引用 foo
并不会导致分离头状态。而检出提交 ID ad0265
将导致分离头状态。也许我没有理解你所传达的微妙之处。希望这篇文章能够帮助你找到我迷失的地方。 - Marc整个视频将为您提供Git系统的简要介绍,因此如果有时间,我也建议您观看整个视频。Head 是你当前所在的分支。它是一个符号引用,指向一个分支。你始终都有HEAD,但HEAD会指向其中一个其他指针(即你所在的某个分支)。它是下一次提交的父级,应该是最后一个检出到你的工作目录中的内容……这是你的工作目录的最后已知状态。
假设这不是一个特殊情况,称为“脱离HEAD”,那么如同《O'Reilly Git书籍》第二版第69页所述,HEAD
的意思是:
HEAD
总是指当前分支上最新的提交。当你切换分支时,HEAD
会更新并指向新分支上的最新提交。
所以
HEAD
是当前分支的“末端”。
请注意,我们可以使用HEAD
来引用最近的提交,并使用HEAD~
表示尖端之前的提交,HEAD~~
或HEAD~2
表示更早的提交等等。
HEAD
是指你当前工作副本所指向的提交,即你当前检出的提交。根据Git修订规范官方文档:
HEAD
指向你在工作树中修改所依据的提交。
然而需要注意的是,在即将发布的Git 1.8.4版本中,@
也可以用作HEAD
的速记符号,正如Git贡献者Junio C Hamano在他的Git Blame博客中所指出的那样:
你可以使用“@”代替“HEAD”,例如“git log @”。
Stack Overflow用户VonC还在回答另一个问题时发现了一些有趣的信息,解释了为什么选择了@
作为速记符号,详情请见此处。
值得注意的是,在某些环境下,不必将HEAD
大写,特别是在使用不区分大小写的文件系统(如Windows和OS X)的操作系统中。
请看创建和操作分支
HEAD 实际上是一个文件,其内容确定了 HEAD 变量所指向的位置:
$ cat .git/HEAD
ref: refs/heads/master
$ cat .git/refs/heads/master
35ede5c916f88d8ba5a9dd6afd69fcaf773f70ed
在这个代码库中,HEAD文件的内容指向一个名为refs/heads/master的第二个文件。文件refs/heads/master包含了主分支上最近提交的哈希值。HEAD
是指向当前检出的分支或提交的指针,它回答了这个问题:我在仓库中的哪个位置?或者说,这是Git知道在哪个提交上映射您的本地工作树以及您当前是否正在工作在一个分支(attached)还是不在(detached)的方式。
HEAD
可以处于两种状态中的任意一种,附加或分离,具体取决于您是否已经检出了分支。默认状态是附加,其中对历史记录的任何操作都会自动记录到当前引用HEAD
的分支中。
在分离状态下,可以进行实验性更改而不会影响任何现有的分支。请参见下面的信息图,说明在附加状态与分离状态下提交之间的区别。
一个常见的误解是消息您处于“分离HEAD”状态的语气有误,事实上它只是描述了HEAD
如何引用当前快照。
可能使HEAD处于分离状态的操作:
$ git checkout 14ko3
$ git checkout origin/master
$ git switch master --detached
$ git checkout v1.0.1
从分离状态转换为附加状态
要从分离状态转换为附加状态,可以从当前位置创建一个新分支或切换回现有分支。
注意:在分离状态下创建的任何提交将在切换到另一个现有分支之前未在新分支中保存更改的情况下(垃圾收集后)被丢弃。
可以通过不同的方式找出当前 HEAD
的状态,以下是两种选项。
show
$ git show HEAD --oneline
14ko3 (HEAD, master) C1
# If attached, the output would have been
14ko3 (HEAD -> master) C1
status
$ git status
HEAD detached at 14ko3
如果您想要明确地查看HEAD
引用了什么,您总是可以检查.git/HEAD
文件,这是Git在内部管理HEAD
所使用的实际文件。该文件包含分支名称或提交哈希值,具体取决于HEAD
是否处于分离状态。
$ cat .git/HEAD
ref: refs/heads/master
# If detached, the output would have been
14ko36e295f1a98ec57397b3acc7bc247da61ff5
来源:以上摘录来自这篇完整文章:Git中的HEAD是什么?
阅读了之前的所有答案后,我仍然希望更清晰地理解。这篇官方Git网站的博客http://git-scm.com/blog给了我所需要的:
在Git中,HEAD是指向当前分支引用的指针,而当前分支引用本身是指向您上次提交或检出到工作目录中的最后一次提交的指针。这也意味着它将成为下一个提交的父级。通常最简单的想法是,HEAD是您上次提交的快照。
HEAD
不是一个提交,它指向一个提交。 - jub0bscheckout HEAD^
,现在 HEAD 甚至不再指向任何分支上的最后提交快照。 - LarsHcommit
、merge
、rebase
、log
等命令来定义的。但从概念上讲,“(指针指向的)当前位置”可能是一个很好的总结。 - LarsH
git ls-remote
),但“HEAD”的定义似乎很难确定。git branch的文档简单地说明HEAD
实际上是“当前分支的末端”。所有的混淆实际上都必须关于分支的定义 - 这是令人惊讶的微妙:我们到底是什么意思“branch”? - Brent Bradburn