WB
WB
文章目录
  1. 1. Linus 扩展不了
  2. 2. BitKeeper 的起源
  3. 3. Linux Kernel 采用 BitKeeper
  4. 4. 没有免费的 BitKeeper 了
  5. 5. Monotone
  6. 6. Git v0.01 初探
  7. 7. Git 早期贡献者
  8. 8. 接班人
  9. 9. GitHub 与 Ruby 人
  10. 10. Git 与 GitHub 有冲突的合并
  11. 11. 后记

Git 的故事:这一次没这么好玩

Linus Torvalds 曾写了一本提到,当初创造 Linux 只是因为好玩,却意外掀起一场革命。Git 是 Linus 的第二代表作,同样也是意外的革命,是现在软体工程师的标配,但至少对 Linus 本人来说,它的起源可就没这么好玩了。

Linus 扩展不了

1998 年是 Linux 风光的一年,许多大公司,如昇阳、IBM 和甲骨文,都纷纷投入 Linux 的业务。那年春天,Linus 的二女儿出生,他们一家从芬兰搬到美国加州也差不多一年,生活步入正轨。虽然 Linux 还尚未给 Linus 带来什么收益,但 Linus 也可算是事业家庭两得意。

反观 Linux Kernel 的开发者社群,随著愈来愈多人加入开发,既有的合作方式开始力不从心。Linus 开始显得没办法跟上开发者们修改程式码的速度,逐渐成为瓶颈。

1998 年 9 月 28 日,Linus 和往常一样,读著 Linux Kernel 邮件列表上的信。

请不要浪费时间送修补了,这些在 vger 上早就修好了。

Linus 看到这句不太高兴。一直以来,Linux 程式码的修改重度仰赖 Linus 本人,Linus 本人就是版本控管。如果你要修改程式码,寄封信到邮件列表上,Linus 看到了并认可,就会将你的修补送进他自己的版本,然后不时在 FTP 上释出新版本。Linus 喜欢这样的合作方式,因为他可以掌控一切变更,大家也信任 Linus,觉得 Linux 本来就该由 Linus 掌控。

但自从 David Miller,一位 Linux Kernel 的资深开发者,架设了一个名为 vger 的 CVS 伺服器,有些人就以为可以绕过 Linus 本人,将变更送到 vger 就没事了。这不是 Linus 第一次遇到同样的问题,他在邮件列表上不悦的回应

“在 vger 上就不要浪费时间”这个说法完全是愚蠢的,因为 vger 上很多东西可能永远都不会进 2.2。

于是几个开发者与 Linus 展开一场激烈的笔战,他们开始陈情,说 Linus 回信太慢,甚至有时候要寄三次才会得到这个“仁慈独裁者”的亲回。

“这些家伙也不照照镜子,”Linus 心想:“我一天要看多少信,如果连寄三次信都嫌麻烦,那这个修补我宁可不要。” Linus 在讨论串留下这个讯息随即怒离:

这次的讨论只是让我烦燥,增加我的压力。走开吧,不要再 CC 我了,我要度假去了,我不要再听到任何有关它的事。总之,滚出我的信箱就对了。

Linus 情绪性的发言反而让一些人开始提出正面的帮助。

开源运动代表人物之一 Eric S. Raymond,著名文章《大教堂和市集》就是他写的。看到 Linus 的怒离文,他冷静地呼吁

各位,这些是职业倦怠的早期征兆。Linus 一直以来的毅心确实令人敬佩,但他也是有极限的。我们所有人(是的,也包括你 Linus)要一起想办法帮这个重要人物减少压力,而不是增加压力。

另一位伸出援手的是 Larry McVoy,在一篇标题为“成长痛的解决方案”的邮件,他这么写:

问题症结在于 Linus 扩展不了(“Linus doesn’t scale”)。我们不能期待 Linus 一个人能跟上 Kernel 变化的速度,我们也不想看到 Linus 失去对 Kernel 的掌控,他已一再证明自己非常适任此职。

(解决方案基本上是)将工作分担给 Linus 身边的几个人,要做到分担,我们要导入新工具。

(这个新工具是)一个分散式版本控管系统⋯⋯

Larry 当时正好在开发一套新的版控软体,叫做 BitKeeper。

BitKeeper 的起源

在 1990 年代早期,昇阳导入了一套名为 Network Software Environment (NSE) 的内部工具来管理程式码,但 NSE 太慢了,使用体验极差,有些工程师甚至为此愤而离职。

Larry McVoy 不仅是个资深的作业系统开发者,过去也做过许多效能相关的工作,所以昇阳的主管就找上了 Larry 来调教一下 NSE 的效能。

Larry 一看 NSE 的程式码吓了一跳,“这东西很多地方当初设计时都没有考量到效能。”他还发现 NSE 的底层其实是 SCCS,SCCS 是 1970 年代的版本控管软体,出现比 CVS 和 Subversion 还早。与其修改体质不良 NSE,Larry 选了另一条路:他用 Perl 写了 NSElite,在 SCCS 之上实作了 resync/resolve 指令,基本上类似现今 Git 的 clone/pull/push 指令。

NSElite 比 NSE 快多了,所以昇阳的工程师一个一个背弃 NSE,改用 NSElite。昇阳某 VP 见状,觉得有商机,就组了一个八人团队,想要用 C++ 重写 Larry 写的 Perl 脚本,将其产品化为 TeamWare

TeamWare 大概是最早的分散式版控系统,后来昇阳 Solaris 作业系统的开发全是借助于它。工程师们用过 TeamWare 都表示回不去了:不同于 CVS 和 Subversion,TeamWare 让你将整个专案复制到你自己的机器,你可以尽情地在本地端提交变更,等到准备好再将你自己本地的版本合并回远端版本。

这八人团队的成员本来是写 C 语言的,当时 C++ 是新的火热语言,他们边学 C++ 边开发 TeamWare。在 TeamWare 还未完成前,Larry 曾尝试继续开发 NSElite,但这无疑是给 TeamWare 团队难堪:一个人用 Perl 竟然比八个人用 C++ 还来得快,VP 见状便告诉 Larry:“这件事已经上报给 Scooter(即 Scott McNealy,昇阳的执行长),如果你再发布一次,你就被解雇了。”

为此,1991 年,Larry 停止 NSElite 的开发,但建造一个分散式版控软体的念头始终在他心中挥之不去。他本来以为会有其他商用软体会跟进 TeamWare 的脚步,但并没有。1997 年 Larry 开始著手开发一款名为 BitKeeper 的分散式版控软体。然而,直到 1998 年 9 月,当他看到邮件列表上 Linus 处于崩溃边缘,这才真正激励他开始认真看待 BitKeeper 这个专案。

Linux Kernel 采用 BitKeeper

1998 年秋天某日,Larry 邀请了 Linus Torvalds、David Miller、Richard Henderson 来家中,吃完晚餐后,他们席地而坐,开始协商对策要如何减少 Linus 的工作量。他们在地板画了三、四个小时的图,这些图大致上就是 TeamWare 在昇阳内部行之有年的运作方式,Larry 对此十分熟悉。

在这个框架中,开发者们可利用 BitKeeper 各自开发,不互相干扰,而且在 Linus 这边做最后整合时,能够不失去修改的历史记录,让 Linus 能看出一个变更的来龙去脉,审查程式码时更容易。

“好吧,如果你做出来,而且跑起来跟你说的一样,我就会用它。”Linus 说道。
“没问题,这我以前做过,大概需要六个月。”Larry 回答。

Larry 马上就意识到他低估了问题的复杂度,所以他成立了一间名为 BitMover 公司,找了几个熟悉版控系统的好手,一起打造 BitKeeper。19 个月后,2000 年 5 月,BitKeeper 公开释出第一版,此时 BitMover 是一个七人团队。

第一版的 BitKeeper 有一个命令列工具 bk,也有一些图形介面的工具。其中 bk clone/pull/push 命令作用有犹如 git clone/pull/push

当时昇阳的 TeamWare 已是有口皆碑,而 BitKeeper 更是 TeamWare 的强化版。例如,TeamWare 只允许在 NFS 档案系统间传递资料,而 BitKeeper 可以走 HTTP 来传输档案,实现了真正的分散。因此不久后,BitKeeper 就为 BitMover 带来充沛的现金流,到了 2002 年,BitMover 团队成长到了 25 人,完全自给自足,没靠外部资金。

Larry McVoy, Linux Expo, 1999

Larry McVoy, Linux Expo, 1999

2002 年 1 月,Linus 工作量太大的问题又再度浮现,开发者送出的修补不是等很久才迟迟回应,不然就是被忽略。有人写了一篇“小小的提议”尝试改善这个问题。讨论串中,有人随口提到“bitkeeper 真是个好工具”,唤醒了三年前,Larry 家中的那顿晚餐,在 Linus 脑中种下的那颗种子。Linus 问道:“有多少人在用 bitkeeper 做 kernel 开发?”

果不其然,当时已经有些 Kernel 开发者早就在使用 BitKeeper。Linux PowerPC (PPC) 团队早在 1999 年 12 月就开始试用 BitKeeper,BitMover 为了帮助他们,架设了 bkbits.net 伺服器。

过没几天,2002 年 2 月 5 日,邮件列表上就看到 Linus 开始在测试 BitKeeper。此后,Linux Kernel 主要开发者们也跟进开始采用 BitKeeper。你不一定要用 BitKeeper 才能参与开发,但如果你是 BitKeeper 的使用者,流程大概是:

1
2
3
4
5
6
7
8
9
10
11
12
<span style="display:flex;"><span><span style="color:#75715e"># 下载仓储(repository)</span>
</span></span><span style="display:flex;"><span>bk clone bk://linux.bkbits.net/linux-2.5 linux-2.5
</span></span><span style="display:flex;"><span>bk clone linux-2.5 alpha-2.5
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 从另一个地方下载变更</span>
</span></span><span style="display:flex;"><span>cd alpha-2.5
</span></span><span style="display:flex;"><span>bk pull bk://gkernel.bkbits.net/alpha-2.5
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 编辑档案并将变更上传回远端</span>
</span></span><span style="display:flex;"><span>bk vi fs/inode.c
</span></span><span style="display:flex;"><span>bk push bk://gkernel@bkbits.net/alpha-2.5
</span></span>

若要将变更送给 Linus,你就再寄封信到邮件列表上,内容大致是:

1
2
3
4
5
6
7
8
Here is an update for something something...

Please pull from: bk://gkernel.bkbits.net/alpha-2.5

example/file1.c | 6 ++++++
example/file2.c | 4 ----
2 files changed, 6 insertions(+), 4 deletions(-)
-----

没有免费的 BitKeeper 了

Larry McVoy 让 Linux Kernel 开发者免费使用 BitKeeper,但免费是有代价的。例如,他们的免费用户的使用执照里规定:

  • 你不可以关掉 Open Logging──此机制会将使用纪录传送至 BitMover 伺服器。
  • 如果你从事的是版控软体的业务,你不可以免费使用 BitKeeper。
  • 如果你要让 BitKeeper 和其他同类软体一起运行,你必须征求 BitMover 同意。

Linux 是开源软体的始祖,社群里有很多自由软体的拥护者,对这些条款不是嗤之以鼻,就是敬而远之。可是对 Linus 和主要的 Kernel 开发者来说,重点是 BitKeeper 减轻了他们的工作量,况且当时没有更好的替代工具,他们也就接受 BitKeeper 的使用条款,以换取它的便利。

以 Linus 来说,他对专用软体(proprietary software)一直持开放态度,他当初会选用自由软体 GPL 作为 Linux Kernel 的授权协议,纯粹是因为他不乐见商业市场“玷污”了 Linux,他的方法就是让 Linux 保持开放,而GPL 刚好在那边符合他的需求,他就拿来用了。但他从不觉得所有软体都该走自由软体的路线,他觉得作者有权以任何他想要的方式散布软体,怎么使用软体不应该是社会运动。

自由软体的拥护者可不这么想,比较极端的甚至会认为专用软体都是邪恶的。这群骇客宁可拥有修改软体的自由,也不要 BitKeeper 的“便利”。

Larry 备受来自社群的压力,为解决此问题,BitKeeper 团队在 2003 年架设了一个 BitKeeper 至 CVS 的镜像,让那些不想装 BitKeeper 的人,也可以透过 CVS 来取得程式码的修改历史。但从 CSV 取得的历史资料和 BitKeeper 上的并不完整,人们还是不满意:“为什么我们的资料要被锁在 BitKeeper 的专用格式里,而且还明文禁止我们用其他程式去读取我们自己的资料?”

有鉴于此,Samba 和 rsync 的作者,澳洲程式设计师 Andrew Tridgell(简称 Tridge),在 2005 年 2 月开始著手写一个免费的 BitKeeper 客户端程式,要解决自由软体用户面临的问题。

Tridge 做了以下尝试。

“这里有一个 BitKeeper 位址,bk://thunk.org:5000,用 telnet 连上去试试看。”

1
2
3
4
$ telnet thunk.org 5000
Trying 69.25.196.29...
Connected to thunk.org.
Escape character is '^]'.

“连上去了,何不输入 help 命令?”

1
2
3
4
5
6
7
8
help
? - print this help
abort - abort resolve
check - check repository
clone - clone the current repository
help - print this help
httpget - http get command
[...]

“BitKeeper 伺服器居然这么好心,列出所有指令。”
“所以 clone 应该就是下载仓储用的指令吧?”

他接著输入 clone,发现输出仅是一连串 SCCS 格式的档案。至此,“反向工程”的工作已大功告成,剩下的只是把程式写出来。

不知 Linus 是从何得知 Tridge 在干的事,或许是 Tridge 自己私下告诉他的。总之,Linus 得知后就将这件事告诉他的好朋友 Larry。Larry 听到后无法接受,因为一个免费的第三方客户端会毁了 BitKeeper 的商业模式,于是 Larry 连手 Linus 和时任 OSDL(即现在的 Linux 基金会)执行长的 Stuart Cohen,要求 Tridge 停手。

Stuart Cohen 选择冷处理,觉得这不关 OSDL 的事。但 Linus 非常不想失去 BitKeeper,所以很努力地居中调解,试著找到出双方都能接受的折衷方案。Tridge 坚定地认为他没错,他甚至认为有一个第三方客户端对 BitKeeper 和 Kernel 开发者们是双赢 。他在 2005 年 4 月在 Freshmeat(后来并到 SourceForge)发布 SourcePuller,里面的 README 文件写道:

有一个开源的客户端本应是一大进步,BitMover 可以在商业环境继续成长,自由软体社群也能使用并从中受益。

BitMover 有权为 BitKeeper 制定使用规范。当然,BitMover 这样描绘我,我很失望。但请理解他们承受了很大的压力,而在压力大的情况下,人们会说错话。

Larry 不认同这会是双赢,支持 Kernel 的开发是要成本的,没收钱的就算了,还可能会违害到既有的商业模式,所以为了维护 BitMover 的生计,他选择撤下 BitKeeper 的免费使用执照。

Linus 交涉了几个礼拜,也不想再当和事佬了。这下没有免费的 BitKeeper 可以用,Linus 怒了,他公开在论譠上责备 Tridge,说他“破坏别人的创新”、“恶搞别人”。当然,Linus 大可付钱,但他没办法要求其他 Kernel 开发者也付钱使用 BitKeeper,所以他必须另辟途径。贴文中他写道:

现在,我得收拾善后。因为最好的版控工具不能用了,我会自己写一个给 Kernel 用。但没关系──我自己的问题,我自己解决,谢谢你了(Tridge)。

2005 年 4 月 6 日,Linus 在邮件列表上宣布 Linux Kernel 与 BitKeeper 要分手的消息。他首先感谢 Larry 和他团队这三年来的帮助。接著他说他会离线一个礼拜,找出一个替代方案。最后他提到:

用不著跟我说 subversion 了,如果你真的想给建议,去看看 monotone,它应该是最可行的替代方案。

Monotone

Monotone 的原作者是 Graydon Hoare。2001 年,住在加拿大的 Graydon 和他澳洲朋友为了让跨时区合作更容易一些,他们打造了一个类似现在的持续整合(CI)系统(当时 CI 还不是显学),确保程式码无时无刻都通过测试。

2002 年,Graydon 开始对版本控管结合 CI 产生兴趣,当时他找到只有 Aegis 有这样的概念。同时,Graydon 又看到朋友使用 BitKeeper,他想到 Aegis 结合分散式版控应该是不错的机会,Monotone 就此应运而生。

值得一提,Graydon 后来加入 Mozilla,并创造了 Rust 程式语言。

好巧不巧,Linus 挑了一个坏的时机点来把玩 Monotone。原本 Monotone 0.7 性能还算快,但自 0.14 开始,Monotone 的开发者开始加入许多验证机制。就在 Linus 下载 Monotone 前,原作者 Graydon 发布 0.17 后就跑出度假了,里头加了一堆严谨的检查程式码,以确保资料写入资料库前是正确的,但这些程式码尚未优化,反而拖慢了性能。在 0.17 的发布纪录提到

pull 命令可能会非常慢,而且占用很多 CPU

有人测试用 Monotone 下载它自己,竟然花了两小时,其中 71 分钟是 CPU 时间。“没有腿的树懒可能都比它快。”那位人士如此形容

Linus 向 Monotone 的开发者回报性能问题。2005 年 4 月 10 日,Monotone 0.18 释出,许多操作都至少快了一倍。虽然 Linus 也名列在 0.18 的贡献名单中,但根据 Monotone 开发者之一 Nathaniel Smith 的说法

Linus 其实没有对 Monotone 贡献过任何程式码,或者据我所知,他也没有对 git 以外的任何版控软体贡献过程式码。除了“这太慢了!”之外,他也没有提出什么实质建议 ;-)。他之所以名列为贡献者,是因为在与他的讨论中,我找到了一个测试案例,追踪到一个重大性能瓶颈。我曾犹豫是否应该把他的名字列上去,因为这可能会让人产生奇怪的想法,但我想,如果是其他人我也会这么做,所以⋯⋯(耸肩)。

与此同时,受到 Monotone 的设计启发,Linus 也从零开始,开始著手写了一些 C 程式码。

Git v0.01 初探

2005 年 4 月 7 日,Linus 上传了一个名叫 Git 的东西,他在邮件列表写道

这边有一个小小的挑战要给疯狂的骇客们,如果你有想玩玩看很乱(但非常快)的东西,看一下 kernel.org:/pub/linux/kernel/people/torvalds/

第一个将 sparse-git 的变更纪录树寄给我的,将会得到一个金色星星和公开表扬,我在里头放了很多线索。

这是 Linus 第一次在公开场合提到 Git。

该网址有以下档案和目录:

1
2
3
4
5
6
7
git.git/                  09-Apr-2005 16:09    -
sparse.git/ 07-Apr-2005 20:07 -
git-0.01.tar.bz2 07-Apr-2005 14:25 39K
git-0.01.tar.bz2.sign 07-Apr-2005 14:25 248
git-0.01.tar.gz 07-Apr-2005 14:25 40K
...
sparse-git.tar.bz2 08-Apr-2005 17:26 15M

git-0.01.tar.bz2 里的 C 程式码加起来大约 1000 行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
---------------------------------------------------------------------
File blank comment code
---------------------------------------------------------------------
./read-cache.c 31 14 219
./update-cache.c 32 23 198
./commit-tree.c 23 26 128
./show-diff.c 8 5 73
./cache.h 17 23 53
./write-tree.c 11 7 53
./read-tree.c 4 5 39
./init-db.c 4 14 38
./Makefile 14 0 26
./cat-file.c 2 5 21
---------------------------------------------------------------------
SUM: 146 122 848
---------------------------------------------------------------------

有别于现在的 Git 有一个单一执行档 git,Linus 最早上传的 Git ,编译后会产生七个独立执行档:

  • init-db
  • update-cache
  • show-diff
  • write-tree
  • read-tree
  • commit-tree
  • cat-file

init-db 做的事情很单纯,它会在当前目录下建立一个名为 .dircache/objects 的目录,然后在 .dircache/objects 里,再建立 256 个以十六进位数字编号的子目录,依序为 00, 01, 02, …, 0f, 10, …, ff

.dircache/objects 目录代表著一个物件资料库,物件的种类有:

  • 二进位资料(blob)──即档案内容。
  • 树(tree)──即目录,本质上是一些档案(二进位资料)和目录(树)的名称。
  • 变更集(changeset)──由两棵树的名称定义而成,意义上代表的是 A 树变更成为了 B 树。“变更集”是 Git 早期的用词,之后成为“提交”(commit)。

这里物件的名称不是档名或目录名,而是物件内容压缩后的 SHA-1 杂凑。这个设计是 Linus 从 Monotone 学来的,差别在于 Monotone 底层使用 SQLite 储存 SHA-1 物件名称和内容,而 Linus 选择直接使用系统呼叫和档案系统。

SHA-1 几乎具有唯一性,因此我们可以假设 Git 资料库中不会有两个不同名、但相同内容的物件。假如有个物件的名称是 ba93e701c0fe6dcd181377068f6b3923babdc150,Git 就会将它储存在 .dircache/objects/ba/ 目录下,一个名为 93e701c0fe6dcd181377068f6b3923babdc150 的档案。

这七个执行档就是以这个“内容可定址”(content-addressable)档案系统为中心的七种操作。例如:

  • write-tree 建立一个树物件,即将某个时间点树的样子写到资料库。
  • commit-tree 建立一个变更集,即在资料库中连结两棵树,类似现今的 git commit 命令。
  • update-cache 加一个档案到 .dircache/index 索引中,类似现今 git add 将档案加到预存区(staging area)。

Linus 当时看到 Monotone 是如何利用 SHA-1 为物件命名,就立刻爱上这个点子,原因无他,就是“简单”二字。“简单”也是 Linus 欣赏 Unix 的原因。在《只是为了好玩》一书,他这么形容 Unix:

Unix 让我(和大多数人)著迷的地方,就是它简单的设计。在 Unix 中,几乎所有事都可以用六个基本操作(称为“系统呼叫”)来完成。

它给你几种不同形状的积木,足以用来建造所有东西,干净的设计就该是这个样子。

Git 也是如此,它的资料模型比 CSV、Subversion、BitKeeper 都要简单。它储存的东西基本上就是改变前和改变后的树,如此而已。它没有在管哪个档案、在哪一行做了什么改变,它也不需要,因为改变前后的树就埋有这些资讯。

Linus 用两天写出来的 Git 原型,功能简单,没有多馀的验证,没有关联式资料库,只有 C 程式码、SHA-1 杂凑、系统呼叫,完全针对 Linus 自己的需求订制。而 Monotone 专案当时迈入第三年,功能完善,还要应付各种场合需求。再加上 Monotone 原作者 Graydon 加了一堆未优化的程式码后跑去度假,家里没大人。因此在速度上,Monotone 当时自然是比不过 Git 。

Linus 当初上传的档案 sparse-git.tar.bz2,应该是史上第一个 Git 仓储。Sparse 是 Linus 于 2003 年写的一个 C 语言的静态分析器。如果你还对 Linus 出的挑战题有兴趣,sparse-git.tar.bz2 解压缩后稍微修改就可以用现今的 git log 命令去读取变更纪录:

1
2
3
4
# 假设你在 sparse-git 目录下
mv .dircache .git
mkdir .git/refs
git log

Git 早期贡献者

初版 Git 引来热烈讨论,过没几天,Linus 就开设了 Git 专用的邮件列表,这让 Linux Kernel 邮件列表能够稍微回归正题。头一个月,Git 邮件列表就出现了约 2600 则讯息,而 Linux Kernel,史上合作人数最多的软体专案,同期每月有 7000-9000 则讯息。

对在版本控管领域耕耘已久的专家们来说,Git 只是“另一个专案”,因为 Linus 最初上传的 Git 只有一些低阶操作,连 clone 和 merge 的命令都没有,离真正可用的版控软体还差得远。而 Linus 在说 Git 多快多棒时,无意间贬低了其他版控软体,这让以 BitTorrent 闻名的 Bram Cohen 很不满意,杠上 Linus

Bram 当时正在推广他自己的同类产品 Codeville。Codeville 在当时已经是个成熟的版控软体,媲美 Monotone,并且内建十分聪明的合并演算法。看到 Linus 如何与 Git 的早期追随者讨论合并演算法,Bram 觉得 Linus 根本就是门外汉在重造轮子,称 Git 只是个“周末小专案”。

Bram 说的有道理,但这个小专案不是一般人的小专案,它是 Linus Torvalds,Linux Kernel 创始人的小专案。身为开源软体界的民间英雄,Linus 的一举一动都是万众瞩目,年轻开发者景仰他,视他为榜样。因此在 Linus 上传 Git 后,随即吸引到一群新血参与讨论和开发。

其中一个早期贡献者是来自捷克的 Petr Baudis。Linus 宣布 Git 的消息当天,Petr 就下载了程式码,为之著迷,并开始贡献。首先,鉴于早期的 Git 很难用,Petr 在 Git 的基础上开发了 git-pasky(pasky 是 Petr 的别名),这个专案后来成为 Cogito。如果将 Git 的基础是水管工程(plumbing),Cogito 就是陶瓷(porcelain)马桶和洗手台,它将 Git 包装得更容易使用。

在软体开发用语中,将低阶基础建设比喻成水管工程的用法已不可考,但“陶瓷”一词用来指高阶的包装工作最早起源自 Git 邮件列表。至今,Git 内部仍使用 plumbing 和 porcelain 二词来称呼低阶和高阶命令。

此外,Petr 还架设了 Git 第一个专案首页 git.or.cz,以及源码托管服务 repo.or.cz。这两个网址一直算是 Git 的“官方”网站──直到 GitHub 取代了它们。

Petr 是从外部贡献,在 Git 基础之上向上堆叠,向外架设服务。另一个早期贡献者,滨野纯(Junio Hamano)则是从内部切入,直接贡献 Git 本身。后来他是更从 Linus 手上接下 Git 维护人的工作,直到今天。

接班人

滨野纯(Junio Hamano)是一个来自日本的软体工程师。大概是 1995 年,毕业后工作不到一年,他就被他任职的公司 Twin Sun 派到洛杉矶,从此在美国定居。在那里,他遇到了当时也在同公司工作的 Paul Eggert。

Paul Eggert 维护过许多自由或开源软体专案,包括 RCS(一个更早的版控软体)和 Tar。目前,他是 UCLA 大学的教授,也是时区资讯资料库的维护人。

滨野纯受到 Paul 的影响,对开源软体的世界产生兴趣。尽管他并非 Kernel 开发者,他仍订阅了 Linux Kernel 等开源专案的邮件列表,纯粹因为好玩

2005 年 4 月,滨野纯在邮件列表上看到 Linux Kernel 与 BitKeeper 要分手的消息。滨野纯一直想要在开源软体界大展身手,而这个叫做 Git 的东西便是个好机会──全新专案,没有历史包袱,好上手。他下载了压缩档,花了约两个小时,一口气读完 Git 初代程式码,发现写得很漂亮,感到由衷佩服。

初版 Git 出现后,Linus 马上又加入了提交(commit)和检视差异(diff)的命令,但还没有合并(merge)的功能。

Linus 之前没有写过版控软体,但他用过三年的 BitKeeper,在那之前,他更有十年“版控人体”的经验,他知道自己想要的合并演算法应该长什么样。但合并的逻辑较为复杂,Linus 觉得可能使用脚本语言会比较合适,他写道

我一直在避免做 merge-tree,因为我希望有其他人来做我所描述的。我不擅长写脚本语言,这东西用 C 语言来写会很冗长,所以没意义。

过了一星期,谁也没上钩。滨野纯刚好正值两个专案的空窗期,有多馀时间,于是他用 Perl 把 Linus 想要的东西写出来,发布到邮件列表上。

我现在有一个 Perl 脚本利用了 rev-tree、cat-file、⋯⋯还有 merge(从 RCS 来的),又快又脏。

滨野纯大概从他的导师 Paul 那边有学到一些 RCS 的知识,对版控软体略懂。在邮件中,他还详细写了大约 30 个测试用例,涵盖各种分支情况。

当时已是深夜一点,而小孩早上七点起床,所以 Linus 平常十点就睡了。但看到滨野纯的 Perl 脚本,Linus 龙心大悦,忍不住回复

这就是我想要的,“又快又脏”才会让事情有进展。

他热切地继续与滨野纯讨论。

和 git-pasky 合并 II”这个讨论串原本是 Petr 问 Linus 要不要合并他的版本,后来离题变成讨论合并演算法,其间 Linus 也向众人解译为什么 Git 底层不需要处理档案改名。

从 4 月 14 日半夜的往后 48 小时,滨野纯与 Linus 在该讨论串上通了十几封信。滨野纯耐心的修改程式码,要做到 Linus 心目中的合并。字里行间不难发现滨野纯是 Linus 的忠实粉丝。例如,滨野纯会引用 Linus 四年前说过的金句“我永远是对”,也会适度地拍 Linus 的马屁。

在 4 月 16 日半夜,Linus 突然灵机一动,说他想到一个“狡滑的计划”。

该死,我的狡滑计划真是好东西。

或者也许因为它狡猾了,连我自己都感到困惑。但看起来它确实有效,而且几乎能瞬间完成合并。

Linus 巧妙的重用既有的索引,在其上引入了“阶段”的概念,大幅简化合并演算法的实作。

看到 Linus 的解法,滨野纯赞叹

我很喜欢这个解法,它非常简单、干净、灵活,而且优雅。这是那种我会心甘情愿地说“天啊!为什么我之前没想到!!!”的东西。

这意味著滨野纯之前写的 Perl 程式码将沦为白工,但新的解法实在太漂亮,滨野纯心服口服。

合并演算法只是个开端,之后滨野纯陆续向 Linus 贡献更多修补,逐渐赢得 Linus 的信任。

Linus 曾说过他不会长期维护 Git,等到时机成熟,他会将 Git 交给别人,然后回去做他的 Linux Kernel 本业。滨野纯是最明显的人选,Linus 欣赏他写程式的“好品味”。于是,三个多月后,7 月 26 日,Linus 宣布将 Git 维护人的工作交棒给滨野纯。

滨野纯也贴了一篇公告

正如有些人在 Linus 宣布之前似乎已经注意到的那样,kernel.org 上的官方 GIT 仓储现在由我拥有。如同 Linus 在他的讯息中所说,这并不意味著他要离开我们,所以请不要惊慌。

我也要感谢 Twin Sun(我的雇主)和 NEC,他们承诺将支持我以兼职方式开发 GIT。我预计每周会有 8 到 12 小时的工作时间,晚间和周末仍然是我的自由时间。我暂定的计划是将星期三和星期六作为主要的 GIT 工作日。

之前,每当想到一个点子,我就把修补丢邮件列表上,看哪个能被接受,完全依赖上游某个有好品味的人来筛选掉不好的。虽然这样和 Linus 一起工作很有趣,但遗憾的是,我浪费了他很多时间。

从今开始,身为“主仓储的牧羊人”,我会放慢速度,变得更加谨慎。至少目前,你会看到我的修补会像其他人一样,在进入主仓储之前,先在邮件列表上发布。

后来,在滨野纯的带领下,Git 1.0.0 正式在 12 月 21 日释出。19 年后的今天(本文发布于 2024 年 7 月),滨野纯任职于谷歌,至今他仍是 Git 的维护人。

本文提及 Linus 的次数比滨野纯多,不过 Git 之所以是现在的样子,最大功臣还是默默耕耘多年的滨野纯和其他开发者。“1% 的天分加上 99% 的努力”或许是老梗,但在 Git 与 Linux Kernel 等成功专案里都是事实。

GitHub 与 Ruby 人

虽然 Git 在早期引来不少关注,但仍是小众。2006 年 1 月,X Window System 团队放弃 CVS,改用 Git,滨野纯得知后还感到很惊喜,他没料到像 X Window System 这像的大专案会愿意大费周章转换版控系统。

自 BitKeeper 之后,分散式版管系统如雨后春笋般冒出,除了 Monotone 之外,还有 Mercurial、Darcs、Bazaar、Arch、Fossil 等。声势最不容小覻的是 Mercurial,作者 Olivia Mackall 晚了 Git 几天发布它,但功能已比当时的 Git 完整,而且更为使用者友善,之后更有 Google Code 和 BitBucket 的背书。总之,版控市场犹如战国时代,每家都占有一席之地。

真正把 Git 推上巅峰、变成主流的是 GitHub。或者根据 Linus 所述,是 Ruby 人,一群奇怪的人,让 Git 一夕爆红。

2007 年 2 月,Git 1.5 释出,Git 总算变得好用一点。当时在旧金山的 Ruby 聚会口耳相传著 Git 这个“新”东西。而 GitHub 的共同创办人 Tom Preston-Werner,最早是从他的同事 Dave Fayram 听到 Git。Tom 认为 Dave 是在 Ruby 社群传播 Git 的“零号病人”。

尽管在 Ruby 社群中 Git 广受好评,但当时唯一一家 Git 托管服务是 Petr Baudis 的 repo.or.cz,它功能阳春。例如,你的程式码在上面只能公开,没有私人仓储的选项。Tom 觉得其中大有商机。

2007 年,社群媒体当道,Facebook、YouTube、Twitter 都先红了一波。Tom 萌生了一个名叫 GitHub 的点子:一个给程式设计师用的社群媒体,一个让程式设计师分享 Git 仓储,交流意见的集散地(hub)。

2007 年 10 月某天,Tom 在一间旧金山的运动酒吧遇到 Chris Wanstrath。他们之前在 Ruby 聚会上认识,但不算熟识。Tom 主动向 Chris 打了招呼,他们聊了起来,Tom 谈起 GitHub 这个点子。Chris 听到后觉得有趣,就同意加入了。

当时 Tom 和 Chris 都还有正职工作,所以他们每晚和星期六用来开发 GitHub。Tom 设计介面,并使用一个名为 Grit 的 Ruby 套件来操作 Git 仓储;Chris 则使用 Ruby on Rails 开发网站。

三个月后,他们开始发送邀请给朋友们试用 GitHub。2008 年 2 月,第三个共同创办人 PJ Hyett 加入。4 月 10 日,GitHub 正式开站,它的副标题是 Social Code Hosting。

GitHub,2008 年 8 月

GitHub,2008 年 8 月

Ruby 的杀手级应用 Rails,在 GitHub 开站前夕就从 Subversion 移到了 GitHub,这无疑是帮 Git 在 Ruby 社群注入更大量的强心针。因为当时在写 Ruby 的人,八成都是在开发 Rails 应用。看到自己赖以为生的框架也用 GitHub ,更多 Ruby 人也欣然跟随。

Git 与 GitHub 有冲突的合并

Scott Chacon 不是一个寻常的 Git + Ruby 人,除了写 Ruby 程式外,他还是一个出色的讲师/写手/传道者。他会录制影片、写文件,教大家怎么使用 Git。不只如此,他对 Git 内部运作也有深入研究,曾经写过《Git Internals》这本电子书。

三年来,Git 的“官方”首页一直是 Petr Baudis 在 2005 年架设的 git.or.cz,而 Scott 想设计一个更为新手友善的 Git 首页。2008 年 7 月,他将 git.or.cz 上的内容整理过后,开设了一个新的首页 git-scm.com,并在 Git 邮件列表上询问 Git 核心开发成员(尤其是 Petr)的意见。

Git 在 Ruby 社群里虽然已流行了一阵子,但 Git 邮件列表上却鲜少出现 Ruby 人的踪迹。Git 核心开发成员,大部分是资深的 C 程式设计师,出没在邮件列表;而 Ruby 人,大部分是年轻一代的网页开发者,出没在实体聚会、网页式的论譠及 GitHub,搞不好一辈子都没用过邮件列表。两个族群互不来往,而 Scott 在 Git 邮件列表上那篇关于 git-scm.com 的讯息,是两个族群早期的少数几次接触之一。

另一个让 Git 核心成员伤脑筋的地方是 Tom 未经讨论,擅自用 Erlang 客制 Git Daemon,以满足 GitHub 单方面的需求。这是因为第一,Tom 对 C 语言不熟;第二,在邮件列表张贴讯息是一件吓人的事,列表上都是比你聪明的人,如果你写的东西没好好断行,就会看起来像个白痴。这过程实在太缓慢了,Tom 才会自己来。

git-scm.com 上有一个“托管由 GitHub 赞助”的标语,于是就有人质疑 Scott 背后的动机不单纯,也有人借此表达 GitHub 用 Git 赚钱,Git 核心开发者却分不到一杯羹的不满。但整体来说,正面回应居多,最终 git-scm.com 成为 Git 的官方首页,git.or.cz 功成身退。

Tom 是在某次 Ruby 聚会认识 Scott 的,当时 Tom 心想:“这家伙未来不是强大的盟友,就是危险的对手。”2008 年 10 月,Scott 加入 GitHub,继续他的 Git 传道之路。他写更多文件,提供顾问服务,到其他公司教大家使用 Git。他还写了一本书《Pro Git》,为 Git 官方推荐书。GitHub 的大外宣策略骤效了,它成功将 Git 发扬光大到 Ruby 以外的社群,GitHub 自己就是最大受惠者。

2008 年 10 月,谷歌赞助了第一届 GitTogether 会议,Git 和 GitHub 两组人马 20 馀人齐聚在谷歌总部山景城。他们放下之前的成见,因为他们很清楚,合作才会让彼此变得更强大。

GitTogether 2008

GitTogether 2008

后记

无法与 Git 和 GitHub 竞争,BitKeeper 后来被迫退出市场,它的团队在 2016 年将其程式码开源。这个祖父级的版控软体,曾经是 Git、Mercurial、Monotone 等软体的灵感来源,如今成了历史文物,供人观赏与研究。被问到有何感想,Larry McVoy 这么回应

事后诸葛亮最简单了。BitKeeper 的生意经营得很好,我们运营了 18 年,赚的钱足够让我和我的商业伙伴退休,不过还不够让每个人都可以选择退休。

我们曾经有一个类似 github 的服务,现在看来我们应该投入大量资金到那个服务,然后开源 BitKeeper。

我只能说,当你已经有一个金鸡母,要割舍它是很困难的。

早知道、早该、早会,我最大的遗憾不是钱,而是 Git 是个糟糕的版本控管系统。它让我抓狂的是,它的模型只是个压缩档伺服器。甚至 Linus 也曾向我承认这个设计很烂。它满足了 Linus 的需求,但他的需求不代表这是这个世界所需要的。

现在,Larry 享受他的退休生活,他平时喜欢和他的孩子们出海钓鱼。

Stack Overflow 在 2022 的调查中,Git 市占率高达 94%,以至于隔年 Stack Overflow 干脆放弃问大家用什么版控系统。

历史上从来没有一个版控软体能如此称霸市场,下一个能取代 Git 的会是什么?不少人说可能会与 AI 有关,但没人说得准,不过可以确信的是,过程中一定会有一连串的偶发事件和一群杰出的骇客。

支持一下
扫一扫,支持一下
  • 微信扫一扫
  • 支付宝扫一扫