Revert changes made by merge
Asked Answered
E

4

30

The developer was commiting small changes to two files. But during this commit, he had a merge conflict which deleted a lot of stuff (probably didn't have the last up to date version). Then it was pushed to the shared repo and some other developers did some other commits.

Now, we noticed, that the merge deleted the important files, and we want to revert it back.
How can I do this without losing the changes from the next commits?

I was trying to git revert commitsha, but it didn't bring the changes back. Do I need to revert back the mergesha? How can I determine it?

Excision answered 30/11, 2011 at 8:30 Comment(1)
Have you tried cherry-pick?Tsaritsyn
K
44

git revert --mainline

Usually:

git revert --mainline 1 dd8cbe3e4

Where:

  • dd8cbe3e4 is the bad merge commit you want to undo, and
  • --mainline tells you which of the multiple previous commits is the one to restore (remember, a merge commit has multiple parent commits and you can only keep one of them).
    • I can't find a good explanation of what the 1 means, but my guess is that 1,2,3... corresponds to a list of mappings to the commits immediately before dd8cbe3e4, sorted by ascending chronological order (oldest first - which is usually what you want to revert to).

Source:

http://thezencoder.com/2013/09/05/how-to-correctly-revert-a-bad-merge-in-git/

Katelin answered 18/8, 2015 at 22:43 Comment(3)
I believe your statement about mainline is correct — docs: git-scm.com/docs/git-revert#git-revert--mparent-numberDarkle
--mainline works for me but -m does not. Gives me fatal: bad revision '1'Troopship
Pretty sad that we have to guess what the 1 means. Regarding your guess: do you think chronological order is in terms of CommitDate, or in terms of AuthorDate?Brusa
J
10

In short, WARNING: there is no real safe way to undo a merge except to actually reset the branch to the commit before the merge.

Let me explain and browse for an existing reference for now.

Quoting the linked answer from How do you revert a faulty git merge commit

Basically, reverting a merge will undo the data changes, but not the history (graph) changes. Therefore it is expected that reverting your faulty merge does nothing.

Certainly, resetting the branch would be the most simple approach, but it has drawbacks if the result of the merge has already been pushed to a shared repo (because you're effectively rewriting published history).

Here is the breakdown

  • git merge <someref> to merge (optionally commit after resolving conflicts)
  • If you find out right away that you want to reset the branch to before the merge:

    git reset HEAD@{1} 
         # optionally pass --hard to reset the working tree too
    
  • if you found out only later,

    • per-use the reflog to find the point before the merge. (HEAD@{1} is short for the previous value of the current head reference, but the reflog tracks a limited history of values for the head reference)

      git reflog
      
    • reset the branch

      git reset HEAD@{n} # substitute reflog entry index
      
    • optionally rebase/cherry-pick the commits done after the merge

      git cherry-pick HEAD@{1} # just an example. interactive tools will make this easier
      
Jemmy answered 30/11, 2011 at 8:46 Comment(6)
Thanks sehe this was close enough! Of course it doesn't work due to some other errors. I am hoping, one day some team will create a version control system that doesn't need a separate master degree and developers can concentrate on development instead of spending days on figuring out a system that is made safe but as confusing as it can be. I dislike git since the first day I was using it and that didn't change since, it evolves though, will be good one day :(Bitolj
The problem with reset rather than revert is that if you’ve already pushed the bad merge and others have pulled it, it’s going to complicate life for them. Once you push, you should generally create compensatory new commits rather than removing commits.Katelin
That's the same issue as ever with changing published history. It's not a problem with reset, it's a problem with published history :)Jemmy
Right, but what do you do after you’ve reset to the last good commit? It’s analogous to syncing clocks in distributed systems. You should never go backwards in time.Katelin
There is no place for "but" in your last message: it's just restating what you already said. That same point was in my answer ever since Nov 30 '11. I guess you can use this answer as a reason to (a) avoid merge, favour pull --rebase (b) never edit merge conflicts in the merge commit (c) don't bork merges (d) enable git-rerereJemmy
Yes you’re right, I didn’t read your full original answer (and others seeing it may not either).Katelin
P
6

Another (more safe) approach is to create a diff between the last good and the current version of the file and then restore the lost parts by copy&paste.

This always works, doesn't need any odd command line options, and it doesn't tamper with things that you should leave alone :-)

Eclipse, for example, has good tools to cherry pick each individual difference and copy it to either version. Just use the "Compare" menu to open both versions side by side.

Pyx answered 30/11, 2011 at 10:1 Comment(1)
Sadly you're right. As a preventative measure it's better to rebase rather mergeKatelin
Y
1

In short, you can do a git reset --soft <commit> where commit can be HEAD^ (previous), HEAD~2 (current-2), a SHA, etc.

With --soft all the changes will be ready to commit, so you can actually change the commit. With --hard the changes will all be lost.

After you altered the commit you have to force push the changes to the shared repo with git push --force.

Note that you will need to tell the other developers that they should rebase their repos onto the shared repo. (use git pull --rebase). They could get some merge conflicts though... Please keep that in mind.

Yawata answered 30/11, 2011 at 8:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.