采取以下案例:
我在主题分支中有一些工作,现在我已准备好合并回主人:
* eb3b733 3 [master] [origin/master]
| * b62cae6 2 [topic]
|/
* 38abeae 1
我从master执行合并,解决冲突,现在我有:
* 8101fe3 Merge branch 'topic' [master]
|\
| * b62cae6 2 [topic]
* | eb3b733 3 [origin/master]
|/
* 38abeae 1
现在,合并花了我一些时间,所以我再做一次提取并注意到远程主分支有新的变化:
* 8101fe3 Merge branch 'topic' [master]
|\
| * b62cae6 2 [topic]
| | * e7affba 4 [origin/master]
| |/
|/|
* | eb3b733 3
|/
* 38abeae 1
如果我从master那里尝试'git rebase origin / master',我将被迫再次解决所有冲突,并且我也失去了合并提交:
* d4de423 2 [master]
* e7affba 4 [origin/master]
* eb3b733 3
| * b62cae6 2 [topic]
|/
* 38abeae 1
有没有一种干净的方法来重新定义合并提交,所以我最终会得到一个类似于我在下面显示的历史记录?
* 51984c7 Merge branch 'topic' [master]
|\
| * b62cae6 2 [topic]
* | e7affba 4 [origin/master]
* | eb3b733 3
|/
* 38abeae 1
答案 0 :(得分:103)
这里有两种选择。
一个是进行交互式rebase并编辑合并提交,手动重做合并并继续rebase。
另一种方法是使用-p
上的git rebase
选项,手册中描述如下:“不要忽略合并,而是尝试重新创建它们。”这个问题进一步解释了它:What exactly does git's "rebase --preserve-merges" do (and why?)
答案 1 :(得分:21)
好的,这是一个老问题,已经接受了@siride
的答案,但在我的情况下答案还不够,因为--preserve-merges
迫使你第二次解决所有冲突。我的解决方案基于@Tobi B
的想法,但具有精确的逐步命令
所以我们将根据问题中的示例开始这样的状态:
* 8101fe3 Merge branch 'topic' [HEAD -> master]
|\
| * b62cae6 2 [topic]
| |
| | * f5a7ca8 5 [origin/master]
| | * e7affba 4
| |/
|/|
* | eb3b733 3
|/
* 38abeae 1
请注意,我们提前2次提交master,所以cherry-pick不起作用。
首先,让我们创建我们想要的正确历史记录:
git checkout -b correct-history # create new branch to save master for future
git rebase -s ours -p origin/master
-p
表示--preserve-merges
,我们使用它来保存历史记录中的合并提交
-s ours
表示--strategy=ours
,我们用它来忽略所有合并冲突,因为我们不关心合并提交中的内容,我们现在只需要很好的历史。
历史将如此(忽略主人):
* 51984c7 Merge branch 'topic' [HEAD -> correct-history]
|\
| * b62cae6 2 [topic]
* | f5a7ca8 5 [origin/master]
* | e7affba 4
* | eb3b733 3
|/
* 38abeae 1
现在让我们得到正确的索引。
git checkout master # return to our master branch
git merge origin/master # merge origin/master on top of our master
我们可能会在此处获得一些额外的合并冲突,但这只会与8101fe3
和f5a7ca8
之间更改的文件发生冲突,但不会包括来自topic
已解决的冲突
历史将如下所示(忽略正确的历史记录):
* 94f1484 Merge branch 'origin/master' [HEAD -> master]
|\
* | f5a7ca8 5 [origin/master]
* | e7affba 4
| * 8101fe3 Merge branch 'topic'
| |\
| | * b62cae6 2 [topic]
|/ /
* / eb3b733 3
|/
* 38abeae 1
最后一步是将我们的分支与正确的历史记录和分支与正确的索引结合起来
git reset --soft correct-history
git commit --amend
我们使用reset --soft
将我们的分支(和历史记录)重置为纠正历史记录,但保留索引和工作树。然后我们使用commit --amend
来重写我们的合并提交,它曾经有过不正确的索引,而我们的索引来自master。
最后我们将有这样的状态(注意顶部提交的另一个id):
* 13e6d03 Merge branch 'topic' [HEAD -> master]
|\
| * b62cae6 2 [topic]
* | f5a7ca8 5 [origin/master]
* | e7affba 4
* | eb3b733 3
|/
* 38abeae 1
答案 2 :(得分:3)
鉴于我只是失去了一天试图解决这个问题,并且在同事的帮助下实际找到了一个解决方案,我想我应该插手。
我们有一个庞大的代码库,我们必须同时处理2个分支。如果您有主分支和辅助分支。
当我将辅助分支合并到主分支时,在主分支中继续工作,到我完成时,我无法推送我的更改,因为它们不兼容。
因此,我需要" rebase"我"合并"。这就是我们最终做到的方式:
1)记下SHA。例如:c4a924d458ea0629c0d694f1b9e9576a3ecf506b
git log -1
2)创建正确的历史记录,但这会破坏合并。
git rebase -s ours --preserve-merges origin/master
3)记下SHA。例如:29dd8101d78
git log -1
4)现在重置到之前的位置
git reset c4a924d458ea0629c0d694f1b9e9576a3ecf506b --hard
5)现在将当前主人合并到你的工作分支
git merge origin/master
git mergetool
git commit -m"correct files
6)既然您拥有正确的文件,但错误的历史记录,请立即行动 改变历史:
git reset 29dd8101d78 --soft
7)然后 - 在原始合并提交中将结果命名为
git commit --amend
瞧!
答案 3 :(得分:1)
看起来你要做的就是删除你的第一次合并。您可以按照以下步骤操作:
git checkout master # Let's make sure we are on master branch
git reset --hard master~ # Let's get back to master before the merge
git pull # or git merge remote/master
git merge topic
那会给你你想要的东西。
答案 4 :(得分:0)