在Git中,HEAD、工作树和索引之间有什么区别?

有人能告诉我Git中HEAD,工作树和索引的区别吗?

据我所知,它们都是不同分支的名称。我的假设正确吗?

我发现了这个:

单个git存储库可以跟踪任意数量的分支,但是您的工作树只与其中一个分支相关联(“当前”;或者“已结帐”;分支),HEAD指向该分支。

这是否意味着HEAD和工作树总是相同的?

188449 次浏览

工作树实际上是您当前正在处理的文件中的内容。

HEAD是一个指向上次签出的分支或提交的指针,如果你进行了新的提交,它将是新提交的父节点。例如,如果您在master分支上,那么HEAD将指向master,当您提交时,新提交将是master所指向的修订的后代,而master将被更新为指向新的提交。

指数是准备新提交的暂存区。本质上,索引的内容就是新提交的内容(尽管如果执行git commit -a,这将在提交之前自动将Git知道的文件的所有更改添加到索引中,因此它将提交工作树的当前内容)。git add将从工作树中添加或更新文件到索引中。

关于这些主题还有一些很好的参考资料:

workflow

我使用索引作为检查点

当我要做一个可能会出错的更改时——当我想探索一些我不确定是否能坚持下去的方向,甚至不确定它是否是一个好主意时,例如在概念上要求重构或更改表示类型时——我会将我的工作检查点到索引中。

如果这是我自上次提交以来所做的第一个更改,那么我可以使用本地存储库作为检查点,但通常我只有一个概念性更改,我将其作为一组小步骤来实现。
我想在每一步之后检查,但保存提交,直到我重新开始工作,测试代码

注:

  1. 工作空间是你看到和编辑的(源)文件的目录树。

  2. 指数<baseOfRepo>/.git/index中的一个大型二进制文件,它列出了当前分支中的所有文件、它们的sha1校验和、时间戳和文件名——它不是另一个包含文件副本的目录。

  3. 本地存储库是一个隐藏目录(.git),包括一个objects目录,其中包含repo中每个文件的所有版本(本地分支和远程分支的副本),作为一个压缩的"blob"文件。

不要将上图中表示的四个“磁盘”视为回购文件的单独副本。

3 states

  • < a href = " http://hades.github。io/2010/01/ Git - Your - Friend -not- Foe - Vol -3-ref -and- Index /" rel="noreferrer">Git是你的朋友而不是敌人Vol. 3:引用和索引 . io/2010/01/ Git - Your - Friend -not- Foe - Vol -3-ref -and- Index /" rel="noreferrer">Git是你的朋友而不是敌人

它们基本上是Git提交的命名引用。有两种主要类型的裁判:标签和头部。

  • 标记是标记历史上某个特定点的固定引用,例如v2.6.29。
  • 相反,头部总是移动,以反映项目开发的当前位置。

 committed

(注意:由于评论Timo Huovinen,这些箭头不是提交指向的,它是工作流程顺序,基本上显示箭头为1 -> 2 -> 3 -> 4,其中1是第一次提交,4是最后一次提交)

现在我们知道项目中发生了什么。
但是要知道这里发生了什么,现在有一个特殊的参考,叫做HEAD。它有两个主要目的:

  • 它告诉Git在签出时要从哪个提交中获取文件
  • 当你提交时,它会告诉Git在哪里放置新的提交。

当您运行git checkout ref时,它将HEAD指向您指定的ref,并从中提取文件。当您运行git commit时,它创建了一个新的提交对象,该对象成为当前HEAD的子对象。正常情况下,HEAD指向其中一个正面,所以一切都很顺利。

checkout

工作树

您的工作树是您当前正在处理的文件。

Git索引

  • git“索引”是存放要提交到git存储库的文件的地方。

  • 索引也称为缓存目录缓存当前目录缓存暂存区暂存文件

  • 在你“提交”(签入)文件到git存储库之前,你需要首先将文件放在git“索引”中。

  • 索引是不是工作目录:你可以输入一个命令,比如git status, git会告诉你工作目录中的哪些文件被添加到git索引中(例如,通过使用git add filename命令)。

  • 索引不是git存储库:如果你使用git commit命令,git索引中的文件是git将提交到git存储库的文件。

这是ProGit book中的一个不可避免的长而容易理解的解释:

作为参考,你可以阅读这本书的第7.7章,重置您

Git作为一个系统,在其正常操作中管理和操作三棵树:

  • 最后一次提交快照,下一个父快照
  • 建议下次提交快照
  • # EYZ0沙箱

HEAD是从指针当前分支引用,而当前分支引用又是指向该分支上的最后一次提交的指针。这意味着HEAD将是创建的下一个提交的父节点。通常最简单的方法是将HEAD看作上次在该分支上提交的快照

< p > # EYZ0
要查看快照的外观,在存储库的根目录中运行以下命令
                                 git ls-tree -r HEAD

结果是这样的:

                       $ git ls-tree -r HEAD
100644 blob a906cb2a4a904a152... README
100644 blob 8f94139338f9404f2... Rakefile
040000 tree 99f1a6d12cb4b6f19... lib

该指数

Git用最后签出到工作目录的所有文件内容的列表填充这个索引,以及它们最初签出时的样子。然后用它们的新版本替换其中一些文件,git commit将其转换到树中进行新的提交。

< p > # EYZ0
使用 git ls-files -s 查看它是什么样子的。您应该会看到如下内容:

                 100644 a906cb2a4a904a152e80877d4088654daad0c859 0 README
100644 8f94139338f9404f26296befa88755fc2598c289 0 Rakefile
100644 47c6340d6459e05787f644c2447d2595f5d3a54b 0 lib/simplegit.rb

工作目录

这是您的文件所在的位置,您可以在将更改提交到登台区域(索引)然后提交到历史记录之前尝试更改。

可视化的样本

< p > # EYZ0
Git的典型工作流程是通过操作这三棵树,连续记录项目处于更好状态的快照。看看这张照片:

enter image description here

为了更好地直观理解,请考虑以下场景。假设您进入一个新目录,其中只有一个文件。称这个文件为v1。它用蓝色表示。运行git init将创建一个带有HEAD引用的Git存储库,该引用指向未生成的主分支

enter image description here

此时,只有工作目录树有内容。 现在我们要提交这个文件,所以我们使用git add来获取工作目录中的内容并将其复制到索引中

enter image description here

然后我们运行git commit,它获取索引的内容并将其保存为永久快照,创建一个指向该快照的提交对象,并更新master以指向该提交。

enter image description here

如果我们运行git status,我们将看到没有变化,因为这三棵树都是一样的

很好的一点

Git状态以以下方式显示这些树之间的差异:

  • 如果工作树与索引不同,那么git status将显示有些更改没有提交
  • 如果工作树与索引相同,但它们与HEAD不同,那么git status将在其结果中显示要提交的更改节下的一些文件
  • 如果工作树不同于索引,索引也不同于HEAD,那么git status将在结果中显示未为提交而暂存的更改节下的一些文件和要提交的更改节下的一些其他文件。

对于更好奇的人

< p > # EYZ1
希望通过了解reset命令是如何工作的,可以进一步阐明这三棵树存在的原因

reset命令是你在git中的时间机器,它可以很容易地让你回到过去,并带来一些旧的快照供你使用。以这种方式,HEAD就是你可以穿越的虫洞。让我们用书中的一个例子来看看它是如何工作的:

考虑下面的存储库,它有一个文件和3次提交,它们以不同的颜色和不同的版本号显示:

enter image description here

树木的状态就像下面这张图:

enter image description here

1 .移动头部(软性):

重置的第一件事是移动HEAD所指向的对象。这与更改HEAD本身不同(签出就是这样做的)。reset移动HEAD所指向的分支。这意味着如果HEAD被设置为主分支,运行git reset 9e5e6a4将从将主控点设置为9e5e6a4开始。如果你用--soft选项调用reset,它将停止在这里,不改变indexworking directory。我们的repo现在看起来像这样:
# EYZ0 < / em >

enter image description here

再次查看该映像,我们可以看到该命令实际上撤消了上一次提交。由于工作树和索引与HEAD相同但不同,git status现在将以绿色显示准备提交的更改。

步骤2:更新索引(——mixed):

命令的默认选项

运行reset--mixed选项,使用当前HEAD所指向的快照内容更新索引,保持工作目录不变。这样做,您的存储库看起来就像您做了一些不分期的工作,git status将用红色显示为未分期提交的更改。此选项还将撤消上次提交并取消所有更改。这就像你做了更改,但还没有调用git add命令。我们的回购现在看起来是这样的:

enter image description here

步骤3:更新工作目录(——hard)

如果你使用--hard选项调用reset,它会将HEAD指向的快照内容复制到HEAD、索引和工作目录中。在执行reset——hard命令后,这意味着你回到了之前的时间点,在那之后根本没有做任何事情。请看下图:

enter image description here

结论<强> < / >强

我希望现在您对这些树有了更好的理解,并且对它们的强大功能有了很好的了解,它们允许您更改存储库中的文件,从而撤销或重做错误的操作。