2023-04-02 05:00:03

Git中的HEAD是什么?

您可以看到Git文档中这样说

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

但Git HEAD到底是什么?


当前回答

分支实际上是一个持有提交ID(例如17a5)的指针。 HEAD是指向用户当前工作的分支的指针。

HEAD有一个如下所示的引用流:

ref:

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

其他回答

我自己还没有弄清楚,但Silfheed对“贴在节点上的便利贴”定义的链接是迄今为止我发现的最好的链接。

我想分享一下我对寻找定义的印象,否则我为什么要把它留给自己。 我把它理解为粘在Git树空间当前位置上的贴纸。我错过了这样一个术语——GIT树中的当前位置,它有自己的属性来指示我们所处的位置。

“参考”或“指针”之类的概念我不太清楚。在我看来,它们暗示了一种新的抽象层次,我们从抽象层次的内部来“指”某物。这可能不是真的,但到目前为止,这是我的看法。

为了理解HEAD是什么,让我们使用一个实际的例子,其中有两个不同的分支,main和feature1,来自两个不同的开发人员Dev1和Dev2,他们在同一个项目上工作。

Dev1主分支的案例1:

name~/repo (main)
$ ls -al
total 9
drwxr-xr-x 1 AlphaLy 197121  0 Dec 22 15:09 ./
drwxr-xr-x 1 AlphaLy 197121  0 Dec 21 20:35 ../
drwxr-xr-x 1 AlphaLy 197121  0 Dec 22 15:09 .git/
-rw-r--r-- 1 AlphaLy 197121 20 Dec 21 20:35 README.md
-rw-r--r-- 1 AlphaLy 197121  0 Dec 22 15:09 test.txt

Next1

name~/repo (main) 
$ cd .git/
name~/repo/.git (GIT_DIR!)
$ ls
COMMIT_EDITMSG  description  HEAD    index  logs/     ORIG_HEAD    refs/
config          FETCH_HEAD   hooks/  info/  objects/  packed-refs

Next2

name~/repo/.git (GIT_DIR!)
$ cat HEAD
ref: refs/heads/main

我们可以清楚地看到HEAD是一个文件,其中一行指向refs/heads目录中的一个名为main的文件(heads是refs目录中的一个目录)。参考Next1步骤定位refs目录

现在让我们转到Next1步骤,cd到refs目录,在heads目录中搜索主文件,看看它包含什么

name~/repo/.git (GIT_DIR!)
    $ cd refs
    
name~/repo/.git/refs (GIT_DIR!)
    $ ls
    heads/  remotes/  tags/
    
name~/repo/.git/refs/ (GIT_DIR!)
    $ cd heads/
    
name~/repo/.git/refs/heads (GIT_DIR!)
    $ ls
    main  maxi

name~/repo/.git/refs/heads (GIT_DIR!)
$ cat main
8b25d89f3396177416c055ab07ebf778616eecdd

8b25d89f3396177416c055ab07ebf778616eecdd是当前提交。因此,我们可以说HEAD指向一个名为main的文件(总是以当前分支命名),该文件包含当前提交(上面的40位字符)。HEAD指的是当前提交。

带有Dev2的feature1分支的案例2

在这里,唯一的区别是在Next2步骤中

name~/repo/.git (GIT_DIR!)
$ cat HEAD
ref: refs/heads/feature1

以及以下几点:

    name~/repo/.git (GIT_DIR!)
   $ cat feature1
03fbf973ac1014085864234010b82393208ebbd6

03fbf973ac1014085864234010b82393208ebbd6是在feature1分支上的当前提交。因此,这里HEAD再次指向一个名为feature1的文件(以当前分支命名),该文件包含当前提交(上面的40位字符)。

结论:

HEAD是指当前提交而不是当前分支。这只是一个巧合,包含当前提交的文件以当前分支命名,我们倾向于说'HEAD指向当前分支'。

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

假设当前的分支是master。

HEAD是你的.git/目录下的一个文件,通常看起来像这样:

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

Refs /heads/master本身是一个文件,通常包含master最新提交的哈希值:

% cat .git/refs/heads/master 
f342e66eb1158247a98d74152a1b91543ece31b4

如果你做git日志,你会看到这是master的最新提交:

% git log --oneline 
f342e66 (HEAD -> master,...) latest commit
fa99692 parent of latest commit

所以我的想法是HEAD文件是一种跟踪最新提交的方便方法,而不是记住长散列值。

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

但是一个存储库只有一个HEAD。HEAD是一个引用,它引用在当前分支完成的最新提交。

它就像git用户的眼睛。无论HEAD引用哪个提交,存储库都开始反映该特定提交期间存储库的条件。

HEAD的基本性质是总是引用当前分支的最新提交,但我们可以通过使用git checkout "commit-hash"将HEAD移动到当前分支的任何提交。

注意:我们可以使用git log——oneline命令轻松获得commit-hash

假设这不是一种叫做“分离HEAD”的特殊情况,那么,正如O'Reilly Git书第2版第69页所述,HEAD的意思是:

HEAD总是指当前节点上最近的提交 分支。当您更改分支时,HEAD将被更新为引用新的分支 布兰奇的最新提交。

so

HEAD是当前分支的“尖端”。

注意,我们可以使用HEAD表示最近的提交,使用HEAD~表示提示之前的提交,使用HEAD~~或HEAD~2表示更早的提交,以此类推。