一、一句话先给结论(总览)
| 维度 | git submodule | git-repo |
|---|---|---|
| 本质 | Git 原生机制 | 多 Git 仓库的管理工具(wrapper) |
| 多仓库关系 | 父 repo 精确引用 子 repo 的 commit | 用一个 manifest 统一描述多个 repo |
| 版本一致性 | 强(固定 commit) | 弱/中(通常跟随分支) |
| 操作复杂度 | 高(易踩坑) | 低(工程友好) |
| 典型使用 | 第三方库、可复用组件 | Android / BSP / 超大工程 |
一句话理解:
submodule 是"代码级组合"
repo 是"工程级编排"
git-repo(工程级编排)
branch / tag
branch / tag
branch / tag
branch / tag
manifest.xml\n(工程蓝图)
kernel repo
middleware repo
app repo
vendor repo
Git Submodule(代码级组合)
记录 commit A1
记录 commit B7
Main Repo\n(产品 / 应用)
Lib A Repo\n(独立发布)
Lib B Repo\n(独立发布)
二、最浅层:从"你 clone 下来看到什么"说起
1️⃣ git submodule:像"嵌在仓库里的另一个仓库"
bash
git clone main_repo
目录结构:
main_repo/
├── app/
├── third_party/
│ └── libA/ # submodule
├── .gitmodules
└── .git/
特点:
-
libA是一个 完整 Git 仓库 -
main_repo里只记录:- libA 的 URL
- libA 的 commit hash
2️⃣ git-repo:像"一次 clone 下很多平级仓库"
bash
repo init -u https://xxx/manifest.git
repo sync
目录结构:
workspace/
├── framework/
├── kernel/
├── vendor/
├── apps/
└── .repo/
特点:
- 每个目录都是 独立、平级的 Git repo
- 没有"父子仓库"关系
- 统一由 manifest.xml 管理
三、一个直观对比例子
🎯 场景:你在做一个车载 OS / 自动驾驶平台
代码构成:
- kernel
- middleware
- perception
- planning
- vendor BSP
❌ 用 git submodule 管理所有模块
vehicle_os/
├── kernel/ (submodule)
├── middleware/ (submodule)
├── perception/ (submodule)
├── planning/ (submodule)
└── .gitmodules
问题开始出现:
-
每加一个模块:
bashgit submodule add ... -
每次更新:
bashgit submodule update --init --recursive -
容易出现:
- detached HEAD
- submodule 没 commit
- submodule commit 推不上去
📌 submodule 管"几个库"还行,管"几十上百个库"会崩
✅ 用 git-repo 管理
workspace/
├── kernel/
├── middleware/
├── perception/
├── planning/
└── vendor/
manifest.xml:
xml
<manifest>
<remote name="origin" fetch="ssh://git.xxx.com"/>
<default revision="main" remote="origin"/>
<project name="kernel" path="kernel"/>
<project name="middleware" path="middleware"/>
<project name="perception" path="perception"/>
<project name="planning" path="planning"/>
</manifest>
一条命令:
bash
repo sync
📌 repo 非常适合:
- 多团队
- 多仓库
- 统一版本冻结 / 回溯
四、深入一层:版本管理方式的本质区别
1️⃣ git submodule:commit 级别绑定
主仓库记录的是:
libA -> commit a1b2c3d
意味着:
- 任何人 clone 下来
- 得到的 libA 一定是 a1b2c3d
- 完全可复现
优点:
- 强一致性
- 非常适合第三方库
代价:
- 更新成本高
- 操作繁琐
2️⃣ git-repo:分支 / tag 级编排
manifest 中常见:
xml
<default revision="release-2024Q4"/>
意味着:
- 各 repo 通常跟随同一个分支或 tag
- 不要求精确到 commit
- 通过 统一 tag / manifest 版本 达成一致
优点:
- 工程效率极高
- 非常适合平台型项目
代价:
- 理论上不如 submodule 严格
📌 实际上:
repo 项目往往用 manifest + tag 来"人为制造一致性"
五、工程实践中的关键差异点
🔹 1. 协作模型
| 维度 | submodule | repo |
|---|---|---|
| 提交代码 | 两步(子 repo + 主 repo) | 各 repo 直接提交 |
| 新人上手 | 容易踩坑 | 体验好 |
| CI/CD | 复杂 | 友好 |
🔹 2. 分支管理
submodule:
- 主 repo 一个分支
- 子 repo 各自分支
- 容易出现"分支矩阵爆炸"
repo:
bash
repo start feature-x --all
👉 所有 repo 同时创建分支
📌 这是 repo 的"杀手级功能"
🔹 3. 大规模工程能力
| 规模 | submodule | repo |
|---|---|---|
| 3~5 repo | ✅ | ❌(重) |
| 10~20 repo | ⚠️ | ✅ |
| 100+ repo | ❌ | ✅(Android) |
六、典型真实世界选择
✅ git submodule 适合:
- 第三方库(Eigen / Protobuf fork)
- 算法 SDK
- 独立发布的组件
📌 关键词:可复用、强版本约束
✅ git-repo 适合:
- Android / AOSP
- 车载 OS
- 自动驾驶整车平台
- BSP / Yocto-like 工程
📌 关键词:工程级、多团队、规模化
七、一句工程师式总结
submodule 解决的是:
👉 "这个工程精确依赖哪个库版本"
repo 解决的是:
👉 "如何高效协同管理一堆 Git 仓库"