summaryrefslogtreecommitdiff
path: root/mercurial/commands.py
diff options
context:
space:
mode:
Diffstat (limited to 'mercurial/commands.py')
-rw-r--r--mercurial/commands.py2435
1 files changed, 856 insertions, 1579 deletions
diff --git a/mercurial/commands.py b/mercurial/commands.py
index 092da83..35aee93 100644
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -15,9 +15,8 @@ import archival, changegroup, cmdutil, hbisect
import sshserver, hgweb, hgweb.server, commandserver
import merge as mergemod
import minirst, revset, fileset
-import dagparser, context, simplemerge, graphmod
-import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
-import phases, obsolete
+import dagparser, context, simplemerge
+import random, setdiscovery, treediscovery, dagutil
table = {}
@@ -98,7 +97,6 @@ logopts = [
_('limit number of changes displayed'), _('NUM')),
('M', 'no-merges', None, _('do not show merges')),
('', 'stat', None, _('output diffstat-style summary of changes')),
- ('G', 'graph', None, _("show the revision DAG")),
] + templateopts
diffopts = [
@@ -107,28 +105,20 @@ diffopts = [
('', 'nodates', None, _('omit dates from diff headers'))
]
-diffwsopts = [
+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')),
- ]
-
-diffopts2 = [
- ('p', 'show-function', None, _('show which function each change is in')),
- ('', 'reverse', None, _('produce a diff that undoes the changes')),
- ] + diffwsopts + [
('U', 'unified', '',
_('number of lines of context to show'), _('NUM')),
('', 'stat', None, _('output diffstat-style summary of changes')),
]
-mergetoolopts = [
- ('t', 'tool', '', _('specify merge tool')),
-]
-
similarityopts = [
('s', 'similarity', '',
_('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
@@ -174,7 +164,7 @@ def add(ui, repo, *pats, **opts):
m = scmutil.match(repo[None], pats, opts)
rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
- opts.get('subrepos'), prefix="", explicitonly=False)
+ opts.get('subrepos'), prefix="")
return rejected and 1 or 0
@command('addremove',
@@ -190,15 +180,13 @@ def addremove(ui, repo, *pats, **opts):
``.hgignore``. As with add, these changes take effect at the next
commit.
- Use the -s/--similarity option to detect renamed files. This
+ 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. With a parameter greater than 0,
- this compares every removed file with every added file and records
- those similar enough as renames. Detecting renamed files this way
+ 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. If
- not specified, -s/--similarity defaults to 100 and only renames of
- identical files are detected.
+ used to check which files were identified as moved or renamed.
Returns 0 if all files are successfully added.
"""
@@ -222,7 +210,7 @@ def addremove(ui, repo, *pats, **opts):
('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'))
- ] + diffwsopts + walkopts,
+ ] + walkopts,
_('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
def annotate(ui, repo, *pats, **opts):
"""show changeset information by line for each file
@@ -251,11 +239,9 @@ def annotate(ui, repo, *pats, **opts):
if not pats:
raise util.Abort(_('at least one filename or pattern is required'))
- hexfn = ui.debugflag and hex or short
-
opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
('number', ' ', lambda x: str(x[0].rev())),
- ('changeset', ' ', lambda x: hexfn(x[0].node())),
+ ('changeset', ' ', lambda x: short(x[0].node())),
('date', ' ', getdate),
('file', ' ', lambda x: x[0].path()),
('line_number', ':', lambda x: str(x[1])),
@@ -279,15 +265,13 @@ def annotate(ui, repo, *pats, **opts):
m = scmutil.match(ctx, pats, opts)
m.bad = bad
follow = not opts.get('no_follow')
- diffopts = patch.diffopts(ui, opts, section='annotate')
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,
- diffopts=diffopts)
+ lines = fctx.annotate(follow=follow, linenumber=linenumber)
pieces = []
for f, sep in funcmap:
@@ -302,9 +286,6 @@ def annotate(ui, repo, *pats, **opts):
for p, l in zip(zip(*pieces), lines):
ui.write("%s: %s" % ("".join(p), l[1]))
- if lines and not lines[-1][1].endswith('\n'):
- ui.write('\n')
-
@command('archive',
[('', 'no-decode', None, _('do not pass files through decoders')),
('p', 'prefix', '', _('directory prefix for files in archive'),
@@ -322,18 +303,6 @@ def archive(ui, repo, dest, **opts):
The archive type is automatically detected based on file
extension (or override using -t/--type).
- .. container:: verbose
-
- Examples:
-
- - create a zip file containing the 1.0 release::
-
- hg archive -r 1.0 project-1.0.zip
-
- - create a tarball excluding .hg files::
-
- hg archive project.tar.gz -X ".hg*"
-
Valid types are:
:``files``: a directory full of files (default)
@@ -379,10 +348,10 @@ def archive(ui, repo, dest, **opts):
@command('backout',
[('', 'merge', None, _('merge with old dirstate parent after backout')),
- ('', 'parent', '',
- _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
+ ('', 'parent', '', _('parent to choose when backing out merge'), _('REV')),
+ ('t', 'tool', '', _('specify merge tool')),
('r', 'rev', '', _('revision to backout'), _('REV')),
- ] + mergetoolopts + walkopts + commitopts + commitopts2,
+ ] + walkopts + commitopts + commitopts2,
_('[OPTION]... [-r] REV'))
def backout(ui, repo, node=None, rev=None, **opts):
'''reverse effect of earlier changeset
@@ -394,21 +363,15 @@ def backout(ui, repo, node=None, rev=None, **opts):
is committed automatically. Otherwise, hg needs to merge the
changes and the merged result is left uncommitted.
- .. note::
- backout cannot be used to fix either an unwanted or
- incorrect merge.
-
- .. container:: verbose
-
- By default, the pending changeset will have one parent,
- maintaining a linear history. With --merge, the pending
- changeset will instead have two parents: the old parent of the
- working directory and a new child of REV that simply undoes REV.
+ By default, the pending changeset will have one parent,
+ maintaining a linear history. With --merge, the pending changeset
+ will instead have two parents: the old parent of the working
+ directory and a new child of REV that simply undoes REV.
- Before version 1.7, the behavior without --merge was equivalent
- to specifying --merge followed by :hg:`update --clean .` to
- cancel the merge and leave the child of REV as a head to be
- merged separately.
+ Before version 1.7, the behavior without --merge was equivalent to
+ specifying --merge followed by :hg:`update --clean .` to cancel
+ the merge and leave the child of REV as a head to be merged
+ separately.
See :hg:`help dates` for a list of formats valid for -d/--date.
@@ -440,7 +403,8 @@ def backout(ui, repo, node=None, rev=None, **opts):
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'))
+ 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') %
@@ -452,46 +416,42 @@ def backout(ui, repo, node=None, rev=None, **opts):
parent = p1
# the backout should appear on the same branch
- wlock = repo.wlock()
- try:
- 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', '')
- finally:
- wlock.release()
+ 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
@command('bisect',
@@ -521,65 +481,10 @@ def bisect(ui, repo, rev=None, extra=None, command=None,
revision as good or bad without checking it out first.
If you supply a command, it will be used for automatic bisection.
- The environment variable HG_NODE will contain the ID of the
- changeset being tested. The exit status of the command 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.
-
- .. container:: verbose
-
- Some examples:
-
- - start a bisection with known bad revision 12, and good revision 34::
-
- hg bisect --bad 34
- hg bisect --good 12
-
- - advance the current bisection by marking current revision as good or
- bad::
-
- hg bisect --good
- hg bisect --bad
-
- - mark the current revision, or a known revision, to be skipped (eg. if
- that revision is not usable because of another issue)::
-
- hg bisect --skip
- hg bisect --skip 23
-
- - forget the current bisection::
-
- hg bisect --reset
-
- - use 'make && make tests' to automatically find the first broken
- revision::
-
- hg bisect --reset
- hg bisect --bad 34
- hg bisect --good 12
- hg bisect --command 'make && make tests'
-
- - see all changesets whose states are already known in the current
- bisection::
-
- hg log -r "bisect(pruned)"
-
- - see the changeset currently being bisected (especially useful
- if running with -U/--noupdate)::
-
- hg log -r "bisect(current)"
-
- - see all changesets that took part in the current bisection::
-
- hg log -r "bisect(range)"
-
- - with the graphlog extension, you can even get a nice graph::
-
- hg log --graph -r "bisect(range)"
-
- See :hg:`help revsets` for more about the `bisect()` keyword.
+ 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.
"""
@@ -655,22 +560,9 @@ def bisect(ui, repo, rev=None, extra=None, command=None,
if command:
changesets = 1
try:
- node = state['current'][0]
- except LookupError:
- if noupdate:
- raise util.Abort(_('current bisect revision is unknown - '
- 'start a new bisect to fix'))
- node, p2 = repo.dirstate.parents()
- if p2 != nullid:
- raise util.Abort(_('current bisect revision is a merge'))
- try:
while changesets:
# update state
- state['current'] = [node]
- hbisect.save_state(repo, state)
- status = util.system(command,
- environ={'HG_NODE': hex(node)},
- out=ui.fout)
+ status = util.system(command, out=ui.fout)
if status == 125:
transition = "skip"
elif status == 0:
@@ -682,20 +574,17 @@ def bisect(ui, repo, rev=None, extra=None, command=None,
raise util.Abort(_("%s killed") % command)
else:
transition = "bad"
- ctx = scmutil.revsingle(repo, rev, node)
+ ctx = scmutil.revsingle(repo, rev)
rev = None # clear for future iterations
state[transition].append(ctx.node())
- ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
+ 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
- node = nodes[0]
- if not noupdate:
- cmdutil.bailifchanged(repo)
- hg.clean(repo, node, show_stats=False)
+ cmdutil.bailifchanged(repo)
+ hg.clean(repo, nodes[0], show_stats=False)
finally:
- state['current'] = [node]
hbisect.save_state(repo, state)
print_result(nodes, good)
return
@@ -727,8 +616,6 @@ def bisect(ui, repo, rev=None, extra=None, command=None,
if extendnode is not None:
ui.write(_("Extending search to changeset %d:%s\n"
% (extendnode.rev(), extendnode)))
- state['current'] = [extendnode.node()]
- hbisect.save_state(repo, state)
if noupdate:
return
cmdutil.bailifchanged(repo)
@@ -748,8 +635,6 @@ def bisect(ui, repo, rev=None, extra=None, command=None,
ui.write(_("Testing changeset %d:%s "
"(%d changesets remaining, ~%d tests)\n")
% (rev, short(node), changesets, tests))
- state['current'] = [node]
- hbisect.save_state(repo, state)
if not noupdate:
cmdutil.bailifchanged(repo)
return hg.clean(repo, node)
@@ -759,16 +644,16 @@ def bisect(ui, repo, rev=None, extra=None, command=None,
('r', 'rev', '', _('revision'), _('REV')),
('d', 'delete', False, _('delete a given bookmark')),
('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
- ('i', 'inactive', False, _('mark a bookmark inactive'))],
+ ('i', 'inactive', False, _('do not mark a new bookmark active'))],
_('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
rename=None, inactive=False):
'''track a line of development with movable markers
- Bookmarks are pointers to certain commits that move when committing.
- Bookmarks are local. They can be renamed, copied and deleted. It is
- possible to use :hg:`merge NAME` to merge from a given bookmark, and
- :hg:`update NAME` to update to a given bookmark.
+ Bookmarks are pointers to certain commits that move when
+ committing. Bookmarks are local. They can be renamed, copied and
+ deleted. It is possible to use bookmark names in :hg:`merge` and
+ :hg:`update` to merge and update respectively to a given bookmark.
You can use :hg:`bookmark NAME` to set a bookmark on the working
directory's parent revision with the given name. If you specify
@@ -779,27 +664,11 @@ def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
push` and :hg:`help pull`). This requires both the local and remote
repositories to support bookmarks. For versions prior to 1.8, this means
the bookmarks extension must be enabled.
-
- With -i/--inactive, the new bookmark will not be made the active
- bookmark. If -r/--rev is given, the new bookmark will not be made
- active even if -i/--inactive is not given. If no NAME is given, the
- current active bookmark will be marked inactive.
'''
hexfn = ui.debugflag and hex or short
marks = repo._bookmarks
cur = repo.changectx('.').node()
- if delete:
- if mark is None:
- raise util.Abort(_("bookmark name required"))
- if mark not in marks:
- raise util.Abort(_("bookmark '%s' does not exist") % mark)
- if mark == repo._bookmarkcurrent:
- bookmarks.setcurrent(repo, None)
- del marks[mark]
- bookmarks.write(repo)
- return
-
if rename:
if rename not in marks:
raise util.Abort(_("bookmark '%s' does not exist") % rename)
@@ -815,6 +684,17 @@ def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
bookmarks.write(repo)
return
+ if delete:
+ if mark is None:
+ raise util.Abort(_("bookmark name required"))
+ if mark not in marks:
+ raise util.Abort(_("bookmark '%s' does not exist") % mark)
+ if mark == repo._bookmarkcurrent:
+ bookmarks.setcurrent(repo, None)
+ del marks[mark]
+ bookmarks.write(repo)
+ return
+
if mark is not None:
if "\n" in mark:
raise util.Abort(_("bookmark name cannot contain newlines"))
@@ -828,15 +708,15 @@ def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
if mark in marks and not force:
raise util.Abort(_("bookmark '%s' already exists "
"(use -f to force)") % mark)
- if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
+ if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
and not force):
raise util.Abort(
_("a bookmark cannot have the name of an existing branch"))
if rev:
marks[mark] = repo.lookup(rev)
else:
- marks[mark] = cur
- if not inactive and cur == marks[mark]:
+ marks[mark] = repo.changectx('.').node()
+ if not inactive and repo.changectx('.').node() == marks[mark]:
bookmarks.setcurrent(repo, mark)
bookmarks.write(repo)
return
@@ -870,11 +750,6 @@ def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
def branch(ui, repo, label=None, **opts):
"""set or show the current branch name
- .. note::
- Branch names are permanent and global. Use :hg:`bookmark` to create a
- light-weight bookmark instead. See :hg:`help glossary` for more
- information about named branches and bookmarks.
-
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
@@ -891,31 +766,29 @@ def branch(ui, repo, label=None, **opts):
Use the command :hg:`update` to switch to an existing branch. Use
:hg:`commit --close-branch` to mark this branch as closed.
+ .. note::
+
+ Branch names are permanent. Use :hg:`bookmark` to create a
+ light-weight bookmark instead. See :hg:`help glossary` for more
+ information about named branches and bookmarks.
+
Returns 0 on success.
"""
- if not opts.get('clean') and not label:
- ui.write("%s\n" % repo.dirstate.branch())
- return
- wlock = repo.wlock()
- try:
- if opts.get('clean'):
- label = repo[None].p1().branch()
- repo.dirstate.setbranch(label)
- ui.status(_('reset working directory to branch %s\n') % label)
- elif label:
- if not opts.get('force') and label in repo.branchmap():
- if label not in [p.branch() for p in repo.parents()]:
- raise util.Abort(_('a branch of the same name already'
- ' exists'),
- # i18n: "it" refers to an existing branch
- hint=_("use 'hg update' to switch to it"))
- repo.dirstate.setbranch(label)
- ui.status(_('marked working directory as branch %s\n') % label)
- ui.status(_('(branches are permanent and global, '
- 'did you want a bookmark?)\n'))
- finally:
- wlock.release()
+ if opts.get('clean'):
+ label = repo[None].p1().branch()
+ repo.dirstate.setbranch(label)
+ ui.status(_('reset working directory to branch %s\n') % label)
+ elif label:
+ if not opts.get('force') and label 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'),
+ # i18n: "it" refers to an existing branch
+ hint=_("use 'hg update' to switch to it"))
+ repo.dirstate.setbranch(label)
+ ui.status(_('marked working directory as branch %s\n') % label)
+ else:
+ ui.write("%s\n" % repo.dirstate.branch())
@command('branches',
[('a', 'active', False, _('show only branches that have unmerged heads')),
@@ -937,45 +810,37 @@ def branches(ui, repo, active=False, closed=False):
"""
hexfunc = ui.debugflag and hex or short
-
- activebranches = set([repo[n].branch() for n in repo.heads()])
- branches = []
- for tag, heads in repo.branchmap().iteritems():
- for h in reversed(heads):
- ctx = repo[h]
- isopen = not ctx.closesbranch()
- if isopen:
- tip = ctx
- break
- else:
- tip = repo[heads[-1]]
- isactive = tag in activebranches and isopen
- branches.append((tip, isactive, isopen))
- branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
- reverse=True)
-
- for ctx, isactive, isopen in branches:
+ 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:
- if isactive:
- label = 'branches.active'
- notice = ''
- elif not isopen:
- if not closed:
- continue
- label = 'branches.closed'
- notice = _(' (closed)')
- else:
- label = 'branches.inactive'
- notice = _(' (inactive)')
- if ctx.branch() == repo.dirstate.branch():
- label = 'branches.current'
- rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
- rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
- 'log.changeset')
- tag = ui.label(ctx.branch(), label)
if ui.quiet:
ui.write("%s\n" % tag)
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(tag))
+ rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
+ tag = ui.label(tag, label)
ui.write("%s %s%s\n" % (tag, rev, notice))
@command('bundle',
@@ -1020,12 +885,6 @@ def bundle(ui, repo, fname, dest=None, **opts):
if 'rev' in opts:
revs = scmutil.revrange(repo, opts['rev'])
- 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'))
-
if opts.get('all'):
base = ['null']
else:
@@ -1036,23 +895,27 @@ def bundle(ui, repo, fname, dest=None, **opts):
"a destination"))
common = [repo.lookup(rev) for rev in base]
heads = revs and map(repo.lookup, revs) or revs
- cg = repo.getbundle('bundle', heads=heads, common=common)
- outgoing = None
else:
dest = ui.expandpath(dest or 'default-push', dest or 'default')
dest, branches = hg.parseurl(dest, opts.get('branch'))
other = hg.peer(repo, opts, dest)
revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
heads = revs and map(repo.lookup, revs) or revs
- outgoing = discovery.findcommonoutgoing(repo, other,
- onlyheads=heads,
- force=opts.get('force'),
- portable=True)
- cg = repo.getlocalbundle('bundle', outgoing)
+ common, outheads = discovery.findcommonoutgoing(repo, other,
+ onlyheads=heads,
+ force=opts.get('force'))
+
+ cg = repo.getbundle('bundle', common=common, heads=heads)
if not cg:
- scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
+ ui.status(_("no changes found\n"))
return 1
+ 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)
@command('cat',
@@ -1114,84 +977,56 @@ def clone(ui, source, dest=None, **opts):
The location of the source is added to the new repository's
``.hg/hgrc`` file, as the default to be used for future pulls.
- Only local paths and ``ssh://`` URLs are supported as
- destinations. For ``ssh://`` destinations, no working directory or
- ``.hg/hgrc`` will be created on the remote side.
-
- To pull only a subset of changesets, specify one or more revisions
- identifiers with -r/--rev or branches with -b/--branch. The
- resulting clone will contain only the specified changesets and
- their ancestors. These options (or 'clone src#rev dest') imply
- --pull, even for local source repositories. Note that specifying a
- tag will include the tagged changeset but not the changeset
- containing the tag.
-
- To check out a particular version, use -u/--update, or
- -U/--noupdate to create a clone with no working directory.
-
- .. container:: verbose
-
- 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
-
- Examples:
-
- - clone a remote repository to a new directory named hg/::
-
- hg clone http://selenic.com/hg
-
- - create a lightweight local clone::
-
- hg clone project/ project-feature/
-
- - clone from an absolute path on an ssh server (note double-slash)::
-
- hg clone ssh://user@server//home/projects/alpha/
-
- - do a high-speed clone over a LAN while checking out a
- specified version::
-
- hg clone --uncompressed http://server/repo -u 1.5
-
- - create a repository without changesets after a particular revision::
-
- hg clone -r 04e544 experimental/ good/
-
- - clone (and track) a particular named branch::
-
- hg clone http://selenic.com/hg#stable
-
- See :hg:`help urls` for details on specifying URLs.
+ 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.
"""
@@ -1212,8 +1047,7 @@ def clone(ui, source, dest=None, **opts):
_('mark new/missing files as added/removed before committing')),
('', 'close-branch', None,
_('mark a branch as closed, hiding it from the branch list')),
- ('', 'amend', None, _('amend the parent of the working dir')),
- ] + walkopts + commitopts + commitopts2 + subrepoopts,
+ ] + walkopts + commitopts + commitopts2,
_('[OPTION]... [FILE]...'))
def commit(ui, repo, *pats, **opts):
"""commit the specified files or all outstanding changes
@@ -1233,28 +1067,10 @@ def commit(ui, repo, *pats, **opts):
commit fails, you will find a backup of your message in
``.hg/last-message.txt``.
- The --amend flag can be used to amend the parent of the
- working directory with a new commit that contains the changes
- in the parent in addition to those currently reported by :hg:`status`,
- if there are any. The old commit is stored in a backup bundle in
- ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
- on how to restore it).
-
- Message, user and date are taken from the amended commit unless
- specified. When a message isn't specified on the command line,
- the editor will open with the message of the amended commit.
-
- It is not possible to amend public changesets (see :hg:`help phases`)
- or changesets that have children.
-
See :hg:`help dates` for a list of formats valid for -d/--date.
Returns 0 on success, 1 if nothing changed.
"""
- if opts.get('subrepos'):
- # Let --subrepos on the command line overide config setting.
- ui.setconfig('ui', 'commitsubrepos', True)
-
extra = {}
if opts.get('close_branch'):
if repo['.'].node() not in repo.branchheads():
@@ -1262,81 +1078,32 @@ def commit(ui, repo, *pats, **opts):
# 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)
- if opts.get('amend'):
- if ui.configbool('ui', 'commitsubrepos'):
- raise util.Abort(_('cannot amend recursively'))
-
- old = repo['.']
- if old.phase() == phases.public:
- raise util.Abort(_('cannot amend public changesets'))
- if len(old.parents()) > 1:
- raise util.Abort(_('cannot amend merge changesets'))
- if len(repo[None].parents()) > 1:
- raise util.Abort(_('cannot amend while merging'))
- if old.children():
- raise util.Abort(_('cannot amend changeset with children'))
-
- e = cmdutil.commiteditor
- if opts.get('force_editor'):
- e = cmdutil.commitforceeditor
-
- def commitfunc(ui, repo, message, match, opts):
- editor = e
- # message contains text from -m or -l, if it's empty,
- # open the editor with the old message
- if not message:
- message = old.description()
- editor = cmdutil.commitforceeditor
- return repo.commit(message,
- opts.get('user') or old.user(),
- opts.get('date') or old.date(),
- match,
- editor=editor,
- extra=extra)
-
- current = repo._bookmarkcurrent
- marks = old.bookmarks()
- node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
- if node == old.node():
+ node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
+ if not node:
+ stat = repo.status(match=scmutil.match(repo[None], pats, opts))
+ if stat[3]:
+ ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
+ % len(stat[3]))
+ else:
ui.status(_("nothing changed\n"))
- return 1
- elif marks:
- ui.debug('moving bookmarks %r from %s to %s\n' %
- (marks, old.hex(), hex(node)))
- for bm in marks:
- repo._bookmarks[bm] = node
- if bm == current:
- bookmarks.setcurrent(repo, bm)
- bookmarks.write(repo)
- else:
- 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)
-
- node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
-
- if not node:
- stat = repo.status(match=scmutil.match(repo[None], pats, opts))
- if stat[3]:
- ui.status(_("nothing changed (%d missing files, see "
- "'hg status')\n") % len(stat[3]))
- else:
- ui.status(_("nothing changed\n"))
- return 1
+ return 1
ctx = repo[node]
parents = ctx.parents()
- if (not opts.get('amend') and bheads and node not in bheads and not
- [x for x in parents if x.node() in bheads and x.branch() == branch]):
+ 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:
@@ -1369,7 +1136,7 @@ def commit(ui, repo, *pats, **opts):
if not opts.get('close_branch'):
for r in parents:
- if r.closesbranch() and r.branch() == branch:
+ if r.extra().get('close') and r.branch() == branch:
ui.status(_('reopening closed branch head %d\n') % r)
if ui.debugflag:
@@ -1486,16 +1253,13 @@ def debugbuilddag(ui, repo, text=None,
tags = []
- lock = tr = None
+ tr = repo.transaction("builddag")
try:
- lock = repo.lock()
- tr = repo.transaction("builddag")
at = -1
atbranch = 'default'
nodeids = []
- id = 0
- ui.progress(_('building'), id, unit=_('revisions'), total=total)
+ ui.progress(_('building'), 0, unit=_('revisions'), total=total)
for type, data in dagparser.parsedag(text):
if type == 'n':
ui.note('node %s\n' % str(data))
@@ -1566,12 +1330,12 @@ def debugbuilddag(ui, repo, text=None,
atbranch = data
ui.progress(_('building'), id, unit=_('revisions'), total=total)
tr.close()
-
- if tags:
- repo.opener.write("localtags", "".join(tags))
finally:
ui.progress(_('building'), None)
- release(tr, lock)
+ tr.release()
+
+ if tags:
+ repo.opener.write("localtags", "".join(tags))
@command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
def debugbundle(ui, bundlepath, all=None, **opts):
@@ -1707,8 +1471,7 @@ def debugdag(ui, repo, file_=None, *revs, **opts):
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)))
+ 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:
@@ -1727,8 +1490,7 @@ def debugdag(ui, repo, file_=None, *revs, **opts):
if newb != b:
yield 'a', newb
b = newb
- yield 'n', (r, list(set(p for p in cl.parentrevs(r)
- if p != -1)))
+ yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
if tags:
ls = labels.get(r)
if ls:
@@ -1786,22 +1548,17 @@ def debugdate(ui, date, range=None, **opts):
_('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
def debugdiscovery(ui, repo, remoteurl="default", **opts):
"""runs the changeset discovery protocol in isolation"""
- remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
- opts.get('branch'))
+ remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
remote = hg.peer(repo, opts, remoteurl)
ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
# make sure tests are repeatable
random.seed(12323)
- def doit(localheads, remoteheads, remote=remote):
+ def doit(localheads, remoteheads):
if opts.get('old'):
if localheads:
- raise util.Abort('cannot use localheads with old style '
- 'discovery')
- if not util.safehasattr(remote, 'branches'):
- # enable in-client legacy support
- remote = localrepo.locallegacypeer(remote.local())
+ raise util.Abort('cannot use localheads with old style discovery')
common, _in, hds = treediscovery.findcommonincoming(repo, remote,
force=True)
common = set(common)
@@ -1899,9 +1656,8 @@ def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
def debugignore(ui, repo, *values, **opts):
"""display the combined ignore pattern"""
ignore = repo.dirstate._ignore
- includepat = getattr(ignore, 'includepat', None)
- if includepat is not None:
- ui.write("%s\n" % includepat)
+ if hasattr(ignore, 'includepat'):
+ ui.write("%s\n" % ignore.includepat)
else:
raise util.Abort(_("no ignore patterns found"))
@@ -1928,8 +1684,7 @@ def debugindex(ui, repo, file_ = None, **opts):
" nodeid p1 p2\n")
elif format == 1:
ui.write(" rev flag offset length"
- " size " + basehdr + " link p1 p2"
- " nodeid\n")
+ " size " + basehdr + " link p1 p2 nodeid\n")
for i in r:
node = r.node(i)
@@ -1940,7 +1695,7 @@ def debugindex(ui, repo, file_ = None, **opts):
if format == 0:
try:
pp = r.parents(node)
- except Exception:
+ except:
pp = [nullid, nullid]
ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
i, r.start(i), r.length(i), base, r.linkrev(i),
@@ -1987,7 +1742,7 @@ def debuginstall(ui):
problems = 0
# encoding
- ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
+ ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
try:
encoding.fromlocal("test")
except util.Abort, inst:
@@ -1996,11 +1751,10 @@ def debuginstall(ui):
problems += 1
# compiled modules
- ui.status(_("checking installed modules (%s)...\n")
+ ui.status(_("Checking installed modules (%s)...\n")
% os.path.dirname(__file__))
try:
import bdiff, mpatch, base85, osutil
- dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
except Exception, inst:
ui.write(" %s\n" % inst)
ui.write(_(" One or more extensions could not be found"))
@@ -2008,10 +1762,9 @@ def debuginstall(ui):
problems += 1
# templates
- import templater
- p = templater.templatepath()
- ui.status(_("checking templates (%s)...\n") % ' '.join(p))
+ ui.status(_("Checking templates...\n"))
try:
+ import templater
templater.templater(templater.templatepath("map-cmdline.default"))
except Exception, inst:
ui.write(" %s\n" % inst)
@@ -2019,7 +1772,7 @@ def debuginstall(ui):
problems += 1
# editor
- ui.status(_("checking commit editor...\n"))
+ ui.status(_("Checking commit editor...\n"))
editor = ui.geteditor()
cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
if not cmdpath:
@@ -2034,7 +1787,7 @@ def debuginstall(ui):
problems += 1
# check username
- ui.status(_("checking username...\n"))
+ ui.status(_("Checking username...\n"))
try:
ui.username()
except util.Abort, e:
@@ -2043,7 +1796,7 @@ def debuginstall(ui):
problems += 1
if not problems:
- ui.status(_("no problems detected\n"))
+ ui.status(_("No problems detected\n"))
else:
ui.write(_("%s problems detected,"
" please check your install!\n") % problems)
@@ -2054,8 +1807,8 @@ def debuginstall(ui):
def debugknown(ui, repopath, *ids, **opts):
"""test whether node ids are known to a repo
- Every ID must be a full-length hex node id string. Returns a list of 0s
- and 1s indicating unknown/known.
+ Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
+ indicating unknown/known.
"""
repo = hg.peer(ui, opts, repopath)
if not repo.capable('known'):
@@ -2063,50 +1816,6 @@ def debugknown(ui, repopath, *ids, **opts):
flags = repo.known([bin(s) for s in ids])
ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
-@command('debugobsolete', [] + commitopts2,
- _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
-def debugobsolete(ui, repo, precursor=None, *successors, **opts):
- """create arbitrary obsolete marker"""
- def parsenodeid(s):
- try:
- # We do not use revsingle/revrange functions here to accept
- # arbitrary node identifiers, possibly not present in the
- # local repository.
- n = bin(s)
- if len(n) != len(nullid):
- raise TypeError()
- return n
- except TypeError:
- raise util.Abort('changeset references must be full hexadecimal '
- 'node identifiers')
-
- if precursor is not None:
- metadata = {}
- if 'date' in opts:
- metadata['date'] = opts['date']
- metadata['user'] = opts['user'] or ui.username()
- succs = tuple(parsenodeid(succ) for succ in successors)
- l = repo.lock()
- try:
- tr = repo.transaction('debugobsolete')
- try:
- repo.obsstore.create(tr, parsenodeid(precursor), succs, 0,
- metadata)
- tr.close()
- finally:
- tr.release()
- finally:
- l.release()
- else:
- for m in obsolete.allmarkers(repo):
- ui.write(hex(m.precnode()))
- for repl in m.succnodes():
- ui.write(' ')
- ui.write(hex(repl))
- ui.write(' %X ' % m._data[2])
- ui.write(m.metadata())
- ui.write('\n')
-
@command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
'''access the pushkey key/value protocol
@@ -2128,27 +1837,6 @@ def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
ui.write("%s\t%s\n" % (k.encode('string-escape'),
v.encode('string-escape')))
-@command('debugpvec', [], _('A B'))
-def debugpvec(ui, repo, a, b=None):
- ca = scmutil.revsingle(repo, a)
- cb = scmutil.revsingle(repo, b)
- pa = pvec.ctxpvec(ca)
- pb = pvec.ctxpvec(cb)
- if pa == pb:
- rel = "="
- elif pa > pb:
- rel = ">"
- elif pa < pb:
- rel = "<"
- elif pa | pb:
- rel = "|"
- ui.write(_("a: %s\n") % pa)
- ui.write(_("b: %s\n") % pb)
- ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
- ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
- (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
- pa.distance(pb), rel))
-
@command('debugrebuildstate',
[('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
_('[-r REV] [REV]'))
@@ -2272,11 +1960,6 @@ def debugrevlog(ui, repo, file_ = None, **opts):
elif delta != nullrev:
numother += 1
- # Adjust size min value for empty cases
- for size in (datasize, fullsize, deltasize):
- if size[0] is None:
- size[0] = 0
-
numdeltas = numrevs - numfull
numoprev = numprev - nump1prev - nump2prev
totalrawsize = datasize[2]
@@ -2284,8 +1967,7 @@ def debugrevlog(ui, repo, file_ = None, **opts):
fulltotal = fullsize[2]
fullsize[2] /= numfull
deltatotal = deltasize[2]
- if numrevs - numfull > 0:
- deltasize[2] /= numrevs - numfull
+ deltasize[2] /= numrevs - numfull
totalsize = fulltotal + deltatotal
avgchainlen = sum(chainlengths) / numrevs
compratio = totalrawsize / totalsize
@@ -2337,31 +2019,23 @@ def debugrevlog(ui, repo, file_ = None, **opts):
fmt2 = pcfmtstr(numdeltas, 4)
ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
if numprev > 0:
- ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev,
- numprev))
- ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev,
- numprev))
- ui.write(' other : ' + fmt2 % pcfmt(numoprev,
- numprev))
+ ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
+ ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
+ ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
if gdelta:
ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
- ui.write('deltas against other : ' + fmt % pcfmt(numother,
- numdeltas))
+ ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
@command('debugrevspec', [], ('REVSPEC'))
def debugrevspec(ui, repo, expr):
- """parse and apply a revision specification
-
- Use --verbose to print the parsed tree before and after aliases
- expansion.
- """
+ '''parse and apply a revision specification'''
if ui.verbose:
tree = revset.parse(expr)[0]
- ui.note(revset.prettyformat(tree), "\n")
+ ui.note(tree, "\n")
newtree = revset.findaliases(ui, tree)
if newtree != tree:
- ui.note(revset.prettyformat(newtree), "\n")
+ ui.note(newtree, "\n")
func = revset.match(ui, expr)
for c in func(repo, range(len(repo))):
ui.write("%s\n" % c)
@@ -2381,7 +2055,7 @@ def debugsetparents(ui, repo, rev1, rev2=None):
wlock = repo.wlock()
try:
- repo.setparents(r1, r2)
+ repo.dirstate.setparents(r1, r2)
finally:
wlock.release()
@@ -2412,7 +2086,7 @@ def debugstate(ui, repo, nodates=None, datesort=None):
if ent[1] & 020000:
mode = 'lnk'
else:
- mode = '%3o' % (ent[1] & 0777 & ~util.umask)
+ 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))
@@ -2435,14 +2109,11 @@ def debugwalk(ui, repo, *pats, **opts):
items = list(repo.walk(m))
if not items:
return
- f = lambda fn: fn
- if ui.configbool('ui', 'slash') and os.sep != '/':
- f = lambda fn: util.normpath(fn)
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, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
+ line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
ui.write("%s\n" % line.rstrip())
@command('debugwireargs',
@@ -2499,32 +2170,6 @@ def diff(ui, repo, *pats, **opts):
Use the -g/--git option to generate diffs in the git extended diff
format. For more information, read :hg:`help diffs`.
- .. container:: verbose
-
- Examples:
-
- - compare a file in the current working directory to its parent::
-
- hg diff foo.c
-
- - compare two historical versions of a directory, with rename info::
-
- hg diff --git -r 1.0:1.2 lib/
-
- - get change stats relative to the last change on some date::
-
- hg diff --stat -r "date('may 2')"
-
- - diff all newly-added files that contain a keyword::
-
- hg diff "set:added() and grep(GNU)"
-
- - compare a revision and its parents::
-
- hg diff -c 9353 # compare against first parent
- hg diff -r 9353^:9353 # same using revset syntax
- hg diff -r 9353^2:9353 # compare against the second parent
-
Returns 0 on success.
"""
@@ -2556,7 +2201,7 @@ def diff(ui, repo, *pats, **opts):
('', 'switch-parent', None, _('diff against the second parent')),
('r', 'rev', [], _('revisions to export'), _('REV')),
] + diffopts,
- _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
+ _('[OPTION]... [-o OUTFILESPEC] REV...'))
def export(ui, repo, *changesets, **opts):
"""dump the header and diffs for one or more changesets
@@ -2580,7 +2225,6 @@ def export(ui, repo, *changesets, **opts):
:``%R``: changeset revision number
:``%b``: basename of the exporting repository
:``%h``: short-form changeset hash (12 hexadecimal digits)
- :``%m``: first line of the commit message (only alphanumeric characters)
:``%n``: zero-padded sequence number, starting at 1
:``%r``: zero-padded changeset revision number
@@ -2594,31 +2238,12 @@ def export(ui, repo, *changesets, **opts):
With the --switch-parent option, the diff will be against the
second parent. It can be useful to review a merge.
- .. container:: verbose
-
- Examples:
-
- - use export and import to transplant a bugfix to the current
- branch::
-
- hg export -r 9353 | hg import -
-
- - export all the changesets between two revisions to a file with
- rename information::
-
- hg export --git -r 123:150 > changes.txt
-
- - split outgoing changes into a series of patches with
- descriptive names::
-
- hg export -r "outgoing()" -o "%n-%m.patch"
-
Returns 0 on success.
"""
changesets += tuple(opts.get('rev', []))
- revs = scmutil.revrange(repo, changesets)
- if not revs:
+ if not changesets:
raise util.Abort(_("export requires at least one changeset"))
+ revs = scmutil.revrange(repo, changesets)
if len(revs) > 1:
ui.note(_('exporting patches:\n'))
else:
@@ -2640,18 +2265,6 @@ def forget(ui, repo, *pats, **opts):
To undo a forget before the next commit, see :hg:`add`.
- .. container:: verbose
-
- Examples:
-
- - forget newly-added binary files::
-
- hg forget "set:added() and binary()"
-
- - forget files that would be excluded by .hgignore::
-
- hg forget "set:hgignore()"
-
Returns 0 on success.
"""
@@ -2659,206 +2272,23 @@ def forget(ui, repo, *pats, **opts):
raise util.Abort(_('no files specified'))
m = scmutil.match(repo[None], pats, opts)
- rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
- return rejected and 1 or 0
-
-@command(
- 'graft',
- [('r', 'rev', [], _('revisions to graft'), _('REV')),
- ('c', 'continue', False, _('resume interrupted graft')),
- ('e', 'edit', False, _('invoke editor on commit messages')),
- ('', 'log', None, _('append graft info to log message')),
- ('D', 'currentdate', False,
- _('record the current date as commit date')),
- ('U', 'currentuser', False,
- _('record the current user as committer'), _('DATE'))]
- + commitopts2 + mergetoolopts + dryrunopts,
- _('[OPTION]... [-r] REV...'))
-def graft(ui, repo, *revs, **opts):
- '''copy changes from other branches onto the current branch
-
- This command uses Mercurial's merge logic to copy individual
- changes from other branches without merging branches in the
- history graph. This is sometimes known as 'backporting' or
- 'cherry-picking'. By default, graft will copy user, date, and
- description from the source changesets.
-
- Changesets that are ancestors of the current revision, that have
- already been grafted, or that are merges will be skipped.
-
- If --log is specified, log messages will have a comment appended
- of the form::
-
- (grafted from CHANGESETHASH)
-
- If a graft merge results in conflicts, the graft process is
- interrupted so that the current merge can be manually resolved.
- Once all conflicts are addressed, the graft process can be
- continued with the -c/--continue option.
-
- .. note::
- The -c/--continue option does not reapply earlier options.
-
- .. container:: verbose
-
- Examples:
-
- - copy a single change to the stable branch and edit its description::
-
- hg update stable
- hg graft --edit 9393
-
- - graft a range of changesets with one exception, updating dates::
-
- hg graft -D "2085::2093 and not 2091"
-
- - continue a graft after resolving conflicts::
-
- hg graft -c
-
- - show the source of a grafted changeset::
-
- hg log --debug -r tip
-
- Returns 0 on successful completion.
- '''
-
- revs = list(revs)
- revs.extend(opts['rev'])
-
- if not opts.get('user') and opts.get('currentuser'):
- opts['user'] = ui.username()
- if not opts.get('date') and opts.get('currentdate'):
- opts['date'] = "%d %d" % util.makedate()
-
- editor = None
- if opts.get('edit'):
- editor = cmdutil.commitforceeditor
-
- cont = False
- if opts['continue']:
- cont = True
- if revs:
- raise util.Abort(_("can't specify --continue and revisions"))
- # read in unfinished revisions
- try:
- nodes = repo.opener.read('graftstate').splitlines()
- revs = [repo[node].rev() for node in nodes]
- except IOError, inst:
- if inst.errno != errno.ENOENT:
- raise
- raise util.Abort(_("no graft state found, can't continue"))
- else:
- cmdutil.bailifchanged(repo)
- if not revs:
- raise util.Abort(_('no revisions specified'))
- revs = scmutil.revrange(repo, revs)
-
- # check for merges
- for rev in repo.revs('%ld and merge()', revs):
- ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
- revs.remove(rev)
- if not revs:
- return -1
-
- # check for ancestors of dest branch
- for rev in repo.revs('::. and %ld', revs):
- ui.warn(_('skipping ancestor revision %s\n') % rev)
- revs.remove(rev)
- if not revs:
- return -1
-
- # analyze revs for earlier grafts
- ids = {}
- for ctx in repo.set("%ld", revs):
- ids[ctx.hex()] = ctx.rev()
- n = ctx.extra().get('source')
- if n:
- ids[n] = ctx.rev()
-
- # check ancestors for earlier grafts
- ui.debug('scanning for duplicate grafts\n')
- for ctx in repo.set("::. - ::%ld", revs):
- n = ctx.extra().get('source')
- if n in ids:
- r = repo[n].rev()
- if r in revs:
- ui.warn(_('skipping already grafted revision %s\n') % r)
- revs.remove(r)
- elif ids[n] in revs:
- ui.warn(_('skipping already grafted revision %s '
- '(same origin %d)\n') % (ids[n], r))
- revs.remove(ids[n])
- elif ctx.hex() in ids:
- r = ids[ctx.hex()]
- ui.warn(_('skipping already grafted revision %s '
- '(was grafted from %d)\n') % (r, ctx.rev()))
- revs.remove(r)
- if not revs:
- return -1
-
- wlock = repo.wlock()
- try:
- for pos, ctx in enumerate(repo.set("%ld", revs)):
- current = repo['.']
-
- ui.status(_('grafting revision %s\n') % ctx.rev())
- if opts.get('dry_run'):
- continue
+ s = repo.status(match=m, clean=True)
+ forget = sorted(s[0] + s[1] + s[3] + s[6])
+ errs = 0
- # we don't merge the first commit when continuing
- if not cont:
- # perform the graft merge with p1(rev) as 'ancestor'
- try:
- # ui.forcemerge is an internal variable, do not document
- repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
- stats = mergemod.update(repo, ctx.node(), True, True, False,
- ctx.p1().node())
- finally:
- repo.ui.setconfig('ui', 'forcemerge', '')
- # report any conflicts
- if stats and stats[3] > 0:
- # write out state for --continue
- nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
- repo.opener.write('graftstate', ''.join(nodelines))
- raise util.Abort(
- _("unresolved conflicts, can't continue"),
- hint=_('use hg resolve and hg graft --continue'))
- else:
- cont = False
-
- # drop the second merge parent
- repo.setparents(current.node(), nullid)
- repo.dirstate.write()
- # fix up dirstate for copies and renames
- cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
-
- # commit
- source = ctx.extra().get('source')
- if not source:
- source = ctx.hex()
- extra = {'source': source}
- user = ctx.user()
- if opts.get('user'):
- user = opts['user']
- date = ctx.date()
- if opts.get('date'):
- date = opts['date']
- message = ctx.description()
- if opts.get('log'):
- message += '\n(grafted from %s)' % ctx.hex()
- node = repo.commit(text=message, user=user,
- date=date, extra=extra, editor=editor)
- if node is None:
- ui.status(_('graft for revision %s is empty\n') % ctx.rev())
- finally:
- wlock.release()
+ for f in m.files():
+ if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
+ if os.path.exists(m.rel(f)):
+ ui.warn(_('not removing %s: file is already untracked\n')
+ % m.rel(f))
+ errs = 1
- # remove state when we complete successfully
- if not opts.get('dry_run') and os.path.exists(repo.join('graftstate')):
- util.unlinkpath(repo.join('graftstate'))
+ for f in forget:
+ if ui.verbose or not m.exact(f):
+ ui.status(_('removing %s\n') % m.rel(f))
- return 0
+ repo[None].forget(forget)
+ return errs
@command('grep',
[('0', 'print0', None, _('end fields with NUL')),
@@ -2895,7 +2325,7 @@ def grep(ui, repo, pattern, *pats, **opts):
Returns 0 if a match is found, 1 otherwise.
"""
- reflags = re.M
+ reflags = 0
if opts.get('ignore_case'):
reflags |= re.I
try:
@@ -2919,7 +2349,7 @@ def grep(ui, repo, pattern, *pats, **opts):
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) + 1
+ begin = body.find('\n', mend) + 1 or len(body)
lend = begin - 1
yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
@@ -3076,7 +2506,7 @@ def grep(ui, repo, pattern, *pats, **opts):
('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
('c', 'closed', False, _('show normal and closed branch heads')),
] + templateopts,
- _('[-ct] [-r STARTREV] [REV]...'))
+ _('[-ac] [-r STARTREV] [REV]...'))
def heads(ui, repo, *branchrevs, **opts):
"""show current repository heads or show branch heads
@@ -3130,7 +2560,7 @@ def heads(ui, repo, *branchrevs, **opts):
headless = ', '.join(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']
+ msg += _(' (started at %s)' % opts['rev'])
ui.warn((msg + '\n') % headless)
if not heads:
@@ -3144,11 +2574,9 @@ def heads(ui, repo, *branchrevs, **opts):
@command('help',
[('e', 'extension', None, _('show only help for extensions')),
- ('c', 'command', None, _('show only help for commands')),
- ('k', 'keyword', '', _('show topics matching keyword')),
- ],
+ ('c', 'command', None, _('show only help for commands'))],
_('[-ec] [TOPIC]'))
-def help_(ui, name=None, unknowncmd=False, full=True, **opts):
+def help_(ui, name=None, with_version=False, unknowncmd=False, full=True, **opts):
"""show help for a given topic or a help overview
With no arguments, print a list of commands with short help messages.
@@ -3158,10 +2586,33 @@ def help_(ui, name=None, unknowncmd=False, full=True, **opts):
Returns 0 if successful.
"""
-
+ option_lists = []
textwidth = min(ui.termwidth(), 80) - 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 name and not full:
+ msg = _('use "hg help %s" to show the full help text' % name)
+ elif aliases:
+ msg = _('use "hg -v help%s" to show builtin 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:
@@ -3169,47 +2620,51 @@ def help_(ui, name=None, unknowncmd=False, full=True, **opts):
# except block, nor can be used inside a lambda. python issue4617
prefix = inst.args[0]
select = lambda c: c.lstrip('^').startswith(prefix)
- rst = helplist(select)
- return rst
-
- rst = []
+ 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:
- ui.pushbuffer()
entry[0](ui)
- rst.append(ui.popbuffer())
- return rst
+ return
# synopsis
if len(entry) > 2:
if entry[2].startswith('hg'):
- rst.append("%s\n" % entry[2])
+ ui.write("%s\n" % entry[2])
else:
- rst.append('hg %s %s\n' % (aliases[0], entry[2]))
+ ui.write('hg %s %s\n' % (aliases[0], entry[2]))
else:
- rst.append('hg %s\n' % aliases[0])
+ ui.write('hg %s\n' % aliases[0])
+
# aliases
if full and not ui.quiet and len(aliases) > 1:
- rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
- rst.append('\n')
+ ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
# description
doc = gettext(entry[0].__doc__)
if not doc:
doc = _("(no help text available)")
- if util.safehasattr(entry[0], 'definition'): # aliased command
+ 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)
- doc = doc.splitlines(True)
if ui.quiet or not full:
- rst.append(doc[0])
- else:
- rst.extend(doc)
- rst.append('\n')
+ 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)
# check if this command shadows a non-trivial (multi-line)
# extension help text
@@ -3219,36 +2674,11 @@ def help_(ui, name=None, unknowncmd=False, full=True, **opts):
if '\n' in doc.strip():
msg = _('use "hg help -e %s" to show help for '
'the %s extension') % (name, name)
- rst.append('\n%s\n' % msg)
+ ui.write('\n%s\n' % msg)
except KeyError:
pass
- # options
- if not ui.quiet and entry[1]:
- rst.append('\n%s\n\n' % _("options:"))
- rst.append(help.optrst(entry[1], ui.verbose))
-
- if ui.verbose:
- rst.append('\n%s\n\n' % _("global options:"))
- rst.append(help.optrst(globalopts, ui.verbose))
-
- if not ui.verbose:
- if not full:
- rst.append(_('\nuse "hg help %s" to show the full help text\n')
- % name)
- elif not ui.quiet:
- rst.append(_('\nuse "hg -v help %s" to show more info\n')
- % name)
- return rst
-
-
- def helplist(select=None):
- # list of commands
- if name == "shortlist":
- header = _('basic commands:\n\n')
- else:
- header = _('list of commands:\n\n')
-
+ def helplist(header, select=None):
h = {}
cmds = {}
for c, e in table.iteritems():
@@ -3272,60 +2702,24 @@ def help_(ui, name=None, unknowncmd=False, full=True, **opts):
h[f] = doc.splitlines()[0].rstrip()
cmds[f] = c.lstrip("^")
- rst = []
if not h:
- if not ui.quiet:
- rst.append(_('no commands defined\n'))
- return rst
+ ui.status(_('no commands defined\n'))
+ return
- if not ui.quiet:
- rst.append(header)
+ ui.status(header)
fns = sorted(h)
+ m = max(map(len, fns))
for f in fns:
if ui.verbose:
commands = cmds[f].replace("|",", ")
- rst.append(" :%s: %s\n" % (commands, h[f]))
+ ui.write(" %s:\n %s\n"%(commands, h[f]))
else:
- rst.append(' :%s: %s\n' % (f, h[f]))
-
- if not name:
- exts = help.listexts(_('enabled extensions:'), extensions.enabled())
- if exts:
- rst.append('\n')
- rst.extend(exts)
-
- rst.append(_("\nadditional help topics:\n\n"))
- topics = []
- for names, header, doc in help.helptable:
- topics.append((names[0], header))
- for t, desc in topics:
- rst.append(" :%s: %s\n" % (t, desc))
-
- optlist = []
- if not ui.quiet:
- if ui.verbose:
- optlist.append((_("global options:"), globalopts))
- if name == 'shortlist':
- optlist.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 name and not full:
- msg = _('use "hg help %s" to show the full help '
- 'text') % name
- else:
- msg = _('use "hg -v help%s" to show builtin aliases and '
- 'global options') % (name and " " + name or "")
- optlist.append((msg, ()))
+ ui.write('%s\n' % (util.wrap(h[f], textwidth,
+ initindent=' %-*s ' % (m, f),
+ hangindent=' ' * (m + 4))))
- if optlist:
- for title, options in optlist:
- rst.append('\n%s\n' % title)
- if options:
- rst.append('\n%s\n' % help.optrst(options, ui.verbose))
- return rst
+ if not ui.quiet:
+ addglobalopts(True)
def helptopic(name):
for names, header, doc in help.helptable:
@@ -3334,20 +2728,20 @@ def help_(ui, name=None, unknowncmd=False, full=True, **opts):
else:
raise error.UnknownCommand(name)
- rst = ["%s\n\n" % header]
# description
if not doc:
- rst.append(" %s\n" % _("(no help text available)"))
- if util.safehasattr(doc, '__call__'):
- rst += [" %s\n" % l for l in doc().splitlines()]
+ 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))
try:
cmdutil.findcmd(name, table)
- rst.append(_('\nuse "hg help -c %s" to see help for '
+ ui.write(_('\nuse "hg help -c %s" to see help for '
'the %s command\n') % (name, name))
except error.UnknownCommand:
pass
- return rst
def helpext(name):
try:
@@ -3363,10 +2757,10 @@ def help_(ui, name=None, unknowncmd=False, full=True, **opts):
head, tail = doc, ""
else:
head, tail = doc.split('\n', 1)
- rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)]
+ ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
if tail:
- rst.extend(tail.splitlines(True))
- rst.append('\n')
+ ui.write(minirst.format(tail, textwidth))
+ ui.status('\n\n')
if mod:
try:
@@ -3374,38 +2768,23 @@ def help_(ui, name=None, unknowncmd=False, full=True, **opts):
except AttributeError:
ct = {}
modcmds = set([c.split('|', 1)[0] for c in ct])
- rst.extend(helplist(modcmds.__contains__))
+ helplist(_('list of commands:\n\n'), modcmds.__contains__)
else:
- rst.append(_('use "hg help extensions" for information on enabling '
+ ui.write(_('use "hg help extensions" for information on enabling '
'extensions\n'))
- return rst
def helpextcmd(name):
- cmd, ext, mod = extensions.disabledcmd(ui, name,
- ui.configbool('ui', 'strict'))
+ cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
doc = gettext(mod.__doc__).splitlines()[0]
- rst = help.listexts(_("'%s' is provided by the following "
+ msg = help.listexts(_("'%s' is provided by the following "
"extension:") % cmd, {ext: doc}, indent=4)
- rst.append('\n')
- rst.append(_('use "hg help extensions" for information on enabling '
+ ui.write(minirst.format(msg, textwidth))
+ ui.write('\n\n')
+ ui.write(_('use "hg help extensions" for information on enabling '
'extensions\n'))
- return rst
-
-
- rst = []
- kw = opts.get('keyword')
- if kw:
- matches = help.topicmatch(kw)
- for t, title in (('topics', _('Topics')),
- ('commands', _('Commands')),
- ('extensions', _('Extensions')),
- ('extensioncommands', _('Extension Commands'))):
- if matches[t]:
- rst.append('%s:\n\n' % title)
- rst.extend(minirst.maketable(sorted(matches[t]), 1))
- rst.append('\n')
- elif name and name != 'shortlist':
+
+ if name and name != 'shortlist':
i = None
if unknowncmd:
queries = (helpextcmd,)
@@ -3417,23 +2796,94 @@ def help_(ui, name=None, unknowncmd=False, full=True, **opts):
queries = (helptopic, helpcmd, helpext, helpextcmd)
for f in queries:
try:
- rst = f(name)
+ f(name)
i = None
break
except error.UnknownCommand, inst:
i = inst
if i:
raise i
+
else:
# program name
- if not ui.quiet:
- rst = [_("Mercurial Distributed SCM\n"), '\n']
- rst.extend(helplist())
+ 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')
- keep = ui.verbose and ['verbose'] or []
- formatted, pruned = minirst.format(''.join(rst), textwidth, keep=keep)
- ui.write(formatted)
+ helplist(header)
+ if name != 'shortlist':
+ text = help.listexts(_('enabled extensions:'), extensions.enabled())
+ 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)
@command('identify|id',
[('r', 'rev', '',
@@ -3442,11 +2892,10 @@ def help_(ui, name=None, unknowncmd=False, full=True, **opts):
('i', 'id', None, _('show global revision id')),
('b', 'branch', None, _('show branch')),
('t', 'tags', None, _('show tags')),
- ('B', 'bookmarks', None, _('show bookmarks')),
- ] + remoteopts,
+ ('B', 'bookmarks', None, _('show bookmarks'))],
_('[-nibtB] [-r REV] [SOURCE]'))
def identify(ui, repo, source=None, rev=None,
- num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
+ num=None, id=None, branch=None, tags=None, bookmarks=None):
"""identify the working copy or specified revision
Print a summary identifying the repository state at REV using one or
@@ -3460,22 +2909,6 @@ def identify(ui, repo, source=None, rev=None,
Specifying a path to a repository root or Mercurial bundle will
cause lookup to operate on that repository/bundle.
- .. container:: verbose
-
- Examples:
-
- - generate a build identifier for the working directory::
-
- hg id --id > build-id.dat
-
- - find the revision corresponding to a tag::
-
- hg id -n -r 1.3
-
- - check the most recent revision of a remote repository::
-
- hg id -r tip http://selenic.com/hg/
-
Returns 0 if successful.
"""
@@ -3490,11 +2923,10 @@ def identify(ui, repo, source=None, rev=None,
if source:
source, branches = hg.parseurl(ui.expandpath(source))
- peer = hg.peer(ui, opts, source)
- repo = peer.local()
- revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
+ repo = hg.peer(ui, {}, source)
+ revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
- if not repo:
+ if not repo.local():
if num or branch or tags:
raise util.Abort(
_("can't query remote revision number, branch, or tags"))
@@ -3503,16 +2935,16 @@ def identify(ui, repo, source=None, rev=None,
if not rev:
rev = "tip"
- remoterev = peer.lookup(rev)
+ remoterev = repo.lookup(rev)
if default or id:
output = [hexfunc(remoterev)]
def getbms():
bms = []
- if 'bookmarks' in peer.listkeys('namespaces'):
+ if 'bookmarks' in repo.listkeys('namespaces'):
hexremoterev = hex(remoterev)
- bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
+ bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
if bmr == hexremoterev]
return bms
@@ -3530,9 +2962,7 @@ def identify(ui, repo, source=None, rev=None,
parents = ctx.parents()
changed = ""
if default or id or num:
- if (util.any(repo.status())
- or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
- changed = '+'
+ changed = util.any(repo.status()) and "+" or ""
if default or id:
output = ["%s%s" %
('+'.join([hexfunc(p.node()) for p in parents]), changed)]
@@ -3577,7 +3007,6 @@ def identify(ui, repo, source=None, rev=None,
_('directory strip option for patch. This has the same '
'meaning as the corresponding patch option'), _('NUM')),
('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
- ('e', 'edit', False, _('invoke editor on commit messages')),
('f', 'force', None, _('skip check for outstanding uncommitted changes')),
('', 'no-commit', None,
_("don't commit, just update the working directory")),
@@ -3589,7 +3018,7 @@ def identify(ui, repo, source=None, rev=None,
_('use any branch information in patch (implied by --exact)'))] +
commitopts + commitopts2 + similarityopts,
_('[OPTION]... PATCH...'))
-def import_(ui, repo, patch1=None, *patches, **opts):
+def import_(ui, repo, patch1, *patches, **opts):
"""import an ordered set of patches
Import a list of patches and commit them individually (unless
@@ -3622,49 +3051,20 @@ def import_(ui, repo, patch1=None, *patches, **opts):
revision.
With -s/--similarity, hg will attempt to discover renames and
- copies in the patch in the same way as :hg:`addremove`.
+ 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.
- .. container:: verbose
-
- Examples:
-
- - import a traditional patch from a website and detect renames::
-
- hg import -s 80 http://example.com/bugfix.patch
-
- - import a changeset from an hgweb server::
-
- hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
-
- - import all the patches in an Unix-style mbox::
-
- hg import incoming-patches.mbox
-
- - attempt to exactly restore an exported changeset (not always
- possible)::
-
- hg import --exact proposed-fix.patch
-
Returns 0 on success.
"""
-
- if not patch1:
- raise util.Abort(_('need at least one patch to import'))
-
patches = (patch1,) + patches
date = opts.get('date')
if date:
opts['date'] = util.parsedate(date)
- editor = cmdutil.commiteditor
- if opts.get('edit'):
- editor = cmdutil.commitforceeditor
-
update = not opts.get('bypass')
if not update and opts.get('no_commit'):
raise util.Abort(_('cannot use --no-commit with --bypass'))
@@ -3680,9 +3080,9 @@ def import_(ui, repo, patch1=None, *patches, **opts):
if (opts.get('exact') or not opts.get('force')) and update:
cmdutil.bailifchanged(repo)
- base = opts["base"]
+ d = opts["base"]
strip = opts["strip"]
- wlock = lock = tr = None
+ wlock = lock = None
msgs = []
def checkexact(repo, n, nodeid):
@@ -3695,8 +3095,8 @@ def import_(ui, repo, patch1=None, *patches, **opts):
patch.extract(ui, hunk)
if not tmpname:
- return (None, None)
- msg = _('applied to working directory')
+ return None
+ commitid = _('to working directory')
try:
cmdline_message = cmdutil.logmessage(ui, opts)
@@ -3722,12 +3122,6 @@ def import_(ui, repo, patch1=None, *patches, **opts):
try:
p1 = repo[p1]
p2 = repo[p2]
- # Without any options, consider p2 only if the
- # patch is being applied on top of the recorded
- # first parent.
- if p1 != parents[0]:
- p1 = parents[0]
- p2 = repo[nullid]
except error.RepoError:
p1, p2 = parents
else:
@@ -3735,10 +3129,10 @@ def import_(ui, repo, patch1=None, *patches, **opts):
n = None
if update:
- if p1 != parents[0]:
+ if opts.get('exact') and p1 != parents[0]:
hg.clean(repo, p1.node())
- if p2 != parents[1]:
- repo.setparents(p1.node(), p2.node())
+ if p1 != parents[0] and p2 != parents[1]:
+ repo.dirstate.setparents(p1.node(), p2.node())
if opts.get('exact') or opts.get('import_branch'):
repo.dirstate.setbranch(branch or 'default')
@@ -3751,17 +3145,17 @@ def import_(ui, repo, patch1=None, *patches, **opts):
if message:
msgs.append(message)
else:
- if opts.get('exact') or p2:
- # If you got here, you either use --force and know what
- # you are doing or used --exact or a merge patch while
- # being updated to its first parent.
+ if opts.get('exact'):
m = None
else:
m = scmutil.matchfiles(repo, files or [])
n = repo.commit(message, opts.get('user') or user,
opts.get('date') or date, match=m,
- editor=editor)
+ editor=cmdutil.commiteditor)
checkexact(repo, n, nodeid)
+ # Force a dirstate write so that the next transaction
+ # backups an up-to-date file.
+ repo.dirstate.write()
else:
if opts.get('exact') or opts.get('import_branch'):
branch = branch or 'default'
@@ -3787,56 +3181,45 @@ def import_(ui, repo, patch1=None, *patches, **opts):
finally:
store.close()
if n:
- # i18n: refers to a short changeset id
- msg = _('created %s') % short(n)
- return (msg, n)
+ commitid = short(n)
+ return commitid
finally:
os.unlink(tmpname)
try:
- try:
- wlock = repo.wlock()
- if not opts.get('no_commit'):
- lock = repo.lock()
- tr = repo.transaction('import')
- parents = repo.parents()
- for patchurl in patches:
- if patchurl == '-':
- ui.status(_('applying patch from stdin\n'))
- patchfile = ui.fin
- patchurl = 'stdin' # for error message
+ wlock = repo.wlock()
+ lock = repo.lock()
+ parents = repo.parents()
+ lastcommit = None
+ for p in patches:
+ pf = os.path.join(d, p)
+
+ if pf == '-':
+ ui.status(_("applying patch from stdin\n"))
+ pf = ui.fin
+ else:
+ ui.status(_("applying %s\n") % p)
+ pf = url.open(ui, pf)
+
+ haspatch = False
+ for hunk in patch.split(pf):
+ commitid = tryone(ui, hunk, parents)
+ if commitid:
+ haspatch = True
+ if lastcommit:
+ ui.status(_('applied %s\n') % lastcommit)
+ lastcommit = commitid
+ if update or opts.get('exact'):
+ parents = repo.parents()
else:
- patchurl = os.path.join(base, patchurl)
- ui.status(_('applying %s\n') % patchurl)
- patchfile = url.open(ui, patchurl)
-
- haspatch = False
- for hunk in patch.split(patchfile):
- (msg, node) = tryone(ui, hunk, parents)
- if msg:
- haspatch = True
- ui.note(msg + '\n')
- if update or opts.get('exact'):
- parents = repo.parents()
- else:
- parents = [repo[node]]
-
- if not haspatch:
- raise util.Abort(_('%s: no diffs found') % patchurl)
-
- if tr:
- tr.close()
- if msgs:
- repo.savecommitmessage('\n* * *\n'.join(msgs))
- except: # re-raises
- # wlock.release() indirectly calls dirstate.write(): since
- # we're crashing, we do not want to change the working dir
- # parent after all, so make sure it writes nothing
- repo.dirstate.invalidate()
- raise
+ parents = [repo[commitid]]
+
+ if not haspatch:
+ raise util.Abort(_('no diffs found'))
+
+ if msgs:
+ repo.savecommitmessage('\n* * *\n'.join(msgs))
finally:
- if tr:
- tr.release()
release(lock, wlock)
@command('incoming|in',
@@ -3865,17 +3248,6 @@ def incoming(ui, repo, source="default", **opts):
Returns 0 if there are incoming changes, 1 otherwise.
"""
- if opts.get('graph'):
- cmdutil.checkunsupportedgraphflags([], opts)
- def display(other, chlist, displayer):
- revdag = cmdutil.graphrevs(other, chlist, opts)
- showparents = [ctx.node() for ctx in repo[None].parents()]
- cmdutil.displaygraph(ui, revdag, displayer, showparents,
- graphmod.asciiedges)
-
- hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
- return 0
-
if opts.get('bundle') and opts.get('subrepos'):
raise util.Abort(_('cannot combine --bundle and --subrepos'))
@@ -3959,14 +3331,14 @@ def locate(ui, repo, *pats, **opts):
[('f', 'follow', None,
_('follow changeset history, or file history across copies and renames')),
('', 'follow-first', None,
- _('only follow the first parent of merge changesets (DEPRECATED)')),
+ _('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 (DEPRECATED)')),
+ ('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)'),
@@ -3975,7 +3347,7 @@ def locate(ui, repo, *pats, **opts):
_('show changesets within the given named branch'), _('BRANCH')),
('P', 'prune', [],
_('do not display revision or any of its ancestors'), _('REV')),
- ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
+ ('', 'hidden', False, _('show hidden changesets')),
] + logopts + walkopts,
_('[OPTION]... [FILE]'))
def log(ui, repo, *pats, **opts):
@@ -3984,14 +3356,18 @@ def log(ui, repo, *pats, **opts):
Print the revision history of the specified files or the entire
project.
- 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.
-
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.
+ 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
@@ -4004,77 +3380,19 @@ def log(ui, repo, *pats, **opts):
its first parent. Also, only files different from BOTH parents
will appear in files:.
- .. note::
- for performance reasons, log FILE may omit duplicate changes
- made on branches and will not show deletions. To see all
- changes including duplicates and deletions, use the --removed
- switch.
-
- .. container:: verbose
-
- Some examples:
-
- - changesets with full descriptions and file lists::
-
- hg log -v
-
- - changesets ancestral to the working directory::
-
- hg log -f
-
- - last 10 commits on the current branch::
-
- hg log -l 10 -b .
-
- - changesets showing all modifications of a file, including removals::
-
- hg log --removed file.c
-
- - all changesets that touch a directory, with diffs, excluding merges::
-
- hg log -Mp lib/
-
- - all revision numbers that match a keyword::
-
- hg log -k bug --template "{rev}\\n"
-
- - check if a given changeset is included is a tagged release::
-
- hg log -r "a21ccf and ancestor(1.9)"
-
- - find all changesets by some user in a date range::
-
- hg log -k alice -d "may 2008 to jul 2008"
-
- - summary of all changesets after the last tag::
-
- hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
-
- See :hg:`help dates` for a list of formats valid for -d/--date.
-
- See :hg:`help revisions` and :hg:`help revsets` for more about
- specifying revisions.
-
- See :hg:`help templates` for more about pre-packaged styles and
- specifying custom templates.
-
Returns 0 on success.
"""
- if opts.get('graph'):
- return cmdutil.graphlog(ui, repo, *pats, **opts)
matchfn = scmutil.match(repo[None], pats, opts)
limit = cmdutil.loglimit(opts)
count = 0
- getrenamed, endrev = None, None
- if opts.get('copies'):
- if opts.get('rev'):
- endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
- getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
+ endrev = None
+ if opts.get('copies') and opts.get('rev'):
+ endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
df = False
- if opts.get("date"):
+ if opts["date"]:
df = util.matchdate(opts["date"])
branches = opts.get('branch', []) + opts.get('only_branch', [])
@@ -4095,28 +3413,22 @@ def log(ui, repo, *pats, **opts):
return
if df and not df(ctx.date()[0]):
return
-
- lower = encoding.lower
- if opts.get('user'):
- luser = lower(ctx.user())
- for k in [lower(x) for x in opts['user']]:
- if (k in luser):
- break
- else:
- return
+ if opts['user'] and not [k for k in opts['user']
+ if k.lower() in ctx.user().lower()]:
+ return
if opts.get('keyword'):
- luser = lower(ctx.user())
- ldesc = lower(ctx.description())
- lfiles = lower(" ".join(ctx.files()))
- for k in [lower(x) for x in opts['keyword']]:
- if (k in luser or k in ldesc or k in lfiles):
+ 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 getrenamed is not None and rev:
+ if opts.get('copies') and rev:
copies = []
+ getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
for fn in ctx.files():
rename = getrenamed(fn, rev)
if rename:
@@ -4195,10 +3507,10 @@ def manifest(ui, repo, node=None, rev=None, **opts):
@command('^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)'))
- ] + mergetoolopts,
+ _('review revisions to merge (no merge is performed)'))],
_('[-P] [-f] [[-r] REV]'))
def merge(ui, repo, node=None, **opts):
"""merge working directory with another revision
@@ -4234,61 +3546,34 @@ def merge(ui, repo, node=None, **opts):
if not node:
node = opts.get('rev')
- if node:
- node = scmutil.revsingle(repo, node).node()
-
- if not node and repo._bookmarkcurrent:
- bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
- curhead = repo[repo._bookmarkcurrent]
- if len(bmheads) == 2:
- if curhead == bmheads[0]:
- node = bmheads[1]
- else:
- node = bmheads[0]
- elif len(bmheads) > 2:
- raise util.Abort(_("multiple matching bookmarks to merge - "
- "please merge with an explicit rev or bookmark"),
- hint=_("run 'hg heads' to see all heads"))
- elif len(bmheads) <= 1:
- raise util.Abort(_("no matching bookmark to merge - "
- "please merge with an explicit rev or bookmark"),
- hint=_("run 'hg heads' to see all heads"))
-
- if not node and not repo._bookmarkcurrent:
+ if not node:
branch = repo[None].branch()
bheads = repo.branchheads(branch)
- nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
-
- if len(nbhs) > 2:
+ if len(bheads) > 2:
raise util.Abort(_("branch '%s' has %d heads - "
"please merge with an explicit rev")
% (branch, len(bheads)),
hint=_("run 'hg heads .' to see heads"))
parent = repo.dirstate.p1()
- if len(nbhs) == 1:
- if len(bheads) > 1:
- raise util.Abort(_("heads are bookmarked - "
- "please merge with an explicit rev"),
- hint=_("run 'hg heads' to see all heads"))
+ if len(bheads) == 1:
if len(repo.heads()) > 1:
raise util.Abort(_("branch '%s' has one head - "
"please merge with an explicit rev")
% branch,
hint=_("run 'hg heads' to see all heads"))
- msg, hint = _('nothing to merge'), None
- if parent != repo.lookup(branch):
- hint = _("use 'hg update' instead")
- raise util.Abort(msg, hint=hint)
+ 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 directory not at a head revision'),
hint=_("use 'hg update' or merge with an "
"explicit revision"))
- if parent == nbhs[0]:
- node = nbhs[-1]
- else:
- node = nbhs[0]
+ node = parent == bheads[0] and bheads[-1] or bheads[0]
+ else:
+ node = scmutil.revsingle(repo, node).node()
if opts.get('preview'):
# find nodes that are ancestors of p2 but not of p1
@@ -4304,7 +3589,7 @@ def merge(ui, repo, node=None, **opts):
try:
# ui.forcemerge is an internal variable, do not document
- repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
+ ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
return hg.merge(repo, node, force=opts.get('force'))
finally:
ui.setconfig('ui', 'forcemerge', '')
@@ -4330,18 +3615,6 @@ def outgoing(ui, repo, dest=None, **opts):
Returns 0 if there are outgoing changes, 1 otherwise.
"""
- if opts.get('graph'):
- cmdutil.checkunsupportedgraphflags([], opts)
- o = hg._outgoing(ui, repo, dest, opts)
- if o is None:
- return
-
- revdag = cmdutil.graphrevs(repo, o, opts)
- displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
- showparents = [ctx.node() for ctx in repo[None].parents()]
- cmdutil.displaygraph(ui, revdag, displayer, showparents,
- graphmod.asciiedges)
- return 0
if opts.get('bookmarks'):
dest = ui.expandpath(dest or 'default-push', dest or 'default')
@@ -4447,106 +3720,21 @@ def paths(ui, repo, search=None):
else:
ui.write("%s = %s\n" % (name, util.hidepassword(path)))
-@command('^phase',
- [('p', 'public', False, _('set changeset phase to public')),
- ('d', 'draft', False, _('set changeset phase to draft')),
- ('s', 'secret', False, _('set changeset phase to secret')),
- ('f', 'force', False, _('allow to move boundary backward')),
- ('r', 'rev', [], _('target revision'), _('REV')),
- ],
- _('[-p|-d|-s] [-f] [-r] REV...'))
-def phase(ui, repo, *revs, **opts):
- """set or show the current phase name
-
- With no argument, show the phase name of specified revisions.
-
- With one of -p/--public, -d/--draft or -s/--secret, change the
- phase value of the specified revisions.
-
- Unless -f/--force is specified, :hg:`phase` won't move changeset from a
- lower phase to an higher phase. Phases are ordered as follows::
-
- public < draft < secret
-
- Return 0 on success, 1 if no phases were changed or some could not
- be changed.
- """
- # search for a unique phase argument
- targetphase = None
- for idx, name in enumerate(phases.phasenames):
- if opts[name]:
- if targetphase is not None:
- raise util.Abort(_('only one phase can be specified'))
- targetphase = idx
-
- # look for specified revision
- revs = list(revs)
- revs.extend(opts['rev'])
- if not revs:
- raise util.Abort(_('no revisions specified'))
-
- revs = scmutil.revrange(repo, revs)
-
- lock = None
- ret = 0
- if targetphase is None:
- # display
- for r in revs:
- ctx = repo[r]
- ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
- else:
- lock = repo.lock()
- try:
- # set phase
- if not revs:
- raise util.Abort(_('empty revision set'))
- nodes = [repo[r].node() for r in revs]
- olddata = repo._phasecache.getphaserevs(repo)[:]
- phases.advanceboundary(repo, targetphase, nodes)
- if opts['force']:
- phases.retractboundary(repo, targetphase, nodes)
- finally:
- lock.release()
- newdata = repo._phasecache.getphaserevs(repo)
- changes = sum(o != newdata[i] for i, o in enumerate(olddata))
- rejected = [n for n in nodes
- if newdata[repo[n].rev()] < targetphase]
- if rejected:
- ui.warn(_('cannot move %i changesets to a more permissive '
- 'phase, use --force\n') % len(rejected))
- ret = 1
- if changes:
- msg = _('phase changed for %i changesets\n') % changes
- if ret:
- ui.status(msg)
- else:
- ui.note(msg)
- else:
- ui.warn(_('no phases changed\n'))
- ret = 1
- return ret
-
def postincoming(ui, repo, modheads, optupdate, checkout):
if modheads == 0:
return
if optupdate:
- movemarkfrom = repo['.'].node()
try:
- ret = hg.update(repo, checkout)
+ return hg.update(repo, checkout)
except util.Abort, inst:
- ui.warn(_("not updating: %s\n") % str(inst))
+ ui.warn(_("not updating: %s\n" % str(inst)))
return 0
- if not ret and not checkout:
- if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
- ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
- return ret
if modheads > 1:
currentbranchheads = len(repo.branchheads())
if currentbranchheads == modheads:
ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
elif currentbranchheads > 1:
- ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
- "merge)\n"))
+ ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
else:
ui.status(_("(run 'hg heads' to see heads)\n"))
else:
@@ -4605,7 +3793,7 @@ def pull(ui, repo, source="default", **opts):
raise util.Abort(err)
modheads = repo.pull(other, heads=revs, force=opts.get('force'))
- bookmarks.updatefromremote(ui, repo, other, source)
+ bookmarks.updatefromremote(ui, repo, other)
if checkout:
checkout = str(repo.changelog.rev(other.lookup(checkout)))
repo._subtoppath = source
@@ -4660,10 +3848,6 @@ def push(ui, repo, dest=None, **opts):
If -r/--rev is used, the specified revision and all its ancestors
will be pushed to the remote repository.
- If -B/--bookmark is used, the specified bookmarked revision, its
- ancestors, and the bookmark 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.
@@ -4686,7 +3870,7 @@ def push(ui, repo, dest=None, **opts):
revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
other = hg.peer(repo, opts, dest)
if revs:
- revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
+ revs = [repo.lookup(rev) for rev in revs]
repo._subtoppath = dest
try:
@@ -4694,14 +3878,14 @@ def push(ui, repo, dest=None, **opts):
c = repo['']
subs = c.substate # only repos that are committed
for s in sorted(subs):
- if c.sub(s).push(opts) == 0:
+ if not c.sub(s).push(opts.get('force')):
return False
finally:
del repo._subtoppath
result = repo.push(other, opts.get('force'), revs=revs,
newbranch=opts.get('new_branch'))
- result = not result
+ result = (result == 0)
if opts.get('bookmark'):
rb = other.listkeys('bookmarks')
@@ -4751,36 +3935,31 @@ def recover(ui, repo):
def remove(ui, repo, *pats, **opts):
"""remove the specified files on the next commit
- Schedule the indicated files for removal from the current branch.
-
- This command schedules the files to be removed at the next commit.
- To undo a remove before that, see :hg:`revert`. To undo added
- files, see :hg:`forget`.
+ Schedule the indicated files for removal from the repository.
- .. container:: verbose
+ 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
+
+ Note that remove never deletes files in Added [A] state from the
+ working directory, not even if option --force is specified.
- -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
- ======= == == == ==
-
- Note that remove never deletes files in Added [A] state from the
- working directory, not even if option --force is specified.
+ 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.
"""
@@ -4815,8 +3994,8 @@ def remove(ui, repo, *pats, **opts):
' 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 forget to undo)\n') % m.rel(f))
+ 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(list):
@@ -4872,8 +4051,9 @@ def rename(ui, repo, *pats, **opts):
('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'))]
- + mergetoolopts + walkopts,
+ + walkopts,
_('[OPTION]... [FILE]...'))
def resolve(ui, repo, *pats, **opts):
"""redo merges or set/view the merge status of files
@@ -4883,8 +4063,7 @@ def resolve(ui, repo, *pats, **opts):
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). See :hg:`help
- merge-tools` for information on configuring merge tools.
+ working directory must have two parents).
The resolve command can be used in the following ways:
@@ -4893,8 +4072,7 @@ def resolve(ui, repo, *pats, **opts):
performed for files already marked as resolved. Use ``--all/-a``
to select 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. Previous file
- contents are saved with a ``.orig`` suffix.
+ 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
@@ -4967,17 +4145,15 @@ def resolve(ui, repo, *pats, **opts):
[('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')),
- ('C', 'no-backup', None, _('do not save backup copies of files')),
+ ('', 'no-backup', None, _('do not save backup copies of files')),
] + walkopts + dryrunopts,
_('[OPTION]... [-r REV] [NAME]...'))
def revert(ui, repo, *pats, **opts):
"""restore files to their checkout state
.. note::
-
To check out earlier revisions, you should use :hg:`update REV`.
- To cancel an uncommitted merge (and lose your changes), use
- :hg:`update --clean .`.
+ To cancel a merge (and lose your changes), use :hg:`update --clean .`.
With no revision specified, revert the specified files or directories
to the contents they had in the parent of the working directory.
@@ -5013,6 +4189,7 @@ def revert(ui, repo, *pats, **opts):
hint=_('use "hg update" or see "hg help revert"'))
ctx = scmutil.revsingle(repo, opts.get('rev'))
+ node = ctx.node()
if not pats and not opts.get('all'):
msg = _("no files or directories specified")
@@ -5021,7 +4198,6 @@ def revert(ui, repo, *pats, **opts):
" or 'hg update -C .' to abort the merge")
raise util.Abort(msg, hint=hint)
dirty = util.any(repo.status())
- node = ctx.node()
if node != parent:
if dirty:
hint = _("uncommitted changes, use --all to discard all"
@@ -5035,10 +4211,177 @@ def revert(ui, repo, *pats, **opts):
hint = _("use --all to revert all files")
raise util.Abort(msg, hint=hint)
- return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
+ 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 = scmutil.match(repo[None], 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 = scmutil.match(repo[node], 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 = scmutil.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 = scmutil.pathauditor(repo.root)
+ for f in remove[0]:
+ if repo.dirstate[f] == 'a':
+ repo.dirstate.drop(f)
+ continue
+ audit_path(f)
+ try:
+ util.unlinkpath(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()
-@command('rollback', dryrunopts +
- [('f', 'force', False, _('ignore safety measures'))])
+@command('rollback', dryrunopts)
def rollback(ui, repo, **opts):
"""roll back the last transaction (dangerous)
@@ -5050,22 +4393,14 @@ def rollback(ui, repo, **opts):
Transactions are used to encapsulate the effects of all commands
that create new changesets or propagate existing changesets into a
- repository.
-
- .. container:: verbose
-
- For example, the following commands are transactional, and their
- effects can be rolled back:
+ 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
-
- To avoid permanent data loss, rollback will refuse to rollback a
- commit transaction if it isn't checked out. Use --force to
- override this protection.
+ - 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
@@ -5076,8 +4411,7 @@ def rollback(ui, repo, **opts):
Returns 0 on success, 1 if no rollback data is available.
"""
- return repo.rollback(dryrun=opts.get('dry_run'),
- force=opts.get('force'))
+ return repo.rollback(opts.get('dry_run'))
@command('root', [])
def root(ui, repo):
@@ -5145,7 +4479,7 @@ def serve(ui, repo, **opts):
def checkrepo():
if repo is None:
- raise error.RepoError(_("there is no Mercurial repository here"
+ raise error.RepoError(_("There is no Mercurial repository here"
" (.hg not found)"))
if opts["stdio"]:
@@ -5176,7 +4510,7 @@ def serve(ui, repo, **opts):
o = opts.get('web_conf') or opts.get('webdir_conf')
if not o:
if not repo:
- raise error.RepoError(_("there is no Mercurial repository"
+ raise error.RepoError(_("There is no Mercurial repository"
" here (.hg not found)"))
o = repo.root
@@ -5319,23 +4653,6 @@ def status(ui, repo, *pats, **opts):
I = ignored
= origin of the previous file listed as A (added)
- .. container:: verbose
-
- Examples:
-
- - show changes in the working directory relative to a
- changeset::
-
- hg status --rev 9353
-
- - show all changes including copies in an existing changeset::
-
- hg status --copies --change 9353
-
- - get a NUL separated list of added files, suitable for xargs::
-
- hg status -an0
-
Returns 0 on success.
"""
@@ -5346,7 +4663,7 @@ def status(ui, repo, *pats, **opts):
msg = _('cannot specify --rev and --change at the same time')
raise util.Abort(msg)
elif change:
- node2 = scmutil.revsingle(repo, change, None).node()
+ node2 = repo.lookup(change)
node1 = repo[node2].p1().node()
else:
node1, node2 = scmutil.revpair(repo, revs)
@@ -5367,24 +4684,31 @@ def status(ui, repo, *pats, **opts):
changestates = zip(states, 'MAR!?IC', stat)
if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
- copy = copies.pathcopies(repo[node1], repo[node2])
-
- fm = ui.formatter('status', opts)
- format = '%s %s' + end
- if opts.get('no_status'):
- format = '%.0s%s' + end
+ 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:
- label = 'status.' + state
+ format = "%s %%s%s" % (char, end)
+ if opts.get('no_status'):
+ format = "%%s%s" % end
+
for f in files:
- fm.startitem()
- fm.write("status path", format, char,
- repo.pathto(f, cwd), label=label)
+ ui.write(format % repo.pathto(f, cwd),
+ label='status.' + state)
if f in copy:
- fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
+ ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
label='status.copied')
- fm.end()
@command('^summary|sum',
[('', 'remote', None, _('check for push and pull'))], '[--remote]')
@@ -5403,7 +4727,6 @@ def summary(ui, repo, **opts):
ctx = repo[None]
parents = ctx.parents()
pnode = parents[0].node()
- marks = []
for p in parents:
# label with log.changeset (instead of log.parent) since this
@@ -5412,7 +4735,7 @@ def summary(ui, repo, **opts):
label='log.changeset')
ui.write(' '.join(p.tags()), label='log.tag')
if p.bookmarks():
- marks.extend(p.bookmarks())
+ ui.write(' ' + ' '.join(p.bookmarks()), label='log.bookmark')
if p.rev() == -1:
if not len(repo):
ui.write(_(' (empty repository)'))
@@ -5431,20 +4754,6 @@ def summary(ui, repo, **opts):
else:
ui.status(m, label='log.branch')
- if marks:
- current = repo._bookmarkcurrent
- ui.write(_('bookmarks:'), label='log.bookmark')
- if current is not None:
- try:
- marks.remove(current)
- ui.write(' *' + current, label='bookmarks.current')
- except ValueError:
- # current bookmark not in parent ctx marks
- pass
- for m in marks:
- ui.write(' ' + m, label='log.bookmark')
- ui.write('\n', label='log.bookmark')
-
st = list(repo.status(unknown=True))[:6]
c = repo.dirstate.copies()
@@ -5488,7 +4797,7 @@ def summary(ui, repo, **opts):
t += _(' (merge)')
elif branch != parents[0].branch():
t += _(' (new branch)')
- elif (parents[0].closesbranch() and
+ 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]):
@@ -5507,12 +4816,12 @@ def summary(ui, repo, **opts):
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]):
+ 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]):
+ for a in cl.ancestors(*[p.rev() for p in parents]):
new[a] = 0
new = sum(new)
@@ -5528,8 +4837,7 @@ def summary(ui, repo, **opts):
t = []
source, branches = hg.parseurl(ui.expandpath('default'))
other = hg.peer(repo, {}, source)
- revs, checkout = hg.addbranchrevs(repo, other, branches,
- opts.get('rev'))
+ revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
ui.debug('comparing with %s\n' % util.hidepassword(source))
repo.ui.pushbuffer()
commoninc = discovery.findcommonincoming(repo, other)
@@ -5545,10 +4853,10 @@ def summary(ui, repo, **opts):
commoninc = None
ui.debug('comparing with %s\n' % util.hidepassword(dest))
repo.ui.pushbuffer()
- outgoing = discovery.findcommonoutgoing(repo, other,
- commoninc=commoninc)
+ common, outheads = discovery.findcommonoutgoing(repo, other,
+ commoninc=commoninc)
repo.ui.popbuffer()
- o = outgoing.missing
+ o = repo.changelog.findmissing(common=common, heads=outheads)
if o:
t.append(_('%d outgoing') % len(o))
if 'bookmarks' in other.listkeys('namespaces'):
@@ -5608,73 +4916,62 @@ def tag(ui, repo, name1, *names, **opts):
Returns 0 on success.
"""
- wlock = lock = None
- try:
- wlock = repo.wlock()
- lock = repo.lock()
- 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 = scmutil.revsingle(repo, rev_).node()
+ 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 = ('Added tag %s for changeset %s' %
- (', '.join(names), short(r)))
+ 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 = scmutil.revsingle(repo, rev_).node()
- date = opts.get('date')
- if date:
- date = util.parsedate(date)
+ if not message:
+ # we don't translate commit messages
+ message = ('Added tag %s for changeset %s' %
+ (', '.join(names), short(r)))
- if opts.get('edit'):
- message = ui.edit(message, ui.username())
+ date = opts.get('date')
+ if date:
+ date = util.parsedate(date)
- # don't allow tagging the null rev
- if (not opts.get('remove') and
- scmutil.revsingle(repo, rev_).rev() == nullrev):
- raise util.Abort(_("null revision specified"))
+ if opts.get('edit'):
+ message = ui.edit(message, ui.username())
- repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
- finally:
- release(lock, wlock)
+ repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
@command('tags', [], '')
def tags(ui, repo):
@@ -5691,22 +4988,19 @@ def tags(ui, repo):
for t, n in reversed(repo.tagslist()):
if ui.quiet:
- ui.write("%s\n" % t, label='tags.normal')
+ ui.write("%s\n" % t)
continue
hn = hexfunc(n)
r = "%5d:%s" % (repo.changelog.rev(n), hn)
- rev = ui.label(r, 'log.changeset')
spaces = " " * (30 - encoding.colwidth(t))
- tag = ui.label(t, 'tags.normal')
if ui.verbose:
if repo.tagtype(t) == 'local':
tagtype = " local"
- tag = ui.label(t, 'tags.local')
else:
tagtype = ""
- ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
+ ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
@command('tip',
[('p', 'patch', None, _('show patch')),
@@ -5751,10 +5045,11 @@ def unbundle(ui, repo, fname1, *fnames, **opts):
for fname in fnames:
f = url.open(ui, fname)
gen = changegroup.readbundle(f, fname)
- modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
+ modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
+ lock=lock)
+ bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
finally:
lock.release()
- bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
return postincoming(ui, repo, modheads, opts.get('update'), None)
@command('^update|up|checkout|co',
@@ -5769,40 +5064,34 @@ def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
Update the repository's working directory to the specified
changeset. If no changeset is specified, update to the tip of the
- current named branch and move the current bookmark (see :hg:`help
- bookmarks`).
+ current named branch.
- Update sets the working directory's parent revison to the specified
- changeset (see :hg:`help parents`).
-
- If the changeset is not a descendant or ancestor 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
+ 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.
- .. container:: verbose
-
- The following rules apply when the working directory contains
- uncommitted changes:
+ Update sets the working directory's parent revison to the specified
+ changeset (see :hg:`help parents`).
- 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.
+ The following rules apply when the working directory contains
+ uncommitted changes:
- 2. With the -c/--check option, the update is aborted and the
- uncommitted changes are preserved.
+ 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.
- 3. With the -C/--clean option, uncommitted changes are discarded and
- the working directory is updated to the requested changeset.
+ 2. With the -c/--check option, the update is aborted and the
+ uncommitted changes are preserved.
- To cancel an uncommitted merge (and lose your changes), use
- :hg:`update --clean .`.
+ 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`).
@@ -5820,11 +5109,6 @@ def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
if rev is None or rev == '':
rev = node
- # with no argument, we also move the current bookmark, if any
- movemarkfrom = None
- if rev is None or node == '':
- movemarkfrom = repo['.'].node()
-
# if we defined a bookmark, we have to remember the original bookmark name
brev = rev
rev = scmutil.revsingle(repo, rev, rev).rev()
@@ -5832,31 +5116,24 @@ def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
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 is not None:
raise util.Abort(_("you can't specify a revision and a date"))
rev = cmdutil.finddate(ui, repo, date)
- if check:
- c = repo[None]
- if c.dirty(merge=False, branch=False):
- raise util.Abort(_("uncommitted local changes"))
- if rev is None:
- rev = repo[repo[None].branch()].rev()
- mergemod._checkunknown(repo, repo[None], repo[rev])
-
- if clean:
+ if clean or check:
ret = hg.clean(repo, rev)
else:
ret = hg.update(repo, rev)
- if not ret and movemarkfrom:
- if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
- ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
- elif brev in repo._bookmarks:
+ if brev in repo._bookmarks:
bookmarks.setcurrent(repo, brev)
- elif brev:
- bookmarks.unsetcurrent(repo)
return ret
@@ -5882,7 +5159,7 @@ def version_(ui):
% util.version())
ui.status(_(
"(see http://mercurial.selenic.com for more information)\n"
- "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
+ "\nCopyright (C) 2005-2011 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"