This instance will be upgraded to Heptapod 0.21.0rc2 on 2021-04-16 at 14:00 UTC+2 (a few minutes of down time)

commands.py 248 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

Gregory Szorc's avatar
Gregory Szorc committed
8 9 10 11 12
from __future__ import absolute_import

import errno
import os
import re
13
import sys
Gregory Szorc's avatar
Gregory Szorc committed
14 15 16 17 18 19 20

from .i18n import _
from .node import (
    hex,
    nullid,
    nullrev,
    short,
21 22
    wdirhex,
    wdirrev,
Gregory Szorc's avatar
Gregory Szorc committed
23
)
24
from .pycompat import open
Gregory Szorc's avatar
Gregory Szorc committed
25 26 27 28
from . import (
    archival,
    bookmarks,
    bundle2,
29
    bundlecaches,
Gregory Szorc's avatar
Gregory Szorc committed
30 31 32
    changegroup,
    cmdutil,
    copies,
33
    debugcommands as debugcommandsmod,
Gregory Szorc's avatar
Gregory Szorc committed
34
    destutil,
35
    dirstateguard,
Gregory Szorc's avatar
Gregory Szorc committed
36 37 38 39 40
    discovery,
    encoding,
    error,
    exchange,
    extensions,
41
    filemerge,
Yuya Nishihara's avatar
Yuya Nishihara committed
42
    formatter,
Gregory Szorc's avatar
Gregory Szorc committed
43
    graphmod,
44
    grep as grepmod,
Gregory Szorc's avatar
Gregory Szorc committed
45 46 47
    hbisect,
    help,
    hg,
48
    logcmdutil,
Gregory Szorc's avatar
Gregory Szorc committed
49
    merge as mergemod,
50
    mergestate as mergestatemod,
51
    narrowspec,
Gregory Szorc's avatar
Gregory Szorc committed
52
    obsolete,
53
    obsutil,
Gregory Szorc's avatar
Gregory Szorc committed
54 55
    patch,
    phases,
56
    pycompat,
57
    rcutil,
58
    registrar,
59
    requirements,
60
    revsetlang,
61
    rewriteutil,
Gregory Szorc's avatar
Gregory Szorc committed
62
    scmutil,
63
    server,
64
    shelve as shelvemod,
65
    state as statemod,
Gregory Szorc's avatar
Gregory Szorc committed
66
    streamclone,
67
    tags as tagsmod,
Gregory Szorc's avatar
Gregory Szorc committed
68 69
    ui as uimod,
    util,
70
    verify as verifymod,
71
    vfs as vfsmod,
72
    wireprotoserver,
Gregory Szorc's avatar
Gregory Szorc committed
73
)
74 75 76 77
from .utils import (
    dateutil,
    stringutil,
)
Gregory Szorc's avatar
Gregory Szorc committed
78

79
table = {}
80
table.update(debugcommandsmod.command._table)
81

82
command = registrar.command(table)
83
INTENT_READONLY = registrar.INTENT_READONLY
84 85 86 87

# common command options

globalopts = [
88
    (
89 90 91 92 93
        b'R',
        b'repository',
        b'',
        _(b'repository root directory or name of overlay bundle file'),
        _(b'REPO'),
94
    ),
95
    (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
96
    (
97 98
        b'y',
        b'noninteractive',
99
        None,
100 101 102
        _(
            b'do not prompt, automatically pick the first choice for all prompts'
        ),
103
    ),
104 105
    (b'q', b'quiet', None, _(b'suppress output')),
    (b'v', b'verbose', None, _(b'enable additional output')),
106
    (
107 108 109
        b'',
        b'color',
        b'',
110 111
        # i18n: 'always', 'auto', 'never', and 'debug' are keywords
        # and should not be translated
112 113
        _(b"when to colorize (boolean, always, auto, never, or debug)"),
        _(b'TYPE'),
114 115
    ),
    (
116 117
        b'',
        b'config',
118
        [],
119 120
        _(b'set/override config option (use \'section.name=value\')'),
        _(b'CONFIG'),
121
    ),
122 123
    (b'', b'debug', None, _(b'enable debugging output')),
    (b'', b'debugger', None, _(b'start debugger')),
124
    (
125 126
        b'',
        b'encoding',
127
        encoding.encoding,
128 129
        _(b'set the charset encoding'),
        _(b'ENCODE'),
130 131
    ),
    (
132 133
        b'',
        b'encodingmode',
134
        encoding.encodingmode,
135 136
        _(b'set the charset encoding mode'),
        _(b'MODE'),
137
    ),
138 139 140 141 142 143
    (b'', b'traceback', None, _(b'always print a traceback on exception')),
    (b'', b'time', None, _(b'time how long the command takes')),
    (b'', b'profile', None, _(b'print command execution profile')),
    (b'', b'version', None, _(b'output version information and exit')),
    (b'h', b'help', None, _(b'display help and exit')),
    (b'', b'hidden', False, _(b'consider hidden changesets')),
144
    (
145 146 147 148 149
        b'',
        b'pager',
        b'auto',
        _(b"when to paginate (boolean, always, auto, or never)"),
        _(b'TYPE'),
150
    ),
151 152
]

153 154 155 156 157
dryrunopts = cmdutil.dryrunopts
remoteopts = cmdutil.remoteopts
walkopts = cmdutil.walkopts
commitopts = cmdutil.commitopts
commitopts2 = cmdutil.commitopts2
158
commitopts3 = cmdutil.commitopts3
159 160 161 162 163 164 165 166 167 168
formatteropts = cmdutil.formatteropts
templateopts = cmdutil.templateopts
logopts = cmdutil.logopts
diffopts = cmdutil.diffopts
diffwsopts = cmdutil.diffwsopts
diffopts2 = cmdutil.diffopts2
mergetoolopts = cmdutil.mergetoolopts
similarityopts = cmdutil.similarityopts
subrepoopts = cmdutil.subrepoopts
debugrevlogopts = cmdutil.debugrevlogopts
169

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

172 173

@command(
174
    b'abort',
175 176 177 178
    dryrunopts,
    helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
    helpbasic=True,
)
179 180 181 182 183 184 185 186
def abort(ui, repo, **opts):
    """abort an unfinished operation (EXPERIMENTAL)

    Aborts a multistep operation like graft, histedit, rebase, merge,
    and unshelve if they are in an unfinished state.

    use --dry-run/-n to dry run the command.
    """
187
    dryrun = opts.get('dry_run')
188 189
    abortstate = cmdutil.getunfinishedstate(repo)
    if not abortstate:
190
        raise error.StateError(_(b'no operation in progress'))
191
    if not abortstate.abortfunc:
192
        raise error.InputError(
193
            (
194
                _(b"%s in progress but does not support 'hg abort'")
195 196 197 198
                % (abortstate._opname)
            ),
            hint=abortstate.hint(),
        )
199
    if dryrun:
200 201 202
        ui.status(
            _(b'%s in progress, will be aborted\n') % (abortstate._opname)
        )
203 204 205
        return
    return abortstate.abortfunc(ui, repo)

206 207

@command(
208
    b'add',
209
    walkopts + subrepoopts + dryrunopts,
210
    _(b'[OPTION]... [FILE]...'),
211
    helpcategory=command.CATEGORY_WORKING_DIRECTORY,
212 213 214
    helpbasic=True,
    inferrepo=True,
)
215
def add(ui, repo, *pats, **opts):
216 217
    """add the specified files on the next commit

218 219
    Schedule files to be version controlled and added to the
    repository.
220

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

timeless's avatar
timeless committed
224 225
    If no names are given, add all files to the repository (except
    files matching ``.hgignore``).
226 227 228

    .. container:: verbose

229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
       Examples:

         - New (unknown) files are added
           automatically by :hg:`add`::

             $ ls
             foo.c
             $ hg status
             ? foo.c
             $ hg add
             adding foo.c
             $ hg status
             A foo.c

         - Specific files to be added can be specified::

             $ ls
             bar.c  foo.c
             $ hg status
             ? bar.c
             ? foo.c
             $ hg add bar.c
             $ hg status
             A bar.c
             ? foo.c
254 255

    Returns 0 if all files are successfully added.
256 257
    """

258
    m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
259
    uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
260
    rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
261
    return rejected and 1 or 0
262

263 264

@command(
265
    b'addremove',
266
    similarityopts + subrepoopts + walkopts + dryrunopts,
267
    _(b'[OPTION]... [FILE]...'),
268
    helpcategory=command.CATEGORY_WORKING_DIRECTORY,
269 270
    inferrepo=True,
)
271
def addremove(ui, repo, *pats, **opts):
272
    """add all new files, delete all missing files
273

274 275
    Add all new files and remove all missing files from the
    repository.
276

timeless's avatar
timeless committed
277 278 279
    Unless names are given, new files are ignored if they match any of
    the patterns in ``.hgignore``. As with add, these changes take
    effect at the next commit.
280

281
    Use the -s/--similarity option to detect renamed files. This
282
    option takes a percentage between 0 (disabled) and 100 (files must
283 284 285
    be identical) as its parameter. With a parameter greater than 0,
    this compares every removed file with every added file and records
    those similar enough as renames. Detecting renamed files this way
286
    can be expensive. After using this option, :hg:`status -C` can be
287 288 289
    used to check which files were identified as moved or renamed. If
    not specified, -s/--similarity defaults to 100 and only renames of
    identical files are detected.
290

291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
    .. container:: verbose

       Examples:

         - A number of files (bar.c and foo.c) are new,
           while foobar.c has been removed (without using :hg:`remove`)
           from the repository::

             $ ls
             bar.c foo.c
             $ hg status
             ! foobar.c
             ? bar.c
             ? foo.c
             $ hg addremove
             adding bar.c
             adding foo.c
             removing foobar.c
             $ hg status
             A bar.c
             A foo.c
             R foobar.c

         - A file foobar.c was moved to foo.c without using :hg:`rename`.
           Afterwards, it was edited slightly::

             $ ls
             foo.c
             $ hg status
             ! foobar.c
             ? foo.c
             $ hg addremove --similarity 90
             removing foobar.c
             adding foo.c
             recording removal of foobar.c as rename to foo.c (94% similar)
             $ hg status -C
             A foo.c
               foobar.c
             R foobar.c

331
    Returns 0 if all files are successfully added.
332
    """
333
    opts = pycompat.byteskwargs(opts)
334 335
    if not opts.get(b'similarity'):
        opts[b'similarity'] = b'100'
336
    matcher = scmutil.match(repo[None], pats, opts)
337
    relative = scmutil.anypats(pats, opts)
338
    uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
339
    return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
340

341 342

@command(
343
    b'annotate|blame',
344
    [
345
        (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
346
        (
347 348
            b'',
            b'follow',
349
            None,
350
            _(b'follow copies/renames and list the filename (DEPRECATED)'),
351
        ),
352 353 354 355 356 357 358
        (b'', b'no-follow', None, _(b"don't follow copies and renames")),
        (b'a', b'text', None, _(b'treat all files as text')),
        (b'u', b'user', None, _(b'list the author (long with -v)')),
        (b'f', b'file', None, _(b'list the filename')),
        (b'd', b'date', None, _(b'list the date (short with -q)')),
        (b'n', b'number', None, _(b'list the revision number (default)')),
        (b'c', b'changeset', None, _(b'list the changeset')),
359
        (
360 361
            b'l',
            b'line-number',
362
            None,
363 364 365 366 367 368
            _(b'show line number at the first appearance'),
        ),
        (
            b'',
            b'skip',
            [],
369
            _(b'revset to not display (EXPERIMENTAL)'),
370
            _(b'REV'),
371 372 373 374 375
        ),
    ]
    + diffwsopts
    + walkopts
    + formatteropts,
376
    _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
377
    helpcategory=command.CATEGORY_FILE_CONTENTS,
378 379 380
    helpbasic=True,
    inferrepo=True,
)
381
def annotate(ui, repo, *pats, **opts):
382
    """show changeset information by line for each file
383

384
    List changes in files, showing the revision id responsible for
385
    each line.
386

387 388
    This command is useful for discovering when a change was made and
    by whom.
389

390 391 392
    If you include --file, --user, or --date, the revision number is
    suppressed unless you also include --number.

393 394 395 396
    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.
397

398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
    .. container:: verbose

      Template:

      The following keywords are supported in addition to the common template
      keywords and functions. See also :hg:`help templates`.

      :lines:   List of lines with annotation data.
      :path:    String. Repository-absolute path of the specified file.

      And each entry of ``{lines}`` provides the following sub-keywords in
      addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.

      :line:    String. Line content.
      :lineno:  Integer. Line number at that revision.
      :path:    String. Repository-absolute path of the file at that revision.

      See :hg:`help templates.operators` for the list expansion syntax.

417
    Returns 0 on success.
418
    """
419
    opts = pycompat.byteskwargs(opts)
420
    if not pats:
421 422 423
        raise error.InputError(
            _(b'at least one filename or pattern is required')
        )
424

425
    if opts.get(b'follow'):
426 427
        # --follow is deprecated and now just an alias for -f/--file
        # to mimic the behavior of Mercurial before version 1.5
428
        opts[b'file'] = True
429

430
    if (
431 432 433 434
        not opts.get(b'user')
        and not opts.get(b'changeset')
        and not opts.get(b'date')
        and not opts.get(b'file')
435
    ):
436
        opts[b'number'] = True
437

438 439 440 441 442 443
    linenumber = opts.get(b'line_number') is not None
    if (
        linenumber
        and (not opts.get(b'changeset'))
        and (not opts.get(b'number'))
    ):
444
        raise error.InputError(_(b'at least one of -n/-c is required for -l'))
445

446
    rev = opts.get(b'rev')
447
    if rev:
448
        repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
449
    ctx = scmutil.revsingle(repo, rev)
450

451 452
    ui.pager(b'annotate')
    rootfm = ui.formatter(b'annotate', opts)
453 454 455
    if ui.debugflag:
        shorthex = pycompat.identity
    else:
456

457 458
        def shorthex(h):
            return h[:12]
459

460
    if ui.quiet:
461
        datefunc = dateutil.shortdate
462
    else:
463
        datefunc = dateutil.datestr
464
    if ctx.rev() is None:
465
        if opts.get(b'changeset'):
466 467
            # omit "+" suffix which is appended to node hex
            def formatrev(rev):
468
                if rev == wdirrev:
469
                    return b'%d' % ctx.p1().rev()
470
                else:
471
                    return b'%d' % rev
472

473
        else:
474

475
            def formatrev(rev):
476
                if rev == wdirrev:
477
                    return b'%d+' % ctx.p1().rev()
478
                else:
479
                    return b'%d ' % rev
480

481
        def formathex(h):
482
            if h == wdirhex:
483
                return b'%s+' % shorthex(hex(ctx.p1().node()))
484
            else:
485
                return b'%s ' % shorthex(h)
486

487
    else:
488 489
        formatrev = b'%d'.__mod__
        formathex = shorthex
490

491
    opmap = [
492 493 494 495 496 497
        (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
        (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
        (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
        (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
        (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
        (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
498 499
    ]
    opnamemap = {
500 501 502 503
        b'rev': b'number',
        b'node': b'changeset',
        b'path': b'file',
        b'lineno': b'line_number',
504
    }
505

506
    if rootfm.isplain():
507

508
        def makefunc(get, fmt):
509
            return lambda x: fmt(get(x))
510

511
    else:
512

513
        def makefunc(get, fmt):
514
            return get
515

516
    datahint = rootfm.datahint()
517 518 519 520 521
    funcmap = [
        (makefunc(get, fmt), sep)
        for fn, sep, get, fmt in opmap
        if opts.get(opnamemap.get(fn, fn)) or fn in datahint
    ]
522 523
    funcmap[0] = (funcmap[0][0], b'')  # no separator in front of first column
    fields = b' '.join(
524 525 526 527
        fn
        for fn, sep, get, fmt in opmap
        if opts.get(opnamemap.get(fn, fn)) or fn in datahint
    )
528

529
    def bad(x, y):
530
        raise error.Abort(b"%s: %s" % (x, y))
531

532 533
    m = scmutil.match(ctx, pats, opts, badfn=bad)

534
    follow = not opts.get(b'no_follow')
535
    diffopts = patch.difffeatureopts(
536
        ui, opts, section=b'annotate', whitespace=True
537
    )
538
    skiprevs = opts.get(b'skip')
539 540 541
    if skiprevs:
        skiprevs = scmutil.revrange(repo, skiprevs)

542
    uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
Matt Mackall's avatar
Matt Mackall committed
543 544
    for abs in ctx.walk(m):
        fctx = ctx[abs]
545
        rootfm.startitem()
546
        rootfm.data(path=abs)
547 548
        if not opts.get(b'text') and fctx.isbinary():
            rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
549 550
            continue

551
        fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
552 553 554
        lines = fctx.annotate(
            follow=follow, skiprevs=skiprevs, diffopts=diffopts
        )
555
        if not lines:
556
            fm.end()
557
            continue
558
        formats = []
559 560
        pieces = []

561
        for f, sep in funcmap:
562
            l = [f(n) for n in lines]
563
            if fm.isplain():
564 565
                sizes = [encoding.colwidth(x) for x in l]
                ml = max(sizes)
566
                formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
567
            else:
568
                formats.append([b'%s'] * len(l))
569
            pieces.append(l)
570

571
        for f, p, n in zip(zip(*formats), zip(*pieces), lines):
572
            fm.startitem()
573
            fm.context(fctx=n.fctx)
574
            fm.write(fields, b"".join(f), *p)
575
            if n.skip:
576
                fmt = b"* %s"
577
            else:
578 579
                fmt = b": %s"
            fm.write(b'line', fmt, n.text)
580

581 582
        if not lines[-1].text.endswith(b'\n'):
            fm.plain(b'\n')
583
        fm.end()
584

585
    rootfm.end()
586

587 588

@command(
589
    b'archive',
590
    [
591
        (b'', b'no-decode', None, _(b'do not pass files through decoders')),
592
        (
593 594 595 596 597
            b'p',
            b'prefix',
            b'',
            _(b'directory prefix for files in archive'),
            _(b'PREFIX'),
598
        ),
599 600
        (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
        (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
601 602 603
    ]
    + subrepoopts
    + walkopts,
604
    _(b'[OPTION]... DEST'),
605 606
    helpcategory=command.CATEGORY_IMPORT_EXPORT,
)
607
def archive(ui, repo, dest, **opts):
608
    '''create an unversioned archive of a repository revision
609

610 611
    By default, the revision used is the parent of the working
    directory; use -r/--rev to specify a different revision.
612

613
    The archive type is automatically detected based on file
timeless's avatar
timeless committed
614
    extension (to override, use -t/--type).
615

Matt Mackall's avatar
Matt Mackall committed
616 617 618 619 620 621 622 623 624 625 626 627
    .. 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*"

628
    Valid types are:
629

630 631 632 633
    :``files``: a directory full of files (default)
    :``tar``:   tar archive, uncompressed
    :``tbz2``:  tar archive, compressed using bzip2
    :``tgz``:   tar archive, compressed using gzip
634
    :``txz``:   tar archive, compressed using lzma (only in Python 3)
635 636
    :``uzip``:  zip archive, uncompressed
    :``zip``:   zip archive, compressed using deflate
637

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

641 642 643 644
    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.
645 646

    Returns 0 on success.
647 648
    '''

649
    opts = pycompat.byteskwargs(opts)
650
    rev = opts.get(b'rev')
651
    if rev:
652
        repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
653
    ctx = scmutil.revsingle(repo, rev)
654
    if not ctx:
655 656 657
        raise error.InputError(
            _(b'no working directory: please specify a revision')
        )
658
    node = ctx.node()
659
    dest = cmdutil.makefilename(ctx, dest)
660
    if os.path.realpath(dest) == repo.root:
661
        raise error.InputError(_(b'repository root cannot be destination'))
662

663 664
    kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
    prefix = opts.get(b'prefix')
665

666 667
    if dest == b'-':
        if kind == b'files':
668
            raise error.InputError(_(b'cannot archive plain files to stdout'))
669
        dest = cmdutil.makefileobj(ctx, dest)
670
        if not prefix:
671
            prefix = os.path.basename(repo.root) + b'-%h'
672

673
    prefix = cmdutil.makefilename(ctx, prefix)
674
    match = scmutil.match(ctx, [], opts)
675 676 677 678 679
    archival.archive(
        repo,
        dest,
        node,
        kind,
680
        not opts.get(b'no_decode'),
681 682
        match,
        prefix,
683
        subrepos=opts.get(b'subrepos'),
684 685 686 687
    )


@command(
688
    b'backout',
689 690
    [
        (
691 692 693 694 695 696 697 698
            b'',
            b'merge',
            None,
            _(b'merge with old dirstate parent after backout'),
        ),
        (
            b'',
            b'commit',
699
            None,
700
            _(b'commit if no conflicts were encountered (DEPRECATED)'),
701
        ),
702
        (b'', b'no-commit', None, _(b'do not commit')),
703
        (
704 705 706 707 708
            b'',
            b'parent',
            b'',
            _(b'parent to choose when backing out merge (DEPRECATED)'),
            _(b'REV'),
709
        ),
710 711
        (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
        (b'e', b'edit', False, _(b'invoke editor on commit messages')),
712 713 714 715 716
    ]
    + mergetoolopts
    + walkopts
    + commitopts
    + commitopts2,
717
    _(b'[OPTION]... [-r] REV'),
718 719
    helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
)
720
def backout(ui, repo, node=None, rev=None, **opts):
Vadim Gelfer's avatar
Vadim Gelfer committed
721 722
    '''reverse effect of earlier changeset

723
    Prepare a new changeset with the effect of REV undone in the
724 725
    current working directory. If no conflicts were encountered,
    it will be committed immediately.
726

727
    If REV is the parent of the working directory, then this new changeset
728
    is committed automatically (unless --no-commit is specified).
729

730
    .. note::
731

732
       :hg:`backout` cannot be used to fix either an unwanted or
733
       incorrect merge.
734

Matt Mackall's avatar
Matt Mackall committed
735 736
    .. container:: verbose

737 738 739 740 741 742 743 744 745 746 747 748
      Examples:

      - Reverse the effect of the parent of the working directory.
        This backout will be committed immediately::

          hg backout -r .

      - Reverse the effect of previous bad revision 23::

          hg backout -r 23

      - Reverse the effect of previous bad revision 23 and
749
        leave changes uncommitted::
750

751 752
          hg backout -r 23 --no-commit
          hg commit -m "Backout revision 23"
753

Matt Mackall's avatar
Matt Mackall committed
754 755 756 757 758 759 760 761 762
      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.
763

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

766 767 768
    See :hg:`help revert` for a way to restore files to the state
    of another revision.

769 770
    Returns 0 on success, 1 if nothing to backout or there are unresolved
    files.