前言
- 这篇文章也是参考了“Git内部存储原理”这篇文章,大概理解了后,当记流水账,加深自己的影响,如有错误,敬请指出。
- 个人观点,叙述一件事或者完成一件工作,应当先在整体框架下,尽可能先完成基础模块,然后由基础模块加上业务逻辑最终形成应用,由一个或者多个应用解决实际面临的问题。这篇文章我也会先按模块再应用的方式叙述。
基本对象
- 之前不理解git的内部原理,只是觉得好用,在看论文网上写的文章后,觉得其实git作者在解决问题的时候一直很直接,用分而治之儿不是囫囵吞枣的方式很好的解决了项目迭代的问题,这种思想值得自己好好学习学习。
- 这里不延伸去讨论具体的实现,只讨论ta的逻辑功能和解决什么问题。
blob对象
在git中,文件会被压缩保存,所有的文件最后都会被单独的作为一个blob
对象,都有一段唯一hash码与之对应,blob
对象主要是解决单个文件的变动记录。
例如:在git文件夹下存在两个文件|
Makefile
和README
,那么git
在处理的时候就会创建一个blob
对象用于记录。
./git
|-----Makefile
|-----README
100644 blob 8cc95f278445722c59d08bbd798fbaf60da8ca14 Makefile
100644 blob 065bcad11008c5e958ff743f2445551e05561f59 README
tree对象
tree对象,顾名思义,就是记录各个路径间的包含关系,还是借用上面的例子,在git
文件夹下加入文件夹src
,并在里面创建文件file1.txt
。
./git
|-----Makefile
|-----README
|-----src
|-----file1.txt
100644 blob 8cc95f278445722c59d08bbd798fbaf60da8ca14 Makefile
100644 blob 065bcad11008c5e958ff743f2445551e05561f59 README
040000 tree 9aeacd1fa832ca167b0f72fb1d0c744a9ee1902f src
100644 blob 79ee69e841a5fd382faef2be2f2eb6e836cc980a file1.txt
其实看到这里所谓的blob对象和tree对象其实和文件系统在组织文件是一个道理,只是换了一种表现形式罢了。
commit对象
终于到最重要的对象了commit
,commit
应该是应用操作的最小逻辑单元了,我是这样理解的,不知道对不对,当完成一轮的修改后,我们在提交了后,git
就会产生一个commit
【快照
】,这个快照
记录了当前所有路径及其下面的文件的状态;
HEAD---> refs/heads/master--> ccc6e(commit)
+
|
v
082b6(tree)
+
|
+-----------------+-----------------+
| | |
v v v
065bc(blob) 8cc95(blob) 9aeac(tree)
README Makefile src
+
|
v
79ee6(blob)
file1.txt
所以这三张图片其实就能很好的解释Git是如何记录和管理文件的了。
- 首先每个文件在被创建或则修改以后,都会在工作区保存,当完成一次提交
commit
以后,发生变化的文件或路径都会产生一个新的记录
,就像上图一样用来记录这个commit
下面各个tree
和blob
的版本。 - 就好比我们记录我们的日常工作,下班后我们把一天的工作记录存档
commit
,里面记录了各个任务tree
的具体完成结果blob
,这样周而复始,我们的tree
和blob
就会被不断更新,进而产生很多个版本。而每天下班存档commit
,就是把当前每个任务完成到哪个状态(对应每个tree
和blob
的版本)记录下来。形成一个commit
快照。
应用
在了解了git内部是如何实现路径及文件的管理后,接下来我们来看看怎么样基于ta们
来完成一些应用。
branch
git
的版本管理像一颗大树,master
是数的主干,branch
是树的枝干,主干会不断的生长,枝干也会不断的生长(不断提交commit
,就长高啦);这里记录几点注意:
branch
是一个指向commit
的指针;- 每一次提交
commit
,而生成一个新版本的tree
/blob
对象; - 如果文件或路径未发生改变,则指向老版本的
tree
/blob
对象; - branch分支所指向的
commit
,会在提交了新的commit
后向前移动。(始终指向最新提交的commit
)。
tag
与branch
类似,不同的是tag
创建后其指向commit
不能改变;就好像我们在某个时间点拍了一张照片,就永远记录那个时间点画面里记录的一切了。
stash
解决工作在某个分支且未提交commit
时,又需要马上切换分支到另外的分支上;
git stash
产生的commit
对象有两个parent
,多出来的这个parent
就表明是未提交且临时保存了的stash
。