文章目录
  1. 1. 前言
  2. 2. 正文
    1. 2.1. 下面举例子来证明以上观点
    2. 2.2. 证明git diff结论
    3. 2.3. 证明git reset跟 git checkout结论
    4. 2.4. 证明git rm 结论
  3. 3. 总结

前言

暂存区(stage, index)Git最重要的概念之一,理解了这个概念很多 Git 命令就不再那么神秘了。下面几个验证例子一开始看不懂没关系,工作区、版本库中的暂存区和版本库之间的关系图先理解先。

正文

下面这个图展示了工作区、版本库中的暂存区和版本库之间的关系。

在这个图中,我们可以看到部分 Git命令是如何影响工作区和暂存区(stage, index)的。

  • 图中左侧为工作区,右侧为版本库。在版本库中标记为 index 的区域是暂存区(stage, index),标记为 master 的是 master 分支所代表的目录树。
  • 图中我们可以看出此时HEAD实际是指向master分支的一个“游标”。所以图示的命令中出现HEAD的地方可以用master来替换。
  • 图中的objects标识的区域为Git的对象库,实际位于.git/objects目录下,我们会在后面的章节重点介绍。
  • 当对工作区修改(或新增)的文件执行git add命令时,暂存区的目录树被更新,同时工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中,而该对象的ID 被记录在暂存区的文件索引中。
  • 当执行提交操作(git commit)时,暂存区的目录树写到版本库(对象库)中,master分支会做相应的更新。即master指向的目录树就是提交时暂存区的目录树。
  • 当执行 git reset HEAD 命令时,暂存区的目录树会被重写,被 master 分支指向的目录树所替换,但是工作区不受影响。
  • 当执行 git checkout . 或者 git checkout -- [file] 命令时,会用暂存区全部或指定的文件替换工作区的文件。这个操作很危险,会清除工作区中未添加到暂存区的改动。
  • 当执行 git checkout HEAD . 或者 git checkout HEAD [file] 命令时,会用 HEAD 指向的 master 分支中的全部或者部分文件替换暂存区和以及工作区中的文件。这个命令也是极具危险性的,因为不但会清除工作区中未提交的改动,也会清除暂存区中未提交的改 动。
  • 当执行 git rm --cached [file]命令时,会直接从暂存区删除文件,工作区则不做出改变。
  • 当执行 git rm file命令时,会同时删除暂存区和工作区的文件。
  • 当执行 rm file命令时,只会删除工作区的文件。

下面举例子来证明以上观点

假设:
工作区:a
暂存区(index):b
HEAD:C

git diff命令结论

1
2
3
git diff           比较a跟b
git diff --cached 比较b跟c
git diff HEAD 比较a跟c

git reset跟 git checkout结论

1
2
3
git reset HEAD              c覆盖b
git checkout -- <file> b覆盖a
git checkout HEAD <file> c覆盖a,b

git rm命令结论

1
2
3
git rm          删除a跟b
git rm --cached 只删除b
rm file 只删除a

证明git diff结论

例子,默认新建一个readme.txt,里面输入内容one然后add并且commit一次。

1:修改readme.txt,新增内容two,这时候a内容改变了,多了two,而b跟c内容不变,都只有one
执行git diff readme.txt查看效果

结论:如图看出,内容有修改, a跟b比较了


执行git diff --cached readme.txt查看效果

结论:如图看出,没有变化,因为b跟c内容一样。


执行git diff HEAD readme.txt查看效果

如图所示:内容有修改,a跟c比较了


2.这时候执行git add readme.txt,这时候a,b内容都多了two,而c内容不变,只有one
执行git diff readme.txt查看效果

结论:如图看出,没有变化, 因为a跟b内容一样。


执行git diff –cached readme.txt查看效果

结论:如图看出,内容有修改,b跟c比较了


执行git diff HEAD readme.txt查看效果

结论:如图看出,内容有修改,a跟c比较了

3.最后使用git commit提交一次,这时候a,b,c内容都一样,都包含two

结论,如图看出,没有变化,说明a,b,c内容一样


根据上面的实例再一次证明了如下观点:

1
2
3
git diff           比较工作区跟暂存区
git diff --cached 比较暂存区跟HEAD
git diff HEAD 比较工作区跟HEAD

证明git reset跟 git checkout结论

例子,默认新建一个readme.txt,里面输入内容one然后add并且commit一次,这时候a,b,c内容都是one


1.修改readme.txt,新增内容two,执行git add readme.txt操作,这时候a ,b内容都多了two,c还是只有one.
执行git reset HEAD -- readme.txt命令后,c覆盖b,这时候b内容也变成只有one了,使用git diff readme.txt命令可以看到,有内容修改,a跟b内容不一样。


2.此时a内容有two,b和c都只有one,执行git checkout -- readme.txt后,b覆盖a,此时a,b,c都是one。执行git diff readme.txt命令可以看到,没有改变。


3.此时a,b,c都只有one,修改一下,添加内容two,执行git add readme.txtgit commit -m "two".再修改一次readme.txt,添加内容three,然后会执行git add readme.txt,此时a跟b都包含three,而c只包含one跟two。执行git checkout HEAD readme.txt后,c覆盖a和b,a,b里面内容都只有one跟two。分别使用命令git diff --cachedgit diff HEAD来查看b跟c,a跟c的比对,发现都一样。


根据上面的实例再一次证明了如下观点:

1
2
3
git reset HEAD              HEAD覆盖暂存区
git checkout -- <file> 暂存区覆盖工作区
git checkout HEAD <file> HEAD覆盖暂存区和工作区


证明git rm 结论

默认新建一个readme.txt,里面输入内容one,然后使用git add readme.txt命令。
1.执行git rm readme.txt命令,发现文件被删除了。

2.再新建一个一个readme.txt,里面输入内容 one,然后使用git add readme.txt命令。执行git rm --cached readme.txt命令,发现文件内readme.txt还在,然后执行git status命令,发现是Untracked状态,也就是未add,这就说明暂存区被删除了。


根据上面的实例再一次证明了如下观点:

1
2
3
git rm file      会将文件从缓存区和你的硬盘中(工作区)删除
git rm --cached 只删除暂存区,不删除工作区
rm file 只删除工作区

总结

暂存区的原理需要大家重复的加深了解,基础打牢了后面学起来就轻松很多,上面几个例子都自己验证一遍,加深印象。


最近撸了个java的公众号,学习资源超级多,视频,电子书,最新开发工具一个都不能少,已全部分享到百度云盘,求资源共享,打造一个学习方便,工作方便的java公众号,开源开源,有需求的可以关注~撒花

文章目录
  1. 1. 前言
  2. 2. 正文
    1. 2.1. 下面举例子来证明以上观点
    2. 2.2. 证明git diff结论
    3. 2.3. 证明git reset跟 git checkout结论
    4. 2.4. 证明git rm 结论
  3. 3. 总结