我有一个项目,其主要(Mercurial)存储库位于SourceForge上,但Bitbucket(Mercurial)和Github(Git)上有克隆。
现在我一直在使用hg-git将Mercurial存储库推送到Github,根据我对该过程的理解,一些元数据在过程中保存在Mercurial存储库中。
现在,当重新克隆Bitbucket存储库并重新克隆Github存储库时,如果我发出hg pull ../github-repo
,我会得到:
pulling from ../github-repo
searching for changes
abort: repository is unrelated
为什么这样,我怎么能说服Mercurial确实他们有关系呢?或者我是否必须依赖我最初推送到Github的原始存储库?我仍然有,但假设我失去了它,我有什么选择,缺少手动变更集移植?
注意:由于拉取请求,Github仓库已更改(新变更集)。但SourceForge和Bitbucket repos仍然认为彼此是相关的。现在的任务是将Github Git仓库中的变更集分别转移到本地仓库,并将它们分别推回SourceForge和Bitbucket。
答案 0 :(得分:10)
相关或非相关位基本上来自两个存储库是否共享公共根,即初始变更集。
为了强迫拉扯,你可以用移植物或移植物扩展做一些邪恶的事情,但这可能有涟漪效应,你似乎对这种解决方案不利 - 我也会这样做!
要了解您遇到问题的原因,您需要了解一下Hg-Git的工作原理。
真正的问题是Hg-Git基本上是动态创建一个新的仓库。因此,两个存储库不相关,原因与hg convert some-existing-hg-repo
的产品与原始存储库无关。到目前为止,您还没有注意到它,因为Hg-Git也在另一个方向上做到这一点 - 当您从Mercurial存储库开始时,它会创建必要的Git存储库。当您第一次开始克隆到GitHub时,您在其服务器上创建了一个裸Git存储库,其所有意图和目的都与每个存储库相关。因此,你推动由Hg-Git创建的新Git仓库是相关的,一切正常,没问题。之后,你正在推动同样的回购,所以再没有问题 - Hg-Git跟踪当地Git和Hg存储库之间的关系,从而保持了你们的关系。但是当你重新开始时,你会创建一个新的Git和/或Hg仓库(取决于你进入的方向)并且通信被破坏。
Hg-Git的工作原理是创建一个隐藏的Git存储库,并在Git和Hg存储库的提交之间建立对应关系。 Hg-Git是一个双向桥,也就是说,它能够进行Git提交并生成Hg提交,反之亦然。 Hg-Git通过使用Python编写的git库(dulwich)并链接到Mercurial作为扩展来实现双语。这意味着 Hg-Git读取和写入Git存储库,而无需安装git
二进制文件/ Git参考实现。但是,Hg-Git是一个Mercurial扩展,因此依赖于Mercurial的Mercurial结束以及用户界面。这就是为什么要努力创建反向接口(Git-Hg等)以便Git用户可以使用Git与Mercurial进行交互。
现在,是否创建了Git或Hg存储库取决于首先如何创建混合存储库。由于您来自规范的Mercurial方面,我们将从那里开始。
当您在Github或Bitbucket上创建存储库时,它最初是裸的并且没有提交,因此与每个存储库相关 - 这是默认情况下创建存储库时没有初始提交的动机的一部分。 (对于Git和Mercurial都是如此。)存储库相关性基于根节点。因此,任何存储库都可以推送到这个新的存储库。当您第一次运行hg push ssh+git://git@github.com/user/some-git-repo
时,Hg-Git会在您的本地文件夹中创建一个新的隐藏Git存储库,然后使用Git协议进行通信并将更改推送到远程。从那时起,您应该在两个存储库之间进行通信时没有问题 - 从根节点的初始转换和父子关系,可以实现两个存储库的更改集之间的一对一映射。 (这并非100%真实,特别是如果你使用Git或Mercurial的更高级的惯用功能,但它现在已经足够了。)Hg-Git追踪的信息比这更多,I& #39;我很确定,如果没有其他原因,只能通过连续的推拉来加快速度。因此,当您从Mercurial克隆开始时,您的" proto-root"是Mercurial根,Git存储库是根据需要创建和维护的。
现在,如果您不是从本地Mercurial克隆开始,而是从远程Git克隆开始,那么您实际上最终结束从Git克隆创建Mercurial克隆 - " proto-root"是Git的根。更准确地说,当您运行hg clone ssh+git://git@github.com/user/some-git-repo
时,Mercurial会启动,检查以确保它可以与远程接口(它可以与Hg-Git的帮助),然后创建目录并调用必要的扩展名(s),即Hg-Git。然后,Hg-Git在.git
文件夹中创建一个隐藏的.hg
文件夹,执行git克隆,然后将Git repo转换为Mercurial文件夹;一旦克隆完成,它就会调用hg update
,它直接在Mercurial仓库上运行,而不必了解Git仓库。
我怀疑,这是你的情况出了什么问题。当你从GitHub做了一个新的克隆时,你实际上创建了一个新的Mercurial存储库,当然它与你的原始存储库没有关系 - 就像hg convert
的产品不是&#39一样; t与原始相关,即使变异提交不包含初始。 (这有点像你将某些东西翻译成另一种语言然后再回来时,你不会总是得到原来的形式。)出于各种原因,我怀疑Hg-Git在与时间无关的情况下执行转换。确定性的方式(几乎肯定是后者,但它可能会添加关于转换本身的额外元数据,这意味着不是前者)。如果是这种情况,那么您应该能够从规范的Hg克隆开始并重新创建与Git存储库的连接。 (是的,初始转换的方向性有所不同有些问题,但是导致设计决策的优缺点最好与开发人员自己讨论。)
回到混合Hg-Git存储库的结构。这里有两个有趣的事情:
重要的是,您实际上可以通过系统Git直接在隐藏的Git存储库上运行。如果您使用Hg-Git,那么Git存储库仅在推送到远程Git克隆时拉动,这意味着那些本地直接Git更改将与Mercurial存储库不同步 - 在最坏的情况下,您提交几次到Git,然后提交Mercurial而不同步并有效地创建两个单独的分支,因为Hg提交和Git提交共享一个共同的祖先但不相互建立。但是,Hg-Git提供了一种机制,用于通过hg gimport [git-repo-to-import-from-if-not-local-hidden]
和hg gexport
手动强制在repos之间进行同步(默认情况下导出为本地隐藏副本,如果需要,可以创建它)。强制执行此同步还应该为您提供处理您已注意到的问题的方法。你可以使用Git来拉(或者在Git术语中,fetch
- git pull
相当于hg pull --update
; git fetch
是hg pull
,这使得Mercurial获取扩展名的确非常不幸)将新的更改集放入Git存储库,然后使用hg gimport
将这些更改集导入Mercurial存储库。
现在,如果您执行了编辑历史记录之类的操作,那么所有投注都会被取消。我不确定Hg-Git会如何处理这个问题 - 我怀疑它最终会创造出双打。 Mercurial克隆中的新提交将添加到Git中,但删除的更改集仍在Git仓库中,可能会导回到Mercurial存储库中。 (这是Hg-Git离线同步变更集的直接结果。)在这种情况下,我建议选择一个规范的存储库,擦除所有克隆并对所有克隆失效的人道歉通过这个烂摊子。 (顺便提一下,这是Mercurial社区对编辑历史非常谨慎的部分原因。)
@EmilSit建议您直接从规范(非GitHub克隆)Mercurial存储库运行hg pull git+ssh://github.com/you/githubrepo.git
。假设Hg-Git创建初始Git克隆的方法完全与时间无关且具有确定性,那么这有很大的工作机会。 (后者几乎可以肯定,但我不确定前者,请参阅上面的文字以获取更多细节。)
您可以使用本地变体:使用git clone ssh://github.com/you/githubrepo.git
获取本地纯git克隆,然后执行hg pull ../githubrepo
。 (这需要你安装了Git。)Hg-Git应该自动启动并进行转换。转换还取决于Hg-Git以确定的,与时间无关的方式进行转换。
您可以直接在原始混合存储库中的隐藏git存储库上运行。使用git fetch
(您可能首先必须cd
进入.git
文件夹中隐藏的.hg
文件夹中。然后运行hg gimport && hg update
从git存储库导入更改并更新。 (您可能已指定gimport
的路径 - .
或隐藏git仓库的路径。我怀疑您也可以指定GitHub路径。)
您可以使用各种哑转移方法 - 导出补丁系列等 - 并手动提交它们。如果您想在进行手动提交时给予其他开发人员信用,那么您可以使用-u
选项在每次提交的基础上设置用户。
您可以使用graft或transplant扩展程序进行智能移植。首先,使用Hg-Git来执行GitHub存储库的新Mercurial克隆。然后使用其中一个扩展来将两个Mercurial存储库组合在一起。
至少有一个非移植方法 应该工作,因为除非Hg-Git按时间依赖魔法,否则应该可以找到一个共同的根。即使找到了一个公共根,你也可能会找到两个基本上重复(未命名)的分支,然后你必须将它们合并在一起。
答案 1 :(得分:3)
我补充说,当你将hg repo推送到git,然后从hg克隆git repo然后你尝试从原来的hg repo中提取更改时,你甚至可以得到一个“存储库无关”错误。从现在开始我们有一个hg repo本地创建的git repo是从原来的hg repo创建的,我想本地和原来的hg repo应该是相关的,但有时候不是。
由于hg和git处理作者姓名和电子邮件的方式存在差异,如果您的原始hg repo与作者有任何不同之处,而不是Name <mail@example.com>
- 样式,您会看到这个问题。原因是hg-git尝试将作者转换为严格的git样式(使用提到的名称 - 电子邮件对),如果不是这样,则填写空白(请参阅hg-git的自述文件中的解释:{ {3}})。
因此,原始hg repo中的变更集的作者可能与git repo中的变更集完全相同;因此,从git repo创建的hg repo中的作者将与原始hg repo中的作者不匹配,例如:
mail@example.com
。mail@example.com <mail@example.com>
。mail@example.com <mail@example.com>
。因为两个repos是相关的,所以初始提交应该完全匹配,即使hash,commit消息,datetime匹配,但是作者是不同的,你将得到“repository unlated”错误。相当痛苦的经历(唉,现在我受到了惩罚,因为我忘了三年前妥善设置作者!)但是完全合理。