我想最好的解决办法是修补 Mercurial 的 Git 子存储库支持以始终使用 Git 的递归选项(例如git clone --recursive
,在克隆基于 Git 的子存储库时,git pull --recurse-submodules && git submodule update
在拉取更新的基于 Git 的子存储库后等)。我知道 Git 开发人员特别选择不自动初始化子模块,因为他们想要支持的工作流程之一是“我永远不想看到任何子模块”,但也许“总是初始化所有子存储库”更适合默认的 Mercurial 操作模式(我不是 Mercurial 用户,所以我不知道默认的 Mercurial 样式是什么)。
在此之前,您可以通过将subrepo/.gitmodules
条目转换为.hgsub
条目来解决该问题。手动操作很容易,但如果它很重要,您可以将其自动化(用于git config
从.git/config
and/or中提取路径和 URL .gitmodules
)。如果您正在处理一个.gitmodules
变化很大的文件,这可能没有吸引力(您必须非常勤奋地在.hgsub
每次.gitmodules
更改时同步)。
我用四个存储库对此进行了测试:
- gitsub — 一个“叶子”存储库(没有 Git 子模块)
- gitsuper — 一个 Git “超级项目”;
gitsub/
是gitsub作为子模块
- hgsuper2 — Mercurial“超级项目”;
gitsuper/
是gitsuper作为子存储库,
gitsuper/gitsub
是gitsub作为子存储库。
- hgsuper2-clone — 一个克隆的 Mercurial “超级项目”;
gitsuper/
是gitsuper作为子存储库,
gitsuper/gitsub
是gitsub作为子存储库。
我像这样构建和测试它们:
- 创建gitsub。添加并提交一些内容。
- 创建gitsuper。
- 添加一些内容。
git submodule add url-of-gitsub gitsub && git submodule init
git commit -m 'added gitsub'
- 创建hgsuper2。
- 添加一些内容。
git clone --recursive url-of-gitsuper gitsuper
echo 'gitsuper = [git]url-of-gitsuper' >> .hgsub
echo 'gitsuper/gitsub = [git]url-of-gitsub' >> .hgsub
这最后两个步骤可以从 和 的位中gitsuper/.git/config
自动化gitsuper/.gitmodules
。
hg add .hgsub && hg commit -m 'added Git subrepositories'
- 从hgsuper2克隆hgsuper2-clone。它在和
中获取适当的内容。
gitsuper/
gitsuper/gitsub/
- 更新并将新内容提交到gitsub。
- 更新gitsuper。
- 添加或更改一些内容并将其暂存。
(cd gitsub && git pull origin master)
git add gitsub && git commit -m 'updated gitsuper content (also gitsub)'
- 在hgsuper2中,从 Git 存储库中提取更改。
(cd gitsuper && git pull --recurse-submodules && git submodule update)
gitsuper/
和中
的内容gitsuper/gitsub/
由拉取更新。
hg commit -m 'updated gitsuper (and its contents)'
- 拉入hgsuper2-clone。
hg pull -u
来自 Git 的内容已更新。
我的测试有效(使用 Mercurial 1.8.1 和 Git 1.7.4.1),但我注意到一个错误。Mercurial 创建并签出一个奇怪命名的 Git 分支(origin/master
(ie refs/heads/origin/master
) 而不是使用分离的 HEAD(就像 Git 对其子模块所做的那样)或仅使用master
(ie refs/heads/master
))。有时它似乎也有点卡住,导致如下错误:
fatal: git checkout: branch origin/master already exists
abort: git checkout error 128 in gitsuper
我通过进入有问题的 Git 存储库(基于 Git 的 Mercurial 子存储库)并使用git checkout HEAD~0 && git branch -D origin/master
(第一个分离 HEAD 并且(更重要的是)移出分支以便可以通过下一个命令删除它)来解决这个问题)。只要您在 Git 存储库中没有任何本地更改更改,此解决方法是完全安全的。
另一个小问题是,在由 Mercurial 创建的 Git 超级存储库中发出 Git 子模块命令之前,您需要运行git submodule init
让 Git 知道它的子模块(子模块被克隆到正确的位置,但它们是由 Mercurial 建立的,所以)中没有它们的条目.git/config
。
同样,如果您计划从基于 Git 的 Mercurial 子存储库中对 Git 管理的内容进行创作更改,那么您应该小心始终添加任何 Git 子模块、提交和推送,然后再提交到 Mercurial “超级项目”。否则,您最终可能会遇到 Mercurial 使用gitsuper和gitsub的一种组合而gitsuper本身引用不同版本的gitsub的情况。换句话说,由于您将绕过 Git 的子模块代码(通过将 Git 子模块作为 Mercurial 子存储库进行管理),因此您需要小心保持 Git 的子模块视图与 Mercurial 的视图同步。