Git Submodule 管理项目子模块

本贴最后更新于 2084 天前,其中的信息可能已经时移世改

使用场景

当项目越来越庞大之后,不可避免的要拆分成多个子模块,我们希望各个子模块有独立的版本管理,并且由专门的人去维护,这时候我们就要用到 git 的 submodule 功能。

常用命令

git clone <repository> --recursive 递归的方式克隆整个项目
git submodule add <repository> <path> 添加子模块
git submodule init 初始化子模块
git submodule update 更新子模块
git submodule foreach git pull 拉取所有子模块

如何使用

1. 创建带子模块的版本库

例如我们要创建如下结构的项目

project
  |--moduleA
  |--readme.txt

创建 project 版本库,并提交 readme.txt 文件

git init --bare project.git
git clone project.git project1
cd project1
echo "This is a project." > readme.txt
git add .
git commit -m "add readme.txt"
git push origin master
cd ..

创建 moduleA 版本库,并提交 a.txt 文件

git init --bare moduleA.git
git clone moduleA.git moduleA1
cd moduleA1
echo "This is a submodule." > a.txt
git add .
git commit -m "add a.txt"
git push origin master
cd ..

在 project 项目中引入子模块 moduleA,并提交子模块信息

cd project1
git submodule add ../moduleA.git moduleA
git status
git diff
git add .
git commit -m "add submodule"
git push origin master
cd ..

使用 git status 可以看到多了两个需要提交的文件,其中 .gitmodules 指定 submodule 的主要信息,包括子模块的路径和地址信息,moduleA 指定了子模块的 commit id,使用 git diff 可以看到这两项的内容。这里需要指出父项目的 git 并不会记录 submodule 的文件变动,它是按照 commit id 指定 submodule 的 git header,所以 .gitmodulesmoduleA 这两项是需要提交到父项目的远程仓库的。

On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
    new file:   .gitmodules
    new file:   moduleA

2. 克隆带子模块的版本库

方法一,先 clone 父项目,再初始化 submodule,最后更新 submodule,初始化只需要做一次,之后每次只需要直接 update 就可以了,需要注意 submodule 默认是不在任何分支上的,它指向父项目存储的 submodule commit id。

git clone project.git project2
cd project2
git submodule init
git submodule update
cd ..

方法二,采用递归参数 --recursive,需要注意同样 submodule 默认是不在任何分支上的,它指向父项目存储的 submodule commit id。

git clone project.git project3 --recursive

3. 修改子模块

修改子模块之后只对子模块的版本库产生影响,对父项目的版本库不会产生任何影响,如果父项目需要用到最新的子模块代码,我们需要更新父项目中 submodule commit id,默认的我们使用 git status 就可以看到父项目中 submodule commit id 已经改变了,我们只需要再次提交就可以了。

cd project1/moduleA
git branch
echo "This is a submodule." > b.txt
git add .
git commit -m "add b.txt"
git push origin master
cd ..
git status
git diff
git add .
git commit -m "update submodule add b.txt"
git push origin master
cd ..

4. 更新子模块

更新子模块的时候要注意子模块的分支默认不是 master。

方法一,先 pull 父项目,然后执行 git submodule update,注意 moduleA 的分支始终不是 master。

cd project2
git pull
git submodule update
cd ..

方法二,先进入子模块,然后切换到需要的分支,这里是 master 分支,然后对子模块 pull,这种方法会改变子模块的分支。

cd project3/moduleA
git checkout master
cd ..
git submodule foreach git pull
cd ..

更换子模块的远程版本库

比如我想更换为我 fork 过来的远程版本库

  1. 编辑.gitmodules
  2. git submodule update --init --recursive --remote

5. 删除子模块

网上有好多用的是下面这种方法

git rm --cached moduleA
rm -rf moduleA
rm .gitmodules
vim .git/config

删除 submodule 相关的内容,例如下面的内容

[submodule "moduleA"]
      url = /Users/nick/dev/nick-doc/testGitSubmodule/moduleA.git

然后提交到远程服务器

git add .
git commit -m "remove submodule"

但是我自己本地实验的时候,发现用下面的方式也可以,服务器记录的是 .gitmodulesmoduleA,本地只要用 git 的删除命令删除 moduleA,再用 git status 查看状态就会发现.gitmodules 和 moduleA 这两项都已经改变了,至于.git/config,仍会记录 submodule 信息,但是本地使用也没发现有什么影响,如果重新从服务器克隆则.git/config 中不会有 submodule 信息。

git rm moduleA
git status
git commit -m "remove submodule"
git push origin master
  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:SymSoloVditor思源笔记

    1083 引用 • 3461 回帖 • 257 关注
  • Git

    Git 是 Linux Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。

    207 引用 • 358 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...