1
2
3
4
|
➜ henryyan@hy-hp ~
/submd/ws/project1-b
git:(master) ✗
grep
path .gitmodules |
awk
'{ print $3 }'
>
/tmp/study-git-submodule-dirs
➜ henryyan@hy-hp ~
/submd/ws/project1-b
git:(master) ✗
cat
/tmp/study-git-submodule-dirs
libs
/lib1
libs
/lib2
|
我们通过分析.gitmodules文件得出子模块的路径,然后就可以根据这些路径进行更新。
1
2
|
➜ henryyan@hy-hp ~
/submd/ws/project1-b
git:(master) ✗
mkdir
bin
➜ henryyan@hy-hp ~
/submd/ws/project1-b
git:(master) ✗
vi
bin
/update-submodules
.sh
|
把下面的脚本复制到bin/update-submodules.sh中:
1
2
3
4
5
6
7
8
9
|
#!/bin/bash
grep
path .gitmodules |
awk
'{ print $3 }'
>
/tmp/study-git-submodule-dirs
# read
while
read
LINE
do
echo
$LINE
(
cd
./$LINE && git checkout master && git pull)
done
<
/tmp/study-git-submodule-dirs
|
稍微解释一下上面的脚本执行过程:
首先把子模块的路径写入到文件/tmp/study-git-submodule-dirs中;
然后读取文件中的子模块路径,依次切换到master分支(修改都是在master分支上进行的),最后更新最近改动。
网友@紫煌给出了更好的办法,一个命令就可以代替上面的bin/update-submodules.sh的功能:
1
|
git submodule foreach git pull
|
此命令也脚本一样,循环进入(enter)每个子模块的目录,然后执行foreach后面的命令。
该后面的命令可以任意的,例如 git submodule foreach ls -l 可以列出每个子模块的文件列表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
➜ henryyan@hy-hp ~
/submd/ws/project1-b
git:(master) ✗ git submodule
+36ad12d40d8a41a4a88a64add27bd57cf56c9de2 libs
/lib1
(heads
/master
)
+7290dce0062bd77df1d83b27dd3fa3f25a836b54 libs
/lib2
(heads
/master
)
# 添加执行权限
➜ henryyan@hy-hp ~
/submd/ws/project1-b
git:(master) ✗
chmod
+x .
/bin/update-submodules
.sh
➜ henryyan@hy-hp ~
/submd/ws/project1-b
git:(master) ✗ .
/bin/update-submodules
.sh
libs
/lib1
Already on
'master'
remote: Counting objects: 4,
done
.
remote: Compressing objects: 100% (2
/2
),
done
.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3
/3
),
done
.
From
/home/henryyan/submd/repos/lib1
36ad12d..8c666d8 master -> origin
/master
Updating 36ad12d..8c666d8
Fast-forward
README | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 README
libs
/lib2
Switched to branch
'master'
remote: Counting objects: 5,
done
.
remote: Compressing objects: 100% (2
/2
),
done
.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3
/3
),
done
.
From
/home/henryyan/submd/repos/lib2
7290dce..e372b21 master -> origin
/master
Updating 7290dce..e372b21
Fast-forward
lib2-features | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
➜ henryyan@hy-hp ~
/submd/ws/project1-b
git:(master) ✗ git submodule
8c666d86531513dd1aebdf235f142adbac72c035 libs
/lib1
(heads
/master
)
e372b21dffa611802c282278ec916b5418acebc2 libs
/lib2
(heads
/master
)
➜ henryyan@hy-hp ~
/submd/ws/project1-b
git:(master) ✗ git status
# On branch master
# Untracked files:
# (use "git add
#
# bin/
nothing added to commit but untracked files present (use
"git add"
to track)
<
/file
>
|
更新之后的两个变化:
git submodule的结果和project2的submodule commit id保持一致;
project1-b不再提示new commits了。
现在可以把工具添加到仓库了,当然你可以很骄傲的分享给其他项目组的同事。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
➜ henryyan@hy-hp ~
/submd/ws/project1-b
git:(master) ✗ git add bin
/update-submodules
.sh
➜ henryyan@hy-hp ~
/submd/ws/project1-b
git:(master) ✗ git commit -m
"添加自动更新submodule的快捷脚本^_^"
[master 756e788] 添加自动更新submodule的快捷脚本^_^
1 files changed, 9 insertions(+), 0 deletions(-)
create mode 100755 bin
/update-submodules
.sh
➜ henryyan@hy-hp ~
/submd/ws/project1-b
git:(master) git push
Counting objects: 5,
done
.
Delta compression using up to 2 threads.
Compressing objects: 100% (3
/3
),
done
.
Writing objects: 100% (4
/4
), 625 bytes,
done
.
Total 4 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (4
/4
),
done
.
To
/home/henryyan/submd/ws/
..
/repos/project1
.git
8fcca50..756e788 master -> master
|
一般人使用的时候都是使用如下命令:
1
2
3
|
git clone
/path/to/repos/foo
.git
git submodule init
git submodule update
|
新员工不耐烦了,嘴上不说但是心里想:怎么那么麻烦?
上面的命令简直弱暴了,直接一行命令搞定:
1
|
git clone --recursive
/path/to/repos/foo
.git
|
–recursive参数的含义:可以在clone项目时同时clone关联的submodules。
git help 对其解释:
--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)
1
2
3
4
5
6
7
8
9
10
11
|
➜ henryyan@hy-hp ~
/submd/ws
git clone --recursive ..
/repos/project2
.git project2-auto-clone-submodules
Cloning into project2-auto-clone-submodules...
done
.
Submodule
'libs/lib1'
(
/home/henryyan/submd/repos/lib1
.git) registered
for
path
'libs/lib1'
Submodule
'libs/lib2'
(
/home/henryyan/submd/repos/lib2
.git) registered
for
path
'libs/lib2'
Cloning into libs
/lib1
...
done
.
Submodule path
'libs/lib1'
: checked out
'8c666d86531513dd1aebdf235f142adbac72c035'
Cloning into libs
/lib2
...
done
.
Submodule path
'libs/lib2'
: checked out
'e372b21dffa611802c282278ec916b5418acebc2'
|
舒服……
牢骚:搞不明白为什么git不设计一个类似:git submodule remove的命令呢?
我们从project1.git克隆一个项目用来练习移除submodule:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
➜ henryyan@hy-hp ~
/submd/ws
git clone --recursive ..
/repos/project1
.git project1-remove-submodules
Cloning into project1-remove-submodules...
done
.
Submodule
'libs/lib1'
(
/home/henryyan/submd/repos/lib1
.git) registered
for
path
'libs/lib1'
Submodule
'libs/lib2'
(
/home/henryyan/submd/repos/lib2
.git) registered
for
path
'libs/lib2'
Cloning into libs
/lib1
...
done
.
Submodule path
'libs/lib1'
: checked out
'8c666d86531513dd1aebdf235f142adbac72c035'
Cloning into libs
/lib2
...
done
.
Submodule path
'libs/lib2'
: checked out
'e372b21dffa611802c282278ec916b5418acebc2'
➜ henryyan@hy-hp ~
/submd/ws
cd
!$
➜ henryyan@hy-hp ~
/submd/ws
cd
project1-remove-submodules
|
1、删除git cache和物理文件夹
1
2
3
4
|
➜ henryyan@hy-hp ~
/submd/ws/project1-remove-submodules
git:(master) git
rm
-r --cached libs/
rm
'libs/lib1'
rm
'libs/lib2'
➜ henryyan@hy-hp ~
/submd/ws/project1-remove-submodules
git:(master) ✗
rm
-rf libs
|
2、删除.gitmodules的内容(或者整个文件) 因为本例只有两个子模块,直接删除文件:
1
|
➜ henryyan@hy-hp ~
/submd/ws/project1-remove-submodules
git:(master) ✗
rm
.gitmodules
|
如果仅仅删除某一个submodule那么打开.gitmodules文件编辑,删除对应submodule配置即可。
3、删除.git/config的submodule配置 源文件:
[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true [remote "origin"] fetch = +refs/heads/*:refs/remotes/origin/* url = /home/henryyan/submd/ws/../repos/project1.git [branch "master"] remote = origin merge = refs/heads/master [submodule "libs/lib1"] url = /home/henryyan/submd/repos/lib1.git [submodule "libs/lib2"] url = /home/henryyan/submd/repos/lib2.git
删除后:
[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true [remote "origin"] fetch = +refs/heads/*:refs/remotes/origin/* url = /home/henryyan/submd/ws/../repos/project1.git [branch "master"] remote = origin merge = refs/heads/master
4、提交更改
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
➜ henryyan@hy-hp ~
/submd/ws/project1-remove-submodules
git:(master) ✗ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD
#
# deleted: libs/lib1
# deleted: libs/lib2
#
# Changes not staged for commit:
# (use "git add/rm
# (use "git checkout --
#
# deleted: .gitmodules
#
➜ henryyan@hy-hp ~
/submd/ws/project1-remove-submodules
git:(master) ✗ git add .gitmodules
➜ henryyan@hy-hp ~
/submd/ws/project1-remove-submodules
git:(master) ✗ git commit -m
"删除子模块lib1和lib2"
[master 5e2ee71] 删除子模块lib1和lib2
3 files changed, 0 insertions(+), 8 deletions(-)
delete mode 100644 .gitmodules
delete mode 160000 libs
/lib1
delete mode 160000 libs
/lib2
➜ henryyan@hy-hp ~
/submd/ws/project1-remove-submodules
git:(master) git push
Counting objects: 3,
done
.
Delta compression using up to 2 threads.
Compressing objects: 100% (2
/2
),
done
.
Writing objects: 100% (2
/2
), 302 bytes,
done
.
Total 2 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (2
/2
),
done
.
To
/home/henryyan/submd/ws/
..
/repos/project1
.git
756e788..5e2ee71 master -> master
<
/file
><
/file
><
/file
>
|
对于Git Submodule来说在刚刚接触的时候多少会有点凌乱的赶紧,尤其是没有接触过svn:externals。
本文从开始创建项目到使用git submodule的每个步骤以及细节、原理逐一讲解,希望到此读者能驾驭它。
学会了Git submdoule你的项目中再也不会出现大量重复的资源文件、公共类库,更不会出现多个版本,甚至一个客户的多个项目风格存在各种差异。
本文的写作来源于工作中的实践,如果您对于某个做法有更好的办法还请赐教,希望能留下您宝贵的意见。
原创文章,转载请注明出处! Git Submoudle使用完整教程--咖啡兔