Git - How to Undo After a Push
In the last article, we covered how to undo things locally in Git before we’ve run push, or in other words, to undo commits. In this article, I’ll go over ways in which we can undo things after we’ve pushed them to the remote server.
Creating an ‘anti’ commit
The most elegant and simple way is to create a kind of ‘anti commit.’ This could be thought of as a commit that undoes the most recent commit and puts itself in its place. This is very easy to do using:
git revert dd61ab31
That strange number is the Git ID in the log. As you may well remember, every commit has a unique number that we can see in the log. We need to find in the log the commit that we want to cancel and then write its number (or just the last 5 digits really) after the git revert command. It goes without saying that this must be on the same branch and be clean of any changes. What happens is that Git, that little trooper, will create a commit on the computer that will undo all of the changes that were made on the same commit. This commit we can use just like any other commit and be certain that all of the changes that were made in the canceled commit will be undone.
The disadvantage of this is that it will all be saved in the log. Though really, this isn’t such a big deal and there’s really no shame in admitting that you messed up and had to undo a commit gone wrong.
Here we need to be quite careful. If anyone else is sharing your branch, it’s likely to end very badly. Why you ask? Because if the other user ran a fetch after the commit that you want to undo and before you actually undo it, it’s possible that their version won’t be able to sync with the remote version, and this would be really bad. So if you change the history in a branch that someone else is working on, then you should really use revert. But, if you want to change the history of the branch and you’re ready to take your chances, here is the code:
git push -f origin last_known_good_commit:branch_name
How to Undo Merges in Git
If you want to undo a merge of branches that were pushed to the remote server, this too is possible. If you ran the merge and then want to undo it, nothing could be easier. Let’s say you ran merge on some branch inside of my master. I look at the log of the remote server using git log and find the point where I did the merge and push the branch. Normally you’ll see ‘Merge pull request’ written next to this. Here an example:
I take its hash, and if you remember, we’re talking about its ID. Again, there’s no need to use the entire number, just the last five digits will do. Then run:
git checkout master git reset --hard 204070
The local branch is in the version that comes right before the merge. Then we run:
git push origin master --force
It’s best to push the change. The merge is effectively canceled and we kind of go back in time. Take note that the revert also includes commits that were made after the merge. In other words, if you added code after running the merge, it’s gone for good. That’s why this method is really good but only if you change your mind immediately after the merge.
If a long time has passed since the merge that you want to undo, it’s more complicated. The first thing you need to do is have a look at the git log and locate the hash of the push where the merge was done. For example:
git revert -m 1 204070
All of the code of this specific branch will be most unceremoniously removed. It’s important to take note of the 1 that comes after the flag m. Why? It indicates the parent that we want to look at. In this case, it’s the original branch. Most of the time this is a 1.
The merge is taken out of the code but will be remembered in eternal disgrace in the history. If at some point you want to merge that branch again, you’ll need to take a few extra steps because at this point Git is sure that this branch is already merged. What steps? First, cancel the undo. How? Look in the log and find where we canceled the merge, and then find its number. Run:
git revert 88edd6d
This will cancel the undo and put in all changes that were made till the canceling of the original branch. Now we need to put in the other changes that were made to the branch using a plain old merge like this:
git merge jk/post-checkout
In general, if I did an unmerge, it’s rare that I would need to put the discarded branch back in, but if for some reason you want to do this, it is indeed possible.
Canceling a Merge from the History
If for whatever reason you don’t want the canceled merge to appear in the history, it’s possible to do this. Of course this is on the condition that only you are using the specific branch and no one else. Why? Because you’re changing the history and if this branch is located on other machines, and changes were made, it’s possible that they’ll have problems since their local history won’t match that of the server. So this is definitely not recommended.
So what can be done instead? Just find the merge number in the log and then run the following code (123456 is the merge number for our purposes):
git rebase -i 123456
And that’s it! That merge has been erased from history. Next time we’ll have a look at Git bisect.
About the author: Ran Bar-Zik is an experienced web developer whose personal blog, Internet Israel, features articles and guides on Node.js, MongoDB, Git, SASS, jQuery, HTML 5, MySQL, and more. Translation of the original article by Aaron Raizen.