Git revert is the command you need to undo a commit in Git, and is the safest way to change history in a git repo. Rather than just discarding changes, like git reset, which I covered in this post, git revert looks at the changes made in a commit and then reverses, or applies the inverse, of each of those changes in a new commit. So rather than hiding what happened by discarding the work in the files you’re undoing, and risking losing work, it records the ‘undo’ in the history. This is much safer way of working and is always the recommended way to undo a commit, especially if you have already pushed your changes to a remote repo.
How to use git revert to undo a commit after you have pushed
Let’s say you’ve pushed some code into the repo and now you’ve realised that something is really wrong. You’ve been working all morning, you’ve made 3 commits, and you now know that the 3rd commit is bad and contains a mistake.
We can use git log to see all our commits, even better we can use :
git log --oneline
… to see a condensed, simple list of our commits, and the hash id for each. It will look like this:
The commit with hash id 2667ffe is the first commit, and is good. But the 3rd commit which has a hash id of c7c318a is bad and we want to ‘undo’ it. We’ve pushed this code to the remote branch so the important (really, really important) thing to be aware of here is that while you’ve slowly been dawning on the fact you’ve pushed some bad code into the repo, your team mates may have pulled that code down to their local repos and are currently wondering why something is wrong.
This is where git reset would NOT work because simply discarding the bad files in your local repo won’t help make everyone else’s bad code get better. So what we want to do, in plain English is:
- Fix the bad code locally by undoing that commit
- Commit the changes so that the fix is recorded in our repo history
- Push this new commit to the remote repo
- Let our team mates know so they can pull down the new, fixed, code
And to do that we will firstly do a git revert of that third commit, so we get the hash id from the git log as shown above, and then type:
git revert c7c318a
This will bring up a series of messages in the terminal window, showing you that you are in the process of reverting the commit. It will suggest a message for this new commit, which you can edit if you want to by placing your cursor where you want to type and then typing (sounds obvious but it is not intuitive). Once you’ve finished editing that message press Esc followed by :wq (you have to hold all 3 of these keys down together). That will save the message, do the commit, and exit from the Vim terminal.
So that is the problem resolved in your local repo, now you need to push this new commit to the remote repo, so type:
And finally you need to let your team mates know you broke it – but you’ve fixed it too!
Getting a merge conflict when using git revert
Depending on the specific details of the changes you’ve made in each of those commits you may get a merge conflict. If so you’ll see something like this, and the file(s) with conflicts will open in your editor asking you to handle the conflict and choose which bits of code you want to keep or discard. You follow the onscreen prompts and then set the commit message, save and then push the new commit, just as described above.
Git revert is a ‘forward moving’ undo operation. Git reset is a backwards moving undo operation. Git revert preserves the change history in your repo, git reset discards the changes. So now you know how to undo a commit in git after you have pushed.