mercurial import后修复git

时间:2017-09-21 13:58:18

标签: git mercurial

前段时间我将项目从我自己托管的mercurial存储库移到了github。

现在看来,我没有仔细检查导入过程的结果。我已经结束了一些没有设置父母的提交。

例如,查看commit fbf4e876f172e7a4a03153b801bd44cf71d98601。它没有父级,包含具有所有内容的所有文件,就好像它是初始提交一样。但是当我查看我的原始hg存储库时,此提交应该有一个父级 - c1b215a3ae19dd9b6771a4ffe9217d6f9b65d4a9

有没有办法重新显示无效提交?我需要多次使用git blame,现在它给了我无用的结果。

1 个答案:

答案 0 :(得分:1)

首先,如果您还没有使用新的Git存储库并且仍然拥有原始的Mercurial存储库,那么您最好的选择是使用任何命令和/或选项重新转换,从而产生正确的转换。然后你不必担心遗漏任何东西。

如果失败,那么:

  

有没有办法重新显示无效提交?

排序,是的。但也没有。考虑使用git replace进行初始修复,然后git filter-branch重写存储库(之后所有用户必须切换到重写的存储库)。

替换

从根本上说,问题是不能改变任何提交。提交可以复制到一个新的,稍微不同的提交,否则“就像原始提交一样好”,这是处理问题的一种方法。

Git能够使用the git replace command“替换”提交(或者确实是任何Git对象)。这种方式下的工作方式是“替换”提交保留在存储库中,保持原始形式,并且您创建一个新的替换对象,通常通过复制 - 但稍微改变 - 原始对象(尽管您可以{ {3}}如果你愿意的话)。此替换对象进入存储库,具有refs/replace/<hash-id>形式的特殊外部名称。每当Git通过其哈希ID查找并使用原始对象时,它首先检查是否存在refs/replace/<id>引用。如果是这样,Git会将目光从原始物体转移到更换物体上。前端git replace命令使这个过程不那么痛苦,但有一个重要的警告:替换对象通常不会跨克隆传输。这包括初始克隆和获取操作。

(他们可以,它不是那么难,但它不是默认的。这是出于各种好的理由,特别是包括安全性。无论从PGP签名标签获得什么安全性和/或提交如果允许替换,则会立即丢失。如果您可以直接访问存储库,以便运行git replace,那么您已经完全独立于加密安全性;但如果您克隆或获取,则依赖于它。 )

过滤器分支

git filter-branch命令完全是关于复制提交,并且在此过程中应用了一些更改(过滤器)。在复制一些提交结束后,以一些分支名称或其他引用点的提交结束,filter-branch命令重写引用以指向新复制的链。

如果提交的副本与其原始文件的位数相同,则实际上的副本是原始副本。只有以某种方式更改的提交才会产生新副本(具有不同的哈希ID)。过滤器分支代码仍会复制每次提交,但有些副本最终会以这种方式“免费”。

考虑这个微小的,四次提交的存储库:

A--B--C--D   <-- master

假设过滤器引入了对提交C的更改,以便它变为提交C',这意味着Git还必须将提交D复制到D'DD'之间的差异是D'链接回C'。然后,过滤后的存储库包含:

A--B--C--D   <-- refs/original/refs/heads/master
    \
     C'-D'   <-- master

如果您根本没有指定过滤器,Git只会复制每个提交。如果您使用--all --tag-name-filter cat,Git会将此过程应用于所有分支和所有标记。但是 - 这是关键 - 复制使用替换。因此,让我们绘制您自己的存储库,包括不正确的提交fbf4e876f172e7a4a03153b801bd44cf71d98601(让我们简称为F)和具有正确父级F'的替换c1b215a3ae19dd9b6771a4ffe9217d6f9b65d4a9(简称为C):

...--C--...  <-- refs/heads/somebranch
      \
       F'    <-- refs/replace/F

F            <--- tag: v2.0.0

(commit F没有父级,所以它只是作为第二个根提交而存在。)

我们现在运行git replace --all --tag-name-filter cat,因此Git会查找所有引用都可以访问的所有提交,包括refs/heads/somebranchrefs/tags/v2.0.0。因此它会复制C之前和之后的提交,但它们没有任何更改。它会复制F,但会切换到替换F',并复制F',但也不会对其进行任何更改。

现在它已经复制了所有内容(F除外),它使名称refs/heads/somebranchrefs/tags/v2.0.0指向副本。这对somebranch没有影响,但会使refs/tags/v2.0.0指向替换提交F'

过滤器分支代码添加refs/original/名称以保留原始分支提示和标记的提交,因此有refs/original/refs/heads/somebranchrefs/original/refs/tags/v2.0.0,您将丢弃。

通常,最简单的方法是克隆已过滤的存储库:此克隆不会获取refs/replace/引用,也不会获取refs/original/引用。它只获得refs/heads/refs/tags/引用。 (如果您不喜欢克隆方法,还有其他几种方法可以执行此操作。大多数方法会在存储库中保留额外的提交副本至少30天,直到它们自然过期并进行垃圾收集。如果您“只是替换了一些提交,这不是什么大不了的事。”