乐趣区

关于git:深入浅出git三索引

暂存区

从 gi t 的角度来看, 文件的批改波及到以下三个区域: 工作目录, stage 区 (暂存区) 以及本地仓库.

当咱们对咱们的我的项目做了一些批改(新增文件, 删除文件, 批改文件等), 咱们解决的就是咱们的工作目录. 这个目录是存在于咱们电脑的文件系统上的. 所有的批改都会保留在工作目录直到咱们把它们退出到暂存区(通过 git add 命令)。

暂存区这是对下一次提交最好的示意形式, 当咱们执行 git commit,git 会获取暂存区中的批改, 并将这些批改作为下一次的提交内容. 暂存区的一个理论作用就是容许你调整你的提交, 你能够向暂存区新增和删除批改直到你对你下一次的提交称心, 这个时候你就能够用git commit 提交你的内容了。

在提交批改后, 它们就会进入 .git/objects 目录, 在其中被保留为 commit,blob 以及 tree objects,(参考数据模型那一篇文章)

把暂存区认为是一个存储批改的实在区域并不精确,git 没有专门的 stage 目录来寄存这些文件的批改(blobs),git 有一个名为 index 的文件来跟踪这三个区域的批改: 工作目录, 暂存区以及本地仓库。

当咱们增加批改到暂存区的时候,git 会更新 index 文件中的信息, 并且创立一个新的 blob object, 而后将它们放到与之前提交的记录所产生的其余 blob 雷同的.git/objects 目录中。

index 的变动

接下来咱们就通过一个失常的 git 流程来演示下 git 如何应用的 index

首先在咱们的仓库外面有 master 以及 feature 两个分支, 如果咱们执行上面的命令, 会有三件事件产生

git checkout feature

第一,git 会挪动 HEAD 指针来指向 feature 分支, 为了更加便于了解, 咱们只显示性能分支的最初一次提交

第二,git 将获取 feautre 分支指向的提交内容并将其增加到索引中

咱们留神到 index 是一个文件而不是目录, 所以 git 是没有往其中存储内容的,git 只是存储咱们仓库中每个文件的信息而已, 相似于下面这样

mtime : 上次更新工夫
file : 文件名称
wdir : 工作目录中文件版本
stage : index 中文件版本
repo : 仓库中的文件版本

文件版本以校验和来标识, 如果两个文件有雷同的校验和, 那么它们就有一样的内容以及版本.

最初,git 会将你的工作目录和 HEAD 指向的内容相匹配(它将应用树和 blob 对象从新创立我的项目目录的内容)

所以, 当你应用 checkout 的时候, 工作目录, 暂存区以及仓库都是雷同的版本
咱们来看看当咱们编辑 Main.java 的时候会产生什么?

当初仅仅只影响了咱们的工作目录, 然而咱们运行上面的命令的时候

git status

git 首先会更新 index 文件中 Main.java 的工作目录的版本

而后咱们看到 Main.java 在工作目录和暂存区有不同的版本

而后 git 会提醒咱们

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:   Main.java
no changes added to commit (use "git add" and/or "git commit -a")

这就表明工作目录的批改不在暂存区中(那么下一次的提交就不会蕴含 Main.java 的批改).

所以, 执行以下命令将 Main.java 退出到暂存区

git add Main.java

执行了下面这条命令, 就又会产生两件事儿, 第一,git 会为 Main.java 创立一个 blob object 而后存储在.git/objects 目录下, 第二, 会再次更新 index 文件

这个时候咱们再次执行命令

git status

git 会发现 Main.java 的暂存区的版本和工作目录版本统一, 然而和仓库的版本不统一

所以 git 就告知咱们

On branch feature
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
modified:   Main.java

证实 Main.java 曾经在暂存区, 然而还没有提交到仓库. 当初咱们就能够提交咱们的批改了

git commit -m "add some code to Main.java"

git 会做上面几件事儿:

1. 新增 commit object 和 tree object, 并把它们和执行 git add 时创立的 blob object 连接起来
2. 挪动 feature 的指针到新的 commit object
3. 更新 index

好啦, 当初咱们的 Main.java 在所有区域都有雷同的版本了.

无论执行 git add还是git commitindex 文件都会变更, 这也更好的证实了咱们上述模型, 当然 index 文件中的内容必定没有那么清晰, 它是一个二进制文件, 如果想要查看它的内容就须要借助其余工具来实现

下面就是对于 git index 的原理了, 当初回过头来看发现其实并不简单, 然而对于咱们了解在一些在 index 上操作的命令 (add,checkout,revert,commit,add…) 却是至关重要的

参考文章

https://www.youtube.com/watch?v=xbLVvrb2-fY

退出移动版