什么是Git中的HEAD?

你看到Git留档说

分支必须完全合并到HEAD中。

什么是GitHEAD

650500 次浏览

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

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

cat .git/HEAD

在我的例子中,输出是:

$ cat .git/HEADref: refs/heads/master

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

引用其他人

一个head是一个简单的引用提交对象。每个头都有一个名称(分支机构名称或标签名称等)。由默认情况下,每个人都有一个头名为master的存储库。一个存储库可以包含任意数量的头。在任何时候都有一个头被选中作为“现任头”。这个头是别名为HEAD,总是大写字母”。

注意这个区别:一个“头”(小写)是指任何一个存储库中的命名头;“HEAD”(大写)专门指目前活跃的头。这区分在Git中经常使用留档

另一个快速涵盖git内部工作原理的好来源(因此可以更好地理解head/HEAD)可以在这里中找到。引用(ref:)或头或分支可以被视为提交历史中粘贴在提交上的便利贴。通常它们指向一系列提交的尖端,但它们可以用#0#1等移动。

我推荐这个定义来自github开发者Scott Chacon[视频参考]:

head是你当前的分支。它是一个符号引用。它是对一个分支的引用。你总是有HEAD,但是HEAD会指向其他指针之一,指向你所在的分支之一。它是你下一次提交的父级。它应该是最后一次签出到你的工作目录的内容…这是你工作目录的最后已知状态。

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

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

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

Mercurial也是如此。

一个很好的方法来开车回家的点在正确的答案是运行git reflog HEAD,您将获得HEAD指向的所有位置的历史记录。

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

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

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

如果你刚刚克隆,没有签出我不知道它指向什么,可能是一些无效的位置。

HEAD指的是您的工作副本指向的当前提交,即您当前签出的提交。从官方Linux内核留档指定Git版本

HEAD命名您在工作树中基于其进行更改的提交。

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

而不是键入“HEAD”,你可以说“@”代替,例如“git log@”。

Stack Overflow用户VonC也发现了一些关于为什么在回答另一个问题时选择#0作为速记的有趣信息

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

我想在Greg Hewgil接受的答案中详细说明一些事情。根据Git Pocket指南

部门:

分支本身定义为提交中可到达的所有点来自命名提交的图(分支的“提示”)。

头:特殊类型的参考

特殊的ref HEAD决定你在哪个分支…

Refs

Git定义了两种引用,或命名指针,它调用"ref":

请求参数
  • 一个简单的ref,直接指向对象ID(通常是提交或标记)
  • 符号ref(或Symref),指向另一个ref(简单或符号)

正如Greg提到的,HEAD可以处于“分离状态”。因此HEAD可以是简单的ref(用于分离的HEAD)或Symref。

如果HEAD是现有分支的符号引用,则为“on”另一方面,如果HEAD是一个简单的直接引用通过其SHA-1 ID命名提交,那么您不是“在”任何分支上,而是而是在“分离头”模式下,当你检查出一些先检查一下

这两个可能会让你困惑:

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

HEAD

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

看看创建和玩树枝

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

$ cat .git/HEADref: refs/heads/master$ cat .git/refs/heads/master35ede5c916f88d8ba5a9dd6afd69fcaf773f70ed

在此存储库中,HEAD文件的内容引用了名为主裁判的第二个文件。文件主裁判包含主分支上最新提交的哈希值。

结果是HEAD指向来自. g it/refs/head/master文件的主分支提交。

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

HEAD总是引用当前服务器上最近的提交当您更改分支时,将更新HEAD以引用新分支分支的最新提交。

所以

HEAD当前分支的“尖端”

请注意,我们可以使用HEAD来引用最近的提交,并使用HEAD~作为提示之前的提交,使用HEAD~~HEAD~2作为更早的提交,依此类推。

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

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

Git中的HEAD是当前分支引用的指针,它反过来是您上次提交或签出到工作目录中的最后一次提交的指针。这也意味着它将是您下一次提交的父级。通常最简单的想法是HEAD是上一次提交的快照。

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

progit书,第3.1 Git分支-果壳中的分支章,在第创建一个新的分支节:

如果创建一个新分支会发生什么?这样做会创建一个新的分支指针供您移动。假设您创建了一个新分支调用测试。您可以使用git分支命令执行此操作:

$ git branch testing

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

输入图片描述

Git如何知道你当前在哪个分支上?它保留了一个名为HEAD的特殊指针。请注意,这与您可能习惯的其他VCS中的HEAD概念,例如Subversion或CVS。在Git中,这是指向本地分支的指针你现在在。在这种情况下,你仍然是主人。那个混蛋分支命令只创建了一个新分支-它没有切换到那个分支分支。

输入图片描述

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

在此处输入图片描述

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

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

这可以是特定分支的尖端(例如“master”)或分支的一些中间提交(“分离头”)

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

在这些答案中,有一个也许微妙但重要的误解。我想我应该加上我的答案来澄清它。

什么是HEAD

头是你

HEAD是一个象征性的引用,指向你在提交历史中的任何位置。无论你去哪里,无论你做什么,它都像影子一样跟着你。如果你做了一个提交,HEAD会移动。如果你签出了某个东西,HEAD也会移动。无论你做什么,如果你在提交历史中移动了新的地方,HEAD都会和你一起移动。要解决一个常见的误解:你不能将自己与HEAD分离。分离的HEAD状态不是这样的。如果你发现自己在想:“哦,不,我处于分离的HEAD状态!我失去了我的HEAD!”记住,这是你的HEAD。HEAD就是你。你没有脱离头脑,你和你的头脑已经脱离了别的东西。

HEAD可以连接到什么?

HEAD可以指向提交,是的,但通常不会。让我再说一遍。通常#0不指向提交。它指向一个分支引用。它是该分支的,当你做某些事情(例如,commit#3)时,附加的分支将与HEAD一起移动。你可以通过查看引擎盖下看到它指向的内容。

cat .git/HEAD

通常你会得到这样的东西:

ref: refs/heads/master

有时你会得到这样的东西:

a3c485d9688e3c6bc14b06ca1529f0e78edd3f86

这就是HEAD直接指向提交时发生的情况。这称为分离的HEAD,因为HEAD指向的不是分支引用。如果您在此状态下进行提交,不再附加到HEADmaster将不再与您一起移动。无论提交在哪里。您可以与主分支处于同一提交状态,但如果#0指向提交而不是分支,则它将被分离,并且新提交不会与分支引用相关联。

如果您尝试以下练习,您可以以图形方式查看此内容。从git存储库中,运行此操作。您会得到一些略有不同的东西,但它们的键位将在那里。当需要直接签出提交时,只需使用您从第一个输出中获得的任何缩写哈希(这里是a3c485d)。

git checkout mastergit 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仍然引用与分支名称关联的特定修订。我们仍然是0号主分支,不是吗?

现在试试:

git status# HEAD detached at a3c485d

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

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

最后

HEAD就是你。它指向你签出的任何内容,无论你在哪里。通常这不是一个提交,它是一个分支。如果HEAD确实指向一个提交(或标签),即使它与分支也指向相同的提交(或标签),你(和HEAD)已经与该分支分离。由于你没有附加分支,当你进行新提交时,分支不会跟随你。然而,HEAD会。

A分支实际上是一个保存提交ID的指针,例如17a5HEAD是指向用户当前正在处理的分支的指针。

HEAD有一个参考文件,如下所示:

参考:

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

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

$ git cat-file -t HEADcommit

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

$ cat .git/refs/heads/masterb089141cc8a7d89d606b2f7c15bfdc48640a8e25

HEAD实际上只是一个用于存储当前分支信息的文件

如果您在git命令中使用HEAD,则指向当前分支

您可以通过以下方式查看此文件的数据cat .git/HEAD

我还在弄清楚git的内部结构,到目前为止已经弄清楚了这一点:

假设当前分支是大师

  1. HEAD是. git/目录中的一个文件,通常看起来像这样:
% cat .git/HEADref: refs/heads/master
  1. 主裁判本身是一个通常具有master最新提交的哈希值的文件:
% cat .git/refs/heads/masterf342e66eb1158247a98d74152a1b91543ece31b4
  1. 如果您执行git日志,您将看到这是master的最新提交:
% git log --onelinef342e66 (HEAD -> master,...) latest commitfa99692 parent of latest commit

所以我的想法是HEAD文件是跟踪最新提交的便捷方式,而不是记住长哈希值。

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

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

分离头

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

分离状态下,可以在不影响任何现有分支的情况下进行实验性更改。请参阅下面的信息图,其中说明了连接状态与分离状态下的犯下之间的差异。

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

一个常见的误解是消息您处于“分离头”状态的语气是错误的,而实际上它只是描述了HEAD如何引用当前快照。

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

  • 检出特定的提交,即:
    $ git checkout 14ko3
  • 显式检出远程分支,即。
    $ git checkout origin/master
  • 使用分离标志切换到分支,即。
    $ git switch master --detached
  • 签出一个标签,即。
    $ git checkout v1.0.1
  • 执行交互式rebase,或包含冲突更改的常规rebase

从分离状态移动到附加状态

要从分离状态移动到附加状态,您可以从您所在的位置创建一个新分支,或者切换回现有分支。

备注:如果您切换到另一个现有分支,在分离状态下创建的任何提交最终都会被丢弃(后垃圾回收机制),而不会首先在新分支中持久化您的更改。

检查HEAD的状态

弄清楚HEAD当前处于哪个状态可以通过不同的方式完成,这里有两个选项。

  • 使用show
    $ git show HEAD --oneline14ko3 (HEAD, master) C1
    # If attached, the output would have been14ko3 (HEAD -> master) C1
  • 使用status
    $ git statusHEAD detached at 14ko3

什么是HEAD?(技术上)

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

$ cat .git/HEADref: refs/heads/master
# If detached, the output would have been14ko36e295f1a98ec57397b3acc7bc247da61ff5

来源:以上摘录来自这个主题的全长帖子:什么是Git中的HEAD?

存储库中可以有多个头。并且头的总数始终等于存储库中存在的分支总数,这意味着头只是每个分支的最新提交

但是对于一个repository.HEAD只有一个HEAD是引用在当前分支完成的最新提交的引用。

无论HEAD引用哪个提交,存储库都会开始反映存储库在该特定提交期间的条件。

HEAD的基本性质是总是引用当前分支的最新提交,但我们可以通过使用git签出“提交哈希”将HEAD移动到当前分支的任何提交

注意:我们可以很容易地使用命令git log--oneline来获取提交哈希

HEAD几乎是分支的头部。所以当你观察一个分支时,你看到的是最新的提交,也就是这个分支的头部。但是,你可以指出自己正在查看该分支历史上更远的另一个提交,当你这样做时,你将HEAD移动到以前的提交。由于HEAD自然属于分支中的最新提交,它被认为是分离的。

可视化表示。每个分支都是一条毛毛虫,每个提交都是该生物的一部分。因此HEAD将位于最前面的部分。如果您将HEAD从该部分移至另一个要使用的部分,则您已经将头部从自然部分分离。希望它有任何意义。

现在,如果您在主分支中分离HEAD,然后签出newFeature,并再次签出main,HEAD仍将被分离,并在另一个提交之上。我认为HEAD是一面镜子,你可以指向你想要的地方。