这次重点讲解索引文件(index file)的作用。
我们在提交工作时,使用最多的命令就是 git commit -a 了,但是这个将提交你所做的所有工作。其实,如果你了解 commit 的工作机制,你会知道我们可以自定义提交哪些部分到哪些工作树中,其实自由度很大的。
一、diff 到底在和谁对比
还记得之前我们建立的 test-project 工作目录么。我们继续在这个目录下演示讲解。
[rocrocket@wupengchong test-project]$ echo “hello world,again”>>file.txt
这次,我们不急着执行 commit 命令,而是先用 git diff 看看差别情况:
[rocrocket@wupengchong test-project]$ git diff
diff –git a/file.txt b/file.txt
index 60be00d..a559610 100644
— a/file.txt
+++ b/file.txt
@@ -1 +1,2 @@
Hi,rocrocket!
+hello world,again
好了,我们可以看到 git 报告了我们刚才所做的修改。下面我们来 add 一下,然后再 git diff,看看 diff 有什么变化呢:
[rocrocket@wupengchong test-project]$ git add file.txt
[rocrocket@wupengchong test-project]$ git diff
[rocrocket@wupengchong test-project]$
大家可以看到在 add 之后的 git diff 的输出竟然为空了,但是此时我们尚未执行 commit 啊。如果这个时候你执行 git diff HEAD,你仍然会看到修改报告:
[rocrocket@wupengchong test-project]$ git diff HEAD
diff –git a/file.txt b/file.txt
index 60be00d..a559610 100644
— a/file.txt
+++ b/file.txt
@@ -1 +1,2 @@
Hi,rocrocket!
+hello world,again
这就说明了一个问题:git diff 不是在和 HEAD 比,而是另外一个“神秘”内容在比,而这个“神秘”内容就是“索引文件”!
二、索引文件
索引文件(index file)就是 .git/index 文件,它是二进制形式的文件。我们可以用 ls-files 来检查它的内容。
[rocrocket@wupengchong test-project]$ git ls-files –stage //一定要记住,此命令是用于查看index file的!!
100644 a55961026a22bdd4e938dcc90a4a83823a81f776 0 file.txt
[rocrocket@wupengchong test-project]$ git cat-file -t a5596
blob
[rocrocket@wupengchong test-project]$ git cat-file blob a5596
Hi,rocrocket!
hello world,again
很明显,我们可以看到其内容已经是改进后的代码了,怪不得 git-diff 会输出空呢!
我们的结论就是 git add 的作用就是创建一个 blob 文件来记录最新的修改代码,并且在 index file 里添加一个到此 blob 的链接。
如果在 git-diff 后面加上参数 HEAD,则 git-diff 会显示当前工作目录和最近一次提交之间的代码区别。
[rocrocket@wupengchong test-project]$ echo ‘again?’>>file.txt
[rocrocket@wupengchong test-project]$ git diff HEAD
diff –git a/file.txt b/file.txt
index 60be00d..dfb67dc 100644
— a/file.txt
+++ b/file.txt
@@ -1 +1,3 @@
Hi,rocrocket!
+hello world,again
+again?
如果使用参数 –cached,则会比较 index file 和最近一次提交之间的代码区别。
[rocrocket@wupengchong test-project]$ git diff –cached
diff –git a/file.txt b/file.txt
index 60be00d..a559610 100644
— a/file.txt
+++ b/file.txt
@@ -1 +1,2 @@
Hi,rocrocket!
+hello world,again
三、小结
按我的认识,更清楚且通俗的解释就是:git 维护的代码分成三部分,“当前工作目录”<------>“index file”<------>“git仓库”。
- git add 会将“当前工作目录”的改变写到“index file”。
- git commit 会将 index file 中的改变写到 git 仓库。
- “commit -a”则会直接将“当前工作目录”的改动同时写到“index file”和“git仓库”。
- git diff 总会拿 git 仓库来作为比较对象之一。如果 git diff 的参数是 HEAD,则另一个比较对象就确定为“当前工作目录”;如果参数是 –cached,则另一个比较对象就被确定为“index file”。
- 由此可见,commit(不加-a选项)的作用是使用 index 来建立 commit,而和当前目录无关。
- git diff:是查看 working tree 与 index file 的差别的。
- git diff --cached:是查看 index file 与 commit 的差别的。
- git diff HEAD:是查看 working tree 和 commit 的差别的,在这里 HEAD 代表的是最近的一次commit的信息。
四、其他
status 命令会显示当前状态的一个简单总结:
[rocrocket@wupengchong test-project]$ git status
# On branch master
# Changes to be committed:
# (use “git reset HEAD <file>…” to unstage)
#
# modified: file.txt
#
# Changed but not updated:
# (use “git add <file>…” to update what will be committed)
#
# modified: file.txt
#
上面两行黑体字中的 Changes to be committed 表示在 index 和 commit 的区别状况。而 Changed but not updated 表示当前目录和 index 的区别状况。
(SAW:Game Over!)