你会看到 Git 文档说类似
分支必须完全合并到 HEAD 中。
但是 Git HEAD
到底是什么?
您可以将 HEAD 视为“当前分支”。当您使用 git checkout
切换分支时,HEAD 版本更改为指向新分支的尖端。
您可以通过执行以下操作查看 HEAD 指向的内容:
cat .git/HEAD
就我而言,输出是:
$ cat .git/HEAD
ref: refs/heads/master
HEAD 可以引用与分支名称无关的特定修订。这种情况称为 detached HEAD。
引用 other people:
头只是对提交对象的引用。每个头都有一个名称(分支名称或标签名称等)。默认情况下,每个存储库中都有一个名为 master 的头。一个存储库可以包含任意数量的头。在任何给定时间,都会选择一个头作为“当前头”。这个头是 HEAD 的别名,总是大写”。注意这个区别:“头”(小写)指代存储库中的任何一个命名头;“头”(大写)专门指当前活动的头。这Git 文档中经常使用区分。
here 可以找到另一个快速涵盖 git 内部工作原理(从而更好地理解 head/HEAD)的好资源。引用 (ref:) 或头部或分支可以被视为粘贴在提交历史中的提交上的便利贴。通常它们指向一系列提交的尖端,但可以使用 git checkout
或 git reset
等来移动它们。
git checkout HEAD~2
),它不是已知头的提交 id。有关更详尽的说明,请参阅 eagain.net/articles/git-for-computer-scientists 中的文章。
git revert
并不是将分支移至不在尖端的一个很好的例子,因为 git revert
只是创建了一些新的提交,并且仍然将当前分支留在(新的)尖端。
commit
、reset
等的行为。
在这些答案中,有一个可能是微妙但重要的误解。我想我会添加我的答案来清除它。
什么是头?
头是你
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
指向的不是分支引用。如果您在此状态下提交,则不再附加到 HEAD
的 master
将不再与您一起移动。该提交在哪里并不重要。 您可以与您的主分支在同一个提交上,但如果 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”状态。
您可以使用 git log -1
查看 (HEAD -> branch)
与 (HEAD, branch)
的相同表示。
综上所述
HEAD
是你。它指向您签出的任何内容,无论您身在何处。通常这不是提交,而是一个分支。如果 HEAD
确实 指向一个提交(或标签),即使它是一个分支也指向的同一个提交(或标签),您(和 HEAD
)已与该提交(或标签)分离分支。由于您没有附加分支,因此在您进行新提交时,该分支不会跟随您。但是,HEAD
会。
.git/HEAD
是软件认为是 HEAD。
HEAD
是一个分支的尖端,但它不是,它就像一个磁带头。一个非常简单的查看此操作的方法是 git checkout HEAD~1
返回一个提交,然后 git checkout HEAD~1
返回另一个提交。如果 HEAD
总是引用分支上的最新提交,则第二个命令将与第一个命令相同 - 它不是。第二个命令将您的 HEAD
再向后移动一次,即您现在从分支的尖端进行了两次提交。这很微妙但很重要。
HEAD 只是一个特殊的指针,指向您当前所在的本地分支。
来自 Pro Git 书第 3.1 Git Branching - Branches in a Nutshell 章的创建新分支部分:
如果你创建一个新的分支会发生什么?好吧,这样做会为您创建一个新的指针来移动。假设您创建了一个名为 testing 的新分支。您可以使用 git branch 命令执行此操作: $ git branch testing 这会在您当前所在的同一提交处创建一个新指针 Git 如何知道您当前所在的分支?它保存了一个特殊的指针,称为 HEAD。请注意,这与您可能习惯的其他 VCS(例如 Subversion 或 CVS)中的 HEAD 概念有很大不同。在 Git 中,这是指向您当前所在的本地分支的指针。在这种情况下,你仍然是主人。 git branch 命令只创建了一个新分支——它没有切换到那个分支。
34ac2
,现在 HEAD 将指向该提交,它被称为分离的 HEAD。在这种状态下,您也可以进行更改、试验和提交更改,但是一旦您签出不同的分支,您将丢失所有更改,除非您当然创建了一个新分支。
git log
并得到类似 commit ad0265... HEAD -> foo ...
的内容,则意味着 foo
分支是对提交 ID ad0265
的引用。对文本引用 foo
进行检查并不是一个独立的头脑。对提交 ID ad0265
进行检查会导致头部分离。可能是我错过了你所交流的一些微妙之处。我希望这堵文字墙有助于发现我迷路的地方。
我向 github 开发者 Scott Chacon [video reference] 推荐这个定义:
Head 是您当前的分支。这是一个象征性的参考。它是对分支的引用。你总是有 HEAD,但 HEAD 将指向这些其他指针之一,指向你所在的分支之一。它是您下一次提交的父级。它应该是最后一次签出到您的工作目录的内容...这是您工作目录的最后一个已知状态。
整个视频将公平地介绍整个 git 系统,所以我也建议你如果有时间观看它。
假设它不是称为“分离的 HEAD”的特殊情况,那么,如 O'Reilly Git 书第 2 版第 69 页中所述,HEAD
表示:
HEAD 总是指当前分支上的最新提交。当您更改分支时,HEAD 会更新以引用新分支的最新提交。
所以
HEAD 是当前分支的“尖端”。
请注意,我们可以使用 HEAD
来引用最近的提交,并使用 HEAD~
作为提示之前的提交,使用 HEAD~~
或 HEAD~2
作为更早的提交,等等。
HEAD
指的是您的工作副本指向的当前提交,即您当前已签出的提交。从 official Linux Kernel documentation on specifying Git revisions:
HEAD 命名工作树中更改所基于的提交。
但是请注意,在即将发布的 Git 1.8.4 版本中,@
也可以用作 HEAD
的简写,如 noted by Git contributor Junio C Hamano in his Git Blame blog:
你可以说“@”而不是输入“HEAD”,例如“git log @”。
Stack Overflow 用户 VonC 还发现了一些 interesting information on why @
was chosen as a shorthand in his answer to another question。
同样有趣的是,在某些环境中,不需要大写 HEAD
,特别是在使用不区分大小写文件系统的操作系统中,特别是 Windows 和 OS X。
看看Creating and playing with branches
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 文件中的主分支提交。
https://i.stack.imgur.com/kYkB8.png
在阅读了所有以前的答案之后,我仍然想要更清楚。 git 官方网站 http://git-scm.com/blog 上的这个博客给了我想要的东西:
HEAD:指向最后提交快照的指针,下一个父级
Git 中的 HEAD 是指向当前分支引用的指针,它又是指向您所做的最后一次提交或检出到工作目录中的最后一次提交的指针。这也意味着它将成为您下一次提交的父级。通常将其视为 HEAD 是您上次提交的快照是最简单的。
HEAD
不是提交;它指向一个。
checkout HEAD^
,现在 HEAD 甚至不会指向任何分支上的最后一个提交快照。
commit
、merge
、rebase
、log
等命令。但从概念上讲,可能是“(指向)当前位置"是一个很好的总结。
我只想详细说明 Greg Hewgil 接受的答案中的一些内容。根据 Git Pocket Guide
分支:
分支本身被定义为从命名提交(分支的“尖端”)在提交图中可到达的所有点。
HEAD:一种特殊类型的 Ref
特殊的 ref HEAD 决定了你在哪个分支......
参考文献
Git 定义了两种引用或命名指针,它称之为“refs”: 一个简单的 ref,它直接指向一个对象 ID(通常是一个提交或标签) 一个符号 ref(或 symref),它指向另一个 ref (无论是简单的还是象征性的)
正如 Greg 提到的,HEAD 可以处于“分离状态”。所以 HEAD 可以是简单的 ref(对于分离的 HEAD)或 symref。
如果 HEAD 是现有分支的符号引用,那么你就在那个分支上。另一方面,如果 HEAD 是一个简单的 ref,直接通过其 SHA-1 ID 命名提交,那么您不是“在”任何分支上,而是处于“分离 HEAD”模式,当您之前签出时会发生这种情况承诺审查。
Git 中的 HEAD 是什么? (概念上)
HEAD
是指向当前签出的分支或提交的指针,它回答了以下问题:我现在在存储库中的什么位置? 或者,换句话说,它是Git 知道在哪个提交上镜像您的本地工作树的方式,以及您当前是否在分支上工作(attached)或没有(detached)。
分离头
HEAD
可以处于两种状态中的任一种,attached 或 detached,具体取决于您是否检查过出一个分支与否。默认状态为 attached,其中对历史记录的任何操作都会自动记录到当前引用的分支 HEAD
。
在分离状态下,可以在不影响任何现有分支的情况下进行实验性更改。请参阅下面的信息图,说明在附加状态与分离状态下提交之间的区别。
https://i.stack.imgur.com/vaQxa.png
一个常见的误解是消息 You are in 'detached HEAD' state 是错误的,而实际上它只是描述了 HEAD
如何引用当前快照。
可以使 HEAD 处于分离状态的操作:
签出特定的提交,即 $ git checkout 14ko3
显式检出远程分支,即 $ git checkout origin/master
使用 detached 标志切换到分支,即 $ git switch master --detached
签出一个标签,即 $ git checkout v1.0.1
执行交互式变基,或包含冲突更改的常规变基
从分离状态转变为附加状态
要从分离状态转移到附加状态,您可以从您所在的位置创建一个新分支,或者切换回现有分支。
注意:如果您切换到另一个现有分支,则在分离状态下创建的任何提交最终都将被丢弃(垃圾回收后),而无需先将更改保留在新分支中。
检查 HEAD 状态
可以通过不同的方式确定 HEAD
当前处于哪个状态,这里有两个选项。
using show $ git show HEAD --oneline 14ko3 (HEAD, master) C1 # 如果附加,输出将是 14ko3 (HEAD -> master) C1
使用 status $ git status HEAD 在 14ko3 分离
HEAD 到底是什么? (技术上)
如果您想明确查看 HEAD
所引用的内容,您可以随时检查 .git/HEAD
文件,这是 Git 在内部用于管理 HEAD
的实际文件。该文件包含分支或提交哈希的名称,具体取决于 HEAD
是否分离。
$ cat .git/HEAD
ref: refs/heads/master
# If detached, the output would have been
14ko36e295f1a98ec57397b3acc7bc247da61ff5
来源: 以上摘录来自这篇关于该主题的完整帖子:What is HEAD in Git?
我认为'HEAD'是当前的签出提交。换句话说,“HEAD”指向当前签出的提交。
如果您刚刚克隆并且没有签出我不知道它指向什么,可能是一些无效的位置。
HEAD
是您当前已签出的任何提交。详见the manual(相关段落紧跟在图 3.4 之后)。
master
分支——所以 HEAD 将指向 master。
master
,但并非总是如此。见remote set-head
remote set-head
的引用,它只影响本地默认分支,不会更改服务器的默认值。
将正确答案中的观点带回家的一个好方法是运行 git reflog HEAD
,您可以获得 HEAD 指出的所有地点的历史记录。
Head 指向当前签出分支的尖端。
https://i.stack.imgur.com/IstVN.png
在您的存储库中,有一个 .git 文件夹。在此位置打开文件:.git\refs\heads。该文件(大多数情况下为 master)中的(sha-1 哈希)代码将是最近的提交,即在命令 git log
的输出中看到的那个。有关 .git 文件夹的更多信息:http://gitready.com/advanced/2009/03/23/whats-inside-your-git-directory.html
git reset HEAD^
也很常见,然后分支的尖端不再指向最近的提交(前一个提示)。
感觉 HEAD
只是您签出的最后一次提交的标签。
这可以是特定分支的尖端(例如“master”)或某个分支的中间提交(“分离头”)
除了所有定义之外,我脑海中浮现的一件事是,当您进行提交时,GIT 会在存储库中创建一个提交对象。提交对象应该有一个父对象(如果是合并提交,则应该有多个父对象)。现在,git 如何知道当前提交的父级?所以 HEAD 是指向(引用)最后一次提交的指针,它将成为当前提交的父级。
Git
都是关于提交的。
Head
指向您当前签出的提交。
$ git cat-file -t HEAD
commit
每当您签出一个分支时,HEAD 都会指向该分支上的最新提交。 HEAD 的内容可以检查如下(对于 master 分支):
$ cat .git/refs/heads/master
b089141cc8a7d89d606b2f7c15bfdc48640a8e25
我还在弄清楚 git 的内部结构,并且到目前为止已经弄清楚了:
假设当前分支是master。
HEAD 是 .git/ 目录中的一个文件,通常看起来像这样:
% cat .git/HEAD
ref: refs/heads/master
refs/heads/master 本身就是一个文件,通常具有 master 最新提交的哈希值:
% cat .git/refs/heads/master
f342e66eb1158247a98d74152a1b91543ece31b4
如果你做一个 git log,你会看到这是 master 的最新提交:
% git log --oneline
f342e66 (HEAD -> master,...) latest commit
fa99692 parent of latest commit
所以我的想法是 HEAD 文件是一种跟踪最新提交的便捷方式,而不是记住长哈希值。
HEAD 几乎是分支的负责人。所以当你观察一个分支时,你看到的是最新的提交,也就是这个分支的头。但是,您可以指出自己正在查看该分支历史中更早的另一个提交,并且当您这样做时,您正在将 HEAD 移动到先前的提交。由于 HEAD 自然属于分支中的最新提交,因此它被认为是分离的。
一种视觉表现。每个分支都是毛毛虫,每次提交都是生物的一部分。因此,HEAD 将位于最领先的部分。如果您将 HEAD 从该段移至另一个要使用的段,则您已将头与自然段分离。希望它有任何意义。
现在,如果您在主分支中分离 HEAD,然后签出 newFeature,然后再次签出 main,HEAD 仍将被分离,并在另一个提交之上。我将 HEAD 视为一面镜子,您可以将其指向您想要的位置。
这两个可能会让你感到困惑:
头
指向最近提交的分支的命名引用。除非您使用包引用,否则头通常存储在 $GIT_DIR/refs/heads/ 中。
头
当前分支,或者您的工作树通常是从 HEAD 指向的树生成的。 HEAD 必须指向一个头,除非您使用的是分离的 HEAD。
看看http://git-scm.com/book/en/Git-Branching-What-a-Branch-Is
图 3-5。 HEAD 文件指向你所在的分支。
HEAD
所指的内容取决于您是在谈论裸仓库还是非裸仓库。在非裸仓库的上下文中,它实际上是指当前签出的提交,它不需要附加分支(即处于分离 HEAD
状态时)。
分支实际上是一个指针,其中包含一个提交 ID,例如 17a5。 HEAD 是指向用户当前正在处理的分支的指针。
HEAD 有一个参考文件,如下所示:
参考:
您可以通过访问您正在使用的存储库中的 .git/HEAD
.git/refs
检查这些文件。
HEAD 实际上只是一个用于存储当前分支信息的文件
如果你在你的 git 命令中使用 HEAD 你指向你当前的分支
您可以通过 cat .git/HEAD
查看此文件的数据
存储库中可以有多个头。并且 head 的总数始终等于存储库中存在的分支总数,这意味着 head 只不过是每个分支的最新提交
但是存储库只有一个 HEAD。HEAD 是一个引用,它引用在当前分支完成的最新提交。
它就像 git 用户的眼睛。无论 HEAD 引用哪个提交,存储库都会开始反映存储库在该特定提交期间所具有的条件。
HEAD 的基本性质是始终引用当前分支的最新提交,但我们可以使用 git checkout "commit-hash" 将 HEAD 移动到当前分支的任何提交
注意:我们可以使用命令 git log --oneline 轻松获取 commit-hash
作为一个概念,头部是分支中的最新版本。如果每个命名分支有多个头,则可能在进行本地提交而不合并时创建了它,从而有效地创建了一个未命名的分支。
要拥有一个“干净”的存储库,每个命名分支应该有一个头,并且在本地工作后总是合并到一个命名分支。
Mercurial 也是如此。