我有一个要转换为 Git 的 Mercurial 存储库。提交历史非常大,我不需要新仓库中的所有提交历史。一旦我将提交历史转换为 Git(并且在推送到新存储库之前),我想将某个标签之前的所有提交压缩为一个提交。
所以,如果我有:
commit 6
commit 5
commit 4
commit 3
commit 2
commit 1 -- First commit ever
Run Code Online (Sandbox Code Playgroud)
我想结束:
commit 6
commit 5
commit X -- squashed 1, 2, 3, 4
Run Code Online (Sandbox Code Playgroud)
注意:我需要压缩数以千计的提交。因此,手动挑选/标记它们不是一种选择。
到目前为止,其他答案都建议 rebase。这可以工作,在某些情况下,这取决于在转换到Git仓库提交图表。新的发烧友 rebase with--rebase-merges绝对可以做到。但这是一种笨拙的方法。执行此操作的理想方法是从您要保留的第一个提交开始转换提交。 也就是说,让您的 Mercurial 导出器导出到 Git,作为 Git 的第一次提交,您要假装的修订版是根。让 Mercurial 导出器继续将提交的后代导出到导入器中,一次一个,就像导出器总是要做这项工作一样(无论以何种方式)。
无论你如何能做到这一点取决于你使用的转换什么工具(S)。(我实际上并没有进行任何这些转换,但大多数人似乎都在使用hg-fast-exportand git fast-import。我没有过多研究 的内部细节,hg-fast-export但没有明显的原因它不能这样做。)
从根本上(内部),Mercurial 将提交存储为变更集。这是不是对Git的情况:Git的存储快照来代替。但是,Mercurial通过根据需要将变更集汇总在一起来检查(即提取)快照,因此如果您的工具通过执行hg checkout(或其内部等效项)工作,那么首先这里没有问题:您只需避免检查修订在您想要的第一个快照之前,并将它们导入 Git,生成的 Git 历史记录将从所需的点开始。
但是,如果您使用的工具使这变得不方便,请注意,在将整个存储库历史记录(包括所有分支和合并)转换为 Git 快照后,您的Git存储库将相对容易地作为第二遍。例如,您的 Git 历史记录可能如下所示:
o-..-o o--o <-- br1
/ \ /
...--o--o--....--o--*--o--o--o--o <-- br2
\ / \
o--...--o o <-- master
Run Code Online (Sandbox Code Playgroud)
其中 commit*是您希望在 Git 存储库中看到的第一个提交。(请注意,如果之前有多个历史可追溯*,则您会遇到不同的问题,如果没有额外的历史修改,就无法首先进行这种转换。但只要*处于某种阻塞点,就像在这张图,很容易在这里剪下图。)
要删除之前的所有内容*,只需使用git replace来进行非常像commit的替代提交*,但没有父项:
git replace --graft <hash-of-*>
Run Code Online (Sandbox Code Playgroud)
你现在有一个大多数 Git 将使用的替代品,而不是*,它没有父提交。然后git filter-branch使用无操作过滤器运行所有分支和标签:
git filter-branch --tag-name-filter cat -- --all
Run Code Online (Sandbox Code Playgroud)
或者,曾经git filter-repo包含在 Git 中(或者如果您已经安装了它):
git filter-repo --force
Run Code Online (Sandbox Code Playgroud)
(使用时要小心这个--force选项filter-repo:这会破坏这个存储库中的旧历史,但在这个 csae 中,这就是我们想要的)。
这将复制每个可访问的提交,包括替代*但排除*和它自己的历史,到新的提交,然后更新你的分支和标签名称。
如果使用过滤器分支,删除refs/originals/名称空间(见的git filter-branch文档获取详细信息),迫使原始对象的早期清除如果你喜欢(额外提交最终会走自己的),你就大功告成了。
假设原来的分支是master,新的分支是new。
git checkout --orphan new commit4
git commit -m "squash commits"
git branch tmp master
git rebase commit4 tmp --onto new
git checkout new
git merge tmp
git branch -D tmp
Run Code Online (Sandbox Code Playgroud)
如果你想保留合并提交,“git rebase”中需要选项“-p”。
为了准确地完成所有这些,步骤将是
function git_squash_from() {
COMMIT_TO_SQUASH=$1
SQUASH_MESSAGE=$2
STARTING_BRANCH=$(git rev-parse --abbrev-ref HEAD) # This will be overwritten
CURRENT_HEAD=$(git rev-parse HEAD)
echo From $CURRENT_HEAD to the successor of $COMMIT_TO_SQUASH will retain, from $COMMIT_TO_SQUASH to beginging will be squashed
git checkout $COMMIT_TO_SQUASH
git reset $(git commit-tree HEAD^{tree} -m "$SQUASH_MESSAGE")
git cherry-pick $CURRENT_HEAD...$COMMIT_TO_SQUASH
git branch -D $STARTING_BRANCH
git checkout -b $STARTING_BRANCH
}
git_squash_from 87ef7fa "Squash ... "
Run Code Online (Sandbox Code Playgroud)
您可以进一步扩展它以从所有提交消息构建 SQUASH_MESSAGE。
| 归档时间: |
|
| 查看次数: |
2104 次 |
| 最近记录: |