11

I have a bug that have been introduced a long time ago, and testing for it is painful. However, I strongly suspect that changes which introduced the bug happened in one particular source code file.

Can I run git bisect on a sub-set of commits that changed that one file?

Max Yankov
  • 10,076
  • 10
  • 54
  • 116

3 Answers3

24

Yes, you can. In the manpage, you find this line:

git bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]
      [--no-checkout] [<bad> [<good>...]] [--] [<paths>...]

so after --, you put the paths of the files or directories.

For example:

git bisect start -- arch/i386 include/asm-i386
Iulian Onofrei
  • 7,489
  • 8
  • 59
  • 96
silvio
  • 1,867
  • 16
  • 34
  • What is "arch"? – Eduard Jan 09 '19 at 13:02
  • 1
    'arch/i386', 'include/asm-i386' and, I guess, 'or' would be the paths that bisect is operating on. It doesn't really matter what they are -- silvio is just using them as examples. Presumably, based on context, 'arch' is the 'architecture' for a build, in this case, i386: https://en.wikipedia.org/wiki/Intel_80386 So in silvio's case, the bisect is being run because there would be some problem with the i386 builds that need to be found. – knickum Feb 19 '19 at 23:35
1

Git bisect allows you to avoid testing a commit (see "Avoiding testing a commit" in the man page): when you are bisecting, and git has chosen a commit for you to test, you can override its choice with git reset --hard <commit you want>.

Using git log, you can find the last commit that affected a file (or subdirectory) - this will return its hash:

git log -1 --pretty=format:%H -- path_that_you_are_interested_in

So, every time git bisect suggests you a commit to test, you should run this command to ensure that you only test the commits that affected somepath:

git reset --hard $(git log -1 --pretty=format:%H -- somepath)

Now, there is one more thing that we need to take care of. If there are no interesting commits (i.e. no commits that modify somepath) between last checked good commit and the commit currently chosen by git bisect, we may end up in a loop. To avoid this, we should use a conditional clause:

#!/bin/bash

last_good=$(git bisect log | tail -1 | sed 's/git bisect good //')
last_interesting=$(git log -1 --pretty=format:%H -- lily/)

if [ "$last_good" == "$last_interesting" ]; then
    # there are no commits modifying somepath between previously
    # tested and currently checked-out one, so it must be good
    git bisect good
else 
    git reset --hard $(git log -1 --pretty=format:%H -- somepath)
fi
Jan Warchoł
  • 933
  • 6
  • 21
  • Updated to avoid potentially infinite loop. – Jan Warchoł Sep 13 '13 at 13:46
  • Why not use `git bisect skip` if not marking commit that do not contain changes to suspected file as good? – Jakub Narębski Sep 13 '13 at 16:57
  • Wouldn't this be slower? With my solution, even if `bisect` chooses a commit that doesn't interest us, we jump to the nearest "interesting" commit right away. OTOH, if there are 10000 commits in total, but only 10 of them matter, using `skip` would mean visiting lots of "uninteresting" commits on our way. – Jan Warchoł Sep 13 '13 at 19:45
0

One technique is to create a temporary branch starting back at a known good location and simply copy across all [i.e. a script] the commits that touch that file, and then do a bisect on that temporay branch. That way you skip all the irrelevant commits.

This was discussed on the Git Mailing List within the last month or so $gmane/232114. The discussion did not identify an easy way to pre-skip commits that had no relevant changes (It's probably something that would be useful though - as they say, patches welcome)

Philip Oakley
  • 11,745
  • 8
  • 42
  • 63
  • But you usually cannot get a branch that contains *only commits changing some file* and at the same time *still works*. – Jan Warchoł Sep 13 '13 at 13:27
  • I was assuming that all of your mainline commits were 'good' at the time of the commit. Do you have an indicator of which commits were thought 'good' at the time of commit? Without that you have a real problem in scripting a revision walker that picks out those that were thought good for the bisect to work against. – Philip Oakley Sep 13 '13 at 15:50