【外评】为什么 Facebook 不使用 Git

我的工作是构建 Graphite,它的基本灵感来自 Facebook 的内部工具。当我开始与朋友一起创建一家初创公司时,尽管我对开发工具充满热情,却从未听说过 Mercurial。我之前的工程经验包括个人项目、大学家庭作业、在谷歌从事 iOS 开发以及在 Airbnb 从事基础设施开发。在我的生活中,Git 就像水一样常见。事实上,它是如此常见,以至于我以为它是创建和管理代码变更的唯一可行工具。

有趣的是,在Airbnb,Mercurial专家格雷戈里-佐尔克(Gregory Szorc)就坐在离我几个座位的地方,尽管我只知道他是一位和蔼可亲的同桌,对他的贡献一无所知。

2021 年,我的队友托马斯和尼克打开了我的思路。他们来自 Facebook,令我惊讶的是,他们几乎不认识 Git。相反,他们在Mercurial模式和Facebook的 “堆叠差异 “工作流程方面训练有素。随着时间的推移,他们让我认识到了非 Git 工具和模式的好处,我们最终在公司早期做出了一个决定,把堆叠差异带给了 GitHub 开发人员。在这个过程中,我们开发了一个 CLI,将 Hg 的理念融入到 Git 中。

这篇文章不是关于我们的初创公司。而是关于过去三年来一直困扰我的根本问题。为什么 Facebook 用户(Metamates 🏴‍☠️)不使用 Git?为什么要采用 Mercurial 并在其基础上构建自定义工作流程?我知道谷歌不使用 Git,但这也说得通–谷歌的工程技术比 Git 早了五年多。另一方面,Facebook与Git创建于2004年左右,而当Facebook认真评估源代码控制工具时,Git已经比Mercurial更流行了。那么,Facebook 为什么不使用 Git 呢?

这个问题比较小众,但我认为这是一个值得思考的问题。如果 Facebook 早在 2010 年代初就使用 Git 并做出贡献,工程世界也许会是另一番景象。Git 可能会更加友好,并支持堆叠修改。GitHub 也许会为闭源软件开发提供更好的支持。像 Uber 和 Pinterest 这样的前早期 Facebooker 公司可能也会使用 Git 和 GitHub 作为他们的源代码控制,而不是 Phabricator 和 Mercurial,从而在过去十年中减少了生态系统的分散。

但是,Facebook 并没有坚持使用 Git(对于他们的主要 monorepos)。相反,他们采用 Mercurial 进行版本控制,并逐步在上面添加自定义工具。为什么会这样?首先,我试着用谷歌搜索答案,发现了下面这篇权威博文:

Scaling Mercurial at Facebook

这篇十年前的文章,以及后来的一些 YouTube 技术讲座 给了我一个开始的答案: “因为性能”。

但我想更深入地了解一下,听听最初做出决定的工程师们是怎么说的。在一位队友的帮助下,我在前 Facebooker 群组中发布了一个问题,询问有关历史。我还给两位参与迁移到 Mercurial 项目的原工程师发去了冷邮件–他们非常友好地给我打了电话,让我不做记录,并讲述了项目的个人经历。以下是我所了解到的Facebook不使用Git的全部原因–希望这篇文章能帮助进一步记录2024年我们的工具为何如此的历史背景。

注:我从未在 Facebook 工作过,这篇文章只是我作为一个不在 Facebook 工作的人对事实最好的理解。我曾与几位参与该项目的人员交谈,并得到他们的允许,将他们向我解释的内容写下来。

为什么以及如何从 Git 迁移到 Facebook

根据 2014 年 Facebook 的博文,Facebook 一开始使用的是 Git。正如人们所预料的那样,这是他们当时对源控制系统的默认选择。但在 2012 年左右,他们开始遇到扩展限制。这篇博文称,他们的代码库 “甚至比 Linux 内核还要大很多倍,后者有 1700 万行代码和 44000 个文件”。具体来说,工程师们开始感到 Git 操作缓慢。虽然没有慢到令人崩溃的地步,但也慢到值得调查的地步。

关键瓶颈在于对所有文件进行 “stat-ing”的过程。”Git 会检查每个文件,随着文件数量的增加,速度自然会越来越慢。工程师们尝试进行了一次模拟,创建了一个与几年后 Facebook 代码库的预期规模相匹配的虚拟 repo。结果令人震惊–基本的 Git 命令需要 45 分钟以上才能完成。用该项目的一位原始工程师的话说:”这种事情不能留到所有工程师都抱怨的时候再处理。到那个时候,这个东西就太笨重了。要想控制损失,更不用说想出一个更简洁的解决方案了,那将是一项艰巨的任务”。

于是,一个由 SWE 组成的临时小组开始着手研究解决方案。首先,他们联系了 Git 的维护者,研究如何扩展 Git 才能更好地支持大型 monorepos:

以下是 Git 维护者邮件中的一些精选语录,虽然已经过去了 12 年,但读到这些信息时我还是感到有些沮丧:

听起来你们把所有东西都放在一个 .git 中。把这个庞大的版本库分割成多个较小的 .git 版本库。

虽然你/可以/这样做,但这不是个好主意,你应该拆分仓库

我同意。我所在的公司有多年的开发历史,拥有多个庞大的 CVS 仓库,我们正在缓慢但稳步地将代码库从 CVS 迁移到 Git。把东西拆分开来。这样可以更好地进行重组,而且在我看来没有任何坏处。

虽然 Git 可以更好地[原文如此]处理大型版本库(尤其是在交互式重置中应用提交似乎会拖慢大型版本库的速度),但对于 130 万个文件的统计工作,你能做的实在有限。

在这种情况下,Git 维护者们的反应并不积极,而且在未来大型单源版本的时代,Git 维护者们的反应也并不积极。Git 维护者拒绝提高性能,而是建议 Facebook 对 monorepo 进行分片。然而,分片对 Facebook 团队来说并不可行,他们对 Git 不愿意扩展的态度感到惊讶。传统上,由大型科技公司提供免费的开源劳动是一份广受欢迎的礼物,可以确保项目的长久生命力。

尽管如此,Git 项目并没有义务屈从于 Facebook 的要求–我无意把他们描绘成这个故事中的 “坏人”。因为 Facebook 的要求而去做某件事并不是生活的方式。有趣的是,两年后,Git 的维护者们在看到 Facebook 对 Mercurial 做出有意义的改进后,似乎改变了他们的态度

他们在邮件列表中提到了 Git 的性能问题。在我看来,反馈相对较少。

我的印象是,如果他们的印象是 git 开发社区对大型软件源的性能问题相对不关心,我也不会感到惊讶。

所以问题在于,Git 社区是否有兴趣在如此大规模的情况下保持竞争力–而 mercurial 现在似乎已经做到了这一点。

十年后的今天,Git 在更好地支持 monorepos 方面做了重大改进。

今天,情况已经发生了翻天覆地的变化,Git 现在(只要掌握了一些方法)可以很好地支持真正的大型 repos。

安尼-贝茨,前 Facebook 用户

考虑过的替代方案

2012 年,Git 的替代方案并不多。团队曾考虑过封闭源代码的 Perforce,即谷歌以前的源代码控制解决方案。在与 Perforce 销售工程师的一次早期调查通话中,Facebook 指出了 Perforce 在读写器节点间本地一致性方面的架构缺陷。销售工程师没有意识到这个根本问题,也没有解决这个问题的路线图计划。

他们还考虑了其他解决方案,比如 Bitkeeper,但很快都被否决了。最后的选择是 Mercurial。它的性能与 Git 相似,但架构更简洁。Git是一个由Bash和C语言代码组成的复杂网络,而Mercurial是用Python语言设计的,使用面向对象的编码模式,设计上具有可扩展性。

其中一位负责调查的工程师以前曾在Mercurial方面有过丰富的经验,于是团队决定参加在阿姆斯特丹举行的Mercurial黑客马拉松活动,以作进一步调查。

因为我之前与Mercurial有很多联系,所以在把Mercurial摆上台面之前,我就一直在努力寻求各种可能的替代方案。

布莱恩-奥沙利文(Bryan O’Sullivan),前Facebook用户

他们发现这是一个易于扩展的系统,而且维护者社区非常欢迎Facebook团队的积极改变。

我想这就是所提到的黑客马拉松,但我并不确定。这段视频给人一种 2010 年初的感觉:https://www.youtube.com/watch?v=fml4s6MEjW8

迁移整个工程组织

阿姆斯特丹黑客马拉松结束后,Facebook 团队被说服了。剩下的工作就是说服公司其他部门进行迁移。这是一项令人望而生畏的任务–工程师们对工具的改变(想象一下 vim 与 emacs 的对比)可能极为敏感,而改变源代码控制系统也是一件大事。

为了不引起其他工程师的抵触情绪,团队尽可能顺利地开始了工作。随后发生的事情听起来就像是内部开发工具迁移的大师课。团队花了几个月的时间来讨论迁移到 Mercurial 的可能性,并花时间绘制了 Git 和 Mercurial 之间的所有常用命令和工作流程图。他们甚至对整个公司的Git命令运行频率进行了统计,并具体记录了最频繁的操作在Mercurial中的运行方式。

其次,他们为开发人员创造机会,让他们表达自己的担忧,并讨论在新系统中可能出现的任何棘手的边缘情况。一开始,团队以为他们会因为晦涩难懂的八路章鱼合并假设而陷入火焰战争。但出乎他们意料的是,他们发现同行工程师们都很包容和友好。”没有人站起来就自己的特殊情况大喊大叫”。

最后,他们承诺进行迁移,并将公司改用 Mercurial。剩下的就是历史了。Facebook 为 Mercurial 的性能改进做出了贡献,使其成为大型单体的最佳选择。埃文-普利斯特里(Evan Priestley)扩展了Phabricator以支持Mercurial。Facebook 利用 Mercurial 的 “diffs “概念创建了一种 “堆栈 “模式,从而实现了新颖的代码审查并行化。前 Facebook 员工离开 Facebook 去了新公司,并带来了他们的工作流程,形成了一个人数不多但声势浩大的堆叠差异爱好者崇拜群体。最后,我认识了其中一些爱好者,并决定在我二十多岁的时候,将 Mercurial 风格的堆叠差异引入 Git 和 GitHub。

结束语

从这个故事中能得到什么启发?回顾这些引语和访谈,我想起了一个经典的观点:历史上许多关键的技术决策都是由人驱动的,而不是由技术驱动的。

Facebook 采用 Mercurial 并不是因为它比 Git 性能更强。他们之所以采用 Mercurial,是因为维护者和代码库觉得 Mercurial 对协作更加开放。Facebook的工程师们与Mercurial的维护者们进行了面对面的交流,并喜欢上了合作的想法。在说服整个工程组织的过程中,这个决定得到了深思熟虑的沟通的支持,而不是因为一种技术比另一种技术更好。

对于所有读到这篇文章的人来说,我认为这是布莱恩让 Mercurial 在 FB 被采用的真正高明之处,也是人们在为公司引入新技术时应该考虑的问题。

前 Facebook 用户,2024 年

在开发工具的世界里,善良和开放是最重要的,我希望在为源代码控制的历史做出贡献的同时,也能将这些价值观发扬光大。

本文文字及图片出自 Why Facebook doesn’t use Git

你也许感兴趣的:

发表回复

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