commands.py 195 KB
Newer Older
mpm@selenic.com's avatar
mpm@selenic.com committed
1 2
# commands.py - command processing for mercurial
#
3
# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
mpm@selenic.com's avatar
mpm@selenic.com committed
4
#
5
# This software may be used and distributed according to the terms of the
Matt Mackall's avatar
Matt Mackall committed
6
# GNU General Public License version 2 or any later version.
mpm@selenic.com's avatar
mpm@selenic.com committed
7

8
from node import hex, bin, nullid, nullrev, short
9
from lock import release
10
from i18n import _, gettext
11
import os, re, difflib, time, tempfile, errno
12
import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
13
import patch, help, url, encoding, templatekw, discovery
14 15
import archival, changegroup, cmdutil, hbisect
import sshserver, hgweb, hgweb.server, commandserver
16
import merge as mergemod
17
import minirst, revset, fileset
18
import dagparser, context, simplemerge
19
import random, setdiscovery, treediscovery, dagutil
20

21 22 23 24 25 26 27 28 29 30 31 32 33
table = {}

command = cmdutil.command(table)

# common command options

globalopts = [
    ('R', 'repository', '',
     _('repository root directory or name of overlay bundle file'),
     _('REPO')),
    ('', 'cwd', '',
     _('change working directory'), _('DIR')),
    ('y', 'noninteractive', None,
34
     _('do not prompt, automatically pick the first choice for all prompts')),
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
    ('q', 'quiet', None, _('suppress output')),
    ('v', 'verbose', None, _('enable additional output')),
    ('', 'config', [],
     _('set/override config option (use \'section.name=value\')'),
     _('CONFIG')),
    ('', 'debug', None, _('enable debugging output')),
    ('', 'debugger', None, _('start debugger')),
    ('', 'encoding', encoding.encoding, _('set the charset encoding'),
     _('ENCODE')),
    ('', 'encodingmode', encoding.encodingmode,
     _('set the charset encoding mode'), _('MODE')),
    ('', 'traceback', None, _('always print a traceback on exception')),
    ('', 'time', None, _('time how long the command takes')),
    ('', 'profile', None, _('print command execution profile')),
    ('', 'version', None, _('output version information and exit')),
    ('h', 'help', None, _('display help and exit')),
]

dryrunopts = [('n', 'dry-run', None,
               _('do not perform actions, just print output'))]

remoteopts = [
    ('e', 'ssh', '',
     _('specify ssh command to use'), _('CMD')),
    ('', 'remotecmd', '',
     _('specify hg command to run on the remote side'), _('CMD')),
    ('', 'insecure', None,
     _('do not verify server certificate (ignoring web.cacerts config)')),
]

walkopts = [
    ('I', 'include', [],
     _('include names matching the given patterns'), _('PATTERN')),
    ('X', 'exclude', [],
     _('exclude names matching the given patterns'), _('PATTERN')),
]

commitopts = [
    ('m', 'message', '',
     _('use text as commit message'), _('TEXT')),
    ('l', 'logfile', '',
     _('read commit message from file'), _('FILE')),
]

commitopts2 = [
    ('d', 'date', '',
     _('record the specified date as commit date'), _('DATE')),
    ('u', 'user', '',
     _('record the specified user as committer'), _('USER')),
]

templateopts = [
    ('', 'style', '',
     _('display using template map file'), _('STYLE')),
    ('', 'template', '',
     _('display with template'), _('TEMPLATE')),
]

logopts = [
    ('p', 'patch', None, _('show patch')),
    ('g', 'git', None, _('use git extended diff format')),
    ('l', 'limit', '',
     _('limit number of changes displayed'), _('NUM')),
    ('M', 'no-merges', None, _('do not show merges')),
    ('', 'stat', None, _('output diffstat-style summary of changes')),
] + templateopts

diffopts = [
    ('a', 'text', None, _('treat all files as text')),
    ('g', 'git', None, _('use git extended diff format')),
    ('', 'nodates', None, _('omit dates from diff headers'))
]

diffopts2 = [
    ('p', 'show-function', None, _('show which function each change is in')),
    ('', 'reverse', None, _('produce a diff that undoes the changes')),
    ('w', 'ignore-all-space', None,
     _('ignore white space when comparing lines')),
    ('b', 'ignore-space-change', None,
     _('ignore changes in the amount of white space')),
    ('B', 'ignore-blank-lines', None,
     _('ignore changes whose lines are all blank')),
    ('U', 'unified', '',
     _('number of lines of context to show'), _('NUM')),
    ('', 'stat', None, _('output diffstat-style summary of changes')),
]

122 123 124 125
mergetoolopts = [
    ('t', 'tool', '', _('specify merge tool')),
]

126 127 128 129 130 131 132 133 134 135
similarityopts = [
    ('s', 'similarity', '',
     _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
]

subrepoopts = [
    ('S', 'subrepos', None,
     _('recurse into subrepositories'))
]

mpm@selenic.com's avatar
mpm@selenic.com committed
136
# Commands start here, listed alphabetically
137

138 139 140
@command('^add',
    walkopts + subrepoopts + dryrunopts,
    _('[OPTION]... [FILE]...'))
141
def add(ui, repo, *pats, **opts):
142 143
    """add the specified files on the next commit

144 145
    Schedule files to be version controlled and added to the
    repository.
146

147
    The files will be added to the repository at the next commit. To
148
    undo an add before that, see :hg:`forget`.
149

150
    If no names are given, add all files to the repository.
151 152 153 154

    .. container:: verbose

       An example showing how new (unknown) files are added
Martin Geisler's avatar
Martin Geisler committed
155
       automatically by :hg:`add`::
156 157 158 159 160 161 162 163

         $ ls
         foo.c
         $ hg status
         ? foo.c
         $ hg add
         adding foo.c
         $ hg status
164
         A foo.c
165 166

    Returns 0 if all files are successfully added.
167 168
    """

169
    m = scmutil.match(repo[None], pats, opts)
170 171
    rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
                           opts.get('subrepos'), prefix="")
172
    return rejected and 1 or 0
173

174 175 176
@command('addremove',
    similarityopts + walkopts + dryrunopts,
    _('[OPTION]... [FILE]...'))
177
def addremove(ui, repo, *pats, **opts):
178
    """add all new files, delete all missing files
179

180 181
    Add all new files and remove all missing files from the
    repository.
182

183
    New files are ignored if they match any of the patterns in
184
    ``.hgignore``. As with add, these changes take effect at the next
185
    commit.
186

187 188 189 190 191
    Use the -s/--similarity option to detect renamed files. With a
    parameter greater than 0, this compares every removed file with
    every added file and records those similar enough as renames. This
    option takes a percentage between 0 (disabled) and 100 (files must
    be identical) as its parameter. Detecting renamed files this way
192 193
    can be expensive. After using this option, :hg:`status -C` can be
    used to check which files were identified as moved or renamed.
194 195

    Returns 0 if all files are successfully added.
196
    """
197
    try:
198
        sim = float(opts.get('similarity') or 100)
199 200
    except ValueError:
        raise util.Abort(_('similarity must be a number'))
201 202
    if sim < 0 or sim > 100:
        raise util.Abort(_('similarity must be between 0 and 100'))
203
    return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
204

205 206 207 208 209 210 211 212 213 214 215 216 217 218
@command('^annotate|blame',
    [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
    ('', 'follow', None,
     _('follow copies/renames and list the filename (DEPRECATED)')),
    ('', 'no-follow', None, _("don't follow copies and renames")),
    ('a', 'text', None, _('treat all files as text')),
    ('u', 'user', None, _('list the author (long with -v)')),
    ('f', 'file', None, _('list the filename')),
    ('d', 'date', None, _('list the date (short with -q)')),
    ('n', 'number', None, _('list the revision number (default)')),
    ('c', 'changeset', None, _('list the changeset')),
    ('l', 'line-number', None, _('show line number at the first appearance'))
    ] + walkopts,
    _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
219
def annotate(ui, repo, *pats, **opts):
220
    """show changeset information by line for each file
221

222 223
    List changes in files, showing the revision id responsible for
    each line
224

225 226
    This command is useful for discovering when a change was made and
    by whom.
227

228 229 230 231
    Without the -a/--text option, annotate will avoid processing files
    it detects as binary. With -a, annotate will annotate the file
    anyway, although the results will probably be neither useful
    nor desirable.
232 233

    Returns 0 on success.
234
    """
235 236 237
    if opts.get('follow'):
        # --follow is deprecated and now just an alias for -f/--file
        # to mimic the behavior of Mercurial before version 1.5
238
        opts['file'] = True
239

240 241
    datefunc = ui.quiet and util.shortdate or util.datestr
    getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
242

243
    if not pats:
244
        raise util.Abort(_('at least one filename or pattern is required'))
245

246 247 248 249 250 251
    opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
             ('number', ' ', lambda x: str(x[0].rev())),
             ('changeset', ' ', lambda x: short(x[0].node())),
             ('date', ' ', getdate),
             ('file', ' ', lambda x: x[0].path()),
             ('line_number', ':', lambda x: str(x[1])),
252 253
            ]

254
    if (not opts.get('user') and not opts.get('changeset')
255
        and not opts.get('date') and not opts.get('file')):
256
        opts['number'] = True
257

258
    linenumber = opts.get('line_number') is not None
259
    if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
260 261
        raise util.Abort(_('at least one of -n/-c is required for -l'))

262 263
    funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
    funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
264

265 266 267
    def bad(x, y):
        raise util.Abort("%s: %s" % (x, y))

268
    ctx = scmutil.revsingle(repo, opts.get('rev'))
269
    m = scmutil.match(ctx, pats, opts)
270
    m.bad = bad
271
    follow = not opts.get('no_follow')
Matt Mackall's avatar
Matt Mackall committed
272 273
    for abs in ctx.walk(m):
        fctx = ctx[abs]
274
        if not opts.get('text') and util.binary(fctx.data()):
275
            ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
276 277
            continue

278
        lines = fctx.annotate(follow=follow, linenumber=linenumber)
279 280
        pieces = []

281
        for f, sep in funcmap:
282 283
            l = [f(n) for n, dummy in lines]
            if l:
284 285
                sized = [(x, encoding.colwidth(x)) for x in l]
                ml = max([w for x, w in sized])
286 287
                pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
                               for x, w in sized])
288

mpm@selenic.com's avatar
mpm@selenic.com committed
289 290
        if pieces:
            for p, l in zip(zip(*pieces), lines):
291
                ui.write("%s: %s" % ("".join(p), l[1]))
292

293 294 295 296 297 298 299 300
@command('archive',
    [('', 'no-decode', None, _('do not pass files through decoders')),
    ('p', 'prefix', '', _('directory prefix for files in archive'),
     _('PREFIX')),
    ('r', 'rev', '', _('revision to distribute'), _('REV')),
    ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
    ] + subrepoopts + walkopts,
    _('[OPTION]... DEST'))
301
def archive(ui, repo, dest, **opts):
302
    '''create an unversioned archive of a repository revision
303

304 305
    By default, the revision used is the parent of the working
    directory; use -r/--rev to specify a different revision.
306

307 308 309
    The archive type is automatically detected based on file
    extension (or override using -t/--type).

Matt Mackall's avatar
Matt Mackall committed
310 311 312 313 314 315 316 317 318 319 320 321
    .. container:: verbose

      Examples:

      - create a zip file containing the 1.0 release::

          hg archive -r 1.0 project-1.0.zip

      - create a tarball excluding .hg files::

          hg archive project.tar.gz -X ".hg*"

322
    Valid types are:
323

324 325 326 327 328 329
    :``files``: a directory full of files (default)
    :``tar``:   tar archive, uncompressed
    :``tbz2``:  tar archive, compressed using bzip2
    :``tgz``:   tar archive, compressed using gzip
    :``uzip``:  zip archive, uncompressed
    :``zip``:   zip archive, compressed using deflate
330

331
    The exact name of the destination archive or directory is given
Martin Geisler's avatar
Martin Geisler committed
332
    using a format string; see :hg:`help export` for details.
333

334 335 336 337
    Each member added to an archive file has a directory prefix
    prepended. Use -p/--prefix to specify a format string for the
    prefix. The default is the basename of the archive, with suffixes
    removed.
338 339

    Returns 0 on success.
340 341
    '''

342
    ctx = scmutil.revsingle(repo, opts.get('rev'))
343
    if not ctx:
344
        raise util.Abort(_('no working directory: please specify a revision'))
345
    node = ctx.node()
346
    dest = cmdutil.makefilename(repo, dest, node)
347 348
    if os.path.realpath(dest) == repo.root:
        raise util.Abort(_('repository root cannot be destination'))
349

350
    kind = opts.get('type') or archival.guesskind(dest) or 'files'
351
    prefix = opts.get('prefix')
352

353 354 355
    if dest == '-':
        if kind == 'files':
            raise util.Abort(_('cannot archive plain files to stdout'))
356
        dest = cmdutil.makefileobj(repo, dest)
357 358
        if not prefix:
            prefix = os.path.basename(repo.root) + '-%h'
359

360
    prefix = cmdutil.makefilename(repo, prefix, node)
361
    matchfn = scmutil.match(ctx, [], opts)
362
    archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
363
                     matchfn, prefix, subrepos=opts.get('subrepos'))
364

365 366 367 368
@command('backout',
    [('', 'merge', None, _('merge with old dirstate parent after backout')),
    ('', 'parent', '', _('parent to choose when backing out merge'), _('REV')),
    ('r', 'rev', '', _('revision to backout'), _('REV')),
369
    ] + mergetoolopts + walkopts + commitopts + commitopts2,
370
    _('[OPTION]... [-r] REV'))
Daniel Holth's avatar
Daniel Holth committed
371
def backout(ui, repo, node=None, rev=None, **opts):
Vadim Gelfer's avatar
Vadim Gelfer committed
372 373
    '''reverse effect of earlier changeset

374 375 376
    Prepare a new changeset with the effect of REV undone in the
    current working directory.

377
    If REV is the parent of the working directory, then this new changeset
378 379 380
    is committed automatically. Otherwise, hg needs to merge the
    changes and the merged result is left uncommitted.

Matt Mackall's avatar
Matt Mackall committed
381 382 383 384 385 386 387 388 389 390 391
    .. container:: verbose

      By default, the pending changeset will have one parent,
      maintaining a linear history. With --merge, the pending
      changeset will instead have two parents: the old parent of the
      working directory and a new child of REV that simply undoes REV.

      Before version 1.7, the behavior without --merge was equivalent
      to specifying --merge followed by :hg:`update --clean .` to
      cancel the merge and leave the child of REV as a head to be
      merged separately.
392

Martin Geisler's avatar
Martin Geisler committed
393
    See :hg:`help dates` for a list of formats valid for -d/--date.
394 395

    Returns 0 on success.
396
    '''
Daniel Holth's avatar
Daniel Holth committed
397 398 399 400 401
    if rev and node:
        raise util.Abort(_("please specify just one revision"))

    if not rev:
        rev = node
Vadim Gelfer's avatar
Vadim Gelfer committed
402

403 404 405
    if not rev:
        raise util.Abort(_("please specify a revision to backout"))

406 407 408 409
    date = opts.get('date')
    if date:
        opts['date'] = util.parsedate(date)

410
    cmdutil.bailifchanged(repo)
411
    node = scmutil.revsingle(repo, rev).node()
412

413
    op1, op2 = repo.dirstate.parents()
414 415
    a = repo.changelog.ancestor(op1, node)
    if a != node:
416
        raise util.Abort(_('cannot backout change on a different branch'))
417

418 419
    p1, p2 = repo.changelog.parents(node)
    if p1 == nullid:
420
        raise util.Abort(_('cannot backout a change with no parents'))
Vadim Gelfer's avatar
Vadim Gelfer committed
421
    if p2 != nullid:
422
        if not opts.get('parent'):
423
            raise util.Abort(_('cannot backout a merge changeset without '
424 425 426
                               '--parent'))
        p = repo.lookup(opts['parent'])
        if p not in (p1, p2):
427
            raise util.Abort(_('%s is not a parent of %s') %
428
                             (short(p), short(node)))
429 430
        parent = p
    else:
431
        if opts.get('parent'):
432 433
            raise util.Abort(_('cannot use --parent on non-merge changeset'))
        parent = p1
434

435 436
    # the backout should appear on the same branch
    branch = repo.dirstate.branch()
437
    hg.clean(repo, node, show_stats=False)
438
    repo.dirstate.setbranch(branch)
Vadim Gelfer's avatar
Vadim Gelfer committed
439
    revert_opts = opts.copy()
440
    revert_opts['date'] = None
441
    revert_opts['all'] = True
Vadim Gelfer's avatar
Vadim Gelfer committed
442
    revert_opts['rev'] = hex(parent)
443
    revert_opts['no_backup'] = None
Vadim Gelfer's avatar
Vadim Gelfer committed
444
    revert(ui, repo, **revert_opts)
445
    if not opts.get('merge') and op1 != node:
446 447 448 449 450
        try:
            ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
            return hg.update(repo, op1)
        finally:
            ui.setconfig('ui', 'forcemerge', '')
451

Vadim Gelfer's avatar
Vadim Gelfer committed
452 453
    commit_opts = opts.copy()
    commit_opts['addremove'] = False
454
    if not commit_opts['message'] and not commit_opts['logfile']:
455
        # we don't translate commit messages
456
        commit_opts['message'] = "Backed out changeset %s" % short(node)
457
        commit_opts['force_editor'] = True
Vadim Gelfer's avatar
Vadim Gelfer committed
458 459 460 461 462
    commit(ui, repo, **commit_opts)
    def nice(node):
        return '%d:%s' % (repo.changelog.rev(node), short(node))
    ui.status(_('changeset %s backs out changeset %s\n') %
              (nice(repo.changelog.tip()), nice(node)))
463
    if opts.get('merge') and op1 != node:
464
        hg.clean(repo, op1, show_stats=False)
465 466
        ui.status(_('merging with changeset %s\n')
                  % nice(repo.changelog.tip()))
467 468 469 470 471
        try:
            ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
            return hg.merge(repo, hex(repo.changelog.tip()))
        finally:
            ui.setconfig('ui', 'forcemerge', '')
472
    return 0
Vadim Gelfer's avatar
Vadim Gelfer committed
473

474 475 476 477 478 479 480 481 482
@command('bisect',
    [('r', 'reset', False, _('reset bisect state')),
    ('g', 'good', False, _('mark changeset good')),
    ('b', 'bad', False, _('mark changeset bad')),
    ('s', 'skip', False, _('skip testing changeset')),
    ('e', 'extend', False, _('extend the bisect range')),
    ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
    ('U', 'noupdate', False, _('do not update to target'))],
    _("[-gbsr] [-U] [-c CMD] [REV]"))
483
def bisect(ui, repo, rev=None, extra=None, command=None,
484 485
               reset=None, good=None, bad=None, skip=None, extend=None,
               noupdate=None):
486 487
    """subdivision search of changesets

488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504
    This command helps to find changesets which introduce problems. To
    use, mark the earliest changeset you know exhibits the problem as
    bad, then mark the latest changeset which is free from the problem
    as good. Bisect will update your working directory to a revision
    for testing (unless the -U/--noupdate option is specified). Once
    you have performed tests, mark the working directory as good or
    bad, and bisect will either update to another candidate changeset
    or announce that it has found the bad revision.

    As a shortcut, you can also use the revision argument to mark a
    revision as good or bad without checking it out first.

    If you supply a command, it will be used for automatic bisection.
    Its exit status will be used to mark revisions as good or bad:
    status 0 means good, 125 means to skip the revision, 127
    (command not found) will abort the bisection, and any other
    non-zero exit status means the revision is bad.
505

506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551
    .. container:: verbose

      Some examples:

      - start a bisection with known bad revision 12, and good revision 34::

          hg bisect --bad 34
          hg bisect --good 12

      - advance the current bisection by marking current revision as good or
        bad::

          hg bisect --good
          hg bisect --bad

      - mark the current revision, or a known revision, to be skipped (eg. if
        that revision is not usable because of another issue)::

          hg bisect --skip
          hg bisect --skip 23

      - forget the current bisection::

          hg bisect --reset

      - use 'make && make tests' to automatically find the first broken
        revision::

          hg bisect --reset
          hg bisect --bad 34
          hg bisect --good 12
          hg bisect --command 'make && make tests'

      - see all changesets whose states are already known in the current
        bisection::

          hg log -r "bisect(pruned)"

      - see all changesets that took part in the current bisection::

          hg log -r "bisect(range)"

      - with the graphlog extension, you can even get a nice graph::

          hg log --graph -r "bisect(range)"

552 553
      See :hg:`help revsets` for more about the `bisect()` keyword.

554
    Returns 0 on success.
555
    """
556 557 558 559 560 561 562 563
    def extendbisectrange(nodes, good):
        # bisect is incomplete when it ends on a merge node and
        # one of the parent was not checked.
        parents = repo[nodes[0]].parents()
        if len(parents) > 1:
            side = good and state['bad'] or state['good']
            num = len(set(i.node() for i in parents) & set(side))
            if num == 1:
Yuya Nishihara's avatar
Yuya Nishihara committed
564
                return parents[0].ancestor(parents[1])
565 566
        return None

567 568 569 570
    def print_result(nodes, good):
        displayer = cmdutil.show_changeset(ui, repo, {})
        if len(nodes) == 1:
            # narrowed it down to a single revision
571 572 573 574
            if good:
                ui.write(_("The first good revision is:\n"))
            else:
                ui.write(_("The first bad revision is:\n"))
575
            displayer.show(repo[nodes[0]])
576 577 578 579 580
            extendnode = extendbisectrange(nodes, good)
            if extendnode is not None:
                ui.write(_('Not all ancestors of this changeset have been'
                           ' checked.\nUse bisect --extend to continue the '
                           'bisection from\nthe common ancestor, %s.\n')
581
                         % extendnode)
582 583
        else:
            # multiple possible revisions
584 585 586 587 588 589
            if good:
                ui.write(_("Due to skipped revisions, the first "
                        "good revision could be any of:\n"))
            else:
                ui.write(_("Due to skipped revisions, the first "
                        "bad revision could be any of:\n"))
590
            for n in nodes:
591
                displayer.show(repo[n])
592
        displayer.close()
593 594 595 596 597 598 599 600 601 602 603

    def check_state(state, interactive=True):
        if not state['good'] or not state['bad']:
            if (good or bad or skip or reset) and interactive:
                return
            if not state['good']:
                raise util.Abort(_('cannot bisect (no known good revisions)'))
            else:
                raise util.Abort(_('cannot bisect (no known bad revisions)'))
        return True

604 605 606 607 608 609 610 611 612 613
    # backward compatibility
    if rev in "good bad reset init".split():
        ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
        cmd, rev, extra = rev, extra, None
        if cmd == "good":
            good = True
        elif cmd == "bad":
            bad = True
        else:
            reset = True
614
    elif extra or good + bad + skip + reset + extend + bool(command) > 1:
615
        raise util.Abort(_('incompatible arguments'))
616 617 618 619 620 621 622

    if reset:
        p = repo.join("bisect.state")
        if os.path.exists(p):
            os.unlink(p)
        return

623 624 625 626
    state = hbisect.load_state(repo)

    if command:
        changesets = 1
627 628 629
        try:
            while changesets:
                # update state
630
                status = util.system(command, out=ui.fout)
631 632 633 634 635 636 637 638 639 640 641
                if status == 125:
                    transition = "skip"
                elif status == 0:
                    transition = "good"
                # status < 0 means process was killed
                elif status == 127:
                    raise util.Abort(_("failed to execute %s") % command)
                elif status < 0:
                    raise util.Abort(_("%s killed") % command)
                else:
                    transition = "bad"
642
                ctx = scmutil.revsingle(repo, rev)
643
                rev = None # clear for future iterations
644 645
                state[transition].append(ctx.node())
                ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
646 647 648 649
                check_state(state, interactive=False)
                # bisect
                nodes, changesets, good = hbisect.bisect(repo.changelog, state)
                # update to next check
650
                cmdutil.bailifchanged(repo)
651 652 653
                hg.clean(repo, nodes[0], show_stats=False)
        finally:
            hbisect.save_state(repo, state)
654 655
        print_result(nodes, good)
        return
656 657

    # update state
658 659

    if rev:
660
        nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
661 662 663
    else:
        nodes = [repo.lookup('.')]

664 665
    if good or bad or skip:
        if good:
666
            state['good'] += nodes
667
        elif bad:
668
            state['bad'] += nodes
669
        elif skip:
670
            state['skip'] += nodes
671
        hbisect.save_state(repo, state)
672

673 674
    if not check_state(state):
        return
675 676

    # actually bisect
677
    nodes, changesets, good = hbisect.bisect(repo.changelog, state)
678 679 680 681 682
    if extend:
        if not changesets:
            extendnode = extendbisectrange(nodes, good)
            if extendnode is not None:
                ui.write(_("Extending search to changeset %d:%s\n"
683
                         % (extendnode.rev(), extendnode)))
684 685
                if noupdate:
                    return
686
                cmdutil.bailifchanged(repo)
687 688 689
                return hg.clean(repo, extendnode.node())
        raise util.Abort(_("nothing to extend"))

690
    if changesets == 0:
691
        print_result(nodes, good)
692 693 694
    else:
        assert len(nodes) == 1 # only a single node can be tested next
        node = nodes[0]
695 696 697 698 699
        # compute the approximate number of remaining tests
        tests, size = 0, 2
        while size <= changesets:
            tests, size = tests + 1, size * 2
        rev = repo.changelog.rev(node)
700 701
        ui.write(_("Testing changeset %d:%s "
                   "(%d changesets remaining, ~%d tests)\n")
702
                 % (rev, short(node), changesets, tests))
703
        if not noupdate:
704
            cmdutil.bailifchanged(repo)
705 706
            return hg.clean(repo, node)

707 708 709 710 711 712 713
@command('bookmarks',
    [('f', 'force', False, _('force')),
    ('r', 'rev', '', _('revision'), _('REV')),
    ('d', 'delete', False, _('delete a given bookmark')),
    ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
    ('i', 'inactive', False, _('do not mark a new bookmark active'))],
    _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
714 715
def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
             rename=None, inactive=False):
716 717 718 719 720 721 722 723 724 725 726 727 728
    '''track a line of development with movable markers

    Bookmarks are pointers to certain commits that move when
    committing. Bookmarks are local. They can be renamed, copied and
    deleted. It is possible to use bookmark names in :hg:`merge` and
    :hg:`update` to merge and update respectively to a given bookmark.

    You can use :hg:`bookmark NAME` to set a bookmark on the working
    directory's parent revision with the given name. If you specify
    a revision using -r REV (where REV may be an existing bookmark),
    the bookmark is assigned to that revision.

    Bookmarks can be pushed and pulled between repositories (see :hg:`help
729 730 731
    push` and :hg:`help pull`). This requires both the local and remote
    repositories to support bookmarks. For versions prior to 1.8, this means
    the bookmarks extension must be enabled.
732 733 734 735 736 737 738
    '''
    hexfn = ui.debugflag and hex or short
    marks = repo._bookmarks
    cur   = repo.changectx('.').node()

    if rename:
        if rename not in marks:
739
            raise util.Abort(_("bookmark '%s' does not exist") % rename)
740
        if mark in marks and not force:
741 742
            raise util.Abort(_("bookmark '%s' already exists "
                               "(use -f to force)") % mark)
743 744 745
        if mark is None:
            raise util.Abort(_("new bookmark name required"))
        marks[mark] = marks[rename]
746
        if repo._bookmarkcurrent == rename and not inactive:
747
            bookmarks.setcurrent(repo, mark)
748
        del marks[rename]
749 750 751 752 753 754 755
        bookmarks.write(repo)
        return

    if delete:
        if mark is None:
            raise util.Abort(_("bookmark name required"))
        if mark not in marks:
756
            raise util.Abort(_("bookmark '%s' does not exist") % mark)
757 758 759 760 761 762 763 764 765 766 767 768 769
        if mark == repo._bookmarkcurrent:
            bookmarks.setcurrent(repo, None)
        del marks[mark]
        bookmarks.write(repo)
        return

    if mark is not None:
        if "\n" in mark:
            raise util.Abort(_("bookmark name cannot contain newlines"))
        mark = mark.strip()
        if not mark:
            raise util.Abort(_("bookmark names cannot consist entirely of "
                               "whitespace"))
770 771 772
        if inactive and mark == repo._bookmarkcurrent:
            bookmarks.setcurrent(repo, None)
            return
773
        if mark in marks and not force:
774 775
            raise util.Abort(_("bookmark '%s' already exists "
                               "(use -f to force)") % mark)
776 777 778 779 780 781 782 783
        if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
            and not force):
            raise util.Abort(
                _("a bookmark cannot have the name of an existing branch"))
        if rev:
            marks[mark] = repo.lookup(rev)
        else:
            marks[mark] = repo.changectx('.').node()
784
        if not inactive and repo.changectx('.').node() == marks[mark]:
785
            bookmarks.setcurrent(repo, mark)
786 787 788 789 790 791 792 793 794
        bookmarks.write(repo)
        return

    if mark is None:
        if rev:
            raise util.Abort(_("bookmark name required"))
        if len(marks) == 0:
            ui.status(_("no bookmarks set\n"))
        else:
795
            for bmark, n in sorted(marks.iteritems()):
796 797 798
                current = repo._bookmarkcurrent
                if bmark == current and n == cur:
                    prefix, label = '*', 'bookmarks.current'
799
                else:
800
                    prefix, label = ' ', ''
801 802 803 804 805 806 807 808 809

                if ui.quiet:
                    ui.write("%s\n" % bmark, label=label)
                else:
                    ui.write(" %s %-25s %d:%s\n" % (
                        prefix, bmark, repo.changelog.rev(n), hexfn(n)),
                        label=label)
        return

810 811 812 813 814
@command('branch',
    [('f', 'force', None,
     _('set branch name even if it shadows an existing branch')),
    ('C', 'clean', None, _('reset branch name to parent branch name'))],
    _('[-fC] [NAME]'))
815
def branch(ui, repo, label=None, **opts):
816 817
    """set or show the current branch name

818 819 820 821 822
    With no argument, show the current branch name. With one argument,
    set the working directory branch name (the branch will not exist
    in the repository until the next commit). Standard practice
    recommends that primary development take place on the 'default'
    branch.
823

824 825
    Unless -f/--force is specified, branch will not let you set a
    branch name that already exists, even if it's inactive.
826

827 828 829
    Use -C/--clean to reset the working directory branch to that of
    the parent of the working directory, negating a previous branch
    change.
830

Martin Geisler's avatar
Martin Geisler committed
831 832
    Use the command :hg:`update` to switch to an existing branch. Use
    :hg:`commit --close-branch` to mark this branch as closed.
833

834 835 836 837 838 839
    .. note::

       Branch names are permanent. Use :hg:`bookmark` to create a
       light-weight bookmark instead. See :hg:`help glossary` for more
       information about named branches and bookmarks.

840
    Returns 0 on success.
841 842
    """

843
    if opts.get('clean'):
844
        label = repo[None].p1().branch()
845 846 847
        repo.dirstate.setbranch(label)
        ui.status(_('reset working directory to branch %s\n') % label)
    elif label:
848
        if not opts.get('force') and label in repo.branchtags():
849
            if label not in [p.branch() for p in repo.parents()]:
850
                raise util.Abort(_('a branch of the same name already exists'),
851
                                 # i18n: "it" refers to an existing branch
852
                                 hint=_("use 'hg update' to switch to it"))
853
        repo.dirstate.setbranch(label)
854
        ui.status(_('marked working directory as branch %s\n') % label)
855
    else:
856
        ui.write("%s\n" % repo.dirstate.branch())
857

858 859 860 861
@command('branches',
    [('a', 'active', False, _('show only branches that have unmerged heads')),
    ('c', 'closed', False, _('show normal and closed branches'))],
    _('[-ac]'))
862
def branches(ui, repo, active=False, closed=False):
863 864
    """list repository named branches

865 866
    List the repository's named branches, indicating which ones are
    inactive. If -c/--closed is specified, also list branches which have
867
    been marked closed (see :hg:`commit --close-branch`).
868

869 870
    If -a/--active is specified, only show active branches. A branch
    is considered active if it contains repository heads.
871

Martin Geisler's avatar
Martin Geisler committed
872
    Use the command :hg:`update` to switch to an existing branch.
873 874

    Returns 0.
875
    """
876

877
    hexfunc = ui.debugflag and hex or short
878
    activebranches = [repo[n].branch() for n in repo.heads()]
879 880 881 882 883
    def testactive(tag, node):
        realhead = tag in activebranches
        open = node in repo.branchheads(tag, closed=False)
        return realhead and open
    branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
884 885
                          for tag, node in repo.branchtags().items()],
                      reverse=True)
886 887 888

    for isactive, node, tag in branches:
        if (not active) or isactive:
889
            if ui.quiet:
890
                ui.write("%s\n" % tag)
891
            else:
892 893
                hn = repo.lookup(node)
                if isactive: