我有一个要转换为Git的Mercurial repo 。提交历史记录非常大,我不需要新存储库中的所有提交历史记录。一旦将提交历史记录转换为Git(并在推送到新的仓库之前),我想将某个标记之前的所有提交压缩为一个提交。
所以,如果我有:
commit 6
commit 5
commit 4
commit 3
commit 2
commit 1 -- First commit ever
我想结束于:
commit 6
commit 5
commit X -- squashed 1, 2, 3, 4
注意:我需要压缩成千上万的提交。因此,手动选择/标记它们不是一个选择。
最佳答案
到目前为止,其他答案都建议重新设置基准。在某些情况下,这可以工作,具体取决于转换为Git的存储库中的提交图。新的基于--rebase-merges
的鸽友基地肯定可以做到。但这是一种笨拙的方式。理想的方法是转换要保留的第一个提交开始的提交。也就是说,将您的Mercurial导出商导出到Git,这是Git的第一次提交,您要假装的修订版是根目录。让Mercurial导出商继续将提交的后代一次导出到进口商,就像导出商总是要完成这项工作一样(无论如何)。
是否以及如何执行此操作取决于要转换的工具。 (我实际上并没有进行任何这些转换,但是大多数人似乎都使用hg-fast-export
和git fast-import
。我没有过多研究hg-fast-export
的内部细节,但是没有明显的理由不能执行此操作。)
从根本上(内部),Mercurial存储作为变更集提交。 Git并非如此:Git而是存储快照。但是,Mercurial通过根据需要汇总变更集来 check out (即提取)快照,因此,如果您的工具通过执行hg checkout
(或其内部等效项)工作,则这里没有任何问题:您只是避免 check out 所需的第一个快照之前的修订版本,然后将其导入到Git中,然后生成的Git历史记录将从所需的点开始。
但是,如果您使用的工具不方便,请注意,在将整个存储库历史记录(包括所有分支和 merge )转换为Git快照后,Git存储库将使第二步变得相对容易。您的Git历史记录可能如下所示:
o-..-o o--o <-- br1
/ \ /
...--o--o--....--o--*--o--o--o--o <-- br2
\ / \
o--...--o o <-- master
其中commit *
是您想在Git存储库中看到的第一个提交。 (请注意,如果在*
之前有多个历史记录,则会遇到另一个问题,如果没有其他历史记录修改,则首先无法进行这种转换。但是,只要*
在某种choke point上,就可以在此图中,很容易在此处截取图表。)要删除
*
之前的所有内容,只需使用git replace
进行替代提交,该提交非常类似于commit *
,但没有父项:git replace --graft <hash-of-*>
现在,您有一个替代品,大多数Git都将使用它来替代*
,而没有父提交。然后使用no-op过滤器在所有分支和标签上运行git filter-branch
:git filter-branch --tag-name-filter cat -- --all
或者,一旦git filter-repo
包含在Git中(或如果已安装),则:git filter-repo --force
(使用--force
时请小心filter-repo
选项:这会使它破坏该存储库中的旧历史记录,但是在此csae中,这就是我们想要的)。这会将每个可到达的提交(包括替代的
*
但不包括*
及其自身的历史记录)复制到新的提交中,然后更新您的分支和标记名。如果使用filter-branch,请删除
refs/originals/
命名空间(有关详细信息,请参见the git filter-branch
documentation),如果愿意,可以尽早清除原始对象(额外的提交最终将自行消失),然后就完成了。关于Git-在特定提交之前压扁历史上的所有提交,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53587814/