Undoing Things With Git

Sometimes bad things happen in a software project and you have to revert a change that has already been committed. There are several ways to do this with Git, including Git's slightly scary ability of changing history. I'll show you the techniques I found most useful.

The classic way of rolling back a change is by recording a new change that reverts the earlier one. This is how it's usually done in systems like Subversion. A change in a revision control system is basically a delta that modifies one revision by turning it into the next revision. By applying such a delta the other way round, you can take a change back. All you need is the SHA-1 checksum of the commit, which you get from the commit log. Then run the revert command using this checksum (or a unique prefix of it):

$ git revert e052b88d

Git opens an editor to let you edit the commit message and then commits a new revision that shows up in the commit log like any other change. If you want to examine the change before committing, you can add the --no-commit command line flag. When you're happy with the change, commit it as usual.

The older the change you're trying to revert, the higher the probability that it doesn't work cleanly. In this case you will have to resolve conflicts manually in your working copy and commit them when you're done.

The git revert method is the preferred way of taking back a change that you already pushed to another repository. Git also supports more drastic methods that manipulate your existing commit history. A word of caution though: Never change anything that you have already shared with someone else! If you do, you open the door to confusion and chaos. The following methods assume that you haven't shared the given revisions with anyone yet.

When committing a change, you sometimes forget to add a new file or you change an existing file but forget to stage it. Git offers you a simple way of fixing this by amending your last commit. Just stage all files using add and commit using the --amend flag:

$ git add some-new-file a-modified-file
$ git commit --amend

Git will open an editor with the previous commit's message, giving you a chance to modify it. When you check the commit log afterwards, you will see a single commit, but with a different revision number than your original commit.

A similar, but more flexible way is to remove the previous commit from the commit log, but leave it in the staging area, giving you a chance to modify the files, and to possibly re-commit them:

$ git reset --soft HEAD^
# edit files and stage changes
$ git commit

You can even reuse the original commit message if you like:

$ git commit -c ORIG_HEAD

When you really want to get rid of your last commit, perhaps because it's broken beyond repair, run the following command:

$ git reset --hard HEAD^

Afterwards, your commit log will show no trace of it. The usual advice applies when doing potentially dangerous things with Git: Be extra careful and have your backup handy.

The techniques I discussed in this article just skim the surface of what you can do with Git. Check the commands' manpages for details, like additional flags that may be useful in your particular situation.