我有一个要转换为Git的Mercurial回购。提交历史记录非常大,我不需要新存储库中的所有提交历史记录。将提交历史记录转换为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
注意:我需要压缩成千上万的提交。因此,手动选择/标记它们不是一个选择。
答案 0 :(得分:4)
要精确地做到所有这些, 步骤将是
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 ... "
您可以进一步扩展它,以根据所有提交消息构建SQUASH_MESSAGE。
答案 1 :(得分:2)
到目前为止,其他答案都建议重新设定基准。在某些情况下,此可以起作用,具体取决于转换为Git的存储库中的提交图。使用--rebase-merges
进行新的更佳变位肯定可以做到。但这是一种笨拙的方式。理想的方法是转换从您要保留的第一个提交开始。也就是说,将Mercurial出口商导出到Git,就像Git的 first 提交一样,您要假装的修订版是根目录。让Mercurial出口商继续将提交的后代一次出口到进口商,就像出口商总是要从事这项工作一样(无论如何)。
能否以及如何 执行此操作取决于您要使用哪种工具进行转换。 (我实际上并没有进行任何这些转换,但是大多数人似乎都使用hg-fast-export
和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
其中提交*
是您希望在Git存储库中看到的第一个提交。 (请注意,如果在*
之前有多个历史记录,那么您会遇到另一个问题,如果没有其他历史记录修改,就无法进行这种转换。但是,*
处于启用状态就像这张图中的choke point一样,在此处剪裁图形很容易。)
要删除*
之前的所有内容,只需使用git replace
进行一个非常类似于 提交*
但没有父项的替代提交:>
git replace --graft <hash-of-*>
您现在有了Git的大多数人将使用的替代品,而不是*
,它没有父提交。然后使用无操作筛选器在所有分支和标签上运行git filter-branch
:
git filter-branch --tag-name-filter cat -- --all
这会将每个 reachable 提交(包括替换项*
但不包括*
及其自身的历史记录)复制到新提交中,然后更新您的分支和标记名。删除refs/originals/
命名空间(有关详细信息,请参见the git filter-branch
documentation),如果愿意,可以尽早清除原始对象(多余的提交最终将自行消失),然后完成。
答案 2 :(得分:0)
尽管我建议将git reset --soft
压榨一组 个提交(as in here),但还是建议使用以下选项:
请注意,这适用于通过git rebase --root
option的第一次提交。
答案 3 :(得分:0)
假设原始分支为 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
如果要保留合并提交,则需要在“ git rebase”中使用选项“ -p”。