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.

Advertisements
This entry was posted in tools and tagged , , , . Bookmark the permalink.

2 Responses to Undoing Things With Git

  1. Danilo Piazzalunga says:

    Nice article! I am always a bit uncomfortable with some Git commands, like ‘git reset’: there is no clear distinction between “safe” and “dangerous” commands, and the operation performed by the command becomes radically different just by changing an option.

    • mafr says:

      I know what you mean. Git has some really powerful concepts, but the user interface is horrific. To be honest, I prefer Mercurial for this very reason, but projects I contribute to work with Git, so I don’t have much of a choice.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s