0%

Git理解-索引

这是我理解Git系列中的第三篇文章,因此在继续之前,请先先阅读一下前两个(数据模型分支)。

Snipaste_2020-05-30_14-54-09.png

从git的角度来看,可以在三个区域进行文件更改:工作目录,暂存区和存储库。

Snipaste_2020-05-30_14-56-36.png

当你在项目中进行修改时,你要处理的是项目的工作目录。这是在你的计算机文件系统中的项目目录。你所做的所有修改都将保留在工作目录中,直到你把它们添加到暂存区(通过git add命令)。暂存区最好被描述为下一次提交的预览区。意思是,当你做一个git提交时,git会把暂存区中的改动拿出来,然后从这些改动中做出新的提交。暂存区的一个实际用途是,它允许你对提交进行微调。你可以从暂存区添加和删除修改,直到你对下一次提交的样子感到满意,这时你可以进行git提交。提交后,你的修改会被保存到 .git/objects 目录中,在那里它们会被保存为 commit、blob 和 tree 对象(就像我们在看 git 的数据模型时看到的那样)。

尽管通常把暂存区看成是git存储修改的真实区域(或目录),但这并不完全正确。Git 没有专门的暂存目录,它没有一个专门的暂存目录,在这个目录中放置一些代表文件修改的对象(blob)。相反,git 有一个叫做索引的文件,用来跟踪工作目录、暂存区和仓库这三个区域的文件变化。当你在暂存区添加变化时,git会更新索引中的变化信息,并创建新的blob对象,但会把它们和其他所有属于之前提交的blob放在同一个.git/objects目录下。这可能听起来有点复杂,但实际上并不复杂,所以让我们通过一个典型的git工作流例子来展示git是如何使用索引的。

假设我们在master分支上,并且存储库中还有一个feature分支。如果我们这样做:

1
git checkout feature

三件事将会发生。

首先,git将移动head指针指向 feature ref(分支)。为了使事情更简单,我们将只显示feature分支上的最后一次提交。

Snipaste_2020-05-30_15-03-09.png

接下来,git会把该功能所指向的提交内容添加到索引中。

Snipaste_2020-05-30_15-04-19.png

正如我们前面提到的index不是一个目录,而是一个文件,所以git实际上并没有将对象(blob)存储到其中。相反,git是在存储我们仓库中的每个文件的信息。

  • mtime - 是上次更新的时间
  • file - 文件名
  • wdir - 工作区的文件版本
  • stage - 索引区的文件版本
  • repo - 存储区的文件版本

文件版本用校验和标记(如果两个文件有相同的校验和,那么它们的内容/版本是相同的)。

最后,git将使你的工作目录与head所指向的提交内容相匹配(它将使用树形和blob对象重新创建你的项目目录的内容)。

Snipaste_2020-05-30_15-10-45.png

因此,签出后,每个文件在工作目录,暂存区/索引和存储库中将具有相同的版本。
如果我们现在编辑index.php文件。

Snipaste_2020-05-30_15-12-10.png

这些更改将仅影响我们的工作目录。但是如果我们现在运行:

1
git status

git将首先用新的工作目录版本更新index.php的索引。

Snipaste_2020-05-30_15-15-23.png

然后会发现index.php在工作目录和暂存目录下有不同的版本。

Snipaste_2020-05-30_15-17-37.png

所以,git会告诉我们:

1
2
3
4
5
6
On branch feature
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: index.php
no changes added to commit (use "git add" and/or "git commit -a")

我们的工作目录中的更改不在暂存区域中(因此,此时将不包括在我们的下一次提交中)。

因此,通过执行以下操作,将我们的index.php文件添加到暂存区域。

1
git add index.php

将会发生两件事。首先,git将为我们的index.php文件创建一个blob对象,并将其存储到.git/objects目录下,其次,它将再次更新索引。

Snipaste_2020-05-30_15-21-23.png

如果我们现在执行:

1
git status

git会看到暂存区中的index.php版本与工作目录版本匹配,但与存储库版本不匹配。

Snipaste_2020-05-30_15-23-13.png

因此git会告诉我们:

1
2
3
4
On branch feature
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: index.php

现在已经将index.php提交了。

现在,当我们提交更改时:

1
git commit -m "Adding some code magic to index.php"

git会:

  • 创建一个新的提交对象和目录对象(并将它们与已经用git add创建的blob对象挂钩)
  • 移动feature ref指针到新的提交
  • 更新索引

Snipaste_2020-05-30_15-27-26.png

现在,我们的index.php文件再次在所有git区域中包含相同的版本。

就是它了–神秘的git索引。现在我们看了它,它并没有那么复杂,但为了理解索引上的操作命令(add、checkout、reset……….),了解它是至关重要的。

^_^