How to fix the history in a wrong merge

I have a problem in Git that I am unable to fix. I have searched for similar cases but I was unable to find a good solution for my situation.

I basically have 2 branches, master and bugfix. Bugfix is derived from master at a point when we’ve done a release. Every time we fix something in bugfix and do a bugfix release we need to merge that in master. Master contains the new features (and of course should never be merged into bugfix). It so happens that someone did merge master with bugfix by mistake.

  • How do I merge between multiple forked repositories on GitHub?
  • Getting push to deploy to work, configuring “release pipeline”
  • Project Organization using Maven + Git
  • Gradle script to autoversion and include the commit hash in Android
  • Is there a simple solution for importing different branches of software into a new git repository?
  • Git Installation on OSX: Cannot exec 'git-credential-osxkeychain': Bad CPU type in executable
  • This is what happened:
    
     master: x1---x2
                    \
     bugfix: y1--y2--M
    
    where M is the merge between bugfix and master
    

    A solution for this was to revert the merge which I did with “git revert -m 1 M” (M is here the SHA from the merge) as described here. I did a revert because we’ve already had other changes in the bugfix branch that we did not want to lose and this worked fine for the bugfix branch.

    Current state:
    
     master: x1--x2------------x---x
    
     bugfix: y1--x1--y2--x2--M--y--y--R1
    
    where R1 is the revert of M
    

    The problem appears later on when we need to merge the bugfix branch in master. As described in the link I’ve posted, the revert fixes the code changes but not the history, this means that when I merge bugfix in master the revert is going to take effect and remove the changes from the master (x1 and x2). What I can do is a revert of the revert in the bugfix before I merge it in master.

    Solution:
    
     master: x1--x2------------x---x--------M
                                           /
     bugfix: y1--x1--y2--x2--M--y--y--R1--R2
    
    where R2 is the revert of R1
    

    This works but is not a final solution because every time we do a merge we would need to do this “revert of the revert”. I have been looking for a permanent solution to this for a few days now and it seems that the only option would be to erase the master commits (x1 and x2) from the bugfix branch’s history. But x1 and x2 are used here just as an example, in reality we have many more commits and dissecting the history of the bugfix branch is very difficult and error prone. I am certain that Git can help me do this but I don’t know how.

    Any ideas would be very helpful.

  • How to “unversion” a file in either svn and/or git
  • Git merge while switching to submodule
  • How to get details about Stashes in LibGit2Sharp?
  • Git: error: RPC failed; result=22, HTTP code = 411
  • How can I see the list of files changed in last or a particular commit?
  • Should I commit /bin directory when working with virtualenv?
  • 3 Solutions collect form web for “How to fix the history in a wrong merge”

    I would personally recommend rewriting the history (see the answer of Useless) and telling your team. But that requires everybody to have a certain level of git knowledge. If the rewrite approach is too risky for you, here’s an alternative:

    What’s happening

    Whenever you merge A into B, git will add all the commits/changes that are reachable from A but not B to B. Your revert is one of them. As you noticed, without rewriting you can’t do anything about that.

    The solution

    You will have to merge the revert into master. As you want keep the stuff you reverted in master, you also need an undo of that revert on master (=reachable from master). The best way to achieve that is with these commands:

    git checkout -b bugfix-revert bugfix
    git revert R1
    git checkout master
    git merge bugfix-revert
    git branch -d bugfix-revert
    

    After these commands every branch will be in the state you want it to be and you can merge bugfix again from now on. Your history will look like this:

     [master] x1---x2----------------------H
                     \                    /
     [bugfix-revert]  \                  M''
                       \                /
     [bugfix] y1--y2----M--y3--y4--M'--y5
    

    As you can see, master contains M', but its changes are not in H, because M'' undid those. M' will never be applied to master, because it already contains it. The state bugfix did not change, and won’t have to.

    Why not just create a new bugfix branch without the bad merge in the first place? You’ll need to coordinate switching branches with everyone though, to make sure no commits get lost

    So you have:

     [master] x1---x2
                     \
     [bugfix]  y1--y2--M--y3--y4--M'
    

    (where M' is the reversion of M). But, you could create a new branch:

    $ git branch bugfix-fix y4
    
     [master] x1---x2
                     \
     [bugfix]  y1--y2--M--y3--y4--M'
                              ^^
                         [bugfix-fix]
    

    detach it from the problematic merge and reversion

    $ git rebase --onto y2 M bugfix-fix
    
     [master] x1---x2
                     \
     [bugfix]  y1--y2--M--y3--y4--M'
                     \
     [bugfix-fix]     y3'--y4'
    

    and then once you’ve verified everything you need is on bugfix-fix, you can just rename both branches

    $ git branch -m bugfix bugfix-broken
    $ git branch -m bugfix-fix bugfix
    

    (you’ll need to push this forcibly, which is safe so long as you’re coordinating with everyone who might have it checked out).

    Your solution is correct… You need to ‘revert the revert’, THEN do another merge with your bugfix branch (to pull in any bugfix commits that were done after the first incorrect merge), just as you’ve shown. This will restore the fixes from your y1 and y2 commits, keep your history correct and pull in the updated changes performed after the first mistaken merge point.

    You would not need to worry about this for future merges as the last merge point is the place in history that git would try to make the merge from, not anything before it (the same exact reason you need to do the ‘revert of the revert’)…


    Do not know why you say this leaves bugfix in a broken state. The following works just fine. You can continue to work on the bug fix branch as necessary without worrying about having to revert anything anymore (unless you obviously do the same thing again…). If you need to merge with master again in the future, you can without issue (need to do nothing special) as git knows the history and will only look for merge issues/conflicts from the point at which the two branches were last common (this last merge).

    https://github.com/g19fanatic/stackoverflow-16713251-496405

    gitk example


    Here is a link with Linus describing this very problem and presenting my above proposed solution as one possible way to correct it…

    Git Baby is a git and github fan, let's start git clone.