SVN 与 Git


十一月的第二周,来学习版本控制系统。

整顿一下,最近写博文总是拖到下一周的周一或者周二才完成,这周一定要努力在周日结束之前发文。


版本控制系统是一个初听有点唬人的名字,版本、控制、系统,这三个词都是带几分黑金属性的气质词汇,合在一起颇有架势。它代表的是这样一个概念:我希望有一个文件库,里面不光存放了所有文件,还保留了每一次的修改信息,如果我想查看某个文件三天前是什么样子的,我仍能看到。

当下常见的版本控制系统就两种,一种是 SVN,另一种是 Git。这两种系统从架构上,到功能实现上,再到价值观上,都是不一样的。总体来说,Git 处于鄙视链的上游地位,代表着信仰,SVN 处于备受唾弃可又怎么都淘汰不了的状态中,充满着妥协。(言重了,言重了)


SVN

我目前工作中使用的是 SVN,实际上我到写博文之前,都是没有使用过 Git 的。所以只能说基本整理一下 SVN 的使用逻辑与方法,但对于 Git 就是浅尝辄止了。

SVN(Subversion),是阿帕奇(Apache)家出的版本控制系统,这家公司(或者应该叫基金会吧)从 HTTP 起家,贡献了 Maven、Kafka、Tomcat 等一堆开源软件或框架,实乃业界良心大佬。SVN 本是为了取代 CVS(一种上古的版本控制系统)而推出的,应当视作一种特定的软件/框架。但是目前看来,SVN 实在是太过成功,以至于成为了一种标杆的存在,代表着中心式的版本控制系统。


中心式的意思是,文件集中起来,由一台服务器进行管理,进行版本控制。如果一个团队有 10 个人,这 10 个人如果想提交代码,或是更新代码,则必须和中心服务器连接起来,提交则上传上去,更新则下载下来。除此之外,我认为中心式还有两层表现:

  1. 中心只维护一套文件,换句话说,使用 SVN 控制的文件,只会有一种表现结果。如果 A 和 B 一起写东西,A 说豆腐脑要吃甜的,B 说豆腐脑要吃咸的,那么上传到中心服务器中的文件,豆腐脑要不然吃甜的,要不然吃咸的,不可以共存。而且,由于只有一套文件,如果文件的内容发生冲突了,提交时必须要自己合并代码,要不然你早点传文件占得先机,要不然就后传文件做冲突处理。
  2. 版本的最终解释权和维护权,在中心。如果你和中心断开了连接,最直接的,你将无法提交代码,也无法更新代码;其次,你没有办法查看某个特定版本的文件,因为所有版本是什么样子的,只有中心才知道,如果觉得自己的代码写得有问题想回滚,那么请先连接中心。

我们在讨论 SVN 和 Git 之间的区别时,大多数情况下,是在讨论中心式管理分布式管理之间的区别。SVN 没有本地库,无法断网开发,几乎不搞分支等等,这些背后基本都是因为它中心式的架构。


SVN 的使用,说实话没什么好写的,因为日常操作实在是太过简单。

平常能够使用 SVN 的地方有两处,一处是 IDE,写代码的时候用到,另一处是 SVN 的客户端 TortoiseSVN(小乌龟),不写代码的时候用到。

使用 SVN,最稀疏平常的两个操作是提交代码下载(更新)代码,提交代码是 commit,更新代码是 update,这两个操作都可以在 IDE 中通过点击鼠标完成(其他操作基本也都可以通过点鼠标完成)。

除了这两项天天都会用到的操作之外,还有检出代码(checkout),即把最新的代码拷贝出来一份,回滚代码(revert),即把代码还原到上一次的提交状态。对比代码(compare with…),即对比自己写的代码和某个版本的代码,显示版本历史(show history),即查看每次的提交记录,以及最最最让人厌烦的代码合并(merge),这并不是一个 SVN 的功能,而是每次提交/更新代码时,如果你的代码和中心代码同时修改了某一处地方,造成了冲突,你需要手动合并。

SVN 的客户端小乌龟,是在不需要写代码的时候使用到的,例如拷贝出来一份代码,修改配置文件的一点参数等等。

实在话,SVN 的使用凭直觉去使用就可以了。


最后我们记录一点 SVN 使用背后的事情。

SVN 是基于文件的来进行版本控制与管理的,如果有三个文件进行改动,就把这三个文件的变化内容记录下来,其他文件不变,并为此赋予一个版本号。下图是 Git 文档对于 SVN 文件版本的演变示意图。

SVN文件版本

我认为,浅尝辄止地认识 SVN 存储原理,需要认识到两个方面:

  1. SVN 的存储是基于文件的,而且它存储的是文件差异。如果文件内容有变化,记录下来,如果文件内容没有变化,无视。
  2. SVN 的版本号是全局的,它描述的是所有文件。所有人都可以向中心指定一个版本号,来获取一整套完整的文件。

Git

惭愧地讲,我至今都没有在 IDE 中使用过 Git,本来想借着这篇博文开始使用,但是用的梯子太不稳定,我连不上高墙之外的 github。


Git 是 Linux 社区搞出来的东西,因为原先用的版本控制工具不让用了,Linux 内核组的大佬花了俩周捣鼓出来一个分布式版本控制系统,也就是 Git,这可真是大佬的任性与倔强……

Git 是分布式版本控制系统的代表,分布式换个表述就是“去中心化”,这是 Git 的核心。稍一思索就会明白,Git 是一个典型的脱胎自 Linux 的产品,Linux 的开发人员是全球的草莽程序员,代码组起来讲究一个英雄不问出处,你指望一个中心式的版本控制系统是不可能的,Git 的出现就是为了实现分布式版本控制系统,分布式是刻在 Git 骨子里的。

Git 为了实现分布式,在设计上就与 SVN 完全不同,主要体现在这些地方上:

  1. Git 同样有中心服务器(远程仓库),但是还有本地仓库。在 SVN 中你只能从中心拉取代码,但是在 Git 中你可以向另一个人的本地仓库处拉取代码。

    事实上,Git 在文件存储位置上的设计远非如此,它设计了四个区域:工作区、暂存区、本地仓库、远程仓库,写代码时你在工作区内写,写完之后保存在暂存区中,当你觉得应该提交代码了,就可以向本地仓库和远程仓库提交代码。

    这种设计造成了两点不同:第一,你可以在暂存区中“攒够”了代码之后再提交,暂存区中的代码可以有好几种版本,你选取一种最好的提交;第二,版本信息不再只保存在中心服务器中,每个人本地也有版本信息,你可以在脱网的情况下查看版本信息(例如对比代码、回滚代码)。

  2. Git 可以随随便便开分支。分支是相对于主线的概念,在 SVN 中大家共用的那套文件一般情况下只会有一条主线,荣也同荣,损也同损,但在 Git 中你可以随便开一个分支,在主线之外处理自己的事情。例如开一个分支实现自己的某个想法,成立则合并进主线,不成立则扔掉这个分支。分支这个概念,使个人能够随便试错,也使团队可以包容多元。

    但是在我查资料的时候,发现很多大佬在讨论 merge 和 rebase 命令之间的选择问题,实际上是在讨论如何让共用版本的分支变少,让版本主线变得“清爽”。这个我大概要用到才能真的体会到,在此只是记录下来。


Git 存储文件的原理,我至今不是很理解,这里记录一下我整理的材料以及认知程度。

每一次提交代码时,Git 将生成一个全部文件的快照。这跟 SVN 的处理方式是完全不同的,SVN 通过记录文件的差异来存储最新的版本内容:我有 A 文件,我有一个文件记录新旧文件的差异,我就可以通过计算得出最新的 A1 文件。你应该注意到,SVN 存储是基于文件的,三个文件改动了就记录下三个差异文件,五个改动就记录五个。但是 Git 每次都是同时记录所有文件,以快照的原理来实现。

我花了好几天,仍不理解快照是什么,我只知道快照不是什么。首先,快照不是文件差异,快照记录下的不光是差异,而是全部信息,有篇博文解释了这件事情:《Git 快照与 SVN 文件差异区别》,但是我对它的正确性存疑(因为没有其他相同观点的文章佐证)。其次,快照不是备份,备份相当于把文件拷贝一份保存在另外一个地方,可以独立存在,而快照需要基于原文件才能读取。

使用快照的好处一在快,二在保存全部文件信息。似乎这是一种用空间换时间的技术方法,但我实在是知之甚少,不敢断言。


记录下两个学习 Git 的公认必备网站,《廖雪峰 Git 教程》《Pro Git 电子版》。总体感觉上,前者论术,后者论道。论术的那个,语言轻浮且不是我喜欢的那类轻浮,论道的那个,翻译腔重(或者说原文就不适合用中文理解),两个都不是我很喜欢的类型。在此记录一下,日后还是要勤读。


就不该开篇立 flag,说什么周日前发文,这篇拖更两周才写完……