重新绑定Git合并提交

jip*_*ino 163 git merge rebase git-rebase git-rewrite-history

采取以下案例:

我在主题分支中有一些工作,现在我已准备好合并回主人:

* eb3b733 3     [master] [origin/master]
| * b62cae6 2   [topic]
|/  
* 38abeae 1
Run Code Online (Sandbox Code Playgroud)

我从master执行合并,解决冲突,现在我有:

*   8101fe3 Merge branch 'topic'  [master]
|\  
| * b62cae6 2                     [topic]
* | eb3b733 3                     [origin/master]
|/  
* 38abeae 1
Run Code Online (Sandbox Code Playgroud)

现在,合并花了我一些时间,所以我再做一次提取并注意到远程主分支有新的变化:

*   8101fe3 Merge branch 'topic'  [master]
|\  
| * b62cae6 2                     [topic]
| | * e7affba 4                   [origin/master]
| |/  
|/|   
* | eb3b733 3
|/  
* 38abeae 1
Run Code Online (Sandbox Code Playgroud)

如果我从master中尝试'git rebase origin/master',我将被迫再次解决所有冲突,并且我也失去了合并提交:

* d4de423 2       [master]
* e7affba 4       [origin/master]
* eb3b733 3
| * b62cae6 2     [topic]
|/  
* 38abeae 1
Run Code Online (Sandbox Code Playgroud)

是否有一种干净的方法来重新定义合并提交,所以我最终得到的历史就像我在下面显示的那样?

*   51984c7 Merge branch 'topic'  [master]
|\  
| * b62cae6 2                     [topic]
* | e7affba 4                     [origin/master]
* | eb3b733 3
|/  
* 38abeae 1
Run Code Online (Sandbox Code Playgroud)

sir*_*ide 117

这里有两个选择.

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

另一种方法是使用-p选项on git rebase,手册中描述如下:"不要忽略合并,而是尝试重新创建它们." 这个问题进一步解释了这一点:git的"rebase --preserve-merges"到底是做什么的(为什么?)

  • 我尝试了-p选项,它确实保留了我想要的提交历史记录,但它迫使我再次解决冲突,即使在未在origin/master中编辑的文件中也是如此.从你的第一个建议开始,这将是精确的命令序列? (14认同)
  • 这是一篇很好的博客文章,描述了这个确切的情况:[在Git中重新合并提交](http://notes.envato.com/developers/rebasing-merge-commits-in-git) (3认同)
  • @jipumarino:git rebase -i(告诉它编辑合并提交),当它进入合并提交时,git reset --hard HEAD ^,git merge,fix conflict,git commit,git rebase --continue.你可能也想看看git rerere应该有助于这种事情(但我从未使用过,所以我不能提供任何建议或帮助). (2认同)
  • 谢谢.我启用了rerere并尝试使用rebase -p并且它正常工作. (2认同)

Iva*_*nov 23

好吧,这是一个老问题,它已经接受了答案@siride,但在我的情况下答案是不够的,因为--preserve-merges迫使你第二次解决所有冲突.我的解决方案基于这个想法,@Tobi B但具有精确的逐步命令

所以我们将基于问题中的示例开始这样的状态:

*   8101fe3 Merge branch 'topic'  [HEAD -> master]
|\  
| * b62cae6 2                     [topic]
| |
| | * f5a7ca8 5                   [origin/master]
| | * e7affba 4
| |/  
|/|   
* | eb3b733 3
|/  
* 38abeae 1
Run Code Online (Sandbox Code Playgroud)

请注意,我们提前2次提交master,所以cherry-pick不起作用.

  1. 首先,让我们创建我们想要的正确历史:

    git checkout -b correct-history # create new branch to save master for future
    git rebase -s ours -p origin/master
    
    Run Code Online (Sandbox Code Playgroud)

    -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
    
    Run Code Online (Sandbox Code Playgroud)
  2. 让我们现在得到正确的索引.

    git checkout master # return to our master branch
    git merge origin/master # merge origin/master on top of our master
    
    Run Code Online (Sandbox Code Playgroud)

    我们可能会在这里得到一些额外的合并冲突,但这只会是来自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
    
    Run Code Online (Sandbox Code Playgroud)
  3. 最后一个阶段是将我们的分支与正确的历史和分支与正确的索引相结合

    git reset --soft correct-history
    git commit --amend
    
    Run Code Online (Sandbox Code Playgroud)

    我们使用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
    
    Run Code Online (Sandbox Code Playgroud)


Cla*_*uin 5

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

我们的代码库很大,我们必须处理两个分支,它们需要同时大量修改。如果有的话,有一个主分支和一个辅助分支。

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

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

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

1)记下SHA。例如:c4a924d458ea0629c0d694f1b9e9576a3ecf506b

git log -1
Run Code Online (Sandbox Code Playgroud)

2)创建正确的历史记录,但这会破坏合并。

git rebase -s ours --preserve-merges origin/master
Run Code Online (Sandbox Code Playgroud)

3)记下SHA。例如:29dd8101d78

git log -1
Run Code Online (Sandbox Code Playgroud)

4)现在重置为您以前的位置

git reset c4a924d458ea0629c0d694f1b9e9576a3ecf506b --hard
Run Code Online (Sandbox Code Playgroud)

5)现在将当前的母版合并到您的工作分支中

git merge origin/master
git mergetool
git commit -m"correct files
Run Code Online (Sandbox Code Playgroud)

6)现在您有了正确的文件,但是错误的历史记录,请使用:在更改的基础上获得正确的历史记录:

git reset 29dd8101d78 --soft
Run Code Online (Sandbox Code Playgroud)

7)然后-修改原始合并提交中的结果

git commit --amend
Run Code Online (Sandbox Code Playgroud)

瞧!