git subtree 和 git submodule

439 阅读4分钟

1.git submodule

什么是git submodule?

有2个概念:主项目、submodule(子模块)。这两者各自都是完整的 Git 仓库。git submodule就是在一个主项目中引入另一个git仓库作为子模块。

如何给一个项目添加submodule?

1.进入主项目A目录下,添加B仓库作为子模块

git submodule add {clone B仓库的地址}

执行完成后在项目A中会生成一个.gitmodules文件,该文件记录了主模块和子模块之间的引用关系

如何初始化项目的submodule?

(常用于新拉取一个带有submodule的项目的时候)

1.先​​git clone 主项目仓库​​,这时候submodule的文件夹都是空的。
2.执行git submodule update --init --recursive,执行完成以后子模块就有内容了

关于submodule的代码更新和提交

方式一:

cd {子模块名称} 进入子模块的目录,正常的执行git 命令

方式二:

前缀git submodule foreach命令即可操作子模块

比如:git submodule foreach git pull

推荐使用vscode的git工具,可以很方便的进行多个工程的代码版本管理

为了方便,我们可以增加一条自定义命令来拉取两个工程的代码:"update": "git pull && git submodule foreach git pull",以后每次执行npm run update即可一次性更新主模块和子模块

注意,有个坑

submodule项目和它的父项目本质上是2个独立的git仓库。只是父项目存储了它依赖的submodule项目的版本号信息而已。如果别人更新了submodule,然后更新了父项目中依赖的版本号。你需要在git pull之后,调用 git submodule update来更新submodule信息。

默认git submodule update并不会将submodule切到任何branch,所以,默认下submodule的HEAD是处于游离状态的(‘detached HEAD’ state)。所以在修改前,记得一定要确认当前子模块的分支,然后才能做修改和提交。

如果你不慎忘记切换到自己的分支分支,又做了提交,可以用cherry-pick命令挽救。具体做法如下:
1.用 git checkout 将HEAD从游离状态切换到 自己的 分支, 这时候,git会报Warning说有一个提交没有在branch上,记住这个提交的change-id(假如change-id为 aaaa)
2.用 git cherry-pick aaaa 来将刚刚的提交作用在 自己的 分支上
3.用 git push 将更新提交到远程版本库中

2.git subtree

git subtree add

使用场景: 添加subtree

完整命令:git subtree add --prefix={目录路径} xxxx.git branch --squash

git subtree pull

使用场景: subtree代码有更新,需要同步到本工程

完整命令: git subtree pull --prefix={目录路径} xxxx.git branch --squash

注意:不加--squash可能会报错

git subtree push

使用场景: 在父工程修改了subtree的内容,需要把修改同步到subtree的git仓库

完整命令: git subtree push --prefix={目录路径} xxxx.git branch

但是会很慢,subtree push实际上是遍历本工程每一次提交,把提交文件涉及到subtree目录的挑出来,同步到subtree工程,如果提交有很多,遍历提交的过程是有严重的性能问题的,在2.19版本以前的git是可以执行的,但是很慢,在2.19以上的版本,会直接抛出异常。

git subtree split

使用场景: 提升subtree push效率

完整命令: git subtree split --prefix={目录路径} --rejoin

执行split命令后,会看到主工程的提交记录,产生了一个新的分支,且这个分支和subtree push操作的逻辑一样,只把涉及subtree目录的提交摘出来了,最终这个分支合并到原分支,产生了一个Split xxxxx的提交记录。

后续再执行subtree push操作,git只会检索split以后的提交,达到减少检索次数的目的,提升push性能。

git rm -r

使用场景: 在父工程中移除subtree,或者切换subtree的分支。如果要切换subtree的分支,就需要用该命令先移除,后执行git subtree add添加

注意:执行该操作前一定要确保subtree的代码已经提交,否则移除等于直接本地删除,会丢失代码

简化操作

在 subtree 相关命令经常会用到 每次都写地址还是比较麻烦,这里可以用 git remote 命令简化写法,为这个远程地址定义一个 “别名”:

git remote add common xxxx.git

比如使用 subtree push 的时候就可以使用如下命令:

git subtree push --prefix={目录路径} develop

3.对比