允许在 git rebase 中合并不相关的历史记录

Allow merging unrelated histories in git rebase

当你想变基保持合并提交的分支时,你传递 --preserve-merges 标志。当您在 git 中合并不相关的历史记录时,您需要传递 --allow-unrelated-histories 标志。

如果您正在执行 git rebase --preserve-merges 当现有合并来自不相关的历史记录时,它将失败:

fatal: refusing to merge unrelated histories

如果你尝试 git rebase --preserve-merges --allow-unrelated-histories 它会失败:

error: unknown option 'allow-unrelated-histories'

是否有其他方法告诉 rebase 允许合并?


编辑:这是一个最小复制:https://github.com/vossad01/rebase-unrelated-merge-reproduction

重现结帐master然后执行:

git rebase --preserve-merges --onto origin/a-prime HEAD~2

蛮力方法是强制一个共同的根——因为你正在尝试变基根,没有内容历史,做一个随机数空提交并告诉 git 这是历史的父您正在合并:

git rev-list --all --max-parents=0 \
| awk '{print [=10=],empty}' empty=`:|git mktree|xargs git commit-tree` \
> .git/info/grafts
git rebase here
rm .git/info/grafts

git rebase 合并失败时,它不会中止变基,因此您有机会手动干预。

如果您愿意手动解决这个问题,您可以按如下方式完成合并:

git merge --allow-unrelated ORIGINAL_BRANCH_THAT_WAS_MERGED --no-commit
git commit -C ORIGINAL_MERGE_COMMIT
git rebase --continue

理想情况下,Git 可以在无需人工干预的情况下处理此问题。

To reproduce checkout master then execute:

git rebase --preserve-merges --onto origin/a-prime HEAD~2 -i

git-rebase 文档说不要合并 -i--preserve-merges

[--preserve-merges] uses the --interactive machinery internally, but combining it with the --interactive option explicitly is generally not a good idea unless you know what you are doing (see BUGS below).

但即使没有 -i 它仍然会失败 fatal: refusing to merge unrelated histories

部分问题是 HEAD~2origin/a-prime 的直系祖先。您的测试回购看起来像这样:

1 [master]
|
2
|\
| |  3 [origin/a-prime]
| |  |
| 4 / [origin/b]
|  /
| /
|/
5 [origin/a]
master

HEAD~2是5。origin/a-prime是3。你的命令相当于:

git rebase -p --onto 3 5

5 是 3 的直接祖先,因此该命令没有多大意义。如果这有效,它会做一些奇怪的事情。


the cases I have encountered a couple of times recently have been in moving a project's documentation from GitHub Wiki to GitHub Pages (when the website already exists).

这是对 rebase 的不当使用。 Rebase 将平行历史变成线性历史,基本上假装一组更改一直在另一组之上完成。这对于在处理功能分支时保持最新状态这样的事情很有用,如果你没有一堆除了更新分支什么都不做的中间合并提交,那么簿记和审查会更容易。对于将来阅读代码和提交历史的任何人来说,这些只是噪音。

但是当你有两个真正不同的历史时,最好将它们保留为不同的历史。合并它们讲述了正确的故事:网站和文档是分开开发的,但后来合并为一个单元。

1 - 3 - 5
         \
  2 - 4 - 6 - 7 - 8 [master]

您可以使用 git log --topo-order 按拓扑顺序 (8, 7, 6, 5, 3, 1, 4, 2) 分别查看它们,或者您可以按日期顺序交错查看它们 (8, 7、6、5、4、3、2、1),git log 默认值。 gitk 或 GitX 等历史可视化工具将同时显示这两个订单。

在另一个之上变基是在说谎:我们在网站上工作,然后我们在文档上工作,然后在某个时候(你必须找到这个点)并且出于某种原因我们一起处理网站和文档。

1 - 3 - 5 - 2 - 4 - 6 - 7 - 8 [master]

这会丢失重要信息,并让人不解为什么某些更改在未来变得更加困难。

进行合并,这是正确的做法。

同步两个不同分支的唯一方法是将它们重新合并在一起,从而产生一个额外的合并提交和两组包含相同更改的提交(原始的和来自你的 rebased 分支的) .不用说,这是一个非常混乱的情况。

所以,在你 运行 git rebase 之前,总是问自己,“还有其他人在看这个分支吗?”如果答案是肯定的,请将手从键盘上拿开,并开始考虑以非破坏性方式进行更改(例如,git revert 命令)。否则,您可以随心所欲地重写历史。

参考:https://www.atlassian.com/git/tutorials/merging-vs-rebasing#the-golden-rule-of-rebasing