繁体   English   中英

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

[英]What's the difference between HEAD, working tree and index, in Git?

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

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


编辑

我发现了这个

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

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

关于这些主题的其他一些很好的参考资料:

工作流程

我使用索引作为检查点

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

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

注意事项:

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

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

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

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

3个州

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

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

提交

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

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

  • 它告诉 Git 在您结帐时从哪个提交中获取文件,以及
  • 它告诉 Git 在你提交时把新的提交放在哪里。

当您运行git checkout ref它会将HEAD指向您指定的 ref 并从中提取文件。 当您运行git commit它会创建一个新的提交对象,该对象成为当前HEAD的子对象。 通常HEAD指向其中一个头,所以一切正常。

结帐

HEAD (当前分支或当前分支上的最后提交状态)、索引(又名暂存区)和工作树(结帐中的文件状态)之间的区别在“1.3 Git 基础知识的“三种状态”部分中有所描述Scott Chacon(知识共享许可)的Pro Git书的章节。

这是本章中说明它的图像:

本地操作 - 工作目录与暂存区(索引)与 git 存储库(HEAD)

上图中“工作目录”与“工作树”相同,“暂存区”是git“index”的替代名称, HEAD指向当前签出的分支,其中tip指向“ git 目录(存储库)”

请注意, git commit -a将在一个步骤中进行更改和提交。

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

HEAD是指向您上次签出的分支或提交的指针,如果您创建它,它将成为新提交的父级。 例如,如果您在master分支上,那么HEAD将指向master ,当您提交时,新提交将是master指向的修订的后代,并且master将更新为指向新提交.

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

工作树

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

Git索引

  • git“索引”是您将要提交到 git 存储库的文件的位置。

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

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

  • 索引不是工作目录:您可以键入诸如git status类的命令,git 会告诉您工作目录中的哪些文件已添加到 git 索引中(例如,通过使用git add filename命令)。

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

这是ProGit 书中不可避免的冗长但易于理解的解释:

注意:作为参考,您可以阅读本书的第 7.7 章,重置揭秘

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

  • HEAD:上次提交快照,下一个父级
  • 索引:提议的下一次提交快照
  • 工作目录:沙盒

HEAD 是指向当前分支引用的指针,它又是指向该分支上最后一次提交的指针。 这意味着 HEAD 将是创建的下一个提交父级 将 HEAD 视为您在该分支上最后一次提交快照通常是最简单的。

它包含什么?
要查看该快照的样子,请在存储库的根目录中运行以下命令:

                                 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 将其转换为新提交的树。

它包含什么?
使用git ls-files -s查看它的样子。 您应该会看到如下内容:

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

工作目录

这是您的文件所在的位置,您可以在将它们提交到暂存区(索引)然后进入历史记录之前尝试更改。

可视化样本

让我们看看这三棵树是如何一起工作的(正如 ProGit 书中提到的那样)?
Git 的典型工作流程是通过操作这三棵树,以连续更好的状态记录项目的快照。 看看这张照片:

在此处输入图片说明

要获得良好的可视化理解,请考虑这种情况。 假设您进入一个包含单个文件的新目录。 调用此文件的 v1。 它以蓝色表示。 运行git init将创建一个带有指向未出生主分支的 HEAD 引用的 Git 存储库

在此处输入图片说明

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

在此处输入图片说明

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

在此处输入图片说明

如果我们运行git status ,我们将看不到任何变化,因为所有三棵树都是相同的

美丽的点

git status 以下列方式显示这些树之间的差异:

  • 如果工作树与索引不同,则git status将显示有一些未暂存以进行提交的更改
  • 如果工作树与索引相同,但与 HEAD 不同,则git status将在其结果中显示更改要提交部分下的一些文件
  • 如果工作树是从指数不同,指数是从头部不同,那么git status会显示一些文件下的变化不连续上演提交改变部分和其他一些文件在它的结果提交的部分。

对于更多的好奇

关于git reset命令的注意事项
希望了解reset命令的工作原理将进一步阐明这三棵树存在背后的原因。

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

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

在此处输入图片说明

树木的状态如下图所示:

在此处输入图片说明

第 1 步:移动头部(--soft):

reset 要做的第一件事是移动 HEAD 指向的内容。 这与更改 HEAD 本身不同(这是 checkout 所做的)。 reset 移动 HEAD 指向的分支。 这意味着如果 HEAD 设置为 master 分支,运行 git reset 9e5e6a4 将首先使 master 指向 9e5e6a4。 如果您使用--soft选项调用reset ,它将在此处停止,而不会更改indexworking directory 我们的回购现在看起来像这样:
注意:HEAD~是HEAD的父级

在此处输入图片说明

第二次查看图像,我们可以看到该命令基本上取消了最后一次提交。 由于工作树和索引相同但与 HEAD 不同,因此git status现在将以绿色显示准备提交的更改。

第 2 步:更新索引(--mixed):

这是命令的默认选项

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

在此处输入图片说明

第 3 步:更新工作目录 (--hard)

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

在此处输入图片说明

结论

我希望现在您对这些树有了更好的理解,并且对它们通过使您能够更改存储库中的文件以撤消或重做您错误地做的事情而给您带来的力量有一个很好的了解。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM