重定一个Git合并提交


183

采取以下情况:

我在主题分支中有一些工作,现在可以合并回master了:

* eb3b733 3     [master] [origin/master]
| * b62cae6 2   [topic]
|/  
* 38abeae 1

我从母版执行合并,解决了冲突,现在有了:

*   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

74
TL; DR:git rebase --preserve-merges origin/master
Ilia K.

6
关于必须重新解决冲突,您可能想看看git rerere
帕克·考茨

git config --global pull.rebase preserve 始终在重定
基准

4
警告:从Git 2.18(2018年第二季度,5年后)开始,git --rebase-merges最终将取代旧版本git --preserve-merges。看看Git的“ rebase --preserve-merges” 到底做了什么(为什么?)
VonC

1
--preserve-merges不推荐使用。使用git rebase --rebase-merges origin/master
Arjun Sreedharan

Answers:


126

这里有两个选择。

一种是进行交互式变基并编辑合并提交,手动重做合并并继续变基。

另一个方法是使用--rebase-mergeson上的选项git rebase,该选项在手册中进行了如下描述:“默认情况下,rebase会简单地从todo列表中删除合并提交,并将重新提交的内容放入单个线性分支中。使用--rebase-合并时,通过重新创建合并提交,rebase将尝试在要重新提交的提交中保留分支结构。在这些合并提交中解决的任何合并冲突或手动修改都必须手动解决/重新应用。”


16
我尝试了-p选项,确实确实保留了所需的提交历史记录,但是即使在未在origin / master中进行编辑的文件中,它也迫使我再次解决冲突。根据您的第一个建议,命令的确切顺序是什么?
jipumarino 2011年

2
@jipumarino:git rebase -i(告诉它编辑合并提交),当它到达合并提交时,git reset --hard HEAD ^,git merge,修复冲突,git commit,git rebase --continue。您可能还需要查看git rerere,它应该可以帮助解决此类问题(但是我从未使用过,所以我无法提供任何建议或帮助)。
siride

2
谢谢。我启用了rerere并尝试使用rebase -p,它可以正常工作。
jipumarino 2011年

3
这里有一个很好的博客帖子描述这个确切情况:衍合合并提交Git中
kynan

1
rere不是解决方案,因为您仍然必须在第一时间手动解决合并问题。
Flimm 2014年

29

好的,这是一个古老的问题,并且已经接受的回答@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个commit提前掌握,所以Cherry-pick无效。

  1. 首先,让我们创建所需的正确历史记录:

    git checkout -b correct-history # create new branch to save master for future
    git rebase --strategy=ours --preserve-merges origin/master
    

    我们--preserve-merges用来将合并提交保存在历史记录中。我们--strategy=ours过去常常忽略所有合并冲突,因为我们并不关心合并提交中的内容,我们现在只需要很好的历史记录即可。

    历史将如下所示(忽略母版):

    *   51984c7 Merge branch 'topic'  [HEAD -> correct-history]
    |\  
    | * b62cae6 2                     [topic]
    * | f5a7ca8 5                     [origin/master]
    * | e7affba 4
    * | eb3b733 3
    |/  
    * 38abeae 1
    
  2. 现在获取正确的索引。

    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
    
  3. 最后一个阶段是将具有正确历史记录的分支与具有正确索引的分支合并

    git reset --soft correct-history
    git commit --amend
    

    我们用于reset --soft将分支(和历史记录)重置为正确的历史记录,但是将索引和工作树保持不变。然后,我们使用commit --amendmaster的良好索引来重写以前具有错误索引的合并提交。

    最后,我们将得到这样的状态(注意top commit的另一个id):

    *   13e6d03 Merge branch 'topic'  [HEAD -> master]
    |\  
    | * b62cae6 2                     [topic]
    * | f5a7ca8 5                     [origin/master]
    * | e7affba 4
    * | eb3b733 3
    |/  
    * 38abeae 1
    

这很棒,对您有很大帮助!但是我并没有用commit --amend来解决问题:您能在此添加更多信息吗?运行它之后究竟发生了什么-我注意到提交的SHA已更改-但是为什么呢?或者,如果不运行该怎么办?
ZenJ

1
@ZenJ git commit --amend将更改添加到最后一个提交(HEAD,在本例中为合并提交)。由于提交内容发生更改,因此哈希被更新。
Dries Staelens

1
对于在解决冲突之前未启用“重启动”的用户而言,此解决方案非常有用,因为它使您不必再次解决冲突。谢谢!
沙克福德

6

考虑到我刚刚花了一天时间试图解决这个问题,并且实际上在同事的帮助下找到了解决方案,所以我认为我应该介入。

我们有一个庞大的代码库,并且必须处理两个分支,同时要对其进行大量修改。如果有的话,有一个主分支和一个辅助分支。

当我将辅助分支合并到主分支中时,工作将在主分支中继续进行,到完成时,我无法推送更改,因为它们是不兼容的。

因此,我需要“重新设置”我的“合并”。

这就是我们最终做到的方式:

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

瞧!


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
启用rerere后,这似乎可以提供与siride上面给出的rebase -p解决方案相同的结果。
jipumarino 2011年

0
  • 从您的合并提交
  • 选择新的变化,这应该很容易
  • 复制你的东西
  • 仅从本地副本中复制文件即可重做合并并解决冲突;)

1
这个答案看起来不错,但是如果您给出了实际的git命令,将会更有用,以防万一用户是git的新用户
Louise Davies
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.