Git Submodule 是什么?
git submodule 是 Git 内置功能:在一个主仓库(父项目)里,嵌入另一个独立 Git 仓库(子仓库)。
场景:项目需要复用公共组件、通用工具库、第三方模块,但是不想把源码直接复制进主仓库,方便单独维护、单独更新。
一、核心特点
- 子仓库是完成独立的 Git 仓库,拥有自己的提交、分支、远程地址;
- 主仓库不存子仓库源码,只记录子仓库的:远程地址 + 固定提交嘻哈;
- 主仓库更新不会影响子仓库,子仓库独立迭代。
二、使用场景
✅适合:
- 前端公共组件库、通用工具包(多个项目公用一套代码)
- 项目依赖第三方开源库,需要自定义修改源码
- 大型项目拆分多模块,各模块独立开发、单独发版
❌不适合: 单纯引入第三方依赖(优先 npm/yarn/pip 包管理器,比 submodule 简单)
三丶基础常用命令
1. 添加子模块
js
// 格式:git submodule add 子仓库地址 本地存放路径
git submodule add https://gitee.com/xxx/common-ui src/components/common
执行后会生成:
.gitmodules配置文件(记录所有子模块地址、路径)- 主仓库暂存该文件,提交到远程,其他人拉取后才能识别子模块
2. 首次拉取带 submodule 的项目
普通 git clone 只会拉下主仓库,子模块文件夹是空的,两种补全方式:
JS
// 方式1:克隆时直接递归拉取子模块(推荐)
git clone --recursive https://xxx/main-project.git
// 方式2:已克隆完,手动初始化 + 拉取子模块
git submodule init
git submodule update
3. 更新子模块到最新代码 子仓库远端有新提交,同步到本地:
JS
# 拉取所有子模块最新代码
git submodule update --remote
4. 子模块切换分支 默认 submodule 锁定在某一个 commit, 不绑定分支,如需跟踪分支:
JS
// 添加时指定跟踪分支
git submodule add -b main 仓库地址 路径
// 已添加的模块修改跟踪分支
git config -f .gitmodules submodule.模块名.branch main
5. 子模块提交、推送代码 子模块内部操作和普通 Git 完全一致:
- 进入子模块目录
cd src/components/common git add .→git commit -m "修改组件"→git push- 返回主仓库,此时能看到子模块 commit 哈希变了,主仓库提交记录这个变更
JS
git add src/components/common
git commit -m "更新公共组件到最新版本"
git push
6. 删除子模块(完整清理)
JS
// 1. 删除配置
git submodule deinit -f 子模块路径
// 2. 删除仓库记录
rm -rf .git/modules/子模块路径
// 3. 删除本地文件夹
git rm -rf 子模块路径
// 4. 提交主仓库变更
git commit -m "移除子模块"
四、关键机制:主仓库只锁定 commit
主仓库不会跟随子模块自动更新,只会固定绑定某一个提交哈希。 举个🌰:
- 你把子模块更新到新版本,主仓库必须单独提交一次,记录新哈希;
- 同事不拉取主仓库最新提交,他本地子模块依然停留在旧版本;
- 优势:项目版本稳定,不会因为子模块自动更新导致线上报错;
- 痛点:每次子模块升级,主仓库都要手动提交同步。
五丶常见坑与注意事项
- 克隆后子模块为空
- 忘记加
--recursive,执行git submodule update --init --recursive修复。
- 忘记加
- 子模块代码修改后,主仓库看不到变更
- 子模块内必须先 push 到自己的远程,否则别人更新主仓库时拉不到你的修改。
- 多人协作版本混乱
- 禁止直接在主仓库随意
update --remote,子模块升级后一定要提交主仓库,同步给团队。
- 禁止直接在主仓库随意
- CI/ 打包部署遗漏子模块
- 流水线克隆代码时必须加递归参数,否则打包缺失子模块代码。