Open chenqunfeng opened 6 years ago
当项目越来越庞大之后,不可避免的要拆分成多个子模块,我们希望各个子模块有独立的版本管理,并且由专门的人去维护,这时候我们就要用到git的submodule或subtree功能。
cd project // 父模块根目录 git submodule add A B // A:子模块的git地址;B:本地路径 // 可以看到目录下多了.gitmodules和对应的B目录 // 同时.git/config也多了对应的submodule配置(记住这几点变化,在删除子模块的时候会用到) git status git add . git commit -m "add submodule" git push origin master
至此,一个带有子模块的版本库就已经创建好并更新到远程仓库了
git clone A project // A为带有子模块的版本库的git地址 cd project // 可以看到.gitmodules文件和对应的子模块空文件夹 git submodule init // 初始化子模块,只需要初始化一次即可 git submodule update // 更新完之后,可以看到子模块文件夹中的文件已经都更新好了
克隆之后的主版本库中的子模块只是一个引用,所以默认没有内容;而远程仓库中对应子模块则是对应子模块的commit id引用
// 进入子模块目录之后,需要注意子模块的分支 // 刚克隆时,分支是默认的,而不是具体的分支 // 修改时需要对应checkout到对应的分支 cd project/common echo "This is a submodule." > common.txt git add . git commit -m "add common.txt" // 到目前为止我们更新了子模块并更新了子模块的代码到远程仓库 git push origin master cd .. git add . git commit -m "modify common" // 此时,将子模块的更改同步到父版本库中 // 可以看到仓库中对应的子模块的commit id已经更新为最新的commit id了 git push origin master
cd project git pull origin master git submodule update
还记得前面创建带子模块的版本库,git submodule add 之后增加的内容不,删除子模块时需要将这增加的内容全部清除干净。
git rm --cached common rm -rf common rm .gitmodules vim .git/config
// -f表示添加的同时fetch仓库资源;A:remote名称; B:远程git地址 git remote add -f A B // A:本地目录; B:远程git地址; C:分支 git subtree add --prefix=A B C --squash git add . git commit -m "add subtree" // 至此,带有子模块的版本库便创建好并更新到远程仓库了 // 而这里的common与submodule不一样,是一个完整的文件目录而不是一个引用 git push origin master
// 至此,一个带有子模块的版本库便克隆完成了 // 我们可以发现与submodule相比,少了初始化和更新的操作 git clone A project
cd project/common echo "This is subtree" > a.txt git add . git commit -m "add a.txt" // 向远程子模块推送代码更新,A:本地目录; B:前面添加的subtree的remote别名; C:分支 // 这里有点内容需要注意一下,就是A的路径设置需要和前面add的路径形式保持一致 // 否则可能会抛错:assertion failed git subtree push --prefix=A B C git push origin master // 更新父版本库的修改到父版本库
ps:其中,向子模块推送代码更新时,这个过程可能会很慢,因为它会自己去检查主仓库中的所有commit,然后找出实际上针对子模块更新的commit,然后再推送对应的commit
cd project/common // A:本地目录; B:前面添加的subtree的remote别名; C:分支 // 当主仓库有修改的代码,且未commit,这个时候去更新subtree的代码时 // 会提示Working tree has modifications. Cannot add. git subtree pull --prefix=A B C git status // 如果pull阶段会有子模块更新,你也看不到对应的修改项 git push origin master // 你只需要在更新完毕之后将更新推送到仓库即可
ps:如果都是在同一个父仓库中操作,或许你不需要care后面两个指令,但是如果你是在一个父仓库更新并推送了子模块的更新,然后在另一个父仓库中拉去子模块的最新代码并更新到远程仓库中,你的操作也跟正常的父仓库代码更新一样,没有任何不一致的地方
rm -rf common
从以上的各个操作来看,我们可以明显感受到submodule和subtree之间的差异性。 其中一个明显的感受就是subtree不需要像submodule一样每一次的代码更新都需要去更新subtree子模块的代码,subtree的子模块在更新和推送之外,就感觉跟一个普通的文件夹一样,而submodule则每次都需要执行git submodule update,否则则可能导致submodule的指向出错。 另外,除了以上的区别之外,在指令方面subtree除了pull和push的指令稍复杂之外,其他方面的操作也都优于submodule。
前言
当项目越来越庞大之后,不可避免的要拆分成多个子模块,我们希望各个子模块有独立的版本管理,并且由专门的人去维护,这时候我们就要用到git的submodule或subtree功能。
submodule
创建带子模块的版本库
至此,一个带有子模块的版本库就已经创建好并更新到远程仓库了
克隆一个带有子模块的版本库
克隆之后的主版本库中的子模块只是一个引用,所以默认没有内容;而远程仓库中对应子模块则是对应子模块的commit id引用
修改子模块,并更新到父版本库
更新子模块
删除子模块
还记得前面创建带子模块的版本库,git submodule add 之后增加的内容不,删除子模块时需要将这增加的内容全部清除干净。
subtree
创建带子模块的版本库
克隆一个带有子模块的版本库
// 至此,一个带有子模块的版本库便克隆完成了 // 我们可以发现与submodule相比,少了初始化和更新的操作 git clone A project
修改子模块,并更新到父版本库
ps:其中,向子模块推送代码更新时,这个过程可能会很慢,因为它会自己去检查主仓库中的所有commit,然后找出实际上针对子模块更新的commit,然后再推送对应的commit
更新子模块
ps:如果都是在同一个父仓库中操作,或许你不需要care后面两个指令,但是如果你是在一个父仓库更新并推送了子模块的更新,然后在另一个父仓库中拉去子模块的最新代码并更新到远程仓库中,你的操作也跟正常的父仓库代码更新一样,没有任何不一致的地方
删除子模块
rm -rf common
submodule与subtree的异同
从以上的各个操作来看,我们可以明显感受到submodule和subtree之间的差异性。 其中一个明显的感受就是subtree不需要像submodule一样每一次的代码更新都需要去更新subtree子模块的代码,subtree的子模块在更新和推送之外,就感觉跟一个普通的文件夹一样,而submodule则每次都需要执行git submodule update,否则则可能导致submodule的指向出错。 另外,除了以上的区别之外,在指令方面subtree除了pull和push的指令稍复杂之外,其他方面的操作也都优于submodule。