No matter how experienced you are, the craft of software development cannot be practiced without making mistakes. But what separates the average from the great programmers is that they know how to undo their mistakes!
If you’re using Git as your version control system, you already have a host of “undo tools” at hand. This post will show you five powerful ways to undo mistakes with Git!
Discarding Some of Your Local Changes
Coding is often a messy process. At times, it feels like you’re taking two steps forward and one step back. In other words: some of the code that you’ve produced is great … but some of it not so much. Here’s where Git can help you: it allows you to keep what’s good and discard the changes that you don’t want anymore.
Let’s take a look at an example scenario with some “local” changes (aka changes we haven’t committed, yet).
Note: for a better overview and clearer visualization, I’m using the Tower Git desktop client in some of my screenshots. You don’t need Tower to follow along with this tutorial.
Let’s tackle the problem in general.css first. The changes we made went in a totally wrong direction. Let’s undo all of them and recreate the last committed state of that file:
$ git restore css/general.css
Note that, alternatively, I could have used the git checkout command to achieve the same outcome. But because git checkout has so many different jobs and meanings, I strongly prefer the slightly newer git restore command (which is focused solely on these types of tasks).
Our second problem in index.html is a little bit more tricky. Some of the changes we made in this file are actually great, while only some of them need to be undone.
Again, git restore comes to the rescue — but this time with the -p flag, because we want to go down to the “patch” level:
$ git restore -p index.html
Git will then take you by the hand and ask you — for every chunk of changes in that file — if you want to discard it or not.
You’ll notice that I typed “n” for the first chunk (in order to keep it) and “y” for the second chunk (in order to discard it). After the process is finished, you can see that only the first, valuable chunk of changes survived — just like we wanted!
Resetting a Specific File to a Previous State
Sometimes you’ll want to restore a specific file to specific revision. For example, you know that index.html was working fine at some earlier point in time, but now it’s not. That’s when you want to turn back time, but only for this specific file and not for the whole project!
The first thing we have to find out is which exact revision we want to restore. With the right set of parameters, you can get the git log command to show you the history of just our single file:
$ git log — index.html
This shows us only the commits where index.html has been changed, which is pretty helpful to find the “bad apple” revision that broke things.
If you need more information and want to look at the contents of those commits, you could have Git show you the actual changes in these commits with the -p flag:
$ git log -p — index.html
Once we’ve found the bad commit where we broke our lovely little file, we can go on and fix the mistake. We’ll do that by restoring the file at the revision before the bad one! This is important: we don’t want to restore the file at the commit which introduced the error, but at the last good state — one commit before that!
$ git checkout <bad-commit-hash>~1 — index.html
Appending ~1 to the bad commit’s hash will instruct Git to do exactly that: go one revision before the referenced one.
After executing that command, you’ll find index.html to be modified in your local working copy: Git restored that last good revision of the file for us!