How could I use git bisect to find the first GOOD commit?
Asked Answered
S

5

113

I have the following problem:

  • the version at master works fine
  • the version of the last tag before master (say last) has a bug
  • a colleague needs a patch for his last revision for that certain bug

Okay. Let's ask our friend git bisect for the revision that fixed the bug:

git bisect start
git bisect bad last
git bisect good master

But that's not going to work:

Some good revs are not ancestor of the bad rev.
git bisect cannot work properly in this case.
Maybe you mistake good and bad revs?

Any hints to overcome this? Did I miss something in the docs?

Savarin answered 14/3, 2013 at 10:47 Comment(5)
I am running git bisect run ... to automate bisecting. So I have no chance just to swap the words good and bad (that was too obvious). How to use run to find the first good revision?Frieder
@DanielBöhmer: you have to swap terms inside your script being run, don't you?Savarin
The script run by git bisect run returns good or bad as exit code, not as a string. See my answer I just posted below.Frieder
@DanielBöhmer: well, in that case you'll have to invert the return code, don't you?Savarin
Correct, that's what is described in my answer.Frieder
P
127

As of git 2.7, you can use the arguments --term-old and --term-new.

For instance, you can identify a problem-fixing commit thus:

git bisect start --term-new=fixed --term-old=unfixed
git bisect fixed master
git bisect unfixed $some-old-sha1

As you test, say git bisect fixed or git bisect unfixed as appropriate.

Old answer, for versions of git prior to 2.7

Instead of temporarily training yourself to think that bad means good and good means bad, why not create some aliases?

In ~/.gitconfig add the following:

[alias]
        bisect-fixed = bisect bad
        bisect-unfixed = bisect good

You can start identifying a problem-fixing commit thus:

$ git bisect start
$ git bisect-fixed master
$ git bisect-unfixed $some-old-sha1

As you test, say git bisect-fixed or git bisect-unfixed as appropriate.

Puling answered 17/6, 2013 at 17:45 Comment(9)
As an aside, git doesn't let you make aliases of sub commands. Hence the dashes. If it actually is (or is made) possible, hopefully someone will update the answer.Puling
And on command line: git config --global alias.bisect-broken 'bisect good' and git config --global alias.bisect-fixed 'bisect bad'Baptlsta
Even if you use aliases, the output from git will not, so it will still report foo is the first bad commit, so it seems temporary training is still necessary, no?Mastoiditis
Fair point. (Upvoted your comment.) Although even so hopefully it's at least a little bit less additional cognitive load to deal with, and as programmers we already have plenty.Puling
Unfortunately, as of git 2.7 you can't reassign meanings to bad and good. Maybe in a future version.Puling
I recommend using aliases 'before' and 'after'. That way you don't have the cognitive overhead of doing the inversion "when I see the bug, I should write 'good'"; instead you only have the—likely smaller—overhead of remembering that you're looking for the appearance/disappearance of a bug (i.e. remembering what kind of change you're looking for—"before what?").Meingolda
@JonasKölker, that's a great idea. I used the suggested aliases in the answer, as well as bisect-after = bisect bad and bisect-before = bisect good, per your recommendation. Now I can use either set of aliases. We'll see which I end up favoring more after a few uses.Epiphenomenalism
Does this actually work? I've tried but it didn't do the trick because git bisect still assumes that a successful exit code means "move forward" and an unsuccessful exit code means "move backwards", which only works if old commit means successful and new commit means unsuccessful. I've only managed to make this work if combined with a script that reverts the exit codes of the build, like thisUrena
I have the same question as @quiram. How can I reverse also the logic of git bisect run without changing the command completely. The command can be a complex consisting of several && clauses and I would like to avoid making a mistake.Dukas
S
50

I would just "cheat" git and swap meanings of good <=> bad.

In other words, consider "bad" as something that does not exhibit the problem so this is not the "good" version to base your patch on.

Good and bad are pretty subjective concepts anyway, right? :)

git bisect start
git bisect good last
git bisect bad master
Sagittate answered 14/3, 2013 at 10:53 Comment(3)
Well, if you think about it there is no general meaning what good or bad is (probably not even in religion).. it just depends on your purposes. This way it's not really cheating - but maybe Git's Sin (to stay on the religious topic:D is to pick up such a contentious term rather than a more neutral "goal"/"origin".. But yes, philosophy can be mind-boggling ;-)Sagittate
This must be the very first time I hear that bugs can be "good".Matronage
That's what I did before I found this question. I'm not going to do it anymore. Remember, it only takes one wrong answer before the whole bisection goes awry. Don't twist your mind.Siphonophore
N
28

If you're using git bisect run like I have been doing with Perl's prove command (which runs automatic tests) you have no chance just to swap good and bad. The success of the tests will be reported as exit code.

I have found a valid Bash syntax to negate the exit code of the program run by git bisect run:

git bisect start
git bisect bad HEAD                 # last revision known to PASS the tests
git bisect good $LAST_FAIL_REVISION # last revision known to FAIL the tests
git bisect run bash -c "! prove"

This gave me the first revision to pass the tests run by prove.

Nina answered 22/3, 2016 at 14:54 Comment(3)
I agree, I'd rather not modify my test case so this is perfect.Maag
This also works well if you're looking to find the first commit containing a certain piece of text - just change the last line to git bisect run bash -c "! git grep 'some text to find' "Poteat
@Poteat I think that it’s much faster to query the log than checking out old revisions. git log -p -S 'some text to find' shows you all diffs that add/remove the text, so probably the commits you wanted.Frieder
T
11

Git now lets you use old and new without first defining them. You have to call git bisect start without commits as further arguments, then properly start the bisection by calling

git bisect old <rev>
git bisect new <rev>

https://git-scm.com/docs/git-bisect#_alternate_terms

This essentially is what @MarcH was suggesting should be implemented.

Trestlework answered 25/12, 2016 at 16:21 Comment(3)
This is the most relevant answer (for modern git). And the start command should be (according to link you shared): git bisect start --term-new fixed --term-old brokenMethedrine
True. When were these options introduced? I'd like to update my answer.Puling
@MichaelWolf They appeared in version 2.7.0.Trestlework
M
6

Git aliases are a good idea, however the terms fixed and unfixed have the same issue than good and bad: you cannot have them be compatible with both regressions and progressions. It's easy to find words which work either way: simply pick them up from the original binary search terminology which is neutral in nature with no preconception of what is good or bad. For instance:

git config --global alias.bisect-high 'bisect bad'
git config --global alias.bisect-low  'bisect good'

With neutral terms like these you can always type: git bisect-high (or git bisect-upper, or git-bisect max,... your choice!) whether you're looking for a regression or a fix.

Too bad the git bisect developers could not simply re-use any of the existing terms. The user interface is not git's concern generally speaking: http://stevebennett.me/2012/02/24/10-things-i-hate-about-git/

Matronage answered 19/2, 2015 at 0:7 Comment(1)
From: git.github.io/rev_news/2015/07/08/edition-5 "Some patch series are being polished to allow git bisect to use an arbitrary pair of terms instead of good and bad,..."Matronage

© 2022 - 2024 — McMap. All rights reserved.