文章

Git 子模块修改与提交流程

总结 Git 子模块修改和提交流程,包含常见问题和解决方案。

Git 子模块修改与提交流程

这是一份简洁教程,说明如何:

  1. 修改一个 Git 子模块中的代码
  2. 将这些修改提交并推送到子模块远端仓库
  3. 让顶层仓库更新子模块指针,指向新的子模块提交

先理解两个仓库

使用 Git 子模块时,实际上存在两个独立仓库:

  • 顶层仓库:主项目
  • 子模块仓库:嵌套在主项目中的独立 Git 仓库

关键点:

  • 在子模块目录中修改代码,应该先在子模块仓库中提交
  • 顶层仓库并不保存子模块源码本身,而是保存“子模块当前指向的提交 SHA”

所以一次完整修改通常需要 两次提交

  1. 在子模块仓库提交代码修改
  2. 在顶层仓库提交“子模块指针更新”

一、进入子模块并确认当前状态

先进入子模块目录:

1
cd path/to/submodule

查看状态:

1
2
3
git status
git remote -v
git branch -vv

建议重点确认两件事:

  • 当前所在分支是否正确
  • origin 是否指向你有权限推送的远端仓库

如果远端不对,可以修改:

1
git remote set-url origin <your-submodule-remote>

再次确认:

1
git remote -v

说明

这里的 git remotegit branchgit status 都只作用于子模块仓库,和顶层仓库没有关系。


二、在子模块仓库中提交修改

先检查修改内容:

1
2
git status
git diff

加入暂存区:

1
git add .

如果只想提交部分文件,也可以显式指定:

1
git add path/to/file1 path/to/file2

提交:

1
git commit -m "Describe your submodule change"

说明

  • git add 是把修改加入暂存区
  • git commit 是在当前仓库生成一个新的提交
  • 这里只会影响子模块仓库,不会自动更新顶层仓库

三、将子模块提交推送到远端

先确认当前分支名:

1
git branch --show-current

然后推送:

1
git push origin <branch-name>

可选:记录一下当前提交 SHA

1
git rev-parse HEAD

为什么这一步不能省略

顶层仓库稍后会记录“子模块应该指向哪个提交”。
如果这个提交只存在于本地、还没有推送到子模块远端,那么别人拉取顶层仓库后,可能无法获取对应的子模块提交。


四、回到顶层仓库并更新子模块指针

回到顶层仓库:

1
2
cd path/to/top-level-repo
git status

这时通常会看到类似:

1
modified: submodule-name (new commits)

或者:

1
modified: submodule-name (modified content)

如果你已经在子模块内完成提交,那么这里的含义通常是:

  • 顶层仓库发现子模块指向了一个新的提交

将这个变化加入暂存区:

1
git add submodule-name

如果顶层仓库还有其他文件一起修改,也可以一起加入:

1
git add submodule-name other-file

然后提交:

1
git commit -m "Update submodule pointer"

说明

这次提交不是在提交子模块源码,而是在提交:

1
“顶层仓库现在应该引用子模块的哪个提交”

这一步本质上是在更新子模块指针。


五、推送顶层仓库

1
git push origin <top-level-branch>

到这里,完整流程才算结束。


标准流程总结

1
2
3
4
5
6
7
8
9
10
cd path/to/submodule
git status
git add .
git commit -m "Describe your submodule change"
git push origin <submodule-branch>

cd path/to/top-level-repo
git add submodule-name
git commit -m "Update submodule pointer"
git push origin <top-level-branch>

常见误区

1. 只在子模块里提交,不更新顶层仓库

结果:顶层仓库仍然指向旧的子模块提交。

2. 更新了顶层子模块指针,但子模块提交没推到远端

结果:别人拉到顶层仓库后,可能拿不到对应的子模块提交。

3. 混淆“子模块仓库”和“顶层仓库”

记住:

  • 在子模块目录里执行 Git 命令,默认作用于子模块仓库
  • 在顶层目录里执行 Git 命令,默认作用于顶层仓库

4. 看到 modified: submodule-name 就以为是普通目录变更

不是。
这通常表示:

  • 子模块内部有未提交改动,或
  • 子模块指向的提交发生了变化

可以进入子模块后运行:

1
git status

查看更具体的状态。


几个实用命令

查看顶层仓库记录的子模块变化:

1
git diff --submodule

查看子模块当前指向:

1
git submodule status

初始化或同步子模块:

1
git submodule update --init --recursive

一句话记忆

1
2
先在子模块里 commit + push,
再在顶层仓库里提交子模块指针更新。
本文由作者按照 CC BY 4.0 进行授权