mercurial/commands.py
changeset 7227 e1afb50ec2aa
parent 7213 b4c035057d34
child 7228 9b72c732ed2f
equal deleted inserted replaced
7226:b71a52f101dc 7227:e1afb50ec2aa
   258             ui.status(_('the backout changeset is a new head - '
   258             ui.status(_('the backout changeset is a new head - '
   259                         'do not forget to merge\n'))
   259                         'do not forget to merge\n'))
   260             ui.status(_('(use "backout --merge" '
   260             ui.status(_('(use "backout --merge" '
   261                         'if you want to auto-merge)\n'))
   261                         'if you want to auto-merge)\n'))
   262 
   262 
   263 def bisect(ui, repo, rev=None, extra=None,
   263 def bisect(ui, repo, rev=None, extra=None, command=None,
   264                reset=None, good=None, bad=None, skip=None, noupdate=None):
   264                reset=None, good=None, bad=None, skip=None, noupdate=None):
   265     """subdivision search of changesets
   265     """subdivision search of changesets
   266 
   266 
   267     This command helps to find changesets which introduce problems.
   267     This command helps to find changesets which introduce problems.
   268     To use, mark the earliest changeset you know exhibits the problem
   268     To use, mark the earliest changeset you know exhibits the problem
   273     or good and bisect will either update to another candidate changeset
   273     or good and bisect will either update to another candidate changeset
   274     or announce that it has found the bad revision.
   274     or announce that it has found the bad revision.
   275 
   275 
   276     As a shortcut, you can also use the revision argument to mark a
   276     As a shortcut, you can also use the revision argument to mark a
   277     revision as good or bad without checking it out first.
   277     revision as good or bad without checking it out first.
   278     """
   278 
   279     # backward compatibility
   279     If you supply a command it will be used for automatic bisection. Its
   280     if rev in "good bad reset init".split():
   280     exit status will be used as flag to mark revision as bad or good (good
   281         ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
   281     in case of 0 and bad in any other case).
   282         cmd, rev, extra = rev, extra, None
   282     """
   283         if cmd == "good":
   283     def print_result(nodes, good):
   284             good = True
       
   285         elif cmd == "bad":
       
   286             bad = True
       
   287         else:
       
   288             reset = True
       
   289     elif extra or good + bad + skip + reset > 1:
       
   290         raise util.Abort(_('incompatible arguments'))
       
   291 
       
   292     if reset:
       
   293         p = repo.join("bisect.state")
       
   294         if os.path.exists(p):
       
   295             os.unlink(p)
       
   296         return
       
   297 
       
   298     # load state
       
   299     state = {'good': [], 'bad': [], 'skip': []}
       
   300     if os.path.exists(repo.join("bisect.state")):
       
   301         for l in repo.opener("bisect.state"):
       
   302             kind, node = l[:-1].split()
       
   303             node = repo.lookup(node)
       
   304             if kind not in state:
       
   305                 raise util.Abort(_("unknown bisect kind %s") % kind)
       
   306             state[kind].append(node)
       
   307 
       
   308     # update state
       
   309     node = repo.lookup(rev or '.')
       
   310     if good:
       
   311         state['good'].append(node)
       
   312     elif bad:
       
   313         state['bad'].append(node)
       
   314     elif skip:
       
   315         state['skip'].append(node)
       
   316 
       
   317     # save state
       
   318     f = repo.opener("bisect.state", "w", atomictemp=True)
       
   319     wlock = repo.wlock()
       
   320     try:
       
   321         for kind in state:
       
   322             for node in state[kind]:
       
   323                 f.write("%s %s\n" % (kind, hex(node)))
       
   324         f.rename()
       
   325     finally:
       
   326         del wlock
       
   327 
       
   328     if not state['good'] or not state['bad']:
       
   329         if (good or bad or skip or reset):
       
   330             return
       
   331         if not state['good']:
       
   332             raise util.Abort(_('cannot bisect (no known good revisions)'))
       
   333         else:
       
   334             raise util.Abort(_('cannot bisect (no known bad revisions)'))
       
   335 
       
   336     # actually bisect
       
   337     nodes, changesets, good = hbisect.bisect(repo.changelog, state)
       
   338     if changesets == 0:
       
   339         displayer = cmdutil.show_changeset(ui, repo, {})
   284         displayer = cmdutil.show_changeset(ui, repo, {})
   340         transition = (good and "good" or "bad")
   285         transition = (good and "good" or "bad")
   341         if len(nodes) == 1:
   286         if len(nodes) == 1:
   342             # narrowed it down to a single revision
   287             # narrowed it down to a single revision
   343             ui.write(_("The first %s revision is:\n") % transition)
   288             ui.write(_("The first %s revision is:\n") % transition)
   346             # multiple possible revisions
   291             # multiple possible revisions
   347             ui.write(_("Due to skipped revisions, the first "
   292             ui.write(_("Due to skipped revisions, the first "
   348                        "%s revision could be any of:\n") % transition)
   293                        "%s revision could be any of:\n") % transition)
   349             for n in nodes:
   294             for n in nodes:
   350                 displayer.show(changenode=n)
   295                 displayer.show(changenode=n)
       
   296 
       
   297     def check_state(state, interactive=True):
       
   298         if not state['good'] or not state['bad']:
       
   299             if (good or bad or skip or reset) and interactive:
       
   300                 return
       
   301             if not state['good']:
       
   302                 raise util.Abort(_('cannot bisect (no known good revisions)'))
       
   303             else:
       
   304                 raise util.Abort(_('cannot bisect (no known bad revisions)'))
       
   305         return True
       
   306 
       
   307     # backward compatibility
       
   308     if rev in "good bad reset init".split():
       
   309         ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
       
   310         cmd, rev, extra = rev, extra, None
       
   311         if cmd == "good":
       
   312             good = True
       
   313         elif cmd == "bad":
       
   314             bad = True
       
   315         else:
       
   316             reset = True
       
   317     elif extra or good + bad + skip + reset + bool(command) > 1:
       
   318         raise util.Abort(_('incompatible arguments'))
       
   319 
       
   320     if reset:
       
   321         p = repo.join("bisect.state")
       
   322         if os.path.exists(p):
       
   323             os.unlink(p)
       
   324         return
       
   325 
       
   326     state = hbisect.load_state(repo)
       
   327 
       
   328     if command:
       
   329         changesets = 1
       
   330         while changesets:
       
   331             # check state
       
   332             status = bool(list(os.popen3(command)[2]))
       
   333             node = repo.lookup(rev or '.')
       
   334             transition = (status and 'bad' or 'good')
       
   335             state[transition].append(node)
       
   336             ui.note(_('Changeset %s: %s\n') % (short(node), transition))
       
   337             check_state(state, interactive=False)
       
   338             # bisect
       
   339             nodes, changesets, good = hbisect.bisect(repo.changelog, state)
       
   340             # update to next check
       
   341             cmdutil.bail_if_changed(repo)
       
   342             hg.clean(repo, nodes[0], show_stats=False)
       
   343         hbisect.save_state(repo, state)
       
   344         return print_result(nodes, not status)
       
   345 
       
   346     # update state
       
   347     node = repo.lookup(rev or '.')
       
   348     if good:
       
   349         state['good'].append(node)
       
   350     elif bad:
       
   351         state['bad'].append(node)
       
   352     elif skip:
       
   353         state['skip'].append(node)
       
   354 
       
   355     hbisect.save_state(repo, state)
       
   356 
       
   357     if not check_state(state):
       
   358         return
       
   359 
       
   360     # actually bisect
       
   361     nodes, changesets, good = hbisect.bisect(repo.changelog, state)
       
   362     if changesets == 0:
       
   363         print_result(nodes, good)
   351     else:
   364     else:
   352         assert len(nodes) == 1 # only a single node can be tested next
   365         assert len(nodes) == 1 # only a single node can be tested next
   353         node = nodes[0]
   366         node = nodes[0]
   354         # compute the approximate number of remaining tests
   367         # compute the approximate number of remaining tests
   355         tests, size = 0, 2
   368         tests, size = 0, 2
  3006         (bisect,
  3019         (bisect,
  3007          [('r', 'reset', False, _('reset bisect state')),
  3020          [('r', 'reset', False, _('reset bisect state')),
  3008           ('g', 'good', False, _('mark changeset good')),
  3021           ('g', 'good', False, _('mark changeset good')),
  3009           ('b', 'bad', False, _('mark changeset bad')),
  3022           ('b', 'bad', False, _('mark changeset bad')),
  3010           ('s', 'skip', False, _('skip testing changeset')),
  3023           ('s', 'skip', False, _('skip testing changeset')),
       
  3024           ('c', 'command', '', _('Use command to check changeset state')),
  3011           ('U', 'noupdate', False, _('do not update to target'))],
  3025           ('U', 'noupdate', False, _('do not update to target'))],
  3012          _("hg bisect [-gbsr] [REV]")),
  3026          _("hg bisect [-gbsr] [REV] [-c COMMAND]")),
  3013     "branch":
  3027     "branch":
  3014         (branch,
  3028         (branch,
  3015          [('f', 'force', None,
  3029          [('f', 'force', None,
  3016            _('set branch name even if it shadows an existing branch')),
  3030            _('set branch name even if it shadows an existing branch')),
  3017           ('C', 'clean', None, _('reset branch name to parent branch name'))],
  3031           ('C', 'clean', None, _('reset branch name to parent branch name'))],