1 Introduction
Both Git Submodule and Git Subtree are functions in the Git version control system for managing subprojects in a code repository.
-
Git Submodule (submodule):
- Submodules refer to bringing in an independent Git repository as part of another Git repository.
- Submodules allow one codebase to be included in another codebase and treated as part of the submodule, enabling independent version control between the parent and child repositories.
- Submodules work by keeping a reference to the subrepo in the parent repository as a separate directory.
- Submodule updates require specific commands to be executed manually.
-
Git Subtree (subtree):
- Subtrees allow copying subdirectories of one Git repository into another Git repository, keeping separate version histories for both.
- Subtrees are implemented by duplicating the specified directory of the subrepo and making it a subdirectory of the parent repo.
- Subtrees can be used to integrate code from one project, along with the associated commit history, into another without requiring the entire subrepo to be brought in as a submodule.
- Subtree updates can be made like any other Git commit, no special commands are required.
The choice of the two depends on the specific usage scenarios and requirements:
- If you want to maintain independent version control between the parent warehouse and the sub-warehouse, and need to manually manage the updates of the sub-warehouse (such as switching branches, pulling the latest code, etc.), you can choose Git Submodule.
- If you just want to integrate part of the code of one project into another project, and want to be able to manage the update of subdirectories like normal code, you can choose Git Subtree.
2. Submodule use
2.1 Initialize the project
Main project main-git: git clone [email protected] :f5l5y5/main-git.git
Sub-project sub-components: git clone [email protected] :f5l5y5/sub-components.git
子项目:sub-utils: git clone [email protected]:f5l5y5/sub-utils.git
添加子模块:
git submodule add [email protected]:f5l5y5/sub-utils.git utils
git submodule add [email protected]:f5l5y5/sub-components.git components
命令说明: 添加子模块到当前文件夹下 utils/components 目录下
2. 提交、拉取、更新
- 提交
修改子项目sub-utils,需要进入utils文件夹,进行单独提交。此时父项目会有一条关于子项目变更记录,进行提交即可。 单独拥有自己的.git文件,commit也是单独的。
例如:
修改子项目:
父项目:
两个进行提交后:
- 拉取、更新
拉取仓库主项目代码:git clone [email protected]: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 |
参考文章: