有人能告诉我Git中HEAD,工作树和索引的区别吗?
据我所知,它们都是不同分支的名称。我的假设正确吗?
我发现了这个:
单个git存储库可以跟踪任意数量的分支,但是您的工作树只与其中一个分支关联(“当前”或“检出”分支),并且HEAD指向该分支。
这是否意味着HEAD和工作树总是相同的?
有人能告诉我Git中HEAD,工作树和索引的区别吗?
据我所知,它们都是不同分支的名称。我的假设正确吗?
我发现了这个:
单个git存储库可以跟踪任意数量的分支,但是您的工作树只与其中一个分支关联(“当前”或“检出”分支),并且HEAD指向该分支。
这是否意味着HEAD和工作树总是相同的?
当前回答
这是ProGit书中一个不可避免的长而容易理解的解释:
注意:作为参考,您可以阅读本书的第7.7章,Reset Demystified
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,它获取索引的内容并将其保存为永久快照,创建一个指向该快照的commit对象,并更新master以指向该提交。
如果我们运行git status,我们不会看到任何变化,因为这三棵树都是一样的。
很好的一点
Git状态以以下方式显示这些树之间的差异:
If the Working Tree is different from index, then git status will show there are some changes not staged for commit If the Working Tree is the same as index, but they are different from HEAD, then git status will show some files under changes to be committed section in its result If the Working Tree is different from the index, and index is different from HEAD, then git status will show some files under changes not staged for commit section and some other files under changes to be committed section in its result.
对于更好奇的人
git reset命令注意事项 希望通过了解reset命令是如何工作的,可以进一步阐明这三棵树存在的原因。
reset命令是你的时间机器在git中,它可以很容易地带你回到过去,并带来一些旧的快照供你工作。以这种方式,HEAD就是你可以穿越的虫洞。让我们用书中的一个例子来看看它是如何工作的:
考虑下面的存储库,它有一个文件和3次提交,它们以不同的颜色和不同的版本号显示:
树木的状态就像下面这张图:
1 .移动头部(软性):
重置要做的第一件事就是移动HEAD所指向的对象。这与更改HEAD本身不同(签出就是这样做的)。reset移动HEAD所指向的分支。这意味着如果HEAD被设置为主分支,运行git reset 9e5e6a4将从将主控点设置为9e5e6a4开始。如果你用——软选项调用reset,它将在这里停止,不改变索引和工作目录。我们的回购现在看起来像这样: 注意:HEAD~是HEAD的父元素
再次查看该映像,我们可以看到该命令实际上撤消了上一次提交。由于工作树和索引与HEAD相同但不同,git状态现在将以绿色显示准备提交的更改。
步骤2:更新索引(——mixed):
这是该命令的默认选项
运行reset with——mixed选项将使用当前HEAD所指向的快照的内容更新索引,而工作目录保持不变。这样做,你的存储库看起来就像你做了一些不分期的工作,git状态将显示为红色的未分期提交的更改。此选项还将撤消上次提交并取消所有更改。这就像你做了更改,但还没有调用git add命令。我们的回购现在看起来是这样的:
步骤3:更新工作目录(——hard)
如果你使用——hard选项调用reset,它会将HEAD指向的快照内容复制到HEAD、索引和工作目录中。在执行reset——hard命令后,这意味着你回到了之前的时间点,在那之后根本没有做任何事情。请看下图:
结论
我希望现在您对这些树有了更好的理解,并且对它们的强大功能有了很好的了解,它们允许您更改存储库中的文件,从而撤销或重做错误的操作。
其他回答
工作树
您的工作树是您当前正在处理的文件。
围棋索引
The git "index" is where you place files you want commit to the git repository. The index is also known as cache, directory cache, current directory cache, staging area, staged files. Before you "commit" (checkin) files to the git repository, you need to first place the files in the git "index". The index is not the working directory: you can type a command such as git status, and git will tell you what files in your working directory have been added to the git index (for example, by using the git add filename command). The index is not the git repository: files in the git index are files that git would commit to the git repository if you used the git commit command.
关于这些主题还有一些很好的参考资料:
我的Git工作流
我使用索引作为检查点。
When I'm about to make a change that might go awry — when I want to explore some direction that I'm not sure if I can follow through on or even whether it's a good idea, such as a conceptually demanding refactoring or changing a representation type — I checkpoint my work into the index. If this is the first change I've made since my last commit, then I can use the local repository as a checkpoint, but often I've got one conceptual change that I'm implementing as a set of little steps. I want to checkpoint after each step, but save the commit until I've gotten back to working, tested code.
Notes: the workspace is the directory tree of (source) files that you see and edit. The index is a single, large, binary file in <baseOfRepo>/.git/index, which lists all files in the current branch, their sha1 checksums, time stamps and the file name -- it is not another directory with a copy of files in it. The local repository is a hidden directory (.git) including an objects directory containing all versions of every file in the repo (local branches and copies of remote branches) as a compressed "blob" file. Don't think of the four 'disks' represented in the image above as separate copies of the repo files.
为什么Git比X好
Git是你的朋友而不是敌人Vol. 3:参考和索引
它们基本上是Git提交的命名引用。有两种主要类型的裁判:标签和头部。 标记是标记历史上某个特定点的固定引用,例如v2.6.29。 相反,头部总是移动,以反映项目开发的当前位置。
(注意:正如Timo Huovinen所评论的那样,这些箭头并不是提交所指向的,而是工作流顺序,基本上箭头显示为1 -> 2 -> 3 -> 4,其中1是第一次提交,4是最后一次提交)
Now we know what is happening in the project. But to know what is happening right here, right now there is a special reference called HEAD. It serves two major purposes: it tells Git which commit to take files from when you checkout, and it tells Git where to put new commits when you commit. When you run git checkout ref it points HEAD to the ref you’ve designated and extracts files from it. When you run git commit it creates a new commit object, which becomes a child of current HEAD. Normally HEAD points to one of the heads, so everything works out just fine.
HEAD(当前分支或当前分支上的最后提交状态)、index(又名。Scott Chacon所著的Pro Git书的“1.3 Git基础知识”章节的“三种状态”部分描述了暂发区)和工作树(签出时文件的状态)。
下面是本章的图片:
上图中的“工作目录”与“工作树”相同,“staging区域”是git“索引”的替代名称,HEAD指向当前签出的分支,tip指向“git目录(存储库)”中的最后一次提交。
注意,git commit -a将在一个步骤中进行更改和提交。
您的工作树是您当前正在处理的文件中的实际内容。
HEAD是指向上次签出的分支或提交的指针,如果您进行了新提交,则它将是新提交的父节点。例如,如果你在master分支上,那么HEAD将指向master,当你提交时,新的提交将是master所指向的修订的后代,master将被更新为指向新的提交。
索引是准备新提交的暂存区。从本质上讲,索引的内容将被放入新的提交中(尽管如果您使用git commit -a,这将在提交前自动将git知道的所有文件更改添加到索引中,因此它将提交您的工作树的当前内容)。Git add会将工作树中的文件添加或更新到索引中。
这是ProGit书中一个不可避免的长而容易理解的解释:
注意:作为参考,您可以阅读本书的第7.7章,Reset Demystified
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,它获取索引的内容并将其保存为永久快照,创建一个指向该快照的commit对象,并更新master以指向该提交。
如果我们运行git status,我们不会看到任何变化,因为这三棵树都是一样的。
很好的一点
Git状态以以下方式显示这些树之间的差异:
If the Working Tree is different from index, then git status will show there are some changes not staged for commit If the Working Tree is the same as index, but they are different from HEAD, then git status will show some files under changes to be committed section in its result If the Working Tree is different from the index, and index is different from HEAD, then git status will show some files under changes not staged for commit section and some other files under changes to be committed section in its result.
对于更好奇的人
git reset命令注意事项 希望通过了解reset命令是如何工作的,可以进一步阐明这三棵树存在的原因。
reset命令是你的时间机器在git中,它可以很容易地带你回到过去,并带来一些旧的快照供你工作。以这种方式,HEAD就是你可以穿越的虫洞。让我们用书中的一个例子来看看它是如何工作的:
考虑下面的存储库,它有一个文件和3次提交,它们以不同的颜色和不同的版本号显示:
树木的状态就像下面这张图:
1 .移动头部(软性):
重置要做的第一件事就是移动HEAD所指向的对象。这与更改HEAD本身不同(签出就是这样做的)。reset移动HEAD所指向的分支。这意味着如果HEAD被设置为主分支,运行git reset 9e5e6a4将从将主控点设置为9e5e6a4开始。如果你用——软选项调用reset,它将在这里停止,不改变索引和工作目录。我们的回购现在看起来像这样: 注意:HEAD~是HEAD的父元素
再次查看该映像,我们可以看到该命令实际上撤消了上一次提交。由于工作树和索引与HEAD相同但不同,git状态现在将以绿色显示准备提交的更改。
步骤2:更新索引(——mixed):
这是该命令的默认选项
运行reset with——mixed选项将使用当前HEAD所指向的快照的内容更新索引,而工作目录保持不变。这样做,你的存储库看起来就像你做了一些不分期的工作,git状态将显示为红色的未分期提交的更改。此选项还将撤消上次提交并取消所有更改。这就像你做了更改,但还没有调用git add命令。我们的回购现在看起来是这样的:
步骤3:更新工作目录(——hard)
如果你使用——hard选项调用reset,它会将HEAD指向的快照内容复制到HEAD、索引和工作目录中。在执行reset——hard命令后,这意味着你回到了之前的时间点,在那之后根本没有做任何事情。请看下图:
结论
我希望现在您对这些树有了更好的理解,并且对它们的强大功能有了很好的了解,它们允许您更改存储库中的文件,从而撤销或重做错误的操作。