143

Steps I performed:

I have two branches branch1 and branch2,

$git branch --Initial state
$branch1

$git checkout branch2
$git pull origin branch1 --Step1

I resolve the conflicts and did a

$git commit -m "Merge resolved"

then

$git checkout branch1
$git merge branch2
$git push origin branch1

Now I realised that while being at step1, the auto merging removed some code and the change code was pushed. Now I want to go back to my initial state in order to revert any changes. Looking for some immediate help?

5
  • Does git revert not do what you want? Commented Sep 21, 2012 at 17:00
  • 1
    it gives message as : fatal: Commit b4a758b36a5bde9311061fe7b56e4f47859de052 is a merge but no -m option was given. @FrederickCheung
    – Bijendra
    Commented Sep 21, 2012 at 18:11
  • Check out the manual about -m option. kernel.org/pub/software/scm/git/docs/git-revert.html Shortly you can use -m 1 or -m 2. This selects to which of two parent revisions you want to revert. Commented Sep 21, 2012 at 20:41
  • yaa i used git revert -m 1 SHA, now all the changes come as changes to be committed in my local,
    – Bijendra
    Commented Sep 22, 2012 at 6:35
  • 1
    There was a error in vim which was exiting it while revert operation, i ran git config --global core.editor /usr/bin/vim and it fixed the issue and then the revert successfully ran to fix the issue.Thanx
    – Bijendra
    Commented Sep 22, 2012 at 9:01

6 Answers 6

162

You can revert the merge following the official guide, however this leaves Git with the erroneous belief that the merged commits are still on the target branch.

Basically you have to :

git revert -m 1 (Commit id of the merge commit)
2
  • 48
    One should be careful with the 1. It means the first parent of merge commit. But if one (hypothetically) 'by accident' merged master to the branch, then fast-forwarded master to the merged commit - one should use -m 2 to revert the merge on master. Commented Sep 26, 2014 at 13:42
  • 2
    Be careful with that 1. It messed up my repository by partially reverting the merge, whereas I wanted to revert the merge completely. I ended up reverting the revert!
    – Javad
    Commented May 25, 2016 at 10:43
71

Try using git reflog <branch> to find out where your branch was before the merge and git reset --hard <commit number> to restore the old revision.

Reflog will show you older states of the branch, so you can return it to any change set you like.

Make sure you are in correct branch when you use git reset

To change remote repository history, you can do git push -f, however this is not recommended because someone can alredy have downloaded changes, pushed by you.

4
  • 2
    i had pushed the code to the remote branch, how will this revert the code from there..
    – Bijendra
    Commented Sep 21, 2012 at 16:54
  • 3
    if you already pushed, you do NOT want to do local history re-writing, as Ilya described
    – ms-tg
    Commented Sep 21, 2012 at 17:41
  • 5
    Sorry, I've missed that thing... Sometimes you can use git push -f to rewrite remote history. This depends on your remote repository config and other team members (if they won't kill you for that forced push). Commented Sep 21, 2012 at 20:31
  • 1
    This must be done very carefully, but it can be useful. If you can confirm with all your team members and no one has pulled it, or they will also reset their own local copy. Otherwise, no!
    – Basya
    Commented Aug 27, 2023 at 14:34
42

The first option is the use of git revert.

git revert -m 1 [sha-commit-before-merge]

The git revert will revert the changes but will keep the history. Therefore you will not be able to continue working in the same branch since you cannot see the actual difference between the merged branch and your feature branch anymore. Use the following way to remove history as well. Do this very carefully if and only if you are the only one pushing changes to the branch at the moment.

git reset --hard [sha-commit-before-merge]
git push [origin] [branch] --force
2
  • 7
    Used the second approach and it worked like a charm. This also made my GitHub merge PR clean as it was before. Thanks. Commented Jan 10, 2022 at 16:40
  • 1
    the second approach was a life saver, because It did not create an undo merge commit. it just took the latest commit back.
    – A5H1Q
    Commented Sep 22, 2023 at 10:19
11

More explanation for given answer git revert -m 1 <merge commit id> with a graphical representation and an example, step-by-step.

Reverting a merge commit is not straightforward as with git revert <commit-hash>, since Git gets confused when looking back from the merge commit due to its two parent commits. To specify the desired parent, uses the -m flag. As git cannot determine which parent is the mainline and which is the branch to un-merge automatically, so this must be specified.

git commit graph

The iss53 branch was merged into master, creating a Merge Commit, C6. C6 had two parents, C5 and C4.

Need to revert C6 and return the repository to its state at C4. So it must specify which parent to use for the revert command.

  • For that check the git log, (here representing actual commit hash with code names from graph)

    > git log
    
    commit C6
    Merge: C4 C5
    Author: Mozz <[email protected]>
    Date:   Wed Feb 29 23:59:59 2020 +0100
    
    Merge branch 'iss53' to master
    ...
    
  • From git log output, note down the parent IDs that come with Merge: - -. It will be in the format of Merge: parent1 parent2, here Merge: C4 C5.

  • The C4 commit is in master branch and we need to revert to that, that is parent 1 and -m 1 is needed here (use git log C4 to verify the previous commits to confirm parent branch).

  • Switch to the branch on which the merge was made ( it is the master branch here and we aim to remove the iss53 branch from it )

    Do the git revert with -m 1 flag.

    # To revert to C4 in master branch
    git revert C6 -m 1
    
    # C6 - is the merge commit hash
    

For some other cases, if needed revert to C5,

# revert to C5 in iss53 branch
git revert C6 -m 2

# General
git revert <merge commit id> -m 1 (reverts to parent1)
git revert <merge commit id> -m 2 (reverts to parent2)
# remember to check and verify the parent1 and parent2 with git log command.

Practical example

Created a new branch revert-test on an existing project that has only main branch, The commit graph looks like this now.

git tree before

(For graphical view of commits use —graph with git log [SO ans ref] OR this more interactive VS code extension - git graph)

Now, I've added some new files, modified existing files, and created separate commits on each branch, then pushed them to the origin. The graph now looks like this:

git tree after commit

Then, created a pull request from GitHub and merged revert-test branch to main.

git tree after merge

I want to undo the merge commit and go back to the last commit in the main branch - which is 12a7327

Note that the merge commit - 2ec06d9 has two parents now - 12a7327 (in main) and 15bde47 (in revert-test), checking git log now,

> git log

commit 2ec06d9d315a3f7919ffe4ad2c2d7cec8c8f9aa3 (HEAD -> main, origin/main, origin/HEAD)
Merge: 12a7327 15bde47
Author: Akshay <[email protected]>
Date:   Sun Feb 5 00:41:13 2023 +0530

    Merge pull request #1 from Akshay/revert-test
    
    Revert test

To revert the merge commit and get back to 12a7327 need to do,

# To the First parent
git revert 2ec06d9 -m 1

Now a commit message will show in editor that specifies the details, check and verify.

git revert commit verify message

So that creates a Revert commit that does the inverse changes of the merge commit.

revert commit

Lastly push the changes, Now the merge commit changes gone and the Log will look like,

final git tree

0
1

In my case, I merged my branch (say: my-branch) with another feature branch (feature-branch) but not master. So my branch history was like this:

my-branch (before merge)

---master----m1----m2----m3---m4

After merging it with another feature-branch which had commits f1, f2 on top of master, it became like this:

my-branch (after merge)

---master----m1----m2----f1----f2----m3---m4----mergecommit

This might have happened because while working on my branch I did a merge from master after 2 commits, or one of 2 branches might not have been up to date with master. So in this case git revert -m 1 was not working as it was leaving those f1 and f2 commits in between.

The solution was simple, which will work in case of normal scenarios, where we don't have in-between commits:

git rebase -i HEAD~6

Instead of 6 use appropriate number based on how many past commits you want to change. Now Vim editor is opened, just mark undesired commits as drop and same and quit using :wq verify log:

git log --oneline 

force push

git push -f

Now the remote branch should be in previous state.

1

As mentioned in another answer, the primary issue with doing a git revert on a merge is that git still thinks all the previous commits were merged (it only changes the code). If you attempt to merge that branch later on, you'll find those prior commits are missing.

The better way (obviously after consulting with your team so they don't keep working on a problematic branch) is to git reset to an earlier commit. It doesn't have to be a hard reset, since that only deals with what to do with your current working changes, so that part is up to you.

You can also create a temporary branch from the previous commit if you would like to make changes there first before doing the reset. In that case you would reset to a commit on your temporary branch.

You won't be able to push without pulling from your upstream, but obviously you don't want to pull the changes you're trying to revert. So, you'll need to do a force push (or force push with lease to stop if any changes have been pushed in the interim).

Side Note: As a fan of VS Code and Git Graph, I find the force push is easy to do by right clicking on the local branch tag name and selecting 'Push Branch...', choosing either Force or Force With Lease, leaving the Set Upstream box checked.

Not the answer you're looking for? Browse other questions tagged or ask your own question.