有人能告诉我Git中HEAD,工作树和索引的区别吗?
据我所知,它们都是不同分支的名称。我的假设正确吗?
我发现了这个:
单个git存储库可以跟踪任意数量的分支,但是您的工作树只与其中一个分支相关联(“当前”;或者“已结帐”;分支),HEAD指向该分支。
这是否意味着HEAD和工作树总是相同的?
工作树实际上是您当前正在处理的文件中的内容。
HEAD是一个指向上次签出的分支或提交的指针,如果你进行了新的提交,它将是新提交的父节点。例如,如果您在master分支上,那么HEAD将指向master,当您提交时,新提交将是master所指向的修订的后代,而master将被更新为指向新的提交。
HEAD
master
指数是准备新提交的暂存区。本质上,索引的内容就是新提交的内容(尽管如果执行git commit -a,这将在提交之前自动将Git知道的文件的所有更改添加到索引中,因此它将提交工作树的当前内容)。git add将从工作树中添加或更新文件到索引中。
git commit -a
git add
头(当前分支或当前分支上的最后提交状态),指数 (aka。)和工作树(签出中文件的状态)在Scott Chacon的箴Git书的“1.3 Git基础知识”中的“三个状态”部分”章节中描述(创作共用许可)。
下面是本章的图片:
< / >
上图中的“工作目录”与“工作树”相同,“staging区域”是git“索引”的替代名称,头指向当前签出的分支,提示指向“git目录(存储库)”中的最后一次提交。
注意,git commit -a将在一个步骤中进行更改和提交。
关于这些主题还有一些很好的参考资料:
我使用索引作为检查点。
当我要做一个可能会出错的更改时——当我想探索一些我不确定是否能坚持下去的方向,甚至不确定它是否是一个好主意时,例如在概念上要求重构或更改表示类型时——我会将我的工作检查点到索引中。 如果这是我自上次提交以来所做的第一个更改,那么我可以使用本地存储库作为检查点,但通常我只有一个概念性更改,我将其作为一组小步骤来实现。 我想在每一步之后检查,但保存提交,直到我重新开始工作,测试代码
当我要做一个可能会出错的更改时——当我想探索一些我不确定是否能坚持下去的方向,甚至不确定它是否是一个好主意时,例如在概念上要求重构或更改表示类型时——我会将我的工作检查点到索引中。
注: 工作空间是你看到和编辑的(源)文件的目录树。 指数是<baseOfRepo>/.git/index中的一个大型二进制文件,它列出了当前分支中的所有文件、它们的sha1校验和、时间戳和文件名——它不是另一个包含文件副本的目录。 本地存储库是一个隐藏目录(.git),包括一个objects目录,其中包含repo中每个文件的所有版本(本地分支和远程分支的副本),作为一个压缩的"blob"文件。 不要将上图中表示的四个“磁盘”视为回购文件的单独副本。
注:
<baseOfRepo>/.git/index
.git
objects
不要将上图中表示的四个“磁盘”视为回购文件的单独副本。
它们基本上是Git提交的命名引用。有两种主要类型的裁判:标签和头部。 标记是标记历史上某个特定点的固定引用,例如v2.6.29。 相反,头部总是移动,以反映项目开发的当前位置。
它们基本上是Git提交的命名引用。有两种主要类型的裁判:标签和头部。
(注意:由于评论由Timo Huovinen,这些箭头不是提交指向的,它是工作流程顺序,基本上显示箭头为1 -> 2 -> 3 -> 4,其中1是第一次提交,4是最后一次提交)
1 -> 2 -> 3 -> 4
1
4
现在我们知道项目中发生了什么。 但是要知道这里发生了什么,现在有一个特殊的参考,叫做HEAD。它有两个主要目的: 它告诉Git在签出时要从哪个提交中获取文件 当你提交时,它会告诉Git在哪里放置新的提交。 当您运行git checkout ref时,它将HEAD指向您指定的ref,并从中提取文件。当您运行git commit时,它创建了一个新的提交对象,该对象成为当前HEAD的子对象。正常情况下,HEAD指向其中一个正面,所以一切都很顺利。
当您运行git checkout ref时,它将HEAD指向您指定的ref,并从中提取文件。当您运行git commit时,它创建了一个新的提交对象,该对象成为当前HEAD的子对象。正常情况下,HEAD指向其中一个正面,所以一切都很顺利。
git checkout ref
git commit
您的工作树是您当前正在处理的文件。
git“索引”是存放要提交到git存储库的文件的地方。
索引也称为缓存, 目录缓存, 当前目录缓存, 暂存区, 暂存文件。
在你“提交”(签入)文件到git存储库之前,你需要首先将文件放在git“索引”中。
索引是不是工作目录:你可以输入一个命令,比如git status, git会告诉你工作目录中的哪些文件被添加到git索引中(例如,通过使用git add filename命令)。
git status
git add filename
索引不是git存储库:如果你使用git commit命令,git索引中的文件是git将提交到git存储库的文件。
Git作为一个系统,在其正常操作中管理和操作三棵树:
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
这是您的文件所在的位置,您可以在将更改提交到登台区域(索引)然后提交到历史记录之前尝试更改。
为了更好地直观理解,请考虑以下场景。假设您进入一个新目录,其中只有一个文件。称这个文件为v1。它用蓝色表示。运行git init将创建一个带有HEAD引用的Git存储库,该引用指向未生成的主分支
git init
此时,只有工作目录树有内容。 现在我们要提交这个文件,所以我们使用git add来获取工作目录中的内容并将其复制到索引中
然后我们运行git commit,它获取索引的内容并将其保存为永久快照,创建一个指向该快照的提交对象,并更新master以指向该提交。
如果我们运行git status,我们将看到没有变化,因为这三棵树都是一样的。
很好的一点
Git状态以以下方式显示这些树之间的差异:
reset
reset命令是你在git中的时间机器,它可以很容易地让你回到过去,并带来一些旧的快照供你使用。以这种方式,HEAD就是你可以穿越的虫洞。让我们用书中的一个例子来看看它是如何工作的:
考虑下面的存储库,它有一个文件和3次提交,它们以不同的颜色和不同的版本号显示:
树木的状态就像下面这张图:
--soft
index
working directory
再次查看该映像,我们可以看到该命令实际上撤消了上一次提交。由于工作树和索引与HEAD相同但不同,git status现在将以绿色显示准备提交的更改。
命令的默认选项
运行reset和--mixed选项,使用当前HEAD所指向的快照内容更新索引,保持工作目录不变。这样做,您的存储库看起来就像您做了一些不分期的工作,git status将用红色显示为未分期提交的更改。此选项还将撤消上次提交并取消所有更改。这就像你做了更改,但还没有调用git add命令。我们的回购现在看起来是这样的:
--mixed
如果你使用--hard选项调用reset,它会将HEAD指向的快照内容复制到HEAD、索引和工作目录中。在执行reset——hard命令后,这意味着你回到了之前的时间点,在那之后根本没有做任何事情。请看下图:
--hard
我希望现在您对这些树有了更好的理解,并且对它们的强大功能有了很好的了解,它们允许您更改存储库中的文件,从而撤销或重做错误的操作。