# HG changeset patch # User Matt Mackall # Date 2008-01-01 00:20:34 # Node ID 35ec669cdd43e807a5420e2d0f6f04620c005789 # Parent 2dd202a6e15bb45d8d3f10acde440bdb3d12e3b0 bisect: handle search for bad to good transitions Automatically detect whether we're looking for a bad to good transition rather than the usual good to bad transition by detecting when badrev is inside the good set and flipping good/bad. diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -258,11 +258,6 @@ def bisect(ui, repo, rev=None, extra=Non working directory as bad or good and bisect will either update to another candidate changeset or announce that it has found the bad revision. - - Note: bisect expects bad revisions to be descendants of good - revisions. If you are looking for the point at which a problem was - fixed, then make the problem-free state \"bad\" and the - problematic state \"good.\" """ # backward compatibility if rev in "good bad reset init".split(): @@ -317,9 +312,9 @@ def bisect(ui, repo, rev=None, extra=Non return # actually bisect - node, changesets = hbisect.bisect(repo.changelog, state) + node, changesets, good = hbisect.bisect(repo.changelog, state) if changesets == 0: - ui.write(_("The first bad revision is:\n")) + ui.write(_("The first %s revision is:\n") % (good and "good" or "bad")) displayer = cmdutil.show_changeset(ui, repo, {}) displayer.show(changenode=node) elif node is not None: diff --git a/mercurial/hbisect.py b/mercurial/hbisect.py --- a/mercurial/hbisect.py +++ b/mercurial/hbisect.py @@ -12,25 +12,36 @@ import hg, util def bisect(changelog, state): clparents = changelog.parentrevs - # only the earliest bad revision matters - badrev = min([changelog.rev(n) for n in state['bad']]) - bad = changelog.node(badrev) skip = dict.fromkeys([changelog.rev(n) for n in state['skip']]) - # build ancestors array - ancestors = [[]] * (changelog.count() + 1) # an extra for [-1] + def buildancestors(bad, good): + # only the earliest bad revision matters + badrev = min([changelog.rev(n) for n in bad]) + goodrevs = [changelog.rev(n) for n in good] + # build ancestors array + ancestors = [[]] * (changelog.count() + 1) # an extra for [-1] - # clear good revs from array - for node in state['good']: - ancestors[changelog.rev(node)] = None - for rev in xrange(changelog.count(), -1, -1): - if ancestors[rev] is None: - for prev in clparents(rev): - ancestors[prev] = None + # clear good revs from array + for node in goodrevs: + ancestors[node] = None + for rev in xrange(changelog.count(), -1, -1): + if ancestors[rev] is None: + for prev in clparents(rev): + ancestors[prev] = None - if ancestors[badrev] is None: + if ancestors[badrev] is None: + return None, None + return badrev, ancestors + + good = 0 + badrev, ancestors = buildancestors(state['bad'], state['good']) + if not ancestors: # looking for bad to good transition? + good = 1 + badrev, ancestors = buildancestors(state['good'], state['bad']) + if not ancestors: # now we're confused raise util.Abort(_("Inconsistent state, %s:%s is good and bad") % (badrev, hg.short(bad))) + bad = changelog.node(badrev) # build children dict children = {} @@ -52,7 +63,7 @@ def bisect(changelog, state): # have we narrowed it down to one entry? tot = len(candidates) if tot == 1: - return (bad, 0) + return (bad, 0, good) perfect = tot / 2 # find the best node to test @@ -91,4 +102,4 @@ def bisect(changelog, state): assert best_rev is not None best_node = changelog.node(best_rev) - return (best_node, tot) + return (best_node, tot, good) diff --git a/tests/test-bisect b/tests/test-bisect --- a/tests/test-bisect +++ b/tests/test-bisect @@ -31,3 +31,13 @@ hg bisect -g hg bisect -g hg bisect -b hg bisect -g + +echo % bisect reverse test +hg bisect -r +hg bisect -b null +hg bisect -g tip +hg bisect -g +hg bisect -g +hg bisect -g +hg bisect -b +hg bisect -g diff --git a/tests/test-bisect.out b/tests/test-bisect.out --- a/tests/test-bisect.out +++ b/tests/test-bisect.out @@ -214,3 +214,20 @@ user: test date: Thu Jan 01 00:00:29 1970 +0000 summary: msg 29 +% bisect reverse test +Testing changeset 15:e7fa0811edb0 (32 changesets remaining, ~5 tests) +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +Testing changeset 7:03750880c6b5 (16 changesets remaining, ~4 tests) +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +Testing changeset 3:b53bea5e2fcb (8 changesets remaining, ~3 tests) +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +Testing changeset 1:5cd978ea5149 (4 changesets remaining, ~2 tests) +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +Testing changeset 2:db07c04beaca (2 changesets remaining, ~1 tests) +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +The first good revision is: +changeset: 2:db07c04beaca +user: test +date: Thu Jan 01 00:00:02 1970 +0000 +summary: msg 2 +