Blog

Ideas and insights from our team

3 Awesome Git commands to help you debug


Git is a great tool but since you only need to know a small subset of commands to use it, people end up not knowing a bunch of awesome features of it. Some of my favourites are blame, bisect and rebase. Hopefully you will find them useful. You can find the repository used for the examples over here.

Git blame

Git blame allows you to look what commit and who was responsible for each line of code in each file of your project.

Let's say you found something odd in your project and want to find out who wrote that piece of code and why. With git blame you can. Just try:

git blame universe.py

You should see something similar to this:

c1de104f (André Ericson 2015-07-04 11:38:32 -0300 1) 
979a1d43 (André Ericson 2015-07-15 01:46:48 -0300 2) ANSWER_OF_LIFE = 0x2a
8cff2007 (André Ericson 2015-07-14 23:40:08 -0300 3) 
8cff2007 (André Ericson 2015-07-14 23:40:08 -0300 4) THOMAS_WAYNE_IS_DEAD = False
8cff2007 (André Ericson 2015-07-14 23:40:08 -0300 5) MARTHA_WAYNE_IS_DEAD = False
8cff2007 (André Ericson 2015-07-14 23:40:08 -0300 6) 
8cff2007 (André Ericson 2015-07-14 23:40:08 -0300 7) BRUCE_WAYNE_IS_A_HAPPY_CHILD = (not THOMAS_WAYNE_IS_DEAD and
8cff2007 (André Ericson 2015-07-14 23:40:08 -0300 8) not MARTHA_WAYNE_IS_DEAD)
8cff2007 (André Ericson 2015-07-14 23:40:08 -0300 9) BATMAN_EXISTS = not BRUCE_WAYNE_IS_A_HAPPY_CHILD

You can now copy the commit hash from the first column of the line you want and see the commit with:

git show 8cff2007

Now, say you want to see the blame for the file before that commit, you can do it with:

git blame universe.py 8cff2007~1

Hopefully you will only use this for good and not to start fights.

Git bisect

I can not quantify how much time this guy has saved me. Git bisect helps you to find which commit was responsible for introducing a bug by doing a binary search.

To use bisect, we need to find a commit where the bug was not present and a commit where the bug is present. With both information git bisect will do a binary search and help you to find in which commit the bug was first introduced.

First we must start a bisect section:

git bisect start

Now we need to tell bisect a good commit (when the bug was not present) and a bad commit. In our example HEAD~1 (this means 1 commit before the top) is known to have the bug.

git bisect bad HEAD~1

and for the good commit, we know for sure c1de104 is good:

git bisect good c1de104

After that, git will change to a point in between the two commits and you can test to see if the bug is present or not. You can tell git your findings with:

git bisect good

or

git bisect bad

Now git will change to another point in between the two commits and you can keep repeating until you find the culprit. But that is a pretty boring task. Git bisect can also let you use a script to test it for you. That means you can just write a test that test if the bug is present or not.

To use this feature just start the bisect and define a good and a bad commit with git bisect good [<rev>] or git bisect bad [<rev>] and then tell bisect how to test. For that we are using pytest:

git bisect run py.test

Now git will work it's magic and give you the culprit commit like this:

818d652b83dd039667251c4d94ec83eda57c0076 is the first bad commit
commit 818d652b83dd039667251c4d94ec83eda57c0076
Author: André Ericson <de.ericson@gmail.com>
Date: Wed Jul 15 01:45:00 2015 -0300

     Hehehehe >:)

:100644 100644 ac62afc4586071380f04c0a79477384e756438b8 0512e59b33bb80a611c9a51b3d5d4ccf231de065 M universe.py
bisect run success

Take a look at the commit with git show and don't forget to run git bisect reset when you are done.

Git rebase

Rebase lets you change or update the base of your branch. This is useful when let's say master gets updated and you want to incorporate changes to your branch. Just do: git rebase master from your branch.

One note about rebase, it will change the history. The golden rule is, never use rebase if your branch is public and there is other people working on/from it.

I will not go into details over rebase because this is covered in this great tutorial Merging vs Rebase.

One feature that I believe deserves a mention here is changing the base of branches.

Let's go over a use case for it. Imagine you are working on a feature and one co-worker is working on another feature. You both branched from master. What if you want to test your feature with your co-worker features?

The best way to do it is by changing the base of your branch.

Suppose your branch is take-over-the-world and your friend's branch is kill-bruce-waynes-parents. To see if your plan will work with batman you can rebase your branch with:

# the 'master' here is the branch from wich take-over-the-world branched from
git rebase --onto kill-bruce-waynes-parents master take-over-the-world

Git will now replay the commits in take-over-the-world on top of kill-bruce-waynes-parents and at the end it will look just like you branched from it instead of from master. Now if we run the test we will see that we can't take over the world because your friend killed the Waynes (Thanks! /s).

~$ py.test tests/test_we_can_take_over_the_world.py

tests/test_we_can_take_over_the_world.py::test_if_we_can_take_over_the_world FAILED

Now to rebase back onto master:

git rebase --onto master kill-bruce-waynes-parents take-over-the-world

Hopefully this will help you saving some time. Let us know what you think and what other git features you use to help you debugging.

About André Ericson

Frontend and Backend developer, Python and modern JavaScript evangelist. CLI is my /home/.

Comments