Reputation: 3930
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?
Upvotes: 30
Views: 46696
Reputation: 25226
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).
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/
Upvotes: 44
Reputation: 392893
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
Upvotes: 10
Reputation: 328556
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.
Upvotes: 6
Reputation: 17769
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.
Upvotes: 1