git 子模块在项目中的使用
在公司的项目中, 经常会遇到一些公共的内容, 多个项目中间通用的, 不可能每次都将整个代码复制一遍, 遇到这种情况有很多不同的解决方案, 一般来说, 项目是通过 git 来管理的, 巧了, git 也同样支持子模块.
创建子模块
git submodule add git@gitee.com:hujingnb/submodule_son.git submodule_son
指定子项目地址, 后面的参数可以更改子模块的路径. 这步操作可给当前项目添加一个子模块.
克隆新项目
当团队加入新人时, 需要将原项目 down 下来. 操作如下:
git clone xxxx.git
(克隆项目)git submodule init
(子模块初始化)git submodule update
(更新子模块)
当然, 最好一条命令就能搞定:
git clone --recursive xxxx.git
子模块操作
对于子模块的更新,提交等操作, 进入对应路径, 正常操作即可.
问题
以上对于子模块的使用, 网上有各种教程, 在此不再赘述.
而我在使用中遇到的问题是这样的: 公司的代码库分为测试环境与生产环境两个分支: dev
, master
. 由于git
对于子模块的管理并不是基于分支, 而是基于commit id
的. 这对于引用第三方库是可以理解的, 毕竟需要一个稳定的版本嘛. 但是对于公司这种需要频繁更新的项目, 就有些混乱了.
举个例子, 经常会有多个任务并行执行的情况, 如果有些任务后开发, 又需要先行合到生产环境, 可能会提交了较新的commit id
上去. 故而并不像分支管理一样, 直接拉取分支即可. 这又该如何是好呢?
不同分支
对于这个问题, 我想了很久. 要想实现分支的正常管理, 还是应该不同环境对应不同的分支, 但是子模块只能指定commit id
, 不能对应分支. 如此一来, 那就只有一个办法, 不同分支指定不同的commit id
, 这也是我能想到的最清楚,最符合流程的方式了. 也就是说, 子模块也切为dev
, master
两个分支, 也正常进行合并. 而对于父项目来说, 将子项目切换到不同的分支, 每次提交之后, 将子模块分支拉取到最新, 然后将commit id
提上去, 不就解决了么...
流程如下:
- 切换子模块分支:
git submodule foreach git checkout master
- 将子模块分支拉取到最新:
git submodule foreach git pull
- 提交
commit id
:git add .; git commit -m ""; git push;
然后将以上操作写到脚本中, 每次自动化拉取最新代码即可.
如此一来, 子模块的管理就和正常流程一致了, 将不同环境代码合并到不同分支, 分别拉取对应分支代码即可.
此方法是我自己想到的, 是否可行还有待验证
子模块冲突
既然子模块是根据commit id
进行管理的, 那么当不同的人提交了不同的commit id
上来的时候, 就很有可能存在冲突.
先说一下我是如何制造冲突的:
- 父项目与子模块分别拉取分支:
master_tmp
- 父项目与子模块切回
master
分支 - 子模块修改文件并提交, 父项目更新
commit id
- 此时父子都回到
master_tmp
分支, 修改同一行内容,并提交commit id
- 将父项目
master_tmp
合并到master
分支
此时冲突如下:
对于没有接触过子模块的我来说, 有如下问题:
- 这两个
commit id
我怎么知道哪个是最新的? 总不能一个一个去找吧 submodule_son
连个文件都没有, 我该怎么解决这个冲突???
如此该如何解决呢? 很明显, 这个冲突是子项目的冲突, 所以要进入子项目解决. 主要的思想当然还是解决分支之间的冲突.
- 将子模块分支切到
master
:git checkout master
- 将子模块产生冲突的提交新建一个分支:
git branch merge_tmp a8f5f8c
- 将子项目合并到
master
:git merge merge_tmp
- 解决子项目的冲突
- 再次回来查看, 冲突解决, 提交即可
子模块冲突解决完毕后, 再回来查看:
此时冲突已经解决完成, 提交即可.
同理, 当你不方便操作master
分支的时候, 将master
合并到你自己的分支, 然后解决冲突, 是一样的.
至此, 基本解决了子模块的不同环境问题, 后面遇到问题再说吧.