0

So i was checking for other solutions but it's not exactly suited for me I'm also dealing with a branch merge

git log
commit 6d034e1b1f03241b2c660312660ce29acca23f60
Author: ME <myfakemail@gmail.com>
Date:   Thu Jun 30 13:09:08 2016 +0100

    text so people click the button

commit b9295485e17ccb6662b688b5c0f796656ef5f0de
Author: Me-again <myfakemail@fakeville.com>
Date:   Wed Jun 29 17:22:33 2016 +0100

    Adding the 4th celebration to index.php

commit 01ab5a9cfcefe34e72f06f52974da96ce1c2980a
Author: Me-again <myfakemail@fakeville.com>
Date:   Wed Jun 29 12:40:37 2016 +0100

    do the status check after all stops have been performed

commit 904bfdfbc4b536d052e61a303a17e6e108b7d9fe
Author: ME <myfakemail@gmail.com>
Date:   Thu Jun 23 15:16:39 2016 +0100

    changing music to StarSpangled

commit 5874707b022fb6039df84372a750c8fc57215af1
Author: ME <myfakemail@gmail.com>
Date:   Thu Jun 23 15:15:30 2016 +0100

    Quintessential american music

commit 175d5e53c43c7175b6478070d5660e7426aeade9
Author: Me-again <myfakemail@fakeville.com>
Date:   Wed Jun 22 13:11:48 2016 +0100

    Adding error logging and messaging for stop and start

commit 630c25055044a44be304353d3d18e385fed091a3
Merge: 7019947 35eb826
Author: Not Me <notme@mail.com>
Date:   Fri Jun 17 16:57:17 2016 +0100
    Quintessential american music

commit 175d5e53c43c7175b6478070d5660e7426aeade9
Author: Me-again <myfakemail@fakeville.com>
Date:   Wed Jun 22 13:11:48 2016 +0100

    Adding error logging and messaging for stop and start

commit 630c25055044a44be304353d3d18e385fed091a3
Merge: 7019947 35eb826
Author: Not Me <notme@mail.com>
Date:   Fri Jun 17 16:57:17 2016 +0100

    Merge branch 'master' of https://github.com/ME/MyProject

commit 7019947ceea28bd80d020e062a003433529c2a5a
Author: Not Me <notme@mail.com>
Date:   Fri Jun 17 16:57:00 2016 +0100

    4th of July draft

commit 35eb826c39f8b8e0fafd51a9cebae68dd434c7eb
Merge: f0a144f 6a6937d
Author: Me-again <myfakemail@fakeville.com>
Date:   Fri Jun 17 16:26:18 2016 +0100

    Merge branch 'master' of https://github.com/ME/MyProject

    Entering the new cast iron  options

So essentially we have this project and decided to add a bit of flavour/fun for our american brethren. The only thing though while we had it prepared for going up , there was some serious commits made to the project.

Now that the 4th is over I want to remove the themed stuff and go back to normal

I was thinking my options are

  • revert all the 4th related commits
  • rebase and add the two serious commits back into the code

So i ran

git revert --no-commit 6d034e1b1f03241b2c660312660ce29acca23f60 b9295485e17ccb6662b688b5c0f796656ef5f0de    904bfdfbc4b536d052e61a303a17e6e108b7d9fe 5874707b022fb6039df84372a750c8fc57215af1 630c25055044a44be304353d3d18e385fed091a3 7019947ceea28bd80d020e062a003433529c2a5a
error: Commit 630c25055044a44be304353d3d18e385fed091a3 is a merge but no -m option was given.

And from what I can see it's left me in a half reverted status with only the edits from those commits removed in the staging area but the changes introduced in the merge still there

Am i better to just rebase to the commit 35eb826c39f8b8e0fafd51a9cebae68dd434c7eb and then add

  • 01ab5a9cfcefe34e72f06f52974da96ce1c2980a

  • 175d5e53c43c7175b6478070d5660e7426aeade9

Sorry for the rant but if you git gurus were in a similar situation what course of action would you take ?

Community
  • 1
  • 1
segaps
  • 47
  • 6
  • This what you are looking for? http://stackoverflow.com/questions/7099833/how-to-revert-a-merge-commit-thats-already-pushed-to-remote-branch – Charlie Fish Jul 05 '16 at 22:21
  • Cheers for the link , but I suppose my main concern is which is the best method to use. I'm very new to Git in general so ideally if this situation arose which would be the best course of action to take ? The revert or the rebase I'd just like to be doing things in the most "correct" manner – segaps Jul 05 '16 at 22:30
  • If you want to undo changes personally I would use revert with those commits. I highly suggest making a copy of your repo so that if you mess up you always have a clean version. So test in your copy and once you know what commands to run then do it on the live repo. – Charlie Fish Jul 05 '16 at 22:32
  • Also HIGHLY recommend SourceTree or some type of Git GUI – Charlie Fish Jul 05 '16 at 22:34

1 Answers1

1

What to know about Git here:

  • Git always adds new stuff. A revert adds a new commit. A rebase adds new commits. A merge, for that matter, adds a new commit.

  • But git rebase adds new commits in a somewhat unusual way. It copies existing commits, by changing them into patches (or mostly-equivalently, into git cherry-pick actions) that are then patch-applied to a different—earlier or later—starting point than before.

  • Moreover, git rebase generally skips merge commits. It's impossible to copy a merge commit in this way, so if you use the --preserve option (which attempts to preserve merges), git rebase re-does the merges, rather than trying to copy them. (How well this works, if it works at all, generally depends both on how simple the merge was originally and where you're "moving" the new commit-chain to.)

  • An interactive rebase lets you choose which commits to copy, and whether to stop and adjust copies. This means that if you copy a chain of commits, leaving out one "bad" one, you get a new chain that never makes the "bad" change. It also lets you "squash" several commits into a single commit, by applying the changes from all but the last of those commits without making a new commit yet, then making the new commit using the final work-tree, and the commit-text from all the commits (and having you edit that text down into a single message).

  • Once rebase is done copying commits, it moves the branch name, so that instead of pointing to the previous tip of the branch, it now points to the tip-most copied commit. The old commits are still in your repository, but the effect is as if they had been removed, and the branch rewound, and then the new copies added in the new place you have copied them to.

    This means that anyone else who is using the original commits—which assumes that you have published (usually git push-ed) them and someone else has the originals—now must take some special action to account for your "copy and rewind and point to copies" effect.

  • Finally, since Git is built around this "add new stuff" model, if you always add new stuff in the simplest way—including ordinary reverts—then everyone and everything around Git works right with no extra fiddling required.

Conclusion: revert is easier

So, you probably do want to revert, just as you have attempted.

It looks to me as though you did almost everything right, in your git revert sequence here. You did one thing that's totally optional—you chose --no-commit so that all the reverts could be combined into one big "undo a bunch of stuff" commit—and then you ran into the problem that reverting a merge is harder than reverting a "regular" (non-merge) commit.

How revert works

The reason that reverting a merge commit is harder has to do with the mechanism of action. To do a revert, Git does, in essence, a "backwards diff": instead of comparing "before" vs "after", to see how to change the older version into the newer, Git compares "after" vs "before", to see how to change back.

To achieve either comparison, Git needs two commit-IDs: the "before" version and the "after" version. For an ordinary (non-merge) commit, this is easy. The commit itself is the "after", and its parent is the "before". Run git log --oneline --graph --decorate to see the parent/child relationships visually. Note now ordinary, non-merge commits have one parent. A merge commit, however, has two (or more) parents, and this means git revert does not know which one to treat as the "before" version.

This is why you get the is a merge but no -m option was given error: the commit is a merge and git revert needs to know which changes to undo, i.e., which parent to compare against. (You almost certainly want -m 1 here.)

Because you used --no-commit, Git did each revert one at a time, as specified on the command line, without committing. It then hit the error and stopped, so it has not reverted that merge, nor any subsequent commits listed on the command line.

Without --no-commit, Git would do each revert and then commit the revert, leaving you in a more obvious state when it failed with the complaint about -m.

Unfortunately, you must specify a -m option to revert a merge commit, and you must not specify a -m option to revert a non-merge commit. This means you must use multiple git revert commands.

The good news is that you can continue with your existing git revert --no-commit: just git revert -n -m 1 <the merge>, then git revert -n each additional commit (just the one more to do). When you are all done, git commit the result to undo everything in one giant revert.

Alternatively, if you would prefer to revert one thing at a time—this makes it easier to see what you were doing, when you look back at this a year from now, but also makes it noisier (and therefore harder) to see what you were doing—you can use git reset --hard to go back to the index/staging-area and work-tree state of the most recent commit:

$ git reset --hard HEAD

This assumes that everything (index and work-tree both) were clean when you started this whole git revert sequence, of course. Now you can:

$ git revert ...

each commit, without -n this time. (This assumes you have changed your mind about wanting to have one big reversal.)

How I might do it

Note that you can do the reverts one at a time, then use git rebase -i to squash them all down into one big revert. This ends up working exactly the same as using git revert -n: first you make a chain of six individual reverts, then you collapse the (unpublished) chain into one big revert, then you publish (git push) the final result.

I might do it this way myself so that I can verify that each revert worked properly, look over the version that has the six individual commits, think for a bit and decide whether future-me would prefer this or the one-big-revert, and then rebase-and-push, or just push, based on that.

Community
  • 1
  • 1
torek
  • 448,244
  • 59
  • 642
  • 775
  • Thank you for the highly detailed answer, really learnt a lot but I did run into this issue git revert -n -m 1 630c25055044a44be304353d3d18e385fed091a3 error: could not revert 630c250... Merge branch 'master' of https://github.com/ME/MyProject – segaps Jul 05 '16 at 23:22
  • If the revert itself fails even with `-m`, you'll be left with some merge conflicts to resolve. This is when reverting one at a time, without `-n`, is most helpful, as your work-tree will have just one intermediate state in it, rather than 4+ to figure out. – torek Jul 05 '16 at 23:26