git一直都在用,一年了,始终都是用别人写的工具,对git算是一知半解,今天趁此机会来研究一下。本文的第一点简单看一下git的先进性,第二点才是git的核心,那就是git的文件结构,工作区和暂存区。
1.SVN和git的区别来理解git的先进性
a:增加了本地库的概念
svn 的模式是:
1.写代码。
2.从服务器拉回服务器的当前版本库,并解决服务器版本库与本地代码的冲突。
3.将本地代码提交到服务器。
分布式版本管理的模式是:
1.写代码。
2.提交到本地版本库。
3.从服务器拉回服务器的当前版本库,并解决服务器版本库与本地代码的冲突。
4.将远程库与本地代码合并结果提交到本地版本库。
5.将本地版本库推到服务器。
看着明显多了两步,区别就在这里。就是本地管理一个版本库,人们常说的集中式和分布式就是在这里。
git和SVN涉及到远程代码服务器的时候都会遇到一个冲突的问题,这是无法避免的。但是git多了一个本地库的概念。区别就在于这个本地库,SVN的话你不提交到远程的中心服务器就没法做版本管理,比如看你的修改历史啊,合并啊什么的。git可以,本地库上你随便搞版本管理,只是你commit到本地库一切都可以搞。
b:可以只pull某个人也就是某个分支的代码。
c:分支管理
分支对于git来说不是独有的,SVN也有,但是优秀在哪儿呢。众所周知,SVN都是与中央服务器交互,那么切换分支的时候自然慢的像蜗牛一样,听说导致大家都不用了。git的优秀还是得益于这个本地版本库,可以做到本地管理分支(当然很快,这个还得益于切换分支只要移动HEAD指针),然后一股脑推上去再合并。现在想想,linus当时肯定是想,这个太慢了,那怎么解决呢,所以就搞个本地的吧,这种分布式,独立的想法其实想想也是顺理成章的,不是说linus不够牛逼,是说每件看上去复杂而美妙的事情都是一步步进化来的,不会一蹴而就,就和你写项目一样,需要不断的重构。
2.工作区和暂存区的概念
首先问,为什么这么设计,据我看来,这么设计是相当于一个缓存,当你add完成之后,这时候给你一个确定你的修改的机会,并且设计了一个diff来让你确定是不是这就是你修改的地方。不然直接commit,也没有比较,容易出错,不透明。
工作区就是你的项目,你的工作区里隐藏着一个版本库就是.git文件,ls -a可以看到。
这个版本库里包含一个区域叫暂存区。git是linus用C写的,那么我们试着跟着linus的思路从C操作文件的角度理解git的设计。
首先,我们试着想象工作区就是你的电脑上的一个个文件,工作区维系着一个目录树,其实工作区,暂存区和版本库的master这部分都有一个目录树。那么真正的文件内容是存在.git/object,最后你push到服务器的就是这个objects的内容。精髓就是大家都是目录,你add的话就是更新暂存区(index)的目录树,commit就是更新master的目录树,而这些目录树都是和objects这个文件有映射的。
这样看来,git最基础的操作应该就是文件的读写,索引的更新,文件的比较,其实就是一些文件的操作。
现在来看git status和git diff,两个都是扫描工作区和暂存区之间的关系,这里简单思考了一下他们是怎么比较的,计算机的东西其本质都是二进制字节码,比较的话就看时间戳和文件长度是否一致。(至于具体为什么这么比较,为什么只比较一个不行还没有想清楚。)
其实每一个命令的操作都是操作这三个地方,做一些文件的比较删除操作。比如reset操作,版本回退,应该是操作master的目录索引,然后对应index索引,最后再更新工作区的索引,这样看来objects里面应该缓存着不少历史版本文件内容,还是只缓存改变的那种。至于缓存多少,会不会清理,怎么缓存就太底层了没想清楚。