《Pro Git》有哪些可以引发深入思考?

摘要:阅读《Pro Git》时的一些随想,包括Git的设计思想、内部原理等,不具体介绍Git基本命令的用法。
之前做版本管理,我使用最多的是SVN,而且也只是在用一些最常用的操作。最近公司里很多项目都开始上Git,借这个机会,我计划好好学习一下Git的操作和原理,以及蕴含在其中的设计思想。同事推荐了一本《Pro Git》,读起来感觉很好,在这里分享下阅读时的思考。此书的在线阅读地址:http://iissnan.com/progit/ 第一章 起步   这一章介绍了Git的相关历史和基本特点,以及安装配置方法。这里提到的Git的特点包括“直接记录快照,而非差异比较”、“近乎所有操作都是本地执行”、“时刻保持数据完整性”、“多数操作仅添加数据”、“文件的三种状态”,除了最后一点我会放在下一章里梳理,下面会对其中一部分进行一些思考的分享。 直接记录快照,而非差异比较 Git 和其他版本控制系统的主要差别在于,Git 只关心文件数据的整体是否发生变化,而大多数其他系统则只关心文件内容的具体差异。   这个策略要求Git记录每个版本的完整文件。如果需要对比同一个文件的两个连续版本间差异,Git会直接比较两个文件,而其他系统可以直接把保存的具体差异取出来;但是如果比较间隔版本的文件,后者需要将差异全部合并,才能显示。这意味着版本的间隔越多,基于差异的系统在比较差异所需要的计算量会越大,而Git完全不会受到这个影响。   可以把这个策略看作是空间换时间的实践。现在单位存储空间的费用越来越低,TB级硬盘也已沦为白菜价,即使是开发人员使用的百兆级SSD也已经普及,额外的空间消耗完全可以不做考虑。 时刻保持数据完整性 在保存到 Git 之前,所有数据都要进行内容的校验和(checksum)计算,并将此结果作为数据的唯一标识和索引。换句话说,不可能在你修改了文件或目录之后,Git 一无所知。这项特性作为 Git 的设计哲学,建在整体架构的最底层。所以如果文件在传输时变得不完整,或者磁盘损坏导致文件数据缺失,Git 都能立即察觉。 Git 使用 SHA-1 算法计算数据的校验和,通过对文件的内容或目录的结构计算出一个 SHA-1 哈希值,作为指纹字符串。该字串由 40 个十六进制字符(0-9 及 a-f)组成,看起来就像是: 24b9da6552252987aa493b52f8696cd6d3b00373 Git 的工作完全依赖于这类指纹字串,所以你会经常看到这样的哈希值。实际上,所有保存在 Git 数据库中的东西都是用此哈希值来作索引的,而不是靠文件名。   使用SHA-1产生的hash值而不是文件名做索引的好处是,hash值的长度固定,并且随机性很好,符合哈希充分散列的要求。SHA-1本身就是一种常用的hash函数,其应用不在这里重述。前一段时间Google宣布“将在Chrome浏览器中逐渐降低SHA-1证书的安全指示”,但它这样做的原因是出于安全考虑,并不意味着Git使用SHA-1做hash函数不合适,有兴趣的读者可以看看相关的分析,如:深度:为什么Google急着杀死加密算法SHA-1。   文件名做索引有什么坏处呢?长度不固定并不是主要的问题。以用maven管理的代码为例,如果依赖比较复杂,那么各个package中都有各自的pom.xml,它们的文件名是完全一样的,会导致严重的hash碰撞。 第二章 Git基础   这章介绍了最基本的 Git 本地操作:创建和克隆仓库,做出修改,暂存并提交这些修改,以及查看所有历史修改记录。这些操作的命令不再一一列出,来看看第一章提到但没有详细讲述的文件状态。 文件状态   梳理一下文件各个状态的转换过程和逻辑,可以画出下面的图示。在这张图中,常用的本地的文件操作命令以及将会导致的状态变更就很清楚了:   除了文件状态,简单说下Git里标签的意义。众所周知,SVN里每个版本都是有版本号的,从1开始,每次提交都会升高。而在Git中,每次提交只会返回一个SHA-1 校验和其他的信息,是没有版本号的。   发布时,如何指定Git上的代码版本?这时就可以用tag来做标记了。tag相当于为一个特定的版本增加的标记,可以替代SVN里版本号的功能,而且更强大。 第三章 Git分支 用链表组织分支   如果要理解Git,要理解Git的分支;如果要理解Git的分支,首先要理解Git中的四个基本的对象模型:blob、tree、commit、tag。这部分原书写的比较简单,具体可以参考《Git Community Book》第一章。幸运的是,该书也有网络版,这一部分内容的地址是:http://gitbook.liuhui998.com/1_2.html。简单地说,这四种对象分别对应于:   blob:表示文件内容,是指向文件的索引。
阅读全文