6

I have merged a dev branch (with constant, sometimes unstable changes) to our master branch (where we store the released, stable code). I want to restore the master branch to the state it was before like the merge with the dev branch had never happened (and that when in the future we merge the dev branch all changes that we will discard now will be merged "again").

This is the current status of the master branch and I want it to have the 'professional-1.1.2' commit/tag at the HEAD.

status of the master branch

I tried:

$ git revert -n professional-1.1.2..HEAD
fatal: Commit 9167e846a387c793edbc089c7ab6bd9eb8260456 is a merge but no -m option was given.
$ git revert -n -m 1 professional-1.1.2..HEAD
fatal: Mainline was specified but commit 380169097f35d07466640bc0db1b639278cd25fa is not a merge.
$ git revert -n -m 2 professional-1.1.2..HEAD
fatal: Mainline was specified but commit 380169097f35d07466640bc0db1b639278cd25fa is not a merge.

After a bit of research I think that the better option is do a git reset --hard professional-1.1.2 and git push --force as the answer to Git: How to ignore fast forward and revert origin [branch] to earlier commit? or reverting push'd git commit . Other developers are in the same office, and they should never commit anything to master (as neither should I, but... yeah, we don't have permissions per branch), so it's not a big problem to tell them and do any action required.

So in the end the question is: git revert something or git reset --hard <TAG> && git push --force? If git revert, which commandline should I use?

Community
  • 1
  • 1
Carlos Campderrós
  • 22,354
  • 11
  • 51
  • 57
  • 2
    The answer given by Jefromi in http://stackoverflow.com/questions/3556501/git-how-to-reset-after-merging might help you. – vpatil Apr 26 '12 at 09:58
  • 1
    @vpatil so better to use `git reset --hard` than `git revert` in my case? – Carlos Campderrós Apr 26 '12 at 10:08
  • 1
    Yes I think so because revert creates a new commit which cancels the last commit. I would definitely suggest to use reset. – vpatil Apr 26 '12 at 10:39
  • 1
    @CarlosCampderrós The only rule is that you should never overwrite history in a public repository. If it is your private repository, you can do whatever you want. But in a public repository, if you rewrite history, you break the repository for everyone who has already downloaded the part you are rewriting. – Šimon Tóth Apr 26 '12 at 12:27
  • @Let_Me_Be Yes I know that. I really don't like doing it but in the end I think that for my current case is the best option as the environment is controlled and nobody should have done nothing with the code in the master branch. – Carlos Campderrós Apr 26 '12 at 13:02

3 Answers3

6

The -m number option specifies which of the parents you want to revert to (since a merge has multiple parents).

So you want git revert -m 1 HEAD or git revert -m 1 SHA_OF_MERGE_COMMIT (assuming you did git checkout master; git merge devel;)

Šimon Tóth
  • 35,456
  • 20
  • 106
  • 151
  • but I don't want to revert just the merge commit, but all of the commits that came with that merge. Btw I dit `git checkout master; git pull origin develop`. – Carlos Campderrós Apr 26 '12 at 10:07
  • 2
    @CarlosCampderrós What do you think a merge commit is? Yes this will revert the merge, meaning: it will remove all the changes you merged into your branch. – Šimon Tóth Apr 26 '12 at 10:38
  • ok I just had the revert syntax wrong (so it didn't work when I tried first (as you can see in the question)) and I chose the wrong parent when I used your answer. Now... if in 2 months I merge the dev branch again, all commits that I'm reverting will be merged? Or only will be merged the changes since the merge I'm reverting now? – Carlos Campderrós Apr 26 '12 at 10:49
  • 1
    @CarlosCampderrós Merging doesn't care about commits. Merging will merge two (or more) HEADs. What is in the history is completely irrelevant. Only the current state on the HEAD is relevant. – Šimon Tóth Apr 26 '12 at 10:55
  • @Let_Me_Be: Actually, it depends on which merge strategy is used - git's basic three-way strategy considers the two parents *and* a common ancestor - which commit in the history is used as the common ancestor makes a big difference to the result of the merge. – Mark Longair Apr 26 '12 at 13:16
  • @MarkLongair Only on the auto merging algorithms. If you are merging manually, what difference can there be? – Šimon Tóth Apr 26 '12 at 13:19
  • @Let_Me_Be: I don't see any suggestion that the OP is intending to do anything more subtle than `git merge develop` at a later stage of development. – Mark Longair Apr 26 '12 at 14:44
6

If you just want to make the state of master exactly the same as professional-1.1.2, while avoiding rewriting history and force-pushing, you can just create a new commit on top of master that represents the same state of the project as professional-1.1.2. You can do that with the following steps:

# Check that "git status" is clean, since the steps that follow will throw
# way uncommitted changes:
git status

# Set the index (staging area) to be as it was at professional-1.1.2:
git read-tree professional-1.1.2

# Create a commit based on that index:
git commit -m "Reverting to the state at professional-1.1.2"

# Your working tree will still be as it was when you started, so
# you'll want to reset that to the new commit:
git reset --hard

As an alternative, you can follow the steps suggested in this answer by Charles Bailey, which accomplishes the same thing, but is slightly more confusing, I think (even though the steps I've suggested involve the "plumbing" command git read-tree).

Community
  • 1
  • 1
Mark Longair
  • 446,582
  • 72
  • 411
  • 327
  • Using this (making a new commit with the status of professional-1.1.2 and pushing it), will this allow the future merge of the dev branch again bringing again the changes that now I'm "reverting"? – Carlos Campderrós Apr 26 '12 at 10:13
  • If the commit I've suggested introducing ends up with object name `f414f31`, I think you can make the future merge work by doing `git revert f414f31` before `git merge dev`. (I think the principle is the same with as with [reverting-a-reverted-merge](http://schacon.github.com/git/howto/revert-a-faulty-merge.txt).) – Mark Longair Apr 26 '12 at 12:52
  • After reading http://code.google.com/p/git-core/source/browse/Documentation/howto/revert-a-faulty-merge.txt I think you are right @MarkLongair. This is more complicated and error-prone (because maybe before doing the `git merge dev` we forget about reverting the revert. As the repo is private and the environment is controlled, I think I'll go with the `git reset --hard` and `git push --force`. – Carlos Campderrós Apr 26 '12 at 13:01
  • @CarlosCampderrós: right - it wasn't clear to me how public the branch was. So long as you talk to anyone who might be pulling from that branch and explain to them how to deal with the rewritten history, it's fine to take the other approach... – Mark Longair Apr 26 '12 at 13:08
2

If you are a daredevil (recovering from an upstream rebase could be necessary for all other committers)

git checkout yourbranch
git reset HEAD <commit-hash>
git push origin yourbranch -f
Sergey K.
  • 24,894
  • 13
  • 106
  • 174