290

So I'm working on a project with other people, and there's multiple github forks being worked on. Someone just made a fix for a problem and I merged with his fork, but then I realized that I could find a better solution. I want to revert the commit I just made. I tried doing this with git revert HEAD but it gave me this error:

fatal: Commit <SHA1> is a merge but no -m option was given.

What does that mean? When I merged and committed, I did use the -m option to say "Merged with <username>".

What am I doing wrong here?

Greg Bacon
  • 134,834
  • 32
  • 188
  • 245
icnhzabot
  • 9,801
  • 5
  • 21
  • 9

4 Answers4

352

By default git revert refuses to revert a merge commit as what that actually means is ambiguous. I presume that your HEAD is in fact a merge commit.

If you want to revert the merge commit, you have to specify which parent of the merge you want to consider to be the main trunk, i.e. what you want to revert to.

Often this will be parent number one, for example if you were on master and did git merge unwanted and then decided to revert the merge of unwanted. The first parent would be your pre-merge master branch and the second parent would be the tip of unwanted.

In this case you could do:

git revert -m 1 HEAD

git cat-file -p [MERGE_COMMIT_ID] will show the parent branches in order. The first one listed would be -m 1, the second -m 2.

Community
  • 1
  • 1
CB Bailey
  • 755,051
  • 104
  • 632
  • 656
  • 5
    OK thanks. I found it easier just to change the two files that were affected by the merge and then commit some of my other changes too. – icnhzabot May 11 '11 at 22:11
  • 65
    Where can I find information whether I have to use -m1 or -m2, ...? – Patrick Cornelissen Jul 18 '16 at 08:51
  • 53
    `git cat-file -p [MERGE_COMMIT_ID]` will show the parent branches in order. The first one listed would be `-m 1`, the second `-m 2`. – nostromo Oct 12 '16 at 05:23
  • 2
    `git revert [HASH] -m 2` is telling me On branch 1.x-1.x nothing to commit, working directory clean but my commit is not reverted. – jenlampton Nov 29 '16 at 19:45
  • the same is true of `git revert 731a400e53381010ec617 -m2` (with no space) – jenlampton Nov 29 '16 at 19:46
  • What I did to determine what number to give with `-m` was to simply try `git revert -m 1 thecommithash` and check if the diff looked right. If not, get rid of the revert (with a `git reset --hard commit_before_revert`) and try again with `-m 2`. – Henrik N Mar 06 '17 at 12:44
  • 5
    So if I need to revert back past 10 merges (which is quite likely since git performs a merge automatically everytime I pull in changes from another developer) I have to do this for every single merge? Is this why git fans are so keen on rebasing, because revert is basically useless? – Neutrino Sep 17 '17 at 16:50
  • 1
    This is BY FAR the best explanation for this. This should be marked as the answer – dVyper Apr 26 '18 at 15:12
  • 1
    what's all the "m" stuff? I dont see any "m 1" or "m 2" when I run `git cat-file -p SOMECOMMIT`. I see 3 lines labeled: tree, parent, parent. – cyrf Jul 27 '21 at 00:52
  • 2
    "what that actually means is ambiguous" - I disagree. If I'm on `branch-b` and merge in some commits from `branch-a`, this results in modified content on `branch-b`, and no modification on `branch-a`. The only sensible thing "revert" can mean in this context is "undo the modifications made to `branch-b`". There's zero ambiguity. – aroth Dec 16 '21 at 03:24
  • Is there any canonical source that clearly explains what numbering system is understood by the --mainline flag? The documentation is (to me) a bit vague: "This option specifies the parent number (starting from 1) of the mainline and allows revert to reverse the change relative to the specified parent" – Nate Kennedy Jan 14 '22 at 00:06
59

Say the other guy created bar on top of foo, but you created baz in the meantime and then merged, giving a history of

$ git lola
*   2582152 (HEAD, master) Merge branch 'otherguy'
|\  
| * c7256de (otherguy) bar
* | b7e7176 baz
|/  
* 9968f79 foo

Note: git lola is a non-standard but useful alias.

No dice with git revert:

$ git revert HEAD
fatal: Commit 2582152... is a merge but no -m option was given.

Charles Bailey gave an excellent answer as usual. Using git revert as in

$ git revert --no-edit -m 1 HEAD
[master e900aad] Revert "Merge branch 'otherguy'"
 0 files changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 bar

effectively deletes bar and produces a history of

$ git lola
* e900aad (HEAD, master) Revert "Merge branch 'otherguy'"
*   2582152 Merge branch 'otherguy'
|\  
| * c7256de (otherguy) bar
* | b7e7176 baz
|/  
* 9968f79 foo

But I suspect you want to throw away the merge commit:

$ git reset --hard HEAD^
HEAD is now at b7e7176 baz

$ git lola
* b7e7176 (HEAD, master) baz
| * c7256de (otherguy) bar
|/  
* 9968f79 foo

As documented in the git rev-parse manual

<rev>^, e.g. HEAD^, v1.5.1^0
A suffix ^ to a revision parameter means the first parent of that commit object. ^<n> means the n-th parent (i.e. <rev>^ is equivalent to <rev>^1). As a special rule, <rev>^0 means the commit itself and is used when <rev> is the object name of a tag object that refers to a commit object.

so before invoking git reset, HEAD^ (or HEAD^1) was b7e7176 and HEAD^2 was c7256de, i.e., respectively the first and second parents of the merge commit.

Be careful with git reset --hard because it can destroy work.

Community
  • 1
  • 1
Greg Bacon
  • 134,834
  • 32
  • 188
  • 245
  • 3
    It's a mixed up, muddled up, shook up world. Except for Lola. Thanks a million for this fantastic alias. – Barney Jan 28 '16 at 14:52
  • 1
    Easy way to Add `lola` to your git commands: `git config --global alias.lola "log --graph --decorate --pretty=oneline --abbrev-commit --all"` – D. Gibbs Apr 28 '20 at 16:05
10

I had this problem, the solution was to look at the commit graph (using gitk) and see that I had the following:

*   commit I want to cherry-pick (x)
|\  
| * branch I want to cherry-pick to (y)
* | 
|/  
* common parent (x)

I understand now that I want to do

git cherry-pick -m 2 mycommitsha

This is because -m 1 would merge based on the common parent where as -m 2 merges based on branch y, that is the one I want to cherry-pick to.

shmish111
  • 3,697
  • 5
  • 30
  • 52
  • 1
    Possibly because it's not related to `git-revert`, which is what this question is about. – pnomolos May 09 '16 at 16:52
  • 1
    I think this question is about the `-m` option, not exclusively about `git merge`. I.e., the reasoning behind the use of the `-m` option would seem to be similar for reverts and cherry-picks. If that's not true, please let us know. Since I haven't found any other questions that specifically address the cherry-pick use of it, thanks for this answer, which probably led google to help me find this question and useful, relevant discussion! – nealmcb Nov 30 '17 at 15:54
  • If I understand correctly, git has no record of which branch (y) was made on; as far as it knows, your picture is symmetric: the unnamed commit on the left branch isn't any better or worse than the one on the right (y) in any way. If that's correct, how does it decide which is 1 and which is 2? – Don Hatch Sep 29 '20 at 20:00
3

In the original question, the '-m option' of the git error was probably mistaken to denote a commit message. As explained in the other answers, use '-m n' to specify the nth parent of the merge to pick the parent you consider to be the main trunk.