Git是程序员在日常开发中不可分割的强有力工具,有时候我们需要在两个甚至多个仓库间进行同步和公用,需要提取一个公共的类库提供给多个项目使用,或者说某个项目需要包含并使用另一(/多)个项目,这时候可以使用Git Submodule 解决。
子模块允许你将一个 Git 仓库作为另一个 Git 仓库的子目录。 它能让你将另一个仓库克隆到自己的项目中,同时还保持提交的独立。
解决问题
如何在git项目中导入子库?
子库在其他的项目中被修改了可以更新到远程的代码库中?
其他项目如何获取到子库最新的提交?
如何在clone的时候能够自动导入子库?
开始使用Submodule
添加Submodule
1 | git submodule add https://github.com/xxx/XXXX [XXXX位置] |
默认,子模块会将子项目放到一个与仓库同名的目录中。 如果你想要放到其他地方,可以在命令结尾添加一个不同的路径。
1 | git status |
.gitmodules 文件
该配置文件保存了项目 URL 与已经拉取的本地目录之间的映射:
1 | $ cat .gitmodules |
如果有多个子模块,该文件中就会有多条记录。该文件一样受到版本控制
修改Submodule
首先需要有对Submodule的commit权限。
进入Submodule目录:
cd XXXX
- 修改内容
- 查看变动:
git status
- 提交更改内容:
git commit
- 推送远程:
git push
回到父目录,提交Submodule在父项目中的变动
- git commit -m’update submodule’
- git push
在Submodule目录中使用git如同在一个独立的项目,更新Submodule时如果有新的commit id产生,需要在父项目产生一个新的提交
更新Submodule
- 方式一:在父项目的目录下直接更新
1 | git submodule foreach git pull |
- 方式一:在Submodule的目录下面更新
1 | cd xxxx |
克隆含有Submodule的项目
- 方式一:递归clone整个项目
1 | git clone git@github.com:xxx/xxxx.git --recursive |
- 方式二:先clone父项目,再更新子项目
1 | git clone git@github.com:xxx/xxxx.git |
更新Submodule
git submodule update --remote
: Git 将会进入子模块然后抓取并更新
此命令默认会假定你想要更新并检出子模块仓库的 master 分支
当运行 git submodule update –remote 时,Git 默认会尝试更新所有子模块,所以如果有很多子模块的话,你可以传递想要更新的子模块的名字。
更改Submodule的追踪分支
1 | // 更改为追踪XXX子模块的xxxBranch分支 |
删除Submodule
git不支持直接删除Submodule,需手动删除:
1 | cd xxxsubmodule |
坑
更新 submodule 的坑
如果你的同事更新了 submodule,然后更新了父项目中依赖的版本号。你需要在
git pull
之后,调用git submodule update
来更新 submodule 信息
修改 submodule 的坑
有些时候你需要对 submodule 做一些修改,很常见的做法就是切到 submodule 的目录,然后做修改,然后 commit 和 push。
默认 git submodule update 并不会将 submodule 切到任何 branch,所以,
默认下 submodule 的 HEAD 是处于游离状态的 (‘detached HEAD’ state)
。所以在修改前,记得一定要用 git checkout master 将当前的 submodule 分支切换到 master,然后才能做修改和提交。
如果你不慎忘记切换到 master 分支,又做了提交,可以用 cherry-pick 命令挽救。具体做法如下:
- 用 git checkout master 将 HEAD 从游离状态切换到 master 分支 , 这时候,git 会报 Warning 说有一个提交没有在 branch 上,记住这个提交的 change-id(假如 change-id 为 aaaa)
- 用 git cherry-pick aaaa 来将刚刚的提交作用在 master 分支上
- 用 git push 将更新提交到远程版本库中