>> >> >>Indexer<< << << <<<<<< Idx >>>>>>
Matched: 0
Submodule
M: 2025-12-31 - ljf12825

git submodule是Git提供的一种机制,用来在一个Git仓库中嵌套另一个Git仓库
可以理解为:

  • 主仓库(superproject)像是“容器”
  • 子模块(submodule)是“指针”,指向某个外部仓库的某个提交(commit)

这非常适合管理依赖库、插件、公共组件等,因为它能让你把一个外部项目直接纳入你的项目里,但又保持它独立管理

适用场景举例:

  • 在开发游戏项目,用到一个公共UI框架(仓库A)
  • 希望这个UI框架独立管理,但又能被多个项目引用
  • 如果直接复制粘贴代码,将来UI框架升级就很麻烦
  • 用Submodule就可以做到:
    • 你的游戏仓库只存一个“指针”指向UI框架某个版本
    • UI框架更新后,可以选择git submodule update或手动切换分支来升级

基本操作

添加子模块

git submodule add <仓库地址> <路径>

示例

git submodule add https://github.com/username/libfoo extern/libfoo

这会在extern/libfoo文件夹下放入libfoo仓库

克隆包含子模块的仓库
直接git clone主仓库时,子模块目录是空的 需要执行

git submodule update --init --recursive

这样才能把子模块拉取下来

--recursive的作用是:如果子模块里还有自模块,也一并初始化

更新子模块
拉取主仓库后,子模块可能停在某个commit。要更新到子模块仓库的最新提交,可以:

git submodule update --remote

或者进入子模块目录手动

cd extern/libfoo
git checkout main
git pull

更新后要回到主仓库提交一次,因为主仓库记录的只是子模块的commit指针

删除子模块
删除比较繁琐,需要

git submodule deinit -f <路径>
rm -rf .git/modules/<路径>
git rm -f <路径>

注意事项

  • 子模块不是自动更新的 git pull主仓库不会自动更新子模块,需要显式执行git submodule update
  • 主仓库只记录commit,不记录分支 所以多人协作时,经常会有人忘记了更新子模块,导致版本不一致
  • 建议写脚本/Makefile 比如setup.sh里写好
git submodule update --init --recursive

让团队一键拉取依赖

  • 提交分离头状态(Detached HEAD):子模块默认不处在任何分支上,而是处于一个“分离头指针”状态,指向某个具体的提交。这意味着如果在子模块内直接修改代码并提交,很容易丢失这些提交,正确的做法是先创建并切换到一个分支

替代方案

Submodule用得不好会很麻烦,常见的替代方案

  • Git Subtree:把外部仓库直接合并进来,历史保留,但依赖更新不如submodule灵活
  • 包管理器(Unity的UPM、C++的vcpkg、C#的NuGet):更现代化,自动化程度更高