通过 GitExtensions 来使用 Git 子模块功能
目录
一、前言
二、Git 子模块
三、子模块更改提交
四、更新子模块
五、[附] 去除最近的提交记录
独立观察员 2021 年 9 月 5 日
一、前言
众所周知,编程,尤其是面向对象编程的一个重要思想就是 “封装”,可重用的代码逻辑封装为方法,使用于同一业务的方法封装为类,功能相关的类封装到一个类库中,等等等等。在 .NET 中,一个项目最终生成一个类库(DLL),当然,这个项目可能会引用其它项目或类库(所以生成路径下可能好多 .dll)。而我们用开发工具 Visual Studio 打开的一般是个解决方案,解决方案中一般包含了 1~n 个项目。另外,现在的开发流程中,一般都会使用版本控制系统,比较流行的就是 Git 和 SVN,就拿 Git 来说,一般我们会将一个解决方案放在一个代码仓库中,然后托管在提供 Git 代码仓库托管服务的网站上,比较流行的就是 GitHub 和 Gitee。
当我们有两个以上的相互独立的解决方案要共用一个类库项目时,一般有以下几种方法:
1、多个解决方案分别引用相同路径的项目;(缺点:只适用于代码仅在本地维护的场景)
2、将该项目代码分别拷贝到各解决方案目录下进行引用;(缺点:容易造成版本不一致的问题)
3、将该项目生成为库文件(如 .dll 文件)然后分别引用;(缺点:同样存在版本问题,且不方便进行代码修改)
4、将该项目打包上传到公共或私有的 NuGet 库中,然后引用;(缺点:适用于提供给其他人使用的场景,不利于代码的修改学习)
可以看到,以上方法都有这样那样的缺点,那么有没有其它比较好的方法呢?答案就是使用本文将要介绍的 Git 子模块(submodule)功能。
既然叫 Git 子模块功能,那么自然是和 Git 深度绑定的。正所谓工欲善其事必先利其器,我先来推荐一个 Git 工具 ——GitExtensions。GitExtensions 是一款类似于 TortoiseGit 的 Git 图形化工具,安装之后既可以当作桌面软件使用,也可以再安个 VS 插件,以便直接在 VS 中打开操作界面。使用方法可略微看看本人五、六年前写的文章《使用 Git Extensions 简单入门 Git》,区别是,现在的版本没有整合 Git 和 KDiff3 了,需要自己安装,然后 VS 插件可在微软网站上下载。(本段中的下载地址请阅读原文)
二、Git 子模块
那么安装好了之后,如何添加 Git 子模块呢?先不急,我们先来看看添加过 Git 子模块后的目录中会有什么变化:
可以看到,就是多了个 .gitmodules 文件,打开看看内容吧:
文件内容显示,当前有两个子模块,分别列出了模块名、本地存放的目录、远程仓库地址、分支名。理论上,添加的话可以直接修改这个文件,当为了保险起见(不知道 Git 的内部操作),建议还是通过命令或图形界面来维护 Git 子模块。命令的方式可以参考网上的文章《git submodule 的使用(.gitmodules 文件子模块加载)》,本文就不再赘述了。下面来介绍如何使用 GitExtensions 进行相关的图形化界面操作。
首先,在 Git 文件夹中右键,点击 “GitExt Open repository”:
在打开的 Git 仓库管理界面,点击 档案库 --> 管理子模块:
可以看到两个现存的子模块的信息,点击 新增子模块 可进行新增,填上 公共仓库路径、本地路径、分支 即可新增了,就是这么简单:
另外三个功能是 同步、更新、移除,更新和移除很好理解,同步大概就是将子模块中修改的内容提交推送吧,我也没用过,我一般就是进入子模块目录,将其当做独立的 Git 目录来进行提交推送的。
当我们克隆带有 Git 子模块的仓库时要记得勾上 “初始化所有子模块” 选项,不然的话克隆结束之后子模块目录不会出现:
我们打开子模块的目录,和普通 Git 目录相比,就是没有了 .git 文件夹,而是一个 .git 文件,里面写明了当前模块的 git 存储位置:
三、子模块更改提交
下面来说说常规的使用方法,我们先在子模块 WPFTemplateLib 的目录中新建一个测试文件:
然后在 GitExtensions 的主界面就能看到检测出变动了,提示说有一项可以提交,而且标示出了是在子模块中产生的变动:
可以直接点击提交,不过提交信息不是很明确:
我一般选择切到子模块界面进行提交,切换方法就是点击状态栏一个像鱼雷一样的图标:
这样提交信息就比较清晰了:
刚才如果只是点的 “提交”,那就再 “推送” 一下:
推送完成之后,看分支图上还是有一个虚线框的分支标记,这就是说明父工程还是引用的上个版本的本模块:
我们再切换到父工程:
可以看到还是有可提交标志,这里其实是提交对子模块的引用信息(引用哪个提交版本)的更改:
提交界面如下(注意和之前的进行对比),显示了新旧的版本信息:
提交(未推送)之后再切到子模块,虚框分支标记就消失了:
四、更新子模块
接下来演示一下更新子模块的操作,我们先复位一下父工程,在上个提交上右键 --> 复位当前分支到此处:
复位方式这里选择 混合模式:
回到了如下状态:
由于我们之前提交子模块时勾选了 “在父工程中载入” 选项,现在我们先在提交界面,右键 --> 更新子模块:
由于父工程对子模块的引用并未更改(提交),所以此处更新子模块后,将会将子模块的提交索引复位(重新指向上个版本):
这样父工程恢复如初:
子模块的当前版本也复位了:
不过这样操作只是通过父工程进行强行复位,可以看到上图中分支的下拉框已经变成 (no branch) 了,这是不好的。正常操作应该是对子模块进行复位,我们先重新切回 master 分支:
然后使用 “复位当前分支到此处” 功能:
这次使用 “硬模式”,当作什么都没有发生过:
情况如下:
这种情况就像是,公共库在别的地方有了新版本,而我这个项目目前在用旧版本,现在可以选择保持使用旧版本,也可以选择更新到新版本。
选择旧版本的话,就是 “更新子模块” 或者什么都不操作(因为克隆的时候已经更新过了):
选择新版本的话,就是对子模块进行拉取操作:
然后父工程界面就会出现熟悉的标志:
当然,实际上你可以选择任何版本。其它的就大家自己探索吧。
五、[附] 去除最近的提交记录
大家也看到了,这次我为了写这篇文章,在项目中提交推送了一条无用的信息:
那么有没有方法去除呢?实际上之前也有过一篇文章《Git 图形化操作之合并提交记录》,不过那个是合并,最终还是有一条记录的,这次是要删除。概括说来,方法就是 复位 强制推送 。
首先是复位(复位当前分支到此处):
然后是强制推送(这里使用 强制租用 就行了):
然后就行了:
Gitee 上也是正常的:
好了,全文完,祝大家生活愉快。