Git Submodule

Git Submodule

July 17, 2018
git

基于公司的项目会越来越多,常常需要提取公共的library提供给多个项目使用,但是这个library怎么和git在一起方便管理呢?

我们需要解决下面几个问题:

  • 如何在git项目中导入library?
  • library在其他的项目中被修改了可以更新到远程的代码库中?
  • 其他项目如何获取到library最新的提交?
  • 如何在clone的时候能够自动导入library?

解决以上问题,可以考虑使用git的submodule来解决。

什么是submodule? #

git submodule 是一个很好的多项目使用共同类库的工具, 他允许把公共的library以子项目引用的形式添加到父项目中。子项目可以有自己独立的commit, push, pull,而父项目以submodule的形式包含子项目,父项目可以指定子项目header,父项目中的提交信息包含submodule的信息,在clone父项目的时候可以把submodule初始化。

使用submodule #

使用git命令可以直接添加submodule

git submodule add [email protected]:maxnilz/submodule-demo-library.git library

使用git status

$ git status

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:   library

看到多了两个需要提交的文件: .gitmoduleslibrary


.gitmodules 内容包含 submodule的主要信息: 远端仓库地址和本地路径

$ cat .gitmodules
[submodule "library"]
        path = library
        url = [email protected]:maxnilz/submodule-demo-library.git

library内容只保存了子项目的commit id, 就能指定到对应的git header上, 例如:

submodule-demo-library commit eee8ab4824474b83a2e606c927dc7eb8f465031c

eee8ab4824474b83a2e606c927dc7eb8f465031c 是子项目的commit id, 父项目并不会记录submodule的文件变动,它是按照commit git指定submodulegit header


.gitmoduleslibrary都需要提交到父项目的git中

$ git add .gitmodules library
$ git commit -m 'library submodule'

修改submodule #

$ cd library
# 修改其中的一个文件,submodule的status:
$ mkdir test_fixtures
$ touch test_fixtures/oidc.yaml
$ git status

On branch master
Your branch is up-to-date with 'origin/master'.
Untracked files:
  (use "git add <file>..." to include in what will be committed)

 test_fixtures/

nothing added to commit but untracked files present (use "git add" to track)
$提交submodule的更改内容:
$ git commit -a -m'test submodule'
# 然后`push`到远端
$ git push
# 然后再回到父目录, 提交`submodule`在父项目中的变动:
$ cd ..
$ git status

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:   library

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

 modified:   library (new commits)
# 可以在父项目中看到`submodule` library 中有新的commit, 需要把`submodule`的变动信息更新到父项目的远端
$ git add .
$ git commit -m'update submodule'
$ git push

更新submodule #

更新submodule有两种方式:

  1. 在父项目的目录下直接运行
$ git submodule foreach git pull
  1. 在submodule的目录下更新
$ cd library
$ git pull

可以看到在submodule的目录中, 使用git和单独的一个项目是一样的, 注意更新submodule的时候如果有新的commit id产生, 需要在父项目产生一个新的提交。

clone submodule #

clone submodule 有两种方式

  • 采用递归的方式clone整个项目
  • clone父项目, 再更新子项目

使用递归参数 –recursive #

$ git clone [email protected]:maxnilz/submodule-demo.git --recursive

Cloning into 'submodule-demo'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
Receiving objects: 100% (11/11), done.
Resolving deltas: 100% (2/2), done.
remote: Total 11 (delta 2), reused 3 (delta 0), pack-reused 0
Checking connectivity... done.
Submodule 'library' (git@maxnilz:maxnilz/submodule-demo-library.git) registered for path 'library'
Cloning into 'library'...
remote: Counting objects: 12, done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 12 (delta 2), reused 5 (delta 1), pack-reused 0
Receiving objects: 100% (12/12), done.
Resolving deltas: 100% (2/2), done.
Checking connectivity... done.
Submodule path 'library': checked out '888175de4e5e624e8e2bb6deb524fbda2bd931a3'

可以看到library submodule会被自动clone下来

先clone父项目,再初始化submodule #

clone 父项目 #

$ git clone [email protected]:maxnilz/submodule-demo.git
$ cd submodule-demo
$ git submodule init

Submodule 'library' (git@maxnilz:maxnilz/submodule-demo-library.git) registered for path 'library'

然后 更新submodule #

$ git submodule update
Cloning into 'library'...
remote: Counting objects: 12, done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 12 (delta 2), reused 5 (delta 1), pack-reused 0
Receiving objects: 100% (12/12), done.
Resolving deltas: 100% (2/2), done.
Checking connectivity... done.
Submodule path 'library': checked out '888175de4e5e624e8e2bb6deb524fbda2bd931a3'

删除submodule #

git 并不支持直接删除submodule, 需要手动删除对应的文件:

$ cd submodule-demo
$ git rm --cached library
$ rm -rf library
$ rm .gitmodules

#  更新git的配置文件config:
$ vi .git/config

# 删除 submodule - library 的配置信息

$ git commit -a -m'remove library submodule'
$ git push