SaltyCrane Blog — Notes on JavaScript and web development

Example using git bisect to narrow in on a commit

I learned about git bisect from this Stack Overflow poll: What are your favorite git features or tricks? I thought it was so cool that I wanted to share an example.

After upgrading from Django 1.2.3 to Django 1.3, something broke on the website I was working on. To figure out what was wrong, I used git bisect to find the Django revision that introduced the relevant change. I cloned the Django github repo and pip install -e'd it into my virtualenv. Then I used git bisect as follows:

  • Start git bisect
    $ git bisect start 
    
    $ git bisect bad 1.3 
    
    $ git bisect good 1.2.3 
    Bisecting: a merge base must be tested
      [618153bd3b047529f6cfb50917c88270f30e8ea8] Fixed #10843: the textile tests now pass against the latest textile library.
    

    Note: 1.3 and 1.2.3 are git tags in the Django git repo. Commit SHA1 hashes can be used instead.

  • Start the development server in another terminal. Load the webpage in the browser. The page loads without error.
    [04/Aug/2011 19:13:20] "GET /my/webpage/ HTTP/1.1" 200 16279
  • Mark the revision good
    $ git bisect good 
    Bisecting: 774 revisions left to test after this (roughly 10 steps)
    [39591cddccffdf3b66cfaaa60b95257daa4ef8c5] Fixed #14781 - Setting "CACHE_PREFIX" should be "CACHE_KEY_PREFIX". Thanks to adamv for report and patch.
    
  • Reload the page. This time it throws a 500 error.
    [04/Aug/2011 19:13:59] "GET /my/webpage/ HTTP/1.1" 500 118861
  • Mark the revision bad
    $ git bisect bad 
    Bisecting: 387 revisions left to test after this (roughly 9 steps)
    [6630bd24f45c7967c49b90adf82c63dd7d93e6f7] Fixed #13863 -- Corrected decimal separator in Swedish format module. Thanks, Ulf Urdén.
    
  • Reload
    [04/Aug/2011 19:15:45] "GET /my/webpage/ HTTP/1.1" 500 117536
  • Mark the revision bad
    $ git bisect bad 
    Bisecting: 193 revisions left to test after this (roughly 8 steps)
    [4d19282beb19b95e73aec119b40ed40456065a21] Migrated custom_methods doctests. Thanks to Alex Gaynor.
    
  • Etc...
    [04/Aug/2011 19:16:17] "GET /my/webpage/ HTTP/1.1" 500 117536
    $ git bisect bad 
    Bisecting: 96 revisions left to test after this (roughly 7 steps)
    [ed63689b9e3be80c3af51bfc5d6805bcedbae9f0] Added file missing from r13590.
    
    [04/Aug/2011 19:16:46] "GET /my/webpage/ HTTP/1.1" 200 16279
    $ git bisect good 
    Bisecting: 48 revisions left to test after this (roughly 6 steps)
    [2eca0cd7f5fe6efd1f177724a948cdde7475f54c] Fixed #13754 - Add a note about a test client session property gotcha
    
    [04/Aug/2011 19:17:12] "GET /my/webpage/ HTTP/1.1" 200 16279
    $ git bisect good 
    Bisecting: 24 revisions left to test after this (roughly 5 steps)
    [d7e3c7bad40e5f66169b8b951d74c87103ece07d] Fixed #13095 -- `formfield_callback` keyword argument is now more sane and works with widgets defined in `ModelForm.Meta.widgets`.  Thanks, hvdklauw for bug report, vung for initial patch, and carljm for review.
    
    [04/Aug/2011 19:17:31] "GET /my/webpage/ HTTP/1.1" 200 16279
    $ git bisect good 
    [I forgot to copy/paste the console output for this one]
    
    [04/Aug/2011 19:17:54] "GET /my/webpage/ HTTP/1.1" 500 117536
    $ git bisect bad 
    Bisecting: 5 revisions left to test after this (roughly 3 steps)
    [622bf3b2199e5e7015edccb00f1ab694291ca121] Fixed #11905: Raise an error on model form creation if a non-existent field was listed in fields. Thanks ben and copelco.
    
    [04/Aug/2011 19:18:17] "GET /my/webpage/ HTTP/1.1" 500 117536
    $ git bisect bad 
    Bisecting: 2 revisions left to test after this (roughly 2 steps)
    [57427e9d758eb37b43f6b7804b24c6f47c2fa456] Fixed a test so that it actually tests what it's supposed to test.
    
    [04/Aug/2011 19:18:37] "GET /my/webpage/ HTTP/1.1" 200 16279
    $ git bisect good 
    Bisecting: 0 revisions left to test after this (roughly 1 step)
    [dcb12158881cdcc619de0ae6d3f6cf674a0d4abb] Better error message for calling get_next_by_* on unsaved models. Patch from Marc Fargas. Fixed #7435.
    
    [04/Aug/2011 19:19:07] "GET /my/webpage/ HTTP/1.1" 200 16279
  • After marking the last commit, git bisect shows the first bad commit as 622bf3b2199e5e7015edccb00f1ab694291ca121
    $ git bisect good
    622bf3b2199e5e7015edccb00f1ab694291ca121 is the first bad commit
    commit 622bf3b2199e5e7015edccb00f1ab694291ca121
    Author: kmtracey <kmtracey>
    Date:   Sat Sep 11 01:39:16 2010 +0000
    
        Fixed #11905: Raise an error on model form creation if a non-existent field was listed in fields. Thanks ben and copelco.
        
        
        git-svn-id: http://code.djangoproject.com/svn/django/trunk@13739 bcc190cf-cafb-0310-a4f2-bffc1f526a37
    
    :040000 040000 87ec1601b970938b55382a5aa66db74716552c3d 2d418dfe8dd9f67fea408e022aa13838086ce33b M      django
    :040000 040000 054e6f42b3b467e47f295f8fda6cdc8a7f2c054c 52ba5265ba9d6458f23c8cb4a8a9bdcdbfc1f590 M      tests</kmtracey>
    

Note: checking for failed unit tests instead of checking for a 500 error in the browser is another (probably better) way to test with git bisect.

Note 2: The problem with my code was that I was adding extra fields to a model formset in the wrong way. I was trying to use add_fields on a base model formset instead of creating a custom Form with the extra field and specifying it in the factory. This Stack Overflow answer solved the problem for me.

Extra details

Here's how I installed Django from github

  • Clone the Django repo and pip install -e it in my virtualenv
    $ git clone https://github.com/django/django.git django-github 
    $ cd django-github 
    $ workon myenv 
    $ pip install -e ./ 
    
  • In another terminal run the Django development server
    $ cd /myproject 
    $ workon myenv 
    $ python manage.py runserver 
    

Comments


#1 Peter Hanley commented on :

I've been finding digging into the surface of git that I scratched somewhat difficult - but you laid bare a really specific and clear use case that I get immediately.

I think the problem I have is that I've mostly used git to update from a repo where I'm not a committer, so most of the tutorials, and use cases that are published don't really apply.

Thanks for this.