summaryrefslogtreecommitdiff
path: root/eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/mercurial/commands.py
diff options
context:
space:
mode:
Diffstat (limited to 'eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/mercurial/commands.py')
-rw-r--r--eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/mercurial/commands.py4530
1 files changed, 4530 insertions, 0 deletions
diff --git a/eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/mercurial/commands.py b/eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/mercurial/commands.py
new file mode 100644
index 0000000..ce27a3e
--- /dev/null
+++ b/eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/mercurial/commands.py
@@ -0,0 +1,4530 @@
+# commands.py - command processing for mercurial
+#
+# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+from node import hex, nullid, nullrev, short
+from lock import release
+from i18n import _, gettext
+import os, re, sys, difflib, time, tempfile
+import hg, util, revlog, extensions, copies, error
+import patch, help, mdiff, url, encoding, templatekw, discovery
+import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
+import merge as mergemod
+import minirst, revset
+import dagparser
+
+# Commands start here, listed alphabetically
+
+def add(ui, repo, *pats, **opts):
+ """add the specified files on the next commit
+
+ Schedule files to be version controlled and added to the
+ repository.
+
+ The files will be added to the repository at the next commit. To
+ undo an add before that, see :hg:`forget`.
+
+ If no names are given, add all files to the repository.
+
+ .. container:: verbose
+
+ An example showing how 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
+
+ Returns 0 if all files are successfully added.
+ """
+
+ m = cmdutil.match(repo, pats, opts)
+ rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
+ opts.get('subrepos'), prefix="")
+ return rejected and 1 or 0
+
+def addremove(ui, repo, *pats, **opts):
+ """add all new files, delete all missing files
+
+ Add all new files and remove all missing files from the
+ repository.
+
+ New files are ignored if they match any of the patterns in
+ .hgignore. As with add, these changes take effect at the next
+ commit.
+
+ 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
+ can be expensive. After using this option, :hg:`status -C` can be
+ used to check which files were identified as moved or renamed.
+
+ Returns 0 if all files are successfully added.
+ """
+ try:
+ sim = float(opts.get('similarity') or 100)
+ except ValueError:
+ raise util.Abort(_('similarity must be a number'))
+ if sim < 0 or sim > 100:
+ raise util.Abort(_('similarity must be between 0 and 100'))
+ return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
+
+def annotate(ui, repo, *pats, **opts):
+ """show changeset information by line for each file
+
+ List changes in files, showing the revision id responsible for
+ each line
+
+ This command is useful for discovering when a change was made and
+ by whom.
+
+ 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.
+
+ Returns 0 on success.
+ """
+ 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
+ opts['file'] = 1
+
+ datefunc = ui.quiet and util.shortdate or util.datestr
+ getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
+
+ if not pats:
+ raise util.Abort(_('at least one filename or pattern is required'))
+
+ 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()),
+ ]
+
+ if (not opts.get('user') and not opts.get('changeset')
+ and not opts.get('date') and not opts.get('file')):
+ opts['number'] = 1
+
+ linenumber = opts.get('line_number') is not None
+ if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
+ raise util.Abort(_('at least one of -n/-c is required for -l'))
+
+ funcmap = [func for op, func in opmap if opts.get(op)]
+ if linenumber:
+ lastfunc = funcmap[-1]
+ funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
+
+ ctx = repo[opts.get('rev')]
+ m = cmdutil.match(repo, pats, opts)
+ follow = not opts.get('no_follow')
+ for abs in ctx.walk(m):
+ fctx = ctx[abs]
+ if not opts.get('text') and util.binary(fctx.data()):
+ ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
+ continue
+
+ lines = fctx.annotate(follow=follow, linenumber=linenumber)
+ pieces = []
+
+ for f in funcmap:
+ l = [f(n) for n, dummy in lines]
+ if l:
+ sized = [(x, encoding.colwidth(x)) for x in l]
+ ml = max([w for x, w in sized])
+ pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
+
+ if pieces:
+ for p, l in zip(zip(*pieces), lines):
+ ui.write("%s: %s" % (" ".join(p), l[1]))
+
+def archive(ui, repo, dest, **opts):
+ '''create an unversioned archive of a repository revision
+
+ By default, the revision used is the parent of the working
+ directory; use -r/--rev to specify a different revision.
+
+ The archive type is automatically detected based on file
+ extension (or override using -t/--type).
+
+ Valid types are:
+
+ :``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
+
+ The exact name of the destination archive or directory is given
+ using a format string; see :hg:`help export` for details.
+
+ 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.
+
+ Returns 0 on success.
+ '''
+
+ ctx = repo[opts.get('rev')]
+ if not ctx:
+ raise util.Abort(_('no working directory: please specify a revision'))
+ node = ctx.node()
+ dest = cmdutil.make_filename(repo, dest, node)
+ if os.path.realpath(dest) == repo.root:
+ raise util.Abort(_('repository root cannot be destination'))
+
+ kind = opts.get('type') or archival.guesskind(dest) or 'files'
+ prefix = opts.get('prefix')
+
+ if dest == '-':
+ if kind == 'files':
+ raise util.Abort(_('cannot archive plain files to stdout'))
+ dest = sys.stdout
+ if not prefix:
+ prefix = os.path.basename(repo.root) + '-%h'
+
+ prefix = cmdutil.make_filename(repo, prefix, node)
+ matchfn = cmdutil.match(repo, [], opts)
+ archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
+ matchfn, prefix, subrepos=opts.get('subrepos'))
+
+def backout(ui, repo, node=None, rev=None, **opts):
+ '''reverse effect of earlier changeset
+
+ The backout command merges the reverse effect of the reverted
+ changeset into the working directory.
+
+ With the --merge option, it first commits the reverted changes
+ as a new changeset. This new changeset is a child of the reverted
+ changeset.
+ The --merge option remembers the parent of the working directory
+ before starting the backout, then merges the new head with that
+ changeset afterwards.
+ This will result in an explicit merge in the history.
+
+ If you backout a changeset other than the original parent of the
+ working directory, the result of this merge is not committed,
+ as with a normal merge. Otherwise, no merge is needed and the
+ commit is automatic.
+
+ Note that the default behavior (without --merge) has changed in
+ version 1.7. To restore the previous default behavior, use
+ :hg:`backout --merge` and then :hg:`update --clean .` to get rid of
+ the ongoing merge.
+
+ See :hg:`help dates` for a list of formats valid for -d/--date.
+
+ Returns 0 on success.
+ '''
+ if rev and node:
+ raise util.Abort(_("please specify just one revision"))
+
+ if not rev:
+ rev = node
+
+ if not rev:
+ raise util.Abort(_("please specify a revision to backout"))
+
+ date = opts.get('date')
+ if date:
+ opts['date'] = util.parsedate(date)
+
+ cmdutil.bail_if_changed(repo)
+ node = repo.lookup(rev)
+
+ op1, op2 = repo.dirstate.parents()
+ a = repo.changelog.ancestor(op1, node)
+ if a != node:
+ raise util.Abort(_('cannot backout change on a different branch'))
+
+ p1, p2 = repo.changelog.parents(node)
+ if p1 == nullid:
+ raise util.Abort(_('cannot backout a change with no parents'))
+ if p2 != nullid:
+ if not opts.get('parent'):
+ raise util.Abort(_('cannot backout a merge changeset without '
+ '--parent'))
+ p = repo.lookup(opts['parent'])
+ if p not in (p1, p2):
+ raise util.Abort(_('%s is not a parent of %s') %
+ (short(p), short(node)))
+ parent = p
+ else:
+ if opts.get('parent'):
+ raise util.Abort(_('cannot use --parent on non-merge changeset'))
+ parent = p1
+
+ # the backout should appear on the same branch
+ branch = repo.dirstate.branch()
+ hg.clean(repo, node, show_stats=False)
+ repo.dirstate.setbranch(branch)
+ revert_opts = opts.copy()
+ revert_opts['date'] = None
+ revert_opts['all'] = True
+ revert_opts['rev'] = hex(parent)
+ revert_opts['no_backup'] = None
+ revert(ui, repo, **revert_opts)
+ if not opts.get('merge') and op1 != node:
+ try:
+ ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
+ return hg.update(repo, op1)
+ finally:
+ ui.setconfig('ui', 'forcemerge', '')
+
+ commit_opts = opts.copy()
+ commit_opts['addremove'] = False
+ if not commit_opts['message'] and not commit_opts['logfile']:
+ # we don't translate commit messages
+ commit_opts['message'] = "Backed out changeset %s" % short(node)
+ commit_opts['force_editor'] = True
+ 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)))
+ if opts.get('merge') and op1 != node:
+ hg.clean(repo, op1, show_stats=False)
+ ui.status(_('merging with changeset %s\n')
+ % nice(repo.changelog.tip()))
+ try:
+ ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
+ return hg.merge(repo, hex(repo.changelog.tip()))
+ finally:
+ ui.setconfig('ui', 'forcemerge', '')
+ return 0
+
+def bisect(ui, repo, rev=None, extra=None, command=None,
+ reset=None, good=None, bad=None, skip=None, noupdate=None):
+ """subdivision search of changesets
+
+ 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.
+
+ Returns 0 on success.
+ """
+ def print_result(nodes, good):
+ displayer = cmdutil.show_changeset(ui, repo, {})
+ if len(nodes) == 1:
+ # narrowed it down to a single revision
+ if good:
+ ui.write(_("The first good revision is:\n"))
+ else:
+ ui.write(_("The first bad revision is:\n"))
+ displayer.show(repo[nodes[0]])
+ 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:
+ common = parents[0].ancestor(parents[1])
+ ui.write(_('Not all ancestors of this changeset have been'
+ ' checked.\nTo check the other ancestors, start'
+ ' from the common ancestor, %s.\n' % common))
+ else:
+ # multiple possible revisions
+ 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"))
+ for n in nodes:
+ displayer.show(repo[n])
+ displayer.close()
+
+ 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
+
+ # 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
+ elif extra or good + bad + skip + reset + bool(command) > 1:
+ raise util.Abort(_('incompatible arguments'))
+
+ if reset:
+ p = repo.join("bisect.state")
+ if os.path.exists(p):
+ os.unlink(p)
+ return
+
+ state = hbisect.load_state(repo)
+
+ if command:
+ changesets = 1
+ try:
+ while changesets:
+ # update state
+ status = util.system(command)
+ 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"
+ ctx = repo[rev or '.']
+ state[transition].append(ctx.node())
+ ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
+ check_state(state, interactive=False)
+ # bisect
+ nodes, changesets, good = hbisect.bisect(repo.changelog, state)
+ # update to next check
+ cmdutil.bail_if_changed(repo)
+ hg.clean(repo, nodes[0], show_stats=False)
+ finally:
+ hbisect.save_state(repo, state)
+ print_result(nodes, good)
+ return
+
+ # update state
+
+ if rev:
+ nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])]
+ else:
+ nodes = [repo.lookup('.')]
+
+ if good or bad or skip:
+ if good:
+ state['good'] += nodes
+ elif bad:
+ state['bad'] += nodes
+ elif skip:
+ state['skip'] += nodes
+ hbisect.save_state(repo, state)
+
+ if not check_state(state):
+ return
+
+ # actually bisect
+ nodes, changesets, good = hbisect.bisect(repo.changelog, state)
+ if changesets == 0:
+ print_result(nodes, good)
+ else:
+ assert len(nodes) == 1 # only a single node can be tested next
+ node = nodes[0]
+ # 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)
+ ui.write(_("Testing changeset %d:%s "
+ "(%d changesets remaining, ~%d tests)\n")
+ % (rev, short(node), changesets, tests))
+ if not noupdate:
+ cmdutil.bail_if_changed(repo)
+ return hg.clean(repo, node)
+
+def branch(ui, repo, label=None, **opts):
+ """set or show the current branch name
+
+ 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.
+
+ Unless -f/--force is specified, branch will not let you set a
+ branch name that already exists, even if it's inactive.
+
+ Use -C/--clean to reset the working directory branch to that of
+ the parent of the working directory, negating a previous branch
+ change.
+
+ Use the command :hg:`update` to switch to an existing branch. Use
+ :hg:`commit --close-branch` to mark this branch as closed.
+
+ Returns 0 on success.
+ """
+
+ if opts.get('clean'):
+ label = repo[None].parents()[0].branch()
+ repo.dirstate.setbranch(label)
+ ui.status(_('reset working directory to branch %s\n') % label)
+ elif label:
+ utflabel = encoding.fromlocal(label)
+ if not opts.get('force') and utflabel in repo.branchtags():
+ if label not in [p.branch() for p in repo.parents()]:
+ raise util.Abort(_('a branch of the same name already exists'
+ " (use 'hg update' to switch to it)"))
+ repo.dirstate.setbranch(utflabel)
+ ui.status(_('marked working directory as branch %s\n') % label)
+ else:
+ ui.write("%s\n" % encoding.tolocal(repo.dirstate.branch()))
+
+def branches(ui, repo, active=False, closed=False):
+ """list repository named branches
+
+ List the repository's named branches, indicating which ones are
+ inactive. If -c/--closed is specified, also list branches which have
+ been marked closed (see :hg:`commit --close-branch`).
+
+ If -a/--active is specified, only show active branches. A branch
+ is considered active if it contains repository heads.
+
+ Use the command :hg:`update` to switch to an existing branch.
+
+ Returns 0.
+ """
+
+ hexfunc = ui.debugflag and hex or short
+ activebranches = [repo[n].branch() for n in repo.heads()]
+ 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)
+ for tag, node in repo.branchtags().items()],
+ reverse=True)
+
+ for isactive, node, tag in branches:
+ if (not active) or isactive:
+ encodedtag = encoding.tolocal(tag)
+ if ui.quiet:
+ ui.write("%s\n" % encodedtag)
+ else:
+ hn = repo.lookup(node)
+ if isactive:
+ label = 'branches.active'
+ notice = ''
+ elif hn not in repo.branchheads(tag, closed=False):
+ if not closed:
+ continue
+ label = 'branches.closed'
+ notice = _(' (closed)')
+ else:
+ label = 'branches.inactive'
+ notice = _(' (inactive)')
+ if tag == repo.dirstate.branch():
+ label = 'branches.current'
+ rev = str(node).rjust(31 - encoding.colwidth(encodedtag))
+ rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
+ encodedtag = ui.label(encodedtag, label)
+ ui.write("%s %s%s\n" % (encodedtag, rev, notice))
+
+def bundle(ui, repo, fname, dest=None, **opts):
+ """create a changegroup file
+
+ Generate a compressed changegroup file collecting changesets not
+ known to be in another repository.
+
+ If you omit the destination repository, then hg assumes the
+ destination will have all the nodes you specify with --base
+ parameters. To create a bundle containing all changesets, use
+ -a/--all (or --base null).
+
+ You can change compression method with the -t/--type option.
+ The available compression methods are: none, bzip2, and
+ gzip (by default, bundles are compressed using bzip2).
+
+ The bundle file can then be transferred using conventional means
+ and applied to another repository with the unbundle or pull
+ command. This is useful when direct push and pull are not
+ available or when exporting an entire repository is undesirable.
+
+ Applying bundles preserves all changeset contents including
+ permissions, copy/rename information, and revision history.
+
+ Returns 0 on success, 1 if no changes found.
+ """
+ revs = opts.get('rev') or None
+ if opts.get('all'):
+ base = ['null']
+ else:
+ base = opts.get('base')
+ if base:
+ if dest:
+ raise util.Abort(_("--base is incompatible with specifying "
+ "a destination"))
+ base = [repo.lookup(rev) for rev in base]
+ # create the right base
+ # XXX: nodesbetween / changegroup* should be "fixed" instead
+ o = []
+ has = set((nullid,))
+ for n in base:
+ has.update(repo.changelog.reachable(n))
+ if revs:
+ revs = [repo.lookup(rev) for rev in revs]
+ visit = revs[:]
+ has.difference_update(visit)
+ else:
+ visit = repo.changelog.heads()
+ seen = {}
+ while visit:
+ n = visit.pop(0)
+ parents = [p for p in repo.changelog.parents(n) if p not in has]
+ if len(parents) == 0:
+ if n not in has:
+ o.append(n)
+ else:
+ for p in parents:
+ if p not in seen:
+ seen[p] = 1
+ visit.append(p)
+ else:
+ dest = ui.expandpath(dest or 'default-push', dest or 'default')
+ dest, branches = hg.parseurl(dest, opts.get('branch'))
+ other = hg.repository(hg.remoteui(repo, opts), dest)
+ revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
+ if revs:
+ revs = [repo.lookup(rev) for rev in revs]
+ o = discovery.findoutgoing(repo, other, force=opts.get('force'))
+
+ if not o:
+ ui.status(_("no changes found\n"))
+ return 1
+
+ if revs:
+ cg = repo.changegroupsubset(o, revs, 'bundle')
+ else:
+ cg = repo.changegroup(o, 'bundle')
+
+ bundletype = opts.get('type', 'bzip2').lower()
+ btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
+ bundletype = btypes.get(bundletype)
+ if bundletype not in changegroup.bundletypes:
+ raise util.Abort(_('unknown bundle type specified with --type'))
+
+ changegroup.writebundle(cg, fname, bundletype)
+
+def cat(ui, repo, file1, *pats, **opts):
+ """output the current or given revision of files
+
+ Print the specified files as they were at the given revision. If
+ no revision is given, the parent of the working directory is used,
+ or tip if no revision is checked out.
+
+ Output may be to a file, in which case the name of the file is
+ given using a format string. The formatting rules are the same as
+ for the export command, with the following additions:
+
+ :``%s``: basename of file being printed
+ :``%d``: dirname of file being printed, or '.' if in repository root
+ :``%p``: root-relative path name of file being printed
+
+ Returns 0 on success.
+ """
+ ctx = cmdutil.revsingle(repo, opts.get('rev'))
+ err = 1
+ m = cmdutil.match(repo, (file1,) + pats, opts)
+ for abs in ctx.walk(m):
+ fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
+ data = ctx[abs].data()
+ if opts.get('decode'):
+ data = repo.wwritedata(abs, data)
+ fp.write(data)
+ err = 0
+ return err
+
+def clone(ui, source, dest=None, **opts):
+ """make a copy of an existing repository
+
+ Create a copy of an existing repository in a new directory.
+
+ If no destination directory name is specified, it defaults to the
+ basename of the source.
+
+ The location of the source is added to the new repository's
+ .hg/hgrc file, as the default to be used for future pulls.
+
+ See :hg:`help urls` for valid source format details.
+
+ It is possible to specify an ``ssh://`` URL as the destination, but no
+ .hg/hgrc and working directory will be created on the remote side.
+ Please see :hg:`help urls` for important details about ``ssh://`` URLs.
+
+ A set of changesets (tags, or branch names) to pull may be specified
+ by listing each changeset (tag, or branch name) with -r/--rev.
+ If -r/--rev is used, the cloned repository will contain only a subset
+ of the changesets of the source repository. Only the set of changesets
+ defined by all -r/--rev options (including all their ancestors)
+ will be pulled into the destination repository.
+ No subsequent changesets (including subsequent tags) will be present
+ in the destination.
+
+ Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
+ local source repositories.
+
+ For efficiency, hardlinks are used for cloning whenever the source
+ and destination are on the same filesystem (note this applies only
+ to the repository data, not to the working directory). Some
+ filesystems, such as AFS, implement hardlinking incorrectly, but
+ do not report errors. In these cases, use the --pull option to
+ avoid hardlinking.
+
+ In some cases, you can clone repositories and the working directory
+ using full hardlinks with ::
+
+ $ cp -al REPO REPOCLONE
+
+ This is the fastest way to clone, but it is not always safe. The
+ operation is not atomic (making sure REPO is not modified during
+ the operation is up to you) and you have to make sure your editor
+ breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
+ this is not compatible with certain extensions that place their
+ metadata under the .hg directory, such as mq.
+
+ Mercurial will update the working directory to the first applicable
+ revision from this list:
+
+ a) null if -U or the source repository has no changesets
+ b) if -u . and the source repository is local, the first parent of
+ the source repository's working directory
+ c) the changeset specified with -u (if a branch name, this means the
+ latest head of that branch)
+ d) the changeset specified with -r
+ e) the tipmost head specified with -b
+ f) the tipmost head specified with the url#branch source syntax
+ g) the tipmost head of the default branch
+ h) tip
+
+ Returns 0 on success.
+ """
+ if opts.get('noupdate') and opts.get('updaterev'):
+ raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
+
+ r = hg.clone(hg.remoteui(ui, opts), source, dest,
+ pull=opts.get('pull'),
+ stream=opts.get('uncompressed'),
+ rev=opts.get('rev'),
+ update=opts.get('updaterev') or not opts.get('noupdate'),
+ branch=opts.get('branch'))
+
+ return r is None
+
+def commit(ui, repo, *pats, **opts):
+ """commit the specified files or all outstanding changes
+
+ Commit changes to the given files into the repository. Unlike a
+ centralized RCS, this operation is a local operation. See
+ :hg:`push` for a way to actively distribute your changes.
+
+ If a list of files is omitted, all changes reported by :hg:`status`
+ will be committed.
+
+ If you are committing the result of a merge, do not provide any
+ filenames or -I/-X filters.
+
+ If no commit message is specified, Mercurial starts your
+ configured editor where you can enter a message. In case your
+ commit fails, you will find a backup of your message in
+ ``.hg/last-message.txt``.
+
+ See :hg:`help dates` for a list of formats valid for -d/--date.
+
+ Returns 0 on success, 1 if nothing changed.
+ """
+ extra = {}
+ if opts.get('close_branch'):
+ if repo['.'].node() not in repo.branchheads():
+ # The topo heads set is included in the branch heads set of the
+ # current branch, so it's sufficient to test branchheads
+ raise util.Abort(_('can only close branch heads'))
+ extra['close'] = 1
+ e = cmdutil.commiteditor
+ if opts.get('force_editor'):
+ e = cmdutil.commitforceeditor
+
+ def commitfunc(ui, repo, message, match, opts):
+ return repo.commit(message, opts.get('user'), opts.get('date'), match,
+ editor=e, extra=extra)
+
+ branch = repo[None].branch()
+ bheads = repo.branchheads(branch)
+
+ node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
+ if not node:
+ ui.status(_("nothing changed\n"))
+ return 1
+
+ ctx = repo[node]
+ parents = ctx.parents()
+
+ if bheads and not [x for x in parents
+ if x.node() in bheads and x.branch() == branch]:
+ ui.status(_('created new head\n'))
+ # The message is not printed for initial roots. For the other
+ # changesets, it is printed in the following situations:
+ #
+ # Par column: for the 2 parents with ...
+ # N: null or no parent
+ # B: parent is on another named branch
+ # C: parent is a regular non head changeset
+ # H: parent was a branch head of the current branch
+ # Msg column: whether we print "created new head" message
+ # In the following, it is assumed that there already exists some
+ # initial branch heads of the current branch, otherwise nothing is
+ # printed anyway.
+ #
+ # Par Msg Comment
+ # NN y additional topo root
+ #
+ # BN y additional branch root
+ # CN y additional topo head
+ # HN n usual case
+ #
+ # BB y weird additional branch root
+ # CB y branch merge
+ # HB n merge with named branch
+ #
+ # CC y additional head from merge
+ # CH n merge with a head
+ #
+ # HH n head merge: head count decreases
+
+ if not opts.get('close_branch'):
+ for r in parents:
+ if r.extra().get('close') and r.branch() == branch:
+ ui.status(_('reopening closed branch head %d\n') % r)
+
+ if ui.debugflag:
+ ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
+ elif ui.verbose:
+ ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
+
+def copy(ui, repo, *pats, **opts):
+ """mark files as copied for the next commit
+
+ Mark dest as having copies of source files. If dest is a
+ directory, copies are put in that directory. If dest is a file,
+ the source must be a single file.
+
+ By default, this command copies the contents of files as they
+ exist in the working directory. If invoked with -A/--after, the
+ operation is recorded, but no copying is performed.
+
+ This command takes effect with the next commit. To undo a copy
+ before that, see :hg:`revert`.
+
+ Returns 0 on success, 1 if errors are encountered.
+ """
+ wlock = repo.wlock(False)
+ try:
+ return cmdutil.copy(ui, repo, pats, opts)
+ finally:
+ wlock.release()
+
+def debugancestor(ui, repo, *args):
+ """find the ancestor revision of two revisions in a given index"""
+ if len(args) == 3:
+ index, rev1, rev2 = args
+ r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
+ lookup = r.lookup
+ elif len(args) == 2:
+ if not repo:
+ raise util.Abort(_("there is no Mercurial repository here "
+ "(.hg not found)"))
+ rev1, rev2 = args
+ r = repo.changelog
+ lookup = repo.lookup
+ else:
+ raise util.Abort(_('either two or three arguments required'))
+ a = r.ancestor(lookup(rev1), lookup(rev2))
+ ui.write("%d:%s\n" % (r.rev(a), hex(a)))
+
+def debugbuilddag(ui, repo, text,
+ mergeable_file=False,
+ appended_file=False,
+ overwritten_file=False,
+ new_file=False):
+ """builds a repo with a given dag from scratch in the current empty repo
+
+ Elements:
+
+ - "+n" is a linear run of n nodes based on the current default parent
+ - "." is a single node based on the current default parent
+ - "$" resets the default parent to null (implied at the start);
+ otherwise the default parent is always the last node created
+ - "<p" sets the default parent to the backref p
+ - "*p" is a fork at parent p, which is a backref
+ - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
+ - "/p2" is a merge of the preceding node and p2
+ - ":tag" defines a local tag for the preceding node
+ - "@branch" sets the named branch for subsequent nodes
+ - "!command" runs the command using your shell
+ - "!!my command\\n" is like "!", but to the end of the line
+ - "#...\\n" is a comment up to the end of the line
+
+ Whitespace between the above elements is ignored.
+
+ A backref is either
+
+ - a number n, which references the node curr-n, where curr is the current
+ node, or
+ - the name of a local tag you placed earlier using ":tag", or
+ - empty to denote the default parent.
+
+ All string valued-elements are either strictly alphanumeric, or must
+ be enclosed in double quotes ("..."), with "\\" as escape character.
+
+ Note that the --overwritten-file and --appended-file options imply the
+ use of "HGMERGE=internal:local" during DAG buildup.
+ """
+
+ if not (mergeable_file or appended_file or overwritten_file or new_file):
+ raise util.Abort(_('need at least one of -m, -a, -o, -n'))
+
+ if len(repo.changelog) > 0:
+ raise util.Abort(_('repository is not empty'))
+
+ if overwritten_file or appended_file:
+ # we don't want to fail in merges during buildup
+ os.environ['HGMERGE'] = 'internal:local'
+
+ def writefile(fname, text, fmode="wb"):
+ f = open(fname, fmode)
+ try:
+ f.write(text)
+ finally:
+ f.close()
+
+ if mergeable_file:
+ linesperrev = 2
+ # determine number of revs in DAG
+ n = 0
+ for type, data in dagparser.parsedag(text):
+ if type == 'n':
+ n += 1
+ # make a file with k lines per rev
+ writefile("mf", "\n".join(str(i) for i in xrange(0, n * linesperrev))
+ + "\n")
+
+ at = -1
+ atbranch = 'default'
+ for type, data in dagparser.parsedag(text):
+ if type == 'n':
+ ui.status('node %s\n' % str(data))
+ id, ps = data
+ p1 = ps[0]
+ if p1 != at:
+ update(ui, repo, node=str(p1), clean=True)
+ at = p1
+ if repo.dirstate.branch() != atbranch:
+ branch(ui, repo, atbranch, force=True)
+ if len(ps) > 1:
+ p2 = ps[1]
+ merge(ui, repo, node=p2)
+
+ if mergeable_file:
+ f = open("mf", "rb+")
+ try:
+ lines = f.read().split("\n")
+ lines[id * linesperrev] += " r%i" % id
+ f.seek(0)
+ f.write("\n".join(lines))
+ finally:
+ f.close()
+
+ if appended_file:
+ writefile("af", "r%i\n" % id, "ab")
+
+ if overwritten_file:
+ writefile("of", "r%i\n" % id)
+
+ if new_file:
+ writefile("nf%i" % id, "r%i\n" % id)
+
+ commit(ui, repo, addremove=True, message="r%i" % id, date=(id, 0))
+ at = id
+ elif type == 'l':
+ id, name = data
+ ui.status('tag %s\n' % name)
+ tag(ui, repo, name, local=True)
+ elif type == 'a':
+ ui.status('branch %s\n' % data)
+ atbranch = data
+ elif type in 'cC':
+ r = util.system(data, cwd=repo.root)
+ if r:
+ desc, r = util.explain_exit(r)
+ raise util.Abort(_('%s command %s') % (data, desc))
+
+def debugcommands(ui, cmd='', *args):
+ """list all available commands and options"""
+ for cmd, vals in sorted(table.iteritems()):
+ cmd = cmd.split('|')[0].strip('^')
+ opts = ', '.join([i[1] for i in vals[1]])
+ ui.write('%s: %s\n' % (cmd, opts))
+
+def debugcomplete(ui, cmd='', **opts):
+ """returns the completion list associated with the given command"""
+
+ if opts.get('options'):
+ options = []
+ otables = [globalopts]
+ if cmd:
+ aliases, entry = cmdutil.findcmd(cmd, table, False)
+ otables.append(entry[1])
+ for t in otables:
+ for o in t:
+ if "(DEPRECATED)" in o[3]:
+ continue
+ if o[0]:
+ options.append('-%s' % o[0])
+ options.append('--%s' % o[1])
+ ui.write("%s\n" % "\n".join(options))
+ return
+
+ cmdlist = cmdutil.findpossible(cmd, table)
+ if ui.verbose:
+ cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
+ ui.write("%s\n" % "\n".join(sorted(cmdlist)))
+
+def debugfsinfo(ui, path = "."):
+ """show information detected about current filesystem"""
+ open('.debugfsinfo', 'w').write('')
+ ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
+ ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
+ ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
+ and 'yes' or 'no'))
+ os.unlink('.debugfsinfo')
+
+def debugrebuildstate(ui, repo, rev="tip"):
+ """rebuild the dirstate as it would look like for the given revision"""
+ ctx = repo[rev]
+ wlock = repo.wlock()
+ try:
+ repo.dirstate.rebuild(ctx.node(), ctx.manifest())
+ finally:
+ wlock.release()
+
+def debugcheckstate(ui, repo):
+ """validate the correctness of the current dirstate"""
+ parent1, parent2 = repo.dirstate.parents()
+ m1 = repo[parent1].manifest()
+ m2 = repo[parent2].manifest()
+ errors = 0
+ for f in repo.dirstate:
+ state = repo.dirstate[f]
+ if state in "nr" and f not in m1:
+ ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
+ errors += 1
+ if state in "a" and f in m1:
+ ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
+ errors += 1
+ if state in "m" and f not in m1 and f not in m2:
+ ui.warn(_("%s in state %s, but not in either manifest\n") %
+ (f, state))
+ errors += 1
+ for f in m1:
+ state = repo.dirstate[f]
+ if state not in "nrm":
+ ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
+ errors += 1
+ if errors:
+ error = _(".hg/dirstate inconsistent with current parent's manifest")
+ raise util.Abort(error)
+
+def showconfig(ui, repo, *values, **opts):
+ """show combined config settings from all hgrc files
+
+ With no arguments, print names and values of all config items.
+
+ With one argument of the form section.name, print just the value
+ of that config item.
+
+ With multiple arguments, print names and values of all config
+ items with matching section names.
+
+ With --debug, the source (filename and line number) is printed
+ for each config item.
+
+ Returns 0 on success.
+ """
+
+ for f in util.rcpath():
+ ui.debug(_('read config from: %s\n') % f)
+ untrusted = bool(opts.get('untrusted'))
+ if values:
+ sections = [v for v in values if '.' not in v]
+ items = [v for v in values if '.' in v]
+ if len(items) > 1 or items and sections:
+ raise util.Abort(_('only one config item permitted'))
+ for section, name, value in ui.walkconfig(untrusted=untrusted):
+ sectname = section + '.' + name
+ if values:
+ for v in values:
+ if v == section:
+ ui.debug('%s: ' %
+ ui.configsource(section, name, untrusted))
+ ui.write('%s=%s\n' % (sectname, value))
+ elif v == sectname:
+ ui.debug('%s: ' %
+ ui.configsource(section, name, untrusted))
+ ui.write(value, '\n')
+ else:
+ ui.debug('%s: ' %
+ ui.configsource(section, name, untrusted))
+ ui.write('%s=%s\n' % (sectname, value))
+
+def debugpushkey(ui, repopath, namespace, *keyinfo):
+ '''access the pushkey key/value protocol
+
+ With two args, list the keys in the given namespace.
+
+ With five args, set a key to new if it currently is set to old.
+ Reports success or failure.
+ '''
+
+ target = hg.repository(ui, repopath)
+ if keyinfo:
+ key, old, new = keyinfo
+ r = target.pushkey(namespace, key, old, new)
+ ui.status(str(r) + '\n')
+ return not(r)
+ else:
+ for k, v in target.listkeys(namespace).iteritems():
+ ui.write("%s\t%s\n" % (k.encode('string-escape'),
+ v.encode('string-escape')))
+
+def debugrevspec(ui, repo, expr):
+ '''parse and apply a revision specification'''
+ if ui.verbose:
+ tree = revset.parse(expr)
+ ui.note(tree, "\n")
+ func = revset.match(expr)
+ for c in func(repo, range(len(repo))):
+ ui.write("%s\n" % c)
+
+def debugsetparents(ui, repo, rev1, rev2=None):
+ """manually set the parents of the current working directory
+
+ This is useful for writing repository conversion tools, but should
+ be used with care.
+
+ Returns 0 on success.
+ """
+
+ if not rev2:
+ rev2 = hex(nullid)
+
+ wlock = repo.wlock()
+ try:
+ repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
+ finally:
+ wlock.release()
+
+def debugstate(ui, repo, nodates=None):
+ """show the contents of the current dirstate"""
+ timestr = ""
+ showdate = not nodates
+ for file_, ent in sorted(repo.dirstate._map.iteritems()):
+ if showdate:
+ if ent[3] == -1:
+ # Pad or slice to locale representation
+ locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
+ time.localtime(0)))
+ timestr = 'unset'
+ timestr = (timestr[:locale_len] +
+ ' ' * (locale_len - len(timestr)))
+ else:
+ timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
+ time.localtime(ent[3]))
+ if ent[1] & 020000:
+ mode = 'lnk'
+ else:
+ mode = '%3o' % (ent[1] & 0777)
+ ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
+ for f in repo.dirstate.copies():
+ ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
+
+def debugsub(ui, repo, rev=None):
+ if rev == '':
+ rev = None
+ for k, v in sorted(repo[rev].substate.items()):
+ ui.write('path %s\n' % k)
+ ui.write(' source %s\n' % v[0])
+ ui.write(' revision %s\n' % v[1])
+
+def debugdag(ui, repo, file_=None, *revs, **opts):
+ """format the changelog or an index DAG as a concise textual description
+
+ If you pass a revlog index, the revlog's DAG is emitted. If you list
+ revision numbers, they get labelled in the output as rN.
+
+ Otherwise, the changelog DAG of the current repo is emitted.
+ """
+ spaces = opts.get('spaces')
+ dots = opts.get('dots')
+ if file_:
+ rlog = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
+ revs = set((int(r) for r in revs))
+ def events():
+ for r in rlog:
+ yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
+ if r in revs:
+ yield 'l', (r, "r%i" % r)
+ elif repo:
+ cl = repo.changelog
+ tags = opts.get('tags')
+ branches = opts.get('branches')
+ if tags:
+ labels = {}
+ for l, n in repo.tags().items():
+ labels.setdefault(cl.rev(n), []).append(l)
+ def events():
+ b = "default"
+ for r in cl:
+ if branches:
+ newb = cl.read(cl.node(r))[5]['branch']
+ if newb != b:
+ yield 'a', newb
+ b = newb
+ yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
+ if tags:
+ ls = labels.get(r)
+ if ls:
+ for l in ls:
+ yield 'l', (r, l)
+ else:
+ raise util.Abort(_('need repo for changelog dag'))
+
+ for line in dagparser.dagtextlines(events(),
+ addspaces=spaces,
+ wraplabels=True,
+ wrapannotations=True,
+ wrapnonlinear=dots,
+ usedots=dots,
+ maxlinewidth=70):
+ ui.write(line)
+ ui.write("\n")
+
+def debugdata(ui, repo, file_, rev):
+ """dump the contents of a data file revision"""
+ r = None
+ if repo:
+ filelog = repo.file(file_)
+ if len(filelog):
+ r = filelog
+ if not r:
+ r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
+ try:
+ ui.write(r.revision(r.lookup(rev)))
+ except KeyError:
+ raise util.Abort(_('invalid revision identifier %s') % rev)
+
+def debugdate(ui, date, range=None, **opts):
+ """parse and display a date"""
+ if opts["extended"]:
+ d = util.parsedate(date, util.extendeddateformats)
+ else:
+ d = util.parsedate(date)
+ ui.write("internal: %s %s\n" % d)
+ ui.write("standard: %s\n" % util.datestr(d))
+ if range:
+ m = util.matchdate(range)
+ ui.write("match: %s\n" % m(d[0]))
+
+def debugindex(ui, repo, file_, **opts):
+ """dump the contents of an index file"""
+ r = None
+ if repo:
+ filelog = repo.file(file_)
+ if len(filelog):
+ r = filelog
+
+ format = opts.get('format', 0)
+ if format not in (0, 1):
+ raise util.Abort("unknown format %d" % format)
+
+ if not r:
+ r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
+
+ if format == 0:
+ ui.write(" rev offset length base linkrev"
+ " nodeid p1 p2\n")
+ elif format == 1:
+ ui.write(" rev flag offset length"
+ " size base link p1 p2 nodeid\n")
+
+ for i in r:
+ node = r.node(i)
+ if format == 0:
+ try:
+ pp = r.parents(node)
+ except:
+ pp = [nullid, nullid]
+ ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
+ i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
+ short(node), short(pp[0]), short(pp[1])))
+ elif format == 1:
+ pr = r.parentrevs(i)
+ ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
+ i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
+ r.base(i), r.linkrev(i), pr[0], pr[1], short(node)))
+
+def debugindexdot(ui, repo, file_):
+ """dump an index DAG as a graphviz dot file"""
+ r = None
+ if repo:
+ filelog = repo.file(file_)
+ if len(filelog):
+ r = filelog
+ if not r:
+ r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
+ ui.write("digraph G {\n")
+ for i in r:
+ node = r.node(i)
+ pp = r.parents(node)
+ ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
+ if pp[1] != nullid:
+ ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
+ ui.write("}\n")
+
+def debuginstall(ui):
+ '''test Mercurial installation
+
+ Returns 0 on success.
+ '''
+
+ def writetemp(contents):
+ (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
+ f = os.fdopen(fd, "wb")
+ f.write(contents)
+ f.close()
+ return name
+
+ problems = 0
+
+ # encoding
+ ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
+ try:
+ encoding.fromlocal("test")
+ except util.Abort, inst:
+ ui.write(" %s\n" % inst)
+ ui.write(_(" (check that your locale is properly set)\n"))
+ problems += 1
+
+ # compiled modules
+ ui.status(_("Checking installed modules (%s)...\n")
+ % os.path.dirname(__file__))
+ try:
+ import bdiff, mpatch, base85, osutil
+ except Exception, inst:
+ ui.write(" %s\n" % inst)
+ ui.write(_(" One or more extensions could not be found"))
+ ui.write(_(" (check that you compiled the extensions)\n"))
+ problems += 1
+
+ # templates
+ ui.status(_("Checking templates...\n"))
+ try:
+ import templater
+ templater.templater(templater.templatepath("map-cmdline.default"))
+ except Exception, inst:
+ ui.write(" %s\n" % inst)
+ ui.write(_(" (templates seem to have been installed incorrectly)\n"))
+ problems += 1
+
+ # patch
+ ui.status(_("Checking patch...\n"))
+ patchproblems = 0
+ a = "1\n2\n3\n4\n"
+ b = "1\n2\n3\ninsert\n4\n"
+ fa = writetemp(a)
+ d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
+ os.path.basename(fa))
+ fd = writetemp(d)
+
+ files = {}
+ try:
+ patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
+ except util.Abort, e:
+ ui.write(_(" patch call failed:\n"))
+ ui.write(" " + str(e) + "\n")
+ patchproblems += 1
+ else:
+ if list(files) != [os.path.basename(fa)]:
+ ui.write(_(" unexpected patch output!\n"))
+ patchproblems += 1
+ a = open(fa).read()
+ if a != b:
+ ui.write(_(" patch test failed!\n"))
+ patchproblems += 1
+
+ if patchproblems:
+ if ui.config('ui', 'patch'):
+ ui.write(_(" (Current patch tool may be incompatible with patch,"
+ " or misconfigured. Please check your configuration"
+ " file)\n"))
+ else:
+ ui.write(_(" Internal patcher failure, please report this error"
+ " to http://mercurial.selenic.com/wiki/BugTracker\n"))
+ problems += patchproblems
+
+ os.unlink(fa)
+ os.unlink(fd)
+
+ # editor
+ ui.status(_("Checking commit editor...\n"))
+ editor = ui.geteditor()
+ cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
+ if not cmdpath:
+ if editor == 'vi':
+ ui.write(_(" No commit editor set and can't find vi in PATH\n"))
+ ui.write(_(" (specify a commit editor in your configuration"
+ " file)\n"))
+ else:
+ ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
+ ui.write(_(" (specify a commit editor in your configuration"
+ " file)\n"))
+ problems += 1
+
+ # check username
+ ui.status(_("Checking username...\n"))
+ try:
+ ui.username()
+ except util.Abort, e:
+ ui.write(" %s\n" % e)
+ ui.write(_(" (specify a username in your configuration file)\n"))
+ problems += 1
+
+ if not problems:
+ ui.status(_("No problems detected\n"))
+ else:
+ ui.write(_("%s problems detected,"
+ " please check your install!\n") % problems)
+
+ return problems
+
+def debugrename(ui, repo, file1, *pats, **opts):
+ """dump rename information"""
+
+ ctx = repo[opts.get('rev')]
+ m = cmdutil.match(repo, (file1,) + pats, opts)
+ for abs in ctx.walk(m):
+ fctx = ctx[abs]
+ o = fctx.filelog().renamed(fctx.filenode())
+ rel = m.rel(abs)
+ if o:
+ ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
+ else:
+ ui.write(_("%s not renamed\n") % rel)
+
+def debugwalk(ui, repo, *pats, **opts):
+ """show how files match on given patterns"""
+ m = cmdutil.match(repo, pats, opts)
+ items = list(repo.walk(m))
+ if not items:
+ return
+ fmt = 'f %%-%ds %%-%ds %%s' % (
+ max([len(abs) for abs in items]),
+ max([len(m.rel(abs)) for abs in items]))
+ for abs in items:
+ line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
+ ui.write("%s\n" % line.rstrip())
+
+def diff(ui, repo, *pats, **opts):
+ """diff repository (or selected files)
+
+ Show differences between revisions for the specified files.
+
+ Differences between files are shown using the unified diff format.
+
+ .. note::
+ diff may generate unexpected results for merges, as it will
+ default to comparing against the working directory's first
+ parent changeset if no revisions are specified.
+
+ When two revision arguments are given, then changes are shown
+ between those revisions. If only one revision is specified then
+ that revision is compared to the working directory, and, when no
+ revisions are specified, the working directory files are compared
+ to its parent.
+
+ Alternatively you can specify -c/--change with a revision to see
+ the changes in that changeset relative to its first parent.
+
+ Without the -a/--text option, diff will avoid generating diffs of
+ files it detects as binary. With -a, diff will generate a diff
+ anyway, probably with undesirable results.
+
+ Use the -g/--git option to generate diffs in the git extended diff
+ format. For more information, read :hg:`help diffs`.
+
+ Returns 0 on success.
+ """
+
+ revs = opts.get('rev')
+ change = opts.get('change')
+ stat = opts.get('stat')
+ reverse = opts.get('reverse')
+
+ if revs and change:
+ msg = _('cannot specify --rev and --change at the same time')
+ raise util.Abort(msg)
+ elif change:
+ node2 = repo.lookup(change)
+ node1 = repo[node2].parents()[0].node()
+ else:
+ node1, node2 = cmdutil.revpair(repo, revs)
+
+ if reverse:
+ node1, node2 = node2, node1
+
+ diffopts = patch.diffopts(ui, opts)
+ m = cmdutil.match(repo, pats, opts)
+ cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
+ listsubrepos=opts.get('subrepos'))
+
+def export(ui, repo, *changesets, **opts):
+ """dump the header and diffs for one or more changesets
+
+ Print the changeset header and diffs for one or more revisions.
+
+ The information shown in the changeset header is: author, date,
+ branch name (if non-default), changeset hash, parent(s) and commit
+ comment.
+
+ .. note::
+ export may generate unexpected diff output for merge
+ changesets, as it will compare the merge changeset against its
+ first parent only.
+
+ Output may be to a file, in which case the name of the file is
+ given using a format string. The formatting rules are as follows:
+
+ :``%%``: literal "%" character
+ :``%H``: changeset hash (40 hexadecimal digits)
+ :``%N``: number of patches being generated
+ :``%R``: changeset revision number
+ :``%b``: basename of the exporting repository
+ :``%h``: short-form changeset hash (12 hexadecimal digits)
+ :``%n``: zero-padded sequence number, starting at 1
+ :``%r``: zero-padded changeset revision number
+
+ Without the -a/--text option, export will avoid generating diffs
+ of files it detects as binary. With -a, export will generate a
+ diff anyway, probably with undesirable results.
+
+ Use the -g/--git option to generate diffs in the git extended diff
+ format. See :hg:`help diffs` for more information.
+
+ With the --switch-parent option, the diff will be against the
+ second parent. It can be useful to review a merge.
+
+ Returns 0 on success.
+ """
+ changesets += tuple(opts.get('rev', []))
+ if not changesets:
+ raise util.Abort(_("export requires at least one changeset"))
+ revs = cmdutil.revrange(repo, changesets)
+ if len(revs) > 1:
+ ui.note(_('exporting patches:\n'))
+ else:
+ ui.note(_('exporting patch:\n'))
+ cmdutil.export(repo, revs, template=opts.get('output'),
+ switch_parent=opts.get('switch_parent'),
+ opts=patch.diffopts(ui, opts))
+
+def forget(ui, repo, *pats, **opts):
+ """forget the specified files on the next commit
+
+ Mark the specified files so they will no longer be tracked
+ after the next commit.
+
+ This only removes files from the current branch, not from the
+ entire project history, and it does not delete them from the
+ working directory.
+
+ To undo a forget before the next commit, see :hg:`add`.
+
+ Returns 0 on success.
+ """
+
+ if not pats:
+ raise util.Abort(_('no files specified'))
+
+ m = cmdutil.match(repo, pats, opts)
+ s = repo.status(match=m, clean=True)
+ forget = sorted(s[0] + s[1] + s[3] + s[6])
+ errs = 0
+
+ for f in m.files():
+ if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
+ ui.warn(_('not removing %s: file is already untracked\n')
+ % m.rel(f))
+ errs = 1
+
+ for f in forget:
+ if ui.verbose or not m.exact(f):
+ ui.status(_('removing %s\n') % m.rel(f))
+
+ repo[None].remove(forget, unlink=False)
+ return errs
+
+def grep(ui, repo, pattern, *pats, **opts):
+ """search for a pattern in specified files and revisions
+
+ Search revisions of files for a regular expression.
+
+ This command behaves differently than Unix grep. It only accepts
+ Python/Perl regexps. It searches repository history, not the
+ working directory. It always prints the revision number in which a
+ match appears.
+
+ By default, grep only prints output for the first revision of a
+ file in which it finds a match. To get it to print every revision
+ that contains a change in match status ("-" for a match that
+ becomes a non-match, or "+" for a non-match that becomes a match),
+ use the --all flag.
+
+ Returns 0 if a match is found, 1 otherwise.
+ """
+ reflags = 0
+ if opts.get('ignore_case'):
+ reflags |= re.I
+ try:
+ regexp = re.compile(pattern, reflags)
+ except re.error, inst:
+ ui.warn(_("grep: invalid match pattern: %s\n") % inst)
+ return 1
+ sep, eol = ':', '\n'
+ if opts.get('print0'):
+ sep = eol = '\0'
+
+ getfile = util.lrucachefunc(repo.file)
+
+ def matchlines(body):
+ begin = 0
+ linenum = 0
+ while True:
+ match = regexp.search(body, begin)
+ if not match:
+ break
+ mstart, mend = match.span()
+ linenum += body.count('\n', begin, mstart) + 1
+ lstart = body.rfind('\n', begin, mstart) + 1 or begin
+ begin = body.find('\n', mend) + 1 or len(body)
+ lend = begin - 1
+ yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
+
+ class linestate(object):
+ def __init__(self, line, linenum, colstart, colend):
+ self.line = line
+ self.linenum = linenum
+ self.colstart = colstart
+ self.colend = colend
+
+ def __hash__(self):
+ return hash((self.linenum, self.line))
+
+ def __eq__(self, other):
+ return self.line == other.line
+
+ matches = {}
+ copies = {}
+ def grepbody(fn, rev, body):
+ matches[rev].setdefault(fn, [])
+ m = matches[rev][fn]
+ for lnum, cstart, cend, line in matchlines(body):
+ s = linestate(line, lnum, cstart, cend)
+ m.append(s)
+
+ def difflinestates(a, b):
+ sm = difflib.SequenceMatcher(None, a, b)
+ for tag, alo, ahi, blo, bhi in sm.get_opcodes():
+ if tag == 'insert':
+ for i in xrange(blo, bhi):
+ yield ('+', b[i])
+ elif tag == 'delete':
+ for i in xrange(alo, ahi):
+ yield ('-', a[i])
+ elif tag == 'replace':
+ for i in xrange(alo, ahi):
+ yield ('-', a[i])
+ for i in xrange(blo, bhi):
+ yield ('+', b[i])
+
+ def display(fn, ctx, pstates, states):
+ rev = ctx.rev()
+ datefunc = ui.quiet and util.shortdate or util.datestr
+ found = False
+ filerevmatches = {}
+ if opts.get('all'):
+ iter = difflinestates(pstates, states)
+ else:
+ iter = [('', l) for l in states]
+ for change, l in iter:
+ cols = [fn, str(rev)]
+ before, match, after = None, None, None
+ if opts.get('line_number'):
+ cols.append(str(l.linenum))
+ if opts.get('all'):
+ cols.append(change)
+ if opts.get('user'):
+ cols.append(ui.shortuser(ctx.user()))
+ if opts.get('date'):
+ cols.append(datefunc(ctx.date()))
+ if opts.get('files_with_matches'):
+ c = (fn, rev)
+ if c in filerevmatches:
+ continue
+ filerevmatches[c] = 1
+ else:
+ before = l.line[:l.colstart]
+ match = l.line[l.colstart:l.colend]
+ after = l.line[l.colend:]
+ ui.write(sep.join(cols))
+ if before is not None:
+ ui.write(sep + before)
+ ui.write(match, label='grep.match')
+ ui.write(after)
+ ui.write(eol)
+ found = True
+ return found
+
+ skip = {}
+ revfiles = {}
+ matchfn = cmdutil.match(repo, pats, opts)
+ found = False
+ follow = opts.get('follow')
+
+ def prep(ctx, fns):
+ rev = ctx.rev()
+ pctx = ctx.parents()[0]
+ parent = pctx.rev()
+ matches.setdefault(rev, {})
+ matches.setdefault(parent, {})
+ files = revfiles.setdefault(rev, [])
+ for fn in fns:
+ flog = getfile(fn)
+ try:
+ fnode = ctx.filenode(fn)
+ except error.LookupError:
+ continue
+
+ copied = flog.renamed(fnode)
+ copy = follow and copied and copied[0]
+ if copy:
+ copies.setdefault(rev, {})[fn] = copy
+ if fn in skip:
+ if copy:
+ skip[copy] = True
+ continue
+ files.append(fn)
+
+ if fn not in matches[rev]:
+ grepbody(fn, rev, flog.read(fnode))
+
+ pfn = copy or fn
+ if pfn not in matches[parent]:
+ try:
+ fnode = pctx.filenode(pfn)
+ grepbody(pfn, parent, flog.read(fnode))
+ except error.LookupError:
+ pass
+
+ for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
+ rev = ctx.rev()
+ parent = ctx.parents()[0].rev()
+ for fn in sorted(revfiles.get(rev, [])):
+ states = matches[rev][fn]
+ copy = copies.get(rev, {}).get(fn)
+ if fn in skip:
+ if copy:
+ skip[copy] = True
+ continue
+ pstates = matches.get(parent, {}).get(copy or fn, [])
+ if pstates or states:
+ r = display(fn, ctx, pstates, states)
+ found = found or r
+ if r and not opts.get('all'):
+ skip[fn] = True
+ if copy:
+ skip[copy] = True
+ del matches[rev]
+ del revfiles[rev]
+
+ return not found
+
+def heads(ui, repo, *branchrevs, **opts):
+ """show current repository heads or show branch heads
+
+ With no arguments, show all repository branch heads.
+
+ Repository "heads" are changesets with no child changesets. They are
+ where development generally takes place and are the usual targets
+ for update and merge operations. Branch heads are changesets that have
+ no child changeset on the same branch.
+
+ If one or more REVs are given, only branch heads on the branches
+ associated with the specified changesets are shown.
+
+ If -c/--closed is specified, also show branch heads marked closed
+ (see :hg:`commit --close-branch`).
+
+ If STARTREV is specified, only those heads that are descendants of
+ STARTREV will be displayed.
+
+ If -t/--topo is specified, named branch mechanics will be ignored and only
+ changesets without children will be shown.
+
+ Returns 0 if matching heads are found, 1 if not.
+ """
+
+ if opts.get('rev'):
+ start = repo.lookup(opts['rev'])
+ else:
+ start = None
+
+ if opts.get('topo'):
+ heads = [repo[h] for h in repo.heads(start)]
+ else:
+ heads = []
+ for b, ls in repo.branchmap().iteritems():
+ if start is None:
+ heads += [repo[h] for h in ls]
+ continue
+ startrev = repo.changelog.rev(start)
+ descendants = set(repo.changelog.descendants(startrev))
+ descendants.add(startrev)
+ rev = repo.changelog.rev
+ heads += [repo[h] for h in ls if rev(h) in descendants]
+
+ if branchrevs:
+ decode, encode = encoding.fromlocal, encoding.tolocal
+ branches = set(repo[decode(br)].branch() for br in branchrevs)
+ heads = [h for h in heads if h.branch() in branches]
+
+ if not opts.get('closed'):
+ heads = [h for h in heads if not h.extra().get('close')]
+
+ if opts.get('active') and branchrevs:
+ dagheads = repo.heads(start)
+ heads = [h for h in heads if h.node() in dagheads]
+
+ if branchrevs:
+ haveheads = set(h.branch() for h in heads)
+ if branches - haveheads:
+ headless = ', '.join(encode(b) for b in branches - haveheads)
+ msg = _('no open branch heads found on branches %s')
+ if opts.get('rev'):
+ msg += _(' (started at %s)' % opts['rev'])
+ ui.warn((msg + '\n') % headless)
+
+ if not heads:
+ return 1
+
+ heads = sorted(heads, key=lambda x: -x.rev())
+ displayer = cmdutil.show_changeset(ui, repo, opts)
+ for ctx in heads:
+ displayer.show(ctx)
+ displayer.close()
+
+def help_(ui, name=None, with_version=False, unknowncmd=False):
+ """show help for a given topic or a help overview
+
+ With no arguments, print a list of commands with short help messages.
+
+ Given a topic, extension, or command name, print help for that
+ topic.
+
+ Returns 0 if successful.
+ """
+ option_lists = []
+ textwidth = ui.termwidth() - 2
+
+ def addglobalopts(aliases):
+ if ui.verbose:
+ option_lists.append((_("global options:"), globalopts))
+ if name == 'shortlist':
+ option_lists.append((_('use "hg help" for the full list '
+ 'of commands'), ()))
+ else:
+ if name == 'shortlist':
+ msg = _('use "hg help" for the full list of commands '
+ 'or "hg -v" for details')
+ elif aliases:
+ msg = _('use "hg -v help%s" to show aliases and '
+ 'global options') % (name and " " + name or "")
+ else:
+ msg = _('use "hg -v help %s" to show global options') % name
+ option_lists.append((msg, ()))
+
+ def helpcmd(name):
+ if with_version:
+ version_(ui)
+ ui.write('\n')
+
+ try:
+ aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
+ except error.AmbiguousCommand, inst:
+ # py3k fix: except vars can't be used outside the scope of the
+ # except block, nor can be used inside a lambda. python issue4617
+ prefix = inst.args[0]
+ select = lambda c: c.lstrip('^').startswith(prefix)
+ helplist(_('list of commands:\n\n'), select)
+ return
+
+ # check if it's an invalid alias and display its error if it is
+ if getattr(entry[0], 'badalias', False):
+ if not unknowncmd:
+ entry[0](ui)
+ return
+
+ # synopsis
+ if len(entry) > 2:
+ if entry[2].startswith('hg'):
+ ui.write("%s\n" % entry[2])
+ else:
+ ui.write('hg %s %s\n' % (aliases[0], entry[2]))
+ else:
+ ui.write('hg %s\n' % aliases[0])
+
+ # aliases
+ if not ui.quiet and len(aliases) > 1:
+ ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
+
+ # description
+ doc = gettext(entry[0].__doc__)
+ if not doc:
+ doc = _("(no help text available)")
+ if hasattr(entry[0], 'definition'): # aliased command
+ if entry[0].definition.startswith('!'): # shell alias
+ doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
+ else:
+ doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
+ if ui.quiet:
+ doc = doc.splitlines()[0]
+ keep = ui.verbose and ['verbose'] or []
+ formatted, pruned = minirst.format(doc, textwidth, keep=keep)
+ ui.write("\n%s\n" % formatted)
+ if pruned:
+ ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
+
+ if not ui.quiet:
+ # options
+ if entry[1]:
+ option_lists.append((_("options:\n"), entry[1]))
+
+ addglobalopts(False)
+
+ def helplist(header, select=None):
+ h = {}
+ cmds = {}
+ for c, e in table.iteritems():
+ f = c.split("|", 1)[0]
+ if select and not select(f):
+ continue
+ if (not select and name != 'shortlist' and
+ e[0].__module__ != __name__):
+ continue
+ if name == "shortlist" and not f.startswith("^"):
+ continue
+ f = f.lstrip("^")
+ if not ui.debugflag and f.startswith("debug"):
+ continue
+ doc = e[0].__doc__
+ if doc and 'DEPRECATED' in doc and not ui.verbose:
+ continue
+ doc = gettext(doc)
+ if not doc:
+ doc = _("(no help text available)")
+ h[f] = doc.splitlines()[0].rstrip()
+ cmds[f] = c.lstrip("^")
+
+ if not h:
+ ui.status(_('no commands defined\n'))
+ return
+
+ ui.status(header)
+ fns = sorted(h)
+ m = max(map(len, fns))
+ for f in fns:
+ if ui.verbose:
+ commands = cmds[f].replace("|",", ")
+ ui.write(" %s:\n %s\n"%(commands, h[f]))
+ else:
+ ui.write('%s\n' % (util.wrap(h[f], textwidth,
+ initindent=' %-*s ' % (m, f),
+ hangindent=' ' * (m + 4))))
+
+ if not ui.quiet:
+ addglobalopts(True)
+
+ def helptopic(name):
+ for names, header, doc in help.helptable:
+ if name in names:
+ break
+ else:
+ raise error.UnknownCommand(name)
+
+ # description
+ if not doc:
+ doc = _("(no help text available)")
+ if hasattr(doc, '__call__'):
+ doc = doc()
+
+ ui.write("%s\n\n" % header)
+ ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
+
+ def helpext(name):
+ try:
+ mod = extensions.find(name)
+ doc = gettext(mod.__doc__) or _('no help text available')
+ except KeyError:
+ mod = None
+ doc = extensions.disabledext(name)
+ if not doc:
+ raise error.UnknownCommand(name)
+
+ if '\n' not in doc:
+ head, tail = doc, ""
+ else:
+ head, tail = doc.split('\n', 1)
+ ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
+ if tail:
+ ui.write(minirst.format(tail, textwidth))
+ ui.status('\n\n')
+
+ if mod:
+ try:
+ ct = mod.cmdtable
+ except AttributeError:
+ ct = {}
+ modcmds = set([c.split('|', 1)[0] for c in ct])
+ helplist(_('list of commands:\n\n'), modcmds.__contains__)
+ else:
+ ui.write(_('use "hg help extensions" for information on enabling '
+ 'extensions\n'))
+
+ def helpextcmd(name):
+ cmd, ext, mod = extensions.disabledcmd(name, ui.config('ui', 'strict'))
+ doc = gettext(mod.__doc__).splitlines()[0]
+
+ msg = help.listexts(_("'%s' is provided by the following "
+ "extension:") % cmd, {ext: doc}, len(ext),
+ indent=4)
+ ui.write(minirst.format(msg, textwidth))
+ ui.write('\n\n')
+ ui.write(_('use "hg help extensions" for information on enabling '
+ 'extensions\n'))
+
+ help.addtopichook('revsets', revset.makedoc)
+
+ if name and name != 'shortlist':
+ i = None
+ if unknowncmd:
+ queries = (helpextcmd,)
+ else:
+ queries = (helptopic, helpcmd, helpext, helpextcmd)
+ for f in queries:
+ try:
+ f(name)
+ i = None
+ break
+ except error.UnknownCommand, inst:
+ i = inst
+ if i:
+ raise i
+
+ else:
+ # program name
+ if ui.verbose or with_version:
+ version_(ui)
+ else:
+ ui.status(_("Mercurial Distributed SCM\n"))
+ ui.status('\n')
+
+ # list of commands
+ if name == "shortlist":
+ header = _('basic commands:\n\n')
+ else:
+ header = _('list of commands:\n\n')
+
+ helplist(header)
+ if name != 'shortlist':
+ exts, maxlength = extensions.enabled()
+ text = help.listexts(_('enabled extensions:'), exts, maxlength)
+ if text:
+ ui.write("\n%s\n" % minirst.format(text, textwidth))
+
+ # list all option lists
+ opt_output = []
+ multioccur = False
+ for title, options in option_lists:
+ opt_output.append(("\n%s" % title, None))
+ for option in options:
+ if len(option) == 5:
+ shortopt, longopt, default, desc, optlabel = option
+ else:
+ shortopt, longopt, default, desc = option
+ optlabel = _("VALUE") # default label
+
+ if _("DEPRECATED") in desc and not ui.verbose:
+ continue
+ if isinstance(default, list):
+ numqualifier = " %s [+]" % optlabel
+ multioccur = True
+ elif (default is not None) and not isinstance(default, bool):
+ numqualifier = " %s" % optlabel
+ else:
+ numqualifier = ""
+ opt_output.append(("%2s%s" %
+ (shortopt and "-%s" % shortopt,
+ longopt and " --%s%s" %
+ (longopt, numqualifier)),
+ "%s%s" % (desc,
+ default
+ and _(" (default: %s)") % default
+ or "")))
+ if multioccur:
+ msg = _("\n[+] marked option can be specified multiple times")
+ if ui.verbose and name != 'shortlist':
+ opt_output.append((msg, None))
+ else:
+ opt_output.insert(-1, (msg, None))
+
+ if not name:
+ ui.write(_("\nadditional help topics:\n\n"))
+ topics = []
+ for names, header, doc in help.helptable:
+ topics.append((sorted(names, key=len, reverse=True)[0], header))
+ topics_len = max([len(s[0]) for s in topics])
+ for t, desc in topics:
+ ui.write(" %-*s %s\n" % (topics_len, t, desc))
+
+ if opt_output:
+ colwidth = encoding.colwidth
+ # normalize: (opt or message, desc or None, width of opt)
+ entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
+ for opt, desc in opt_output]
+ hanging = max([e[2] for e in entries])
+ for opt, desc, width in entries:
+ if desc:
+ initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
+ hangindent = ' ' * (hanging + 3)
+ ui.write('%s\n' % (util.wrap(desc, textwidth,
+ initindent=initindent,
+ hangindent=hangindent)))
+ else:
+ ui.write("%s\n" % opt)
+
+def identify(ui, repo, source=None,
+ rev=None, num=None, id=None, branch=None, tags=None):
+ """identify the working copy or specified revision
+
+ With no revision, print a summary of the current state of the
+ repository.
+
+ Specifying a path to a repository root or Mercurial bundle will
+ cause lookup to operate on that repository/bundle.
+
+ This summary identifies the repository state using one or two
+ parent hash identifiers, followed by a "+" if there are
+ uncommitted changes in the working directory, a list of tags for
+ this revision and a branch name for non-default branches.
+
+ Returns 0 if successful.
+ """
+
+ if not repo and not source:
+ raise util.Abort(_("there is no Mercurial repository here "
+ "(.hg not found)"))
+
+ hexfunc = ui.debugflag and hex or short
+ default = not (num or id or branch or tags)
+ output = []
+
+ revs = []
+ if source:
+ source, branches = hg.parseurl(ui.expandpath(source))
+ repo = hg.repository(ui, source)
+ revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
+
+ if not repo.local():
+ if not rev and revs:
+ rev = revs[0]
+ if not rev:
+ rev = "tip"
+ if num or branch or tags:
+ raise util.Abort(
+ "can't query remote revision number, branch, or tags")
+ output = [hexfunc(repo.lookup(rev))]
+ elif not rev:
+ ctx = repo[None]
+ parents = ctx.parents()
+ changed = False
+ if default or id or num:
+ changed = util.any(repo.status())
+ if default or id:
+ output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
+ (changed) and "+" or "")]
+ if num:
+ output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
+ (changed) and "+" or ""))
+ else:
+ ctx = repo[rev]
+ if default or id:
+ output = [hexfunc(ctx.node())]
+ if num:
+ output.append(str(ctx.rev()))
+
+ if repo.local() and default and not ui.quiet:
+ b = encoding.tolocal(ctx.branch())
+ if b != 'default':
+ output.append("(%s)" % b)
+
+ # multiple tags for a single parent separated by '/'
+ t = "/".join(ctx.tags())
+ if t:
+ output.append(t)
+
+ if branch:
+ output.append(encoding.tolocal(ctx.branch()))
+
+ if tags:
+ output.extend(ctx.tags())
+
+ ui.write("%s\n" % ' '.join(output))
+
+def import_(ui, repo, patch1, *patches, **opts):
+ """import an ordered set of patches
+
+ Import a list of patches and commit them individually (unless
+ --no-commit is specified).
+
+ If there are outstanding changes in the working directory, import
+ will abort unless given the -f/--force flag.
+
+ You can import a patch straight from a mail message. Even patches
+ as attachments work (to use the body part, it must have type
+ text/plain or text/x-patch). From and Subject headers of email
+ message are used as default committer and commit message. All
+ text/plain body parts before first diff are added to commit
+ message.
+
+ If the imported patch was generated by :hg:`export`, user and
+ description from patch override values from message headers and
+ body. Values given on command line with -m/--message and -u/--user
+ override these.
+
+ If --exact is specified, import will set the working directory to
+ the parent of each patch before applying it, and will abort if the
+ resulting changeset has a different ID than the one recorded in
+ the patch. This may happen due to character set problems or other
+ deficiencies in the text patch format.
+
+ With -s/--similarity, hg will attempt to discover renames and
+ copies in the patch in the same way as 'addremove'.
+
+ To read a patch from standard input, use "-" as the patch name. If
+ a URL is specified, the patch will be downloaded from it.
+ See :hg:`help dates` for a list of formats valid for -d/--date.
+
+ Returns 0 on success.
+ """
+ patches = (patch1,) + patches
+
+ date = opts.get('date')
+ if date:
+ opts['date'] = util.parsedate(date)
+
+ try:
+ sim = float(opts.get('similarity') or 0)
+ except ValueError:
+ raise util.Abort(_('similarity must be a number'))
+ if sim < 0 or sim > 100:
+ raise util.Abort(_('similarity must be between 0 and 100'))
+
+ if opts.get('exact') or not opts.get('force'):
+ cmdutil.bail_if_changed(repo)
+
+ d = opts["base"]
+ strip = opts["strip"]
+ wlock = lock = None
+
+ def tryone(ui, hunk):
+ tmpname, message, user, date, branch, nodeid, p1, p2 = \
+ patch.extract(ui, hunk)
+
+ if not tmpname:
+ return None
+ commitid = _('to working directory')
+
+ try:
+ cmdline_message = cmdutil.logmessage(opts)
+ if cmdline_message:
+ # pickup the cmdline msg
+ message = cmdline_message
+ elif message:
+ # pickup the patch msg
+ message = message.strip()
+ else:
+ # launch the editor
+ message = None
+ ui.debug('message:\n%s\n' % message)
+
+ wp = repo.parents()
+ if opts.get('exact'):
+ if not nodeid or not p1:
+ raise util.Abort(_('not a Mercurial patch'))
+ p1 = repo.lookup(p1)
+ p2 = repo.lookup(p2 or hex(nullid))
+
+ if p1 != wp[0].node():
+ hg.clean(repo, p1)
+ repo.dirstate.setparents(p1, p2)
+ elif p2:
+ try:
+ p1 = repo.lookup(p1)
+ p2 = repo.lookup(p2)
+ if p1 == wp[0].node():
+ repo.dirstate.setparents(p1, p2)
+ except error.RepoError:
+ pass
+ if opts.get('exact') or opts.get('import_branch'):
+ repo.dirstate.setbranch(branch or 'default')
+
+ files = {}
+ try:
+ patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
+ files=files, eolmode=None)
+ finally:
+ files = cmdutil.updatedir(ui, repo, files,
+ similarity=sim / 100.0)
+ if not opts.get('no_commit'):
+ if opts.get('exact'):
+ m = None
+ else:
+ m = cmdutil.matchfiles(repo, files or [])
+ n = repo.commit(message, opts.get('user') or user,
+ opts.get('date') or date, match=m,
+ editor=cmdutil.commiteditor)
+ if opts.get('exact'):
+ if hex(n) != nodeid:
+ repo.rollback()
+ raise util.Abort(_('patch is damaged'
+ ' or loses information'))
+ # Force a dirstate write so that the next transaction
+ # backups an up-do-date file.
+ repo.dirstate.write()
+ if n:
+ commitid = short(n)
+
+ return commitid
+ finally:
+ os.unlink(tmpname)
+
+ try:
+ wlock = repo.wlock()
+ lock = repo.lock()
+ lastcommit = None
+ for p in patches:
+ pf = os.path.join(d, p)
+
+ if pf == '-':
+ ui.status(_("applying patch from stdin\n"))
+ pf = sys.stdin
+ else:
+ ui.status(_("applying %s\n") % p)
+ pf = url.open(ui, pf)
+
+ haspatch = False
+ for hunk in patch.split(pf):
+ commitid = tryone(ui, hunk)
+ if commitid:
+ haspatch = True
+ if lastcommit:
+ ui.status(_('applied %s\n') % lastcommit)
+ lastcommit = commitid
+
+ if not haspatch:
+ raise util.Abort(_('no diffs found'))
+
+ finally:
+ release(lock, wlock)
+
+def incoming(ui, repo, source="default", **opts):
+ """show new changesets found in source
+
+ Show new changesets found in the specified path/URL or the default
+ pull location. These are the changesets that would have been pulled
+ if a pull at the time you issued this command.
+
+ For remote repository, using --bundle avoids downloading the
+ changesets twice if the incoming is followed by a pull.
+
+ See pull for valid source format details.
+
+ Returns 0 if there are incoming changes, 1 otherwise.
+ """
+ if opts.get('bundle') and opts.get('subrepos'):
+ raise util.Abort(_('cannot combine --bundle and --subrepos'))
+
+ ret = hg.incoming(ui, repo, source, opts)
+ return ret
+
+def init(ui, dest=".", **opts):
+ """create a new repository in the given directory
+
+ Initialize a new repository in the given directory. If the given
+ directory does not exist, it will be created.
+
+ If no directory is given, the current directory is used.
+
+ It is possible to specify an ``ssh://`` URL as the destination.
+ See :hg:`help urls` for more information.
+
+ Returns 0 on success.
+ """
+ hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
+
+def locate(ui, repo, *pats, **opts):
+ """locate files matching specific patterns
+
+ Print files under Mercurial control in the working directory whose
+ names match the given patterns.
+
+ By default, this command searches all directories in the working
+ directory. To search just the current directory and its
+ subdirectories, use "--include .".
+
+ If no patterns are given to match, this command prints the names
+ of all files under Mercurial control in the working directory.
+
+ If you want to feed the output of this command into the "xargs"
+ command, use the -0 option to both this command and "xargs". This
+ will avoid the problem of "xargs" treating single filenames that
+ contain whitespace as multiple filenames.
+
+ Returns 0 if a match is found, 1 otherwise.
+ """
+ end = opts.get('print0') and '\0' or '\n'
+ rev = opts.get('rev') or None
+
+ ret = 1
+ m = cmdutil.match(repo, pats, opts, default='relglob')
+ m.bad = lambda x, y: False
+ for abs in repo[rev].walk(m):
+ if not rev and abs not in repo.dirstate:
+ continue
+ if opts.get('fullpath'):
+ ui.write(repo.wjoin(abs), end)
+ else:
+ ui.write(((pats and m.rel(abs)) or abs), end)
+ ret = 0
+
+ return ret
+
+def log(ui, repo, *pats, **opts):
+ """show revision history of entire repository or files
+
+ Print the revision history of the specified files or the entire
+ project.
+
+ File history is shown without following rename or copy history of
+ files. Use -f/--follow with a filename to follow history across
+ renames and copies. --follow without a filename will only show
+ ancestors or descendants of the starting revision. --follow-first
+ only follows the first parent of merge revisions.
+
+ If no revision range is specified, the default is ``tip:0`` unless
+ --follow is set, in which case the working directory parent is
+ used as the starting revision. You can specify a revision set for
+ log, see :hg:`help revsets` for more information.
+
+ See :hg:`help dates` for a list of formats valid for -d/--date.
+
+ By default this command prints revision number and changeset id,
+ tags, non-trivial parents, user, date and time, and a summary for
+ each commit. When the -v/--verbose switch is used, the list of
+ changed files and full commit message are shown.
+
+ .. note::
+ log -p/--patch may generate unexpected diff output for merge
+ changesets, as it will only compare the merge changeset against
+ its first parent. Also, only files different from BOTH parents
+ will appear in files:.
+
+ Returns 0 on success.
+ """
+
+ matchfn = cmdutil.match(repo, pats, opts)
+ limit = cmdutil.loglimit(opts)
+ count = 0
+
+ endrev = None
+ if opts.get('copies') and opts.get('rev'):
+ endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
+
+ df = False
+ if opts["date"]:
+ df = util.matchdate(opts["date"])
+
+ branches = opts.get('branch', []) + opts.get('only_branch', [])
+ opts['branch'] = [repo.lookupbranch(b) for b in branches]
+
+ displayer = cmdutil.show_changeset(ui, repo, opts, True)
+ def prep(ctx, fns):
+ rev = ctx.rev()
+ parents = [p for p in repo.changelog.parentrevs(rev)
+ if p != nullrev]
+ if opts.get('no_merges') and len(parents) == 2:
+ return
+ if opts.get('only_merges') and len(parents) != 2:
+ return
+ if opts.get('branch') and ctx.branch() not in opts['branch']:
+ return
+ if df and not df(ctx.date()[0]):
+ return
+ if opts['user'] and not [k for k in opts['user']
+ if k.lower() in ctx.user().lower()]:
+ return
+ if opts.get('keyword'):
+ for k in [kw.lower() for kw in opts['keyword']]:
+ if (k in ctx.user().lower() or
+ k in ctx.description().lower() or
+ k in " ".join(ctx.files()).lower()):
+ break
+ else:
+ return
+
+ copies = None
+ if opts.get('copies') and rev:
+ copies = []
+ getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
+ for fn in ctx.files():
+ rename = getrenamed(fn, rev)
+ if rename:
+ copies.append((fn, rename[0]))
+
+ revmatchfn = None
+ if opts.get('patch') or opts.get('stat'):
+ if opts.get('follow') or opts.get('follow_first'):
+ # note: this might be wrong when following through merges
+ revmatchfn = cmdutil.match(repo, fns, default='path')
+ else:
+ revmatchfn = matchfn
+
+ displayer.show(ctx, copies=copies, matchfn=revmatchfn)
+
+ for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
+ if count == limit:
+ break
+ if displayer.flush(ctx.rev()):
+ count += 1
+ displayer.close()
+
+def manifest(ui, repo, node=None, rev=None):
+ """output the current or given revision of the project manifest
+
+ Print a list of version controlled files for the given revision.
+ If no revision is given, the first parent of the working directory
+ is used, or the null revision if no revision is checked out.
+
+ With -v, print file permissions, symlink and executable bits.
+ With --debug, print file revision hashes.
+
+ Returns 0 on success.
+ """
+
+ if rev and node:
+ raise util.Abort(_("please specify just one revision"))
+
+ if not node:
+ node = rev
+
+ decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
+ ctx = repo[node]
+ for f in ctx:
+ if ui.debugflag:
+ ui.write("%40s " % hex(ctx.manifest()[f]))
+ if ui.verbose:
+ ui.write(decor[ctx.flags(f)])
+ ui.write("%s\n" % f)
+
+def merge(ui, repo, node=None, **opts):
+ """merge working directory with another revision
+
+ The current working directory is updated with all changes made in
+ the requested revision since the last common predecessor revision.
+
+ Files that changed between either parent are marked as changed for
+ the next commit and a commit must be performed before any further
+ updates to the repository are allowed. The next commit will have
+ two parents.
+
+ ``--tool`` can be used to specify the merge tool used for file
+ merges. It overrides the HGMERGE environment variable and your
+ configuration files.
+
+ If no revision is specified, the working directory's parent is a
+ head revision, and the current branch contains exactly one other
+ head, the other head is merged with by default. Otherwise, an
+ explicit revision with which to merge with must be provided.
+
+ :hg:`resolve` must be used to resolve unresolved files.
+
+ To undo an uncommitted merge, use :hg:`update --clean .` which
+ will check out a clean copy of the original merge parent, losing
+ all changes.
+
+ Returns 0 on success, 1 if there are unresolved files.
+ """
+
+ if opts.get('rev') and node:
+ raise util.Abort(_("please specify just one revision"))
+ if not node:
+ node = opts.get('rev')
+
+ if not node:
+ branch = repo.changectx(None).branch()
+ bheads = repo.branchheads(branch)
+ if len(bheads) > 2:
+ raise util.Abort(_(
+ 'branch \'%s\' has %d heads - '
+ 'please merge with an explicit rev\n'
+ '(run \'hg heads .\' to see heads)')
+ % (branch, len(bheads)))
+
+ parent = repo.dirstate.parents()[0]
+ if len(bheads) == 1:
+ if len(repo.heads()) > 1:
+ raise util.Abort(_(
+ 'branch \'%s\' has one head - '
+ 'please merge with an explicit rev\n'
+ '(run \'hg heads\' to see all heads)')
+ % branch)
+ msg = _('there is nothing to merge')
+ if parent != repo.lookup(repo[None].branch()):
+ msg = _('%s - use "hg update" instead') % msg
+ raise util.Abort(msg)
+
+ if parent not in bheads:
+ raise util.Abort(_('working dir not at a head rev - '
+ 'use "hg update" or merge with an explicit rev'))
+ node = parent == bheads[0] and bheads[-1] or bheads[0]
+
+ if opts.get('preview'):
+ # find nodes that are ancestors of p2 but not of p1
+ p1 = repo.lookup('.')
+ p2 = repo.lookup(node)
+ nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
+
+ displayer = cmdutil.show_changeset(ui, repo, opts)
+ for node in nodes:
+ displayer.show(repo[node])
+ displayer.close()
+ return 0
+
+ try:
+ # ui.forcemerge is an internal variable, do not document
+ ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
+ return hg.merge(repo, node, force=opts.get('force'))
+ finally:
+ ui.setconfig('ui', 'forcemerge', '')
+
+def outgoing(ui, repo, dest=None, **opts):
+ """show changesets not found in the destination
+
+ Show changesets not found in the specified destination repository
+ or the default push location. These are the changesets that would
+ be pushed if a push was requested.
+
+ See pull for details of valid destination formats.
+
+ Returns 0 if there are outgoing changes, 1 otherwise.
+ """
+ ret = hg.outgoing(ui, repo, dest, opts)
+ return ret
+
+def parents(ui, repo, file_=None, **opts):
+ """show the parents of the working directory or revision
+
+ Print the working directory's parent revisions. If a revision is
+ given via -r/--rev, the parent of that revision will be printed.
+ If a file argument is given, the revision in which the file was
+ last changed (before the working directory revision or the
+ argument to --rev if given) is printed.
+
+ Returns 0 on success.
+ """
+ rev = opts.get('rev')
+ if rev:
+ ctx = repo[rev]
+ else:
+ ctx = repo[None]
+
+ if file_:
+ m = cmdutil.match(repo, (file_,), opts)
+ if m.anypats() or len(m.files()) != 1:
+ raise util.Abort(_('can only specify an explicit filename'))
+ file_ = m.files()[0]
+ filenodes = []
+ for cp in ctx.parents():
+ if not cp:
+ continue
+ try:
+ filenodes.append(cp.filenode(file_))
+ except error.LookupError:
+ pass
+ if not filenodes:
+ raise util.Abort(_("'%s' not found in manifest!") % file_)
+ fl = repo.file(file_)
+ p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
+ else:
+ p = [cp.node() for cp in ctx.parents()]
+
+ displayer = cmdutil.show_changeset(ui, repo, opts)
+ for n in p:
+ if n != nullid:
+ displayer.show(repo[n])
+ displayer.close()
+
+def paths(ui, repo, search=None):
+ """show aliases for remote repositories
+
+ Show definition of symbolic path name NAME. If no name is given,
+ show definition of all available names.
+
+ Path names are defined in the [paths] section of your
+ configuration file and in ``/etc/mercurial/hgrc``. If run inside a
+ repository, ``.hg/hgrc`` is used, too.
+
+ The path names ``default`` and ``default-push`` have a special
+ meaning. When performing a push or pull operation, they are used
+ as fallbacks if no location is specified on the command-line.
+ When ``default-push`` is set, it will be used for push and
+ ``default`` will be used for pull; otherwise ``default`` is used
+ as the fallback for both. When cloning a repository, the clone
+ source is written as ``default`` in ``.hg/hgrc``. Note that
+ ``default`` and ``default-push`` apply to all inbound (e.g.
+ :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
+ :hg:`bundle`) operations.
+
+ See :hg:`help urls` for more information.
+
+ Returns 0 on success.
+ """
+ if search:
+ for name, path in ui.configitems("paths"):
+ if name == search:
+ ui.write("%s\n" % url.hidepassword(path))
+ return
+ ui.warn(_("not found!\n"))
+ return 1
+ else:
+ for name, path in ui.configitems("paths"):
+ ui.write("%s = %s\n" % (name, url.hidepassword(path)))
+
+def postincoming(ui, repo, modheads, optupdate, checkout):
+ if modheads == 0:
+ return
+ if optupdate:
+ if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
+ return hg.update(repo, checkout)
+ else:
+ ui.status(_("not updating, since new heads added\n"))
+ if modheads > 1:
+ ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
+ else:
+ ui.status(_("(run 'hg update' to get a working copy)\n"))
+
+def pull(ui, repo, source="default", **opts):
+ """pull changes from the specified source
+
+ Pull changes from a remote repository to a local one.
+
+ This finds all changes from the repository at the specified path
+ or URL and adds them to a local repository (the current one unless
+ -R is specified). By default, this does not update the copy of the
+ project in the working directory.
+
+ Use :hg:`incoming` if you want to see what would have been added
+ by a pull at the time you issued this command. If you then decide
+ to add those changes to the repository, you should use :hg:`pull
+ -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
+
+ If SOURCE is omitted, the 'default' path will be used.
+ See :hg:`help urls` for more information.
+
+ Returns 0 on success, 1 if an update had unresolved files.
+ """
+ source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
+ other = hg.repository(hg.remoteui(repo, opts), source)
+ ui.status(_('pulling from %s\n') % url.hidepassword(source))
+ revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
+ if revs:
+ try:
+ revs = [other.lookup(rev) for rev in revs]
+ except error.CapabilityError:
+ err = _("other repository doesn't support revision lookup, "
+ "so a rev cannot be specified.")
+ raise util.Abort(err)
+
+ modheads = repo.pull(other, heads=revs, force=opts.get('force'))
+ if checkout:
+ checkout = str(repo.changelog.rev(other.lookup(checkout)))
+ repo._subtoppath = source
+ try:
+ return postincoming(ui, repo, modheads, opts.get('update'), checkout)
+ finally:
+ del repo._subtoppath
+
+def push(ui, repo, dest=None, **opts):
+ """push changes to the specified destination
+
+ Push changesets from the local repository to the specified
+ destination.
+
+ This operation is symmetrical to pull: it is identical to a pull
+ in the destination repository from the current one.
+
+ By default, push will not allow creation of new heads at the
+ destination, since multiple heads would make it unclear which head
+ to use. In this situation, it is recommended to pull and merge
+ before pushing.
+
+ Use --new-branch if you want to allow push to create a new named
+ branch that is not present at the destination. This allows you to
+ only create a new branch without forcing other changes.
+
+ Use -f/--force to override the default behavior and push all
+ changesets on all branches.
+
+ If -r/--rev is used, the specified revision and all its ancestors
+ will be pushed to the remote repository.
+
+ Please see :hg:`help urls` for important details about ``ssh://``
+ URLs. If DESTINATION is omitted, a default path will be used.
+
+ Returns 0 if push was successful, 1 if nothing to push.
+ """
+ dest = ui.expandpath(dest or 'default-push', dest or 'default')
+ dest, branches = hg.parseurl(dest, opts.get('branch'))
+ revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
+ other = hg.repository(hg.remoteui(repo, opts), dest)
+ ui.status(_('pushing to %s\n') % url.hidepassword(dest))
+ if revs:
+ revs = [repo.lookup(rev) for rev in revs]
+
+ repo._subtoppath = dest
+ try:
+ # push subrepos depth-first for coherent ordering
+ c = repo['']
+ subs = c.substate # only repos that are committed
+ for s in sorted(subs):
+ if not c.sub(s).push(opts.get('force')):
+ return False
+ finally:
+ del repo._subtoppath
+ r = repo.push(other, opts.get('force'), revs=revs,
+ newbranch=opts.get('new_branch'))
+ return r == 0
+
+def recover(ui, repo):
+ """roll back an interrupted transaction
+
+ Recover from an interrupted commit or pull.
+
+ This command tries to fix the repository status after an
+ interrupted operation. It should only be necessary when Mercurial
+ suggests it.
+
+ Returns 0 if successful, 1 if nothing to recover or verify fails.
+ """
+ if repo.recover():
+ return hg.verify(repo)
+ return 1
+
+def remove(ui, repo, *pats, **opts):
+ """remove the specified files on the next commit
+
+ Schedule the indicated files for removal from the repository.
+
+ This only removes files from the current branch, not from the
+ entire project history. -A/--after can be used to remove only
+ files that have already been deleted, -f/--force can be used to
+ force deletion, and -Af can be used to remove files from the next
+ revision without deleting them from the working directory.
+
+ The following table details the behavior of remove for different
+ file states (columns) and option combinations (rows). The file
+ states are Added [A], Clean [C], Modified [M] and Missing [!] (as
+ reported by :hg:`status`). The actions are Warn, Remove (from
+ branch) and Delete (from disk)::
+
+ A C M !
+ none W RD W R
+ -f R RD RD R
+ -A W W W R
+ -Af R R R R
+
+ This command schedules the files to be removed at the next commit.
+ To undo a remove before that, see :hg:`revert`.
+
+ Returns 0 on success, 1 if any warnings encountered.
+ """
+
+ ret = 0
+ after, force = opts.get('after'), opts.get('force')
+ if not pats and not after:
+ raise util.Abort(_('no files specified'))
+
+ m = cmdutil.match(repo, pats, opts)
+ s = repo.status(match=m, clean=True)
+ modified, added, deleted, clean = s[0], s[1], s[3], s[6]
+
+ for f in m.files():
+ if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
+ ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
+ ret = 1
+
+ if force:
+ remove, forget = modified + deleted + clean, added
+ elif after:
+ remove, forget = deleted, []
+ for f in modified + added + clean:
+ ui.warn(_('not removing %s: file still exists (use -f'
+ ' to force removal)\n') % m.rel(f))
+ ret = 1
+ else:
+ remove, forget = deleted + clean, []
+ for f in modified:
+ ui.warn(_('not removing %s: file is modified (use -f'
+ ' to force removal)\n') % m.rel(f))
+ ret = 1
+ for f in added:
+ ui.warn(_('not removing %s: file has been marked for add (use -f'
+ ' to force removal)\n') % m.rel(f))
+ ret = 1
+
+ for f in sorted(remove + forget):
+ if ui.verbose or not m.exact(f):
+ ui.status(_('removing %s\n') % m.rel(f))
+
+ repo[None].forget(forget)
+ repo[None].remove(remove, unlink=not after)
+ return ret
+
+def rename(ui, repo, *pats, **opts):
+ """rename files; equivalent of copy + remove
+
+ Mark dest as copies of sources; mark sources for deletion. If dest
+ is a directory, copies are put in that directory. If dest is a
+ file, there can only be one source.
+
+ By default, this command copies the contents of files as they
+ exist in the working directory. If invoked with -A/--after, the
+ operation is recorded, but no copying is performed.
+
+ This command takes effect at the next commit. To undo a rename
+ before that, see :hg:`revert`.
+
+ Returns 0 on success, 1 if errors are encountered.
+ """
+ wlock = repo.wlock(False)
+ try:
+ return cmdutil.copy(ui, repo, pats, opts, rename=True)
+ finally:
+ wlock.release()
+
+def resolve(ui, repo, *pats, **opts):
+ """redo merges or set/view the merge status of files
+
+ Merges with unresolved conflicts are often the result of
+ non-interactive merging using the ``internal:merge`` configuration
+ setting, or a command-line merge tool like ``diff3``. The resolve
+ command is used to manage the files involved in a merge, after
+ :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
+ working directory must have two parents).
+
+ The resolve command can be used in the following ways:
+
+ - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
+ files, discarding any previous merge attempts. Re-merging is not
+ performed for files already marked as resolved. Use ``--all/-a``
+ to selects all unresolved files. ``--tool`` can be used to specify
+ the merge tool used for the given files. It overrides the HGMERGE
+ environment variable and your configuration files.
+
+ - :hg:`resolve -m [FILE]`: mark a file as having been resolved
+ (e.g. after having manually fixed-up the files). The default is
+ to mark all unresolved files.
+
+ - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
+ default is to mark all resolved files.
+
+ - :hg:`resolve -l`: list files which had or still have conflicts.
+ In the printed list, ``U`` = unresolved and ``R`` = resolved.
+
+ Note that Mercurial will not let you commit files with unresolved
+ merge conflicts. You must use :hg:`resolve -m ...` before you can
+ commit after a conflicting merge.
+
+ Returns 0 on success, 1 if any files fail a resolve attempt.
+ """
+
+ all, mark, unmark, show, nostatus = \
+ [opts.get(o) for o in 'all mark unmark list no_status'.split()]
+
+ if (show and (mark or unmark)) or (mark and unmark):
+ raise util.Abort(_("too many options specified"))
+ if pats and all:
+ raise util.Abort(_("can't specify --all and patterns"))
+ if not (all or pats or show or mark or unmark):
+ raise util.Abort(_('no files or directories specified; '
+ 'use --all to remerge all files'))
+
+ ms = mergemod.mergestate(repo)
+ m = cmdutil.match(repo, pats, opts)
+ ret = 0
+
+ for f in ms:
+ if m(f):
+ if show:
+ if nostatus:
+ ui.write("%s\n" % f)
+ else:
+ ui.write("%s %s\n" % (ms[f].upper(), f),
+ label='resolve.' +
+ {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
+ elif mark:
+ ms.mark(f, "r")
+ elif unmark:
+ ms.mark(f, "u")
+ else:
+ wctx = repo[None]
+ mctx = wctx.parents()[-1]
+
+ # backup pre-resolve (merge uses .orig for its own purposes)
+ a = repo.wjoin(f)
+ util.copyfile(a, a + ".resolve")
+
+ try:
+ # resolve file
+ ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
+ if ms.resolve(f, wctx, mctx):
+ ret = 1
+ finally:
+ ui.setconfig('ui', 'forcemerge', '')
+
+ # replace filemerge's .orig file with our resolve file
+ util.rename(a + ".resolve", a + ".orig")
+
+ ms.commit()
+ return ret
+
+def revert(ui, repo, *pats, **opts):
+ """restore individual files or directories to an earlier state
+
+ .. note::
+ This command is most likely not what you are looking for.
+ Revert will partially overwrite content in the working
+ directory without changing the working directory parents. Use
+ :hg:`update -r rev` to check out earlier revisions, or
+ :hg:`update --clean .` to undo a merge which has added another
+ parent.
+
+ With no revision specified, revert the named files or directories
+ to the contents they had in the parent of the working directory.
+ This restores the contents of the affected files to an unmodified
+ state and unschedules adds, removes, copies, and renames. If the
+ working directory has two parents, you must explicitly specify a
+ revision.
+
+ Using the -r/--rev option, revert the given files or directories
+ to their contents as of a specific revision. This can be helpful
+ to "roll back" some or all of an earlier change. See :hg:`help
+ dates` for a list of formats valid for -d/--date.
+
+ Revert modifies the working directory. It does not commit any
+ changes, or change the parent of the working directory. If you
+ revert to a revision other than the parent of the working
+ directory, the reverted files will thus appear modified
+ afterwards.
+
+ If a file has been deleted, it is restored. If the executable mode
+ of a file was changed, it is reset.
+
+ If names are given, all files matching the names are reverted.
+ If no arguments are given, no files are reverted.
+
+ Modified files are saved with a .orig suffix before reverting.
+ To disable these backups, use --no-backup.
+
+ Returns 0 on success.
+ """
+
+ if opts.get("date"):
+ if opts.get("rev"):
+ raise util.Abort(_("you can't specify a revision and a date"))
+ opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
+
+ if not pats and not opts.get('all'):
+ raise util.Abort(_('no files or directories specified; '
+ 'use --all to revert the whole repo'))
+
+ parent, p2 = repo.dirstate.parents()
+ if not opts.get('rev') and p2 != nullid:
+ raise util.Abort(_('uncommitted merge - please provide a '
+ 'specific revision'))
+ ctx = repo[opts.get('rev')]
+ node = ctx.node()
+ mf = ctx.manifest()
+ if node == parent:
+ pmf = mf
+ else:
+ pmf = None
+
+ # need all matching names in dirstate and manifest of target rev,
+ # so have to walk both. do not print errors if files exist in one
+ # but not other.
+
+ names = {}
+
+ wlock = repo.wlock()
+ try:
+ # walk dirstate.
+
+ m = cmdutil.match(repo, pats, opts)
+ m.bad = lambda x, y: False
+ for abs in repo.walk(m):
+ names[abs] = m.rel(abs), m.exact(abs)
+
+ # walk target manifest.
+
+ def badfn(path, msg):
+ if path in names:
+ return
+ path_ = path + '/'
+ for f in names:
+ if f.startswith(path_):
+ return
+ ui.warn("%s: %s\n" % (m.rel(path), msg))
+
+ m = cmdutil.match(repo, pats, opts)
+ m.bad = badfn
+ for abs in repo[node].walk(m):
+ if abs not in names:
+ names[abs] = m.rel(abs), m.exact(abs)
+
+ m = cmdutil.matchfiles(repo, names)
+ changes = repo.status(match=m)[:4]
+ modified, added, removed, deleted = map(set, changes)
+
+ # if f is a rename, also revert the source
+ cwd = repo.getcwd()
+ for f in added:
+ src = repo.dirstate.copied(f)
+ if src and src not in names and repo.dirstate[src] == 'r':
+ removed.add(src)
+ names[src] = (repo.pathto(src, cwd), True)
+
+ def removeforget(abs):
+ if repo.dirstate[abs] == 'a':
+ return _('forgetting %s\n')
+ return _('removing %s\n')
+
+ revert = ([], _('reverting %s\n'))
+ add = ([], _('adding %s\n'))
+ remove = ([], removeforget)
+ undelete = ([], _('undeleting %s\n'))
+
+ disptable = (
+ # dispatch table:
+ # file state
+ # action if in target manifest
+ # action if not in target manifest
+ # make backup if in target manifest
+ # make backup if not in target manifest
+ (modified, revert, remove, True, True),
+ (added, revert, remove, True, False),
+ (removed, undelete, None, False, False),
+ (deleted, revert, remove, False, False),
+ )
+
+ for abs, (rel, exact) in sorted(names.items()):
+ mfentry = mf.get(abs)
+ target = repo.wjoin(abs)
+ def handle(xlist, dobackup):
+ xlist[0].append(abs)
+ if (dobackup and not opts.get('no_backup') and
+ os.path.lexists(target)):
+ bakname = "%s.orig" % rel
+ ui.note(_('saving current version of %s as %s\n') %
+ (rel, bakname))
+ if not opts.get('dry_run'):
+ util.rename(target, bakname)
+ if ui.verbose or not exact:
+ msg = xlist[1]
+ if not isinstance(msg, basestring):
+ msg = msg(abs)
+ ui.status(msg % rel)
+ for table, hitlist, misslist, backuphit, backupmiss in disptable:
+ if abs not in table:
+ continue
+ # file has changed in dirstate
+ if mfentry:
+ handle(hitlist, backuphit)
+ elif misslist is not None:
+ handle(misslist, backupmiss)
+ break
+ else:
+ if abs not in repo.dirstate:
+ if mfentry:
+ handle(add, True)
+ elif exact:
+ ui.warn(_('file not managed: %s\n') % rel)
+ continue
+ # file has not changed in dirstate
+ if node == parent:
+ if exact:
+ ui.warn(_('no changes needed to %s\n') % rel)
+ continue
+ if pmf is None:
+ # only need parent manifest in this unlikely case,
+ # so do not read by default
+ pmf = repo[parent].manifest()
+ if abs in pmf:
+ if mfentry:
+ # if version of file is same in parent and target
+ # manifests, do nothing
+ if (pmf[abs] != mfentry or
+ pmf.flags(abs) != mf.flags(abs)):
+ handle(revert, False)
+ else:
+ handle(remove, False)
+
+ if not opts.get('dry_run'):
+ def checkout(f):
+ fc = ctx[f]
+ repo.wwrite(f, fc.data(), fc.flags())
+
+ audit_path = util.path_auditor(repo.root)
+ for f in remove[0]:
+ if repo.dirstate[f] == 'a':
+ repo.dirstate.forget(f)
+ continue
+ audit_path(f)
+ try:
+ util.unlink(repo.wjoin(f))
+ except OSError:
+ pass
+ repo.dirstate.remove(f)
+
+ normal = None
+ if node == parent:
+ # We're reverting to our parent. If possible, we'd like status
+ # to report the file as clean. We have to use normallookup for
+ # merges to avoid losing information about merged/dirty files.
+ if p2 != nullid:
+ normal = repo.dirstate.normallookup
+ else:
+ normal = repo.dirstate.normal
+ for f in revert[0]:
+ checkout(f)
+ if normal:
+ normal(f)
+
+ for f in add[0]:
+ checkout(f)
+ repo.dirstate.add(f)
+
+ normal = repo.dirstate.normallookup
+ if node == parent and p2 == nullid:
+ normal = repo.dirstate.normal
+ for f in undelete[0]:
+ checkout(f)
+ normal(f)
+
+ finally:
+ wlock.release()
+
+def rollback(ui, repo, **opts):
+ """roll back the last transaction (dangerous)
+
+ This command should be used with care. There is only one level of
+ rollback, and there is no way to undo a rollback. It will also
+ restore the dirstate at the time of the last transaction, losing
+ any dirstate changes since that time. This command does not alter
+ the working directory.
+
+ Transactions are used to encapsulate the effects of all commands
+ that create new changesets or propagate existing changesets into a
+ repository. For example, the following commands are transactional,
+ and their effects can be rolled back:
+
+ - commit
+ - import
+ - pull
+ - push (with this repository as the destination)
+ - unbundle
+
+ This command is not intended for use on public repositories. Once
+ changes are visible for pull by other users, rolling a transaction
+ back locally is ineffective (someone else may already have pulled
+ the changes). Furthermore, a race is possible with readers of the
+ repository; for example an in-progress pull from the repository
+ may fail if a rollback is performed.
+
+ Returns 0 on success, 1 if no rollback data is available.
+ """
+ return repo.rollback(opts.get('dry_run'))
+
+def root(ui, repo):
+ """print the root (top) of the current working directory
+
+ Print the root directory of the current repository.
+
+ Returns 0 on success.
+ """
+ ui.write(repo.root + "\n")
+
+def serve(ui, repo, **opts):
+ """start stand-alone webserver
+
+ Start a local HTTP repository browser and pull server. You can use
+ this for ad-hoc sharing and browsing of repositories. It is
+ recommended to use a real web server to serve a repository for
+ longer periods of time.
+
+ Please note that the server does not implement access control.
+ This means that, by default, anybody can read from the server and
+ nobody can write to it by default. Set the ``web.allow_push``
+ option to ``*`` to allow everybody to push to the server. You
+ should use a real web server if you need to authenticate users.
+
+ By default, the server logs accesses to stdout and errors to
+ stderr. Use the -A/--accesslog and -E/--errorlog options to log to
+ files.
+
+ To have the server choose a free port number to listen on, specify
+ a port number of 0; in this case, the server will print the port
+ number it uses.
+
+ Returns 0 on success.
+ """
+
+ if opts["stdio"]:
+ if repo is None:
+ raise error.RepoError(_("There is no Mercurial repository here"
+ " (.hg not found)"))
+ s = sshserver.sshserver(ui, repo)
+ s.serve_forever()
+
+ # this way we can check if something was given in the command-line
+ if opts.get('port'):
+ opts['port'] = util.getport(opts.get('port'))
+
+ baseui = repo and repo.baseui or ui
+ optlist = ("name templates style address port prefix ipv6"
+ " accesslog errorlog certificate encoding")
+ for o in optlist.split():
+ val = opts.get(o, '')
+ if val in (None, ''): # should check against default options instead
+ continue
+ baseui.setconfig("web", o, val)
+ if repo and repo.ui != baseui:
+ repo.ui.setconfig("web", o, val)
+
+ o = opts.get('web_conf') or opts.get('webdir_conf')
+ if not o:
+ if not repo:
+ raise error.RepoError(_("There is no Mercurial repository"
+ " here (.hg not found)"))
+ o = repo.root
+
+ app = hgweb.hgweb(o, baseui=ui)
+
+ class service(object):
+ def init(self):
+ util.set_signal_handler()
+ self.httpd = hgweb.server.create_server(ui, app)
+
+ if opts['port'] and not ui.verbose:
+ return
+
+ if self.httpd.prefix:
+ prefix = self.httpd.prefix.strip('/') + '/'
+ else:
+ prefix = ''
+
+ port = ':%d' % self.httpd.port
+ if port == ':80':
+ port = ''
+
+ bindaddr = self.httpd.addr
+ if bindaddr == '0.0.0.0':
+ bindaddr = '*'
+ elif ':' in bindaddr: # IPv6
+ bindaddr = '[%s]' % bindaddr
+
+ fqaddr = self.httpd.fqaddr
+ if ':' in fqaddr:
+ fqaddr = '[%s]' % fqaddr
+ if opts['port']:
+ write = ui.status
+ else:
+ write = ui.write
+ write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
+ (fqaddr, port, prefix, bindaddr, self.httpd.port))
+
+ def run(self):
+ self.httpd.serve_forever()
+
+ service = service()
+
+ cmdutil.service(opts, initfn=service.init, runfn=service.run)
+
+def status(ui, repo, *pats, **opts):
+ """show changed files in the working directory
+
+ Show status of files in the repository. If names are given, only
+ files that match are shown. Files that are clean or ignored or
+ the source of a copy/move operation, are not listed unless
+ -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
+ Unless options described with "show only ..." are given, the
+ options -mardu are used.
+
+ Option -q/--quiet hides untracked (unknown and ignored) files
+ unless explicitly requested with -u/--unknown or -i/--ignored.
+
+ .. note::
+ status may appear to disagree with diff if permissions have
+ changed or a merge has occurred. The standard diff format does
+ not report permission changes and diff only reports changes
+ relative to one merge parent.
+
+ If one revision is given, it is used as the base revision.
+ If two revisions are given, the differences between them are
+ shown. The --change option can also be used as a shortcut to list
+ the changed files of a revision from its first parent.
+
+ The codes used to show the status of files are::
+
+ M = modified
+ A = added
+ R = removed
+ C = clean
+ ! = missing (deleted by non-hg command, but still tracked)
+ ? = not tracked
+ I = ignored
+ = origin of the previous file listed as A (added)
+
+ Returns 0 on success.
+ """
+
+ revs = opts.get('rev')
+ change = opts.get('change')
+
+ if revs and change:
+ msg = _('cannot specify --rev and --change at the same time')
+ raise util.Abort(msg)
+ elif change:
+ node2 = repo.lookup(change)
+ node1 = repo[node2].parents()[0].node()
+ else:
+ node1, node2 = cmdutil.revpair(repo, revs)
+
+ cwd = (pats and repo.getcwd()) or ''
+ end = opts.get('print0') and '\0' or '\n'
+ copy = {}
+ states = 'modified added removed deleted unknown ignored clean'.split()
+ show = [k for k in states if opts.get(k)]
+ if opts.get('all'):
+ show += ui.quiet and (states[:4] + ['clean']) or states
+ if not show:
+ show = ui.quiet and states[:4] or states[:5]
+
+ stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
+ 'ignored' in show, 'clean' in show, 'unknown' in show,
+ opts.get('subrepos'))
+ changestates = zip(states, 'MAR!?IC', stat)
+
+ if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
+ ctxn = repo[nullid]
+ ctx1 = repo[node1]
+ ctx2 = repo[node2]
+ added = stat[1]
+ if node2 is None:
+ added = stat[0] + stat[1] # merged?
+
+ for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
+ if k in added:
+ copy[k] = v
+ elif v in added:
+ copy[v] = k
+
+ for state, char, files in changestates:
+ if state in show:
+ format = "%s %%s%s" % (char, end)
+ if opts.get('no_status'):
+ format = "%%s%s" % end
+
+ for f in files:
+ ui.write(format % repo.pathto(f, cwd),
+ label='status.' + state)
+ if f in copy:
+ ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
+ label='status.copied')
+
+def summary(ui, repo, **opts):
+ """summarize working directory state
+
+ This generates a brief summary of the working directory state,
+ including parents, branch, commit status, and available updates.
+
+ With the --remote option, this will check the default paths for
+ incoming and outgoing changes. This can be time-consuming.
+
+ Returns 0 on success.
+ """
+
+ ctx = repo[None]
+ parents = ctx.parents()
+ pnode = parents[0].node()
+
+ for p in parents:
+ # label with log.changeset (instead of log.parent) since this
+ # shows a working directory parent *changeset*:
+ ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
+ label='log.changeset')
+ ui.write(' '.join(p.tags()), label='log.tag')
+ if p.rev() == -1:
+ if not len(repo):
+ ui.write(_(' (empty repository)'))
+ else:
+ ui.write(_(' (no revision checked out)'))
+ ui.write('\n')
+ if p.description():
+ ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
+ label='log.summary')
+
+ branch = ctx.branch()
+ bheads = repo.branchheads(branch)
+ m = _('branch: %s\n') % branch
+ if branch != 'default':
+ ui.write(m, label='log.branch')
+ else:
+ ui.status(m, label='log.branch')
+
+ st = list(repo.status(unknown=True))[:6]
+
+ c = repo.dirstate.copies()
+ copied, renamed = [], []
+ for d, s in c.iteritems():
+ if s in st[2]:
+ st[2].remove(s)
+ renamed.append(d)
+ else:
+ copied.append(d)
+ if d in st[1]:
+ st[1].remove(d)
+ st.insert(3, renamed)
+ st.insert(4, copied)
+
+ ms = mergemod.mergestate(repo)
+ st.append([f for f in ms if ms[f] == 'u'])
+
+ subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
+ st.append(subs)
+
+ labels = [ui.label(_('%d modified'), 'status.modified'),
+ ui.label(_('%d added'), 'status.added'),
+ ui.label(_('%d removed'), 'status.removed'),
+ ui.label(_('%d renamed'), 'status.copied'),
+ ui.label(_('%d copied'), 'status.copied'),
+ ui.label(_('%d deleted'), 'status.deleted'),
+ ui.label(_('%d unknown'), 'status.unknown'),
+ ui.label(_('%d ignored'), 'status.ignored'),
+ ui.label(_('%d unresolved'), 'resolve.unresolved'),
+ ui.label(_('%d subrepos'), 'status.modified')]
+ t = []
+ for s, l in zip(st, labels):
+ if s:
+ t.append(l % len(s))
+
+ t = ', '.join(t)
+ cleanworkdir = False
+
+ if len(parents) > 1:
+ t += _(' (merge)')
+ elif branch != parents[0].branch():
+ t += _(' (new branch)')
+ elif (parents[0].extra().get('close') and
+ pnode in repo.branchheads(branch, closed=True)):
+ t += _(' (head closed)')
+ elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
+ t += _(' (clean)')
+ cleanworkdir = True
+ elif pnode not in bheads:
+ t += _(' (new branch head)')
+
+ if cleanworkdir:
+ ui.status(_('commit: %s\n') % t.strip())
+ else:
+ ui.write(_('commit: %s\n') % t.strip())
+
+ # all ancestors of branch heads - all ancestors of parent = new csets
+ new = [0] * len(repo)
+ cl = repo.changelog
+ for a in [cl.rev(n) for n in bheads]:
+ new[a] = 1
+ for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
+ new[a] = 1
+ for a in [p.rev() for p in parents]:
+ if a >= 0:
+ new[a] = 0
+ for a in cl.ancestors(*[p.rev() for p in parents]):
+ new[a] = 0
+ new = sum(new)
+
+ if new == 0:
+ ui.status(_('update: (current)\n'))
+ elif pnode not in bheads:
+ ui.write(_('update: %d new changesets (update)\n') % new)
+ else:
+ ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
+ (new, len(bheads)))
+
+ if opts.get('remote'):
+ t = []
+ source, branches = hg.parseurl(ui.expandpath('default'))
+ other = hg.repository(hg.remoteui(repo, {}), source)
+ revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
+ ui.debug('comparing with %s\n' % url.hidepassword(source))
+ repo.ui.pushbuffer()
+ common, incoming, rheads = discovery.findcommonincoming(repo, other)
+ repo.ui.popbuffer()
+ if incoming:
+ t.append(_('1 or more incoming'))
+
+ dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
+ revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
+ other = hg.repository(hg.remoteui(repo, {}), dest)
+ ui.debug('comparing with %s\n' % url.hidepassword(dest))
+ repo.ui.pushbuffer()
+ o = discovery.findoutgoing(repo, other)
+ repo.ui.popbuffer()
+ o = repo.changelog.nodesbetween(o, None)[0]
+ if o:
+ t.append(_('%d outgoing') % len(o))
+
+ if t:
+ ui.write(_('remote: %s\n') % (', '.join(t)))
+ else:
+ ui.status(_('remote: (synced)\n'))
+
+def tag(ui, repo, name1, *names, **opts):
+ """add one or more tags for the current or given revision
+
+ Name a particular revision using <name>.
+
+ Tags are used to name particular revisions of the repository and are
+ very useful to compare different revisions, to go back to significant
+ earlier versions or to mark branch points as releases, etc. Changing
+ an existing tag is normally disallowed; use -f/--force to override.
+
+ If no revision is given, the parent of the working directory is
+ used, or tip if no revision is checked out.
+
+ To facilitate version control, distribution, and merging of tags,
+ they are stored as a file named ".hgtags" which is managed similarly
+ to other project files and can be hand-edited if necessary. This
+ also means that tagging creates a new commit. The file
+ ".hg/localtags" is used for local tags (not shared among
+ repositories).
+
+ Tag commits are usually made at the head of a branch. If the parent
+ of the working directory is not a branch head, :hg:`tag` aborts; use
+ -f/--force to force the tag commit to be based on a non-head
+ changeset.
+
+ See :hg:`help dates` for a list of formats valid for -d/--date.
+
+ Since tag names have priority over branch names during revision
+ lookup, using an existing branch name as a tag name is discouraged.
+
+ Returns 0 on success.
+ """
+
+ rev_ = "."
+ names = [t.strip() for t in (name1,) + names]
+ if len(names) != len(set(names)):
+ raise util.Abort(_('tag names must be unique'))
+ for n in names:
+ if n in ['tip', '.', 'null']:
+ raise util.Abort(_('the name \'%s\' is reserved') % n)
+ if not n:
+ raise util.Abort(_('tag names cannot consist entirely of whitespace'))
+ if opts.get('rev') and opts.get('remove'):
+ raise util.Abort(_("--rev and --remove are incompatible"))
+ if opts.get('rev'):
+ rev_ = opts['rev']
+ message = opts.get('message')
+ if opts.get('remove'):
+ expectedtype = opts.get('local') and 'local' or 'global'
+ for n in names:
+ if not repo.tagtype(n):
+ raise util.Abort(_('tag \'%s\' does not exist') % n)
+ if repo.tagtype(n) != expectedtype:
+ if expectedtype == 'global':
+ raise util.Abort(_('tag \'%s\' is not a global tag') % n)
+ else:
+ raise util.Abort(_('tag \'%s\' is not a local tag') % n)
+ rev_ = nullid
+ if not message:
+ # we don't translate commit messages
+ message = 'Removed tag %s' % ', '.join(names)
+ elif not opts.get('force'):
+ for n in names:
+ if n in repo.tags():
+ raise util.Abort(_('tag \'%s\' already exists '
+ '(use -f to force)') % n)
+ if not opts.get('local'):
+ p1, p2 = repo.dirstate.parents()
+ if p2 != nullid:
+ raise util.Abort(_('uncommitted merge'))
+ bheads = repo.branchheads()
+ if not opts.get('force') and bheads and p1 not in bheads:
+ raise util.Abort(_('not at a branch head (use -f to force)'))
+ r = repo[rev_].node()
+
+ if not message:
+ # we don't translate commit messages
+ message = ('Added tag %s for changeset %s' %
+ (', '.join(names), short(r)))
+
+ date = opts.get('date')
+ if date:
+ date = util.parsedate(date)
+
+ if opts.get('edit'):
+ message = ui.edit(message, ui.username())
+
+ repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
+
+def tags(ui, repo):
+ """list repository tags
+
+ This lists both regular and local tags. When the -v/--verbose
+ switch is used, a third column "local" is printed for local tags.
+
+ Returns 0 on success.
+ """
+
+ hexfunc = ui.debugflag and hex or short
+ tagtype = ""
+
+ for t, n in reversed(repo.tagslist()):
+ if ui.quiet:
+ ui.write("%s\n" % t)
+ continue
+
+ try:
+ hn = hexfunc(n)
+ r = "%5d:%s" % (repo.changelog.rev(n), hn)
+ except error.LookupError:
+ r = " ?:%s" % hn
+ else:
+ spaces = " " * (30 - encoding.colwidth(t))
+ if ui.verbose:
+ if repo.tagtype(t) == 'local':
+ tagtype = " local"
+ else:
+ tagtype = ""
+ ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
+
+def tip(ui, repo, **opts):
+ """show the tip revision
+
+ The tip revision (usually just called the tip) is the changeset
+ most recently added to the repository (and therefore the most
+ recently changed head).
+
+ If you have just made a commit, that commit will be the tip. If
+ you have just pulled changes from another repository, the tip of
+ that repository becomes the current tip. The "tip" tag is special
+ and cannot be renamed or assigned to a different changeset.
+
+ Returns 0 on success.
+ """
+ displayer = cmdutil.show_changeset(ui, repo, opts)
+ displayer.show(repo[len(repo) - 1])
+ displayer.close()
+
+def unbundle(ui, repo, fname1, *fnames, **opts):
+ """apply one or more changegroup files
+
+ Apply one or more compressed changegroup files generated by the
+ bundle command.
+
+ Returns 0 on success, 1 if an update has unresolved files.
+ """
+ fnames = (fname1,) + fnames
+
+ lock = repo.lock()
+ try:
+ for fname in fnames:
+ f = url.open(ui, fname)
+ gen = changegroup.readbundle(f, fname)
+ modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
+ lock=lock)
+ finally:
+ lock.release()
+
+ return postincoming(ui, repo, modheads, opts.get('update'), None)
+
+def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
+ """update working directory (or switch revisions)
+
+ Update the repository's working directory to the specified
+ changeset. If no changeset is specified, update to the tip of the
+ current named branch.
+
+ If the changeset is not a descendant of the working directory's
+ parent, the update is aborted. With the -c/--check option, the
+ working directory is checked for uncommitted changes; if none are
+ found, the working directory is updated to the specified
+ changeset.
+
+ The following rules apply when the working directory contains
+ uncommitted changes:
+
+ 1. If neither -c/--check nor -C/--clean is specified, and if
+ the requested changeset is an ancestor or descendant of
+ the working directory's parent, the uncommitted changes
+ are merged into the requested changeset and the merged
+ result is left uncommitted. If the requested changeset is
+ not an ancestor or descendant (that is, it is on another
+ branch), the update is aborted and the uncommitted changes
+ are preserved.
+
+ 2. With the -c/--check option, the update is aborted and the
+ uncommitted changes are preserved.
+
+ 3. With the -C/--clean option, uncommitted changes are discarded and
+ the working directory is updated to the requested changeset.
+
+ Use null as the changeset to remove the working directory (like
+ :hg:`clone -U`).
+
+ If you want to update just one file to an older changeset, use
+ :hg:`revert`.
+
+ See :hg:`help dates` for a list of formats valid for -d/--date.
+
+ Returns 0 on success, 1 if there are unresolved files.
+ """
+ if rev and node:
+ raise util.Abort(_("please specify just one revision"))
+
+ if not rev:
+ rev = node
+
+ rev = cmdutil.revsingle(repo, rev, rev).rev()
+
+ if check and clean:
+ raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
+
+ if check:
+ # we could use dirty() but we can ignore merge and branch trivia
+ c = repo[None]
+ if c.modified() or c.added() or c.removed():
+ raise util.Abort(_("uncommitted local changes"))
+
+ if date:
+ if rev:
+ raise util.Abort(_("you can't specify a revision and a date"))
+ rev = cmdutil.finddate(ui, repo, date)
+
+ if clean or check:
+ return hg.clean(repo, rev)
+ else:
+ return hg.update(repo, rev)
+
+def verify(ui, repo):
+ """verify the integrity of the repository
+
+ Verify the integrity of the current repository.
+
+ This will perform an extensive check of the repository's
+ integrity, validating the hashes and checksums of each entry in
+ the changelog, manifest, and tracked files, as well as the
+ integrity of their crosslinks and indices.
+
+ Returns 0 on success, 1 if errors are encountered.
+ """
+ return hg.verify(repo)
+
+def version_(ui):
+ """output version and copyright information"""
+ ui.write(_("Mercurial Distributed SCM (version %s)\n")
+ % util.version())
+ ui.status(_(
+ "(see http://mercurial.selenic.com for more information)\n"
+ "\nCopyright (C) 2005-2010 Matt Mackall and others\n"
+ "This is free software; see the source for copying conditions. "
+ "There is NO\nwarranty; "
+ "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
+ ))
+
+# Command options and aliases are listed here, alphabetically
+
+globalopts = [
+ ('R', 'repository', '',
+ _('repository root directory or name of overlay bundle file'),
+ _('REPO')),
+ ('', 'cwd', '',
+ _('change working directory'), _('DIR')),
+ ('y', 'noninteractive', None,
+ _('do not prompt, assume \'yes\' for any required answers')),
+ ('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')),
+]
+
+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 datecode 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')),
+]
+
+similarityopts = [
+ ('s', 'similarity', '',
+ _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
+]
+
+subrepoopts = [
+ ('S', 'subrepos', None,
+ _('recurse into subrepositories'))
+]
+
+table = {
+ "^add": (add, walkopts + subrepoopts + dryrunopts,
+ _('[OPTION]... [FILE]...')),
+ "addremove":
+ (addremove, similarityopts + walkopts + dryrunopts,
+ _('[OPTION]... [FILE]...')),
+ "^annotate|blame":
+ (annotate,
+ [('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...')),
+ "archive":
+ (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')),
+ "backout":
+ (backout,
+ [('', 'merge', None,
+ _('merge with old dirstate parent after backout')),
+ ('', 'parent', '',
+ _('parent to choose when backing out merge'), _('REV')),
+ ('t', 'tool', '',
+ _('specify merge tool')),
+ ('r', 'rev', '',
+ _('revision to backout'), _('REV')),
+ ] + walkopts + commitopts + commitopts2,
+ _('[OPTION]... [-r] REV')),
+ "bisect":
+ (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')),
+ ('c', 'command', '',
+ _('use command to check changeset state'), _('CMD')),
+ ('U', 'noupdate', False, _('do not update to target'))],
+ _("[-gbsr] [-U] [-c CMD] [REV]")),
+ "branch":
+ (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]')),
+ "branches":
+ (branches,
+ [('a', 'active', False,
+ _('show only branches that have unmerged heads')),
+ ('c', 'closed', False,
+ _('show normal and closed branches'))],
+ _('[-ac]')),
+ "bundle":
+ (bundle,
+ [('f', 'force', None,
+ _('run even when the destination is unrelated')),
+ ('r', 'rev', [],
+ _('a changeset intended to be added to the destination'),
+ _('REV')),
+ ('b', 'branch', [],
+ _('a specific branch you would like to bundle'),
+ _('BRANCH')),
+ ('', 'base', [],
+ _('a base changeset assumed to be available at the destination'),
+ _('REV')),
+ ('a', 'all', None, _('bundle all changesets in the repository')),
+ ('t', 'type', 'bzip2',
+ _('bundle compression type to use'), _('TYPE')),
+ ] + remoteopts,
+ _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
+ "cat":
+ (cat,
+ [('o', 'output', '',
+ _('print output to file with formatted name'), _('FORMAT')),
+ ('r', 'rev', '',
+ _('print the given revision'), _('REV')),
+ ('', 'decode', None, _('apply any matching decode filter')),
+ ] + walkopts,
+ _('[OPTION]... FILE...')),
+ "^clone":
+ (clone,
+ [('U', 'noupdate', None,
+ _('the clone will include an empty working copy (only a repository)')),
+ ('u', 'updaterev', '',
+ _('revision, tag or branch to check out'), _('REV')),
+ ('r', 'rev', [],
+ _('include the specified changeset'), _('REV')),
+ ('b', 'branch', [],
+ _('clone only the specified branch'), _('BRANCH')),
+ ('', 'pull', None, _('use pull protocol to copy metadata')),
+ ('', 'uncompressed', None,
+ _('use uncompressed transfer (fast over LAN)')),
+ ] + remoteopts,
+ _('[OPTION]... SOURCE [DEST]')),
+ "^commit|ci":
+ (commit,
+ [('A', 'addremove', None,
+ _('mark new/missing files as added/removed before committing')),
+ ('', 'close-branch', None,
+ _('mark a branch as closed, hiding it from the branch list')),
+ ] + walkopts + commitopts + commitopts2,
+ _('[OPTION]... [FILE]...')),
+ "copy|cp":
+ (copy,
+ [('A', 'after', None, _('record a copy that has already occurred')),
+ ('f', 'force', None,
+ _('forcibly copy over an existing managed file')),
+ ] + walkopts + dryrunopts,
+ _('[OPTION]... [SOURCE]... DEST')),
+ "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
+ "debugbuilddag":
+ (debugbuilddag,
+ [('m', 'mergeable-file', None, _('add single file mergeable changes')),
+ ('a', 'appended-file', None, _('add single file all revs append to')),
+ ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
+ ('n', 'new-file', None, _('add new file at each rev')),
+ ],
+ _('[OPTION]... TEXT')),
+ "debugcheckstate": (debugcheckstate, [], ''),
+ "debugcommands": (debugcommands, [], _('[COMMAND]')),
+ "debugcomplete":
+ (debugcomplete,
+ [('o', 'options', None, _('show the command options'))],
+ _('[-o] CMD')),
+ "debugdag":
+ (debugdag,
+ [('t', 'tags', None, _('use tags as labels')),
+ ('b', 'branches', None, _('annotate with branch names')),
+ ('', 'dots', None, _('use dots for runs')),
+ ('s', 'spaces', None, _('separate elements by spaces')),
+ ],
+ _('[OPTION]... [FILE [REV]...]')),
+ "debugdate":
+ (debugdate,
+ [('e', 'extended', None, _('try extended date formats'))],
+ _('[-e] DATE [RANGE]')),
+ "debugdata": (debugdata, [], _('FILE REV')),
+ "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
+ "debugindex": (debugindex,
+ [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
+ _('FILE')),
+ "debugindexdot": (debugindexdot, [], _('FILE')),
+ "debuginstall": (debuginstall, [], ''),
+ "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
+ "debugrebuildstate":
+ (debugrebuildstate,
+ [('r', 'rev', '',
+ _('revision to rebuild to'), _('REV'))],
+ _('[-r REV] [REV]')),
+ "debugrename":
+ (debugrename,
+ [('r', 'rev', '',
+ _('revision to debug'), _('REV'))],
+ _('[-r REV] FILE')),
+ "debugrevspec":
+ (debugrevspec, [], ('REVSPEC')),
+ "debugsetparents":
+ (debugsetparents, [], _('REV1 [REV2]')),
+ "debugstate":
+ (debugstate,
+ [('', 'nodates', None, _('do not display the saved mtime'))],
+ _('[OPTION]...')),
+ "debugsub":
+ (debugsub,
+ [('r', 'rev', '',
+ _('revision to check'), _('REV'))],
+ _('[-r REV] [REV]')),
+ "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
+ "^diff":
+ (diff,
+ [('r', 'rev', [],
+ _('revision'), _('REV')),
+ ('c', 'change', '',
+ _('change made by revision'), _('REV'))
+ ] + diffopts + diffopts2 + walkopts + subrepoopts,
+ _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
+ "^export":
+ (export,
+ [('o', 'output', '',
+ _('print output to file with formatted name'), _('FORMAT')),
+ ('', 'switch-parent', None, _('diff against the second parent')),
+ ('r', 'rev', [],
+ _('revisions to export'), _('REV')),
+ ] + diffopts,
+ _('[OPTION]... [-o OUTFILESPEC] REV...')),
+ "^forget":
+ (forget,
+ [] + walkopts,
+ _('[OPTION]... FILE...')),
+ "grep":
+ (grep,
+ [('0', 'print0', None, _('end fields with NUL')),
+ ('', 'all', None, _('print all revisions that match')),
+ ('f', 'follow', None,
+ _('follow changeset history,'
+ ' or file history across copies and renames')),
+ ('i', 'ignore-case', None, _('ignore case when matching')),
+ ('l', 'files-with-matches', None,
+ _('print only filenames and revisions that match')),
+ ('n', 'line-number', None, _('print matching line numbers')),
+ ('r', 'rev', [],
+ _('only search files changed within revision range'), _('REV')),
+ ('u', 'user', None, _('list the author (long with -v)')),
+ ('d', 'date', None, _('list the date (short with -q)')),
+ ] + walkopts,
+ _('[OPTION]... PATTERN [FILE]...')),
+ "heads":
+ (heads,
+ [('r', 'rev', '',
+ _('show only heads which are descendants of STARTREV'),
+ _('STARTREV')),
+ ('t', 'topo', False, _('show topological heads only')),
+ ('a', 'active', False,
+ _('show active branchheads only (DEPRECATED)')),
+ ('c', 'closed', False,
+ _('show normal and closed branch heads')),
+ ] + templateopts,
+ _('[-ac] [-r STARTREV] [REV]...')),
+ "help": (help_, [], _('[TOPIC]')),
+ "identify|id":
+ (identify,
+ [('r', 'rev', '',
+ _('identify the specified revision'), _('REV')),
+ ('n', 'num', None, _('show local revision number')),
+ ('i', 'id', None, _('show global revision id')),
+ ('b', 'branch', None, _('show branch')),
+ ('t', 'tags', None, _('show tags'))],
+ _('[-nibt] [-r REV] [SOURCE]')),
+ "import|patch":
+ (import_,
+ [('p', 'strip', 1,
+ _('directory strip option for patch. This has the same '
+ 'meaning as the corresponding patch option'),
+ _('NUM')),
+ ('b', 'base', '',
+ _('base path'), _('PATH')),
+ ('f', 'force', None,
+ _('skip check for outstanding uncommitted changes')),
+ ('', 'no-commit', None,
+ _("don't commit, just update the working directory")),
+ ('', 'exact', None,
+ _('apply patch to the nodes from which it was generated')),
+ ('', 'import-branch', None,
+ _('use any branch information in patch (implied by --exact)'))] +
+ commitopts + commitopts2 + similarityopts,
+ _('[OPTION]... PATCH...')),
+ "incoming|in":
+ (incoming,
+ [('f', 'force', None,
+ _('run even if remote repository is unrelated')),
+ ('n', 'newest-first', None, _('show newest record first')),
+ ('', 'bundle', '',
+ _('file to store the bundles into'), _('FILE')),
+ ('r', 'rev', [],
+ _('a remote changeset intended to be added'), _('REV')),
+ ('b', 'branch', [],
+ _('a specific branch you would like to pull'), _('BRANCH')),
+ ] + logopts + remoteopts + subrepoopts,
+ _('[-p] [-n] [-M] [-f] [-r REV]...'
+ ' [--bundle FILENAME] [SOURCE]')),
+ "^init":
+ (init,
+ remoteopts,
+ _('[-e CMD] [--remotecmd CMD] [DEST]')),
+ "locate":
+ (locate,
+ [('r', 'rev', '',
+ _('search the repository as it is in REV'), _('REV')),
+ ('0', 'print0', None,
+ _('end filenames with NUL, for use with xargs')),
+ ('f', 'fullpath', None,
+ _('print complete paths from the filesystem root')),
+ ] + walkopts,
+ _('[OPTION]... [PATTERN]...')),
+ "^log|history":
+ (log,
+ [('f', 'follow', None,
+ _('follow changeset history,'
+ ' or file history across copies and renames')),
+ ('', 'follow-first', None,
+ _('only follow the first parent of merge changesets')),
+ ('d', 'date', '',
+ _('show revisions matching date spec'), _('DATE')),
+ ('C', 'copies', None, _('show copied files')),
+ ('k', 'keyword', [],
+ _('do case-insensitive search for a given text'), _('TEXT')),
+ ('r', 'rev', [],
+ _('show the specified revision or range'), _('REV')),
+ ('', 'removed', None, _('include revisions where files were removed')),
+ ('m', 'only-merges', None, _('show only merges')),
+ ('u', 'user', [],
+ _('revisions committed by user'), _('USER')),
+ ('', 'only-branch', [],
+ _('show only changesets within the given named branch (DEPRECATED)'),
+ _('BRANCH')),
+ ('b', 'branch', [],
+ _('show changesets within the given named branch'), _('BRANCH')),
+ ('P', 'prune', [],
+ _('do not display revision or any of its ancestors'), _('REV')),
+ ] + logopts + walkopts,
+ _('[OPTION]... [FILE]')),
+ "manifest":
+ (manifest,
+ [('r', 'rev', '',
+ _('revision to display'), _('REV'))],
+ _('[-r REV]')),
+ "^merge":
+ (merge,
+ [('f', 'force', None, _('force a merge with outstanding changes')),
+ ('t', 'tool', '', _('specify merge tool')),
+ ('r', 'rev', '',
+ _('revision to merge'), _('REV')),
+ ('P', 'preview', None,
+ _('review revisions to merge (no merge is performed)'))],
+ _('[-P] [-f] [[-r] REV]')),
+ "outgoing|out":
+ (outgoing,
+ [('f', 'force', None,
+ _('run even when the destination is unrelated')),
+ ('r', 'rev', [],
+ _('a changeset intended to be included in the destination'),
+ _('REV')),
+ ('n', 'newest-first', None, _('show newest record first')),
+ ('b', 'branch', [],
+ _('a specific branch you would like to push'), _('BRANCH')),
+ ] + logopts + remoteopts + subrepoopts,
+ _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
+ "parents":
+ (parents,
+ [('r', 'rev', '',
+ _('show parents of the specified revision'), _('REV')),
+ ] + templateopts,
+ _('[-r REV] [FILE]')),
+ "paths": (paths, [], _('[NAME]')),
+ "^pull":
+ (pull,
+ [('u', 'update', None,
+ _('update to new branch head if changesets were pulled')),
+ ('f', 'force', None,
+ _('run even when remote repository is unrelated')),
+ ('r', 'rev', [],
+ _('a remote changeset intended to be added'), _('REV')),
+ ('b', 'branch', [],
+ _('a specific branch you would like to pull'), _('BRANCH')),
+ ] + remoteopts,
+ _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
+ "^push":
+ (push,
+ [('f', 'force', None, _('force push')),
+ ('r', 'rev', [],
+ _('a changeset intended to be included in the destination'),
+ _('REV')),
+ ('b', 'branch', [],
+ _('a specific branch you would like to push'), _('BRANCH')),
+ ('', 'new-branch', False, _('allow pushing a new branch')),
+ ] + remoteopts,
+ _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
+ "recover": (recover, []),
+ "^remove|rm":
+ (remove,
+ [('A', 'after', None, _('record delete for missing files')),
+ ('f', 'force', None,
+ _('remove (and delete) file even if added or modified')),
+ ] + walkopts,
+ _('[OPTION]... FILE...')),
+ "rename|move|mv":
+ (rename,
+ [('A', 'after', None, _('record a rename that has already occurred')),
+ ('f', 'force', None,
+ _('forcibly copy over an existing managed file')),
+ ] + walkopts + dryrunopts,
+ _('[OPTION]... SOURCE... DEST')),
+ "resolve":
+ (resolve,
+ [('a', 'all', None, _('select all unresolved files')),
+ ('l', 'list', None, _('list state of files needing merge')),
+ ('m', 'mark', None, _('mark files as resolved')),
+ ('u', 'unmark', None, _('mark files as unresolved')),
+ ('t', 'tool', '', _('specify merge tool')),
+ ('n', 'no-status', None, _('hide status prefix'))]
+ + walkopts,
+ _('[OPTION]... [FILE]...')),
+ "revert":
+ (revert,
+ [('a', 'all', None, _('revert all changes when no arguments given')),
+ ('d', 'date', '',
+ _('tipmost revision matching date'), _('DATE')),
+ ('r', 'rev', '',
+ _('revert to the specified revision'), _('REV')),
+ ('', 'no-backup', None, _('do not save backup copies of files')),
+ ] + walkopts + dryrunopts,
+ _('[OPTION]... [-r REV] [NAME]...')),
+ "rollback": (rollback, dryrunopts),
+ "root": (root, []),
+ "^serve":
+ (serve,
+ [('A', 'accesslog', '',
+ _('name of access log file to write to'), _('FILE')),
+ ('d', 'daemon', None, _('run server in background')),
+ ('', 'daemon-pipefds', '',
+ _('used internally by daemon mode'), _('NUM')),
+ ('E', 'errorlog', '',
+ _('name of error log file to write to'), _('FILE')),
+ # use string type, then we can check if something was passed
+ ('p', 'port', '',
+ _('port to listen on (default: 8000)'), _('PORT')),
+ ('a', 'address', '',
+ _('address to listen on (default: all interfaces)'), _('ADDR')),
+ ('', 'prefix', '',
+ _('prefix path to serve from (default: server root)'), _('PREFIX')),
+ ('n', 'name', '',
+ _('name to show in web pages (default: working directory)'),
+ _('NAME')),
+ ('', 'web-conf', '',
+ _('name of the hgweb config file (see "hg help hgweb")'),
+ _('FILE')),
+ ('', 'webdir-conf', '',
+ _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
+ ('', 'pid-file', '',
+ _('name of file to write process ID to'), _('FILE')),
+ ('', 'stdio', None, _('for remote clients')),
+ ('t', 'templates', '',
+ _('web templates to use'), _('TEMPLATE')),
+ ('', 'style', '',
+ _('template style to use'), _('STYLE')),
+ ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
+ ('', 'certificate', '',
+ _('SSL certificate file'), _('FILE'))],
+ _('[OPTION]...')),
+ "showconfig|debugconfig":
+ (showconfig,
+ [('u', 'untrusted', None, _('show untrusted configuration options'))],
+ _('[-u] [NAME]...')),
+ "^summary|sum":
+ (summary,
+ [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
+ "^status|st":
+ (status,
+ [('A', 'all', None, _('show status of all files')),
+ ('m', 'modified', None, _('show only modified files')),
+ ('a', 'added', None, _('show only added files')),
+ ('r', 'removed', None, _('show only removed files')),
+ ('d', 'deleted', None, _('show only deleted (but tracked) files')),
+ ('c', 'clean', None, _('show only files without changes')),
+ ('u', 'unknown', None, _('show only unknown (not tracked) files')),
+ ('i', 'ignored', None, _('show only ignored files')),
+ ('n', 'no-status', None, _('hide status prefix')),
+ ('C', 'copies', None, _('show source of copied files')),
+ ('0', 'print0', None,
+ _('end filenames with NUL, for use with xargs')),
+ ('', 'rev', [],
+ _('show difference from revision'), _('REV')),
+ ('', 'change', '',
+ _('list the changed files of a revision'), _('REV')),
+ ] + walkopts + subrepoopts,
+ _('[OPTION]... [FILE]...')),
+ "tag":
+ (tag,
+ [('f', 'force', None, _('force tag')),
+ ('l', 'local', None, _('make the tag local')),
+ ('r', 'rev', '',
+ _('revision to tag'), _('REV')),
+ ('', 'remove', None, _('remove a tag')),
+ # -l/--local is already there, commitopts cannot be used
+ ('e', 'edit', None, _('edit commit message')),
+ ('m', 'message', '',
+ _('use <text> as commit message'), _('TEXT')),
+ ] + commitopts2,
+ _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
+ "tags": (tags, [], ''),
+ "tip":
+ (tip,
+ [('p', 'patch', None, _('show patch')),
+ ('g', 'git', None, _('use git extended diff format')),
+ ] + templateopts,
+ _('[-p] [-g]')),
+ "unbundle":
+ (unbundle,
+ [('u', 'update', None,
+ _('update to new branch head if changesets were unbundled'))],
+ _('[-u] FILE...')),
+ "^update|up|checkout|co":
+ (update,
+ [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
+ ('c', 'check', None,
+ _('update across branches if no uncommitted changes')),
+ ('d', 'date', '',
+ _('tipmost revision matching date'), _('DATE')),
+ ('r', 'rev', '',
+ _('revision'), _('REV'))],
+ _('[-c] [-C] [-d DATE] [[-r] REV]')),
+ "verify": (verify, []),
+ "version": (version_, []),
+}
+
+norepo = ("clone init version help debugcommands debugcomplete"
+ " debugdate debuginstall debugfsinfo debugpushkey")
+optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
+ " debugdata debugindex debugindexdot")