Git 的故事(作者:场长)
Linus Torvalds 曾在一本书中写道,“创建 Linux 只是为了好玩”,但后面却引发了一场操作系统“革命”。他的第二项“重大技术发明”—— Git 也成了一场意外的“革命”,如今它已经成为软件工程师们的标准工具。
Linus 无法做到可扩展
1998 年是 Linux 大发展的一年,Sun、IBM 和 Oracle 等大公司均开始涉足 Linux生态。也是那年的春天,Linus 的第二个女儿出生了。他和家人一起从芬兰搬到加利福尼亚,开始了新生活。尽管 Linux 还没有给 Linus 带来多少经济收益,但他的事业和家庭生活都过得还不错。
另一方面,Linux 内核开发者社区日益壮大,原有的协作方式显得有些力不从心,Linus 开始难以跟上开发者代码修改的步伐,他个人成为整个过程中的“瓶颈”。
1998 年 9 月 28 日,Linus 像往常一样阅读 Linux 内核邮件列表。这时他看到了这样一条消息:请不要浪费时间创建这些补丁。这些东西在 vger 树中可用的。
就是这封电子邮件惹恼了 Linus。
此时,Linux 源代码的更改很大程度上依赖于 Linus 本人。
比如你想修改,可以向邮件列表中发送电子邮件,如果 Linus 看到并批准了,他会将你的补丁合并到他的版本中,并时不时地在 FTP 上发布新的版本。
Linus 很喜欢这种方式,因为这让他能够控制所有的代码更改。而团队里每个人也都信任 Linus 来管理 Linux 主代码。
然而,后来事情起了变化,资深 Linux 内核开发人员 David Miller 建立了一个名为 vger 的 CVS 服务器,一些人认为他们可以绕过 Linus,直接将更改提交到 vger。
这并不是 Linus 第一次遇到此类问题,他在邮件列表中很不高兴地说道:请注意,说“它在 vger 中,所以你在浪费时间”仍然是完全愚蠢的。它在 vger 中这一事实绝对没有影响,尤其是 vger 中有很多东西可能永远不会进入 2.2。
随后 ,Linus 和一些开发者之间发生了激烈的争论,有的人抱怨 Linus 的回复太慢,有时需要发三封邮件才能得到这位“仁慈独裁者”的答复。
“这些人应该照照镜子,” Linus 说道。“我每天要读这么多电子邮件。如果发三封邮件都嫌麻烦,我宁愿不要这个补丁。”
他留下了下面这条消息,然后愤愤然拂袖而去:
坦率地说,这次讨论(包括之前的其它讨论)让我很烦躁,并且平添了很多压力。那么请你们走开,各位伙伴们!现在不要再给我发抄送。我不感兴趣,我正在度假,我不想再听到这件事了。简单证明,请滚出我的邮箱!
Linus 的情绪爆发,促使一些人伸出了不同援手。
开源运动领袖之一、著名的《大教堂与集市》的作者埃里克·雷蒙德(Eric S. Raymond)冷静又理性地呼吁道:
各位,这些都是潜在倦怠的早期预警信号。注意这些并接受警告。Linus 的耐力令人惊叹,但他不是无限的。我们所有人(是的,这也包括你,Linus)都需要合作,以减轻中间关键人物的压力,而不是增加压力。
Larry McVoy 也伸出了援助之手。在一封题为“解决成长烦恼”的电子邮件中,他这样写道:
当前问题是 Linus 本人不具备可扩展性。我们无法期望看到内核的变化率继续增加,内核每天都变得越来越复杂和庞大,并且希望 Linus 能够跟上。但我们也不想让 Linus 失去对内核的控制和最终决定权,他已经一次又一次地证明了他在这方面很擅长。
要想办法让 Linus 身边有一些人来做他的一部分工作,比如添加一些工具来实现这一点。使这一切发生的机制便是分布式源码管理系统……
为此,Larry 开始开发一个名为 BitKeeper 的版本控制系统。
BitKeeper的由来
20 世纪 90 年代初,Sun Microsystems 推出了一款名为网络软件环境 (NSE) 的内部工具来管理内部的源代码,但 NSE 速度慢且用户体验极差,一些工程师甚至因为用它而崩溃辞职。Larry McVoy 是一位经验丰富的操作系统开发人员,具有高性能相关工作背景,Sun 的管理层找到他来改善 NSE 的性能。
当 Larry 查看 NSE 的代码时,他大吃了一惊。他说:“这玩意的设计完全没有考虑性能。”
他还发现 NSE 是建立在 SCCS 之上的,SCCS 是 20 世纪 70 年代的版本控制系统,比 CVS 和 Subversion 还要古老。
Larry 没有试图修复存在严重缺陷的 NSE,而是选择了一条不同的道路。
他用 Perl 重新写了 NSElite,在 SCCS 之上实现了重新同步/解析命令,类似于当今 Git 的clone/pull/push等命令。
NSElite 比 NSE 快多了,因此 Sun 的工程师们放弃了 NSE 选择了 NSElite。
Sun 的一位副总裁看到了“商机”,于是很快就组建了一个8人团队,用 C++ 重写了 Larry 的 Perl 脚本,并将其变成了一款名为“TeamWare” 的软件产品。
TeamWare 可能是第一个分布式版本控制系统 (DVCS),它后来成为开发 Sun Solaris 操作系统里必不可少的工具。
使用过 TeamWare 的工程师不会选择回头,这款软件与 CVS 和 Subversion 不同,TeamWare 允许人们将整个项目克隆到本地计算机,在本地进行更改,并在准备就绪时将自己的版本合并回远程版本。
TeamWare 团队是 8名经验丰富的 C 程序员 所组成。 C++ 是当时最热门的新语言,他们在开发 TeamWare 时学习了 C++。在 TeamWare 完成之前,Larry 仍然继续开发 NSElite,这让 TeamWare 团队颜面扫地:一个使用 Perl 的人比八个使用 C++ 的人厉害得多。
副总裁警告 Larry:“这件事已经报告给了 Scooter(Sun 的首席执行官 Scott McNealy)。如果你再发布它,你就会被公司解雇。”
1991 年,Larry 停止了 NSElite 的开发,但无法摆脱构建 DVCS 的想法。他认为商业软件会效仿 TeamWare,但事实并非如此。1997 年,Larry 开始开发一个名为 “BitKeeper”的分布式源码管理系统(DVCS)。
然而直到 1998 年 9 月,当他看到 Linus 在邮件列表中快要精疲力竭时,他才真正有动力认真对待这个 BitKeeper。
Linus 采用 BitKeeper
1998 年的秋天,Larry邀请 Linus Torvalds、David Miller 和 Richard Henderson 到他家做客。晚餐后,他们坐在地板上,开始集思广益,几个人想办法减轻 Linus 的工作量。他们在地板上画了三四个小时的图表,主要基于 TeamWare 在 Sun Microsystems 内部的工作方式。
Larry 很了解他们。在这个框架下,开发人员可以使用 BitKeeper 独立工作,互不干扰。当 Linus 进行最后的整合时,他不会丢失更改的历史记录,这让他更容易审查代码。
Linus 说:“好吧,如果你能做出来这个东西,而且它真的像你说的那样好用,我就用它。”
“没问题,我以前做过。大概也就需要6个月,” Larry 回答道。
Larry很快意识到自己低估了这项任务的复杂性。
他后来成立了一家名为 BitMover 的公司,并招聘了一些版本控制技术专家来帮助构建 BitKeeper。19 个月后,即 2000 年 5 月,BitKeeper 的第一个版本发布。那时,BitMover 是一个由7人组成的研发团队。
BitKeeper 的第一个版本包含一个名为 bk 的命令行工具和一些图形界面工具。bk 的clone/pull/push命令的功能类似于git中的 clone/pull/push。
当时,Sun 的 TeamWare 已经广受好评,BitKeeper 则被人们视为是 TeamWare 的升级版。
例如,TeamWare 只允许通过 NFS 文件系统传输数据,而 BitKeeper 可以通过 HTTP 传输文件,这使得其更加分布式。
因此,BitKeeper 很快为 BitMover 带来了健康的现金流。
到 2002 年,BitMover 已发展成为一个拥有 25 名员工的团队,完全自给自足,无需外部资金。
Larry McVoy,Linux 博览会,1999 年
2002 年 1 月,Linus 的工作量问题又一次浮出水面:开发人员提交的补丁要么需要很长时间才能得到回复,要么被Linus不小心忽略。
有人写了“一个温和的建议”来尝试解决这个问题。在讨论中,有人随口提到“BitKeeper 真的是一个很棒的工具”,这让 Linus 想起了三年前在 Larry 家吃的那顿晚餐。
Linus问道:“实际上有多少人已经在内核中使用 Bitkeeper 了?”
事实上,一些内核开发人员确实已经在使用 BitKeeper了。其中 Linux PowerPC (PPC) 团队于 1999 年 12 月开始测试 BitKeeper,BitMover 还设立了 bkbits.net 的域名和服务器来支持他们。
几天后,Linus 在邮件列表中开始测试 BitKeeper。从那时起,主要的 Linux 内核开发人员开始采用 BitKeeper。
其流程大致如下:
# Download the repository bk clone bk://linux.bkbits.net/linux-2.5 linux-2.5 bk clone linux-2.5 alpha-2.5 # Pull changes from another place cd alpha-2.5 bk pull bk://gkernel.bkbits.net/alpha-2.5 # Edit files and push changes back to the remote bk vi fs/inode.c bk push bk://gkernel@bkbits.net/alpha-2.5
要将更改发送给 Linus,你可以向邮件列表发送类似如下的内容:
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 内核开发人员免费使用 BitKeeper,但有一些附加条件。例如,要遵守免费用户许可证要求。包括:- 您无法关闭将使用日志发送到 BitMover 服务器的 Open Logging。
- 如果您正在使用其它版本控制软件,则不能使用 BitKeeper 进行版本控制。
- 如果您想与其他软件同时运行 BitKeeper,则必须获得 BitMover 的许可。
Linus 一直对专有软件持开放态度。他选择 GPL 作为 Linux 内核的唯一目的就是防止商业市场“玷污”Linux。
GPL 许可证符合他的需要,所以他就使用了它。但他从未认为所有软件都必须是免费软件;他认为作者有权以他们想要的方式分发他们的软件。对他来说,软件使用不是一场社会运动。
自由软件的拥护者并不认同他的观点。一些极端人士甚至认为专有软件是邪恶的。这些黑客更喜欢修改软件的自由,而不是 BitKeeper 的便利性。
Larry 感受到了来自社区的压力。为了解决这个问题,BitKeeper 团队在 2003 年建立了 BitKeeper 到 CVS 的镜像,让那些不想安装 BitKeeper 的人可以通过 CVS 访问代码历史记录。然而,与 BitKeeper 相比,CVS 的历史记录不完整,人们并不满意。“为什么我们的数据要被锁定在 BitKeeper 的专有格式中,为什么禁止我们使用其他工具读取我们自己的数据?”
为了解决这一问题,Samba 和 rsync 背后的作者——澳大利亚程序员 Andrew Tridgell (Tridge) 于 2005 年 2 月开始开发免费的 BitKeeper 客户端,以解决免费软件用户面临的问题。
Tridge 做了以下的事情。“这是 BitKeeper 地址,bk://thunk.org:5000。我们可尝试使用 telnet 连接。”
$ telnet thunk.org 5000 Trying 69.25.196.29... Connected to thunk.org. Escape character is '^]'. “我们已连接。为什么不输入帮助命令?” 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 和 Stuart Cohen(当时 OSDL 的首席执行官,现为 Linux 基金会)寻求帮助,希望 Tridge 停止这种做法。
Stuart Cohen 选择置身事外,认为这不关 OSDL 的事。但 Linus 不想失去 BitKeeper,所以他努力调解,试图找到双方都能接受的妥协方案。Tridge 坚信自己没有做错什么,认为第三方客户端对 BitKeeper 和内核开发人员来说都是双赢的。2005 年 4 月,他在 Freshmeat(后来合并到 SourceForge)上发布了SourcePuller。
在软件的 README 中,他写道:
开放的客户端与准确导入其他源代码管理工具的能力相结合将是一个巨大的进步,并且应该允许 BitMover 在商业环境中蓬勃发展,同时仍被自由软件社区使用。
我还想说,BitMover 完全有权根据自己的意愿授权 BitKeeper。我当然对 BitMover 对我的一些行为的描述感到失望,但请理解他们承受着很大的压力。在压力之下,人们有时会说出不该说的话。
Larry 不同意双赢的想法。支持内核开发需要花钱,他们不仅没有赚钱,而且还冒着损害现有商业模式的风险。为了保护 BitMover 的生计,Larry 选择撤销 BitKeeper 的免费使用许可。
经过数周的谈判,Linus 厌倦了充当调解人。由于没有更多免费的 BitKeeper 可用,Linus 开始变得愤怒。他在论坛上公开指责 Tridge ,称他“只是拆毁了新的东西”并“欺骗了人们”。Linus 本可以自己支付 BitKeeper 的费用,但他不能要求其他内核开发人员也这样做,因此他需要一个新的解决方案。他继续写道:
现在,我正在处理后果,我将编写自己的内核源代码跟踪工具,因为我不能再使用一个最好的工具了。没关系 - 我会处理自己的问题,非常感谢大家。
2005 年 4 月 6 日,Linus在邮件列表中宣布Linux 内核将与 BitKeeper 分道扬镳。他首先感谢 Larry 和他的团队在过去三年的帮助,然后他说他将下线一周以寻找替代者。最后他补充道:别费心告诉我有关颠覆的事情。如果你一定要告诉我,那就开始阅读“Monoton”吧。这似乎是最可行的选择。
Monoton
Monotone 的创始人是 Graydon Hoare。2001 年,住在加拿大的 Graydon 想和他的澳大利亚朋友更轻松地合作。于是他们开发了一个类似于当今持续集成 (CI) 的系统,当时这种系统还不为人所知。他们的系统确保代码始终通过测试。
2002 年,Graydon 对将版本控制与 CI 结合起来产生了兴趣。当时只有Aegis有这样的概念。Graydon 也看到朋友在使用 BitKeeper,于是觉得将 Aegis 与 DVCS 合并可能是一个机会。
于是 Monotone 应运而生。
值得一提的是,Graydon 后来加入了 Mozilla 并创建了 Rust 语言。
不幸的是,Linus 选择了一个糟糕的时间来使用 Monotone。Monotone 0.7 的性能不错,但从 0.14 开始,开发人员往里面添加许多验证机制。就在 Linus 下载 Monotone 之前,Graydon 发布了 v0.17,然后去度假了。此版本包含许多严格的检查,以确保在写入数据库之前的数据完整性,但这些检查没有进行优化,从而降低了性能。0.17 的发行说明中提到:
尚未完全优化;“pull”可能非常慢,并且占用大量 CPU
有人测试了下载 Monotone 和测试 Monotone 本身,耗时两个小时,占用了 71 分钟的 CPU 时间。“一只没有腿的、被麻醉的树懒可能速度更快,”他们这样评论道。
Linus 向 Monotone 开发人员报告了性能问题。
2005 年 4 月 10 日,Monotone 0.18 版本发布,许多操作的运行速度提高了两倍。虽然 Linus 在 0.18 版本中被列为贡献者,但根据 Monotone 开发人员 Nathaniel Smith 的话:
Linus 实际上没有为 Monotone 贡献任何代码,或者,据我所知,除了 git 之外,没有为任何 SCM 贡献代码。
他也没有真正提供任何建议,除了“这太慢了!”;-)。我之所以在这里归功于他,是因为在与他的讨论中,我找到了正确的测试用例,来追踪我们的主要性能错误之一。我犹豫了一会儿,是否应该点名表扬他,因为这很可能会给人们带来奇怪的想法,但我想,如果是其他人,我就会这么做,所以……*耸耸肩*。
同时,受到 Monotone 设计的启发,Linus 开始从头编写一些 C 代码。
Git v0.01:第一版本
2005年4月7日,Linus上传了一个叫Git的东西,并在邮件列表中写道:
这里有一个对您和任何疯狂黑客的快速挑战:
如果您想玩一些非常讨厌的东西(但也非常快),请查看 kernel.org:/pub/linux/kernel/people/torvalds/。
第一个向我发送 sparse-git 的变更日志树(以及提交和推送/拉取进一步变更的工具)的人将获得一颗金星和一个荣誉奖。
我在那里放了很多线索。
这是 Linus 第一次公开提到 Git。该 URL 包含以下文件和目录:
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有大约 1,000 行 C 代码: --------------------------------------------------------------------- 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 不同,Linus 上传的最早版本的 Git 编译为七个单独的可执行文件:
init-db update-cache show-diff write-tree read-tree commit-tree cat-file
其实命令很简单,在当前目录中创建一个名为 init-db 的目录,并在其中创建 256 个以十六进制数从到编号的子目录。
.dircache/objects00ff.dircache/objects该.dircache/objects目录代表具有以下类型对象的对象数据库:
- Blob:文件内容。
- 树:目录,本质上包含文件(blob)和目录(树)的名称。
- 变更集:由两棵树的名称定义,表示从树 A 到树 B 的变更。“变更集”是后来被称为“提交”的早期术语。
Linus 借用了 Monotone 的这个想法,但 Monotone 使用 SQLite 来存储 SHA-1 对象名称和内容,而 Linus 选择直接使用系统调用与文件系统。
SHA-1 的独特性意味着 Git 数据库几乎不会有两个名称不同但内容相同的对象。
如果某个对象的名称为ba93e701c0fe6dcd181377068f6b3923babdc150,Git 会将其存储.dircache/objects/ba/为名为 的文件93e701c0fe6dcd181377068f6b3923babdc150。
这七个可执行文件主要针对这个“内容可寻址”文件系统的不同操作。例如:
- write-tree:创建一个树对象,将目录的快照写入数据库。
- commit-tree:创建一个变更集,链接数据库中的两棵树,类似于今天的git commit。
- update-cache:将文件添加到.dircache/index,类似于今天的git add到暂存区。
在他的书《Just for Fun》中,他曾这样描述 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命令来读取它的更改历史记录:
# Assuming you are in the sparse-git directory mv .dircache .git mkdir .git/refs git log
Git 的早期贡献者
Git 的初始版本引发了人们热烈的讨论。几天后,Linus 为 Git 创建了一个专用邮件列表,让 Linux 内核邮件列表重回正轨。
第一个月,Git 邮件列表收到了大约 2,600 条消息,而历史上协作性最高的软件项目 Linux 内核在同一时期每月收到了 7,000-9,000 条消息。
对于版本控制领域的专家来说,Git 只是一个项目而已。Linus 首次上传的 Git 只包含一些低级操作。它缺少 clone和merge等基本命令,因此远不是一个可用的版本控制系统。而且 Linus 对 Git 的不断拔高无意中贬低了其他版本控制系统。这激怒了BitTorrent 的创建者 Bram Cohen。
当时,Bram 正在推广自己的版本控制系统 Codeville。Codeville 已经是一个成熟的 DVCS,可以与 Monotone 相媲美,并且拥有先进的合并算法。看到 Linus 和他的追随者们谈论合并算法时,Bram 觉得 Linus 这个局外人在重新发明轮子。Bram写道:“Git 是周末黑客,看起来就像周末黑客。”
Bram 说得很有道理,但这并不是普通的周末黑客攻击——这是 Linus Torvalds 的黑客攻击,Linux 内核创建者的黑客攻击。
作为开源软件界的民间英雄,Linus 的一举一动都备受关注。年轻的开发人员仰慕他,视他为榜样。因此,在 Linus 上传 Git 后,它迅速吸引了一群渴望加入讨论和开发的年轻开发人员。
早期贡献者之一是来自捷克共和国的 Petr Baudis。
就在 Linus 宣布 Git 的那天,Petr 下载了代码,他着迷不已,立即开始做出贡献。考虑到早期 Git 的可用性问题,Petr 开发了 git-pasky(pasky 是 Petr 的别名),最终成为Cogito。
如果说 Git 的基础是管道,那么 Cogito 就是瓷器 — 一个用户友好的界面。在软件开发术语中,将低级基础设施与管道进行比较并很难追溯,但使用“瓷器”来描述高级打包起源于Git 邮件列表。
直到今天,Git 仍然使用术语“管道”和“瓷器”分别指代低级和高级命令。此外,Petr 还为 Git 建立了第一个项目网站 git.or.cz,以及代码托管服务 repo.or.cz。在 GitHub 接管之前,这些网站一直是 Git 的“官方”网站。
Petr 通过在 Git 基础上进行构建并围绕它创建服务来为外部做出贡献。另一位早期贡献者 Junio Hamano 则直接从 Git 内部做出贡献。后来他从 Linus 手中接过 Git 的维护者一职。他至今仍担任这一职位。
继任者
Junio Hamano 是一名来自日本的软件工程师。1995 年左右,也就是他刚刚毕业一年后,他被雇主 Twin Sun 派往洛杉矶,从此便一直住在美国。在那里,他遇到了当时在同一家公司工作的 Paul Eggert。
Paul Eggert 维护过许多免费或开源软件项目,包括 RCS(早期的版本控制系统)和 Tar。他目前是加州大学洛杉矶分校的教授,也是时区数据库的维护者。
受Paul的影响,Junio 对开源软件产生了兴趣。虽然他不是内核开发人员,但他出于兴趣订阅了 Linux 内核等开源项目的邮件列表。
2005 年 4 月,Junio 在邮件列表中看到 Linus 宣布 Linux 内核将与 BitKeeper “分道扬镳”。
Junio 一直想在开源软件世界中留下属于自己的印记,而这个名为 Git 的新项目似乎是一个很好的机会 — 全新、没有历史包袱、易于理解。
他随后便下载了 tarball,花了大约两个小时一次性阅读了初始 Git 代码。代码写得如此出色令他印象深刻。
在 Git 首次发布后,Linus 很快添加了commit和diff命令,但尚未实现合并。
尽管 Linus 之前从未编写过版本控制软件,但他已经使用 BitKeeper 三年了。在此之前,他有十年的“版本控制人”经验。他知道自己想要什么样的合并算法。然而,由于合并逻辑很复杂,Linus 认为它可能更适合脚本语言。
Linus 这样写道:
我一直避免做合并树的事情,希望别人能做我所描述的事情。我确实不擅长编写脚本,但这显然是使用 C 来做很多事情毫无意义的事情。
一周过去了,没有人领受此任务。Junio 当时正在做项目,正好一段时间有空,所以他用 Perl 写了 Linus 想要的东西,并将其发布到邮件列表中。
我现在有了一个使用 rev-tree、cat-file 等和 merge(来自 RCS)的 Perl 脚本。快速而稍显粗略。
Junio 可以从导师 Paul 那里学到了一些 RCS 的知识,因此对版本控制软件有一定的了解。在他的电子邮件中,他还详细介绍了大约 30 个测试用例,涵盖了各个代码分支。
当时已经是凌晨 1 点了,孩子们早上 7 点起床,Linus 通常晚上 10 点就要睡觉了。但看到 Junio 的 Perl 脚本,Linus 兴奋不已,忍不住回复道:这正是我想要的!Q'n'D 就是让事情开始运转的方式。他热切地继续与 Junio 讨论。
“与 git-pasky II 合并”最初是由 Petr 询问 Linus 有关合并其版本开始的,但是两个人很快就转向了关于合并算法的讨论。
在讨论中,Linus 还解释了为什么 Git 的内部不需要处理文件重命名。
从 4 月 14 日午夜开始的 48 小时内,Junio 和 Linus 在该线程中交换了十几封电子邮件。Junio 耐心地修改代码,以符合 Linus 的合并期待与愿景。
从他的言辞中可以明显看出,Junio 是 Linus 的忠实粉丝。例如,Junio 会引用 Linus 四年前说过的话“我总是对的”,并充分地“奉承” Linus。
4月16日午夜,Linus 灵机一动,发布邮件提到他自己开始有一个“狡猾的计划”。妈的,我的狡猾计划真是个好东西。或者它太狡猾了,连我自己都感到困惑。但它看起来确实有效,而且它允许几乎即时的合并。
其实是 Linus 巧妙地重用了现有的索引,并在其之上引入了“阶段”的概念,大大简化了合并的实现。
Junio对 Linus 的解决方案感到“惊叹”:我非常喜欢这个!它非常简单 、清晰、灵活,堪称优雅的典范。这是我会高兴地说“谢天谢地!我怎么没有先想到这个!!!”的事情之一。
这意味着 Junio 之前的 Perl 代码将被浪费扔掉,但新的解决方案如此出色, Junio 全心全意地接受了它。
合并算法只是一个开始,Junio继续为Linus贡献更多的代码补丁,逐渐赢得了Linus的信任。
Linus 之前曾提到过他不会长期维护 Git。
一旦时机成熟,Linus 就会将 Git 交给其他人,然后回到 Linux 内核的主要工作岗位上。Junio 是很明显的“继任”选项,Linus 也欣赏他编写代码的“良好品味”。
因此三个月后,即 7 月 26 日,Linus宣布将 Git 维护者的角色移交给 Junio。
Junio 也发了一条公告:
我们中的一些人似乎在 Linus 宣布之前就已经注意到了,kernel.org 上的官方 GIT 存储库现在归我所有。正如 Linus 在消息中所说,这并不意味着他要离开我们,所以请大家不要惊慌。
我还要感谢 Twin Sun Inc(我的雇主)和 NEC 承诺从现在起支持我兼职从事 GIT 工作。我预计每周白天工作 8 到 12 小时;晚上和周末和以前一样属于我自己的时间。我的初步计划是将周三和周六作为我从事 GIT 的主要时间。
以前,我会根据脑海中浮现的想法制作尽可能多的补丁,然后将它们全部放入列表中,看看哪些可以保留,并依靠上游有品味的人删除所有不好的补丁。虽然与 Linus 一起工作很有趣,但遗憾的是,我最终浪费了他很多时间。
从现在起,我会放慢脚步,更加小心谨慎地担任“主存储库的守护者”。至少现在,在进入主存储库之前,您会看到我的补丁像其他人的补丁一样发布在列表中。
在Junio的领导下,Git 1.0.0于12月21日发布。而即便过了19年,截至2024年7月,Junio 已经移到 Google 工作,仍然维护着 Git。
本文提到 Linus 的次数多于 Junio,但 Git 如今最大的贡献者是 Junio 和其他开发人员在幕后坚持不懈的努力结果。“1% 的灵感加上 99% 的汗水”可能是一句陈词滥调,但对于 Git 和 Linux 内核等成功的项目来说,这句话是绝对适用的。
GitHub 与 Ruby 开发者
尽管 Git 早期就获得了相当多的关注,但它仍然相当小众。2006 年 1 月,X Window System 团队从 CVS 切换到 Git。这已经足以让Junio惊叹不已。他没想到像 X Window System 这样的大项目会愿意经历更换版本控制系统的麻烦。
在 BitKeeper 之后,许多 DVCS 开始涌现。除了 Monotone,还有 Mercurial、Darcs、Bazaar、Arch 和 Fossil。
其中最引人注目的是 Olivia Mackall 创建的 Mercurial。它在 Git 发布几天后发布,功能更完善,界面更友好。它还得到了 Google Code 和 BitBucket 的支持。
这时的版本控制市场就像狂野的西部牛仔,每个系统都独树一帜。
真正将 Git 推向顶峰并成为主流的是 GitHub。或者用 Linus 的话来说,是 Ruby 的作者,一个奇怪的人,他让 Git 一夜成名。
2007 年 2 月,Git 1.5 发布,终于让普通人更容易使用 Git。当时Git 是旧金山 Ruby 聚会上热议的新事物。GitHub 联合创始人 Tom Preston-Werner 第一次听说 Git ,是从他的同事 Dave Fayram 那里听说的。
Tom 认为 Dave 是Ruby 社区中 Git 采用率传播的“零号病人”。
尽管 Git 在 Ruby 社区中非常受欢迎,但当时唯一可用的 Git 托管服务是 Petr Baudis 的 repo.or.cz,而且功能相当地基础。例如,您的代码必须是公开的,没有私有存储库的选项。
Tom 在那里看到了巨大的商业和发展机会。
2007 年,社交媒体蓬勃发展,Facebook、YouTube 和 Twitter 引领互联网之潮流。Tom 提出了一个名为 GitHub 的想法:一个供程序员共享 Git 存储库和交流想法的社交媒体中心。
2007 年 10 月的一天,Tom 在旧金山的一家体育酒吧遇到了 Chris Wanstrath。他们之前在 Ruby 聚会上见过面,但彼此并不太熟悉。Tom 主动搭讪,分享了他的 GitHub 想法,Chris 觉得很有趣,同意加入。
当时,Tom 和 Chris 都有全职工作,所以他们利用晚上和周六的时间开发 GitHub。Tom 设计了用户界面,并使用名为 Grit 的 Ruby 库与 Git 存储库进行交互,而 Chris 则使用 Ruby on Rails 开发了网站。
三个月后,他们开始向朋友们发出邀请来测试 GitHub。
2008 年 2 月,PJ Hyett 加入,成为第三位联合创始人。4 月 10 日,GitHub 正式上线,标语为“社交代码托管”。
![](https://cdn.easycorp.cn/web/data/upload/zentao/202407/f_65beba08331626980681f63a72fb7932.png)
GitHub,2008 年 8 月上线
Rails 是 Ruby 的杀手级应用。
在 GitHub 发布之前,它从 Subversion 切换到了 GitHub,这让 Git 在 Ruby 社区中获得了更大的推动力。
合并 Git 和 GitHub 时的冲突
Scott Chacon 并不是典型的 Git + Ruby 开发者。除了编写 Ruby 代码外,他还是一位出色的演讲者、作家和传播者。他制作视频、撰写文档并教人们如何使用 Git。他还对 Git 内部机制有着深入的了解,并撰写了一本名为“Git 内部机制”的电子书。三年来,Git 的“官方”主页一直是 git.or.cz,由 Petr Baudis 于 2005 年建立。
Scott 想为初学者创建一个更方便用户的网站。2008 年 7 月,他重新整理了 git.or.cz 的内容,并推出了一个新主页git-scm.com。然后,他在 Git 邮件列表中向 Git 核心开发人员(尤其是 Petr)征求反馈。
虽然 Git 在 Ruby 社区流行了一段时间,但 Ruby 开发人员很少出现在 Git 邮件列表中。大多数 Git 核心开发人员都是活跃在邮件列表中的经验丰富的 C 程序员,而 Ruby 人群大多是年轻的 Web 开发人员,他们经常参加聚会、参加 Web 论坛和 GitHub,可能一生中从未使用过邮件列表。这两个群体之间互动不多,Scott 在 Git 邮件列表上发布的关于 git-scm.com 的帖子是他们之间为数不多的早期互动之一。
Git 核心开发人员面临的另一个问题是,Tom 未经任何讨论就使用 Erlang 分叉并定制了 Git 守护进程,以满足 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 人齐聚谷歌山景城总部。
他们放下分歧,深知任何组织只有共同努力,才能变得更强大。
![](https://cdn.easycorp.cn/web/data/upload/zentao/202407/f_9fcc33cfe360c4568de7827e346640ef.jpg)
GitTogether 2008
结语
由于无法与 Git 和 GitHub 竞争,BitKeeper 最终退出市场。在 2016 年,该团队开源了其代码。这个启发了 Git、Mercurial、Monotone 等的分布式代码的祖辈软件,现在已成为人们观察与研究的历史记录。
当被问及开源的想法时,Larry McVoy回答道:
事后看来一切都很顺利。BitKeeper 业务发展良好,我们经营了 18 年。它赚的钱足以让我和我的生意伙伴靠我们的收入退休。
另一方面,我们赚的钱不足以让每个人退休(如果他们想退休的话)。我们有一个类似 GitHub 的产品,很明显,我们应该投入大量资金并开源 BitKeeper。
我只能说,当你有东西可以支付账单时,做出这样的选择是极其困难的。
应该、可以、会,我最大的遗憾不是钱,而是 Git 是一个糟糕的 SCM 借口。它的模型是一个 tarball 服务器,这让我很抓狂。甚至 Linus 也向我承认,这是一个糟糕的设计。
它做了他想要的,但他想要的不是世界应该想要的。
现在的Larry 很享受退休生活,比如他喜欢和孩子们一起钓鱼。
在 Stack Overflow 某一年的一项调查中,Git 的市场份额占比为 94%,第二年,Stack Overflow 便不再询问人们使用哪种版本控制系统。
历史上从未有版本控制系统像 Git 一样占据市场主导地位。
那么,下一个取代 Git 的会是什么?很多人说它可能与人工智能有关,但没有人能肯定地回答。
而我们可以肯定的说,这一转变很可能涉及一系列偶然事件,还有一群才华横溢的技术黑客。
那人也可能就是你。
_________
原文链接:https://mp.weixin.qq.com/s/jChEKH2D-jowj04Tl46EmQ
声明:本文系转载,文章版权属于原作者,如有疑问请联系删除。
![](https://cdn.easycorp.cn/web/data/contact/avatar/2845263372.png)
![](/theme/default/default/images/main/icon-contact-split.png)
![](/theme/default/default/images/main/icon-contact-split.png)
![](/theme/default/default/images/main/icon-contact-split.png)
![](https://cdn.easycorp.cn/web/data/contact/18562550650.png)