git和其他的版本控制系统有很多差异, 其概念的命令都具有很强的混淆效果, 但是无奈速度快被大面积推广使用。。
pro git这本书介绍git的时候说要学好git先要把以前用的版本控制概念忘掉, 以避免混淆, 这个说的太好了。。同时书中也多次提到某个命令有点怪。。。可见开发git的都是一群怪人, 但同时git的版本推进过程中, 命令改动较大, 说明这群怪人也意识到这些命令太恶心了, 正在改进。
先从git记录版本的方式说起, git不同于最传统的版本控制系统, 它使用的是文件快照的方式, 而不是增量的方式。在版本库分布上, 有别于传统的只有服务器有完整的版本库的方式, git在每一台客户机上都有一套完整的版本库。
既然git是用快照的方式保存文件版本历史的, 那么具体是如何保存的呢?我们先新建一个版本库:
git init
创建好后打开目录中的.git文件夹, 发现这个目录中有个HEAD文件, 问什么叫HEAD呢?这是因为git使用类似链表的方式进行文件版本历史的索引,HEAD指向当前所在的分支的最后一次快照, 打开这个文件发现里面指向ref: refs/heads/master, 打开此目录发现里面并没有master这个文件, 这是因为我们还没有对版本库进行过操作, 也就没有快照, 我们先新建一个文件:
nano 1.txt
然后对其修改保存后, 将其添加到版本追踪:
git add 1.txt
此时对文件的添加操作就进入了操作缓存, 注意, 此时git还未将此操作进行提交, 只是进行了缓存, 执行下面的命令提交:
git commit
然后我们发现git创建了master这个文件, 打开master我们可以看到这次提交的一个唯一编号, 一个sha1值,这次提交的信息又指向一个文件记录文件目录结构的文件, 记录文件目录结构的文件又指向一个一个记录文件快照的文件, 这里引用pro git中的一个图:
这些文件全都放在object目录中, 以文件名称前两位分目录存储。
我们发现HEAD中记录的是master这个文件, 而我们知道git中默认的分支是master, 那么我们可以想象HEAD中记录的是当前所在branch的名称, 如果我们新建分支并将当前分支切换到新建的分支, 那么HEAD中的内容是不是应该有所变化呢?新建分支:
git branch testing
切换到新建的分支
git checkout testing
我们再来看HEAD文件, 果然, 其中的内容变成了ref: refs/heads/testing, 这时我们打开这个文件查看, 发现其中的内容和master中相同, 这说明git中分支指向的其实就是一次提交, 即一次快照。再来看一张pro git中的图:
在图中我们又发现每一次提交都指向上一次提交, 那么这个又是从哪记录的呢?在log目录中, 这里有HEAD指针的移动记录, 有各个分支的提交记录, git正是通过这样的链表结构来进行历史回溯的。