首先,要理解git底层原理必须知道git的三个对象:blob、tree以及commit,所有对象存储在.git\objects路径下
- blob对象,在add操作后生成,记录的是文件的内容,文件名为文件内容的hash值,需要注意的是如果文件内容一样只会有一个blob文件显示,如果文件没内容也不会生成blob对象。
- tree对象,在commit操作后生成,tree对象包含blob对象,如果文件时存储在文件夹中(既存在目录,一个目录是一个tree对象),那么还会包含子tree对象,与tree对象是无区别,在这个子tree对象中又会包含blob对象以及一些文件的元数据信息。
- commit对象,在commit操作后生成,commit对象包含tree对象、父commit对象、一些文件的元数据信息及commit message。
如图所示:
在这张图图中,git指针的概念就很清晰了,首先,当你commit之后,commit的指针就指向一个tree对象, tree对象存在文件的话,指针直接指向这个文件的blob对象,blob对象就指向了文件的内容,所以,add到暂存区跟commit到本地仓库的其实不是实体的文件,而是这三个对象。
关于分支的切换原理也就是指针指向的转换,在.git\refs\heads路径下,每个文件的名字就是分支的名字,文件的内容为commit_id,指向一个commit对象,git会自己维护这个HEAD指针,在git1\.git目录下的HEAD文件,里面的内容就为.git\refs\heads的分支文件路径,如图所示,只需将HEAD指针指向不同分支即可。
总的来说,git将文件的各种元数据信息(文件名、大小、内容。。。)转化为三个对象进行存储,通过指针的方式,控制分支的切换及各个区域的回退。 (tip:git是基于元数据操作的,而svn则是基于文件操作的)。