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:

  1. 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.
  2. 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 代替);

是要引用的项目的仓库地址;

引用的项目在 super project 中要存放的位置(下面用 libs\lib1 代替);

结果:

查看 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
2
3
4
--recursive, --recurse-submodules
After the clone is created, initialize all submodules within, using their default settings. This is equivalent to running git
submodule update --init --recursive immediately after the clone is finished. This option is ignored if the cloned repository
does not have a worktree/checkout (i.e. if any of --no-checkout/-n, --bare, or --mirror is given)

在 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
2
3
4
5
6
7
8
9
10
11
12
通过 4.3 其他开发人更新了 submodule,那么团队的其他人员如何同步到这个开发人员的更新内容;就是以下命令方式:
在开发人员 B 的电脑上执行:
git pull
git status
我们运行了git pull命令和git status获取了最新的仓库源码,然后看到了状态时modified 信息,就能看到 submodule 有变化
git diff # 比较一下不同点
git submodule init # 当需要更新子模块的内容时请先确保已经运行过 git submodule init
git submodule update

拉取所有子模块快捷命令总结git submodule foreach git pull
git submodule foreach --recursive git submodule init
git submodule foreach --recursive git submodule update

移除 Submodule

1
2
3
4
5
6
git 没有设计 git submodule remove 或者类似的命令,因此只能手动一步一步移除 submodule
git rm -r --cached libs/ # 删除git cache和物理文件夹
rm -rf libs/lib1
修改或者删除 .gitmodules 文件
删除.git/config 文件中的 submodule 配置
最后提交更改;

update submodule

https://stackoverflow.com/questions/5828324/update-git-submodule-to-latest-commit-on-origin?noredirect=1

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**
```

img

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 也会自动拉取子模块的更新

img

参考文档

git 官方文档

https://www.cnblogs.com/lsgxeva/p/8540758.html