Git has a nice feature called bisect
that’s immensely useful for finding out where and when something broke.
For this example, we’ll use small integers for commit ids because they’re easier to reason about and orderly. In reality, they’ll be long SHA hashes.
Let’s say you have a commit history like this:
commit 12
Author: Joe
commit 11
Author: Scott
commit 10
Author: Scott
commit 9
Author: Scott
commit 8
Author: Miles
commit 7
Author: Joe
commit 6
Author: Dave
commit 5
Author: Bob
commit 4
Author: Joe
commit 3
Author: Dave
Pretend you’re Dave (your last commit was commit 6) and you do a git pull
and an ‘install-dev’ and see that the site’s busted, CSS all over the place, whatever. Git bisect to the rescue. First, tell git you’re ready to have it help you find the problem:
$ git bisect start
Now, mark the current commit as “bad”:
$ git bisect bad
Note, this doesn’t do anything permanent. It just marks a commit temporarily as “bad” (it doesn’t change your repo or anything permanent). Now pick a commit that you know was good and mark it as such:
$ git bisect good 6
git
will find a commit halfway between the good and bad commit and check it out into your working directory. Now you can test this checkout (e.g., make test
). If it’s good, tell git about it:
$ git bisect good
if it’s bad:
$ git bisect bad
Either way, git
will then bisect (cut in half again) to find another commit halfway between this one and the previous one for you to mark. This repeats until there are no more commits to test. git
will say:
10 is the first bad commit
and show you the offending commit and what file or tree was changed:
10 is the first bad commit
commit 10
Author: Scott
Date: Fri Feb 1 10:16:54 2013 -0700
- add *.local to exclusion list
:040000 040000 82c44e7914e7be2f67fdc0f30387e1f66a677212 e0e88a84b7f247e801028b878b09e98e992c60d4 M lib
You can diff this, etc. to see what changed between this and the previous commit like this:
$ git diff HEAD~1
You don’t want to make any actual fixes yet. This tool is just for helping you find the problem. Now you should get back to the last commit of the branch where you were when you started the bisect. Always do this:
$ git bisect reset
which will put your working tree back to where it was after you pulled, but now you know what the problem is and whom to blame :)
If you’re fortunate enough to be working on a codebase with regression tests, you can leverage that and let git find the broken commit for you:
$ git bisect run make test
If the result of make test
returns non-zero, git understands that as a failure and marks that commit as bad until it finds the first offending commit—completely automatic.
Last modified on 2013-08-15