Search code examples
gitgit-branchgit-mergegit-revert

Why did this revert fail?


While attempting to revert a commit which is not the latest on my branch, I have run into this message:

error: commit fce9354*** is a merge but no -m option was given.
fatal: revert failed

Here is the git log of the branch just before the revert attempt:

C:\git\manager [feature/revert]> gl -n15 --oneline
a81945f (HEAD -> feature/revert, origin/develop, develop) Merge branch 'develop' of https://xyz/manager into develop
60cf3e5 Merge branch '***' into develop
b94fc85 Merge branch '***' into develop
9d81bc6 (origin/***) Accept 
48b318d (origin/***) Accept 
6f57592 ***
d823f1f (origin/***) removed 
854887b *** merged
0ebef20 added 
fce9354 Merged PR 12345: Add 
90f2b0f (origin/***) Add 
c859184 Merge branch '***' into develop
a1afdb3 Change 
fb48628 added 
2641680 added 
C:\git\manager [feature/revert]> git revert fce9354
error: commit fce9354*** is a merge but no -m option was given.
fatal: revert failed

I understand that a revert is essentially a new commit created to undo a previous commit.

The git revert documentation for the -m flag states:

Usually you cannot revert a merge because you do not know which side of the merge should be considered the mainline. This option specifies the parent number (starting from 1) of the mainline and allows revert to reverse the change relative to the specified parent.

How can I find the value I should be providing to the -m flag?

I only want to remove the commit which represents the merge of the branch into the develop branch so that I can fix the branch and create a later merge which introduces everything on the branch back into develop. ie: I do not want to prevent previous changes on the branch from being merged into develop later.

Is there a simpler way to undo the changes of a previous commit?


Solution

  • A typical merge commit would be shown as below in the git log command output.

    commit dddfd0b6d529bfcdcd6515555ea1dcf186fe338
    Merge: 6b5619b 40ad694
    Author: Raja Anbazhagan <[email protected]>
    Date:   Fri Jun 7 03:11:23 2019 +0530
    
        Merge branch 'xyz' into 'develop'
    

    Here, You can see that the second line contains two short hashes. 6b5619b and 40ad694. Both of these are the top most commits of the branches that got merged.

    Here 6b5619b is the top most commit id of the branch develop. And 40ad694 is the top most commit of the feature branch xyz.

    I am telling you all this is because this information is important for what I am going to explain next.

    When you are resetting or reverting a commit, it will try to figure out what had changed in that commit by comparing it to its ancestor commit.

    In this case there are two ancestors 6b5619b and 40ad694 and GIT is now not sure from which ancestor it has to find the diff.

    In these cases, the user will have to provide the appropriate parent commit id for the process to continue. Which is done with a flag -m followed by an ordinal number that represents where the parent commit id resides in the merge commit.

    for my sample merge commit, possible -m values are 1 and 2. 1 for 6b5619b and 2 for 40ad694.

    So if you want to revert your code on your develop branch, you should do

    git revert -m 1 <merge-commit>
    

    With -m 1 the git revert happens in relevance to develop branch (first parent of the merge). Passing -m 2 would result in the revert happening in relevance to the feature branch xxx

    In general cases -m 1 is the one you should use. But that is not true for all cases.