简体   繁体   English

错误合并后重建git分支(尊重合并提交)

[英]Rebuilding git branch after a faulty merge (respecting merge commits)

I have a classic situation: I merged a dev branch into master , then realised I made a mistake and reverted the merge. 我有一个典型的情况:我将一个dev分支合并到master ,然后意识到我犯了一个错误并恢复了合并。 Then added a fix into dev and want to merge it again. 然后将一个修复程序添加到dev并希望再次合并它。 Of course, I cannot merge it directly, since, from git's point of view, it was already merged. 当然,我不能直接合并它,因为从git的角度来看,它已经被合并了。

Classic solution 经典解决方案

Revert the revert commit, apply your fix. 还原还原提交,应用您的修复程序。 Move on. 继续。

  • Pros : simple. 优点 :简单。

  • Cons : history is spoiled. 缺点 :历史被宠坏了。 It is very hard to blame deeper than this revert of the revert. 很难比这次恢复的责任更深。

What I want 我想要的是

I want to rebuild the dev branch from scratch, and merge it again. 我想从头开始重建dev分支,然后再次合并。 Should be easily done with git rebase --force-rebase , according to the books. 根据书,应该使用git rebase --force-rebase轻松完成。 But the branch history was not so simple, and contained a number of merges, including merges from master . 但是分支的历史记录并不是那么简单,它包含许多合并,包括master合并。 I want to respect these. 我要尊重这些。

Let's have an example already: 让我们已经有一个例子:

                                     master|
                                           v
-*------------X-----Y---------*-----*----M-W
  \          /       \         \   /    /
   \        /         \         -*-    /
    \      /  -D-      G--H--         /
     \    /  /   \    /      \       /
      A--B--C-----E--F--------I-----J
                                    ^
                                    |dev

The faulty merge is M . 错误的合并是M Its revert is W . 其还原为W I assume that commits on dev up to B are ok, since B was merged into master as X . 我认为对B dev提交是可以的,因为B已作为X合并到master中。 I want to rebuild the branch starting from B with exactly the same topology. 我想从B开始以完全相同的拓扑重建分支。 See the tree below. 请参阅下面的树。 New commits are marked with the prime. 新提交标记有撇号。 You can see how commits C..J were rebased to C'..J' . 您可以看到如何将提交C..J重新设置为C'..J' Correspondingly, dev is rebased to dev' . 相应地, dev会以dev' Other commits did not change. 其他提交未更改。

                                dev'|
                                    v
            C'----E'-F'-------I'----J'
           / \   /    \      /        
          |   -D'      G'-H'-           
          |           /                    |master
          |          /                     v
-*--------+---X-----Y---------*-----*----M-W
  \       |  /       \         \   /    /
   \      | /         \         -*-    /
    \     |/  -D-      G--H--         /
     \    /  /   \    /      \       /
      A--B--C-----E--F--------I-----J
                                    ^
                                    |dev


Then I'll apply my fix K and merge this new branch to master : 然后,我将应用我的修订K并将此新分支合并到master

                                dev'|
                                    v
            C'----E'-F'-------I'----J'--K
           / \   /    \      /           \
          |   -D'      G'-H'-             \
          |           /                    \ |master
          |          /                      \v
-*--------+---X-----Y---------*-----*----M-W-M2
  \       |  /       \         \   /    /
   \      | /         \         -*-    /
    \     |/  -D-      G--H--         /
     \    /  /   \    /      \       /
      A--B--C-----E--F--------I-----J
                                    ^
                                    |dev

  • Pros : good history. 优点 :良好的历史。

  • Cons : I don't know how to do this. 缺点 :我不知道该怎么做。

Ok, seems like rebase has an option for this, and it is called --rebase-merges . 好的,似乎rebase为此提供了一个选项,它称为--rebase-merges But it does not do what I want. 但这并不能满足我的要求。 It rebases all commits, that are ancestors of dev and descendants of B . 它以所有提交为基础, dev祖先和B后代 Which includes commits X and Y . 其中包括提交XY Which are on master already, why would I want them? 哪些已经master了,我为什么要它们? (Actually, it also brings some other commits from the more ancient history, and I don't understand why yet, but it's not the point here). (实际上,它还带来了更古老的历史中的其他一些贡献,我还不知道为什么,但这不是重点)。

Instead, I want to bring commits, that are ancestors of dev but not master (considering master before the faulty merge of course). 相反,我想提出一些提交, 这些提交dev始祖,而不是master (当然,在错误合并之前考虑master )。 Sounds really easy to me. 对我来说听起来真的很容易。 Yet I don't understand how to do it, except by manually constructing this difference of commits and somehow cherry-picking them by hand, carefully preserving parents. 但是我不知道该怎么做,除非通过手工构造这种不同的提交,然后以某种方式手工挑选它们,并小心翼翼地保护父母。

So, how do I rebuild my branch, containing only work done on my branch and respecting merge commits? 那么,如何重建分支, 包含在分支上完成的工作并尊重合并提交?

PS We cannot simply reset master to M^ , that would be too easy. PS我们不能简单地将master重置为M^ ,这太容易了。

Ok, seems like I found a solution: 好的,好像我找到了解决方案:

  1. git rebase --interactive --rebase-merges B dev
  2. reword C 改写C

This produces exactly the history I want. 这正是我想要的历史。 Credits to @mstrap for the hint. 归功于@mstrap作为提示。

I'm not exactly sure why this works the way I want though. 我不确定这为什么能按我想要的方式工作。

Based on https://github.com/git/git/blob/master/Documentation/howto/revert-a-faulty-merge.txt , I would 基于https://github.com/git/git/blob/master/Documentation/howto/revert-a-faulty-merge.txt ,我会

git checkout dev
$EDITOR files
git commit files -m 'Fix'
git checkout master
git revert W
git merge dev

The revert-revert is necessary to keep the changes when you re-merge. 当您重新合并时,还原-还原是保持更改所必需的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM