有人可以在Git中告诉我HEAD,工作树和索引之间的区别吗?
据我所知,它们都是不同分支的名称。我的假设是否正确?
我发现了这个
单个git存储库可以跟踪任意数量的分支,但是您的工作树只与其中一个分支相关联(“当前”或“已检出”分支),HEAD指向该分支。
这是否意味着HEAD和工作树始终相同?
答案 0 :(得分:509)
关于这些主题的一些其他好的参考资料:
我将索引用作检查点。
当我即将做出可能出错的改变时 - 当我想探索一些方向时,我不确定我是否可以继续,或者是否这是一个好主意,例如概念要求的重构或更改表示类型 - 我检查我的工作到索引。 如果这是我自上次提交以来所做的第一次更改,那么我可以使用本地存储库作为检查点,但通常我有一个概念上的更改,我正在实现一组小步骤。我希望在每一步之后检查点,但保存提交,直到我回到工作,测试过的代码。
注意:
工作区是您查看和编辑的(源)文件的目录树。
索引是
<baseOfRepo>/.git/index
中的单个大型二进制文件,其中列出了当前分支中的所有文件,其 sha1 校验和,时间戳和文件名 - 它不是另一个包含文件副本的目录。- 醇>
本地存储库是一个隐藏目录(
.git
),其中包含一个objects
目录,其中包含repo中每个文件的所有版本(本地分支和副本)远程分支)作为压缩的“blob”文件。不要将上图中表示的四个“磁盘”视为回购文件的单独副本。
它们基本上是Git提交的命名参考。有两种主要类型的参考:标签和头部。
- 标记是标记历史记录中特定点的固定引用,例如v2.6.29。
- 相反,总是移动头来反映项目开发的当前位置。
(注意:commented为Timo Huovinen,这些箭头不是提交所指向的,它是工作流程订单,基本上显示为1 -> 2 -> 3 -> 4
的箭头其中1
是第一次提交而4
是最后一次提交
现在我们知道项目中发生了什么 但要知道这里发生了什么,现在有一个特殊的参考叫做HEAD。它有两个主要目的:
- 它告诉Git哪个提交从结账时提取文件,
- 它会告诉Git在提交时将新提交放在哪里。
当您运行
git checkout ref
时,它会将HEAD
指向您指定的引用,并从中提取文件。当您运行git commit
时,它会创建一个新的提交对象,该对象将成为当前HEAD
的子对象。通常HEAD
指向其中一个头部,所以一切正常。
答案 1 :(得分:117)
HEAD (当前分支上的当前分支或上次提交状态),索引(又称暂存区域)和工作树之间的区别(结帐时文件的状态)由Scott Chacon(知识共享许可)"The Three States" section of the "1.3 Git Basics一书的Pro Git一章中描述。
以下是本章的图片说明:
在上图中,“工作目录”与“工作树”相同,“暂存区”是git“index”的替代名称, HEAD 指向当前签出的分支,哪个提示指向“git目录(存储库)”
中的最后一次提交请注意,git commit -a
会分阶段进行更改和提交。
答案 2 :(得分:55)
工作树是您当前正在处理的文件中的实际内容。
HEAD
是指向您上次检出的分支或提交的指针,如果您创建它,它将是新提交的父级。例如,如果您在master
分支上,则HEAD
将指向master
,并且当您提交时,该新提交将成为{{1的修订版的后代指向,master
将更新为指向新提交。
索引是准备新提交的暂存区域。本质上,索引的内容将进入新的提交(尽管如果你做master
,这将在提交之前自动将所有更改添加到Git知道的文件中,因此它将提交当前工作树的内容)。 git commit -a
会将工作树中的文件添加或更新到索引中。
答案 3 :(得分:32)
您的工作树是您当前正在处理的文件。
git“index”是您要将文件放置到git存储库的位置。
索引也称为缓存,目录缓存,当前目录缓存,暂存区域,暂存文件。
在您将文件“提交”(签入)文件到git存储库之前,您需要先将文件放在git“index”中。
索引不工作目录:您可以键入git status
等命令,git会告诉您工作目录中的哪些文件已添加到工作目录中git index(例如,使用git add filename
命令)。
索引不是git存储库:git索引中的文件是git将使用git commit命令提交给git存储库的文件。
答案 4 :(得分:6)
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
这是文件所在的位置,可以在尝试将更改提交到暂存区(索引)然后提交到历史记录之前进行尝试。
让我们看看这三棵树(如ProGit所指的那样)如何协同工作?
Git的典型工作流程是,通过操纵这三棵树,以连续更好的状态记录项目的快照。看看这张照片:
要获得良好的可视化理解,请考虑这种情况。假设您进入的新目录中只有一个文件。将此文件称为v1。以蓝色显示。运行git init
将创建一个带有HEAD引用的Git存储库,该HEAD指向未出生的master分支
此时,只有工作目录树具有任何内容。
现在我们要提交此文件,因此我们使用git add
在工作目录中获取内容并将其复制到索引中。
然后我们运行git commit
,该操作将获取索引的内容并将其保存为永久快照,创建一个指向该快照的提交对象,并更新master以指向该提交。
如果我们运行git status
,我们会看到没有更改,因为所有三棵树都是相同的。
美丽的地方
git status通过以下方式显示这些树之间的差异:
git status
将显示有一些未提交的更改 git status
将在结果的要提交的更改部分中显示一些文件git status
将在未暂存为提交的更改部分中显示一些文件,而在<< 部分。 有关git reset
命令的注意事项
希望知道reset
命令的工作方式将进一步弄清这三棵树存在的原因。
reset
命令是您在git中使用的Time Machine,可以轻松地带您回到过去,并带一些旧快照供您处理。通过这种方式,HEAD是您可以及时穿越的虫洞。让我们用书中的一个例子来看看它是如何工作的:
考虑以下具有单个文件和3个提交的存储库,这些提交以不同的颜色和不同的版本号显示:
树木的状态就像下图:
重置将要做的第一件事是移动HEAD指向的位置。这与更改HEAD本身(签出操作)不同。 reset移动HEAD指向的分支。这意味着,如果将HEAD设置为master分支,则通过将master指向9e5e6a4开始运行git reset 9e5e6a4。如果使用reset
选项调用--soft
,它将在此处停止,而不会更改index
和working directory
。我们的仓库现在看起来像这样:
注意:HEAD〜是HEAD的父母
再次查看该图像,我们可以看到该命令实质上取消了最后一次提交。由于工作树和索引相同,但与HEAD不同,因此git status
将以绿色显示更改,准备提交。
这是命令的默认选项
使用reset
选项运行--mixed
,将使用HEAD当前指向的快照快照的内容更新索引,而工作目录保持不变。这样做,您的存储库将看起来像您完成了一些未暂存的工作,而git status
将显示未暂存的更改以红色提交。此选项还将撤消上一次提交,并撤消所有更改。就像您进行了更改,但尚未调用git add
命令一样。我们的仓库现在看起来像这样:
如果使用reset
选项调用--hard
,它将把HEAD指向的快照内容复制到HEAD,索引和工作目录中。执行reset --hard命令后,这意味着您回到了上一个时间点,之后根本什么也没做。参见下图:
我希望您现在对这些树有更好的了解,并希望它们使您能够更改存储库中的文件以撤消或重做您做错的事情,从而带给您强大的功能。