Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accidentally merged master into develop and pushed

Tags:

git

github

I work in a git repo where we maintain a master and a develop branch. Changes are made in develop and merged into master before releases. Today I accidentally merged master into develop and pushed the result to develop. A git log in develop now shows the merge develop into master commits. I need to fix this somehow. I found the most recent good commit using git reflog. What is the correct approach to revert to it?

Since I have already pushed, I would like to avoid rewriting history. However, I'm not sure that I can use git revert. I'm not convinced that the "revert a faulty merge" howto and other SO questions apply since the commits that I want to revert are merges themselves (https://www.kernel.org/pub/software/scm/git/docs/howto/revert-a-faulty-merge.txt).

like image 891
aschmied Avatar asked Oct 01 '13 01:10

aschmied


People also ask

How do I revert changes from merged to master?

simply run git reset --hard to revert all those changes.

Can you undo a merge to master?

You can use the Git reset command to undo a merge. Firstly, you need to check for the commit hash (or id) so you can use it to go back to the previous commit. To check for the hash, run git log or git reflog . git reflog is a better option because things are more readable with it.

How do I undo a merge in progress?

How do I cancel a git merge? Use git-reset or git merge --abort to cancel a merge that had conflicts. Please note that all the changes will be reset, and this operation cannot be reverted, so make sure to commit or git-stash all your changes before you start a merge.

How do I undo a merge master into a branch?

You can undo a Git merge using the git reset –merge command. This command changes all files that are different between your current repository and a particular commit. There is no “git undo merge” command but the git reset command works well to undo a merge.


1 Answers

You can use git revert to revert the merge. Just be aware that when you do that, you make a future "re-merge" more difficult. Read that message you linked closely—it says a lot about how to make the future "re-merge" work—but be aware that it's talking about merging develop into master, and you said you did the opposite, merged master into develop:

A -- B -- C -- D -- E          <-- master
      \          \
       F - G - H - M           <-- develop

In this case (having merged master into develop instead of the other way around) you can choose a number of different options, all with advantages and drawbacks...

The easiest method, which I prefer if it's an option

(0) Do nothing. If merging in C and D doesn't break the develop branch, just leave it that way. Later, someone will git checkout master and git merge --no-ff develop and get this (let's say one more commit I got added to develop first):

A -- B -- C -- D -- E -- M2    <-- master
      \          \      /
       F - G - H - M - I       <-- develop

Here merge finds what's been done in develop since it split off from master, which was at B. So it puts in F, G, and H, skips any parts of M that came off master (probably all of it), and finally puts in I and makes merge-commit M2 (because of commit E; but if E were not there, it would be because I used --no-ff too).

Some easy methods with obvious drawbacks

(1) Just "rewrite history": erase commit M from branch develop. Alert everyone else who uses the branch that this is about to happen: that commit M is going away and they should take whatever measures they must, to handle this.

(2) Stop using the old name develop, make a new branch name develop1 or whatever:

A -- B -- C -- D -- E          <-- master
     |           \
     |             M           <-- develop
      \          /
       F - G - H               <-- develop1

This is the same as option (1) except that the commit M is still there, along with the branch label on it, and you have a new/different branch label pointing to commit H. You still need to alert everyone, but it might make their jobs easier. You can delete develop later, when everyone is good with that.

The revert and its drawbacks

(3) Revert the merge. As in the linked article, let's use W to represent the new revert commit:

A -- B -- C -- D -- E          <-- master
      \          \
       F - G - H - M - W       <-- develop

What's in W? Whatever it takes to "erase the effect" of the merge. In this case, that means, changes that un-do whatever was done in C and D. So far so good, develop has just the changes from F, G, and H, again. The problem occurs later, if/when someone does:

git checkout master
git merge develop

The second command goes rooting around to find where master and develop were split, i.e., commit B, so it picks up all the changes since then. Which at this point include those in W, which will un-do C and D, not at all what you wanted. It can be fixed-up afterward, but whoever does the merge has to know about this "delete C and D" time-bomb waiting for them.

Note that this is the same merge as in the "do nothing" option (0). The issue here is the contents of W. In case (0), you want the contents of commit I, but here you don't want the contents of W.

One more option

This is arguably the worst option of all, given what's shown above, but I'll list it anyway:

(4) make an all-new branch with copies of the commits you want to keep, and name it develop. (Or name it something else, but then we're back to the develop1-like situation above, and you should probably just use that one.) Whether you keep the old-develop branch, or just abandon it (by not labeling it), is up to you, but I will draw it in:

       F' - G' - H'            <-- develop
      /
A -- B -- C -- D -- E          <-- master
      \          \
       F - G - H - M           <-- old-develop

This is described in the link you included. It's only really useful in more complex cases.

like image 82
torek Avatar answered Oct 20 '22 08:10

torek