公共模块管理之 Git Submodule 使用总结

公共模块管理之 Git Submodule 使用总结

Write By CS逍遥剑仙

我的主页: csxiaoyao.com

GitHub: github.com/csxiaoyaojianxian

Email: sunjianfeng@csxiaoyao.com QQ: 1724338257

1. 公共模块管理:npm or git-submodule

在企业级项目开发中,对于较复杂的项目,不可避免地会引用一些公共基础库,或是将代码拆解成公共模块和多个子模块进行管理,主项目工程中的子模块需要对公共模块有依赖关系,却又不必关心公共模块内部的开发流程细节,若直接将公共代码复制到项目中显然是不合适的,因为不方便更新维护。关于公共模块的管理有很多成熟的实践,常见的有 npmgit submodule 两类方式:

1.1 npm 等包管理工具

前端开发者对 Node.js 的包管理工具 npm 应该再熟悉不过了,此外,Java 的 Maven, php 的 composer 等包管理工具皆同理,有效解决了原先需要插件依赖时,手动在网上搜索下载包代码复制到项目目录,自己管理使用的黑暗模式,大大提升了工程化效率。

以世界上最好的语言 JavaScript 的伴侣 npm 为例,开发者编写一个公共模块,作为 npm package 发布,不仅可在自己的项目间复用,还可以贡献到开源社区,使更多的开发者受益。使用者使用起来也极为简单,一条命令搞定:

$ npm install <moduleName>

1.2 git 子模块管理工具 submodule

git submodule 能够在项目主工程中添加子工程模块,而又保持子工程独立的版本控制,和 npm 极简的体验相比,git submodule 有一定的学习成本,对于初学者并不友好。

其实在 git submodule 之前,我们也许都曾有过相似的经历:开发一个新项目,需要用到团队的公共库,但是又不想把公共代码提交到自己的项目时,会考虑在当前工作目录下,将公共模块文件夹加入到 .gitignore 文件中或是 svn 的忽略文件列表,这样本地能够正常调试的同时,每次提交都能够忽略公共代码。但这样做的弊端是,使用该项目的人需要有一个先验知识(一般写在 README.md 说明文件中):需要在当前目录下放置一份某版本的公共模块代码。而 git submodule 实现的就是自动维护主项目和子项目之间的依赖关系。

虽然 git submodule 需要一定的学习成本,但也有其不可取代的优势:

  1. 更方便的主工程调试:由于子模块源码直接暴露在主项目工程下,更加便于主项目工程的调试运行;
  2. 更方便的子模块调试:在某些场景下,子模块需要在主工程项目中频繁调试迭代,由于 npm 包在主工程的忽略文件列表 node_modules 中,只能切换到独立的子模块工程中开发,而 git submodule 子模块的整个工程都直接在主工程下目录下,直接在主工程中调试子模块提交更新即可;
  3. 更方便的版本权限控制:有一种场景,公共子模块需要频繁迭代,且必须在主工程下调试,但不希望公共子模块的开发者提交对主工程的修改,此时直接关闭该用户主工程的提交权限即可。例如,在最近的 UI 自助化项目中,为了避免开发 UI 组件的开发者提交在主工程中的随意编写的测试代码,只要将组件库独立为 git submodule,同时不开放 UI 组件开发者的主工程提交权限,就能够轻松解决问题。

2. git submodule 操作指引

2.1 创建 submodule

git 工具的 submodule 其实是建立了当前项目与子模块间的依赖关系:子模块路径子模块远程仓库子模块版本号

创建子模块只需一条命令:

$ git submodule add <submodule_url> <submodule_local_path>

此时,项目中会多出两个文件:.gitmodules 和子模块项目文件夹,以及在 .git/config 文件和 .git/modules 文件夹下也会多出相关内容。在此期间,git 做了3件事情:

  • 记录引用的仓库
  • 记录主项目中 submodules 的目录位置
  • 记录引用 submodule 的 commit id

创建完 submodule 后执行提交命令:

$ git commit -m "add submodule"

提交后,在主项目仓库中,会显示出子模块文件夹,并附带其所在仓库的版本号,如:foo @ abcd1234

2.2 获取 submodule

使用 git submodule add 命令会自动拉取子工程项目代码到指定目录,但其他开发者获取主项目代码时,使用 git clone 命令是不会拉取到子项目的代码的,必须运行两条命令:

$ git submodule init # 初始化本地配置文件
$ git submodule update # 检出对应的 commit id 的子项目

也可以在 clone 命令中添加 --recurse-submodules--recursive 参数递归拉取子模块代码。

$ git clone --recursive /path/to/repos/foo.git

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)

2.3 更新 submodule

由于子工程保持独立的版本控制,直接按照 git 的方式更新即可,但对于主工程,子模块代码可能有四类更新:

2.3.1 子项目本地修改未提交

本地子项目下内容发生了未跟踪的变动,可能是有意或无意(如编译产生)的,此时在主项目中虽然会显示该子项目有未跟踪的内容修改,但不会列出差异,并且主项目所有的 git addgit commit 操作都不会对子项目产生影响。此时若需要提交子项目修改,需要进入子项目文件夹再执行版本提交操作,完成后进入下文 2.3.2 中的状态。

2.3.2 子项目本地修改并提交新版本

本地子项目有版本更新,此时在主项目中使用 git status 查看仓库状态时,会显示子项目有新的提交,可以在主项目中使用 git add/commit 命令提交修改。值得注意的是,此时主项目修改的是其依赖的子项目的版本,而非完整变更代码,即引用的子项目的 commit id

2.3.3 子项目远程更新,主项目已更新 commit id

此时在主项目中执行 git pull 后会自动同步主项目中的子项目 commit id 依赖,由于主项目已知子项目更新,只需要执行 submodule 更新命令便可将落后的子项目更新到指定的版本。

$ git submodule update

2.3.4 子项目远程更新,主项目未更新 commit id

在多人协作开发时,主项目与子项目的开发往往是异步进行的,子项目升级后子项目远程仓库更新并告知主项目可以更新对子项目的版本依赖。由于当前主项目记录的子项目版本还未变化,因此主项目执行 git submodule update 也不会更新,此时需要从主项目主动进入子项目执行 git pull 主动拉取新版代码,回到前面的 2.3.2 状态,再更新 commit id 同步到主项目中。

2.4 删除 submodule

首先,使用 git submodule deinit 命令卸载子模块:

# --force 参数将同时删除子模块工作区内的修改
$ git submodule deinit <submodule-name>

然后,在主项目下删除对应的子模块工程目录,接着删除 .gitmodules.git/config 配置文件下的相关条目,再删除 .git/module/ 下的子模块目录,最后执行:

$ git rm --cached <submodule-name>

3. 其他说明

3.1 使用 foreach 批量操作

若一个项目中有多个子模块需要执行相同的操作,每次切换到对应的目录挨个执行效率太低,此时可以使用 git submodule foreach <command>

$ git submodule foreach git checkout master
$ git submodule foreach git pull

3.2 关于默认分支

当 clone 包含 submodule 的项目时,主项目获取到的是 submodule 的 commit id,然后当执行 git submodule update 时是根据这个 commit id 来拉取代码的,所以 clone 之后不在任何分支上,但如果子仓库都在 master 开发的,此时 master 分支的 commit idHEAD 保持一致。因此,如果需要在主项目中开发子模块,建议还是把子模块切换到 master 分支进行开发提交,便于管理。此外,当主项目 clone 后,也可以使用上述的 foreach 命令批量切换到 master 分支进行更新。

4. 总结

本文详述的 git submodule 的使用方式源自本人在当下工作中的实践,希望能对您有所帮助,若有更好的实践方案可以给我留言。

原文地址:https://cloud.tencent.com/developer/article/1803958

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340