管理带有子模块的git库(以 DragonBonesCPP 为例)
2015-09-06 更新: 加入 删除子模块 的内容。
DragonBonesCPP 是一个包含子模块的库,在 clone/commit/push 的时候需要一些额外的操作。
本文将描述这些操作。
子模块(submodule)
限(wei)于(le)篇(tou)幅(lan),请自行学习下面的内容:
clone DragonBonesCPP
蛋碎方法一
1git clone --recursive git@github.com:DragonBones/DragonBonesCPP.git
使用这个方法,将会自动 clone 该项目下的所有子模块。这其实是最简单的方法了。
为什么说它令人蛋碎呢?因为 DragoneBones 中包含的 engines/cocos2d-x 子模块也包含子模块。
这样就出现了嵌套子模块,一个 cocos2d-x 的所有历史加起来就超过1G了,再加上子模块的所有历史,这就……。
蛋疼方法二
为了避免蛋碎的问题,我们换一个方法,可是蛋疼是免不了了。
1# git clone git@github.com:DragonBones/DragonBonesCPP.git
2Cloning into 'DragonBonesCPP'...
3remote: Counting objects: 103, done.
4remote: Compressing objects: 100% (87/87), done.
5remote: Total 103 (delta 18), reused 96 (delta 13)
6Receiving objects: 100% (103/103), 88.96 KiB | 47 KiB/s, done.
7Resolving deltas: 100% (18/18), done.
此时已经将所有 DragonBonesCPP 的核心代码 clone 下来了,由于项目不大,这个过程会非常快。
但是子模块不会自动 clone,接下来需要设置子模块。
1# cd DragonBonesCPP
2# DragonBonesCPP git:(master) > git submodule status
3-a7709c35badbd930f98adaf1c172a3251f8c6543 engines/cocos2d-x
refid 前面的减号 - 代表子模块还没有加载,我们需要初始化并检出它:
1# DragonBonesCPP git:(master) > git submodule init
2Submodule 'cocos2d-x' (git@github.com:DragonBones/cocos2d-x.git) registered for path 'engines/cocos2d-x'
3
4# DragonBonesCPP git:(master) > git submodule update
5Cloning into 'engines/cocos2d-x'...
6remote: Reusing existing pack: 200502, done.
7Receiving objects: 100% (200502/200502), 763.78 MiB | 98 KiB/s, done.
8Resolving deltas: 100% (133006/133006), done.
9Submodule path 'engines/cocos2d-x': checked out 'a7709c35badbd930f98adaf1c172a32 51f8c6543'
等待是漫长的,看我的网速就知道这到底花了多长时间。
和蛋碎方法不同的是,这种方法不会 clone cocos2d-x 中的子模块(嵌套子模块)。若有需要,可以进入 cocos2d-x 中再次执行蛋疼方法二。
分支
DragonBonesCPP 的分支介绍
DragonBonesCPP 项目目前有2个分支,master 和 dev ,区别如下:
以对 cocos2d-x 引擎的支持为例:
切换分支
在开发的过程中,我们经常需要切换分支。例如对 cocos2d-x 2.x 的相关功能进行修改后(位于master分支),希望切换到 cocos2d-x 3.x 的另一些功能进行修改。
这种情况下,我们一般使用 git checkout 来切换分支。于是,奇怪的事情发生了:
1# DragonBonesCPP git:(master) > git checkout dev
2M engines/cocos2d-x
3Switched to branch 'dev'
4# DragonBonesCPP git:(dev) > git status
5 On branch dev
6 Changes not staged for commit:
7 (use "git add <file>..." to update what will be committed)
8 (use "git checkout -- <file>..." to discard changes in working directory)
9
10 modified: engines/cocos2d-x (new commits)
11
12no changes added to commit (use "git add" and/or "git commit -a")
显然我们切换分支后还没有对dev进行修改,但dev分支中已经出现了一个 modified!
diff 看看有什么不同:
1DragonBonesCPP git:(dev) > git diff
2diff --git a/engines/cocos2d-x b/engines/cocos2d-x
3index 123b410..a7709c3 160000
4thumbnail = "/uploads/2014/04/gitsubmodule1.png"
5+++ b/engines/cocos2d-x
6@@ -1 +1 @@
7-Subproject commit 123b410b99510e4a33ceadc08abc09d292f5df49
8+Subproject commit a7709c35badbd930f98adaf1c172a3251f8c6543
从比较的结果看来,子模块指向的 refid 发生了变化,从 123b410... 变成了 a7709c3... 。
wwwwait! 这两个id怎么看着那么眼熟捏?原来,他们分别是 master 和 dev 分支中的 cocos2d-x 子模块指向的 refid。见下图:
也就是说,虽然从 master 切换到了 dev 分支,但是子模块 cocos2d-x 中 HEAD 指向的 refid 并没有跟着改变到 dev 分支中应有的指向。
为了进一步证明这个推测,我们可以进入子模块 cocos2d-x 中查看所处分支: (注意下面的操作位于子模块 cocos2d-x 中)
1# DragonBonesCPP git:(dev) > cd engines/cocos2d-x
2# cocos2d-x git:(master) > git status
3# On branch master
4nothing to commit, working directory clean
注意,在这里可以看到,我们并不是位于我们期望的 cocos2d-x 的 develop 分支(这是 cocos2d-x 3.x的所在分支),而是依然位于 master(cocos2d-x 2.x的所在分支) 分支。
知道了原因,切换起来就简单了。我们只需要进入 cocos2d-x 子模块,将现有的指向改为 cocos2d-x 的 develop 分支即可。
1# cocos2d-x git:(master) > git checkout develop
2Switched to branch 'develop'
3
4# cocos2d-x git:(develop) cd ../../
5# DragonBonesCPP git:(dev) git status
6# On branch dev
7# Your branch is ahead of 'origin/dev' by 3 commits.
8# (use "git push" to publish your local commits)
9#
10nothing to commit, working directory clean
看吧,没有提交,世界清静了。
合并分支
由于我们使用了分支来区分不同的版本,因此在合并的时候,必须做一些处理确保正常。
例如,对于 renderer 中的内容,一定是基于分支独立的。它们不应该在合并的时候被处理。
- master 分支中的 renderer ,与 dev 分支中的 renderer 就可能完全不同,我们不希望在将 master 分支合并到 dev 分支(或者相反)的时候,导致完全不同的两个渲染器互相冲突;
- 而 library 中的内容,则恰恰相反,它们需要在分支之间合并。
gitattributes 文件可以解决这个问题,可参阅这里: Merge-Strategies 。
为了解决这个矛盾,我已在 .gitattributes 中将 renderer 和 engines 目录排除,在合并的时候,它们将保存各自的版本。
若有更深入的需求,例如 renderer 中的某些渲染器需要合并而有些不要,则后续进一步处理。
提交和推送
在提交 DragonBonesCPP 之前,若已经修改过子模块,请务必先提交子模块的修改并推送子模块,然后再提交并推送 DragonBonesCPP 。
删除子模块
为了方便查询,这里摘抄 Git Submodule使用完整教程 一文中的移除 Submodule 的方法如下:
1. 删除 git cache 和物理文件夹
以删除 engines/cocos2d-x
为例:
1git rm -r --cached engines/cocos2d-x/
2rm -rf engines/cocos2d-x/
2. 修改配置文件
- 删除
.gitmodules
文件中对应的配置内容; - 删除
.git/config
中的对应 submodule remote 的内容。
3. 提交更改
(全文完)
- 文章ID:2096
- 原文作者:zrong
- 原文链接:https://blog.zengrong.net/post/manage_a_git_library_with_submodules/
- 版权声明:本作品采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可,非商业转载请注明出处(原文作者,原文链接),商业转载请联系作者获得授权。