前言

献给

启明星闪亮的清晨

我和Git

一直以来,我的团队使用SVN作为代码版本管理工具。日复一日,提交、提交、再提交,每个产品版本开发完成会打个标签、偶尔回溯修订历史查找Bug,一切都简洁、快速、美好。SVN很棒,它逐步的替代掉了我司内之前的CVS、VCS等同类工具。

然后,Git出现。基于对新事物的渴望、以及追逐偶像的动力,我决定自己去试试它。我把独立进行的、处于商业化早期的研究项目放到github上,克隆到我几台工作机上,然后使用github desktop在Mac、Windows上访问git,并且暂存、提交、推送、拉取。github GUI当然不错,但是我喜欢命令行,因为简洁,不多占用窗口,也能力全面。于是,我就去学了命令行。我立马感觉Git不像我期望的那么酷。

概念多而繁杂,我的感受就是这样:SHA1? Hunk? 远程分支? 引用? 这都是啥啊。当然这只是难而已。真正让人大跌眼镜的是,默认情况下,不少命令的输出看起来有些碎碎念的心烦:比如常见的git status,它不但很啰嗦地显示状态,也会把文件撤销和提交的命令提示出来。不够酷啊!这还不算,当我觉得郁闷时,有人继续补刀,高调地宣布:学习Git的最好方式是理解它的实现。你怎么不去上天?

我丢下git命令行一段时间,然后再捡起来,再丢下,心理很矛盾,有时候觉得git没有大家说的那么好,有时候觉得是不是自己很笨,并且认为我是程序员,不想去碰这些house-keeping类的工作。然后,某天我比较空,完整地清理了下目前为止对git的看法,得出这样的结论:不管git困难还是简单,我这样浅尝辄止、动辄想要输出价值观的思路和做法,是永远也学不会的。

于是我决定放下令人裹足不前的自尊和骄傲,花费了4个月的时间,看了数百页的资料,做了无数的实验,在一台主机上搭建N个仓库互相推送拉取,然后我把分支、合并、rebase如同提交一样,变成我的日常工作。于是,我有了新的感受——正如c语言一样,Git有无数的缺点,它也在继续演进中,但是它的分布式仓库和分支用起来太舒服了,特别是对于经常需要远程工作的人:

  1. 我可以在本地无需服务器就可以完成大部分常用的版本管理;
  2. 可以随时因为某个想法而开一个分支,成功完成后合并到主干,或者失败直接丢弃,开分支除非主动推送否则根本不会影响到其他人;
  3. 和他人协作只要通过接受pull request即可接受别人的贡献,而无需给他开一个账号。

这样自我折腾后,回头再看Linus在Google做的Git专题演讲(2007年),我秒懂了他提到的信任网络。我会在后记内就此话题多说几句。

Git的复杂度

掌握Git并不容易。和SVN相比的话,Git的复杂程度翻了几倍。这不可避免地会令人怀疑且裹足不前。

幸好,Git的复杂是可以划分的。首先是本质复杂度。本质复杂度是不可避免的。多引入一个实体,就意味着同时引入一组概念、以及它和老实体之间的一组关系,所以Git就是更难,哪怕封装得再好也是。作为是一个分布式的、单机可分支的工具,它引入了新的实体对象必然比SVN复杂,比如:

  1. 为了管理提交的颗粒度,它引入了暂存区(stage),引入了块(Hunk);
  2. 为了能够分布,它的提交标示符无法采用简单数字,而是采用了一个看起来令人困惑的字符串(SHA1)。

另外,它也引入了不少非本质复杂度。此类型复杂度在于设计上的缺陷。比如:

  1. 有些命令引入的功能太多。看看git reset子命令即可了解我的意思。
  2. 概念命名随意。比如暂存区有多个名字,包括Index,Stage,Cache。
  3. 参数设计随意。例如git branch -b等价于git branch后跟git checkout 。

Git从一个本不知名的工具,到如今的风头正健,本身依然还在演进之中,非本质复杂度会随着这个过程而逐步降低。

Git刷新了我对版本工具的传统认识——充分利用分布特性来减少依赖,使用分支特性随心创造而无后顾之忧。所以,我认为我花费了不少时间来学习Git是值得的。

关于作者

作者:刘传君

创建过产品,创过业。不好动,读书机器。倾慕unix哲学,以此书略表致敬。

可以通过 1000copy#gmail.com 联系到我。

目录

  • 前言
  • 准备
  • 介绍
  • 暂存区
  • 撤销
  • 分支
  • 修订的标识
  • 标签
  • 多仓库
  • 协议
  • 后记 : 信任网络