有人能告诉我Git中HEAD、工作区和索引之间的区别吗?
据我所知,它们都是不同分支的名称。我的假设正确吗?
我找到了这个:
单个git存储库可以跟踪任意数量的分支,但您的工作树仅与其中一个相关联(“当前”或“签出”的分支),而HEAD指向该分支。
这是否意味着HEAD和工作区始终相同?
有人能告诉我Git中HEAD、工作区和索引之间的区别吗?
据我所知,它们都是不同分支的名称。我的假设正确吗?
我找到了这个:
单个git存储库可以跟踪任意数量的分支,但您的工作树仅与其中一个相关联(“当前”或“签出”的分支),而HEAD指向该分支。
这是否意味着HEAD和工作区始终相同?
以下是关于这些主题的其他好参考资料:
我将索引用作“检查点”。<baseOfRepo>/.git/index
中,列出了当前分支中的所有文件、它们的sha1校验和、时间戳和文件名——它不是另一个带有文件副本的目录。.git
),包括一个objects
目录,其中包含存储为压缩的“blob”文件的仓库中每个文件的所有版本(本地分支和远程分支的副本)。它们基本上是Git提交的命名引用。有两种主要类型的引用:标记和头。
- 标记是固定的引用,标记历史上的特定点,例如v2.6.29。
- 相反,头总是移动以反映项目开发的当前位置。
(注意:正如评论者 Timo Huovinen所指出的,这些箭头不是提交指向的内容,而是工作流顺序,基本上显示为箭头1 -> 2 -> 3 -> 4
,其中1
是第一个提交,4
是最后一个。)
git checkout ref
时,它会将HEAD
指向您指定的引用并从中提取文件。当您运行git commit
时,它会创建一个新的提交对象,该对象成为当前HEAD
的子级。通常,HEAD
指向其中一个分支,所以一切都很顺利。
rebase
应该在git pull --rebase
的上下文中理解:即从远程仓库进行fetch
操作,然后在远程跟踪分支的基础上进行rebase
操作。 - VonCgit commit -a
将在一步中暂存更改并提交。工作树是您当前工作的实际文件内容。
HEAD
是指向您上次检出的分支或提交的指针,如果您进行新提交,它将成为新提交的父提交。例如,如果您在master
分支上,则HEAD
将指向master
,并且当您提交时,新提交将是指向的修订版的后代,并且master
将更新为指向新提交。
索引是准备新提交的暂存区域。本质上,索引中的内容是将进入新提交的内容(尽管如果您执行git commit -a
,这会自动将Git知道的所有更改添加到索引中,以在提交之前提交当前工作树的内容)。git add
将从工作树中添加或更新文件到您的索引中。
git commit -a
提交(需要用 git add
添加),因此你的工作树可能有额外的文件,而你的索引、本地仓库或远程仓库没有。 - Brian CampbellHEAD
指的是最近的提交,因此当您提交时,您将HEAD
更新为新的提交,它与索引匹配。推送与此无关 - 它使远程的分支与本地存储库中的分支匹配。 - Cascabel你正在处理的文件就是你的工作树。
Git的"索引"是你要提交到git仓库中的文件存放的地方。
这个索引也被称为缓存,目录缓存,当前目录缓存,暂存区,已暂存文件。
在你将文件"提交"(checkin)到git仓库之前,首先需要将文件放在git的"索引"中。
索引不是工作目录: 你可以输入命令,例如git status
,git会告诉你哪些文件被添加到了git索引中(例如通过使用git add filename
命令)。
索引不是git仓库: git索引中的文件是git如果使用git commit命令提交到git仓库的文件。
reset --hard HEAD
确保你的索引与工作树相同。然后:
mkdir history && git checkout-index --prefix history/ -a
结果是在你的“history/”目录中复制了你整个的工作树。
因此,git索引 >= git工作目录。 - Adam Kurkiewiczgit reset --HARD
和git checkout-index
步骤之前或之后先运行echo untracked-data > untracked-file
,那么证明将会失败。你会发现未跟踪的文件不在history
目录中。你也可以独立修改索引和工作树,但是要想在不改变工作树的情况下修改索引是困难的(需要使用git update-index --index-info
)。 - torekGit作为一个系统,在正常操作中管理和操作三棵树:
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 ls-files -s
命令查看它的内容。你应该看到类似于以下内容:
100644 a906cb2a4a904a152e80877d4088654daad0c859 0 README
100644 8f94139338f9404f26296befa88755fc2598c289 0 Rakefile
100644 47c6340d6459e05787f644c2447d2595f5d3a54b 0 lib/simplegit.rb
这是您的文件所在的位置,在将其提交到暂存区(索引)然后进入历史记录之前,您可以在此处尝试更改。
让我们看看这三个树(正如ProGit书籍所称)如何共同工作?
Git的典型工作流程是通过操作这三个树来记录项目的连续快照,以获得不断改进的状态。请看这张图片:
git init
将创建一个Git存储库,并创建一个指向未出生的主分支的HEAD引用。{{请注意保留原文中的代码格式和标签}}
此时,只有工作目录树才有任何内容。
现在我们想要提交这个文件,因此我们使用git add
将工作目录中的内容复制到索引中。
git commit
,它会将索引的内容保存为永久快照,并创建一个指向该快照的提交对象,然后更新主分支以指向该提交。
如果我们运行git status
,我们会看到没有任何更改,因为所有三个树是相同的。
精华
git status以以下方式显示这些树之间的差异:git status
将显示有一些未提交的更改
- 如果工作树与索引相同,但它们与HEAD不同,则git status
将在其结果中显示一些文件在要提交的更改部分下
- 如果工作树与索引不同,并且索引与HEAD不同,则git status
将在其结果中显示一些文件在未提交的更改部分下,并在要提交的更改部分下显示其他一些文件。git reset
命令的注意事项reset
命令的工作原理将进一步解释存在这三个树背后的原因。
reset
命令是你在git中的时间机器,可以轻松地带您回到过去并为您带来一些旧的快照供您使用。以这种方式,HEAD是你可以通过它穿越时间的虫洞。让我们看一个来自书籍的例子来了解它的工作原理:树的状态如下图所示:
reset命令的第一件事是移动HEAD指向的位置。这并不等同于改变HEAD本身(这是checkout所做的)。reset移动HEAD指向的分支。这意味着如果HEAD设置为主分支,运行git reset 9e5e6a4将使主分支指向9e5e6a4。如果使用--soft
选项调用reset
,则会在此处停止,而不更改索引
和工作目录
。现在我们的repo看起来像这样:
注意:HEAD~是HEAD的父级
如果您使用 reset
命令并带上 --hard
选项,它将把 HEAD 所指向的快照内容复制到 HEAD、索引和工作目录中。执行 reset --hard 命令后,就好像您回到了过去的某个时间点,并且在那之后没有做过任何事情。请参见下图:
我希望现在你对这些“树”有了更好的理解,并且对于它们通过允许您更改存储库中的文件以撤消或重做您错误执行的操作所带来的强大功能有了一个很好的想法。
HEAD
是当前分支末端的提交记录。如果你刚刚检出了该分支,即没有修改过任何文件,则HEAD
的内容与工作树一致。一旦你修改了任何内容,它就不再匹配。 - Cascabel