Git Submodule 的使用
GitSubmodule 是一种在 git repository 中嵌入另外一个 git repository ,并在两个 repository 之间建立关系的一种技术
简单来说 Git Submodule 是一种在 git repository 中嵌入另外一个 git repository ,并在两个 repository 之间建立关系的一种技术。这样有什么作用呢?他可以把原本多个独立的 repository 通过这种技术放在一个 repository 中进行集成管理,以 repository 的维度对一个大项目进行模块划分。具体的用法和好处接下来我们慢慢讲述。
解释:
![imp://confluence.cbim.org.cn:8090/download/attachments/67820378/image2020-3-31_14-39-49.png?version=1&modificationDate=1654071841000&api=v2)
submodule 也是仓库;
嵌入在其他项目的仓库中;
一套代码体系,在 superproject 和 submodule 自己的 project 都可以发起修改操作;
使用场景
想使用其他项目的代码,但又想保持独立的操作记录;
引用一段《Git权威指南》的话: 项目的版本库在某些情况虾需要引用其他版本库中的文件,例如公司积累了一套常用的函数库,被多个项目调用,显然这个函数库的代码不能直接放到某个项目的代码中,而是要独立为一个代码库,那么其他项目要调用公共函数库该如何处理呢?分别把公共函数库的文件拷贝到各自的项目中会造成冗余,丢弃了公共函数库的维护历史,这显然不是好的方法。
把一个大项目拆分成不同的仓库,然后又想把这些仓库以某种方式集合在一起;
Git Doc DESCRIPTION (官方解释)
A submodule is a repository embedded inside another repository. The submodule has its own history; the repository it is embedded in is called a superproject.
On the filesystem, a submodule usually (but not always - see FORMS below) consists of (i) a Git directory located under the $GIT_DIR/modules/
directory of its superproject, (ii) a working directory inside the superproject’s working directory, and a .git
file at the root of the submodule’s working directory pointing to (i).
Assuming the submodule has a Git directory at $GIT_DIR/modules/foo/
and a working directory at path/to/bar/
, the superproject tracks the submodule via a gitlink
entry in the tree at path/to/bar
and an entry in its .gitmodules
file (see gitmodules(5)) of the form submodule.foo.path = path/to/bar
.
The gitlink
entry contains the object name of the commit that the superproject expects the submodule’s working directory to be at.
The section submodule.foo.*
in the .gitmodules
file gives additional hints to Git’s porcelain layer. For example, the submodule.foo.url
setting specifies where to obtain the submodule.
Submodules can be used for at least two different use cases:
- Using another project while maintaining independent history. Submodules allow you to contain the working tree of another project within your own working tree while keeping the history of both projects separate. Also, since submodules are fixed to an arbitrary version, the other project can be independently developed without affecting the superproject, allowing the superproject project to fix itself to new versions only when desired.
- Splitting a (logically single) project into multiple repositories and tying them back together. This can be used to overcome current limitations of Git’s implementation to have finer grained access:
- Size of the Git repository: In its current form Git scales up poorly for large repositories containing content that is not compressed by delta computation between trees. For example, you can use submodules to hold large binary assets and these repositories can be shallowly cloned such that you do not have a large history locally.
- Transfer size: In its current form Git requires the whole working tree present. It does not allow partial trees to be transferred in fetch or clone. If the project you work on consists of multiple repositories tied together as submodules in a superproject, you can avoid fetching the working trees of the repositories you are not interested in.
- Access control: By restricting user access to submodules, this can be used to implement read/write policies for different users.
使用方法介绍
为主项目添加Submodules
命令:git submodule add
解释:
在 super project 中执行(下面用 superproject 代替);
结果:
查看 superproject 当前的状态发现添加了一个新文件(.gitmodules) 和
.gitmodules 记录了每个 submodule 的引用信息,知道在当前项目的位置以及仓库的所在。
Clone 带有 Submodule 的仓库
一般操作:git clone <repository url>
然后进入项目根目录。执行以下命令;
1 | git submodule |
看到 显示的 submodules 的状态是hash码和文件目录,但是注意前面有一个减号:**-**,含义是该子模块还没有检出。
检出 submodule 命令: git submodule init
结果是:开始 clone submodule 了;
多个步骤比较麻烦,总结一下简单的方法:
git clone --recursive <repository url>
–recursive 参数的含义:可以在clone项目时同时clone关联的 submodules。
git help 对其解释:
1 | --recursive, --recurse-submodules |
在 superproject 中修改 submodule
在 superproject 目录下执行
cd libs/lib1
git status
git checkout master # 切换到子模块的 master 分支 (也可以是其他分支,这里只是做一下示意)
git remote -v # 验证当前所处的分支
## 做一些 lib1 的修改操作;
git status
git add .
git commit -m “xxx”
git push # push 到的是 lib1 的远程仓库(通过 merge request 最终合并到 master 分支,下面的操作不是必要的)
-————————————————
cd superproject
git add -A
git comm -m “xxx”
这时候会发现 superproject 下引用的 libs\lib1 的Head Id才会变化
其他开发人员更新主项目的 Submodules
1 | 通过 4.3 其他开发人更新了 submodule,那么团队的其他人员如何同步到这个开发人员的更新内容;就是以下命令方式: |
移除 Submodule
1 | git 没有设计 git submodule remove 或者类似的命令,因此只能手动一步一步移除 submodule |
update submodule
The git submodule update
command actually tells Git that you want your submodules to each check out the commit already specified in the index of the superproject. If you want to update your submodules to the latest commit available from their remote, you will need to do this directly in the submodules.
So in summary:
1 | # Get the submodule initially``git submodule add ssh:``//bla submodule_dir``git submodule init` `# Time passes, submodule upstream is updated``# and you now want to update` `# Change to the submodule directory``cd submodule_dir` `# Checkout desired branch``git checkout master` `# Update``git pull` `# Get back to your project root``cd ..` `# Now the submodules are in the state you want, so``git commit -am ``"Pulled down update to submodule_dir" |
Or, if you’re a busy person:
```
**git submodule foreach git pull origin release**
```
git checkout 同时更新子模块
参考链接:https://www.codenong.com/1899792/
默认情况,如果切换分支前后的两个分支的 submodule 子模块的版本不一致, git checkout
git checkout –recurse-submodules已添加到git 2.13
在发行说明中提到了这一点:https://github.com/git/git/commit/e1104a5ee539408b81566066aaa6963cb87d5cd6#diff-c24776ff22455a30fbb78e378b7df0b0R139
submodule.recurse选项已添加到git 2.14
设置:
1 | git config –global submodule.recurse true |
---|---|
man git-config说:
Specifies if commands recurse into submodules by default. This applies to all commands that have a –recurse-submodules option. Defaults to false.
设置 submodule.recurse true 后,不仅仅 git checkout 会自动切换子模块,git fetch / pull 也会自动拉取子模块的更新
参考文档
git 官方文档