Git submodule 学习笔记
条评论参考自 Git 官方文档:7.11 Git 工具 - 子模块
开始使用子模块
将一个已存在的 Git 仓库添加为正在工作的仓库的子模块
1 | git submodule add <子模块仓库地址> |
克隆含有子模块的项目
普通的git clone
命令默认会包含子模块的目录,但其中还没有任何文件,需要执行 2 个命令:
1 | 初始化本地配置文件 |
更简单的方式:
1 | 会自动初始化并更新仓库中的每一个子模块 |
在包含子模块的项目上工作
拉取上游修改
- 进入子模块目录执行:
git fetch
与git merge
- 直接在主项目目录下执行:
1 | Git 默认会尝试更新所有子模块,所以如果有很多子模块的话,你可以传递想要更新的子模块的名字 |
如果你忘记 –rebase 或 –merge,Git 会将子模块更新为服务器上的状态。并且会将项目重置为一个游离的 HEAD 状态
即便这真的发生了也不要紧,你只需回到目录中再次检出你的分支(即还包含着你的工作的分支)然后手动地合并或变基 origin/stable(或任何一个你想要的远程分支)就行了。
修改子模块的默认分支
1 | 例如要修改子模块的默认分支到develop上 |
其实就是修改了.gitmodule
这个文件。提交以后,当其他人执行git submodule update --remote
后,就会从子模块拉取 develop 这个新分支(但是还得手动进入子模块目录后切到 develop 分支- -)
发布子模块改动
如果我们在主项目中提交并推送但并不推送子模块上的改动,其他尝试检出我们修改的人会遇到麻烦,因为他们无法得到依赖的子模块改动。 那些改动只存在于我们本地的拷贝中。
所以我们可以:
1. 让 Git 在推送到主项目前检查所有子模块是否已推送,如果任何提交的子模块改动没有推送那么 “check” 选项会直接使 push 操作失败:
1 | git push --recurse-submodules=check |
2. 让 Git 进入到每个子模块中然后在推送主项目前推送。如果那个子模块因为某些原因推送失败,主项目也会推送失败。
1 | git push --recurse-submodules=on-demand |
合并子模块改动
子模块技巧
子模块遍历
有一个 foreach 子模块命令,它能在每一个子模块中运行任意命令。 如果项目中包含了大量子模块,这会非常有用。
1 | git submodule foreach 'git pull' |
子模块的问题
- 问题一
在有子模块的项目中切换分支可能会造成麻烦。 如果你创建一个新分支,在其中添加一个子模块,之后切换到没有该子模块的分支上时,你仍然会有一个还未跟踪的子模块目录。
- 解决方案
如果你移除它然后切换回有那个子模块的分支,需要运行 submodule update –init 来重新建立和填充。
1 | git clean -fdx |
- 问题二
如果你在项目中已经跟踪了一些文件,然后想要将它们移动到一个子模块中,那么请务必小心,否则 Git 会对你发脾气。 假设项目内有一些文件在子目录中,你想要将其转换为一个子模块。 如果删除子目录然后运行 submodule add,Git 会朝你大喊:
1 | rm -Rf CryptoLibrary/ |
- 解决方案
你必须要先取消暂存 CryptoLibrary 目录。 然后才可以添加子模块:
1 | git rm -r CryptoLibrary |