Jeff Kreeftmeijer

The mighty reflog and the amazing bisect

2010-08-30

This week I want to take the time to tell you what Git’s reflog and bisect commands do and give you a use-case for both so you know when you can actually use them.

This might be old news for you, but I’ve come across people that use Git but never heard of both or are afraid to use them because they’re scary. In fact, they’re not scary. They have the ability to save your ass and make you find bugs faster. Isn’t that Awesome?

Awesome robot dinosaurs

The mighty reflog

You just did a git reset that put you a couple of commits back or you just rebased your whole repository into one commit (don’t do that) and you realize you didn’t really want that.

You probably knew you can reset commits, but did you know you can do that — and more — on a lot of actions (like merges, pulls and rebases) as well? Simply use git reflog to get an overview of the last actions you did:

$ git reflog
0db8285 HEAD@{0}: HEAD~5: updating HEAD
177762a HEAD@{1}: commit: change affiliate field names
bb5d920 HEAD@{2}: pull origin develop: Merge made by recursive.
f6fade5 HEAD@{3}: commit: sort the category brands by name on ...
9309873 HEAD@{4}: checkout: moving from feature/affiliate to develop
92a80c2 HEAD@{5}: checkout: moving from develop to feature/affiliate

Because every action in this list has a SHA1 hash, you can use the commands you’re familiar with. In our example, we want to reset to before we messed up:

$ git reset 177762a

Now you moved back to right before you decided to reset or rebase. It’s like nothing ever happened.

The amazing bisect

Something broke and you found out it worked six commits ago (in the release tagged “v0.1.24”) by doing a quick git checkout v0.1.24 and running your tests. However, you don’t know which commit introduced the bug, but you want to find out what changed, who did it and if you can revert it quickly.

A really quick way to do something like this is to use git bisect. After starting, you have to specify a “good” commit and a “bad” one. In this case you know the commit tagged “v0.1.24” worked and the “develop” branch is broken:

$ git bisect start
$ git bisect good v0.1.24
$ git bisect bad develop
Bisecting: 2 revisions left to test after this (roughly 1 step)
[5dec197fedabd9db02cc1621f5bbdb2e8defeb48] Merge branch hotfix/...

What happened? Well, you switched off your development branch and git bisect took you back three commits so you’re at the one in the middle between the “good” and the “bad” one.

Next, run your tests and see if the bug was in this commit already. Let’s say it was, so you mark this commit “bad” as well:

$ git bisect bad
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[9dea486b10f14475beb56e9d67c6dd45c8fab088] sort the category ...

You’re taken to the next commit to test and you find out it worked in this one, so you mark it “good” and Git will tell you the commit that broke stuff:

$ git bisect good
154f34cd41619eaace63122480c8aa7180f7dbe6 is the first bad commit
commit 154f34cd41619eaace63122480c8aa7180f7dbe6
Author: Thijs Cadier
Date:   Sat Aug 28 19:20:40 2010 +0200

    An editor can publish a photo

Now we know which commit introduced the bug, so you can use git show to see what changed and fix it — or maybe even use git revert — right away. Did you do this manually before? I did and I can tell you bisecting is a lot faster.

Want more?

These are all use-cases that I’ve run into, but the commands I talked about have a lot more cool features you might want to check out. Two good places to start would be Git Ready by @qrush and the Git Community Book, since they explain stuff like reflogging and bisecting more thoroughly.