赞
踩
当项目越来越庞大之后,不可避免的要拆分成多个子模块,我们希望各个子模块有独立的版本管理,并且由专门的人去维护,这时候我们可以使用git的subtree功能
git subtree add --prefix=<prefix> <repository> <branch> <ref> --squash 添加子仓库
git subtree pull --prefix=<prefix> <repository> <branch> --squash 拉取更新子仓库
git subtree push --prefix=<prefix> <repository> <branch> 推送修改到子仓库
例如我们要构建如下结构的项目
project
| --moduleA
| --readme.txt
创建project版本库,并提交readme.txt文件
git init --bare project.git
git clone project.git project1
cd project1
echo "This is a project." > readme.txt
git add .
git commit -m "add readme.txt"
git push origin master
cd ..
创建moduleA版本库,并提交a.txt文件
git init --bare moduleA.git
git clone moduleA.git/ moduleA
cd moduleA
echo "This is a submodule" > a.txt
git add .
git commit -m "add a.txt"
git push origin master
cd ..
在project项目中引入子模块moduleA,并提交子模块信息
cd project1
git subtree add --prefix=moduleA ../moduleA.git/ master --squash
git status
git push origin master
cd ..
--prefix
指明了存放子模块目录结构,../moduleA.git
是子模块的地址,--squash
参数,就是把subtree的子项目更新记录合并,再合并到主项目中。详细的分析请参看[git subtree相关问题。最后,记得push更新信息到远端。
与submodule命令不同,subtree克隆命令非常简单
git clone project.git project2
subtree
命令同时拉取父项目和子项目;而submodule
需要先克隆父项目,然后用submodule init
初始化,最后用submodule update
来拉取子模块
如果在project1
仓库中对moduleA
进行了修改,使用subtree push
将修改推送到moduleA
cd project1/moduleA/
echo "This is b.txt" > b.txt
git add .
git commit -m "update moduleA:add b.txt"
git push origin master
git subtree push --prefix=moduleA/ ../moduleA.git master
git push
将所有更新推送到父项目,git subtree push
将更新推送到子项目
当子模块进行了更新,父项目使用git subtree pull来获取更新
cd moduleA
echo "This is c.txt" > c.txt
git add .
git commit -m "add c.txt"
git push origin master
cd ../project1
git subtree pull --prefix=moduleA/ ../moduleA.git master --squash
删除使用subtree
管理的子模块非常简单,只要将子模块看成是普通文件进行删除即可
cd project1
git rm -rf moduelA
git commit -m "remote moduleA"
git push origin master
子模块的地址通常比较长,不容易记忆,这里我们可以将子仓库的地址作为一个remote,方便记忆
git remote add moduleA ../moduleA.git
然后可以简化subtree
命令
git subtree add --prefix=moduleA moduleA master --squash
git subtree pull --prefix=moduleA moduleA master --squash
git subtree push --prefix=moduleA moduleA master
Q:如何修改子模块存放的目录
A:对--prefix
进行修改即可,例如可以使用
git subtree add --prefix=sub/moduleA ../moduleA.git/ master --squash
来得到如下目录结构:
project
| --sub
|--moduleA
| --readme.txt
Q:subtree
和submodule
的不同之处?
A: 网络上很多讨论,例如 Differences between git submodule and subtree和浅谈「用 git submodule 还是 git subtree」?
,正如这些讨论中所说的那样"submodule is link, subtree is copy"是最本质的区别。更具体的优劣对比,参考下面的表格
/ | subtree | submodule | 对比结果 |
---|---|---|---|
远程仓库占用空间 | 子模块copy,占用较大空间 | 只是引用,基本不占空间 | 使用submodule的远程仓库占用空间较小,略优 |
本地仓库占用空间 | 会下载整个项目 | 可根据下载,但基本都要全部下载 | 所有模块基本都要下载,二者差异不大 |
克隆仓库 | 克隆马上可用 | 克隆后所有模块为空,需要注册和更新,更新后还要切分支 | submodule步骤多,subtree占优 |
更新本地仓库 | 所有子模块需要单独更细 | 更新后所有子模块指向最后一次提交,可能需要切回分支,所有模块可用一行命令更新 | subtree虽然要手动对子模块一个一个更新,但是更新后就可用,submodule需要切回分支,对比下subtree比较合适 |
提交本地修改 | 所有子模块单独更新,指令较复杂 | 只关心子模块即可,所有操作与普通git项目相同 | submodule优秀一丢丢 |
Q:使用subtree
或者submodule
有什么坑需要注意的?
A:请参看Git submodule的坑和git submoudle vs git subtree
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。