Git 子模块修改与提交流程
总结 Git 子模块修改和提交流程,包含常见问题和解决方案。
Git 子模块修改与提交流程
这是一份简洁教程,说明如何:
- 修改一个 Git 子模块中的代码
- 将这些修改提交并推送到子模块远端仓库
- 让顶层仓库更新子模块指针,指向新的子模块提交
先理解两个仓库
使用 Git 子模块时,实际上存在两个独立仓库:
- 顶层仓库:主项目
- 子模块仓库:嵌套在主项目中的独立 Git 仓库
关键点:
- 在子模块目录中修改代码,应该先在子模块仓库中提交
- 顶层仓库并不保存子模块源码本身,而是保存“子模块当前指向的提交 SHA”
所以一次完整修改通常需要 两次提交:
- 在子模块仓库提交代码修改
- 在顶层仓库提交“子模块指针更新”
一、进入子模块并确认当前状态
先进入子模块目录:
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 remote、git branch、git 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 进行授权