返回顶部

Monorepo 是什么

Monorepo 介绍

monorepo(单存储库)是一种版本管理配置,它将许多项目存储在一个存储库中。这些项目可以是不相关的,也可以是完全不同的。
由于谷歌在Monorepo上的实践,Monorepo受到了越来越多的关注

Multirepo 介绍

multirepo(多存储库)每个项目提供一个存储库。存储库的数量会有所不同,但它将基于代码的逻辑划分。例如,每个项目可能都有自己的位置。

Mono vs Multi Repos

场景 MultiRepo MonoRepo
代码可见性 ✅ 代码隔离,研发者只需关注自己负责的仓库
❌ 包管理按照各自owner划分,当出现问题时,需要到依赖包中进行判断并解决。
✅ 一个仓库中多个相关项目,很容易看到整个代码库的变化趋势,更好的团队协作。
❌ 增加了非owner改动代码的风险
依赖管理 ❌ 多个仓库都有自己的 node_modules,存在依赖重复安装情况,占用磁盘内存大。 ✅ 多项目代码都在一个仓库中,相同版本依赖提升到顶层只安装一次,节省磁盘内存,
代码权限 ✅ 各项目单独仓库,不会出现代码被误改的情况,单个项目出现问题不会影响其他项目。 ❌ 多个项目代码都在一个仓库中,没有项目粒度的权限管控,一个项目出问题,可能影响所有项目。
开发迭代 ✅ 仓库体积小,模块划分清晰,可维护性强。
❌ 多仓库来回切换(编辑器及命令行),项目多的话效率很低。多仓库见存在依赖时,需要手动 npm link,操作繁琐。
❌ 依赖管理不便,多个依赖可能在多个仓库中存在不同版本,重复安装,npm link 时不同项目的依赖会存在冲突。
✅ 多个项目都在一个仓库中,可看到相关项目全貌,编码非常方便。
✅ 代码复用高,方便进行代码重构。
❌ 多项目在一个仓库中,当仓库的代码规模非常的巨大,达到GB/TB的级别,会增大开发环境的代码git clone、pull成本,以及安装成本,本地硬盘的压力,执行git status也可能需要花费数秒甚至数分钟的时间
✅ 依赖调试方便,依赖包迭代场景下,借助工具自动 npm link,直接使用最新版本依赖,简化了操作流程。
工程配置 ❌ 各项目构建、打包、代码校验都各自维护,不一致时会导致代码差异或构建差异。 ✅ 多项目在一个仓库,工程配置一致,代码质量标准及风格也很容易一致。
构建部署 ❌ 多个项目间存在依赖,部署时需要手动到不同的仓库根据先后顺序去修改版本及进行部署,操作繁琐效率低。 ✅ 构建性 Monorepo 工具可以配置依赖项目的构建优先级,可以实现一次命令完成所有的部署。

工具

正确的工具是有效的单一代码库的关键——需要重写思考构建和测试

  • Bazel[1]:由谷歌发布,部分基于他们自己的构建系统(Blaze)。Bazel支持多种语言,并支持大规模构建和测试。
  • Buck[2]: Facebook开源的快速构建系统,支持在多种语言和平台上进行不同的构建。
  • Pands[3]:Pands构建系统是与Twitter、Foursquare和Square合作创建的。目前只支持Python,后续还将支持更多的语言。
  • RushJS[4]:微软用于JavaScript的可扩展的单一代码库管理器,能够从一个代码库构建和部署多个包。

Monorepos正在获得越来越多的关注,尤其是在JavaScript方面,如下项目所示:

  • Lerna[5]:JavaScript的单一代码库管理器,可以与React、Angular或Babel等流行框架集成。
  • Yarn workspace[6]:用一个命令在多个地方安装和更新Node.js的依赖项。
  • ultra-runner[7]:JavaScript单一代码库管理脚本,支持Yarn、pnpm和Lerna插件,支持并行构建。
  • Monorepo builder[8]:通过单一代码库安装和更新PHP包。

扩展代码库

源代码控制是单一代码库的另一个痛点,这些工具可以帮助您扩展存储库:

  • Virtual Filesystem for Git(VFS)[9]:为Git添加流支持。VFS可以根据需要从Git仓库下载对象。这个项目最初是为了管理Windows代码库(最大的Git仓库)而创建的,只能在Windows上使用,但已经宣布要支持MacOS。
  • Large File Storage[10]:Git的开源扩展,为大文件提供了更好的支持。安装了这个扩展,就可以跟踪任何类型的文件,并将它们无缝的上传到云存储中,从而释放代码库的空间,使push和pull的速度更快。
  • Mercurial[11]:Git的替代方案,Mercurial是一个分布式版本控制工具,专注于速度。Facebook使用Mercurial,多年来已经发布了许多提高速度的补丁[12]
  • Git CODEOWNERS[13]:允许定义哪个团队拥有代码库中的子目录,当有人提交pull request或push代码到受保护的分支时,代码所有者会自动被要求进行审查。GitHub和GitLab都支持这一特性。

Monorepo 的挑战

Monrepos 建立在协作工作的理念之上,对 monorepo 中的任何数据几乎没有限制。这一切都很好,但随着单一存储库变得越来越大,客户将不得不等待更长时间才能得到响应。将所有数据集中在一个地方的性质很诱人,但如果您必须等待几分钟到几小时才能得到响应,那么单个数据集有什么用呢?

Monorepos 在 DevOps 工具链上是最难的。长时间的等待会导致队列积压。任何错误都会加剧问题。

如果长等待时间和队列瓶颈还不够具有挑战性,那么包含数十年历史和文件的单一存储库的剪切大小可能大到足以超过单个磁盘驱动器。您可能拥有多个 TB 的此类数据,并且许多工具会创建超大文件。

因此,长期单一仓库在存储方面可能会很昂贵,特别是如果您需要长时间保存数据。处理此问题的一种方法是创建可以分布在许多服务器上的单个数据集。在单一权威的控制下仍然存在单一事实来源,但可以通过复制策略将数据放置在更接近用户的位置。

以这种方式分发数据可以防止用户必须获取整个存储库树。Helix Core 拥有在单一事实来源中提供数据子存储库视图的技术


  1. https://bazel.build/ ↩︎

  2. https://buck.build/ ↩︎

  3. http://www.pantsbuild.org/ ↩︎

  4. https://rushjs.io/ ↩︎

  5. https://github.com/lerna/lerna ↩︎

  6. https://classic.yarnpkg.com/en/docs/workspaces/ ↩︎

  7. https://github.com/folke/ultra-runner ↩︎

  8. https://github.com/Symplify/MonorepoBuilder ↩︎

  9. https://vfsforgit.org/ ↩︎

  10. https://git-lfs.github.com/ ↩︎

  11. https://www.mercurial-scm.org/ ↩︎

  12. https://engineering.fb.com/2014/01/07/core-data/scaling-mercurial-at-facebook/ ↩︎

  13. https://help.github.com/articles/about-codeowners/ ↩︎