前段时间我将项目从我自己托管的mercurial存储库移到了github。
现在看来,我没有仔细检查导入过程的结果。我已经结束了一些没有设置父母的提交。
例如,查看commit fbf4e876f172e7a4a03153b801bd44cf71d98601。它没有父级,包含具有所有内容的所有文件,就好像它是初始提交一样。但是当我查看我的原始hg存储库时,此提交应该有一个父级 - c1b215a3ae19dd9b6771a4ffe9217d6f9b65d4a9。
有没有办法重新显示无效提交?我需要多次使用git blame,现在它给了我无用的结果。
答案 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'
, D
和D'
之间的差异是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/somebranch
和refs/tags/v2.0.0
。因此它会复制C
之前和之后的提交,但它们没有任何更改。它会复制F
,但会切换到替换F'
,并复制F'
,但也不会对其进行任何更改。
现在它已经复制了所有内容(F
除外),它使名称refs/heads/somebranch
和refs/tags/v2.0.0
指向副本。这对somebranch
没有影响,但会使refs/tags/v2.0.0
指向替换提交F'
。
过滤器分支代码添加refs/original/
名称以保留原始分支提示和标记的提交,因此有refs/original/refs/heads/somebranch
和refs/original/refs/tags/v2.0.0
,您将丢弃。
通常,最简单的方法是克隆已过滤的存储库:此克隆不会获取refs/replace/
引用,也不会获取refs/original/
引用。它只获得refs/heads/
和refs/tags/
引用。 (如果您不喜欢克隆方法,还有其他几种方法可以执行此操作。大多数方法会在存储库中保留额外的提交副本至少30天,直到它们自然过期并进行垃圾收集。如果您“只是替换了一些提交,这不是什么大不了的事。”