Git Submodule
July 17, 2018
基于公司的项目会越来越多,常常需要提取公共的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
看到多了两个需要提交的文件: .gitmodules
和library
.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
指定submodule
的git header
。
.gitmodules
和library
都需要提交到父项目的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有两种方式:
- 在父项目的目录下直接运行
$ git submodule foreach git pull
- 在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