源码仓库管理策略 - 从少到多再到少

280 阅读4分钟

Monorepo(单仓库)和 Multirepo(多仓库)分别代表了两种不同的源代码管理策略。

mono 源自希腊语,单个 ; multi 单词前缀,表示多

repo 是 repository 的缩写

演进阶段

截屏2024-01-10 15.42.26.png

阶段一: 单仓库巨石应用, 一个 Git 仓库维护着项目代码,随着迭代业务复杂度的提升,项目代码会变得越来越多,越来越复杂,大量代码构建效率也会降低,最终导致了单体巨石应用,这种代码管理方式称之为 Monolith

阶段二: 多仓库多模块应用,于是将项目拆解成多个业务模块,并在多个 Git 仓库管理,模块解耦,降低了巨石应用的复杂度,每个模块都可以独立编码、测试、发版,代码管理变得简化,构建效率也得以提升,这种代码管理方式称之为 MultiRepo

阶段三: 单仓库多模块应用,随着业务复杂度的提升,模块仓库越来越多,MultiRepo这种方式虽然从业务上解耦了,但增加了项目工程管理的难度,随着模块仓库达到一定数量级,会有几个问题:跨仓库代码难共享;分散在单仓库的模块依赖管理复杂(底层模块升级后,其他上层依赖需要及时更新,否则有问题);增加了构建耗时。于是将多个项目集成到一个仓库下,共享工程配置,同时又快捷地共享模块代码,成为趋势,这种代码管理方式称之为 MonoRepo

一些想法:MonoRepo 不一定是要将所有组件放一起,可以将同类型业务以统一仓库的形式管理。从业务视角将分散的组件,拼成几大类仓库。比如营销Repo、会员Repo等

Monorepo(单仓库)

# monorepo目录结构:公共依赖 + 每个子包的独立依赖
|-- monorepo-demo              
|   |-- packages                  # packages目录
|   |   |-- compiler              # compiler子包
|   |   |   |-- package.json      # compiler子包特有的依赖
|   |   |-- reactivity            # reactivity子包
|   |   |   |-- package.json      # reactivity子包特有的依赖
|   |   |-- shared                # shared子包
|   |   |   |-- package.json      # shared子包特有的依赖
|   |-- package.json              # 所有子包都公共的依赖

优点:

  1. 统一的版本管理:所有项目或包使用相同的依赖版本,避免了依赖地狱。
  2. 代码重用非常容易:由于都在一个仓库下,很容易抽离出各个项目共用的业务组件或工具。
  3. 避免重复安装包:减少了磁盘空间的占用,并降低了构建时间;内部代码可以彼此相互引用;

缺点:

  1. 仓库大小:随着时间推移,Monorepo 可能会变得非常大,影响克隆和拉取的速度。
  2. 权限和安全性:项目粒度的权限管理变得非常复杂,需要精细管理权限。
  3. 新人学习成本高:原来一个项目一个仓库,现在n个项目一个仓库,新人需要理清各个代码仓库之间的相互逻辑。

使用场景:

  • 大型组织,需要跨团队和项目进行协作的情况。
  • 对项目之间的一致性和同步有高要求的环境。
  • 需要频繁共享代码和进行协作的项目组合。

Multirepo(多仓库)

# multirepo-a目录结构:每个项目依赖隔离,独立存在
|-- multirepo-a
|   |-- src 
|   |   |-- feature1              # feature1目录
|   |   |-- feature2              # featrue2目录
|   |-- package.json              # 整个项目依赖

# multirepo-b目录结构
|-- multirepo-b
|   |-- src 
|   |   |-- feature3              # feature3目录
|   |   |-- feature4              # featrue4目录
|   |-- package.json              # 整个项目依赖

优点:

  1. 灵活性:每个项目可以独立管理,有自己的构建、测试和部署流程。
  2. 细化权限控制:更容易对不同项目设置不同的访问权限。
  3. 易于维护:项目较小,易于管理和维护。
  4. 规模可控:项目的大小不会影响仓库的性能。

缺点:

  1. 依赖管理复杂:需要跨仓库管理和协调依赖版本。
  2. 代码重复:不同项目中可能会出现重复代码。
  3. 协作难度:跨仓库的更改需要协调,可能导致集成问题。
  4. 版本不一致风险:不同项目使用的组件版本可能不一致,增加了集成和测试的复杂性。

使用场景:

  • 较小的团队或项目,不需要频繁地跨项目协作。
  • 每个项目的依赖和构建流程差异较大,需要独立管理。
  • 对项目的隔离性和安全性有较高要求。

结论

一般来说

  • 大型开源库,例如 Babal 以及 Vue3 等等都会选择使用 Monorepo
  • 而日常业务中,通常都是项目制的,通常会选择 Multirepo

差别

  • Monorepo 目录中除了会有公共的 package.json 依赖以外,在每个 sub-package 子包下面,也会有其特有的 package.json 依赖。

  • Multirepo 更倾向与在项目制中,将一个个项目使用不同的仓库进行隔离,每一个项目下使用独有的package.json 来管理依赖。

参考引用

  1. 带你了解更全面的 Monorepo - 优劣、踩坑、选型
  2. All in one:项目级 monorepo 策略最佳实践