我有一个git中的子模块,我希望能够让不同的分支为这个子模块指定不同的URL,在.gitmodules中指定。我知道这是可能的,但现在每当我在这些分支之间切换时,都需要整个过程才能将子模块放到正确的哈希中。我必须卸载子模块,删除.git/下的模块路径,然后重新编译,这需要一段时间。考虑到每个分支使用不同的子模块URL,有没有一种更容易的方法来切换分支并获得正确的哈希?
分支——我指的是分支名称——在这里不相关1重要的是提交。。。不幸的是,在您自己的案例中,检查每个提交的特定模式。
子模块无非是一个单独的Git存储库。如果您还没有子模块,Git必须运行git clone
才能获得它,Git通过以gitlink的形式组合某个特定提交中的信息来找到该git clone
命令的指令,该路径类似于path/to/submodule
,其条目为mode 160000
,即gitlink,带有一些哈希ID,加上名为.gitmodules
的文件中同一提交的信息。
让我们举一个例子。假设超级存储库名为super
,在提交a123456
时,path/to/sub
的模式为160000,表示为commit 5555555
。克隆超级项目并签出提交a123456
。子模块尚未被克隆,但超级项目的索引显示";我们需要为CCD_ 12提交CCD_;此时。
如果你现在运行git submodule update --init
(或者已经使用递归克隆为你做了这件事(,Git现在会注意到,嘿,存储库还没有克隆,所以它在.gitmodules
中查找path/to/sub
来找到克隆它的指令。然后,它使用(实际上(--no-checkout
运行git clone
,然后进入子模块并检查提交5555555
(通过原始哈希ID(。
但现在path/to/sub
与被克隆的子模块相关联。假设您现在在super
中签出提交b789abc
,并且它说";使用提交CCD_ 22";。这进入了Git的索引(对于super
:子模块sub
的索引和工作树还没有被修改(。如果您现在运行git submodule update
,或者启用了递归签出(这对您来说是这样做的(,Git会注意到子模块已经被克隆,并且不需要从b789abc
中查找.gitmodules
文件。
请注意,如果在提交a123456
时没有运行git submodule update --init
,则子模块还不会被克隆。因此,super
中的操作现在将查看提交b789abc
中出现的.gitmodules
文件,该文件可能具有完全不同的URL。Git会克隆该URL,并在那里查找提交5678567
。
这就是你试图解决的问题。除了你一直在使用的可怕的手动流程之外,没有其他解决方法。
(这个问题的常见术语是,你有一个"路径依赖的结果"。Git没有预料到这一点,只是没有正确处理它。(
1特别是,多个分支名称可以指向同一提交。如果main
和develop
都指向提交a123456
,那么使用哪个名称就无关紧要了,因为无论哪种方式都可以提交a123456
。分支名称会随时间移动,因此main
今天识别a123456
并不意味着它明天会识别a123456
。
一种解决方案是为每个不同的源URL使用不同的子模块名称。
例如,假设我有时想要使用来自源url_a
的包pkg
,有时使用从源url_b
获取的pkg
。我将首先在我的存储库中创建两个独立的子模块pkg_from_a
和pkg_from_b
:
git submodule add <url_a> pkg_from_a
git submodule add <url_b> pkg_from_b
现在我有两个独立的子模块,但如何选择正在使用的子模块?这是通过根据需要创建指向pkg_from_a
或pkg_from_b
的符号链路pkg
来完成的。例如,如果我从一个应该使用pkg_from_a
的分支开始,我会创建并提交这样的链接:
ln -s pkg_from_a pkg # NOTE: Unix syntax for creating a symbolic link
git add pkg
git commit pkg
修改链接是在两个子模块之间切换所必需的全部内容。链接可以在逐个提交的基础上更改,因此不同的分支可以轻松地使用来自不同位置的pkg
。