336
develop branch
--> dashboard (working branch)

I use git merge --no-ff develop to merge any upstream changes into dashboard

git log:

commit 88113a64a21bf8a51409ee2a1321442fd08db705
Merge: 981bc20 888a557
Author: XXXX <>
Date:   Mon Jul 30 08:16:46 2012 -0500

    Merge branch 'develop' into dashboard

commit 888a5572428a372f15a52106b8d74ff910493f01
Author: root <root@magneto.giveforward.com>
Date:   Sun Jul 29 10:49:21 2012 -0500

    fixed end date edit display to have leading 0

commit 167ad941726c876349bfa445873bdcd475eb8cd8
Author: XXXX <>
Date:   Sun Jul 29 09:13:24 2012 -0500

The merge had about 50+ commits in it, and I am wondering how to just revert the merge so dashboard goes back to the state pre-merge

The second part of this is, if I dont do merge with --no-ff, I don't get the commit 'Merge branch 'develop' into dashboard' .. How would I roll that merge back?

BlitZ
  • 12,038
  • 3
  • 49
  • 68
cgmckeever
  • 3,923
  • 2
  • 18
  • 17
  • 3
    Possible duplicate of [Undo a Git merge?](http://stackoverflow.com/q/2389361/456814). –  Jul 07 '14 at 04:45

5 Answers5

469

Reverting a merge commit has been exhaustively covered in other questions. When you do a fast-forward merge, the second one you describe, you can use git reset to get back to the previous state:

git reset --hard <commit_before_merge>

You can find the <commit_before_merge> with git reflog, git log, or, if you're feeling the moxy (and haven't done anything else): git reset --hard HEAD@{1}

Community
  • 1
  • 1
Christopher
  • 42,720
  • 11
  • 81
  • 99
  • 6
    thanks for the quick reply .. looking at git log, the commit before the merge is 50+ commits back, as the git merge develop actually puts in all the other commits. I guess what I dont get is, if I dont know what/where that merge was - how do I find it? You mention finding the commit_before_merge .. I guess I am not understanding that part – cgmckeever Jul 30 '12 at 13:42
  • 5
    looks like with git reflog looks like it summarizes the last heads nicely, and allows me to know where I need to reset to. git log seems to have too much granularity to pinpoint the place to reset to. Thanks – cgmckeever Jul 30 '12 at 13:53
  • 1
    Yeah, `reflog`'s a lifesaver. `HEAD@{1}` just describes the second most recent state of HEAD, or more technically: "A ref followed by the suffix @ with an ordinal specification enclosed in a brace pair (e.g. {1}, {15}) specifies the n-th prior value of that ref." – Christopher Jul 30 '12 at 14:22
  • 5
    What about pushing the revert to remote? I don't see how it will work. – Anton Savelyev Apr 12 '19 at 16:26
  • This is especially dangerous if the branch in question is shared among multiple people. With `git reset`, you're rewriting the history of the branch, a history that already exists on everyone else's machines. It's much more in the spirit of git, in this scenario, to revert the merge commit via @sturrockad's answer below, with `git revert -m 1 ` – Whellow Jul 08 '19 at 18:54
  • 5
    This is hopeless. It destroys all commits after the merge. – aaa90210 Jul 22 '19 at 22:03
  • Ok, but then what? I did this and wanted the roll back to be remote as well, not just local, but couldn't commit with no changes or push this old state because it was "behind". – jupiterjelly Sep 19 '19 at 19:32
  • @jupiterjelly you have to --force it because it's behind. If you have changes you want to keep from after the merge, you can `git stash` them, revert the merge with the answer above, unstash the changes you made, and then push --force. As is standard, be careful with `--force` – James B Oct 29 '19 at 12:23
  • For the ff-merge case, if you have the previous commit, you can revert all the commits between the `HEAD` and the previous commit (`HEAD@{1}`) and squash them into a giant revert commit for brevity. Using reset will change history with all the consequences for public/shared repos – SEK Nov 05 '19 at 08:18
  • You can also use the `^` to get the commit before the merge. `git reset --hard [mergeCommitHash]^` – Umbrella Jun 17 '20 at 19:31
  • Please, don't to that if you working in a team, in a remote repository, this is disruptive, it will "destroy" the git working tree of the other users, this is not the way a "rollback" should be done in a remote repository - think of it as a ledger book, as in blockchain, you always have to go forward, even when "undoing" things. Take a look at `git revert`, it might help. This is fine if you are sure you are work alone in this repo. – Ualter Jr. Apr 14 '23 at 07:50
  • @UalterJr. The context of the question is that someone has just pulled and merged from the remote. This isn’t disruptive to anyone if the merge commit hasn’t been pushed out. – Guildenstern May 12 '23 at 14:48
  • Such a popular answer should hint at `git reset --hard @^` so that people don’t have to go reflog spelunking. – Guildenstern May 12 '23 at 14:49
  • And then what ? how to push the rollback to the remote branch ? – Ricky Levi Aug 01 '23 at 07:44
218

From here:

http://www.christianengvall.se/undo-pushed-merge-git/

git revert -m 1 <merge commit hash>

Git revert adds a new commit that rolls back the specified commit.

Using -m 1 tells git that this is a merge and we want to roll back to the parent commit on the master branch. You would use -m 2 to specify the develop branch.

SwissCodeMen
  • 4,222
  • 8
  • 24
  • 34
sturrockad
  • 4,460
  • 2
  • 19
  • 19
  • 43
    Note that you cannot re-merge the branch after this, as the docs says: "Reverting a merge commit declares that you will never want the tree changes brought in by the merge. As a result, later merges will only bring in tree changes introduced by commits that are not ancestors of the previously reverted merge. This may or may not be what you want." – Dalibor Karlović Nov 12 '15 at 09:44
  • 33
    @DaliborKarlović That statement is a bit harsh. You can definitely bring back those changes later, the trick is to revert the revert commit. More info [here](https://git-scm.com/blog/2010/03/02/undoing-merges.html) in the section "Reverting the revert" – Hilikus Nov 01 '16 at 18:15
  • 4
    Sadly, the `here` link in the @Hilikus comment is no longer valid. The site claims the content got moved to a book ( https://git-scm.com/book/en/v2 ) but if so, it is non-trivial to locate in there. – Jesse Chisholm Jul 26 '19 at 15:23
  • @DaliborKarlović is this the case wkth the answer above from @Christopher? – James B Oct 29 '19 at 12:25
  • 8
    The undoing merges content was moved to [here](https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_undoing_merges) – SEK Nov 05 '19 at 08:14
48

Just reset the merge commit with git reset --hard HEAD^.

If you use --no-ff git always creates a merge, even if you did not commit anything in between. Without --no-ff git will just do a fast forward, meaning your branches HEAD will be set to HEAD of the merged branch. To resolve this find the commit-id you want to revert to and git reset --hard $COMMITID.

Nico Erfurth
  • 3,362
  • 22
  • 26
28
git revert -m 1 88113a64a21bf8a51409ee2a1321442fd08db705

But may have unexpected side-effects. See --mainline parent-number option in git-scm.com/docs/git-revert

Perhaps a brute but effective way would be to check out the left parent of that commit, make a copy of all the files, checkout HEAD again, and replace all the contents with the old files. Then git will tell you what is being rolled back and you create your own revert commit :) !

Ryan McGeary
  • 235,892
  • 13
  • 95
  • 104
Jorge Orpinel Pérez
  • 6,361
  • 1
  • 21
  • 38
  • 1
    +1 because this answer does not mess with the history as reset does (really important if you already pushed to remote). But what unexpected side-effects should I expect? – pedromanoel Aug 24 '15 at 13:59
  • 3
    Is this the side-effect you mentioned? `Reverting a merge commit declares that you will never want the tree changes brought in by the merge. As a result, later merges will only bring in tree changes introduced by commits that are not ancestors of the previously reverted merge. This may or may not be what you want.` – pedromanoel Aug 24 '15 at 14:03
  • 1
    You say `git reset` is the solution, but also mention that it might have unexpected side-effects. However, that link is from `git revert`, not `git reset` :) – Mark Mar 19 '19 at 07:27
  • 2
    Please note, git reset does not have an -m flag. Also note @JorgeOrpinel references the git-revert docs, not git-reset. I think he meant to say `git revert` not `git reset` – Devin Gleason Lambert Jul 09 '19 at 16:03
  • How to avoid _Mainline was specified but commit 1234xyz is not a merge_ error. – Achal Jan 17 '20 at 11:46
  • you're reverting something that isn't a merge @Achal – Chazt3n Apr 06 '20 at 19:26
  • @pedromanoel - you can get the changes back by simply reverting the revert commit – Chazt3n Apr 06 '20 at 19:26
4

If you merged the branch, then reverted the merge using a pull request and merged that pull request to revert.

The easiest way I felt was to:

  1. Take out a new branch from develop/master (where you merged)
  2. Revert the "revert" using git revert -m 1 xxxxxx (if the revert was merged using a branch) or using git revert xxxxxx if it was a simple revert
  3. The new branch should now have the changes you want to merge again.
  4. Make changes or merge this branch to develop/master
Rohin Tak
  • 489
  • 4
  • 8