Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to revert a merge which used strategy=ours?

I'm working with a repository where a merge was performed weeks ago which we just discovered used the --strategy=ours flag (it was supposed to use the --strategy-option=ours flag), thus not applying any changes to HEAD. However, we need to have the changes applied. Git already recognizes the branch as being merged and the commits in the history of the branch.

This sort of merge can't be reverted using git revert -m ...

What would be the proper way of reverting and/or re-applying the merge to change the files?

master  A - B - E - F - G ---> L - M - N
             \     /
topic         C - D

Merge commit (F) would be the culprit in this scenario.

like image 285
Highway of Life Avatar asked Jan 08 '13 23:01

Highway of Life


2 Answers

I have discovered a solution to this problem. It was all in the letter that Linus wrote regarding reverting faulty merges: How to revert a faulty merge. The git merge --strategy=ours topic in our case was not intended. Even though it's a faulty merge, it can't be reverted, and having long been pushed, has the same effect of having a revert merge commit without being able to revert the revert commit.

The solution was to checkout the topic branch, run rebase --no-ff from the first commit and then merge that branch back into master.

git checkout topic
git rebase -i --no-ff <C>
git checkout master
git merge topic

This had the effect of yielding:

fixed–topic   C'–––D'––––––––––––––––––––-
             /                            \
master  A–––B–––E–––F–––G –––> L–––M–––N–––F2
             \     /
topic         C–––D

To really understand this in-depth, read the last portion of the letter How to Revert a Faulty Merge using the --no-ff rebase option to re-create the branch.

like image 52
Highway of Life Avatar answered Sep 29 '22 02:09

Highway of Life


@Highway of Life has a great answer. The one thing is that the rebased commits now look like new different commits, which in many cases may be undesirable. I wanted to merge the identical commits a second time, but git-merge prevents this. However, I find time and again that it is always possible to get git to do what you want.

  1. Follow Highway of Life's instructions but don't merge straight onto master:

    git checkout -b fixed-topic <D>
    git rebase -i --no-ff <B>
    git checkout -b re-merged master
    git merge fixed-topic
    

    This results in:

    re-merged               ––––––––––––––––––––------R
                           /                         /
    fixed–topic      C'–––D'                        /
                    /                              /
    master     A–––B–––E–––F–––G –––> L–––M–––N–––F2
                    \     /
    topic            C–––D
    
  2. Now the tree is set up exactly how you want—all the files show exactly the contents you desire. The one problem is that your merge commit's parents are rebased copies of your original commits, instead of actually being the original commits themselves. It's easy to fix this with git-reparent:

    git reparent -p master -p <D>
    

    This ends up with:

    master     A–––B–––E–––F–––G –––> L–––M–––N–––F2
                    \     /                        \
    topic            C–––D                          \
                          \                          \
    re-merged              ---------------------------R
    

    An important thing to note is that the contents of R haven't changed since the last step—only the parents.

  3. Fast-forward master to the new merge commit:

    git checkout master
    git merge re-merged
    
  4. Finally you can clean up with

    git branch -d fixed-topic re-master
    

Done! Now your history looks like this, with one branch merged twice:

master  A–––B–––E–––F–––G –––> L–––M–––N–––F2---R
             \     /                           /
topic         C–––D----------------------------
like image 30
adzenith Avatar answered Sep 29 '22 00:09

adzenith