沉梦手记 沉梦手记
首页
  • 基础篇
  • 集合篇
  • 并发篇
  • JVM
  • 新特性
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 基础篇
  • MySql
  • Redis
  • 达梦数据库
  • Spring
  • SpringBoot
  • Mybatis
  • Shiro
  • 设计须知
  • UML画图
  • 权限校验
  • 设计模式
  • API网关
  • 网络通信
  • 消息队列
  • SpringCloud
  • 分布式事务
  • 云存储
  • 搜索引擎
  • 音视频处理
  • Linux 与容器化运维
  • 开发工具篇
  • 工具库篇
  • 开发技巧篇
  • 工具类系列
  • 随笔
  • 前端环境搭建
  • HTML与CSS
  • JS学习
  • Axios入门
  • Vue Router入门
  • Pinia入门
  • Vue3入门
  • Vue3进阶
  • 黑马Vue3
  • 脚手架搭建
  • 瑞吉外卖
  • 黑马点评
  • vue-blog
  • 沉梦接口开放平台
  • 用户中心
  • 聚合搜索平台
  • 仿12306项目
  • 壁纸小程序项目
  • RuoYi-Vue
  • 博客搭建
  • 网站收藏箱
  • 断墨寻径摘录
  • 费曼学习法
Github (opens new window)

沉梦听雨

时间是最好的浸渍剂,而沉淀是最好的提纯器🚀
首页
  • 基础篇
  • 集合篇
  • 并发篇
  • JVM
  • 新特性
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 基础篇
  • MySql
  • Redis
  • 达梦数据库
  • Spring
  • SpringBoot
  • Mybatis
  • Shiro
  • 设计须知
  • UML画图
  • 权限校验
  • 设计模式
  • API网关
  • 网络通信
  • 消息队列
  • SpringCloud
  • 分布式事务
  • 云存储
  • 搜索引擎
  • 音视频处理
  • Linux 与容器化运维
  • 开发工具篇
  • 工具库篇
  • 开发技巧篇
  • 工具类系列
  • 随笔
  • 前端环境搭建
  • HTML与CSS
  • JS学习
  • Axios入门
  • Vue Router入门
  • Pinia入门
  • Vue3入门
  • Vue3进阶
  • 黑马Vue3
  • 脚手架搭建
  • 瑞吉外卖
  • 黑马点评
  • vue-blog
  • 沉梦接口开放平台
  • 用户中心
  • 聚合搜索平台
  • 仿12306项目
  • 壁纸小程序项目
  • RuoYi-Vue
  • 博客搭建
  • 网站收藏箱
  • 断墨寻径摘录
  • 费曼学习法
Github (opens new window)
  • 开发工具篇

    • idea相关

    • 玩转Git

      • 基础知识梳理
      • Git配置相关操作
      • git修改已提交的用户名和邮箱
      • git提交规范
      • git分支管理
      • git常用操作
      • git-submodule子模块管理
        • 什么是 Submodule?
        • 实战:主仓库管理三端子项目
          • 1. 添加子模块
          • 2. 查看 .gitmodules 文件
          • 3. 提交主仓库
        • 克隆含子模块的项目
          • 方式一:一步到位(推荐)
          • 方式二:先克隆,再初始化子模块
        • 日常开发流程
          • 修改子模块代码并同步到主仓库
          • 切换子模块分支
          • 查看子模块状态
        • 更新子模块到最新版本
        • 删除子模块
        • 子模块的注意事项
        • 学习参考
      • fork工作流与上游同步
      • gitignore最佳实践
      • 常见问题
    • Maven相关

    • 前端工具

    • 测试工具

    • AI工具

  • 工具库篇

  • 开发技巧篇

  • 工具类系列

  • 随笔

  • 开发日常
  • 开发工具篇
  • 玩转Git
沉梦听雨
2026-07-22
目录

git-submodule子模块管理

# Git Submodule 子模块管理

# 什么是 Submodule?

当一个项目需要包含并引用其他独立的 Git 仓库时,可以使用 Git Submodule(子模块)。

典型场景:

  • 一个 monorepo 主项目包含多个独立子项目,各子项目有各自的远程仓库和提交历史
  • 项目依赖一个外部库,且希望跟踪该库的特定版本
  • 多端项目(如后端 + 前端 + 小程序)各自独立仓库,但需要一个主仓库统一管理

Submodule 的本质:主仓库并不保存子模块的文件内容,只保存一个指向子模块某个 commit 的引用(指针)。主仓库的 .gitmodules 文件记录子模块的路径和远程地址。

与直接把子项目代码放进主仓库的区别:子模块保持独立的提交历史和远程仓库,主仓库只追踪"当前使用的是子模块的哪个版本"。

# 实战:主仓库管理三端子项目

以我的点餐项目 cm-food-ordering 为例,主仓库管理三个子仓库:

cm-food-ordering/          ← 主仓库
├── backend/               ← submodule(fork 自 RuoYi-Vue-Plus)
├── frontend/              ← submodule(fork 自 plus-ui)
└── uniapp/                ← submodule(独立项目)
1
2
3
4

# 1. 添加子模块

# 语法:git submodule add <子仓库远程地址> <本地目录名>
git submodule add https://gitee.com/dream-deeply-tyu/RuoYi-Vue-Plus.git backend
git submodule add https://gitee.com/dream-deeply-tyu/plus-ui.git frontend
git submodule add https://gitee.com/dream-deeply-tyu/cm-food-ordering-uniapp.git uniapp
1
2
3
4

执行后会:

  • 在对应目录克隆子仓库
  • 生成 .gitmodules 文件(记录子模块配置)
  • 在主仓库暂存 .gitmodules 和各子模块目录

# 2. 查看 .gitmodules 文件

[submodule "backend"]
	path = backend
	url = https://gitee.com/dream-deeply-tyu/RuoYi-Vue-Plus.git
[submodule "frontend"]
	path = frontend
	url = https://gitee.com/dream-deeply-tyu/plus-ui.git
[submodule "uniapp"]
	path = uniapp
	url = https://gitee.com/dream-deeply-tyu/cm-food-ordering-uniapp.git
1
2
3
4
5
6
7
8
9

# 3. 提交主仓库

git add .gitmodules backend frontend uniapp
git commit -m "chore: 改用 submodule 管理三端子仓库"
git push
1
2
3

# 克隆含子模块的项目

# 方式一:一步到位(推荐)

git clone --recurse-submodules https://gitee.com/dream-deeply-tyu/cm-food-ordering.git
1

--recurse-submodules 会在克隆主仓库的同时初始化并拉取所有子模块。

# 方式二:先克隆,再初始化子模块

# 先克隆主仓库(子模块目录是空的)
git clone https://gitee.com/dream-deeply-tyu/cm-food-ordering.git
cd cm-food-ordering

# 初始化并拉取所有子模块
git submodule update --init --recursive
1
2
3
4
5
6

如果子模块里面还嵌套了子模块,--recursive 参数会递归处理。

# 日常开发流程

# 修改子模块代码并同步到主仓库

# 1. 进入子模块目录,正常开发提交
cd backend
git add -A
git commit -m "feat: 新增点餐业务模块"
git push origin cm-food-ordering

# 2. 回到主仓库,更新 submodule 指针
cd ..
git add backend
git commit -m "chore: bump backend submodule"
git push
1
2
3
4
5
6
7
8
9
10
11

关键点:子模块代码改动后,主仓库会显示子模块有新提交(modified: backend (new commits))。需要在主仓库额外提交一次,记录子模块指向的新 commit。

# 切换子模块分支

子模块默认会处于"detached HEAD"状态(指向某个具体的 commit,不在任何分支上)。要开发需要先切到分支:

cd backend
git checkout cm-food-ordering
# 之后正常开发提交
1
2
3

# 查看子模块状态

# 查看所有子模块的当前状态
git submodule status

# 输出示例:
# +a043dbd61c... backend (cm-food-ordering)
#  3964bb7... frontend (cm-food-ordering)
#  cc35188... uniapp (cm-food-ordering)
# 前面的 + 表示子模块有未提交的改动
1
2
3
4
5
6
7
8

# 更新子模块到最新版本

当子模块远程仓库有新提交(比如其他协作者推送了代码),主仓库需要同步:

# 方式一:进入子模块目录拉取
cd backend
git pull origin cm-food-ordering
cd ..
git add backend
git commit -m "chore: update backend submodule"

# 方式二:在主仓库统一更新所有子模块
git submodule update --remote
git add backend frontend uniapp
git commit -m "chore: update all submodules"
1
2
3
4
5
6
7
8
9
10
11

git submodule update --remote 会拉取每个子模块远程对应分支的最新提交,但不会自动切换子模块的 HEAD,需要再 git add + git commit 记录新指针。

# 删除子模块

Git 没有提供 git submodule remove 命令,需要手动操作:

# 1. 从 .git/config 中移除子模块配置
git submodule deinit -f backend

# 2. 从主仓库索引中移除
git rm -f backend

# 3. 删除 .gitmodules 中的相关条目(如果没有其他子模块,直接删文件)
# 4. 删除 .git/modules/ 下的子模块缓存
rm -rf .git/modules/backend

# 5. 提交
git commit -m "chore: 移除 backend 子模块"
1
2
3
4
5
6
7
8
9
10
11
12

# 子模块的注意事项

  1. 主仓库只保存指针:主仓库不存储子模块的文件内容,只记录子模块当前指向的 commit hash。克隆主仓库时必须用 --recurse-submodules 或手动 git submodule update --init。

  2. 子模块默认是 detached HEAD:克隆后子模块不在任何分支上,开发前需要手动 git checkout <branch>。

  3. 子模块改动需双重提交:在子模块内提交后,还要在主仓库提交一次指针更新。容易忘记第二步,导致主仓库记录的子模块版本是旧的。

  4. 不要在主仓库直接修改子模块文件:虽然技术上可行,但容易造成混乱。应该进入子模块目录操作。

  5. 切换主仓库分支时注意子模块状态:git checkout 主仓库分支后,子模块可能不会自动切换到对应版本,需要 git submodule update。

# 学习参考

  • Git 官方文档 - 子模块 (opens new window)
  • Git submodule 教程 (opens new window)
上次更新: 2026/7/24 16:59:26
git常用操作
fork工作流与上游同步

← git常用操作 fork工作流与上游同步→

Theme by Vdoing | Copyright © 2023-2026 沉梦听雨 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式