这就是我创建一个空文件 file_1.txt 并提交后 object 目录看起来的样子。请注意如果你的文件的哈希值是“89faaee…”,git 会把这个文件存在 “89” 目录下然后命名这个文件为 “faaee…”。
你会看到3个哈希。一个对应 file_1.txt ,另一个对应在提交时所创建的快照。那么第三个是什么呢?其实是因为 commit 本身也是一个对象并且也被压缩存放在 object 目录下。
现在,你需要记住的是一个 commit 包含四个部分:
工作目录快照的哈希
提交的说明信息
提交者的信息
父提交的哈希值
如果我们解压缩一个提交,你自己可以看看到底是什么:
// by looking at the history you can easily find your commit hash
// you also don't have to paste the whole hash, only enough
// characters to make the hash unique
gitcat-file-p 4cf44f1e3fe4fb7f8aa42138c324f63f5ac85828
这是我看到的
tree 86550c31847e518e1927f95991c949fc14efc711
author PierreDeWulf<test@gmail.com>1455775173-0500
committer PierreDeWulf<test@gmail.com>1455775173-0500
commit A
如你所见我们得到了所期望看到的的:快照的哈希,作者,提交信息。这里有两样东西很重要:
正如预料的一样,快照的哈希 “86550…” 也是一个对象并且能在object目录下找到。
因为这是我的第一个提交,所以没有父提交。
那我的快照里面到底是些什么呢?
gitcat-file-p 86550c31847e518e1927f95991c949fc14efc711
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file_1.txt
到这里我们看到的最后一个对象是我们先前提到的唯一会存在于快照中的对象。它是一个 blob(二进制文件),这里就不作深究了。
分支,标签,HEAD 都是一家人那么现在你知道 git 的每一个对象都有一个正确的哈希值。现在我们来看看 HEAD 吧!那么,在 HEAD 里又有什么呢?
cat HEAD
ref: refs/heads/master
这看起来 HEAD 不是一个hash,倒是容易理解,因为 HEAD 可以看作一个你目前所在分支的指针。如果我们看看 refs/heads/master,就会发现这些:
cat refs/heads/master
4cf44f1e3fe4fb7f8aa42138c324f63f5ac85828
是不是很熟悉?是的,这和我们第一个提交的哈希完全一样。由此表明分支和标签就是一个提交的指针。明白这一点你就可以删除所有你想删除的分支和标签,而他们指向的提交依然在那里。只是有点难以被访问到。如果你想对这部分了解更多,请参考git book。
尾声到目前为止你应该了解到, git 所做的事就是当你提交的时候“压缩”当前的工作目录,同时将其和其他一些信息一并存入 objects 目录。但是如果你足够了解 git 的话,你就能完全控制提交时哪些文件应该放进去而哪些不应该放。
我的意思是,一个提交并非真正意义上是一个你当前工作目录的快照,而是一个你想提交的文件的快照。在提交之前 git 把你想提交的文件放在哪里? git 把他们放在 index 文件里。我们现在不会去深入探究 index,同时如果你确实好奇你可以参考这里。
鸣谢