我有一个要转换为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-exportgit 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/

10-11 01:45
查看更多