Question

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.

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.

Was it helpful?

Solution

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.

OTHER TIPS

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...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top