重温 Git 子模块
Git 的子模块受到了普遍的嘲笑,以至于几乎整个行业都致力于提供管理依赖关系的替代方案。
但就像 git 中的任何东西一样,通常值得仔细阅读手册页并弄清楚是否有一些选项可以满足您的要求,或者看看它们最近是否有所改进。
我想要什么
所以,Metre是我的样板项目。它有很多子模块,部分原因是我们的一些客户运行的是(非常)老旧的 Linux 版本,所以我们需要进行静态链接。耶,真有意思!
但这意味着我们要管理和交付我们自己构建的 OpenSSL 版本——这对我们的安全人员(可爱的西蒙)来说是一个可怕的前景。实际上,对我来说也相当可怕。
那么,实际上,我们的发布周期包括沿着所有子模块的稳定分支推进,这样我们就能确信所有错误都已修复。这需要尽可能简单——实际上,只需要一个命令,我们就可以根据需要运行。
但是,我们希望高度确信检查 Metre 的特定提交哈希将为我们提供与我们构建的相同的依赖关系。
Git 子模块添加
最初,我尝试了git submodule
很多手动工作。我(首席开发人员)对此很不满意。安全专家 Simon 也对此很不满意。我们的高级开发人员 Pete 对项目进行了全面审查,并重点指出了这一点。
问题在于,一次失误和一次依赖可能会留下严重的安全问题。而 Metre 的宗旨就是安全。
的优点是它可以跟踪子模块的提交哈希,并且您可以使用或git submodule
以正确的哈希检查它们。git clone --recursive
git submodule update --init --recursive
我们考虑过换用其他产品,但这样一来,我们就会失去很多内置的智能git submodule
,这也是一种痛苦。
哦,看——树枝!
man git-submodule
然而man 7 gitsubmodules
,深入研究后,我发现了金子。
首先,有一个-b branch
切换到 的开关git submodule add
。这会将子模块添加到特定分支,并且还会将“跟踪分支”(git 通常从中拉取的分支)设置为远程 origin 分支,就像你平常做的那样。
其次,我找到了一个配置选项submodule.{submodule name}.branch
,用于存储这些信息。不过,这并不像你想象的那么好,因为虽然你可以git config
为存储库设置它,但它不会被跟踪。
害怕我的编辑技巧
但是,子模块配置存储在存储库.gitmodules
顶部的文件中。因此,您可以编辑该文件,找到相应部分,然后直接branch
在其中添加一个键:
[submodule "deps/spiffing"]
path = deps/spiffing
url = http://github.com/surevine/spiffing
[submodule "deps/openssl"]
path = deps/openssl
url = git://git.openssl.org/openssl.git
branch = OpenSSL_1_1_0-stable
不过,默认值是master
,所以如果这就是您想要的,那么您已经拥有了。
更新分支
更新子模块的常规命令是git submodule update
。有三个值得关注的标志:
--init
git submodule init
如果子模块尚未克隆到位,则执行,否则不执行任何操作 - 因此始终可以安全使用。
--recursive
递归遍历每个子模块,git submodule update
在每个子模块中运行相同的命令。
--remote
就是那个神奇的——沿着远程跟踪分支执行git pull
。这就是我们想要的。
工作流程摘要
现在工作流程如下:
git clone --recursive git@github.com:surevine/metre
- 克隆存储库并检出HEAD
。master
git checkout foo
- 检出 foo 分支或提交 - 并将子模块切换到它们对 foo 的提交。
git submodule update --init --recursive --remote
-沿跟踪分支递归更新所有--remote
子模块。如果没有,它会将子模块的工作目录重置为父模块的“正确”提交。
最后,您可以:
git config submodule.recurse true
- 告诉 git 大多数命令应该以递归方式执行,特别是git pull
。