1. 问题描述:
假设我们在 root-project 里需要添加3个submodules:A和B是根项目的子模块。 C又是项目A的子模块。
root-project | |-- A | | | |-- C | |-- B
2. 准备工作
mkdir repository // 模拟远程仓库位置 // 模拟远程子模块A&B git init --bare repository/submodule_A.git git init --bare repository/submodule_B.git // 初始化子模块A&B用于测试 mkdir init cd init git clone ../repository/submodule_A.git git clone ../repository/submodule_B.git echo "" > submodule_A/"This is submolue A".txt echo "" > submodule_B/"This is submolue B".txt cd submodule_A git add . git commit -m "init" git push cd submodule_B git add . git commit -m "init" git push // 模拟工程目录 git init --bare repository/prj.git git clone repository/prj.git prj/myprj // 指定路径的话会修改*.git原来目录的名称 cd prj/myprj/
echo "" > "This is root project".txt
目录结构:
. |-- init | |-- submodule_A | `-- submodule_B |-- prj | `-- myprj `-- repository |-- prj.git |-- submodule_A.git `-- submodule_B.git
3. 使用submodule进行管理
添加子模块A&B
// 使用*.git默认的名称你需要先切换到想放置的目录 git submodule add ../../repository/submodule_A.git/ // 重新命名文件夹,命名“submodule_B” 为 “renamedB” git submodule add ../../repository/submodule_B.git/ renamedB
结果示意:
$ tree . |-- This is root project.txt |-- renamedB | `-- This is submolue B.txt `-- submodule_A `-- This is submolue A.txt
4. submodule修改提交
4.1 提交修改
切换到submodule的路径下,和git的使用方式相同:
$ cd submodule_A/ $ echo "" > submodule_A/"modified in A".txt $ git add . $ git commit -m "modified"
4.2 更新到远程分支
第1种是直接push:
$ git push
试想一下:
1. 如果你一个工程里有多个submodules,虽然你每次修改子模块时都有commit;
2. 但是因为prj没有完成,或者子模块还没有修改到可以发布的程度,所以你每次commit 后并不想更新远程分支。
3. prj工程已经完成,可以push工程里所有的submodule到远程分支了;但是如果一个个路径再打开push,太麻烦。
这时就可以使用递归的方法:
// 模拟修改过程 $ cd submodule_A/ echo "" > "modified 2 in A".txt $ git add . $ git commit -m "modified 2" $ cd ../renamedB/ echo "" > "modified 2 in B".txt $ git add . $ git commit -m "modified 2" // 提交prj修改记录 $ cd .. $ git add . $ git commit -m "update now"
第2种:使用递归push:
git push --recurse-submodules=check // 如果子模块没有提交,会直接报错 // or git push --recurse-submodules=on-demand // 如果子模块没有提交,会尝试提交,提交不成功同时会阻止主仓库的推送
4. 带有submodule仓库的克隆方法
1. 直接clone的话是没有submodule信息的,只有文件夹。
mkdir local $ git clone ../repository/prj.git cloneDirect $ cd cloneDirect/ $ tree -a -L 2 . |-- .git | |-- HEAD | |-- config | |-- description | |-- hooks | |-- index | |-- info | |-- logs | |-- objects | |-- packed-refs | `-- refs |-- .gitmodules |-- This is root project.txt |-- renamedB `-- submodule_A 8 directories, 7 files
这是因为,父项目的git并不会记录submodule的文件变动,它是按照commit id指定submodule的git header。
不过可以先对submodule初始化,然后更新,就可以clone到原module的内容。
2. 第二种方式使用递归clone,添加参数 --recursive。
在远程修改submodule及本地更新submodule
1. 远程更新submodule
2. 本地更新submodule
2.1 直接pull或者更新submodule是无效的,因为远程prj.git并未记录submodule有任何的改动,即远程prj.git不知道也根本不管submodule有没有更新,除非你在prj.git有commit记录。
2.2 在这种情况下仍要更新submodule,就需要直接进入submodule仓库下并切换为需要的分支进行更新。
2.3 这时prj.git 理所当然地发生了变化,根据需要提交变更记录即可。
在本地修改submodule并push后,他处submodule更新流程
1. 本地A修改submodule并Push
1.1. 现在本地submodule添加一个新功能:c.md,然后push。
1.2 接着,提交本次prj.git的变更记录:
2. 他处B更新submodule
2.1 pull后发现submodule发生了改动:
2.2 使用update对submodule进行更新
删除submodule
1. git rm moduleA,即可
这样做git的config文件中仍有相关记录,但是不影响使用,如果新clone的话,就不会有相关的记录了。
如果介意可以手动将该文件的相关行删除。
2. 新clone后,config则无相关记录
echo "" > "This is root project".txt
|