0


Git--子模块(submodule)介绍

Git--子模块(submodule)介绍

1 简介

1.1 概述

当程序比较大参与开发人员较多时,代码管理就复杂起来。
代码如果全员可见,可以创建share分支维护共用代码,可以创建core分支维护核心算法代码,各进程分别占一个分支,定期同步share和core分支。
代码如果不能全员可见,可以仓库中包含子仓库,子仓库管理模块代码,主仓库定时更新。

2 常用子模块命令

7.11 Git 工具 - 子模块
Git Submodule管理项目子模块

2.1 常用命令

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

3 操作

3.1 需求

我们尝试使用 Git 来维护一个项目的代码。这个项目的结构比较复杂:
项目包含由多个子模块,每个子模块是一个独立的 Git 仓库,子模块还允许继续嵌套包含子模块。 例如,主工程依赖 common、framework、react_native 等多个子模块,而 react_native 子模块又依赖 node_modules、HFCommon、HFModules 等多个嵌套子模块。

[-] app_android/|-[+] HFUIKit
|-[+] channel
|-[+] common
|-[+] framework
|-[+] hybrid
|-[+] messagecenter
|-[-] react_native
|-[+] HFCommon
|-[+] HFModules
|-[+] node_modules

主工程和子模块允许存在多个分支,且相互之间有依赖关系。例如,主工程的 jilin 分支同时依赖 common 子模块的 master 分支,以及 framework 子模块的 jilin 分支。

3.2 git submodule添加子模块

Git 提供了 submodule 来支持子模块的需求,使用它可以很方便的将多个独立仓库包含到同一个主工程中:

$ git init
$ git submodule add http://xxx.xxx/common.git
$ git submodule add http://xxx.xxx/framework.git

Git submodule 还支持嵌套添加子模块:

$ git submodule add http://xxx.xxx/react_native.git
$ cd react_native
$ git submodule add http://xxx.xxx/HFCommon.git
$ git submodule add http://xxx.xxx/HFModules.git
$ git submodule add http://xxx.xxx/node_modules.git

3.3 Git submodule 使用风险

通过子模块,这些子模块既可以各自独立的修改和提交代码,又可以将改动作用到依赖它的父工程。这听起来是个很棒的特性,然而 Git submodule 也存在着一些让人抓狂的坑。

首先,主工程并不直接跟踪子模块的代码,而仅仅只跟踪子模块的 commit id 的改动。在执行 git submodule update 更新子模块代码时,Git 就是根据主工程所维护的 commit id 来更新子模块到指定状态的。

bash-3.2$ git diff react_native
diff --git a/react_native b/react_native
index 3a9c5b1..ad68a28 160000--- a/react_native
+++ b/react_native
@@ -1+1 @@
-Subproject commit 3a9c5b14c45b199e2e6863d2b6da22dabc2a54f5
+Subproject commit ad68a28c13d4196df531c7df8523d07358288297(END)

因此,如果你只在子模块中修改并提交了代码,而没有到主工程上面再把子模块的 commit id 提交一下,其他人拉取工程代码的时候会发现子模块的代码依然停留在老的 commit id 所指向的状态。对于嵌套子模块,这种工作尤为繁琐,提交代码后要逐层往上提交 commit id ,否则其他人无法正确更新代码。
其次,如前面所说,使用 git submodule update 更新子模块后,子模块将被切换到一个指向父工程维护的 commit id 所指定的游离状态:

bash-3.2$ git submodule update react_native
bash-3.2$ cd react_native
bash-3.2$ git branch
*(detached from 3a9c5b1)
master
jilin
TaiShan

一旦代码处于游离分支,你就要时刻警惕在游离分支上的提交有没有即时合并到非游离分支上。如果你直接在游离分支上开发并提交了代码,之后在父工程里再次 git submodule update ,你所有未合并的提交都会丢失!

最后还有一个非常麻烦,但也极容易出现的问题:如果团队里有人只提交了主工程该子模块的 commit id ,却忘了进入该模块提交模块真正的代码,那么当推送到中央仓库之后,其他人就会因为找不到与该 commit id 对应的代码而无法正确更新代码:

bash-3.2$ git submodule update
error: pathspec 'ad68a28c13d4196df531c7df8523d07358288297' did not match any file(s) known to git.
Did you forget to 'git add'?
Unable to checkout 'ad68a28c13d4196df531c7df8523d07358288297' in submodule path 'react_native'

对于熟练的用户,这些坑自然可以轻松越过。但考虑到团队里大都是 Git 新手,我们发现子模块的引入对他们造成了很大的负担,频繁出现子模块代码没有更新到最新状态,或者更新出错的情况。

3.4 子模块的更新

子模块的维护者提交了更新后,使用子模块的项目必须手动更新才能包含最新的提交。
在项目中,进入到子模块目录下,执行 git pull更新,查看git log查看相应提交。
完成后返回到项目目录,可以看到子模块有待提交的更新,使用git add,提交即可。

3.5 删除子模块

有时子模块的项目维护地址发生了变化,或者需要替换子模块,就需要删除原有的子模块。
删除子模块较复杂,步骤如下:

rm -rf 子模块目录 删除子模块目录及源码
vi .gitmodules 删除项目目录下.gitmodules文件中子模块相关条目
vi .git/config 删除配置项中子模块相关条目
rm .git/module/* 删除模块下的子模块目录,每个子模块对应一个目录,注意只删除对应的子模块目录即可

执行完成后,再执行添加子模块命令即可,如果仍然报错,执行如下:

git rm --cached 子模块名称

4 示例

4.1 git submodule没有权限时如何更新到某个提交

  • 当某个git submodule没有权限时,无法拉到代码,也无法checkout到某个revision,所以常规的checkout更新submodule的操作行不通。
  • 但有时我们确实有这样的需求,去更新这个submodule到最新版本,因为虽然你没权限,但是打包机是有的,更新这个submodule可以打出带上最新submodule的包。
  • 是有办法的,虽然拿不到代码,但是最新的commit hash是可以拿到的,剩下的就是怎么告诉主repo更新这个submodule到指定的revision。
  • 这里用到了git的update-index命令
git remote update 
git rev-parse origin/master:PathToSubModule   
// suppose we get this  6b7ad40e8287d7e452c29e0e2cffa0d46e49f077
 
git ls-files --stage PathToSubModule
//   160000 8ad2765f410bbac1805ca931cb5abcf8b3986c15 0       SubModuleName

// done the job
git update-index --add --cacheinfo 160000 6b7ad40e8287d7e452c29e0e2cffa0d46e49f077 SubModuleName

4.2 忽略 Git submodule

  • 首先 .gitmodules 文件只是一个初始化配置。当你执行 git submodule init 时,git 会从 .gitmodules 读取信息来操作 .git/ 目录下的文件,比如修改 .git/config 以及修改 .git/modules/ 目录等操作。
  • 存在一种使用场景,一个很大的项目下有些 submodule 项目不能让某些开发者访问。那么执行 git submodule update 会报错导致中断。
  • 你可以忽略那些没有访问权限的子项目。假设有个名叫 xxx 的 submodule。 那么在 git submodule init 之后,修改 .git/config 文件,修改 active=false 和 ignore=all 即可。即:
[submodule "xxx"]
        url = [email protected]:zzz/xxx.git
        active = false
        ignore = all

之后的 git submodule 操作都会忽略掉 xxx 项目了。
这些配置可以通过 git help config 来找到,比如搜索 submodule..ignore。

5 来自道哥

5.1 真实案例

from:「IOT物联网小镇」的原创文章
事情发生在功能机的时代,我们项目组开发一款手机,软件开发成员大概有 20 人左右吧。结果在手机发布的一周后,另一家小厂就推出了软件界面、功能几乎完全一样的手机,除了开机界面。

因为那个时代,大家几乎都是使用 MTK、高通提供的解决方案,都是统一的菜单式功能,你没法拿出有力的证据来说明别人偷窃了你的代码。

后来内部查明,的确是有开发人员把代码泄漏出去了,于是后来所有的电脑上 USB 口全部被禁掉了。

这是我亲身经历的真实故事,当时每个人负责一个模块,比如:A 负责通话管理和电话簿,B 负责系统设置,C 负责短信和彩信。。。在编译的时候,是需要所有的代码放在一起,统一编译的,这也就意味着所有的软件人员都可以拿到全部源代码,这也就为代码泄漏埋下了隐患,出现了这次严重的事件,毕竟人为财死、鸟为食亡!

5.2 解决办法

现在项目中,都强调要分层、分模块,这是从软件工程的角度来考虑的。如果再进一步, 把这些模块都划分为一个小的子系统,每个开发人员只负责自己的模块,并且只能有权限拉取自己的代码,这样他就没法获取到一个项目中所有模块的代码了。

只有项目整合人员(管理员),才有全部权限来拉取所有源代码来构建整个系统,这样的话,就可以对代码的安全问题有更好的掌控了。

要实现这样的代码管控,使用 git 工具中的 submodule 就可以完成。

参考

1、7.11 Git 工具 - 子模块
2、子模块相关操作
3、Git 管理实践(一):多分支子模块依赖管理
4、Git Submodule管理项目子模块
5、子模块相关操作
6、git中submodule子模块的添加、使用和删除
7、git submodule没有权限时如何更新到某个提交
8、使用Jenkins + git submodule 实现自动化编译,解决代码安全性问题

标签: git

本文转载自: https://blog.csdn.net/qq_38880380/article/details/123288706
版权归原作者 worthsen 所有, 如有侵权,请联系我们删除。

“Git--子模块(submodule)介绍”的评论:

还没有评论