##// END OF EJS Templates
# User Dan Villiom Podlaski Christiansen <danchr@gmail.com>...
# User Dan Villiom Podlaski Christiansen <danchr@gmail.com> # Date 1289564504 -3600 # Node ID b75264c15cc888cf38c3c7b8f619801e3c2589c7 # Parent 89b2e5d940f669e590096c6be70eee61c9172fff revsets: overload the branch() revset to also take a branch name. This should only change semantics in the specific case of a tag/branch conflict where the tag wasn't done on the branch with the same name. Previously, branch(whatever) would resolve to the branch of the tag in that case, whereas now it will resolve to the branch of the name. The previous behaviour, while documented, seemed very counter-intuitive to me. An alternate approach would be to introduce a new revset such as branchname() or namedbranch(). While this would retain backwards compatibility, the distinction between it and branch() would not be readily apparent to users. The most intuitive behaviour would be to have branch(x) require 'x' to be a branch name, and something like branchof(x) or samebranch(x) do what branch(x) currently does. Unfortunately, our backwards compatibility guarantees prevent us from doing that. Please note that while 'hg tag' guards against shadowing a branch, 'hg branch' does not. Besides, even if it did, that wouldn't solve the issue of conversions with such tags and branches...

File last commit:

r12067:a4fbbe0f stable
r13750:7eb82f88 default
Show More
hbisect.py
155 lines | 5.0 KiB | text/x-python | PythonLexer
Matt Mackall
bisect: make bisect a built-in command
r5775 # changelog bisection for mercurial
#
# Copyright 2007 Matt Mackall
# Copyright 2005, 2006 Benoit Boissinot <benoit.boissinot@ens-lyon.org>
Martin Geisler
add blank line after copyright notices and after header
r8228 #
Matt Mackall
bisect: make bisect a built-in command
r5775 # Inspired by git bisect, extension skeleton taken from mq.py.
#
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Matt Mackall
bisect: make bisect a built-in command
r5775
Alexander Solovyov
bisect: ability to check revision with command
r7227 import os
Matt Mackall
bisect: make bisect a built-in command
r5775 from i18n import _
Alexander Solovyov
bisect: ability to check revision with command
r7227 from node import short, hex
Joel Rosdahl
Avoid importing mercurial.node/mercurial.repo stuff from mercurial.hg
r6217 import util
Matt Mackall
bisect: make bisect a built-in command
r5775
def bisect(changelog, state):
Bernhard Leiner
Add support for multiple possible bisect results (issue1228, issue1182)...
r6858 """find the next node (if any) for testing during a bisect search.
returns a (nodes, number, good) tuple.
'nodes' is the final result of the bisect if 'number' is 0.
Otherwise 'number' indicates the remaining possible candidates for
the search and 'nodes' contains the next bisect target.
'good' is True if bisect is searching for a first good changeset, False
if searching for a first bad one.
"""
Matt Mackall
bisect: make bisect a built-in command
r5775 clparents = changelog.parentrevs
Martin Geisler
replace set-like dictionaries with real sets...
r8152 skip = set([changelog.rev(n) for n in state['skip']])
Matt Mackall
bisect: make bisect a built-in command
r5775
Matt Mackall
bisect: handle search for bad to good transitions...
r5776 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]
Matt Mackall
bisect: limit considered set to descendants of first good rev
r9583 goodrev = min(goodrevs)
# build visit array
ancestors = [None] * (len(changelog) + 1) # an extra for [-1]
# set nodes descended from goodrev
ancestors[goodrev] = []
for rev in xrange(goodrev + 1, len(changelog)):
for prev in clparents(rev):
if ancestors[prev] == []:
ancestors[rev] = []
Matt Mackall
bisect: make bisect a built-in command
r5775
Matt Mackall
bisect: handle search for bad to good transitions...
r5776 # clear good revs from array
for node in goodrevs:
ancestors[node] = None
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 for rev in xrange(len(changelog), -1, -1):
Matt Mackall
bisect: handle search for bad to good transitions...
r5776 if ancestors[rev] is None:
for prev in clparents(rev):
ancestors[prev] = None
Matt Mackall
bisect: make bisect a built-in command
r5775
Matt Mackall
bisect: handle search for bad to good transitions...
r5776 if ancestors[badrev] is None:
Matt Mackall
bisect: improve tests...
r5777 return badrev, None
Matt Mackall
bisect: handle search for bad to good transitions...
r5776 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'])
Matt Mackall
bisect: improve tests...
r5777 bad = changelog.node(badrev)
Matt Mackall
bisect: handle search for bad to good transitions...
r5776 if not ancestors: # now we're confused
Matt Mackall
bisect: better message for unrelated starting revisions
r12005 if len(state['bad']) == 1 and len(state['good']) == 1:
raise util.Abort(_("starting revisions are not directly related"))
Martin Geisler
Lowercase error messages
r12067 raise util.Abort(_("inconsistent state, %s:%s is good and bad")
Joel Rosdahl
Avoid importing mercurial.node/mercurial.repo stuff from mercurial.hg
r6217 % (badrev, short(bad)))
Matt Mackall
bisect: make bisect a built-in command
r5775
# build children dict
children = {}
visit = [badrev]
candidates = []
while visit:
rev = visit.pop(0)
if ancestors[rev] == []:
candidates.append(rev)
for prev in clparents(rev):
if prev != -1:
if prev in children:
children[prev].append(rev)
else:
children[prev] = [rev]
visit.append(prev)
candidates.sort()
# have we narrowed it down to one entry?
Bernhard Leiner
Add support for multiple possible bisect results (issue1228, issue1182)...
r6858 # or have all other possible candidates besides 'bad' have been skipped?
Matt Mackall
bisect: make bisect a built-in command
r5775 tot = len(candidates)
Bernhard Leiner
Add support for multiple possible bisect results (issue1228, issue1182)...
r6858 unskipped = [c for c in candidates if (c not in skip) and (c != badrev)]
if tot == 1 or not unskipped:
return ([changelog.node(rev) for rev in candidates], 0, good)
Benoit Boissinot
bisect: use integer division
r7902 perfect = tot // 2
Matt Mackall
bisect: make bisect a built-in command
r5775
# find the best node to test
best_rev = None
best_len = -1
Benoit Boissinot
bisect: use set instead of dict
r8463 poison = set()
Matt Mackall
bisect: make bisect a built-in command
r5775 for rev in candidates:
if rev in poison:
Martin Geisler
hbisect: use set.update for bulk updates
r8482 # poison children
poison.update(children.get(rev, []))
Matt Mackall
bisect: make bisect a built-in command
r5775 continue
a = ancestors[rev] or [rev]
ancestors[rev] = None
x = len(a) # number of ancestors
y = tot - x # number of non-ancestors
value = min(x, y) # how good is this test?
if value > best_len and rev not in skip:
best_len = value
best_rev = rev
if value == perfect: # found a perfect candidate? quit early
break
Bernhard Leiner
Circumvent removal of valid bisect candidates due to previously skipped ones...
r7557 if y < perfect and rev not in skip: # all downhill from here?
Martin Geisler
hbisect: use set.update for bulk updates
r8482 # poison children
poison.update(children.get(rev, []))
Matt Mackall
bisect: make bisect a built-in command
r5775 continue
for c in children.get(rev, []):
if ancestors[c]:
Martin Geisler
replace set-like dictionaries with real sets...
r8152 ancestors[c] = list(set(ancestors[c] + a))
Matt Mackall
bisect: make bisect a built-in command
r5775 else:
ancestors[c] = a + [c]
assert best_rev is not None
best_node = changelog.node(best_rev)
Bernhard Leiner
Add support for multiple possible bisect results (issue1228, issue1182)...
r6858 return ([best_node], tot, good)
Alexander Solovyov
bisect: ability to check revision with command
r7227
def load_state(repo):
state = {'good': [], 'bad': [], 'skip': []}
if os.path.exists(repo.join("bisect.state")):
for l in repo.opener("bisect.state"):
kind, node = l[:-1].split()
node = repo.lookup(node)
if kind not in state:
raise util.Abort(_("unknown bisect kind %s") % kind)
state[kind].append(node)
return state
def save_state(repo, state):
f = repo.opener("bisect.state", "w", atomictemp=True)
wlock = repo.wlock()
try:
for kind in state:
for node in state[kind]:
f.write("%s %s\n" % (kind, hex(node)))
f.rename()
finally:
Ronny Pfannschmidt
switch lock releasing in the core from gc to explicit
r8109 wlock.release()
Alexander Solovyov
bisect: ability to check revision with command
r7227