【外评】Git 的故事:这次没那么有趣

Linus Torvalds 曾在一本书中写道,他创建 Linux 只是为了好玩,但最终却引发了一场革命。Git 是他的第二个重要创造,也是一场意外的革命。现在,它已成为软件工程师的标准工具,但至少对莱纳斯来说,它的起源故事并不那么有趣。

Linus 不具备扩展性

1998 年对 Linux 来说是重要的一年。Sun、IBM 和甲骨文等大公司开始涉足 Linux。那年春天,莱纳斯的第二个女儿出生了。他全家从芬兰搬到加利福尼亚州已经快一年了,他们已经适应了新的生活。尽管 Linux 还没有给莱纳斯带来多少经济收益,但他的事业和家庭生活都过得很好。

另一方面,Linux 内核开发者社区在不断壮大,而现有的合作方式已显得力不从心。莱纳斯开始努力跟上开发者修改代码的步伐,成为这个过程中的瓶颈。

1998 年 9 月 28 日,莱纳斯像往常一样阅读 Linux 内核邮件列表时,看到了这样一条信息:

请不要把时间浪费在创建这些补丁上。这些东西在 vger 树中已经很实用了。

这条信息惹恼了莱纳斯。Linux 代码的修改在很大程度上依赖于 Linus 本人。如果你想修改代码,就给邮件列表发邮件,如果莱纳斯看到并批准了,他就会把你的补丁并入他的版本,并不时地在 FTP 上发布新版本。莱纳斯喜欢这种工作方式,因为这样他就能控制所有改动。每个人都信任莱纳斯来管理 Linux。

然而,自从资深 Linux 内核开发者大卫-米勒(David Miller)建立了一个名为 vger 的 CVS 服务器后,一些人认为他们可以绕过莱纳斯,直接向 vger 提交修改。这已经不是莱纳斯第一次遇到这个问题了,他在邮件列表中做出了令人不快的回应:

请注意,说 “它在 vger 中,所以你是在浪费时间 “仍然是完全彻底的愚蠢。它在 vger 中这一事实完全没有影响,尤其是 vger 中有很多东西可能永远都不会进入 2.2 版。

随后,莱纳斯和几位开发者展开了激烈的争论,他们抱怨莱纳斯的回复太慢,有时需要发三封邮件才能得到这位 “仁慈的独裁者 “的回复。

“这些人应该照照镜子,”莱纳斯想。”我每天要读这么多封邮件。如果发三封邮件都嫌麻烦,我宁愿不要这个补丁。”他在暴走前留下了这句话

坦率地说,这次讨论(以及之前的其他讨论)让我很烦躁,也增加了我的压力。

走开吧,各位。或者至少别再抄送我了。我不感兴趣,我在休假,我不想再听了。总之,从我的邮箱里滚出去。

莱纳斯的情绪失控引发了一些人的帮助。

开放源代码运动的领导者之一、著名论文《大教堂与集市》的作者埃里克-雷蒙德(Eric S. Raymond)冷静地劝说道

人们,这些都是潜在职业倦怠的预警信号。请注意它们,并引以为戒。莱纳斯的耐力令人惊叹,但并非无穷无尽。我们所有人(是的,也包括你,莱纳斯)都需要合作,减轻而不是增加中间关键人物的压力。

Larry McVoy 也伸出了援助之手。他在一封题为 “成长之痛的解决方案 “的电子邮件中写道:

问题在于 Linus 无法扩展。内核每天都在变得更复杂、更庞大,我们不能指望内核的变化速度继续增加,也不能指望 Linus 能够跟上。但我们也不想让莱纳斯失去对内核的控制权和最终决定权,他已经一次又一次地证明了他在这方面的能力。

找出一种方法,让莱纳斯身边能有一些人完成他的部分工作。添加一些工具,使之成为可能。

实现这一切的机制就是分布式源代码管理系统……

Larry当时正在开发一个名为 BitKeeper 的新版本控制系统。

BitKeeper 的起源

20 世纪 90 年代初,Sun Microsystems 推出了一款名为 Network Software Environment (NSE) 的内部工具来管理他们的代码,但 NSE 运行缓慢,用户体验极差。一些工程师甚至因此而辞职。

拉里-麦克沃伊(Larry McVoy)是一位经验丰富的操作系统开发人员,具有性能工作背景,Sun 的管理层找到他,希望他能改善 NSE 的性能。

当 Larry 查看 NSE 的代码时,他大吃一惊。”这东西在设计时根本没有考虑到性能。他还发现,NSE 是在 SCCS 的基础上构建的,而 SCCS 是 20 世纪 70 年代的版本控制系统,比 CVS 和 Subversion 还要古老。Larry 没有试图修复漏洞百出的 NSE,而是选择了另一条道路:他用 Perl 编写了 NSElite,在 SCCS 的基础上实现了 resync/resolve 命令,类似于今天 Git 的 clone/pull/push 命令。

NSElite 比 NSE 快得多,因此 Sun 的工程师们开始放弃 NSE,转而使用 NSElite。看到这一点,Sun 的一位副总裁看到了商机,于是组建了一个八人团队,用 C++ 重写 Larry 的 Perl 脚本,并将其转化为名为 TeamWare 的产品。

TeamWare 可能是第一个分布式版本控制系统(DVCS),它最终成为开发 Sun Solaris 操作系统的关键。使用过 TeamWare 的工程师们再也回不去了:与 CVS 和 Subversion 不同,TeamWare 允许您将整个项目克隆到本地机器,在本地进行修改,并在准备就绪时将您的版本合并回远程版本。

团队由八名经验丰富的 C 程序员组成。由于 C++ 是当时最热门的新语言,他们在开发 TeamWare 的同时学习了 C++。在 TeamWare 完成之前,Larry 继续开发 NSElite,这让 TeamWare 团队的形象大打折扣:一个人使用 Perl 超过了八个人使用 C++。然后,副总裁告诉 Larry:”这已经报告给了 Scooter(Scott McNealy,Sun 的首席执行官)。如果你再发布它,你就会被解雇。”

1991 年,Larry 停止了 NSElite 的开发,但仍无法打消开发 DVCS 的念头。他以为商业软件会追随 TeamWare 的脚步,但没有。1997 年,Larry 开始开发名为 BitKeeper 的 DVCS。然而,直到 1998 年 9 月,当他在邮件列表上看到 Linus 濒临倦怠时,他才真正有动力认真对待 BitKeeper。

Linux 内核采用 BitKeeper

1998 年秋天的一天,Larry 邀请 Linus Torvalds、David Miller 和 Richard Henderson 到他家做客。晚饭后,他们坐在地板上,开始集思广益,讨论如何减少 Linus 的工作量。他们在地板上画了三四个小时的图表,大部分都是基于 TeamWare 在 Sun Microsystems 内部的工作方式。拉里非常了解他们。

在这个框架中,开发人员可以使用 BitKeeper 独立工作,互不干扰。当莱纳斯进行最终整合时,他不会丢失修改的历史记录,从而更容易审查代码。

“好吧,如果你造出来了,而且能像你说的那样工作,我就用它。”莱纳斯说。
“没问题,我以前做过这个。大概需要六个月的时间。”拉里回答道。

拉里很快意识到自己低估了任务的复杂性。他成立了一家名为 BitMover 的公司,并招募了一些版本控制专家来帮助构建 BitKeeper。19 个月后,2000 年 5 月,BitKeeper 的第一个版本发布了。当时,BitMover 是一个七人团队。

第一版 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 Expo, 1999

2002 年 1 月,莱纳斯的工作量问题再次出现。开发人员提交的补丁要么需要很长时间才能得到回复,要么被忽略。有人写了 “一个小建议”,试图解决这个问题。在讨论中,有人不经意地提到:”BitKeeper 确实是个不错的工具,”这让莱纳斯想起了三年前在拉里家的那次晚餐。莱纳斯问道:”究竟还有多少人已经在使用内核中的 bitkeeper?

事实证明,一些内核开发人员已经在使用 BitKeeper。Linux PowerPC(PPC)团队于 1999 年 12 月开始测试 BitKeeper,BitMover 建立了一个 bkbits.net 服务器为他们提供支持。

几天后,即 2002 年 2 月 5 日,邮件列表中看到 Linus 开始测试 BitKeeper。从那时起,主要的 Linux 内核开发者都开始采用 BitKeeper。你不一定非得使用 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 

要向莱纳斯发送更改,您可以向邮件列表发送电子邮件,内容如下

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,但也有一些附加条件。例如,免费用户许可证要求

  • 你不能关闭 Open Logging(向 BitMover 服务器发送使用日志)。
  • 如果你正在使用版本控制软件,就不能使用 BitKeeper 进行版本控制。
  • 如果你想在运行 BitKeeper 的同时运行其他类似软件,你必须获得 BitMover 的许可。

自由软件拥护者云集的 Linux 社区对此反应不一。有些人对这些条款嗤之以鼻,有些人则避而远之。不过,对于莱纳斯和主要的内核开发人员来说,关键是 BitKeeper 减少了他们的工作量。由于当时没有更好的替代方案,他们接受了 BitKeeper 的条款,因为它提供了便利。

莱纳斯一直对专有软件持开放态度。他选择 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,发现输出是一系列 SCCS 格式的文件。这样,”逆向工程 “就完成了一大半,剩下的就是编写程序了。

莱纳斯不知怎么知道了特里奇在做什么–也许是特里奇私下告诉他的。莱纳斯随后告诉了他的朋友拉里。拉里对此不以为然。免费的第三方客户端会毁掉 BitKeeper 的商业模式。拉里向莱纳斯和斯图尔特-科恩(Stuart Cohen,时任 OSDL(现 Linux 基金会)首席执行官)寻求帮助,想让特里奇停下来。

斯图尔特-科恩选择置身事外,认为这与 OSDL 无关。但莱纳斯不想失去 BitKeeper,所以他努力调解,试图找到一个双方都能接受的折中方案。特里奇坚信自己没有做错,他认为第三方客户端对 BitKeeper 和内核开发者来说是双赢的。2005 年 4 月,他在 Freshmeat(后来并入 SourceForge)上发布了 SourcePuller。他在 README 中写道:

一个开放的客户端,再加上能准确导入其他源代码管理工具的能力,本应是向前迈进的一大步,本应使 BitMover 在商业环境中蓬勃发展,同时仍被自由软件社区所使用。

我还想说的是,BitMover 有权按照自己的意愿许可 BitKeeper。当然,我对 BitMover 如何描述我的一些行为感到失望,但请理解他们正承受着巨大的压力。在压力下,人们有时会说出一些也许不该说的话。

拉里不同意双赢的想法。支持内核开发需要花钱。他们不仅赚不到钱,还要冒着损害现有商业模式的风险。为了保护 BitMover 的生计,他选择取消 BitKeeper 的免费使用许可。

经过几周的谈判,莱纳斯厌倦了扮演调解人的角色。没有了免费的 BitKeeper,莱纳斯勃然大怒。他在论坛上公开指责特里奇,说他 “只是拆掉了一些新东西”,”把人们害惨了”。莱纳斯本可以自己花钱买 BitKeeper,但他不能要求其他内核开发者也这么做,所以他需要一个新的解决方案。他继续写:

现在,我正在处理余波,我将编写自己的内核源代码跟踪工具,因为我不能再使用最好的工具了。没关系,我的问题我自己解决,非常感谢。

2005 年 4 月 6 日,Linus 在邮件列表中宣布 Linux 内核将与 BitKeeper 分道扬镳。他首先感谢 Larry 和他的团队在过去三年中提供的帮助。然后,他说他将离线一周来寻找替代者。最后,他补充道

别跟我提什么颠覆。如果你一定要听,那就去读读 “单音 “吧。这似乎是最可行的选择。

Monotone

Monotone 由 Graydon Hoare 创建。2001 年,居住在加拿大的 Graydon 希望与他的澳大利亚朋友更轻松地合作。于是,他们开发了一个类似于今天的持续集成(CI)的系统,当时还没有被广泛熟知。他们的系统确保代码始终通过测试。

2002年,格雷登开始对把版本控制和CI结合起来感兴趣。当时,只有Aegis公司有这样的概念。格雷登还看到他的朋友们在使用BitKeeper,他认为把Aegis与DVCS合并可能是一个机会。这就是Monotone的由来。

值得一提的是,格雷登后来加入了 Mozilla,并创建了 Rust 编程语言。

不幸的是,莱纳斯选择了一个糟糕的时机来玩 Monotone。Monotone 0.7 的性能还算不错,但从 0.14 版开始,开发人员开始添加许多验证机制。就在 Linus 下载 Monotone 之前,Graydon 发布了 v0.17,然后就去度假了。这个版本包含了大量严格的检查,以确保数据在写入数据库前的完整性,但这些检查并没有经过优化,从而降低了性能。0.17 版的发布说明中提到

尚未完全优化;”拉取 “可能会非常慢,并使用大量 CPU

有人测试了用 Monotone 本身下载 Monotone,结果花了两个小时,CPU 占用 71 分钟。”他们评论说:”一只被严重镇静的没有腿的树懒可能会更快。

Linus 向 Monotone 开发人员报告了性能问题。2005 年 4 月 10 日,Monotone 0.18 发布,许多操作的运行速度至少快了一倍。虽然莱纳斯在 0.18 版本中被列为贡献者,但根据 Monotone 开发人员纳撒尼尔-史密斯(Nathaniel Smith)的说法:”莱纳斯是我们的贡献者:

莱纳斯实际上并没有为 Monotone 贡献任何代码,据我所知,除了 git 之外,他也没有为任何 SCM 贡献代码。除了 “这个太慢了!”之外,他也没有提供任何建议。)之所以说他是功臣,是因为在与他的讨论中,我找到了正确的测试用例来追踪我们的一个主要性能 bug。我曾犹豫过是否应该把他的名字写在上面,因为这很可能会让别人产生奇怪的想法,但我想,如果是其他人,我也会这么做的,所以……*耸耸肩*。

与此同时,受到 Monotone 设计的启发,莱纳斯开始从头开始编写一些 C 代码。

Git v0.01:初体验

2005 年 4 月 7 日,莱纳斯上传了一个名为 Git 的东西,并在邮件列表中写道:

这里有一个对你和所有疯狂黑客的挑战:如果你想玩一个非常恶心(但也非常快速)的东西,请访问 kernel.org:/pub/linux/kernel/people/torvalds/。

第一个把 sparse-git 的更新日志树(以及提交和推送/拉取进一步修改的工具)发给我的人将获得一颗金星和一个荣誉奖。我在里面放了很多线索。

这是莱纳斯第一次公开提到 Git。

网址上有以下文件和目录:

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 有大约 1000 行 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 不同,莱纳斯上传的最早版本的 Git 编译成了七个独立的可执行文件:

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

init-db 命令非常简单。它在当前目录下创建了一个名为 .dircache/objects 的目录,然后在 .dircache/objects 目录下创建了 256 个子目录,这些子目录以十六进制从 00 ff 进行编号。

.dircache/objects 目录代表一个对象数据库,其中包含以下类型的对象:

  • Blob: 文件内容。
  • Tree:目录,主要包含文件名(Blob)和目录名(树)。
  • 变更集:由两棵树的名称定义,代表从树 A 到树 B 的变化。”变更集 “是后来称为 “提交 “的早期术语。

这里的对象名称不是文件或目录名称,而是其压缩内容的 SHA-1 哈希值。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 添加到暂存区域。

Linus 在 Monotone 中一看到基于 SHA-1 的命名方式就喜欢上了,因为它很简单。简单也是莱纳斯喜欢 Unix 的原因。他在《Just for Fun》一书中描述了 Unix:

这种简单的设计是 Unix 吸引我和大多数人的地方(至少是我们这些极客)。在 Unix 中,几乎所有的操作都只需要六个基本操作(称为 “系统调用”,…

它为你提供了足以完成所有操作的构件。这就是简洁设计的意义所在。

Git 秉承了这一理念,其数据模型比 CSV、Subversion 或 BitKeeper 都要简单。它主要存储目录更改前后的状态,而不跟踪具体更改了哪些文件或行。这些信息已经包含在目录树的前后状态中。

莱纳斯用两天时间写出的 Git 原型非常简单。没有额外的验证。没有关系数据库。只有 C 代码、SHA-1 哈希值和系统调用,完全根据 Linus 的需求量身定制。与此同时,Monotone 项目已进入第三个年头,功能丰富,必须满足广泛的用例需求。此外,Monotone 的原作者 Graydon 在休假前添加了大量未经优化的代码,导致项目失去了领导力。由于处于劣势,Monotone 的速度无法与 Git 相比。

莱纳斯最初上传的 sparse-git.tar.bz2 文件很可能是有史以来第一个 Git 仓库。Sparse 是 Linus 于 2003 年编写的 C 语言静态分析器。如果你仍然对莱纳斯的挑战感兴趣,可以稍微修改一下提取出来的 sparse-git.tar.bz2,然后使用现在的 git log 命令来阅读修改历史:

# Assuming you are in the sparse-git directory
mv .dircache .git
mkdir .git/refs
git log

视频:https://youtu.be/idLyobOhtO4

Git 的早期贡献者

Git 的最初版本引发了热烈的讨论。几天后,莱纳斯为 Git 创建了一个专门的邮件列表,让 Linux 内核邮件列表重回正轨。在第一个月,Git 邮件列表收到了约 2,600 条信息,而 Linux 内核这个史上协作最多的软件项目在同一时期每月收到 7,000-9,000 条信息。

对于版本控制领域的专家来说,Git 只是另一个项目。Linus 首次上传的 Git 只包含一些低级操作。它缺乏clonemerge等基本命令,因此远非一个可用的版本控制系统。而且,莱纳斯对 Git 的不断赞美无意中贬低了其他版本控制系统。这激怒了 BitTorrent 的创建者布拉姆-科恩(Bram Cohen)。

当时,布拉姆正在推广自己的版本控制系统 Codeville。Codeville 已经是一个成熟的 DVCS,可与 Monotone 相媲美,并拥有先进的合并算法。看到莱纳斯和他的追随者们是如何谈论合并算法的,布拉姆觉得莱纳斯这个局外人是在重新发明轮子。”布拉姆写道:”Git 是周末黑客,看起来像周末黑客。

布拉姆说到了点子上,但这不是普通的周末黑客–这是 Linus Torvalds 的黑客,Linux 内核创造者的黑客。作为开源软件界的民间英雄,莱纳斯的一举一动都备受瞩目。年轻的开发者仰慕他,视他为榜样。因此,在莱纳斯上传 Git 之后,很快就吸引了一批渴望加入讨论和开发的年轻开发者。

来自捷克共和国的 Petr Baudis 就是早期的贡献者之一。在 Linus 发布 Git 的当天,Petr 就下载了代码,并被深深吸引,开始贡献自己的力量。鉴于早期 Git 的可用性问题,Petr 开发了 git-pasky(pasky 是 Petr 的别名),最终成为了 Cogito。如果说 Git 的基础是管道,那么 Cogito 就是瓷器–用户友好的界面。

在软件开发术语中,很难将底层基础架构与管道相提并论,但用 “瓷器 “来描述高层包装,则起源于 Git 邮件列表。时至今日,Git 仍用 “plumbing “和 “chorcelain “分别指代低级和高级命令。

此外,Petr 还为 Git 创建了第一个项目主页 git.or.cz,以及代码托管服务 repo.or.cz。在 GitHub 接管之前,这些网站一直是 Git 的 “官方 “网站。

Petr 在 Git 的基础上创建了相关服务,为 Git 做出了外部贡献。另一位早期的贡献者 Junio Hamano 则直接从 Git 本身做出贡献。后来,他接替 Linus 成为 Git 的维护者。他至今仍担任这一职务。

继任者

Junio Hamano 是一位来自日本的软件工程师。1995 年左右,也就是毕业一年后,他被雇主 Twin Sun 派往洛杉矶工作,此后一直生活在美国。在那里,他遇到了当时也在同一家公司工作的保罗-埃格特。

保罗-埃格特维护了许多自由或开源软件项目,包括 RCS(一种早期的版本控制系统)和 Tar。他目前是加州大学洛杉矶分校的教授,也是时区数据库的维护者。

受保罗的影响,朱尼奥对开源软件世界产生了浓厚的兴趣。虽然他不是内核开发人员,但他订阅了 Linux 内核等开源项目的邮件列表,只是为了好玩。

2005 年 4 月,朱尼奥在邮件列表中看到莱纳斯宣布 Linux 内核将与 BitKeeper 分道扬镳。朱尼奥一直想在开源世界里大显身手,而这个名为 Git 的新项目似乎是个好机会–全新的、没有历史包袱的、容易上手的。他下载了压缩包,花了大约两个小时在一个环境中阅读了 Git 的初始代码。代码写得很好,给他留下了深刻印象。

在 Git 发布之初,Linus 迅速添加了提交和差异命令,但还没有合并功能。

虽然莱纳斯以前从未编写过版本控制软件,但他使用过三年的 BitKeeper。在此之前,他已有十年的 “版本控制人类 “经验。他知道自己想要什么样的合并算法。不过,由于合并逻辑涉及的内容较多,莱纳斯认为用脚本语言编写可能更合适:

我一直在避免做合并树的事情,希望别人能做我描述的事情。我真的很不擅长编写脚本,但很明显,用 C 语言来做很多事情是毫无意义的。

一个星期过去了,没有人找我。当时正处于项目间歇期的 Junio 有了一些空闲时间,于是他用 Perl 写了 Linus 想要的东西,并发布到邮件列表中。

现在,我有了一个使用 rev-tree、cat-file……和合并(来自 RCS)的 Perl 脚本。快速而肮脏。

朱尼奥可能从他的导师保罗那里学到了一些关于 RCS 的知识,所以他对版本控制软件有一定的了解。在邮件中,他还详细介绍了 30 个测试用例,涵盖了不同的代码分支。

此时已是凌晨 1 点,孩子们早上 7 点就起床了,莱纳斯通常在晚上 10 点前上床睡觉。但看到朱尼奥的 Perl 脚本,莱纳斯激动不已,情不自禁地回复了他:

这正是我想要的。Q’n’D就是这样开始的。

他迫不及待地继续与朱尼奥讨论。

“用 git-pasky 合并 II “一开始是 Petr 向 Linus 询问关于合并他的版本的问题,但很快就转入了关于合并算法的讨论。在讨论过程中,Linus 还解释了为什么 Git 的内部结构不需要处理文件重命名。

从4月14日午夜开始,在接下来的48小时里,朱尼奥和莱纳斯在这个线程中交换了十几封电子邮件。朱尼奥耐心地修改代码,以满足莱纳斯对合并的设想。从他的言谈中可以看出,朱尼奥是莱纳斯的忠实粉丝。例如,朱尼奥会引用莱纳斯四年前说过的话 “我永远是对的”,并充分奉承莱纳斯。

4 月 16 日午夜,莱纳斯突发奇想,说他有一个 “狡猾的计划”。

妈的,我的狡猾计划可真是个好东西。

也许是太狡猾了,连我自己都搞糊涂了。不过,看起来它确实在起作用,而且几乎可以实现即时合并。

Linus 聪明地重新使用了现有的索引,并在其基础上引入了 “阶段 “的概念,这大大简化了合并的实现。

朱尼奥对莱纳斯的解决方案赞叹不已

我非常喜欢这个方案。它简单、清晰、灵活,是优雅的典范。这是我很乐意说 “Sheeeeeeeeeeeeeeeeeesh!我怎么就没想到呢!!”。

这意味着朱尼欧之前的 Perl 代码将被浪费,但新的解决方案非常出色,朱尼欧全盘接受了它。

合并算法只是一个开始。朱尼奥继续为莱纳斯贡献更多的补丁,逐渐赢得了莱纳斯的信任。

莱纳斯曾说过,他不会长期维护 Git。一旦时机成熟,他就会把 Git 交给别人,自己则回到 Linux 内核的主要工作岗位上。朱尼奥是不二人选,因为莱纳斯欣赏他写代码的 “品味”。于是,三个月后的 7 月 26 日,莱纳斯宣布把 Git 维护者的角色交给朱尼奥。

朱尼奥也发布了一则公告

你们中的一些人似乎在莱纳斯宣布之前就已经注意到了,kernel.org 的官方 GIT 仓库现在归我所有。正如莱纳斯在留言中所说,这并不意味着他将离开我们,所以请不要惊慌。

我还要感谢双子太阳公司(我的雇主)和 NEC 承诺从现在起支持我兼职开发 GIT。我预计每周工作 8 到 12 个小时,晚上和周末和以前一样是我自己的时间。我的初步计划是将每周三和周六作为我的主要 GIT 日。

早些时候,我总是随心所欲地制作各种补丁,把所有的想法都扔到列表里,看看哪些能坚持下来,而那些糟糕的补丁则会被上游的某个品味不错的人扔掉。虽然和 Linus 一起工作很有趣,但遗憾的是,我浪费了他很多时间。

从现在起,作为 “主仓库的牧羊人”,我会放慢脚步,更加小心谨慎。至少现在,你会看到我的补丁在进入主仓库之前,像其他人的补丁一样发布在列表上。

在朱尼奥的领导下,Git 1.0.0 于 12 月 21 日发布。19 年后(截至 2024 年 7 月),朱尼奥在谷歌工作,仍在维护 Git。

这篇文章提到 Linus 的次数比提到 Junio 的次数要多,但 Git 能有今天,最大的功臣是 Junio 和其他后台开发人员的不懈努力。”1%的灵感和99%的汗水 “也许是老生常谈,但对于像Git和Linux内核这样成功的项目来说,却非常适用。

视频:https://youtu.be/qs_xS1Y6nGc

GitHub 和 Ruby 人

尽管 Git 在早期就获得了相当多的关注,但它仍然是个小众产品。2006 年 1 月,X Window System 团队从 CVS 转向 Git。这已经足够让朱尼欧惊叹了。他没想到像 X Window System 这样的大项目也会大费周章地更换版本控制系统。

BitKeeper 之后,许多 DVCS 开始涌现。除了 Monotone 之外,还有 Mercurial、Darcs、Bazaar、Arch 和 Fossil。其中最著名的是 Olivia Mackall 创建的 Mercurial。它在 Git 发布几天后就发布了,拥有更完整的功能和更友好的用户界面。它还得到了谷歌代码和 BitBucket 的支持。当时的版本控制市场就像狂野的西部,每个系统都有自己的优势。

真正将 Git 推向巅峰并使其成为主流的是 GitHub。或者,正如莱纳斯所说,是 Ruby 人,奇怪的人,让 Git 一夜成名。

2007 年 2 月,Git 1.5 发布,终于让普通人也能使用 Git 了。当时,Git 是旧金山 Ruby 聚会上谈论的热门新事物。GitHub 的联合创始人汤姆-普雷斯顿-沃纳(Tom Preston-Werner)第一次听说 Git 是从他的同事戴夫-费拉姆(Dave Fayram)那里。汤姆认为戴夫是在 Ruby 社区推广 Git 的 “零号病人”

尽管 Git 在 Ruby 社区很受欢迎,但当时唯一可用的 Git 托管服务是 Petr Baudis 的 repo.or.cz,而且非常基本。例如,你的代码必须是公开的,没有私有仓库选项。汤姆看到了其中的巨大商机。

2007 年,Facebook、YouTube 和 Twitter 等社交媒体蓬勃发展。汤姆提出了一个名为 GitHub 的想法:一个供程序员共享 Git 仓库和交流想法的社交媒体中心。

2007 年 10 月的一天,汤姆在旧金山的一家体育酒吧遇到了 Chris Wanstrath。他们以前在 Ruby 聚会上见过,但彼此并不熟悉。汤姆与他攀谈起来,并分享了他的 GitHub 创意。克里斯觉得很有意思,同意加入。

当时,汤姆和克里斯都有全职工作,所以他们利用晚上和周六的时间创建了 GitHub。汤姆设计了用户界面,并使用名为 Grit 的 Ruby 库与 Git 仓库进行交互,而克里斯则使用 Ruby on Rails 构建了网站。

三个月后,他们开始邀请朋友测试 GitHub。2008 年 2 月,PJ Hyett 作为第三位联合创始人加入。4 月 10 日,GitHub 以 “社交代码托管 “为口号正式发布。

GitHub, August 2008

Rails 是 Ruby 的杀手级应用,就在 GitHub 推出之前,Rails 从 Subversion 转向了 GitHub,这让 Git 在 Ruby 社区中的地位得到了进一步提升。当时,大多数编写 Ruby 的人都在开发 Rails 应用程序。当他们看到自己的首选框架在使用 GitHub 时,更多的 Ruby 开发者纷纷效仿。

在冲突中合并 Git 和 GitHub

Scott Chacon 并不是一个典型的 Git + Ruby 人。除了编写 Ruby 代码,他还是一位出色的演讲者、作家和传播者。他制作视频,编写文档,教人们如何使用 Git。他还深入了解 Git 的内部结构,并撰写了一本名为《Git 内部结构》的电子书。

三年来,Git 的 “官方 “主页一直是由 Petr Baudis 于 2005 年创建的 git.or.cz。斯科特希望为初学者创建一个更友好的主页。2008 年 7 月,他重新组织了 git.or.cz 的内容,推出了新的主页 git-scm.com。随后,他在 Git 邮件列表上征求 Git 核心开发人员(尤其是 Petr)的反馈意见。

虽然 Git 在 Ruby 社区已经流行了一段时间,但在 Git 邮件列表上却很少看到 Ruby 人的身影。大多数 Git 核心开发者都是活跃在邮件列表上的资深 C 语言程序员,而 Ruby 群体大多是年轻的网络开发者,他们在聚会、网络论坛和 GitHub 上闲逛,可能一辈子都用不上邮件列表。这两个群体的互动并不多,斯科特在 Git 邮件列表上发布的关于 git-scm.com 的帖子是他们之间为数不多的早期互动之一。

对于 Git 核心开发者来说,另一个问题是汤姆在没有任何讨论的情况下,为了满足 GitHub 自己的需求,用 Erlang fork 了并定制了 Git 守护进程。这首先是因为汤姆不熟悉 C 语言,其次是在邮件列表上发帖太可怕了。邮件列表里都是比你聪明的人,如果你的信息格式不正确,你就会看起来像个白痴。这个过程太慢了,所以汤姆决定自己处理。

Git-scm.com 的横幅上写着 “托管服务由 GitHub 捐赠”,这让一些人质疑斯科特的动机。一些人对 GitHub 从 Git 上赚钱而 Git 核心开发者却分文未得表示不满。不过,大多数反馈都是积极的,最终,git-scm.com 成为了 Git 的官方主页,git.or.cz 则退出了历史舞台。

汤姆是在一次 Ruby 聚会上认识斯科特的。他想,“这家伙要么会成为强大的盟友,要么会成为危险的敌人”。2008 年 10 月,斯科特加入 GitHub,继续他传播 Git 的使命。他编写了更多文档,提供咨询服务,并教授公司如何使用 Git。他还撰写了《Pro Git》一书,该书成为 Git 的官方书籍。GitHub 的宣传策略取得了完美的效果,将 Git 的影响力扩展到了 Ruby 社区之外。而 GitHub 本身也是最大的受益者。

2008 年 10 月,谷歌赞助了第一届 GitTogether 大会。来自 Git 和 GitHub 团队的约 20 人在谷歌位于山景城的总部会面。他们摒弃分歧,深知只有携手合作,才能变得更加强大。

GitTogether 2008

后记

由于无法与 Git 和 GitHub 竞争,BitKeeper 最终不得不退出市场。2016 年,该团队将其代码开源。这个启发了 Git、Mercurial、Monotone 等公司的 DVCS 鼻祖,如今已成为供人们观察和研究的一段历史。当被问及他的想法时,拉里-麦克沃伊回答道

事后诸葛亮。BitKeeper 的业务发展得很好,我们已经走过了 18 个年头。它赚的钱足够让我和我的业务伙伴退休。

另一方面,如果每个人都想退休,我们赚的钱也不够。我们曾在 Github 上推出过类似的产品,但很明显,我们本应在其中投入大量资金,并将 BitKeeper 开放源代码。

我只能说,当你有东西在支付账单时,做出这样的选择是非常困难的。

我最大的遗憾不是钱,而是 Git 作为 SCM 的借口太糟糕了。它的模式是一个 tarball 服务器,这让我很抓狂。连莱纳斯都向我承认,这是一个糟糕的设计。它做了他想做的事,但他想做的事并不是全世界都该做的事。

现在,拉里享受着他的退休生活。他喜欢和孩子们一起钓鱼。

在 2022 年 Stack Overflow 的一项调查中,Git 占据了 94% 的市场份额,以至于第二年,Stack Overflow 不再询问人们使用哪种版本控制系统。

历史上从来没有一个版本控制系统能像 Git 一样主导市场。下一个取代 Git 的是什么?很多人说可能与人工智能有关,但谁也说不准。我们可以肯定的是,这一转变可能会涉及一系列偶然事件和一群天才黑客。

你也许感兴趣的:

共有 114 条讨论

  1. 感谢安德鲁-特里吉尔(Andrew Tridgell)没有让内核受困于专有的源代码控制。从长远来看,坚持原则可以让世界变得更美好,即使一开始会惹恼别人。

    1. 内核并没有被 “卡住”;莱纳斯归根结底是个务实的人,用它来做集成工作没问题。是否改用开源解决方案的问题最终会被再次提出,但在当时,它做了它应该做的事情。

  2. 感谢您分享这篇有趣的文章。

    Bitkeeper很不错,我对它的总体看法与Larry McVoy如出一辙:我希望他能将其开源,让他的坚果运行类似 github 的东西,但用于 Bitkeeper,并希望它能存活下来。

    我和他只有过一次交集。二十世纪初,我为 TortoiseCVS 贡献了少量代码。(比如改进了安装程序,添加了一个调用工具的方法,该工具可以合理地显示`.doc`和`.rtf`文件的差异)。我有一个新的、非常小众的硬件,我对它很感兴趣,并想在 Linux 内核中添加对它的支持。在阅读了他的 Bitkeeper 许可协议条款并打算维护我的 TortoiseCVS 补丁之后,我给他发了一封邮件,问他我是否可以使用 Bitkeeper。他告诉我,我看起来不像是在做版本控制软件的生意(我不是!),并让我继续使用,但如果情况有变,请通知他。

    我现在一直在用 git,因为它已经足够好了,我不应该把我的 “创新代币 “花在这个领域。但我还是宁愿用 bitkeeper、mercurial 或 fossil。我只是无法证明,与众不同会给协作带来多大的影响。

    1. 就像我告诉很多人的那样,去看看 Jujutsu 吧。它的用户界面很有 Mercurial 风格,但比 Mercurial 更好(首席开发人员和我在 Mercurial 上共事多年),Git 是它主要支持的后端之一。我已经全职使用它快一年了。

      1. 我很想使用 jujutsu,它似乎是个不错的模式。不过我觉得,如果全世界都开始用一家公司的老板和一个 CLA 来构建顶级软件,那结果会很糟糕。

        我希望 CLA 有一天会消失。

        1. 请注意,CLA 并不转让版权,因此从版权角度来看,”单一公司所有者 “并不准确。

          1. 从 “只有一家公司有权任意更改许可 “的角度来看,它是准确的。

            1. 不,这不准确。谷歌的 CLA 并非如此。(虽然也有其他 CLA 与您描述的内容比较接近)

              (更新:* 虽然我不懂法律,但你应该读读孩子的评论和 CLA 本身,然后自己做出判断。https://cla.developers.google.com/about/google-individual。我的其余评论与前一段基本无关)。

              另外,虽然我不是专业人士,但据我所知,任何人都可以 fork`jj` 并销售基于 jj 的专有产品(并且可以在几乎任何他们喜欢的许可下发布,几乎没有任何限制),因为它目前是 Apache 许可,但这与 Google CLA 无关。

              让我对我不知道的事情进行更大胆的猜测。以下是我的猜测。

              一种解释是,谷歌倾向于在 Apache 下发布他们的项目,因此没有必要要求人们将版权转让给谷歌。通过在 Apache 下发布你的作品,你已经给了谷歌(或其他任何人)它需要的所有权利。

              据我所知,谷歌个人 CLA 的主要目的是让你签署一份声明,声称你拥有自己作品的权利,并且没有将这些权利转让给你的雇主。

              1. > 授予版权许可。根据本协议的条款和条件,您特此授予 Google 和 Google 发布的软件的接收者永久的、全球的、非排他性的、免费的、不可撤销的版权许可,以复制、制作衍生作品、公开展示、公开表演、再许可和分发您的贡献和此类衍生作品。

                这是一个比 Apache-2.0 更为宽松的许可协议(更不用说适用于谷歌也适用该 CLA 的作品的其他许可协议了)。该条款意味着,谷歌可以无视 Apache-2.0 的条款,转而在这种更为宽松的许可下使用作品,而其他人则受 Apache-2.0 的约束。换句话说,他们可以对代码为所欲为。其他人当然可以在专有产品中使用该代码,但他们不能无视许可证条款。

                “许可 “并不意味着 “为所欲为”。Apache-2.0 除其他规定外,还要求保留许可证声明、

                (请注意,”和接收者 “条款并不意味着其他人可以无视许可条款,因为他们仍需遵守谷歌在其分发的软件上发布的任何许可条款,无论该许可是 Apache-2.0 还是某种专有许可)。

                因此,我坚持认为,”只有一家公司有权任意更改许可条款 “是一个基本准确的总结/概括。或者,如果你愿意,”有一家公司有权无视许可条款”。

                1. 说得好,你确实可以认为 “有一家公司有权无视许可条款 “是正确的。谢谢你的详细说明,我在评论中加了注释。

                  我仍然不确定这是否真的与 Apache 许可证有关,但我觉得自己没有资格争论这个问题。

                  我想我反对的 “稻草人 “说法是,有些人认为你把版权转让给了谷歌(你没有),但这与你的说法不同。

                  1. 谢谢,感谢你的跟进和编辑。版权转让协议比 CLA 更糟糕,但我并没有说 Google CLA 包含版权转让。

                    对于 Apache 许可来说,版权转让比版权许可更不重要,但人们使用 Apache 而不是 MIT 或公有领域仍有其原因,而且 Apache 许可确实包含了一些人们关心的保护措施。

                    关于您的编辑:

                    > 据我所知,谷歌个人 CLA 的主要目的是让你签署一份声明,声称你拥有自己作品的权利,并且没有将这些权利交给你的雇主。

                    开发者原产地证书(DCO,如果你使用 “Signed-off-by: Your Name <email@example.org>”一行,你签署的就是该证书)也有同样的目的,但它不是 CLA,也不会引起同样的问题。法律部门一般不会担心开发人员签署 DCO,而许多法律部门则会理所当然地阻止或限制开发人员签署 CLA(即使他们在其他方面对开发人员为开放源代码做出贡献没有意见)。

    2. 我是 BitKeeper 的忠实用户。

      在我看来,Git 几乎就是对 BitKeeper 的彻底重写。Gitk 和 git-gui 本质上就是 BitKeeper 图形用户界面的克隆。

      我不明白你为什么还要继续用 BitKeeper。

      1. 我想我的记忆可能是因为 BitKeeper 是我的第一个 DVCS。我从来不是它的忠实用户。

        我是在管理团队的 CVS 服务器时接触到 BitKeeper 的。在我的下一个团队中,我们转用了 svn,从开发者的角度来看,它总给人一种 cvs 更好用的感觉,但当管理服务器的工作落到我头上时,我却觉得它比 CVS 好用多了。从开发者的角度来看,我觉得 BitKeeper 会更好。

        在我的下一个团队,我们使用 mercurial。无论是作为开发人员还是开发基础架构管理员,我都非常、非常、非常喜欢 mercurial。在 Windows 上,它也比 git 或 BitKeeper 糟糕得多。

        上次我为一个新团队做决定时,mercurial 和 git 是不二之选。我选择了 git,因为它显然是世界上最受欢迎的工具,而且这样我也不需要花费太多精力就能让新团队成员尽快适应。

        说了这么多……我之所以直接比较 git 和 bitkeeper,是因为当时 bitkeeper 很成熟,而 git 显然还不成熟。然后我就把它和 mercurial(我现在还是更喜欢 mercurial)和 fossil(同上)混为一谈了。你对 BK 的看法可能完全正确。

      2. 从概念上讲,Git 的功能更强大。但我记得 bitkeeper CLI 的界面要合理得多。

        1. 它有自己奇怪的怪癖,有时会显示它是一个有很多有趣格式行的单一文件的幌子。我们与它只是时间上的隔阂,只有熟悉的东西才能让人真正憎恨。

    3. 我不会把化石列入协作清单,因为它并不是一个真正的协作工具,或者说,协作存在障碍,比如为每个化石库创建一个用户名。在我看来,这是一个巨大的障碍。如果能有一个通用的认证身份,可以在所有地方使用,那就更好了,但现在还没有实现。

      顺便说一句,mercurial 似乎比 git 更有优势,而且对大型版本库的支持似乎是由 facebook 提供的,所以在 facebook 转向 git 之前,mercurial 仍将继续存在。

      1. Facebook 并没有真正使用 vanilla mercurial,而是使用了自己面向规模的 rust fork。它的开源版本是 “sapling”。

      1. 从历史来看,https://github.com/bitkeeper-scm/bitkeeper 在多个层面上都很有趣。

  3. 非常棒的读物!我喜欢这本书。

    这是我目前所知的最完整的 git 历史。出类拔萃!

    我希望能读到更多类似的历史文章,了解那些帮助我们塑造世界的软件。

    1. > 这是目前我所知道的最完整的 git 历史。

      在看到你的评论之前,我本来没打算读这个故事。我知道 BitKeeper 的摘要和后果,但这本书太详细了。谢谢!

    2. +!很好的读物。这个领域很年轻,正在加速发展。历史相当紧凑。这样的文章很有价值。

    3. 同上。这真是一篇不错的文章!

  4. > 我最大的遗憾不是钱,而是 Git 作为 SCM 的借口太糟糕了。它的模式是一个 tarball 服务器,这让我很抓狂。就连 Linus 也向我承认这是一个糟糕的设计。它做了他想做的事,但他想做的事并不是全世界都该做的事。

    为什么是蹩脚的?怎样做会更好?

    编辑:@luckydude 感谢您慷慨地回应了我的提示,尤其是几乎是瞬间的回应,哇 🙂

    1. 我与 Git 的问题

      – 不支持重命名,只能猜测

      – 没有编织。在此不做赘述,假设有人在某个分支上添加了 N 个字节,然后该分支被合并了。这 N 个字节会被复制到合并节点中(是的,我知道,git 会查找并删除这些字节,但这只是解决问题的一个缓慢的 “创可贴”)。

      – 注释是错误的,如果我在分支上添加了 N 个字节,而你合并了它,那么(除非现在这个问题得到了解决)在合并节点中就会显示你是 N 个字节的作者。

      – 整个资源库只有一个图形。这会导致多个问题:A) GCA 是版本库的 GCA,如果像 BitKeeper 那样每个文件都有一张图,它可能会与文件的 GCA 相去甚远。B) 调试是颠倒的,你需要从变更集开始向下钻取。在 BitKeeper 中,由于每个文件都有一个图形,假设我有一个 assert() pop。在该文件上运行 bk revtool,找到断言,然后查看断言之前有哪些变化。将鼠标悬停在某一行上,它会显示文件的提交注释,然后是更改集。找到可能的那一行,双击它,现在你就能看到更改集了。我们是一家很小的公司,从未有过 25 人的规模,但我们支持大量的用户。这种调试方式是我们能支持这么多人的重要原因。C)提交注释是按变更集而不是按文件写的。我们有一个图形化的签入工具,可以让你浏览文件列表,显示该文件的差异,并让你发表评论。现在,当你看到 ChangeSet 文件时,它会要求你提供 Git 所要求的注释,但差异是所有文件名,后面跟着你刚才写的内容。这让人们不得不提高提交注释的级别。我们的一些大客户坚持要求工程师使用该工具,而不是使用命令行来检查所有带有相同注释的内容。

      – 子模块把 Git 变成了 CVS。也许现在已经重做了,但我上次看的时候,如果你有子模块,你就不能做横向拉取。BK 的做法更接近于正确,如果所有模块都存在,版本库产生的结果与单版本库完全相同(在稀疏的情况下,不填充模块的结果也完全相同)。无论是单版本库还是多版本库,语义和功能都完全相同。

      – 性能。在大型版本库中,Git 的速度会变得非常慢,我们在 BitKeeper 中为此做了大量工作,在注释等方面,我们的速度快了好几个数量级。

      总之,Git 并不是一个真正的版本控制系统,Linus 早在几年前就向我承认了这一点。版本控制系统需要忠实记录所有发生的事情,不多也不少。Git 不记录重命名,它通过值而不是引用在分支间传递内容。在我看来,这是一种巨大的倒退。

      还有一件事。我们做了一个与 Git 兼容的 bk 快速导出和 bk 快速导入。你可以在 BK 中建立一棵树,并不断更新它,而且无论你在历史中的哪个位置运行 bk fast-export,都会得到相同的版本库。我们的快速导出是幂等的。Git 做不到这一点,它不会发送重命名信息,因为它不会记录重命名信息。这意味着我们必须在进行 bk 快速导入时编译重命名信息,也就是说 Git -> BK 并不是等价的。

      我不指望在这一点上说服任何人,有人点拨,我就试一试。我已经不看 hackernews 了,所以不要指望我为自己说过的话辩护,我现在真的不在乎。我更乐于远离技术,我只是去海边钓鱼,不去想这些事情。

      1. > 不支持重命名,只能猜测

        Git 追踪的不是改动,而是状态。它有工具来比较这些状态,但这并不意味着它需要跟踪额外的数据来帮助这些工具。

        我不认为跟踪重命名真的有用,因为这只是许多可能的状态修改中最简单的一种。如果你把文件 A 分割成文件 B 和 C 呢?你也需要能够跟踪这一点。把一个文件合并到另一个文件也是一样。还有很多很多可能的修改。因此,把重点放在状态上,然后改进比较它们的工具,才是明智之举。

        跟踪所有类型的修改还需要所有开发工具都了解版本控制。你不能再使用标准工具进行大规模重命名,而是要以某种方式将它们构建在 vcs 上,这样它就能跟踪这些操作。这是跟踪版本库状态所不具备的巨大优势。

        > 子模块

        我同意,子模块和子树都不是理想的解决方案。

        1. > 如果把文件 A 分割成文件 B 和 C 呢?你也需要能够跟踪它。把一个文件合并到另一个文件中也是一样。还有很多很多可能的修改。

          我想,Bitkeeper 可以有意义地处理这个问题,因为他们的数据模型可以深入到文件内容。

      2. > 在该文件上运行 bk revtool,找到断言并查看断言之前的更改。将鼠标悬停在某一行上,它会显示文件的提交注释,然后是更改集。找到可能的那一行,双击它,现在你就能看到更改集了。

        我对 bk revool 仍记忆犹新。自那以后,我再也没发现任何东西能像它一样直观、实用。

      3. 我还没听说过每个文件图的概念,我知道这很有用。但我不得不同意,钓一条鱼听起来很不错。

    2. 作为一个在过去十年中一直使用 Git 的人,我也不明白为什么 Git 是一个糟糕的设计。它易于发布,运行良好,使用 tarball 服务器也没什么不好。

      1. 没错。虽然这篇文章很好地介绍了事件的历史,但对功能的演进(这与软件开发的演进密切相关,也反映了软件开发的演进)却不够深入。这就是……:

        TeamWare – 易于分支(通过从父版本复制整个工作区,并将更改带入/放回,良好的合并工具),历史是本地的,部分提交。

        BitKeeper 增加了分布式模式和变更集。

        Git 增加了非常简单的分支、储藏等功能。

        目前可用的其他源代码控制通常至少缺少其中一项功能。很能说明问题的是 Mercurial,它也是为了满足当时对现代源代码控制的同样需求而在差不多同一时间出现的,但却缺少了部分提交等功能,而且分支功能也非常繁琐(比如没有本地历史记录之类的–我上次看它还是十多年前的事)–这使得它只能在非常严格/苛刻的环境下使用,而对其他人来说,它是个不入流的东西。

        1. Git 在分支方面做得很糟糕,不断地压制和重定向不是它的功能,而是一种烦恼。请参阅 fossil 了解如何进行适当的分支/合并/日志记录,这是它的本质。

          1. >不断压扁和重定标不是一个功能,而是一种烦恼

            例如,它是一个允许同时处理多个版本、补丁、热修复等的功能。一旦出现了更好的替代方案,我们就会像以前跳上 Git 这艘船时一样,跳上 Git 这艘船。

            >将版本库与数据分开

            这是很多源代码控制软件的特点,也是他们败给 Git 的原因之一。

            >它迫使你

            这也是源码控制输给 Git 的另一个原因,因为 Git 并没有强迫你以某种狭隘的方式做事。

            当然,我不否认对于某些人/团队/项目来说,其他源代码控制方式会更好用,你的评论就说明了这一点。我只是想说为什么 git 能在大多数情况下胜出。

            1. > 一旦出现了更好的替代方案,我们就会像以前跳上 Git 这艘船一样,跳下 Git 这艘船。

              目前还没那么容易。git 的势头很猛,尤其是与 GitHub 的结合。

              任何学习软件开发的人都会了解 git 和 GitHub。

              人们希望软件能在 GitHub 上发布。

              在 git 取得成功的时候,还有一些更好的系统,比如 mercurial,现在我们有了 fossil,但与对它的普遍了解以及与每种工具(任何编辑器、任何 CI 系统、任何软件包管理器……)和流程的集成相比,git 的缺点实在是太微不足道了。

              1. >git 的势头很猛,尤其是与 GitHub 的结合。

                当年的 CVS 也是这样,包括公共仓库等。

                >在 git 取得成功的时候,可以说还有更好的系统,比如 mercurial

                我在上文特别提到 Mercurial,是因为它们都是在应对同样的挑战时同时出现的,而 Mercurial 恰好在设计上不如 Git。公司也都在抢着用它,比如我们当时的管理层就选择了它,但它是一个可以预见的大麻烦,几年后就被 git 取代了。

                1. > CVS 当年也是这样,包括公共 repos 等。

                  其实不然。

                  CVS 有太多的缺陷(没有原子性、没有适当的分支、没有良好的离线工作等),而 Subversion 作为 “自然的继承者”,修正了一些问题,并吞噬了 CVS 的某些部分。

                  与此同时,当时的 GitHub sourceforge 也开始疏远用户。

                  之后,企业在更大程度上使用了不同的工具(VSS、sccs、Bk、perforce 等),而现在这个市场基本上已经不存在了,Git 无处不在。

                  很多人没有版本控制的时间比现在要长得多。现在的孩子们很早就学会了 Git 的基本原理,甚至在 Windows 上也是如此,并将其作为一种习惯。而在 2000 年代初,我看到许多 “专业 “开发人员的版本控制只有”.bak “或”.old “文件或源代码目录的副本。

                  1. 1986 年,人们开始付钱让我开发软件。我第一次使用版本控制软件是在 1996 年。它糟透了。两年后,我离开公司,创办了自己的软件公司,但在那之前,我使用版本控制软件的经验太糟糕了,所以前几年我都没有使用版本控制软件。2002 年左右,我开始使用 CVS(还是 RCS,很久以前的事了!),很快又换成了 Subversion。2009 年左右,我在 Raku 的工作中学习了 git,大概在 2012 年,我把我的 $WORK 主 repo 换成了 git。从那时起,我创建的每个 repo 都使用了 git,但我还没把所有的 svn repo 都转移到 git。

                  2. > 虽然现在这个市场基本上已经不存在了,而 git 已经无处不在。

                    在游戏开发领域,Perforce 依然拥有大批忠实拥趸–即使有了 LFS,git 对二进制文件的处理也只能算是差强人意。

                    1. 是的,但市场份额已大幅缩水(尤其是在市场大规模增长之后),甚至连 Perforce 如今都成了与 git 集成的工具。

            2. > 这是一项功能,可以同时处理多个版本、补丁、热修复等。一旦出现更好的替代方案,我们就会像以前跳上 Git 这艘船一样,跳上 Git 这艘船。

              你在说什么?我不是在说取消分支,而是在说合并分支通常只是一次虚假的单次提交,掩盖了分支的复杂性和决定性。请参阅 [0] 了解如何利用分支和日志获得合理的提交历史。

              > 这也是很多源代码控制软件的一个特点,也是它们输给 Git 的原因之一。

              如果你有证据证明很多人都在说:”我讨厌数据和版本库的划分!”那么这个说法就可信了,或者你把数据/版本库的划分和 cvs 混淆了?

              [0]: https://fossil-scm.org/home/timeline

  5. > 特里奇做了以下工作。

    > 这是一个 BitKeeper 地址,bk://thunk.org:5000。让我们试试用 telnet 连接。”

    著名的是,特里奇就此发表了一次演讲,并让演讲听众重现了 “逆向工程”。资料来源见 https://lwn.net/Articles/133016/。

    > 我今天参加了特里奇的演讲。演示中最精彩的部分是,他要求听众输入他应该输入的每一条命令。听众们立刻齐声喊出了每条命令(”telnet”、”help”、”echo clone | nc”)。

    1. 我参加了那次演讲,那是一段美好时光。多年来,Tridge 在 Linux.conf.au 上发表了很多精彩的演讲。

      1. 我也一样。我肯定还记得那句 “帮助”。

    2. 这完全不符合事实。你不可能通过 telnet 到 BK 并运行命令来克隆 BK。这些命令不会告诉你网络协议,只会告诉你该协议的结果,但对协议的深入了解是零。

      特里奇没有告诉人们,当莱纳斯在他家做客时,他正在窥探莱纳斯运行 BK 命令时的网络情况。他就是这样完成克隆的。

      事实上,你们都相信特里奇的话,这让人很失望,你们应该做得更好。

      特里奇撒谎的事实令人失望,但我已经知道,只要能达到目的,开源人士愿意无视道德。我喜欢开源,但不喜欢道德。不只是特里奇。

      1. > 你不可能通过 telnet 到 BK 并运行命令来克隆 BK。这些命令不会告诉你网络协议

        根据多个消息来源和在 LCA 上的演讲,网络协议是 “向 URL 中可见的端口发送文本,得到文本返回”。收到的数据是 SCCS,这是现有工具可以理解的格式。而特里奇编写的工具 sourcepuller 并没有克隆 BitKeeper 的全部内容,它只克隆了足够的内容来获取源代码,这意味着 “连接、发送命令、获取 SCCS”。

        除此之外都是道听途说,与已证实的证据完全不符。你有任何参考资料可以证明协议比他在 LCA 舞台上演示的更复杂,或者证明特里奇实施了你所说的网络监控?

        再说清楚一点,除此之外,对专有工具进行更广泛的逆向工程以编写兼容的开源等价物绝对没有任何不道德之处。(如果像你所说的那样,他还在未经朋友明确知晓和同意的情况下记录了他们的网络流量,那就有问题了,但同样,这样做的必要性似乎与许多来源的证据完全不符。如果真的发生了这种情况,仅凭这一点我就会略感失望,但仍会感谢他对世界所做的净贡献)。

        我很理解你当时对特里奇的工作感到愤怒,也许现在仍然如此,但这并不意味着它是错的。我们这些不使用专有软件的人很欣赏可用功能的净增长,就像我们很欣赏使用 Samba 与 SMB 进行互操作的能力一样,不管这对微软来说有多么不方便。

        1. > 你试过了吗?

          你回复的 @luckydude 是 Larry McVoy,他创建了 BitKeeper。

          1. 太有意思了,我还不知道有这个链接(而且在回复之前也没有系统地查看过别人的 HN 简介)。谢谢你的参考;我已经修改了我的评论,将其考虑在内。

        2. 我在 bk 工作过

          > 收到的数据是 SCCS 格式,这是现有工具可以理解的格式。

          你会很惊讶的。SCCS 并不广为人知。BK 也不完全是 SCCS。

          我在 SourcePuller 代码发布(sp-01)时读过它。读起来很轻松。这要归功于 Tridge。我写了一个小测试,让它检出了错误的数据,而且没有错误报告。问题在 sp-02 中仍然存在。

      2. 如果说这里有什么不道德的地方,那就是把别人的数据锁在专有工具里,然后不让他们导出成开放格式。

      3. 拜托,老兄,你应该做得更好。这么多年过去了,你肯定已经意识到逆向工程并不是什么道德缺失。逆向工程带来了多少知识和文化财富?通过谷歌诉甲骨文一案,我们终于在法律上解决了外部可见的应用程序接口和实现行为不被视为知识产权的问题。

        特里奇逆向设计了 bk,并引发了一系列导致 git 诞生的事件,这可能是有史以来对软件行业产生最积极影响的事情之一。无论在当时还是今天,他都不应该因此受到抨击。我很感激他,我们都应该感激他。我知道这对你来说很刺痛,但我希望有一天你能在事后总结经验,并以积极的态度看待这段历史–因为即使事情没有按照你希望的方式发展,你自己对这段历史的影响最终也是非常积极和有意义的,你应该以此为荣,而不是贬低他人。

      4. 这个帖子是胡说八道。你应该删除它。

  6. 有一张截图自称是 2008 年 5 月的 GitHub。但有迹象表明,部分或全部 CSS 已无法加载,而且如果你当时访问该网站的话,这并不是网站真正的样子。事实上,如果你在 Wayback Machine 中查看 github.com,就会发现其最早的抓取时间是 2008 年 5 月,但却未能捕获外部样式表,因此当你今天尝试加载该副本时,会出现 404。遇到这种情况,最好还是不要截图。

    (虽然在这种情况下这样做特别愚蠢,因为在 Wayback Machine 中访问该副本[1]会发现,GitHub 网站包含的自身截图与本文中的截图完全不同)。

    1.<https://web.archive.org/web/20080514210148/http://github.com…>

    1. 作者在此。很好,谢谢!我用 2008 年 8 月的最新截图替换了它。

      1. 拉里想给你打电话,讨论对这篇文章的两处修改(”一处小修改,一处大修改”)。为了方便起见,我已经把你的电子邮件地址传给了他,但你还是应该联系他。

        1. 我已经给他发邮件跟进了。谢谢你告诉我!

    2. 谢谢–我很难相信 GitHub 会以如此糟糕的面貌上线–2008 年的网页可不是欧洲核子研究中心(CERN)时代的网页!

    1. 这部分真的应该直接引用;对原帖进行了非常轻率的改写,感觉形式很糟糕。

    2. 这篇文章的整个评论区都是一座金矿,谢谢!

  7. > 在 Stack Overflow 2022 年的一项调查中,Git 的市场份额为 94%,…

    > 历史上从来没有一个版本控制系统能像 Git 一样主导市场。下一个取代 Git 的会是什么?很多人说可能与人工智能有关,但谁也说不准。

    我很怀疑它会被取代。这不仅是因为它占据了如此大的市场,还因为市场比 CVS 时代大得多。

    很难想象每个人都会从 Git 转向 Git。从 GitHub 转向 Git?从 Git?那就难多了。

    1. 在这一点上,Git 的缺点已经众所周知,所以后继项目要做的 “只是 “解决这些问题。Git 可以扩展到 Linux 内核规模的项目,但事实证明还有更大、更复杂的项目,所以它无法扩展到 Google 规模的组织。你会希望支持集中式和分散式操作,但同时也要意识到这两种操作,因此它可以支持多个远程操作,同时也更容易保持它们的一致性。Github 上的副本是否与 gitlab、CI 系统、我的笔记本电脑和台式机同步?它必须能很好地处理二进制文件,而且是原生的,这样我就能签入我的 100 兆字节的 jpeg 文件,而不会把事情搞得一团糟。你既想把它用作单发布仓库,也想把它用作多发布仓库,因为它允许你只签出单发布仓库的子树。在本地,工作流程既要支持 git 的复杂性,又要比 git 更容易使用。

      总之,在我看来,要取代 git,必须做到以上四点。

      如果有了这样一个系统,让人们不再使用 git 就不是问题了–提供 git 兼容性,如果他们不想使用高级功能,就可以继续使用现有的 git 工作流程。但这样做的问题是,为什么还要使用你的新系统呢?

      这就涉及到一个问题:如何让它成为一个全球性的全球产品?FAANG 规模的公司都有自己的内部工具团队来管理源代码。任何规模较小的公司都没有预算从零开始创建这样的产品,但

      你不能去做这个产品,然后把它卖给别人,因为有多少公司会选择一个未经验证的新工作流程工具,而他们的工程师又想要这个工具呢?对于那些认为 “git 还不够好”,而且腰包足够鼓的公司来说,TAM 又是什么呢?

      1. 你说得没错。GIT 不是 DVFS,而是 DVCS。它是用来跟踪源代码的,而不是二进制数据。如果你把二进制数据放到 DVCS,那你就做错了。

        但是,有些行业需要它,比如游戏行业。因此,他们应该使用允许这样做的工具。我听说 Plastic-SCM 在这方面做得很好。但我从未使用过,所以无法亲身体验。

        取代 GIT 是个愚蠢的想法。没有一种工具能处理所有情况。只需根据自己的工作流程使用合适的工具即可。例如,我需要对二进制文件进行版本控制。我知道 GIT 处理得很糟糕,但我真的很喜欢这个工具。解决方案是什么?我为这种情况编写了自己的简单 DVFS 工具:dot.exe (138KB)

        这是一个非常简单的 DVFS,供个人使用,点对点同步(本地、TCP、SSH)。数据和元数据都经过 SHA-1 校验。它的速度非常快,能满足我的需求:)经过几周的使用,我非常喜欢它,因此添加了包存储来处理文本文件,并将我的所有笔记从 SVN 移到 DOT 🙂

        1. DVCS 代表分布式版本控制系统,它与源代码有什么关系?

          也许你把它和 SCM 弄混了,SCM 是源代码控制管理器,是唯一只处理严格源代码的管理器,但 scm 也有其他含义。

          1. 很难说。对我来说,DVCS 是 DVFS 的高级版本。DVCS 可以做分支和合并,为修订提供更多的元数据等。而 DVFS 只做了一件事,那就是存储二进制 Blob。由于二进制 Blob 无法轻松合并,我不会用它来存储。但我想,这只是我的想法。)

          1. 我知道 git-annex。它可能是大数据的好解决方案。就我而言,我并不想将存储与元数据解耦。我想要的是自成一体的单一项目的单一 repo。这样更易于管理,因为它是真正的分布式存储。无需费心备份,因为每个副本都已经拥有所有内容。对于几 GB 的数据来说,这是个不错的模式。

        2. 我也是这么想的,对我来说,GIT 是文本文件版本管理的最佳选择。

          不处理二进制文件对我来说不是缺点,因为 GIT 不应该是处理二进制文件版本管理的工具,我们应该用其他工具来处理。

          1. 当你有一个很小的 .png 或 .jpg 文件需要与源代码共存时,你会怎么做?

            1. 我可以把二进制文件放到 GIT 仓库中,尤其是小文件和不会改变的文件–人们想要的是 “很好地处理二进制文件”,不管这意味着什么,但把大的二进制文件放到 GIT 中,或把大量二进制文件放到 GIT 中,或对它们进行版本控制,这都不是 GIT 的用例。

            2. 把它放到你的 Git 仓库中就可以了。

      2. 你是这么说的,但 Git 近年来在扩展巨大仓库方面取得了长足进步。目前你可以很好地做到 “只签出单仓库的子树”,还可以使用浅克隆来接近集中式系统(最重要的是减少了本地存储的使用)。

        > 如果有了这样一个系统,让人们离开 git 就不是问题了–提供与 git 的兼容性和[…]

        Git 已经在这么做了。

          1. 不行(因为提交是版本库根目录的快照)。不过,你可以使用这种近似方法:

             git clone --filter=blob:none --sparse https://github.com/neovim/neovim
                cd neovim
                git sparse-checkout add scripts
            

            不幸的是,GitHub 不支持 –filter=sparse:oid=master:scripts,所以 blob 会在你使用 repo 时按需获取。

        1. 但 Git 本身并非如此,它没有任何实际意义。要克隆 mono repo 中的所有子树,这在可用性上是不可能的。你需要一个知道如何在访问时提取文件的伪文件系统。而且最好能与构建系统集成,以抵消按需进行远程操作的成本,并提高并行性。Facebook 正在开源他们的许多工作,但都是基于 mercurial。微软已经买入了 git,但目前还没有开源其支持 git 的工具,因此这一点并不可行。

          总之:问题更为复杂,假装 “你可以检出一个子树 “就能解决问题,其实是舍本逐末。

          1. 微软的 git vfs 是开源的。scalar 也是。这是微软用于大型仓库的两种主要方法。不幸的是,技术上更胜一筹的 vfs 方法在 macOS 上并不成功。

    2. 感觉就像在问:”什么将取代 ASCII?”扩展当然可以,但 0x41 在公元 5050 年将表示 “A”。

      1. 作者在此。我不认为 ASCII 是正确的比较。的确,任何东西都很难与 Git 竞争,因为我们拥有的很多基础设施都已与 Git 深度集成。但想想 x86 与 ARM 的对比,以及人工智能会如何改变我们的代码生成方式。

        1. 不过这也验证了 gp 的观点:UTF-8 并没有取代 ASCII,而是对其进行了扩展。所有有效的 ASCII 文本仍然是有效的 UTF-8,同时保持相同的含义。以 git 的发展势头,不兼容的东西很难取代它,但扩展的 git 可能会流行起来。

    3. 我真的很怀疑这会发生。当它达到谷歌规模的 repos 时,就会失败。但无论如何,世界上大多数人都不会使用这么大的版本库。

      只有那些庞大的组织才会使用替代品,而且通常都是他们自己做的。对其他人来说,git 已经足够好了。

  8. 好久没读完这么长的文章了。写得非常好!

    我试图找出作者是谁,或者他/她为什么知道这么多。没找到。还有谁知道或者 OP 愿意提供一些信息?

  9. 精彩阅读

    我相信我不是第一个指出 Junio(指定的 git “牧羊人”)在谷歌工作的人,在谷歌内部,mercurial 是 “推荐的本地 vcs”,而不是 git。

    1. 谷歌的很多部门都依赖 Git,其中最著名的是 Chrome 浏览器和安卓系统。

      此外,如果朱尼奥能在不影响谷歌当务之急的情况下独立完成工作,也是一件好事。

  10. 顺便提一下,Mercurial 的开发者现在的名字是 Olivia Mackall;遗憾的是,谷歌的信息框没有显示更新的信息。

  11. 这个故事缺少了汤姆-洛德的 TLA 对 git 设计的影响。

  12. > 没有腿的被严重镇静的树懒可能更快

    从现在起,我要借用这句话来形容一切缓慢的事物。

  13. 这句话真的把我带回了过去。在 Git 还没大红大紫的时候(2010/2011 年左右),我不幸在一家使用 IBM Rational ClearCase 的大型企业工作,感觉糟透了。不过,由于它太糟糕、太昂贵,我被委以 “修复它 “的重任。为了解决这个问题,我从瑞典来到了 2011 年的 GitTogether。很多当年的 Git 朋友都来了,至少我记得 Junio、Peff 和 Shawn Pearce 都来了。我当时非常兴奋,回去后组建了一个小团队,在接下来的两年里把一个庞大的代码库(我有很多恐怖的故事)迁移到了 Git 上。这是我职业生涯早期做的最有意义的一件事。

    感谢你们创造了 Git、Gerrit 以及这个行业所缺少的所有救命工具,让这一切成为可能!肖恩-皮尔斯(Shawn Pearce)的逝世令人惋惜,但我们不会忘记他!

  14. > 此外,Petr 还为 Git 创建了第一个项目主页 git.or.cz,以及代码托管服务 repo.or.cz。在 GitHub 接管之前,这些网站一直是 Git 的 “官方 “网站。

    这是真的吗?我还以为 GitHub 与 Git 项目没有官方关系呢

    1. 我认为有些 Github 员工写的代码被放到了 git 中,但这并不是正式的隶属关系。

      在我看来,”官方 “的引号意味着非官方,即在不了解情况的人看来是官方的。

    2. 这就是为什么 “官方 “要加引号。就像”事实上的标准”。

      1. git-scm.org 是 Git 项目事实上的 “官方 “网站,就像法语是法国事实上的 “官方 “语言一样。

        他们的意思和他们写的完全一样:GitHub 接管了 Git 官方网站的托管职责(因为他们确实接管了)。

  15. 有趣的阅读

    bitkeeper 的授权是真实存在的。虽然我现在完全不关注内核邮件列表了,但我记得艾伦-考克斯(Alan Cox)把它称为 buttkeeper。美好时光

  16. 我以前听说过这个故事,但读起来还是很有趣。我没有意识到最初版本的 git 是如此简陋。这让人不禁要问:git 是建立一个无处不在的版本控制系统的最后机会吗?还会有下一次机会吗?不管 git 的技术优点如何,有一点我非常高兴,那就是它是免费软件。它似乎是在自由软件雪崩之前出现的,真正改变了人们的工作方式(希望是好的)。

    1. 它造成了雪崩。如果没有 git 和 GitHub,我想我们现在拥有的自由软件规模是不可能实现的。

  17. 我以前从未听说过 “瓷器 “这个词,但我喜欢这个小故事。

    “在软件开发术语中,将底层基础架构比作管道是很难追溯的,但使用 “瓷器 “来描述高层封装则起源于 Git 邮件列表。时至今日,Git 仍用 “plumbing “和 “chorcelain “分别指代低级和高级命令。”

    另外,与此无关的是,”Ruby 人,奇怪的人 “视频让我捧腹大笑。

    https://www.youtube.com/watch?v=0m4hlWx7oRk&t=1080s

  18. 为了继续工作而向源代码控制工具供应商申请许可简直是无稽之谈。

    今天它还活着!Sr.ht 也有不能托管的工作类别。还在酝酿中。

  19. 因为有了 rails,我们只能用 git,真是诗情画意。

  20. 关于许可

    > 如果您正在使用版本控制软件,就不能使用 BitKeeper 进行版本控制。

    > 如果您想在运行 BitKeeper 的同时运行其他类似软件,您必须获得 BitMover 的许可。

    这简直不可理喻。

  21. 我没有使用 c 语言的经验,我想知道:为什么莱纳斯决定使用脚本语言而不是 c 语言来实现合并?

  22. > bk clone/pull/push 命令的功能与 git clone/pull/push 类似。

    这听起来有点倒退:实际上,Git 的工作方式与 BitKeeper 类似(由于我对 bk 不熟悉,所以不能说在多大程度上类似),而不是相反。

  23. > 2006 年 1 月,X Window 团队从 CVS 转向 Git,这让朱尼奥大吃一惊。他没想到像 X Window 这样的大项目也会大费周章地更换版本控制系统。

    这就是 “X Window System”,简称 “X”。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注