git术语解释staging,index,cache

当我在使用git的时候,有三个东西的出现,一度让我非常困扰,就如题所述,staging,index,和cache。

比如,当我阅读git官网提供的电子书《Pro Git》的时候,最初一章里,就提到,文件在git里面,有三种状态,working copy,staging area,和 in repository。而在读一些man pages的时候,比如git-reset命令,又会看到index,这非常让人困扰。而git-rm 指令又有一个参数叫 –cached,其作用是”unstage and remove paths only from the index”,更加奇怪了,同时提到了stage和index,而参数名竟然是cached!!!

这三者的来龙去脉到底怎么回事?搞清楚这些问题,对于喜欢刨根究底的我来说,极其重要。通过谷歌,我找到了一个叫Junio C Hamano的日本小哥,他是git的核心维护者之一,讲述了这三者的故事。本文主要内容从那个文章中解读出来,添加了一些自己的理解,不感冒的同学,请直接阅读原文。

读完原文后,我的基本感觉是,这些都是Linus大神当时的一念之差和命名的随意性搞出来的问题。

原来,Linus当年在维护Kernel的时候,使用了一种叫做“tarball and patches”的工作流模型(什么鬼?),具体原理没搞懂,我理解的意思,他要研究每个Kernel的patch对Kernel到底有什么影响。例如,他有一个2.6.12的tarball,还有 patch-1,patch-2 两个,所以,他至少要弄出来三个新版本,2.6.12-patch1,2.6.12-patch2,2.6.12-patch1&2。区区两个patch就搞出了3个新版本,如果patch多了不堪重负。

于是,他发明了一个“目录缓存(directory cache)”,其实就是现今git中的tree的概念,这个tree上的每个节点,都是一个Kernel的整个目录结构和文件(用一种高度压缩的形式表示的)。构建这个tree的方法,就是将内容添加到“缓存cache”,或者“更新缓存cache中的内容”。

用来存储这个树状结构的目录,叫“.dircache”(现在叫“.git”)。这个目录里,有个文件叫index,在git源码里(用C写的),操作这个index的各种变量名称,都有个前缀叫“cache”。这个index文件的作用,就是决定你要将什么文件,最终写入到那个树状结构里的,index就是暂存用的缓冲区。(可以看出来,这个树状结构,其根本作用就是维护海量的版本,其实就是git版本库本身了)(开发团队里的)每个人,都混用cache和index两个词,因为记录缓冲区(cache)内容的文件名,叫index。如果你给定文件路径,就能从index文件中找出来你要提交的内容(现在依旧如此)。

现在,越来越多的人,不需要通过阅读git的源码,就可以使用git了(因为有了文档和很多书籍,从应用层面介绍了很多的git知识,所以不需要从源码里找到所有秘密了:D)。所以,index这个名字变得越来越流行,因为这个文件会出现在.git目录里,而源代码里,cache开头的那些变量却不为人知。最终,我们(git开发团队)不再使用cache这个单词给小白用户(End User)解释问题了,但是当我们讨论git内部数据结构和git实现的时候,还是会用到cache这个词。

对于小白用户来说,现在 cache 这个词都以过去分词 cached 的形式出现,其词性是形容词了。表示要讨论的内容目前位于index文件中,而不是在工作目录(work tree)里面。(假如,我在工作目录里修改了一个文件,使用 git-add 命令,我修改的部分内容 —— 相当于一个patch —— 会在index里出现,但是在我的工作目录里,当然也还是有我修改的内容的,不过是叠加在版本库中的文件上的)。当然,我们也可以用 “indexed” 这个词,但是 “cached contents”,在英语里是个词组,早已存在,表达的就是这个意思,所以我们不需要再发明一个词来说明这个意思,就用了cached了(我了个去啊 >-<)。

有些git命令,会用到 –index 和 –cached 参数,有的命令,甚至两个都用,这很容易让人混淆,这里给出一对简单的规则来区分他们:

  • –cached,总是表示,作用于index文件中的内容,不会动工作目录
  • –index,通常表示作用于工作目录,而且也会关系到index文件

(这些命令的例子,我就不列举了,作为小白来说,十有八九竟然都用不到,感兴趣的去原文看)

在早期的时候,将“一个新文件添加到index里面”,和“更新一个index里面已经有的文件”,是两件不同的事情,但是,现在,已经统一起来了,都用 git-add 命令来操作。到这里,基本讲完了index的故事。因为index的添加和更新操作被统一起来了,所以,一些git的培训师,就将index这件事情,抽象成了一个叫做“下次提交的暂存区(staging area)”的东西,所以,将文件添加到index里面,也因此被叫做“to stage”,所以,stage这个词,是新近才出现在git的术语表里的,而且是个冗余的词。(T_T,我一开始读到的,就已经是stage了!!)

–staged 和 –cached,完全是同义词了,有些命令有 –staged 的参数,但是,没有刻意推广使用。搞清楚 –cached 和 –index 这两个参数的差别,是有意义的。而 –staged 仅仅是同义词而已,不用太过在意。

本来想尽量用自己的话来讲整个故事的,但是大部分还是翻译了,不知道为什么,读过这篇(原文)后,我对git的理解,感觉上了一个台阶,当然也可能是错觉了,不管怎么说,这些八卦和来龙去脉的历史,对我来说,真的很有趣,不知道读到这里的小伙伴,你怎么想呢?