Git Submodule和Git Subtree使用
1. 前言
Git Submodule和Git Subtree都是Git版本控制系统中用于管理代码库中的子项目的功能。
-
Git Submodule(子模块):
- 子模块是指将一个独立的Git仓库作为另一个Git仓库的一部分引入。
- 子模块允许在一个代码库中包含另一个代码库,并将其视为子模块的一部分,可以在父仓库和子仓库之间进行独立的版本控制。
- 子模块通过在父仓库中保存子仓库的引用,并将其作为一个单独的目录存在。
- 子模块的更新需要手动执行特定的命令。
-
Git Subtree(子树):
- 子树允许将一个Git仓库的子目录复制到另一个Git仓库中,并保持两者独立的版本历史。
- 子树是通过复制子仓库的指定目录,并将其作为父仓库的子目录来实现的。
- 子树可以用于将一个项目的代码以及相关的提交历史集成到另一个项目中,而不需要将整个子仓库作为子模块引入。
- 子树的更新可以像其他Git提交一样进行,不需要特殊的命令。
两者的选择取决于具体的使用场景和需求:
- 如果您希望在父仓库和子仓库之间保持独立的版本控制,并且需要手动管理子仓库的更新(如切换分支、拉取最新代码等),那么可以选择Git Submodule。
- 如果您只是希望将一个项目的部分代码集成到另一个项目中,并且希望能够像处理普通代码一样管理子目录的更新,那么可以选择Git Subtree。
2. submodule 使用
2.1 初始化项目
主项目main-git: git clone git@github.com:f5l5y5/main-git.git
子项目sub-components: git clone git@github.com:f5l5y5/sub-components.git
子项目:sub-utils: git clone git@github.com:f5l5y5/sub-utils.git
添加子模块:
git submodule add git@github.com:f5l5y5/sub-utils.git utils
git submodule add git@github.com:f5l5y5/sub-components.git components
命令说明: 添加子模块到当前文件夹下 utils/components 目录下
2. 提交、拉取、更新
- 提交
修改子项目sub-utils,需要进入utils文件夹,进行单独提交。此时父项目会有一条关于子项目变更记录,进行提交即可。 单独拥有自己的.git文件,commit也是单独的。
例如:
修改子项目:
父项目:
两个进行提交后:
- 拉取、更新
拉取仓库主项目代码:git clone git@github.com:f5l5y5/main-git.git
子项目没有文件
获取子项目代码:
git submodule init
git submodule update
// 合并
git submodule update --init
嵌套子项目情况:
git submodule update --init --recursive // 递归进行更新拉取
- 一次性拉取
git clone --recursive git@github.com:f5l5y5/main-git.git
或
git clone --recurse-submodules git@github.com:f5l5y5/main-git.git
总结
-
添加子模块:
git submodule add <子模块仓库URL> <子模块目录>
这个命令将子模块添加到父仓库中,并指定子模块的仓库URL和子模块在父仓库中的目录位置。
-
克隆父仓库和子模块:
- 如果你是第一次克隆父仓库,可以使用以下命令:
这个命令会同时克隆父仓库和子模块,并获取子模块的代码和提交历史。git clone --recurse-submodules <父仓库的URL>
- 如果你已经克隆了父仓库但没有子模块的代码,请在父仓库的根目录中执行以下命令:
git submodule update --init --recursive
- 如果你是第一次克隆父仓库,可以使用以下命令:
-
更新子模块:
- 进入父仓库的根目录,在命令行中执行以下命令来更新子模块:
这个命令将拉取子模块的最新代码。git submodule update --remote <子模块目录>
- 进入父仓库的根目录,在命令行中执行以下命令来更新子模块:
-
切换子模块分支:
- 进入父仓库的根目录,在命令行中执行以下命令来切换子模块的分支:
这个命令将在子模块中切换到指定分支,并拉取最新代码。cd <子模块目录> git checkout <分支名> git pull origin <分支名> cd ..
- 进入父仓库的根目录,在命令行中执行以下命令来切换子模块的分支:
3. subtree使用
3.1 添加子树
git subtree add --prefix=components git@github.com:f5l5y5/sub-components.git main
git subtree add --prefix=utils git@github.com:f5l5y5/sub-utils.git main
必须在顶层运行:
运行后:
- 子项目没有.git 文件
- subtree 的方式在创建目录的时候会生成一个 commit
文件结构:
3.2 提交、拉取、更新
- 提交
如果修改子项目一个文件
git add .
git commit -m "xxx"
git push origin main //推送主项目
如果在主项目中直接使用git push 子项目是不会更新
只推送子项目
git remote add utils git@github.com:f5l5y5/sub-utils.git // 定义utils远程仓库别名
git subtree push --prefix=utils utils main
- 拉取、更新
- 直接拉取,会将所有子项目拉取
- 更新,如果子项目有更新,主项目需要更新,则使用git subtree pull --prefix=utils gitUrl main
更新是会生成一条merge记录,将子项目的提交合并到主项目。
subtree使用总结
以下是Git Subtree的一些常用操作和用法:
-
添加子树:
- 添加一个子树到父仓库:
git subtree add --prefix=<子树目录> <子树仓库URL> <子树分支>
- 添加一个子树到父仓库:
-
拉取子树更改:
- 提取子树的更改到父仓库中:
git subtree pull --prefix=<子树目录> <子树仓库URL> <子树分支>
- 提取子树的更改到父仓库中:
-
推送子树更改:
- 推送父仓库对子树的更改到子树仓库:
git subtree push --prefix=<子树目录> <子树仓库URL> <子树分支>
- 示例:
- 推送父仓库对子树的更改到子树仓库:
-
查看子树的提交历史:
- 查看子树的提交历史:
git log --prefix=<子树目录>
- 示例:
git log --prefix=vendor/mylibrary
- 查看子树的提交历史:
-
移除子树:
- 从父仓库中移除子树:
git subtree remove --prefix=<子树目录>
- 从父仓库中移除子树:
总结
git submodule和subtree根据使用场景自己进行选择,主要区别如下:
总结 | submodule | subtree |
---|---|---|
添加 | git submodule add gitUrl 文件夹名称 | git subtree add --prefix=文件夹名称 gitUrl branch |
.git文件 | 每个子项目都会有单独的.git | 子项目没有单独的.git |
单独提交子代码 | 到子项目文件夹下 | 使用git subtree push --prefix=utils gitUrl main |
主项目提交代码 | 子项目提交主项目会生成记录 | 可以直接提交,不会影响子项目 |
拉取子项目更新 | git submodule update --recursive | git subtree pull --prefix=utils gitUrl main --squash |
参考文章:
转载自:https://juejin.cn/post/7253391363453288506