暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

开发者前沿 #7|pull request 简史

Bytebase 2025-04-07
16

原文地址:https://rdnlsmith.com/posts/2023/004/pull-request-origins

我生性好奇。每当有了新的爱好,或投入一部电视剧中,或开始使用一些新的(数字)工具时,我做的第一件事就是阅读能找到的一切相关资料,去了解它如何运作、是谁发明的、为什么叫这个名字、随着时间推移发生了哪些变化。

即使我已在某件事情中浸淫了一段时间(比如,我从事专业编程快九年了,此前作为学生和爱好者也做了很久),我仍会不时产生疑惑,被驱使着痴迷地研究,直至找到满意的答案。我经常发现自己在几个月或几年后重温一些同样的问题,因为我忘记了细节,或不再满足于自己第一次的结论。

如今,pull request(以下简称 PR)在软件开发中无处不在,但我们都很难定义它,最多只能试图解释其用途:有助于代码审查;表明某些功能完成;可以捕捉到变更的背景信息,以供后人参考。这些解释很有帮助,但并没有从根本上回答我对于定义的疑问,也没有解释它们名称的由来。

要彻底回答这些问题,我们必须去了解 PR 的起源和演变。经过粗略的搜索,你有理由片面地认为 PR 是由 GitHub 发明的,是 Git 的一项便利功能(但并非 Git 的组成部分)。而我们的故事要从更早的时候讲起:早在 PR 最初作为 Git 的一部分之前。因为但凡提及 Git 的历史,就不能不提及 Linux,Git 的成因。


老方法:1991~2002‍‍‍‍

1991 年 8 月,Linus Torvalds 在 USENET 高调官宣他「做着玩玩」的操作系统项目:当然,项目很快被命名为「Linux」。此后三十多年间,它成为了彪炳计算机史册的项目,驱动了海量网络服务器、所有的安卓手机、各种嵌入式设备,当然还有写作本文所用的计算机。

当时存在的源代码控制系统(最著名的是 CVS 及其前身 RCS 和 SCCS)都是集中式系统,依赖于服务器来协调活动。因此,为规避修改冲突的风险,两个人不能同时编辑同一个文件。它们也许适合大型机(UNIX),但不再适合围绕 Linux 兴起的大规模并行、大规模分布式社区。

最初的十来年间,Linux 没有使用任何正式的源代码控制系统。当时,代码贡献者下载并拷贝最新发布版本的源代码 tar 压缩包,在其中一份拷贝中修改,使用 GNU diff 工具生成与另一份拷贝的比较结果(称为补丁),通过邮件发送到 Linux 内核邮件列表(LKML)上,供社区成员查看、讨论、修改(这与 GitHub 中 PR 的注释非常相似)。邮件是纯文本,且补丁作为邮件正文的一部分内嵌发送,所以可在回复中引用任意代码段进行细粒度讨论。

如果你在终端使用过 Git,你应该很熟悉 GNU diff 补丁格式。例如,这是 1997 年 Molnar Ingo 提交的一个小补丁,也是我在 LKML 档案中能找到最早的补丁:

和 Git 一样,添加到原始文件中的行用 + 标记,删除的行用 - 标记;改动被分为「hunks」,每个「hunks」以一个标头(@@ -3396,6 +3396,11 @@)开头,标明其分别在原始文件和更新文件中的位置。

当一个补丁(或一系列相关补丁)通过了审核,最终版本就会被发送给负责相关子系统的维护者,并最终发送给 Linus 本人。Linus 会使用 diff 的对应工具(恰如其分地叫作 patch),自动将修改应用到他自己的 Linux 代码副本中。重点是,社区中其他人如果想测试或在版本发布前抢先应用修改,都可以这样做。

这个经 Linux 代码库的第一次 Git 提交保存的文档,从代码贡献者的角度讲解了上述过程:https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/SubmittingPatches?id=1da177e4c3f41524e886b7f1b8a0c1fc7321cac2

随着代码和社区的发展,原先的 diff / patch 流程开始出现问题。从某次版本发布开始,时间越长,应用的补丁越多,贡献者的代码与 Linus 需要整合的代码差异就越大,补丁越不容易被妥善地应用。此外,流经邮件列表的补丁(和其他事务)数量巨大,以至于很多补丁被无故放弃。如果一个补丁足够重要,人们希望最终会有人(无论原作者还是其他相关人员)在下次发布时提交修改过的版本。这有时会引起冲突。

1998 年,Larry McVoy 成立了一家名为 BitMover 的公司,提出了解决方案:一个新的分布式版本控制系统。他后来将其命名为 BitKeeper。


BitKeeper 风波:2002~2005

2002 年,BitKeeper 已经足够成熟,Linus 将它当作自己的项目来测试。大多数贡献者继续通过邮件提交补丁;也有一些人(尤其是有资历的维护者),开始将自己的工作保存在 BitKeeper 仓库中,与 Linus 的仓库保持或多或少的同步更新。

如前所述,BitKeeper 和 Git 一样都是分布式系统。与一切都依赖于中央服务器的 CVS 不同,BitKeeper 仓库的每个副本(或克隆)本身都是完整的,也都与它的父版本保持关联;两个版本库之间可以同步变更,一个版本库可以从另一个版本库中提取变更,也可以将变更推送给另一个版本库。

这份简要介绍此过程的文档,同样是通过 Linux 的首次 Git 提交得以保存:https://web.git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/BK-usage/bk-kernel-howto.txt?id=1da177e4c3f41524e886b7f1b8a0c1fc7321cac2

这一切与我们熟悉的 Git 也有些许不同之处。例如,BitKeeper 并没有 Git 意义上的分支;相反,从远程服务器克隆版本库后,需要在本地计算机上制作额外的克隆版本来区分不同的行。Git 替换同一目录下的文件来切换分支,BitKeeper 则是通过导航到其他目录来切换克隆版本。
使用 BitKeeper 的最大好处是简化了整合大量补丁的过程。首先,Linus(以及其他使用 BitKeeper 的维护者)的仓库状态可以通过网络永久访问,这大大减少了补丁漂移问题。其次,莱纳斯不再需要亲自动手合并每个补丁:每个子系统的维护者都可以处理各自负责领域的合并工作,然后 Linus 只需从他们的仓库中将更改 bk pull 进自己的仓库即可。
当维护者在 BitKeeper 代码库中准备好代码供 Linus 调用时,他们会发送一封邮件,例如 2003 年 Russell King 发送的这封邮件:
https://lore.kernel.org/lkml/20030322165525.D8712@flint.arm.linux.org.uk/
(为简洁起见,信息已被截断。)这些信息被称为 pull requests 似乎是理所当然的
你还没讲到风波?
尽管 BitKeeper 为 Linux 的开发过程带来了很多好处,它还是在 Linux 内核邮件列表 (LKML) 上引发了反复的争论。问题在于,它虽然对 Linux 社区成员免费提供,却并非真正意义上的自由软件。
BitMover 的商业模式旨在让自由软件项目免费使用,同时保留从商业客户获取收入的能力。为此,免费版本的 BitKeeper 客户端会在网上公开记录变更集元数据。理论上,这种公开记录对自由软件项目来说完全没问题,因为它们的开发无论如何都是公开进行的;企业则难以接受,反而愿意为能够更私密运行的客户端版本付费。
因此,免费使用的许可证包含了许多限制:用户被禁止干扰日志记录;如果他们有本事访问源代码,他们只能使用或传播仍然「通过该版本的所有当前回归测试」并且「执行与当前或最近(不超过一年)版本相同的开放日志」的衍生版本。一些人质疑了这些要求。
最具争议的是一个不竞争条款,禁止任何为其他版本控制系统做出贡献的人使用BitKeeper。
总地说,BitKeeper 的许可证对「实用主义阵营」(包括Linus本人)而言是可接受的,对「自由软件理想主义阵营」则不然。Richard Stallman 就不止一次写文抗议;当 Linux 后来被迫放弃 BitKeeper 时,他还发表了一篇幸灾乐祸的「告诉过你们」文章。
也许令人有些意外的是,俄亥俄州立大学开源俱乐部还向 LKML 提交过一份正式请愿书,认为 Linux 是「开源和自由软件的重要象征」,因此 Linux 核心开发者公开推广使用专有系统是不恰当的。
Larry McVoy 在为 BitKeeper 及其许可证辩护时可能有些生硬,但他确实也做出了一些努力来安抚批评者。他维护了一个 CVS 桥接器 BK2CVS ,允许代码贡献者使用 CVS 客户端跟踪 Linus 的主要开发线,尽管会有一些延迟。后来,他发布了一个自由软件客户端,虽然它被故意限制(只能获取仓库的当前状态,无法访问其历史记录,Larry 也非常明确地表示他无意改变这一点)并且它附带了一个「禁止抱怨许可证」,戏谑地说明了 BitKeeper 在 Linux 社区内所面临的紧张关系。

无论好坏,Larry 希望的免费客户端并没有「(最终)平息关于 BitKeeper 不是开源软件的抱怨」。争论仍在继续;2005 年 3 月,Andrew「Tridge」Tridgell(除了内核开发外,他因在 Samba 和 rsync 上的工作而闻名)创建了另一个未经授权的免费客户端,名为 SourcePuller。虽然他声称这从未打算取代 BitKeeper,但其理念是允许那些不愿意或无法使用 BitKeeper 的人访问 BitKeeper 仓库中的历史数据:这正是 Larry 的免费客户端特意不提供的功能。

2005 年 4 月,Larry 和 Linus 达成一致,认为 BitKeeper 不再适合 Linux 内核。2005 年 比 1991 年有更多的源代码控制选项:Linus 特别提到 Monotone(另一个分布式系统)作为候选。但最终,Linus 仍对这些选项都不完全满意。于是,他暂停了两周的内核工作,奠定了 Git 的基础。

GitHub 之前的 Git:2005~2008
Linus 在最初几个月里深度参与 Git 的开发,之后他将注意力重新转回内核开发,并将 Git 的维护权交给了 Junio Hamano,后者至今仍然领导着该项目。Git 是专门设计用来取代 BitKeeper 的,所以代码提交流程基本相似这一点并不令人意外。
代码贡献者们继续通过邮件向 Linux 内核邮件列表(LKML)发送补丁,社区会在那里对其进行审核。几乎所有代码贡献者都开始采用 Git,因为它是真正的自由软件,而且便于跟上其他人的工作进度;然而补丁格式基本保持不变,所以如果有人真的不想用 Git,他们可以继续使用较老的 diff 工具来生成补丁。不过 Git 更方便:一旦在本地完成提交,有内置命令(git format-patch 和 git send-email)可以将它们转换成适当格式的一系列邮件。在接收端,git am5 从邮件中提取补丁并将其重新组合成提交。
那些托管自己 Git 仓库的维护者也可以像使用 BitKeeper 时一样提交 PR。Git 也有一个用于生成这些请求的命令:git request-pull,最初由 Ryan Anderson 于 2005 年 7 月编写。其格式(同样,不出所料)与上面 BitKeeper 的例子非常相似:一个介绍性信息;一个仓库链接;按作者分组的提交主题行列表;以及一个整体的 diffstat 统计信息。
如今,Linux 和 Git 本身仍在使用同样的开发流程。
GitHub 来临:2008~2011
GitHub 于 2008 年 4 月正式上线,此前几个月,网站一直处于测试阶段。7 最初的版本很像 GUI 封装的 Git request-pull,所做的只是向一个或多个其他用户发送通知。通知列出了要拉取的版本库和头部提交,带有查看相关提交的链接,并留有可选的简短信息空间。然后,接收者就可以根据文档中的示例手动拉取提交:
同年晚些时候,他们增加了自动回复功能,以应对有人无法(如休假)或不愿意通过 GitHub 接受 PR 请求的情况。除此之外,在接下来的两年里,PR 的体验基本保持不变。
2010 年 8 月,GitHub 推出了「PR 2.0」,从根本上将 PR 转变成了我们今天所熟悉的样子(原文中有着重号):
改版后的提交界面是一个完整的页面,而不是模式对话框,现在还留出了用户输入主题行的空间。信息文本框更大,并支持 Markdown 格式。此外,还可以在标签页中查看包含的提交和整体差异。除了 CSS 之外,与现在的版本唯一明显不同的是,仍然有一个在 PR 提交时会收到通知的人员列表。

PR 从收件箱中暂存的通知变成了永久的公共记录。每次代码提交的讨论一直存在,并可追踪讨论中出现的任何进一步修改。

2011 年 2 月,GitHub 增加了直接在 PR 的 diff 视图中发表评论的功能,这使得过去二十年来在 LKML 中出现的细粒度审查方式终于得以实现。

有趣的是,在此期间,人们仍然需要手动合并 PR。直到 2011 年 4 月,人们期待已久的合并按钮才首次出现。

百花齐放:2011 至今
我本想通过追踪其他源代码托管平台采用 GitHub 式 PR 的情况来结束这篇文章,但事实证明,这些平台的数量比我想象的要多得多:CodePlex(已停用)、Google Code(已停用)、SourceForge(居然还没停用)、Bitbucket、GNU Savannah、Phabricator(已停用)、Launchpad、GitLab(已停用)、 Google代码(已停用)、SourceForge(令人意外地没停用)、Bitbucket、GNU Savannah、Phabricator(已停用)、Launchpad、GitLab、Gitea……这些还只是我听说过的平台中的一部分。因此,这部分内容没有我所希望的那么详尽,但至少你能明白我的意思。
截至 2011 年中期,GitHub 的主要竞争对手似乎是 SourceForge、Bitbucket、Google Code 和 CodePlex。如前所述,Google Code 和 CodePlex 已经停止运营,我也没有花太多精力去挖掘它们功能集的发展时间线。
Bitbucket 与 GitHub 同样创立于 2008 年;不同之处在于,它最初专注于 Mercurial(也是从 2005 年 4 月开始创建的,是 BitKeeper 的潜在替代品)。Bitbucket 于 2011 年 10 月添加了对 Git 的支持,这是在为 Mercurial 实现类似 GitHub 的 PR 功能几个月之后(我猜测当 Git 仓库可用时,它们可以使用相同的功能)。
2020年,Bitbucket 放弃了对 Mercurial 的支持,转而专注于 Git,理由是 Git 的压倒性普及以及确保新功能和其他改进与两个系统兼容的难度。
SourceForge 的历史更悠久:它于 1999 年推出,最初仅提供 CVS,并在 2006 年添加了 Subversion 支持。
可惜,SourceForge 的博客存档在功能历史方面不如 GitHub 或 Bitbucket 的那样有帮助,所以据我所知,他们在互联网档案馆(Internet Archive)保存的 2006 年服务列表快照和 2009 年类似页面快照之间的某个时间点添加了 Git 支持(以及 Mercurial 和 Bazaar)。
2006:http://web.archive.org/web/20060425131322/http://sourceforge.net:80/docman/display_doc.php?docid=753&group_id=1
2009:http://web.archive.org/web/20090615090416/http://sourceforge.net:80/apps/trac/sourceforge/wiki/WikiStart
我放弃了尝试寻找关于他们 merge request 功能(他们的称呼)的更多细节,但即使在今天,它也更接近GitHub的拉取请求1.0而非2.0版本(尽管有单一讨论线程和合并按钮)。
微软的 Azure DevOps Services(前身为 Visual Studio Team Services,再前身为 Visual Studio Online,最初为 Team Foundation Service)于2012年作为托管平台诞生,尽管同样的软件自2005年以来就可供公司自托管,并与 CodePlex 密切相关。它最初仅支持 Team Foundation 版本控制(TFVC),一个集中式系统,但在 2013 年添加了 Git 支持,并在 2014 年接入了 GitHub 风格的 PR。
GitLab 始于 2011 年,作为 GitHub 的开源替代品:尽管 GitHub 的存在理由是托管免费和开源项目,但它自身却以专有而闻名。他们在一个月后的 2011 年 11 月添加了 merge requests。GitLab Inc. 公司,现在负责监督 GitLab 软件的持续开发并提供托管在 gitlab.com 的实例,于四年后的 2014 年成立。
Codeberg 于 2019 年作为德国非营利组织成立,提供由开源 Gitea 项目支持的类 GitHub 服务。Gitea 在 2016 年从一个名为 Gogs 的较老项目分叉出来,原因是对 Gogs 维护者的不满。Gogs 始于 2014 年,并在 2015 年添加了 PR 功能。去年,Gitea 的管理者出人意料地将 Gitea 商标和 gitea.com 域名所有权转让给了新成立的营利性公司 Gitea Ltd.,显然是希望确保更稳定的收入流来资助 Gitea 开发。
尽管有所保证,但 Gitea 社区的相当一部分人对此举感到不安,最终在 Codeberg 非营利组织的支持下启动了另一个分叉项目 Forgejo(现在 Codeberg 运行的是 Forgejo 而非 Gitea)。
这一趋势中有一个非常显著的例外是 SourceHut。虽然上述大多数服务要么推出时就有,要么采用了基于 GitHub 示例的拉取请求(和其他 UI 元素),但 SourceHut(成立于2018年)却反其道而行之,探索了现代服务拥抱 Git 设计初衷的电子邮件工作流会是什么样子。这个结果对我个人来说非常有趣;但这或许是另一个话题了。


开发者前沿 #6 - 用开源软件制作奥斯卡最佳动画长片

Cursor CTO 斯坦福讲座:数据库选错,公司差点凉凉

Bytebase 3.5.1 - 扩展了对数据库的连接参数支持

MCP Server 实现笔记:开发者视角下的优缺点

文章转载自Bytebase,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论