附录B Git与CVS面对面

B.1 面对面访谈录

Git:我的提交是原子提交。每次提交都对应于一个目录树(树对象)。因为我的提交ID是对目录树及相关的提交信息建立的一个SHA1哈希值,所以可以保证数据的完整性。

CVS:我承认这是我的软肋,一次错误或冲突的提交会导致部分数据被提交,而部分数据没有提交,版本库的完整性会被破坏,所以人们才设计出来Subversion(SVN)来取代我。

Git:我的分支和里程碑管理非常快捷。因为我的分支和里程碑就是一个记录提交ID的40字节的文件,你的呢?

CVS:你怎么又提到别人的痛处了!我的分支和里程碑创建速度还是很快的,……嗯……,如果在版本库中只有几个文件的话。当然如果版本库中的文件很多,创建分支和里程碑就需要花费很长的时间。有些人对此忍无可忍,于是设计出SVN来取代我。

Git:其实我不用里程碑都没有关系,因为每个提交ID就对应于唯一的一个提交状态。

CVS:这也是我做不到的。我没有全局版本号的概念,每个文件都通过单独的版本号记录其变更历史,所以人们在使用我的时候必须经常用里程碑(tag)对我的状态进行标识。还需要提醒一句的是,如果版本库中的文件太多,创建里程碑是很耗时的,因为要逐一打开每个版本库中的文件,并在其中记录里程碑和文件版本的关联。

Git:我的工作区很干净。只在工作区的根目录下有一个.git目录,此外再无其他辅助目录或文件。

CVS:我要在工作区的每一个目录下都放置一个CVS目录,这个目录下有个Entries文件很重要,记录了对应工作区文件的检出版本及时间戳等信息。这样做的好处是可以将工作区移动到任何其他磁盘和目录,而毫不影响使用,甚至我可以将工作区的一个子目录拿出来,作为独立的工作区。

Git:我也可以将工作区移动到其他磁盘,但是要保证工作区下的.git目录和工作区一同移动。不可以只移动工作区下的一个目录到其他磁盘或目录,那样的话移出的目录就不能工作了。

Git:我的网络传输效率很高。在和其他版本库交互时,对方会告诉我他有什么,我也知道我有什么,因为只传输缺失对象的打包文件,所以效率很高而且能够显示传输进度。

CVS:这一点我不行。因为我本地没有文件做对照,所以我在传输的时候不可能做到增量传输。

Git:我甚至可以不需要网络,因为我在本地拥有完整的版本库,几乎所有的操作都在本地完成。

CVS:我的操作处处需要网络,如果版本库在网络中的其他服务器上,而且网速又比较慢,那么查看日志或历史版本都需要等很长时间。

CVS:你怎么没有更新(update)命令?还有你为什么老是要执行检出命令(checkout)?对我而言,检出命令只在工作区创建时一次性完成。

Git:你的检出命令(checkout)是从远程版本库服务器获取数据来完成本地工作区的创建,版本库仍然位于远程服务器上。你的更新(update)命令执行得很慢,对吗?之所以你需要执行更新命令是因为你的版本库在远程啊。别忘了我的版本库是在本地,本地版本库会随着我在本地工作区中的操作(如提交)而更新。我的检出(checkout)操作是将本地版本库的数据检出到本地工作区,用于恢复本地丢失或错误改动的文件,也用于切换不同的分支。我也有一个和你的更新(update)操作类似的、比较耗时的网络操作命令:git fetch或git pull,这两个操作是从别人的版本库获取他人的改动。一般使用我(Git)做团队协作的时候,会部署一个集中共享的版本库,我就用这两个命令(git fetch或git pull)从共享的版本库执行拉回操作。也许你(CVS)会觉得git fetch或git pull和你的cvs update命令更像吧。至于你的检出命令(cvs checkout),实际上和我的克隆命令(git clone)很相似,只不过我的克隆命令不但创建了本地工作区,而且在本地还复制了和远程版本库一样的本地版本库。

CVS:为什么你的检入(commit)命令执行得那么快?

Git:是的,我的检入命令飞一般就执行完了,这也是因为版本库就在本地。也许你(CVS)会觉得我的推送命令(git push)和你的检入命令(cvs commit)更相像,其实这是一个误会。如果我不做本地提交,是没有东西可以推送(git push)的。你(CVS)每一次提交都要和版本库进行网络通信,而我可以在本地版本库进行多次提交,直到我的主人想喝咖啡了才执行一次git push,将我本地版本库中的新提交推送给远程版本库。

CVS:我每个文件都一个独立的版本号,你有吗?

Git:每个文件一个版本号?这有什么值得夸耀的?我听说你最早是用脚本对RCS系统进行封装实现的,所以你的每个文件都有一个独立的版本控制,这让你变得很零碎。我听说某些商业版本控制系统也是这样,真糟糕。我的每次提交都有一个全球唯一的版本号,不但在本地版本库中是唯一的,和其他人的版本库也不会有冲突。

CVS:我能一次检出一个目录,你好像不能吧?

Git:所以我有子模组,以及repo等第三方工具,可以帮助我把一个大的版本库拆成多个版本库组合来使用啊。而且我还有稀疏检出的功能,只不过很少有人用到罢了。

CVS:我能添加空目录,你好像不能吧?

Git:是的,我现在还不能记录空目录。但是用户可以在空目录下创建一个隐含文件,并将该隐含文件添加到版本库中,这就实现了空目录的添加功能。你,CVS,目录管理是你的软肋,你很难实现目录的重命名,而目录重命名对我来说却是小菜一碟。