基于组件的项目很多,但是如果直接用包的方式直接引用到项目中,如果出现问题很难进行调试的操作,也很难进行组件的优化和管理,所以写了一篇文章来介绍下git submodule的用法,用submodule可以一定程度上解决组件难以管理的问题。接下来我用两个测试项目来演示下submodule的基本用法。
新建Git仓储库
在本地clone我们的父项目,并查看当前repository状态
添加子模块
命令:git submodule add XXXXX
查看当前repository状态,除了刚刚添加的 公共库模块外,还多了一个 .gitmodules 文件。这个文件就是用于记录子模块的路径对应远程版本库地址的地方
这两个文件处于待提交状态,我们把它推送到服务器。查看我们当前repository的目录
可以看见在我们git repository中多出一个modules的文件夹,这个是存放的我们子模块reposirory的相关信息,父模块不会记录submodule的变动,只会记录一个子模块提交日志的指针,后面我们可以在更新中看到相关的内容。到此为止,我们的子模块就建立完毕了,下面来说下submodule的一些操作。
到码云中查看我们当前的项目结构
可以在我们的项目目录中看见我们submodule引用的repository,后面的数据就是我们submodule提交的指针。我们把公共类库中的项目引用到当前项目,就能进行正常的开发调试工作了。但是为了强化我们公共类库的管理,一方面不能大范围的开放commit权限,另一方面我们使用中也尽量使用fork的方式来避免一些误操作更改了我们的公共类库(这种方式在更新方面就有点麻烦)。
submodule的更新
我们在公共类库中添加了一个名为SubModuleTest.txt的文件,并推送到服务器。
在我们项目中更新子模块组件使用命令 git submodule foreach git pull
可以看见我们指针的变化,而且当前reposirory有一个新的待提交更改,为什么更新之后还需要提交?其实,Git 在父仓库中记录了一个子模块的提交日志的指针,用于保存子模块的提交日志所处的位置,以保证无论子模块是否有新的提交,在任何一个地方克隆下项目时,各个子模块的记录是一致的。避免因为所引用的子模块不一致导致的潜在问题。如果我们更新了子模块,我们需要把这个最近的记录提交到版本库中,以方便和其他人协同。这也是刚刚添加完子模块后还要在父仓库中提交一次的原因。
把项目推送到码云上后,在码云中可以见看见我们指针的更改。
submodule克隆
clone Submodule有两种方式 一种是采用递归的方式clone整个项目,一种是clone父项目,再更新子项目。主要说下第一种方式这是最新的也是较简便的方式。
1. 采用递归参数 –recursive
git clone https://git.oschina.net/DekeXing/TestSubmoduleParent.git –recursive
可以看到init Submodule 会自动被clone下来。但是克隆submodule的时候可能因为用户名的原因而导致错误,可以提前让git记住账户名密码使用指令 git config –global credential.helper store
submodule删除
git rm XXXX
submodule的坑
submodule项目和它的父项目本质上是2个独立的git仓库。只是父项目存储了它依赖的submodule项目的版本号信息而已。如果你的同事更新了submodule,然后更新了父项目中依赖的版本号。你需要在git pull之后,调用 git submodule update来更新submodule信息。
这儿的坑在于,如果你git pull之后,忘记了调用 git submodule update,那么你极有可能再次把旧的submodule依赖信息提交上去。对于那些习惯使用 git commit -a的人来说,这种危险会更大一些。所以建议大家:
–.git pull之后,立即执行git status, 如果发现submodule有修改,立即执行git submodule update
–.尽量不要使用 git commit -a, git add命令存在的意义就是让你对加入暂存区的文件做二次确认,而 git commit -a相当于跳过了这个确认过程。
另外尽量不要在子模块中进行修改,即使用的是fork的方式,我们组件的修改还是统一到组件的reposirory中进行维护。
最后说下组件的问题,尽量把组件设计得低耦合一点,采取接口的方式,让组件的修改尽大可能不影响到组件的依赖项。