##// END OF EJS Templates
Clarify update help text for update without an explicit revision
Brendan Cully -
r4205:7ca05d29 default
parent child Browse files
Show More
@@ -1,3319 +1,3320 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 import demandimport; demandimport.enable()
8 import demandimport; demandimport.enable()
9 from node import *
9 from node import *
10 from i18n import _
10 from i18n import _
11 import bisect, os, re, sys, signal, imp, urllib, pdb, shlex, stat
11 import bisect, os, re, sys, signal, imp, urllib, pdb, shlex, stat
12 import fancyopts, ui, hg, util, lock, revlog, bundlerepo
12 import fancyopts, ui, hg, util, lock, revlog, bundlerepo
13 import difflib, patch, time, help, mdiff, tempfile
13 import difflib, patch, time, help, mdiff, tempfile
14 import traceback, errno, version, atexit, socket
14 import traceback, errno, version, atexit, socket
15 import archival, changegroup, cmdutil, hgweb.server, sshserver
15 import archival, changegroup, cmdutil, hgweb.server, sshserver
16
16
17 class UnknownCommand(Exception):
17 class UnknownCommand(Exception):
18 """Exception raised if command is not in the command table."""
18 """Exception raised if command is not in the command table."""
19 class AmbiguousCommand(Exception):
19 class AmbiguousCommand(Exception):
20 """Exception raised if command shortcut matches more than one command."""
20 """Exception raised if command shortcut matches more than one command."""
21
21
22 def bail_if_changed(repo):
22 def bail_if_changed(repo):
23 modified, added, removed, deleted = repo.status()[:4]
23 modified, added, removed, deleted = repo.status()[:4]
24 if modified or added or removed or deleted:
24 if modified or added or removed or deleted:
25 raise util.Abort(_("outstanding uncommitted changes"))
25 raise util.Abort(_("outstanding uncommitted changes"))
26
26
27 def logmessage(opts):
27 def logmessage(opts):
28 """ get the log message according to -m and -l option """
28 """ get the log message according to -m and -l option """
29 message = opts['message']
29 message = opts['message']
30 logfile = opts['logfile']
30 logfile = opts['logfile']
31
31
32 if message and logfile:
32 if message and logfile:
33 raise util.Abort(_('options --message and --logfile are mutually '
33 raise util.Abort(_('options --message and --logfile are mutually '
34 'exclusive'))
34 'exclusive'))
35 if not message and logfile:
35 if not message and logfile:
36 try:
36 try:
37 if logfile == '-':
37 if logfile == '-':
38 message = sys.stdin.read()
38 message = sys.stdin.read()
39 else:
39 else:
40 message = open(logfile).read()
40 message = open(logfile).read()
41 except IOError, inst:
41 except IOError, inst:
42 raise util.Abort(_("can't read commit message '%s': %s") %
42 raise util.Abort(_("can't read commit message '%s': %s") %
43 (logfile, inst.strerror))
43 (logfile, inst.strerror))
44 return message
44 return message
45
45
46 def setremoteconfig(ui, opts):
46 def setremoteconfig(ui, opts):
47 "copy remote options to ui tree"
47 "copy remote options to ui tree"
48 if opts.get('ssh'):
48 if opts.get('ssh'):
49 ui.setconfig("ui", "ssh", opts['ssh'])
49 ui.setconfig("ui", "ssh", opts['ssh'])
50 if opts.get('remotecmd'):
50 if opts.get('remotecmd'):
51 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
51 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
52
52
53 # Commands start here, listed alphabetically
53 # Commands start here, listed alphabetically
54
54
55 def add(ui, repo, *pats, **opts):
55 def add(ui, repo, *pats, **opts):
56 """add the specified files on the next commit
56 """add the specified files on the next commit
57
57
58 Schedule files to be version controlled and added to the repository.
58 Schedule files to be version controlled and added to the repository.
59
59
60 The files will be added to the repository at the next commit. To
60 The files will be added to the repository at the next commit. To
61 undo an add before that, see hg revert.
61 undo an add before that, see hg revert.
62
62
63 If no names are given, add all files in the repository.
63 If no names are given, add all files in the repository.
64 """
64 """
65
65
66 names = []
66 names = []
67 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
67 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
68 if exact:
68 if exact:
69 if ui.verbose:
69 if ui.verbose:
70 ui.status(_('adding %s\n') % rel)
70 ui.status(_('adding %s\n') % rel)
71 names.append(abs)
71 names.append(abs)
72 elif repo.dirstate.state(abs) == '?':
72 elif repo.dirstate.state(abs) == '?':
73 ui.status(_('adding %s\n') % rel)
73 ui.status(_('adding %s\n') % rel)
74 names.append(abs)
74 names.append(abs)
75 if not opts.get('dry_run'):
75 if not opts.get('dry_run'):
76 repo.add(names)
76 repo.add(names)
77
77
78 def addremove(ui, repo, *pats, **opts):
78 def addremove(ui, repo, *pats, **opts):
79 """add all new files, delete all missing files
79 """add all new files, delete all missing files
80
80
81 Add all new files and remove all missing files from the repository.
81 Add all new files and remove all missing files from the repository.
82
82
83 New files are ignored if they match any of the patterns in .hgignore. As
83 New files are ignored if they match any of the patterns in .hgignore. As
84 with add, these changes take effect at the next commit.
84 with add, these changes take effect at the next commit.
85
85
86 Use the -s option to detect renamed files. With a parameter > 0,
86 Use the -s option to detect renamed files. With a parameter > 0,
87 this compares every removed file with every added file and records
87 this compares every removed file with every added file and records
88 those similar enough as renames. This option takes a percentage
88 those similar enough as renames. This option takes a percentage
89 between 0 (disabled) and 100 (files must be identical) as its
89 between 0 (disabled) and 100 (files must be identical) as its
90 parameter. Detecting renamed files this way can be expensive.
90 parameter. Detecting renamed files this way can be expensive.
91 """
91 """
92 sim = float(opts.get('similarity') or 0)
92 sim = float(opts.get('similarity') or 0)
93 if sim < 0 or sim > 100:
93 if sim < 0 or sim > 100:
94 raise util.Abort(_('similarity must be between 0 and 100'))
94 raise util.Abort(_('similarity must be between 0 and 100'))
95 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
95 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
96
96
97 def annotate(ui, repo, *pats, **opts):
97 def annotate(ui, repo, *pats, **opts):
98 """show changeset information per file line
98 """show changeset information per file line
99
99
100 List changes in files, showing the revision id responsible for each line
100 List changes in files, showing the revision id responsible for each line
101
101
102 This command is useful to discover who did a change or when a change took
102 This command is useful to discover who did a change or when a change took
103 place.
103 place.
104
104
105 Without the -a option, annotate will avoid processing files it
105 Without the -a option, annotate will avoid processing files it
106 detects as binary. With -a, annotate will generate an annotation
106 detects as binary. With -a, annotate will generate an annotation
107 anyway, probably with undesirable results.
107 anyway, probably with undesirable results.
108 """
108 """
109 getdate = util.cachefunc(lambda x: util.datestr(x.date()))
109 getdate = util.cachefunc(lambda x: util.datestr(x.date()))
110
110
111 if not pats:
111 if not pats:
112 raise util.Abort(_('at least one file name or pattern required'))
112 raise util.Abort(_('at least one file name or pattern required'))
113
113
114 opmap = [['user', lambda x: ui.shortuser(x.user())],
114 opmap = [['user', lambda x: ui.shortuser(x.user())],
115 ['number', lambda x: str(x.rev())],
115 ['number', lambda x: str(x.rev())],
116 ['changeset', lambda x: short(x.node())],
116 ['changeset', lambda x: short(x.node())],
117 ['date', getdate], ['follow', lambda x: x.path()]]
117 ['date', getdate], ['follow', lambda x: x.path()]]
118 if (not opts['user'] and not opts['changeset'] and not opts['date']
118 if (not opts['user'] and not opts['changeset'] and not opts['date']
119 and not opts['follow']):
119 and not opts['follow']):
120 opts['number'] = 1
120 opts['number'] = 1
121
121
122 ctx = repo.changectx(opts['rev'])
122 ctx = repo.changectx(opts['rev'])
123
123
124 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
124 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
125 node=ctx.node()):
125 node=ctx.node()):
126 fctx = ctx.filectx(abs)
126 fctx = ctx.filectx(abs)
127 if not opts['text'] and util.binary(fctx.data()):
127 if not opts['text'] and util.binary(fctx.data()):
128 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
128 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
129 continue
129 continue
130
130
131 lines = fctx.annotate(follow=opts.get('follow'))
131 lines = fctx.annotate(follow=opts.get('follow'))
132 pieces = []
132 pieces = []
133
133
134 for o, f in opmap:
134 for o, f in opmap:
135 if opts[o]:
135 if opts[o]:
136 l = [f(n) for n, dummy in lines]
136 l = [f(n) for n, dummy in lines]
137 if l:
137 if l:
138 m = max(map(len, l))
138 m = max(map(len, l))
139 pieces.append(["%*s" % (m, x) for x in l])
139 pieces.append(["%*s" % (m, x) for x in l])
140
140
141 if pieces:
141 if pieces:
142 for p, l in zip(zip(*pieces), lines):
142 for p, l in zip(zip(*pieces), lines):
143 ui.write("%s: %s" % (" ".join(p), l[1]))
143 ui.write("%s: %s" % (" ".join(p), l[1]))
144
144
145 def archive(ui, repo, dest, **opts):
145 def archive(ui, repo, dest, **opts):
146 '''create unversioned archive of a repository revision
146 '''create unversioned archive of a repository revision
147
147
148 By default, the revision used is the parent of the working
148 By default, the revision used is the parent of the working
149 directory; use "-r" to specify a different revision.
149 directory; use "-r" to specify a different revision.
150
150
151 To specify the type of archive to create, use "-t". Valid
151 To specify the type of archive to create, use "-t". Valid
152 types are:
152 types are:
153
153
154 "files" (default): a directory full of files
154 "files" (default): a directory full of files
155 "tar": tar archive, uncompressed
155 "tar": tar archive, uncompressed
156 "tbz2": tar archive, compressed using bzip2
156 "tbz2": tar archive, compressed using bzip2
157 "tgz": tar archive, compressed using gzip
157 "tgz": tar archive, compressed using gzip
158 "uzip": zip archive, uncompressed
158 "uzip": zip archive, uncompressed
159 "zip": zip archive, compressed using deflate
159 "zip": zip archive, compressed using deflate
160
160
161 The exact name of the destination archive or directory is given
161 The exact name of the destination archive or directory is given
162 using a format string; see "hg help export" for details.
162 using a format string; see "hg help export" for details.
163
163
164 Each member added to an archive file has a directory prefix
164 Each member added to an archive file has a directory prefix
165 prepended. Use "-p" to specify a format string for the prefix.
165 prepended. Use "-p" to specify a format string for the prefix.
166 The default is the basename of the archive, with suffixes removed.
166 The default is the basename of the archive, with suffixes removed.
167 '''
167 '''
168
168
169 node = repo.changectx(opts['rev']).node()
169 node = repo.changectx(opts['rev']).node()
170 dest = cmdutil.make_filename(repo, dest, node)
170 dest = cmdutil.make_filename(repo, dest, node)
171 if os.path.realpath(dest) == repo.root:
171 if os.path.realpath(dest) == repo.root:
172 raise util.Abort(_('repository root cannot be destination'))
172 raise util.Abort(_('repository root cannot be destination'))
173 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
173 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
174 kind = opts.get('type') or 'files'
174 kind = opts.get('type') or 'files'
175 prefix = opts['prefix']
175 prefix = opts['prefix']
176 if dest == '-':
176 if dest == '-':
177 if kind == 'files':
177 if kind == 'files':
178 raise util.Abort(_('cannot archive plain files to stdout'))
178 raise util.Abort(_('cannot archive plain files to stdout'))
179 dest = sys.stdout
179 dest = sys.stdout
180 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
180 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
181 prefix = cmdutil.make_filename(repo, prefix, node)
181 prefix = cmdutil.make_filename(repo, prefix, node)
182 archival.archive(repo, dest, node, kind, not opts['no_decode'],
182 archival.archive(repo, dest, node, kind, not opts['no_decode'],
183 matchfn, prefix)
183 matchfn, prefix)
184
184
185 def backout(ui, repo, rev, **opts):
185 def backout(ui, repo, rev, **opts):
186 '''reverse effect of earlier changeset
186 '''reverse effect of earlier changeset
187
187
188 Commit the backed out changes as a new changeset. The new
188 Commit the backed out changes as a new changeset. The new
189 changeset is a child of the backed out changeset.
189 changeset is a child of the backed out changeset.
190
190
191 If you back out a changeset other than the tip, a new head is
191 If you back out a changeset other than the tip, a new head is
192 created. This head is the parent of the working directory. If
192 created. This head is the parent of the working directory. If
193 you back out an old changeset, your working directory will appear
193 you back out an old changeset, your working directory will appear
194 old after the backout. You should merge the backout changeset
194 old after the backout. You should merge the backout changeset
195 with another head.
195 with another head.
196
196
197 The --merge option remembers the parent of the working directory
197 The --merge option remembers the parent of the working directory
198 before starting the backout, then merges the new head with that
198 before starting the backout, then merges the new head with that
199 changeset afterwards. This saves you from doing the merge by
199 changeset afterwards. This saves you from doing the merge by
200 hand. The result of this merge is not committed, as for a normal
200 hand. The result of this merge is not committed, as for a normal
201 merge.'''
201 merge.'''
202
202
203 bail_if_changed(repo)
203 bail_if_changed(repo)
204 op1, op2 = repo.dirstate.parents()
204 op1, op2 = repo.dirstate.parents()
205 if op2 != nullid:
205 if op2 != nullid:
206 raise util.Abort(_('outstanding uncommitted merge'))
206 raise util.Abort(_('outstanding uncommitted merge'))
207 node = repo.lookup(rev)
207 node = repo.lookup(rev)
208 p1, p2 = repo.changelog.parents(node)
208 p1, p2 = repo.changelog.parents(node)
209 if p1 == nullid:
209 if p1 == nullid:
210 raise util.Abort(_('cannot back out a change with no parents'))
210 raise util.Abort(_('cannot back out a change with no parents'))
211 if p2 != nullid:
211 if p2 != nullid:
212 if not opts['parent']:
212 if not opts['parent']:
213 raise util.Abort(_('cannot back out a merge changeset without '
213 raise util.Abort(_('cannot back out a merge changeset without '
214 '--parent'))
214 '--parent'))
215 p = repo.lookup(opts['parent'])
215 p = repo.lookup(opts['parent'])
216 if p not in (p1, p2):
216 if p not in (p1, p2):
217 raise util.Abort(_('%s is not a parent of %s') %
217 raise util.Abort(_('%s is not a parent of %s') %
218 (short(p), short(node)))
218 (short(p), short(node)))
219 parent = p
219 parent = p
220 else:
220 else:
221 if opts['parent']:
221 if opts['parent']:
222 raise util.Abort(_('cannot use --parent on non-merge changeset'))
222 raise util.Abort(_('cannot use --parent on non-merge changeset'))
223 parent = p1
223 parent = p1
224 hg.clean(repo, node, show_stats=False)
224 hg.clean(repo, node, show_stats=False)
225 revert_opts = opts.copy()
225 revert_opts = opts.copy()
226 revert_opts['date'] = None
226 revert_opts['date'] = None
227 revert_opts['all'] = True
227 revert_opts['all'] = True
228 revert_opts['rev'] = hex(parent)
228 revert_opts['rev'] = hex(parent)
229 revert(ui, repo, **revert_opts)
229 revert(ui, repo, **revert_opts)
230 commit_opts = opts.copy()
230 commit_opts = opts.copy()
231 commit_opts['addremove'] = False
231 commit_opts['addremove'] = False
232 if not commit_opts['message'] and not commit_opts['logfile']:
232 if not commit_opts['message'] and not commit_opts['logfile']:
233 commit_opts['message'] = _("Backed out changeset %s") % (hex(node))
233 commit_opts['message'] = _("Backed out changeset %s") % (hex(node))
234 commit_opts['force_editor'] = True
234 commit_opts['force_editor'] = True
235 commit(ui, repo, **commit_opts)
235 commit(ui, repo, **commit_opts)
236 def nice(node):
236 def nice(node):
237 return '%d:%s' % (repo.changelog.rev(node), short(node))
237 return '%d:%s' % (repo.changelog.rev(node), short(node))
238 ui.status(_('changeset %s backs out changeset %s\n') %
238 ui.status(_('changeset %s backs out changeset %s\n') %
239 (nice(repo.changelog.tip()), nice(node)))
239 (nice(repo.changelog.tip()), nice(node)))
240 if op1 != node:
240 if op1 != node:
241 if opts['merge']:
241 if opts['merge']:
242 ui.status(_('merging with changeset %s\n') % nice(op1))
242 ui.status(_('merging with changeset %s\n') % nice(op1))
243 hg.merge(repo, hex(op1))
243 hg.merge(repo, hex(op1))
244 else:
244 else:
245 ui.status(_('the backout changeset is a new head - '
245 ui.status(_('the backout changeset is a new head - '
246 'do not forget to merge\n'))
246 'do not forget to merge\n'))
247 ui.status(_('(use "backout --merge" '
247 ui.status(_('(use "backout --merge" '
248 'if you want to auto-merge)\n'))
248 'if you want to auto-merge)\n'))
249
249
250 def branch(ui, repo, label=None, **opts):
250 def branch(ui, repo, label=None, **opts):
251 """set or show the current branch name
251 """set or show the current branch name
252
252
253 With <name>, set the current branch name. Otherwise, show the
253 With <name>, set the current branch name. Otherwise, show the
254 current branch name.
254 current branch name.
255
255
256 Unless --force is specified, branch will not let you set a
256 Unless --force is specified, branch will not let you set a
257 branch name that shadows an existing branch.
257 branch name that shadows an existing branch.
258 """
258 """
259
259
260 if label is not None:
260 if label is not None:
261 if not opts.get('force') and label in repo.branchtags():
261 if not opts.get('force') and label in repo.branchtags():
262 if label not in [p.branch() for p in repo.workingctx().parents()]:
262 if label not in [p.branch() for p in repo.workingctx().parents()]:
263 raise util.Abort(_('a branch of the same name already exists'
263 raise util.Abort(_('a branch of the same name already exists'
264 ' (use --force to override)'))
264 ' (use --force to override)'))
265 repo.opener("branch", "w").write(util.fromlocal(label) + '\n')
265 repo.opener("branch", "w").write(util.fromlocal(label) + '\n')
266 else:
266 else:
267 b = util.tolocal(repo.workingctx().branch())
267 b = util.tolocal(repo.workingctx().branch())
268 if b:
268 if b:
269 ui.write("%s\n" % b)
269 ui.write("%s\n" % b)
270
270
271 def branches(ui, repo):
271 def branches(ui, repo):
272 """list repository named branches
272 """list repository named branches
273
273
274 List the repository's named branches.
274 List the repository's named branches.
275 """
275 """
276 b = repo.branchtags()
276 b = repo.branchtags()
277 l = [(-repo.changelog.rev(n), n, t) for t, n in b.items()]
277 l = [(-repo.changelog.rev(n), n, t) for t, n in b.items()]
278 l.sort()
278 l.sort()
279 for r, n, t in l:
279 for r, n, t in l:
280 hexfunc = ui.debugflag and hex or short
280 hexfunc = ui.debugflag and hex or short
281 if ui.quiet:
281 if ui.quiet:
282 ui.write("%s\n" % t)
282 ui.write("%s\n" % t)
283 else:
283 else:
284 spaces = " " * (30 - util.locallen(t))
284 spaces = " " * (30 - util.locallen(t))
285 ui.write("%s%s %s:%s\n" % (t, spaces, -r, hexfunc(n)))
285 ui.write("%s%s %s:%s\n" % (t, spaces, -r, hexfunc(n)))
286
286
287 def bundle(ui, repo, fname, dest=None, **opts):
287 def bundle(ui, repo, fname, dest=None, **opts):
288 """create a changegroup file
288 """create a changegroup file
289
289
290 Generate a compressed changegroup file collecting changesets not
290 Generate a compressed changegroup file collecting changesets not
291 found in the other repository.
291 found in the other repository.
292
292
293 If no destination repository is specified the destination is assumed
293 If no destination repository is specified the destination is assumed
294 to have all the nodes specified by one or more --base parameters.
294 to have all the nodes specified by one or more --base parameters.
295
295
296 The bundle file can then be transferred using conventional means and
296 The bundle file can then be transferred using conventional means and
297 applied to another repository with the unbundle or pull command.
297 applied to another repository with the unbundle or pull command.
298 This is useful when direct push and pull are not available or when
298 This is useful when direct push and pull are not available or when
299 exporting an entire repository is undesirable.
299 exporting an entire repository is undesirable.
300
300
301 Applying bundles preserves all changeset contents including
301 Applying bundles preserves all changeset contents including
302 permissions, copy/rename information, and revision history.
302 permissions, copy/rename information, and revision history.
303 """
303 """
304 revs = opts.get('rev') or None
304 revs = opts.get('rev') or None
305 if revs:
305 if revs:
306 revs = [repo.lookup(rev) for rev in revs]
306 revs = [repo.lookup(rev) for rev in revs]
307 base = opts.get('base')
307 base = opts.get('base')
308 if base:
308 if base:
309 if dest:
309 if dest:
310 raise util.Abort(_("--base is incompatible with specifiying "
310 raise util.Abort(_("--base is incompatible with specifiying "
311 "a destination"))
311 "a destination"))
312 base = [repo.lookup(rev) for rev in base]
312 base = [repo.lookup(rev) for rev in base]
313 # create the right base
313 # create the right base
314 # XXX: nodesbetween / changegroup* should be "fixed" instead
314 # XXX: nodesbetween / changegroup* should be "fixed" instead
315 o = []
315 o = []
316 has = {nullid: None}
316 has = {nullid: None}
317 for n in base:
317 for n in base:
318 has.update(repo.changelog.reachable(n))
318 has.update(repo.changelog.reachable(n))
319 if revs:
319 if revs:
320 visit = list(revs)
320 visit = list(revs)
321 else:
321 else:
322 visit = repo.changelog.heads()
322 visit = repo.changelog.heads()
323 seen = {}
323 seen = {}
324 while visit:
324 while visit:
325 n = visit.pop(0)
325 n = visit.pop(0)
326 parents = [p for p in repo.changelog.parents(n) if p not in has]
326 parents = [p for p in repo.changelog.parents(n) if p not in has]
327 if len(parents) == 0:
327 if len(parents) == 0:
328 o.insert(0, n)
328 o.insert(0, n)
329 else:
329 else:
330 for p in parents:
330 for p in parents:
331 if p not in seen:
331 if p not in seen:
332 seen[p] = 1
332 seen[p] = 1
333 visit.append(p)
333 visit.append(p)
334 else:
334 else:
335 setremoteconfig(ui, opts)
335 setremoteconfig(ui, opts)
336 dest = ui.expandpath(dest or 'default-push', dest or 'default')
336 dest = ui.expandpath(dest or 'default-push', dest or 'default')
337 other = hg.repository(ui, dest)
337 other = hg.repository(ui, dest)
338 o = repo.findoutgoing(other, force=opts['force'])
338 o = repo.findoutgoing(other, force=opts['force'])
339
339
340 if revs:
340 if revs:
341 cg = repo.changegroupsubset(o, revs, 'bundle')
341 cg = repo.changegroupsubset(o, revs, 'bundle')
342 else:
342 else:
343 cg = repo.changegroup(o, 'bundle')
343 cg = repo.changegroup(o, 'bundle')
344 changegroup.writebundle(cg, fname, "HG10BZ")
344 changegroup.writebundle(cg, fname, "HG10BZ")
345
345
346 def cat(ui, repo, file1, *pats, **opts):
346 def cat(ui, repo, file1, *pats, **opts):
347 """output the current or given revision of files
347 """output the current or given revision of files
348
348
349 Print the specified files as they were at the given revision.
349 Print the specified files as they were at the given revision.
350 If no revision is given, the parent of the working directory is used,
350 If no revision is given, the parent of the working directory is used,
351 or tip if no revision is checked out.
351 or tip if no revision is checked out.
352
352
353 Output may be to a file, in which case the name of the file is
353 Output may be to a file, in which case the name of the file is
354 given using a format string. The formatting rules are the same as
354 given using a format string. The formatting rules are the same as
355 for the export command, with the following additions:
355 for the export command, with the following additions:
356
356
357 %s basename of file being printed
357 %s basename of file being printed
358 %d dirname of file being printed, or '.' if in repo root
358 %d dirname of file being printed, or '.' if in repo root
359 %p root-relative path name of file being printed
359 %p root-relative path name of file being printed
360 """
360 """
361 ctx = repo.changectx(opts['rev'])
361 ctx = repo.changectx(opts['rev'])
362 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
362 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
363 ctx.node()):
363 ctx.node()):
364 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
364 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
365 fp.write(ctx.filectx(abs).data())
365 fp.write(ctx.filectx(abs).data())
366
366
367 def clone(ui, source, dest=None, **opts):
367 def clone(ui, source, dest=None, **opts):
368 """make a copy of an existing repository
368 """make a copy of an existing repository
369
369
370 Create a copy of an existing repository in a new directory.
370 Create a copy of an existing repository in a new directory.
371
371
372 If no destination directory name is specified, it defaults to the
372 If no destination directory name is specified, it defaults to the
373 basename of the source.
373 basename of the source.
374
374
375 The location of the source is added to the new repository's
375 The location of the source is added to the new repository's
376 .hg/hgrc file, as the default to be used for future pulls.
376 .hg/hgrc file, as the default to be used for future pulls.
377
377
378 For efficiency, hardlinks are used for cloning whenever the source
378 For efficiency, hardlinks are used for cloning whenever the source
379 and destination are on the same filesystem (note this applies only
379 and destination are on the same filesystem (note this applies only
380 to the repository data, not to the checked out files). Some
380 to the repository data, not to the checked out files). Some
381 filesystems, such as AFS, implement hardlinking incorrectly, but
381 filesystems, such as AFS, implement hardlinking incorrectly, but
382 do not report errors. In these cases, use the --pull option to
382 do not report errors. In these cases, use the --pull option to
383 avoid hardlinking.
383 avoid hardlinking.
384
384
385 You can safely clone repositories and checked out files using full
385 You can safely clone repositories and checked out files using full
386 hardlinks with
386 hardlinks with
387
387
388 $ cp -al REPO REPOCLONE
388 $ cp -al REPO REPOCLONE
389
389
390 which is the fastest way to clone. However, the operation is not
390 which is the fastest way to clone. However, the operation is not
391 atomic (making sure REPO is not modified during the operation is
391 atomic (making sure REPO is not modified during the operation is
392 up to you) and you have to make sure your editor breaks hardlinks
392 up to you) and you have to make sure your editor breaks hardlinks
393 (Emacs and most Linux Kernel tools do so).
393 (Emacs and most Linux Kernel tools do so).
394
394
395 If you use the -r option to clone up to a specific revision, no
395 If you use the -r option to clone up to a specific revision, no
396 subsequent revisions will be present in the cloned repository.
396 subsequent revisions will be present in the cloned repository.
397 This option implies --pull, even on local repositories.
397 This option implies --pull, even on local repositories.
398
398
399 See pull for valid source format details.
399 See pull for valid source format details.
400
400
401 It is possible to specify an ssh:// URL as the destination, but no
401 It is possible to specify an ssh:// URL as the destination, but no
402 .hg/hgrc and working directory will be created on the remote side.
402 .hg/hgrc and working directory will be created on the remote side.
403 Look at the help text for the pull command for important details
403 Look at the help text for the pull command for important details
404 about ssh:// URLs.
404 about ssh:// URLs.
405 """
405 """
406 setremoteconfig(ui, opts)
406 setremoteconfig(ui, opts)
407 hg.clone(ui, ui.expandpath(source), dest,
407 hg.clone(ui, ui.expandpath(source), dest,
408 pull=opts['pull'],
408 pull=opts['pull'],
409 stream=opts['uncompressed'],
409 stream=opts['uncompressed'],
410 rev=opts['rev'],
410 rev=opts['rev'],
411 update=not opts['noupdate'])
411 update=not opts['noupdate'])
412
412
413 def commit(ui, repo, *pats, **opts):
413 def commit(ui, repo, *pats, **opts):
414 """commit the specified files or all outstanding changes
414 """commit the specified files or all outstanding changes
415
415
416 Commit changes to the given files into the repository.
416 Commit changes to the given files into the repository.
417
417
418 If a list of files is omitted, all changes reported by "hg status"
418 If a list of files is omitted, all changes reported by "hg status"
419 will be committed.
419 will be committed.
420
420
421 If no commit message is specified, the editor configured in your hgrc
421 If no commit message is specified, the editor configured in your hgrc
422 or in the EDITOR environment variable is started to enter a message.
422 or in the EDITOR environment variable is started to enter a message.
423 """
423 """
424 message = logmessage(opts)
424 message = logmessage(opts)
425
425
426 if opts['addremove']:
426 if opts['addremove']:
427 cmdutil.addremove(repo, pats, opts)
427 cmdutil.addremove(repo, pats, opts)
428 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
428 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
429 if pats:
429 if pats:
430 status = repo.status(files=fns, match=match)
430 status = repo.status(files=fns, match=match)
431 modified, added, removed, deleted, unknown = status[:5]
431 modified, added, removed, deleted, unknown = status[:5]
432 files = modified + added + removed
432 files = modified + added + removed
433 slist = None
433 slist = None
434 for f in fns:
434 for f in fns:
435 if f not in files:
435 if f not in files:
436 rf = repo.wjoin(f)
436 rf = repo.wjoin(f)
437 if f in unknown:
437 if f in unknown:
438 raise util.Abort(_("file %s not tracked!") % rf)
438 raise util.Abort(_("file %s not tracked!") % rf)
439 try:
439 try:
440 mode = os.lstat(rf)[stat.ST_MODE]
440 mode = os.lstat(rf)[stat.ST_MODE]
441 except OSError:
441 except OSError:
442 raise util.Abort(_("file %s not found!") % rf)
442 raise util.Abort(_("file %s not found!") % rf)
443 if stat.S_ISDIR(mode):
443 if stat.S_ISDIR(mode):
444 name = f + '/'
444 name = f + '/'
445 if slist is None:
445 if slist is None:
446 slist = list(files)
446 slist = list(files)
447 slist.sort()
447 slist.sort()
448 i = bisect.bisect(slist, name)
448 i = bisect.bisect(slist, name)
449 if i >= len(slist) or not slist[i].startswith(name):
449 if i >= len(slist) or not slist[i].startswith(name):
450 raise util.Abort(_("no match under directory %s!")
450 raise util.Abort(_("no match under directory %s!")
451 % rf)
451 % rf)
452 elif not stat.S_ISREG(mode):
452 elif not stat.S_ISREG(mode):
453 raise util.Abort(_("can't commit %s: "
453 raise util.Abort(_("can't commit %s: "
454 "unsupported file type!") % rf)
454 "unsupported file type!") % rf)
455 else:
455 else:
456 files = []
456 files = []
457 try:
457 try:
458 repo.commit(files, message, opts['user'], opts['date'], match,
458 repo.commit(files, message, opts['user'], opts['date'], match,
459 force_editor=opts.get('force_editor'))
459 force_editor=opts.get('force_editor'))
460 except ValueError, inst:
460 except ValueError, inst:
461 raise util.Abort(str(inst))
461 raise util.Abort(str(inst))
462
462
463 def docopy(ui, repo, pats, opts, wlock):
463 def docopy(ui, repo, pats, opts, wlock):
464 # called with the repo lock held
464 # called with the repo lock held
465 #
465 #
466 # hgsep => pathname that uses "/" to separate directories
466 # hgsep => pathname that uses "/" to separate directories
467 # ossep => pathname that uses os.sep to separate directories
467 # ossep => pathname that uses os.sep to separate directories
468 cwd = repo.getcwd()
468 cwd = repo.getcwd()
469 errors = 0
469 errors = 0
470 copied = []
470 copied = []
471 targets = {}
471 targets = {}
472
472
473 # abs: hgsep
473 # abs: hgsep
474 # rel: ossep
474 # rel: ossep
475 # return: hgsep
475 # return: hgsep
476 def okaytocopy(abs, rel, exact):
476 def okaytocopy(abs, rel, exact):
477 reasons = {'?': _('is not managed'),
477 reasons = {'?': _('is not managed'),
478 'a': _('has been marked for add'),
478 'a': _('has been marked for add'),
479 'r': _('has been marked for remove')}
479 'r': _('has been marked for remove')}
480 state = repo.dirstate.state(abs)
480 state = repo.dirstate.state(abs)
481 reason = reasons.get(state)
481 reason = reasons.get(state)
482 if reason:
482 if reason:
483 if state == 'a':
483 if state == 'a':
484 origsrc = repo.dirstate.copied(abs)
484 origsrc = repo.dirstate.copied(abs)
485 if origsrc is not None:
485 if origsrc is not None:
486 return origsrc
486 return origsrc
487 if exact:
487 if exact:
488 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
488 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
489 else:
489 else:
490 return abs
490 return abs
491
491
492 # origsrc: hgsep
492 # origsrc: hgsep
493 # abssrc: hgsep
493 # abssrc: hgsep
494 # relsrc: ossep
494 # relsrc: ossep
495 # target: ossep
495 # target: ossep
496 def copy(origsrc, abssrc, relsrc, target, exact):
496 def copy(origsrc, abssrc, relsrc, target, exact):
497 abstarget = util.canonpath(repo.root, cwd, target)
497 abstarget = util.canonpath(repo.root, cwd, target)
498 reltarget = util.pathto(cwd, abstarget)
498 reltarget = util.pathto(cwd, abstarget)
499 prevsrc = targets.get(abstarget)
499 prevsrc = targets.get(abstarget)
500 if prevsrc is not None:
500 if prevsrc is not None:
501 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
501 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
502 (reltarget, util.localpath(abssrc),
502 (reltarget, util.localpath(abssrc),
503 util.localpath(prevsrc)))
503 util.localpath(prevsrc)))
504 return
504 return
505 if (not opts['after'] and os.path.exists(reltarget) or
505 if (not opts['after'] and os.path.exists(reltarget) or
506 opts['after'] and repo.dirstate.state(abstarget) not in '?r'):
506 opts['after'] and repo.dirstate.state(abstarget) not in '?r'):
507 if not opts['force']:
507 if not opts['force']:
508 ui.warn(_('%s: not overwriting - file exists\n') %
508 ui.warn(_('%s: not overwriting - file exists\n') %
509 reltarget)
509 reltarget)
510 return
510 return
511 if not opts['after'] and not opts.get('dry_run'):
511 if not opts['after'] and not opts.get('dry_run'):
512 os.unlink(reltarget)
512 os.unlink(reltarget)
513 if opts['after']:
513 if opts['after']:
514 if not os.path.exists(reltarget):
514 if not os.path.exists(reltarget):
515 return
515 return
516 else:
516 else:
517 targetdir = os.path.dirname(reltarget) or '.'
517 targetdir = os.path.dirname(reltarget) or '.'
518 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
518 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
519 os.makedirs(targetdir)
519 os.makedirs(targetdir)
520 try:
520 try:
521 restore = repo.dirstate.state(abstarget) == 'r'
521 restore = repo.dirstate.state(abstarget) == 'r'
522 if restore and not opts.get('dry_run'):
522 if restore and not opts.get('dry_run'):
523 repo.undelete([abstarget], wlock)
523 repo.undelete([abstarget], wlock)
524 try:
524 try:
525 if not opts.get('dry_run'):
525 if not opts.get('dry_run'):
526 util.copyfile(relsrc, reltarget)
526 util.copyfile(relsrc, reltarget)
527 restore = False
527 restore = False
528 finally:
528 finally:
529 if restore:
529 if restore:
530 repo.remove([abstarget], wlock)
530 repo.remove([abstarget], wlock)
531 except IOError, inst:
531 except IOError, inst:
532 if inst.errno == errno.ENOENT:
532 if inst.errno == errno.ENOENT:
533 ui.warn(_('%s: deleted in working copy\n') % relsrc)
533 ui.warn(_('%s: deleted in working copy\n') % relsrc)
534 else:
534 else:
535 ui.warn(_('%s: cannot copy - %s\n') %
535 ui.warn(_('%s: cannot copy - %s\n') %
536 (relsrc, inst.strerror))
536 (relsrc, inst.strerror))
537 errors += 1
537 errors += 1
538 return
538 return
539 if ui.verbose or not exact:
539 if ui.verbose or not exact:
540 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
540 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
541 targets[abstarget] = abssrc
541 targets[abstarget] = abssrc
542 if abstarget != origsrc and not opts.get('dry_run'):
542 if abstarget != origsrc and not opts.get('dry_run'):
543 repo.copy(origsrc, abstarget, wlock)
543 repo.copy(origsrc, abstarget, wlock)
544 copied.append((abssrc, relsrc, exact))
544 copied.append((abssrc, relsrc, exact))
545
545
546 # pat: ossep
546 # pat: ossep
547 # dest ossep
547 # dest ossep
548 # srcs: list of (hgsep, hgsep, ossep, bool)
548 # srcs: list of (hgsep, hgsep, ossep, bool)
549 # return: function that takes hgsep and returns ossep
549 # return: function that takes hgsep and returns ossep
550 def targetpathfn(pat, dest, srcs):
550 def targetpathfn(pat, dest, srcs):
551 if os.path.isdir(pat):
551 if os.path.isdir(pat):
552 abspfx = util.canonpath(repo.root, cwd, pat)
552 abspfx = util.canonpath(repo.root, cwd, pat)
553 abspfx = util.localpath(abspfx)
553 abspfx = util.localpath(abspfx)
554 if destdirexists:
554 if destdirexists:
555 striplen = len(os.path.split(abspfx)[0])
555 striplen = len(os.path.split(abspfx)[0])
556 else:
556 else:
557 striplen = len(abspfx)
557 striplen = len(abspfx)
558 if striplen:
558 if striplen:
559 striplen += len(os.sep)
559 striplen += len(os.sep)
560 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
560 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
561 elif destdirexists:
561 elif destdirexists:
562 res = lambda p: os.path.join(dest,
562 res = lambda p: os.path.join(dest,
563 os.path.basename(util.localpath(p)))
563 os.path.basename(util.localpath(p)))
564 else:
564 else:
565 res = lambda p: dest
565 res = lambda p: dest
566 return res
566 return res
567
567
568 # pat: ossep
568 # pat: ossep
569 # dest ossep
569 # dest ossep
570 # srcs: list of (hgsep, hgsep, ossep, bool)
570 # srcs: list of (hgsep, hgsep, ossep, bool)
571 # return: function that takes hgsep and returns ossep
571 # return: function that takes hgsep and returns ossep
572 def targetpathafterfn(pat, dest, srcs):
572 def targetpathafterfn(pat, dest, srcs):
573 if util.patkind(pat, None)[0]:
573 if util.patkind(pat, None)[0]:
574 # a mercurial pattern
574 # a mercurial pattern
575 res = lambda p: os.path.join(dest,
575 res = lambda p: os.path.join(dest,
576 os.path.basename(util.localpath(p)))
576 os.path.basename(util.localpath(p)))
577 else:
577 else:
578 abspfx = util.canonpath(repo.root, cwd, pat)
578 abspfx = util.canonpath(repo.root, cwd, pat)
579 if len(abspfx) < len(srcs[0][0]):
579 if len(abspfx) < len(srcs[0][0]):
580 # A directory. Either the target path contains the last
580 # A directory. Either the target path contains the last
581 # component of the source path or it does not.
581 # component of the source path or it does not.
582 def evalpath(striplen):
582 def evalpath(striplen):
583 score = 0
583 score = 0
584 for s in srcs:
584 for s in srcs:
585 t = os.path.join(dest, util.localpath(s[0])[striplen:])
585 t = os.path.join(dest, util.localpath(s[0])[striplen:])
586 if os.path.exists(t):
586 if os.path.exists(t):
587 score += 1
587 score += 1
588 return score
588 return score
589
589
590 abspfx = util.localpath(abspfx)
590 abspfx = util.localpath(abspfx)
591 striplen = len(abspfx)
591 striplen = len(abspfx)
592 if striplen:
592 if striplen:
593 striplen += len(os.sep)
593 striplen += len(os.sep)
594 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
594 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
595 score = evalpath(striplen)
595 score = evalpath(striplen)
596 striplen1 = len(os.path.split(abspfx)[0])
596 striplen1 = len(os.path.split(abspfx)[0])
597 if striplen1:
597 if striplen1:
598 striplen1 += len(os.sep)
598 striplen1 += len(os.sep)
599 if evalpath(striplen1) > score:
599 if evalpath(striplen1) > score:
600 striplen = striplen1
600 striplen = striplen1
601 res = lambda p: os.path.join(dest,
601 res = lambda p: os.path.join(dest,
602 util.localpath(p)[striplen:])
602 util.localpath(p)[striplen:])
603 else:
603 else:
604 # a file
604 # a file
605 if destdirexists:
605 if destdirexists:
606 res = lambda p: os.path.join(dest,
606 res = lambda p: os.path.join(dest,
607 os.path.basename(util.localpath(p)))
607 os.path.basename(util.localpath(p)))
608 else:
608 else:
609 res = lambda p: dest
609 res = lambda p: dest
610 return res
610 return res
611
611
612
612
613 pats = util.expand_glob(pats)
613 pats = util.expand_glob(pats)
614 if not pats:
614 if not pats:
615 raise util.Abort(_('no source or destination specified'))
615 raise util.Abort(_('no source or destination specified'))
616 if len(pats) == 1:
616 if len(pats) == 1:
617 raise util.Abort(_('no destination specified'))
617 raise util.Abort(_('no destination specified'))
618 dest = pats.pop()
618 dest = pats.pop()
619 destdirexists = os.path.isdir(dest)
619 destdirexists = os.path.isdir(dest)
620 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
620 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
621 raise util.Abort(_('with multiple sources, destination must be an '
621 raise util.Abort(_('with multiple sources, destination must be an '
622 'existing directory'))
622 'existing directory'))
623 if opts['after']:
623 if opts['after']:
624 tfn = targetpathafterfn
624 tfn = targetpathafterfn
625 else:
625 else:
626 tfn = targetpathfn
626 tfn = targetpathfn
627 copylist = []
627 copylist = []
628 for pat in pats:
628 for pat in pats:
629 srcs = []
629 srcs = []
630 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts,
630 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts,
631 globbed=True):
631 globbed=True):
632 origsrc = okaytocopy(abssrc, relsrc, exact)
632 origsrc = okaytocopy(abssrc, relsrc, exact)
633 if origsrc:
633 if origsrc:
634 srcs.append((origsrc, abssrc, relsrc, exact))
634 srcs.append((origsrc, abssrc, relsrc, exact))
635 if not srcs:
635 if not srcs:
636 continue
636 continue
637 copylist.append((tfn(pat, dest, srcs), srcs))
637 copylist.append((tfn(pat, dest, srcs), srcs))
638 if not copylist:
638 if not copylist:
639 raise util.Abort(_('no files to copy'))
639 raise util.Abort(_('no files to copy'))
640
640
641 for targetpath, srcs in copylist:
641 for targetpath, srcs in copylist:
642 for origsrc, abssrc, relsrc, exact in srcs:
642 for origsrc, abssrc, relsrc, exact in srcs:
643 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
643 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
644
644
645 if errors:
645 if errors:
646 ui.warn(_('(consider using --after)\n'))
646 ui.warn(_('(consider using --after)\n'))
647 return errors, copied
647 return errors, copied
648
648
649 def copy(ui, repo, *pats, **opts):
649 def copy(ui, repo, *pats, **opts):
650 """mark files as copied for the next commit
650 """mark files as copied for the next commit
651
651
652 Mark dest as having copies of source files. If dest is a
652 Mark dest as having copies of source files. If dest is a
653 directory, copies are put in that directory. If dest is a file,
653 directory, copies are put in that directory. If dest is a file,
654 there can only be one source.
654 there can only be one source.
655
655
656 By default, this command copies the contents of files as they
656 By default, this command copies the contents of files as they
657 stand in the working directory. If invoked with --after, the
657 stand in the working directory. If invoked with --after, the
658 operation is recorded, but no copying is performed.
658 operation is recorded, but no copying is performed.
659
659
660 This command takes effect in the next commit. To undo a copy
660 This command takes effect in the next commit. To undo a copy
661 before that, see hg revert.
661 before that, see hg revert.
662 """
662 """
663 wlock = repo.wlock(0)
663 wlock = repo.wlock(0)
664 errs, copied = docopy(ui, repo, pats, opts, wlock)
664 errs, copied = docopy(ui, repo, pats, opts, wlock)
665 return errs
665 return errs
666
666
667 def debugancestor(ui, index, rev1, rev2):
667 def debugancestor(ui, index, rev1, rev2):
668 """find the ancestor revision of two revisions in a given index"""
668 """find the ancestor revision of two revisions in a given index"""
669 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index, "", 0)
669 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index, "", 0)
670 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
670 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
671 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
671 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
672
672
673 def debugcomplete(ui, cmd='', **opts):
673 def debugcomplete(ui, cmd='', **opts):
674 """returns the completion list associated with the given command"""
674 """returns the completion list associated with the given command"""
675
675
676 if opts['options']:
676 if opts['options']:
677 options = []
677 options = []
678 otables = [globalopts]
678 otables = [globalopts]
679 if cmd:
679 if cmd:
680 aliases, entry = findcmd(ui, cmd)
680 aliases, entry = findcmd(ui, cmd)
681 otables.append(entry[1])
681 otables.append(entry[1])
682 for t in otables:
682 for t in otables:
683 for o in t:
683 for o in t:
684 if o[0]:
684 if o[0]:
685 options.append('-%s' % o[0])
685 options.append('-%s' % o[0])
686 options.append('--%s' % o[1])
686 options.append('--%s' % o[1])
687 ui.write("%s\n" % "\n".join(options))
687 ui.write("%s\n" % "\n".join(options))
688 return
688 return
689
689
690 clist = findpossible(ui, cmd).keys()
690 clist = findpossible(ui, cmd).keys()
691 clist.sort()
691 clist.sort()
692 ui.write("%s\n" % "\n".join(clist))
692 ui.write("%s\n" % "\n".join(clist))
693
693
694 def debugrebuildstate(ui, repo, rev=""):
694 def debugrebuildstate(ui, repo, rev=""):
695 """rebuild the dirstate as it would look like for the given revision"""
695 """rebuild the dirstate as it would look like for the given revision"""
696 if rev == "":
696 if rev == "":
697 rev = repo.changelog.tip()
697 rev = repo.changelog.tip()
698 ctx = repo.changectx(rev)
698 ctx = repo.changectx(rev)
699 files = ctx.manifest()
699 files = ctx.manifest()
700 wlock = repo.wlock()
700 wlock = repo.wlock()
701 repo.dirstate.rebuild(rev, files)
701 repo.dirstate.rebuild(rev, files)
702
702
703 def debugcheckstate(ui, repo):
703 def debugcheckstate(ui, repo):
704 """validate the correctness of the current dirstate"""
704 """validate the correctness of the current dirstate"""
705 parent1, parent2 = repo.dirstate.parents()
705 parent1, parent2 = repo.dirstate.parents()
706 repo.dirstate.read()
706 repo.dirstate.read()
707 dc = repo.dirstate.map
707 dc = repo.dirstate.map
708 keys = dc.keys()
708 keys = dc.keys()
709 keys.sort()
709 keys.sort()
710 m1 = repo.changectx(parent1).manifest()
710 m1 = repo.changectx(parent1).manifest()
711 m2 = repo.changectx(parent2).manifest()
711 m2 = repo.changectx(parent2).manifest()
712 errors = 0
712 errors = 0
713 for f in dc:
713 for f in dc:
714 state = repo.dirstate.state(f)
714 state = repo.dirstate.state(f)
715 if state in "nr" and f not in m1:
715 if state in "nr" and f not in m1:
716 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
716 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
717 errors += 1
717 errors += 1
718 if state in "a" and f in m1:
718 if state in "a" and f in m1:
719 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
719 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
720 errors += 1
720 errors += 1
721 if state in "m" and f not in m1 and f not in m2:
721 if state in "m" and f not in m1 and f not in m2:
722 ui.warn(_("%s in state %s, but not in either manifest\n") %
722 ui.warn(_("%s in state %s, but not in either manifest\n") %
723 (f, state))
723 (f, state))
724 errors += 1
724 errors += 1
725 for f in m1:
725 for f in m1:
726 state = repo.dirstate.state(f)
726 state = repo.dirstate.state(f)
727 if state not in "nrm":
727 if state not in "nrm":
728 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
728 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
729 errors += 1
729 errors += 1
730 if errors:
730 if errors:
731 error = _(".hg/dirstate inconsistent with current parent's manifest")
731 error = _(".hg/dirstate inconsistent with current parent's manifest")
732 raise util.Abort(error)
732 raise util.Abort(error)
733
733
734 def showconfig(ui, repo, *values, **opts):
734 def showconfig(ui, repo, *values, **opts):
735 """show combined config settings from all hgrc files
735 """show combined config settings from all hgrc files
736
736
737 With no args, print names and values of all config items.
737 With no args, print names and values of all config items.
738
738
739 With one arg of the form section.name, print just the value of
739 With one arg of the form section.name, print just the value of
740 that config item.
740 that config item.
741
741
742 With multiple args, print names and values of all config items
742 With multiple args, print names and values of all config items
743 with matching section names."""
743 with matching section names."""
744
744
745 untrusted = bool(opts.get('untrusted'))
745 untrusted = bool(opts.get('untrusted'))
746 if values:
746 if values:
747 if len([v for v in values if '.' in v]) > 1:
747 if len([v for v in values if '.' in v]) > 1:
748 raise util.Abort(_('only one config item permitted'))
748 raise util.Abort(_('only one config item permitted'))
749 for section, name, value in ui.walkconfig(untrusted=untrusted):
749 for section, name, value in ui.walkconfig(untrusted=untrusted):
750 sectname = section + '.' + name
750 sectname = section + '.' + name
751 if values:
751 if values:
752 for v in values:
752 for v in values:
753 if v == section:
753 if v == section:
754 ui.write('%s=%s\n' % (sectname, value))
754 ui.write('%s=%s\n' % (sectname, value))
755 elif v == sectname:
755 elif v == sectname:
756 ui.write(value, '\n')
756 ui.write(value, '\n')
757 else:
757 else:
758 ui.write('%s=%s\n' % (sectname, value))
758 ui.write('%s=%s\n' % (sectname, value))
759
759
760 def debugsetparents(ui, repo, rev1, rev2=None):
760 def debugsetparents(ui, repo, rev1, rev2=None):
761 """manually set the parents of the current working directory
761 """manually set the parents of the current working directory
762
762
763 This is useful for writing repository conversion tools, but should
763 This is useful for writing repository conversion tools, but should
764 be used with care.
764 be used with care.
765 """
765 """
766
766
767 if not rev2:
767 if not rev2:
768 rev2 = hex(nullid)
768 rev2 = hex(nullid)
769
769
770 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
770 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
771
771
772 def debugstate(ui, repo):
772 def debugstate(ui, repo):
773 """show the contents of the current dirstate"""
773 """show the contents of the current dirstate"""
774 repo.dirstate.read()
774 repo.dirstate.read()
775 dc = repo.dirstate.map
775 dc = repo.dirstate.map
776 keys = dc.keys()
776 keys = dc.keys()
777 keys.sort()
777 keys.sort()
778 for file_ in keys:
778 for file_ in keys:
779 if dc[file_][3] == -1:
779 if dc[file_][3] == -1:
780 # Pad or slice to locale representation
780 # Pad or slice to locale representation
781 locale_len = len(time.strftime("%x %X", time.localtime(0)))
781 locale_len = len(time.strftime("%x %X", time.localtime(0)))
782 timestr = 'unset'
782 timestr = 'unset'
783 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
783 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
784 else:
784 else:
785 timestr = time.strftime("%x %X", time.localtime(dc[file_][3]))
785 timestr = time.strftime("%x %X", time.localtime(dc[file_][3]))
786 ui.write("%c %3o %10d %s %s\n"
786 ui.write("%c %3o %10d %s %s\n"
787 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
787 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
788 timestr, file_))
788 timestr, file_))
789 for f in repo.dirstate.copies():
789 for f in repo.dirstate.copies():
790 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
790 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
791
791
792 def debugdata(ui, file_, rev):
792 def debugdata(ui, file_, rev):
793 """dump the contents of an data file revision"""
793 """dump the contents of an data file revision"""
794 r = revlog.revlog(util.opener(os.getcwd(), audit=False),
794 r = revlog.revlog(util.opener(os.getcwd(), audit=False),
795 file_[:-2] + ".i", file_, 0)
795 file_[:-2] + ".i", file_, 0)
796 try:
796 try:
797 ui.write(r.revision(r.lookup(rev)))
797 ui.write(r.revision(r.lookup(rev)))
798 except KeyError:
798 except KeyError:
799 raise util.Abort(_('invalid revision identifier %s') % rev)
799 raise util.Abort(_('invalid revision identifier %s') % rev)
800
800
801 def debugdate(ui, date, range=None, **opts):
801 def debugdate(ui, date, range=None, **opts):
802 """parse and display a date"""
802 """parse and display a date"""
803 if opts["extended"]:
803 if opts["extended"]:
804 d = util.parsedate(date, util.extendeddateformats)
804 d = util.parsedate(date, util.extendeddateformats)
805 else:
805 else:
806 d = util.parsedate(date)
806 d = util.parsedate(date)
807 ui.write("internal: %s %s\n" % d)
807 ui.write("internal: %s %s\n" % d)
808 ui.write("standard: %s\n" % util.datestr(d))
808 ui.write("standard: %s\n" % util.datestr(d))
809 if range:
809 if range:
810 m = util.matchdate(range)
810 m = util.matchdate(range)
811 ui.write("match: %s\n" % m(d[0]))
811 ui.write("match: %s\n" % m(d[0]))
812
812
813 def debugindex(ui, file_):
813 def debugindex(ui, file_):
814 """dump the contents of an index file"""
814 """dump the contents of an index file"""
815 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
815 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
816 ui.write(" rev offset length base linkrev" +
816 ui.write(" rev offset length base linkrev" +
817 " nodeid p1 p2\n")
817 " nodeid p1 p2\n")
818 for i in xrange(r.count()):
818 for i in xrange(r.count()):
819 node = r.node(i)
819 node = r.node(i)
820 pp = r.parents(node)
820 pp = r.parents(node)
821 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
821 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
822 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
822 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
823 short(node), short(pp[0]), short(pp[1])))
823 short(node), short(pp[0]), short(pp[1])))
824
824
825 def debugindexdot(ui, file_):
825 def debugindexdot(ui, file_):
826 """dump an index DAG as a .dot file"""
826 """dump an index DAG as a .dot file"""
827 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
827 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
828 ui.write("digraph G {\n")
828 ui.write("digraph G {\n")
829 for i in xrange(r.count()):
829 for i in xrange(r.count()):
830 node = r.node(i)
830 node = r.node(i)
831 pp = r.parents(node)
831 pp = r.parents(node)
832 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
832 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
833 if pp[1] != nullid:
833 if pp[1] != nullid:
834 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
834 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
835 ui.write("}\n")
835 ui.write("}\n")
836
836
837 def debuginstall(ui):
837 def debuginstall(ui):
838 '''test Mercurial installation'''
838 '''test Mercurial installation'''
839
839
840 def writetemp(contents):
840 def writetemp(contents):
841 (fd, name) = tempfile.mkstemp()
841 (fd, name) = tempfile.mkstemp()
842 f = os.fdopen(fd, "wb")
842 f = os.fdopen(fd, "wb")
843 f.write(contents)
843 f.write(contents)
844 f.close()
844 f.close()
845 return name
845 return name
846
846
847 problems = 0
847 problems = 0
848
848
849 # encoding
849 # encoding
850 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
850 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
851 try:
851 try:
852 util.fromlocal("test")
852 util.fromlocal("test")
853 except util.Abort, inst:
853 except util.Abort, inst:
854 ui.write(" %s\n" % inst)
854 ui.write(" %s\n" % inst)
855 ui.write(_(" (check that your locale is properly set)\n"))
855 ui.write(_(" (check that your locale is properly set)\n"))
856 problems += 1
856 problems += 1
857
857
858 # compiled modules
858 # compiled modules
859 ui.status(_("Checking extensions...\n"))
859 ui.status(_("Checking extensions...\n"))
860 try:
860 try:
861 import bdiff, mpatch, base85
861 import bdiff, mpatch, base85
862 except Exception, inst:
862 except Exception, inst:
863 ui.write(" %s\n" % inst)
863 ui.write(" %s\n" % inst)
864 ui.write(_(" One or more extensions could not be found"))
864 ui.write(_(" One or more extensions could not be found"))
865 ui.write(_(" (check that you compiled the extensions)\n"))
865 ui.write(_(" (check that you compiled the extensions)\n"))
866 problems += 1
866 problems += 1
867
867
868 # templates
868 # templates
869 ui.status(_("Checking templates...\n"))
869 ui.status(_("Checking templates...\n"))
870 try:
870 try:
871 import templater
871 import templater
872 t = templater.templater(templater.templatepath("map-cmdline.default"))
872 t = templater.templater(templater.templatepath("map-cmdline.default"))
873 except Exception, inst:
873 except Exception, inst:
874 ui.write(" %s\n" % inst)
874 ui.write(" %s\n" % inst)
875 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
875 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
876 problems += 1
876 problems += 1
877
877
878 # patch
878 # patch
879 ui.status(_("Checking patch...\n"))
879 ui.status(_("Checking patch...\n"))
880 path = os.environ.get('PATH', '')
880 path = os.environ.get('PATH', '')
881 patcher = util.find_in_path('gpatch', path,
881 patcher = util.find_in_path('gpatch', path,
882 util.find_in_path('patch', path, None))
882 util.find_in_path('patch', path, None))
883 if not patcher:
883 if not patcher:
884 ui.write(_(" Can't find patch or gpatch in PATH\n"))
884 ui.write(_(" Can't find patch or gpatch in PATH\n"))
885 ui.write(_(" (specify a patch utility in your .hgrc file)\n"))
885 ui.write(_(" (specify a patch utility in your .hgrc file)\n"))
886 problems += 1
886 problems += 1
887 else:
887 else:
888 # actually attempt a patch here
888 # actually attempt a patch here
889 a = "1\n2\n3\n4\n"
889 a = "1\n2\n3\n4\n"
890 b = "1\n2\n3\ninsert\n4\n"
890 b = "1\n2\n3\ninsert\n4\n"
891 d = mdiff.unidiff(a, None, b, None, "a")
891 d = mdiff.unidiff(a, None, b, None, "a")
892 fa = writetemp(a)
892 fa = writetemp(a)
893 fd = writetemp(d)
893 fd = writetemp(d)
894 fp = os.popen('%s %s %s' % (patcher, fa, fd))
894 fp = os.popen('%s %s %s' % (patcher, fa, fd))
895 files = []
895 files = []
896 output = ""
896 output = ""
897 for line in fp:
897 for line in fp:
898 output += line
898 output += line
899 if line.startswith('patching file '):
899 if line.startswith('patching file '):
900 pf = util.parse_patch_output(line.rstrip())
900 pf = util.parse_patch_output(line.rstrip())
901 files.append(pf)
901 files.append(pf)
902 if files != [fa]:
902 if files != [fa]:
903 ui.write(_(" unexpected patch output!"))
903 ui.write(_(" unexpected patch output!"))
904 ui.write(_(" (you may have an incompatible version of patch)\n"))
904 ui.write(_(" (you may have an incompatible version of patch)\n"))
905 ui.write(output)
905 ui.write(output)
906 problems += 1
906 problems += 1
907 a = file(fa).read()
907 a = file(fa).read()
908 if a != b:
908 if a != b:
909 ui.write(_(" patch test failed!"))
909 ui.write(_(" patch test failed!"))
910 ui.write(_(" (you may have an incompatible version of patch)\n"))
910 ui.write(_(" (you may have an incompatible version of patch)\n"))
911 problems += 1
911 problems += 1
912 os.unlink(fa)
912 os.unlink(fa)
913 os.unlink(fd)
913 os.unlink(fd)
914
914
915 # merge helper
915 # merge helper
916 ui.status(_("Checking merge helper...\n"))
916 ui.status(_("Checking merge helper...\n"))
917 cmd = (os.environ.get("HGMERGE") or ui.config("ui", "merge")
917 cmd = (os.environ.get("HGMERGE") or ui.config("ui", "merge")
918 or "hgmerge")
918 or "hgmerge")
919 cmdpath = util.find_in_path(cmd, path)
919 cmdpath = util.find_in_path(cmd, path)
920 if not cmdpath:
920 if not cmdpath:
921 cmdpath = util.find_in_path(cmd.split()[0], path)
921 cmdpath = util.find_in_path(cmd.split()[0], path)
922 if not cmdpath:
922 if not cmdpath:
923 if cmd == 'hgmerge':
923 if cmd == 'hgmerge':
924 ui.write(_(" No merge helper set and can't find default"
924 ui.write(_(" No merge helper set and can't find default"
925 " hgmerge script in PATH\n"))
925 " hgmerge script in PATH\n"))
926 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
926 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
927 else:
927 else:
928 ui.write(_(" Can't find merge helper '%s' in PATH\n") % cmd)
928 ui.write(_(" Can't find merge helper '%s' in PATH\n") % cmd)
929 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
929 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
930 problems += 1
930 problems += 1
931 else:
931 else:
932 # actually attempt a patch here
932 # actually attempt a patch here
933 fa = writetemp("1\n2\n3\n4\n")
933 fa = writetemp("1\n2\n3\n4\n")
934 fl = writetemp("1\n2\n3\ninsert\n4\n")
934 fl = writetemp("1\n2\n3\ninsert\n4\n")
935 fr = writetemp("begin\n1\n2\n3\n4\n")
935 fr = writetemp("begin\n1\n2\n3\n4\n")
936 r = os.system('%s %s %s %s' % (cmd, fl, fa, fr))
936 r = os.system('%s %s %s %s' % (cmd, fl, fa, fr))
937 if r:
937 if r:
938 ui.write(_(" got unexpected merge error %d!") % r)
938 ui.write(_(" got unexpected merge error %d!") % r)
939 problems += 1
939 problems += 1
940 m = file(fl).read()
940 m = file(fl).read()
941 if m != "begin\n1\n2\n3\ninsert\n4\n":
941 if m != "begin\n1\n2\n3\ninsert\n4\n":
942 ui.write(_(" got unexpected merge results!") % r)
942 ui.write(_(" got unexpected merge results!") % r)
943 ui.write(_(" (your merge helper may have the"
943 ui.write(_(" (your merge helper may have the"
944 " wrong argument order)\n"))
944 " wrong argument order)\n"))
945 ui.write(m)
945 ui.write(m)
946 os.unlink(fa)
946 os.unlink(fa)
947 os.unlink(fl)
947 os.unlink(fl)
948 os.unlink(fr)
948 os.unlink(fr)
949
949
950 # editor
950 # editor
951 ui.status(_("Checking commit editor...\n"))
951 ui.status(_("Checking commit editor...\n"))
952 editor = (os.environ.get("HGEDITOR") or
952 editor = (os.environ.get("HGEDITOR") or
953 ui.config("ui", "editor") or
953 ui.config("ui", "editor") or
954 os.environ.get("EDITOR", "vi"))
954 os.environ.get("EDITOR", "vi"))
955 cmdpath = util.find_in_path(editor, path)
955 cmdpath = util.find_in_path(editor, path)
956 if not cmdpath:
956 if not cmdpath:
957 cmdpath = util.find_in_path(editor.split()[0], path)
957 cmdpath = util.find_in_path(editor.split()[0], path)
958 if not cmdpath:
958 if not cmdpath:
959 if editor == 'vi':
959 if editor == 'vi':
960 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
960 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
961 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
961 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
962 else:
962 else:
963 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
963 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
964 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
964 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
965 problems += 1
965 problems += 1
966
966
967 # check username
967 # check username
968 ui.status(_("Checking username...\n"))
968 ui.status(_("Checking username...\n"))
969 user = os.environ.get("HGUSER")
969 user = os.environ.get("HGUSER")
970 if user is None:
970 if user is None:
971 user = ui.config("ui", "username")
971 user = ui.config("ui", "username")
972 if user is None:
972 if user is None:
973 user = os.environ.get("EMAIL")
973 user = os.environ.get("EMAIL")
974 if not user:
974 if not user:
975 ui.warn(" ")
975 ui.warn(" ")
976 ui.username()
976 ui.username()
977 ui.write(_(" (specify a username in your .hgrc file)\n"))
977 ui.write(_(" (specify a username in your .hgrc file)\n"))
978
978
979 if not problems:
979 if not problems:
980 ui.status(_("No problems detected\n"))
980 ui.status(_("No problems detected\n"))
981 else:
981 else:
982 ui.write(_("%s problems detected,"
982 ui.write(_("%s problems detected,"
983 " please check your install!\n") % problems)
983 " please check your install!\n") % problems)
984
984
985 return problems
985 return problems
986
986
987 def debugrename(ui, repo, file1, *pats, **opts):
987 def debugrename(ui, repo, file1, *pats, **opts):
988 """dump rename information"""
988 """dump rename information"""
989
989
990 ctx = repo.changectx(opts.get('rev', 'tip'))
990 ctx = repo.changectx(opts.get('rev', 'tip'))
991 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
991 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
992 ctx.node()):
992 ctx.node()):
993 m = ctx.filectx(abs).renamed()
993 m = ctx.filectx(abs).renamed()
994 if m:
994 if m:
995 ui.write(_("%s renamed from %s:%s\n") % (rel, m[0], hex(m[1])))
995 ui.write(_("%s renamed from %s:%s\n") % (rel, m[0], hex(m[1])))
996 else:
996 else:
997 ui.write(_("%s not renamed\n") % rel)
997 ui.write(_("%s not renamed\n") % rel)
998
998
999 def debugwalk(ui, repo, *pats, **opts):
999 def debugwalk(ui, repo, *pats, **opts):
1000 """show how files match on given patterns"""
1000 """show how files match on given patterns"""
1001 items = list(cmdutil.walk(repo, pats, opts))
1001 items = list(cmdutil.walk(repo, pats, opts))
1002 if not items:
1002 if not items:
1003 return
1003 return
1004 fmt = '%%s %%-%ds %%-%ds %%s' % (
1004 fmt = '%%s %%-%ds %%-%ds %%s' % (
1005 max([len(abs) for (src, abs, rel, exact) in items]),
1005 max([len(abs) for (src, abs, rel, exact) in items]),
1006 max([len(rel) for (src, abs, rel, exact) in items]))
1006 max([len(rel) for (src, abs, rel, exact) in items]))
1007 for src, abs, rel, exact in items:
1007 for src, abs, rel, exact in items:
1008 line = fmt % (src, abs, rel, exact and 'exact' or '')
1008 line = fmt % (src, abs, rel, exact and 'exact' or '')
1009 ui.write("%s\n" % line.rstrip())
1009 ui.write("%s\n" % line.rstrip())
1010
1010
1011 def diff(ui, repo, *pats, **opts):
1011 def diff(ui, repo, *pats, **opts):
1012 """diff repository (or selected files)
1012 """diff repository (or selected files)
1013
1013
1014 Show differences between revisions for the specified files.
1014 Show differences between revisions for the specified files.
1015
1015
1016 Differences between files are shown using the unified diff format.
1016 Differences between files are shown using the unified diff format.
1017
1017
1018 NOTE: diff may generate unexpected results for merges, as it will
1018 NOTE: diff may generate unexpected results for merges, as it will
1019 default to comparing against the working directory's first parent
1019 default to comparing against the working directory's first parent
1020 changeset if no revisions are specified.
1020 changeset if no revisions are specified.
1021
1021
1022 When two revision arguments are given, then changes are shown
1022 When two revision arguments are given, then changes are shown
1023 between those revisions. If only one revision is specified then
1023 between those revisions. If only one revision is specified then
1024 that revision is compared to the working directory, and, when no
1024 that revision is compared to the working directory, and, when no
1025 revisions are specified, the working directory files are compared
1025 revisions are specified, the working directory files are compared
1026 to its parent.
1026 to its parent.
1027
1027
1028 Without the -a option, diff will avoid generating diffs of files
1028 Without the -a option, diff will avoid generating diffs of files
1029 it detects as binary. With -a, diff will generate a diff anyway,
1029 it detects as binary. With -a, diff will generate a diff anyway,
1030 probably with undesirable results.
1030 probably with undesirable results.
1031 """
1031 """
1032 node1, node2 = cmdutil.revpair(repo, opts['rev'])
1032 node1, node2 = cmdutil.revpair(repo, opts['rev'])
1033
1033
1034 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1034 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1035
1035
1036 patch.diff(repo, node1, node2, fns, match=matchfn,
1036 patch.diff(repo, node1, node2, fns, match=matchfn,
1037 opts=patch.diffopts(ui, opts))
1037 opts=patch.diffopts(ui, opts))
1038
1038
1039 def export(ui, repo, *changesets, **opts):
1039 def export(ui, repo, *changesets, **opts):
1040 """dump the header and diffs for one or more changesets
1040 """dump the header and diffs for one or more changesets
1041
1041
1042 Print the changeset header and diffs for one or more revisions.
1042 Print the changeset header and diffs for one or more revisions.
1043
1043
1044 The information shown in the changeset header is: author,
1044 The information shown in the changeset header is: author,
1045 changeset hash, parent(s) and commit comment.
1045 changeset hash, parent(s) and commit comment.
1046
1046
1047 NOTE: export may generate unexpected diff output for merge changesets,
1047 NOTE: export may generate unexpected diff output for merge changesets,
1048 as it will compare the merge changeset against its first parent only.
1048 as it will compare the merge changeset against its first parent only.
1049
1049
1050 Output may be to a file, in which case the name of the file is
1050 Output may be to a file, in which case the name of the file is
1051 given using a format string. The formatting rules are as follows:
1051 given using a format string. The formatting rules are as follows:
1052
1052
1053 %% literal "%" character
1053 %% literal "%" character
1054 %H changeset hash (40 bytes of hexadecimal)
1054 %H changeset hash (40 bytes of hexadecimal)
1055 %N number of patches being generated
1055 %N number of patches being generated
1056 %R changeset revision number
1056 %R changeset revision number
1057 %b basename of the exporting repository
1057 %b basename of the exporting repository
1058 %h short-form changeset hash (12 bytes of hexadecimal)
1058 %h short-form changeset hash (12 bytes of hexadecimal)
1059 %n zero-padded sequence number, starting at 1
1059 %n zero-padded sequence number, starting at 1
1060 %r zero-padded changeset revision number
1060 %r zero-padded changeset revision number
1061
1061
1062 Without the -a option, export will avoid generating diffs of files
1062 Without the -a option, export will avoid generating diffs of files
1063 it detects as binary. With -a, export will generate a diff anyway,
1063 it detects as binary. With -a, export will generate a diff anyway,
1064 probably with undesirable results.
1064 probably with undesirable results.
1065
1065
1066 With the --switch-parent option, the diff will be against the second
1066 With the --switch-parent option, the diff will be against the second
1067 parent. It can be useful to review a merge.
1067 parent. It can be useful to review a merge.
1068 """
1068 """
1069 if not changesets:
1069 if not changesets:
1070 raise util.Abort(_("export requires at least one changeset"))
1070 raise util.Abort(_("export requires at least one changeset"))
1071 revs = cmdutil.revrange(repo, changesets)
1071 revs = cmdutil.revrange(repo, changesets)
1072 if len(revs) > 1:
1072 if len(revs) > 1:
1073 ui.note(_('exporting patches:\n'))
1073 ui.note(_('exporting patches:\n'))
1074 else:
1074 else:
1075 ui.note(_('exporting patch:\n'))
1075 ui.note(_('exporting patch:\n'))
1076 patch.export(repo, revs, template=opts['output'],
1076 patch.export(repo, revs, template=opts['output'],
1077 switch_parent=opts['switch_parent'],
1077 switch_parent=opts['switch_parent'],
1078 opts=patch.diffopts(ui, opts))
1078 opts=patch.diffopts(ui, opts))
1079
1079
1080 def grep(ui, repo, pattern, *pats, **opts):
1080 def grep(ui, repo, pattern, *pats, **opts):
1081 """search for a pattern in specified files and revisions
1081 """search for a pattern in specified files and revisions
1082
1082
1083 Search revisions of files for a regular expression.
1083 Search revisions of files for a regular expression.
1084
1084
1085 This command behaves differently than Unix grep. It only accepts
1085 This command behaves differently than Unix grep. It only accepts
1086 Python/Perl regexps. It searches repository history, not the
1086 Python/Perl regexps. It searches repository history, not the
1087 working directory. It always prints the revision number in which
1087 working directory. It always prints the revision number in which
1088 a match appears.
1088 a match appears.
1089
1089
1090 By default, grep only prints output for the first revision of a
1090 By default, grep only prints output for the first revision of a
1091 file in which it finds a match. To get it to print every revision
1091 file in which it finds a match. To get it to print every revision
1092 that contains a change in match status ("-" for a match that
1092 that contains a change in match status ("-" for a match that
1093 becomes a non-match, or "+" for a non-match that becomes a match),
1093 becomes a non-match, or "+" for a non-match that becomes a match),
1094 use the --all flag.
1094 use the --all flag.
1095 """
1095 """
1096 reflags = 0
1096 reflags = 0
1097 if opts['ignore_case']:
1097 if opts['ignore_case']:
1098 reflags |= re.I
1098 reflags |= re.I
1099 regexp = re.compile(pattern, reflags)
1099 regexp = re.compile(pattern, reflags)
1100 sep, eol = ':', '\n'
1100 sep, eol = ':', '\n'
1101 if opts['print0']:
1101 if opts['print0']:
1102 sep = eol = '\0'
1102 sep = eol = '\0'
1103
1103
1104 fcache = {}
1104 fcache = {}
1105 def getfile(fn):
1105 def getfile(fn):
1106 if fn not in fcache:
1106 if fn not in fcache:
1107 fcache[fn] = repo.file(fn)
1107 fcache[fn] = repo.file(fn)
1108 return fcache[fn]
1108 return fcache[fn]
1109
1109
1110 def matchlines(body):
1110 def matchlines(body):
1111 begin = 0
1111 begin = 0
1112 linenum = 0
1112 linenum = 0
1113 while True:
1113 while True:
1114 match = regexp.search(body, begin)
1114 match = regexp.search(body, begin)
1115 if not match:
1115 if not match:
1116 break
1116 break
1117 mstart, mend = match.span()
1117 mstart, mend = match.span()
1118 linenum += body.count('\n', begin, mstart) + 1
1118 linenum += body.count('\n', begin, mstart) + 1
1119 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1119 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1120 lend = body.find('\n', mend)
1120 lend = body.find('\n', mend)
1121 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1121 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1122 begin = lend + 1
1122 begin = lend + 1
1123
1123
1124 class linestate(object):
1124 class linestate(object):
1125 def __init__(self, line, linenum, colstart, colend):
1125 def __init__(self, line, linenum, colstart, colend):
1126 self.line = line
1126 self.line = line
1127 self.linenum = linenum
1127 self.linenum = linenum
1128 self.colstart = colstart
1128 self.colstart = colstart
1129 self.colend = colend
1129 self.colend = colend
1130
1130
1131 def __eq__(self, other):
1131 def __eq__(self, other):
1132 return self.line == other.line
1132 return self.line == other.line
1133
1133
1134 matches = {}
1134 matches = {}
1135 copies = {}
1135 copies = {}
1136 def grepbody(fn, rev, body):
1136 def grepbody(fn, rev, body):
1137 matches[rev].setdefault(fn, [])
1137 matches[rev].setdefault(fn, [])
1138 m = matches[rev][fn]
1138 m = matches[rev][fn]
1139 for lnum, cstart, cend, line in matchlines(body):
1139 for lnum, cstart, cend, line in matchlines(body):
1140 s = linestate(line, lnum, cstart, cend)
1140 s = linestate(line, lnum, cstart, cend)
1141 m.append(s)
1141 m.append(s)
1142
1142
1143 def difflinestates(a, b):
1143 def difflinestates(a, b):
1144 sm = difflib.SequenceMatcher(None, a, b)
1144 sm = difflib.SequenceMatcher(None, a, b)
1145 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1145 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1146 if tag == 'insert':
1146 if tag == 'insert':
1147 for i in xrange(blo, bhi):
1147 for i in xrange(blo, bhi):
1148 yield ('+', b[i])
1148 yield ('+', b[i])
1149 elif tag == 'delete':
1149 elif tag == 'delete':
1150 for i in xrange(alo, ahi):
1150 for i in xrange(alo, ahi):
1151 yield ('-', a[i])
1151 yield ('-', a[i])
1152 elif tag == 'replace':
1152 elif tag == 'replace':
1153 for i in xrange(alo, ahi):
1153 for i in xrange(alo, ahi):
1154 yield ('-', a[i])
1154 yield ('-', a[i])
1155 for i in xrange(blo, bhi):
1155 for i in xrange(blo, bhi):
1156 yield ('+', b[i])
1156 yield ('+', b[i])
1157
1157
1158 prev = {}
1158 prev = {}
1159 def display(fn, rev, states, prevstates):
1159 def display(fn, rev, states, prevstates):
1160 found = False
1160 found = False
1161 filerevmatches = {}
1161 filerevmatches = {}
1162 r = prev.get(fn, -1)
1162 r = prev.get(fn, -1)
1163 if opts['all']:
1163 if opts['all']:
1164 iter = difflinestates(states, prevstates)
1164 iter = difflinestates(states, prevstates)
1165 else:
1165 else:
1166 iter = [('', l) for l in prevstates]
1166 iter = [('', l) for l in prevstates]
1167 for change, l in iter:
1167 for change, l in iter:
1168 cols = [fn, str(r)]
1168 cols = [fn, str(r)]
1169 if opts['line_number']:
1169 if opts['line_number']:
1170 cols.append(str(l.linenum))
1170 cols.append(str(l.linenum))
1171 if opts['all']:
1171 if opts['all']:
1172 cols.append(change)
1172 cols.append(change)
1173 if opts['user']:
1173 if opts['user']:
1174 cols.append(ui.shortuser(get(r)[1]))
1174 cols.append(ui.shortuser(get(r)[1]))
1175 if opts['files_with_matches']:
1175 if opts['files_with_matches']:
1176 c = (fn, r)
1176 c = (fn, r)
1177 if c in filerevmatches:
1177 if c in filerevmatches:
1178 continue
1178 continue
1179 filerevmatches[c] = 1
1179 filerevmatches[c] = 1
1180 else:
1180 else:
1181 cols.append(l.line)
1181 cols.append(l.line)
1182 ui.write(sep.join(cols), eol)
1182 ui.write(sep.join(cols), eol)
1183 found = True
1183 found = True
1184 return found
1184 return found
1185
1185
1186 fstate = {}
1186 fstate = {}
1187 skip = {}
1187 skip = {}
1188 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1188 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1189 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1189 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1190 found = False
1190 found = False
1191 follow = opts.get('follow')
1191 follow = opts.get('follow')
1192 for st, rev, fns in changeiter:
1192 for st, rev, fns in changeiter:
1193 if st == 'window':
1193 if st == 'window':
1194 matches.clear()
1194 matches.clear()
1195 elif st == 'add':
1195 elif st == 'add':
1196 mf = repo.changectx(rev).manifest()
1196 mf = repo.changectx(rev).manifest()
1197 matches[rev] = {}
1197 matches[rev] = {}
1198 for fn in fns:
1198 for fn in fns:
1199 if fn in skip:
1199 if fn in skip:
1200 continue
1200 continue
1201 fstate.setdefault(fn, {})
1201 fstate.setdefault(fn, {})
1202 try:
1202 try:
1203 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1203 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1204 if follow:
1204 if follow:
1205 copied = getfile(fn).renamed(mf[fn])
1205 copied = getfile(fn).renamed(mf[fn])
1206 if copied:
1206 if copied:
1207 copies.setdefault(rev, {})[fn] = copied[0]
1207 copies.setdefault(rev, {})[fn] = copied[0]
1208 except KeyError:
1208 except KeyError:
1209 pass
1209 pass
1210 elif st == 'iter':
1210 elif st == 'iter':
1211 states = matches[rev].items()
1211 states = matches[rev].items()
1212 states.sort()
1212 states.sort()
1213 for fn, m in states:
1213 for fn, m in states:
1214 copy = copies.get(rev, {}).get(fn)
1214 copy = copies.get(rev, {}).get(fn)
1215 if fn in skip:
1215 if fn in skip:
1216 if copy:
1216 if copy:
1217 skip[copy] = True
1217 skip[copy] = True
1218 continue
1218 continue
1219 if fn in prev or fstate[fn]:
1219 if fn in prev or fstate[fn]:
1220 r = display(fn, rev, m, fstate[fn])
1220 r = display(fn, rev, m, fstate[fn])
1221 found = found or r
1221 found = found or r
1222 if r and not opts['all']:
1222 if r and not opts['all']:
1223 skip[fn] = True
1223 skip[fn] = True
1224 if copy:
1224 if copy:
1225 skip[copy] = True
1225 skip[copy] = True
1226 fstate[fn] = m
1226 fstate[fn] = m
1227 if copy:
1227 if copy:
1228 fstate[copy] = m
1228 fstate[copy] = m
1229 prev[fn] = rev
1229 prev[fn] = rev
1230
1230
1231 fstate = fstate.items()
1231 fstate = fstate.items()
1232 fstate.sort()
1232 fstate.sort()
1233 for fn, state in fstate:
1233 for fn, state in fstate:
1234 if fn in skip:
1234 if fn in skip:
1235 continue
1235 continue
1236 if fn not in copies.get(prev[fn], {}):
1236 if fn not in copies.get(prev[fn], {}):
1237 found = display(fn, rev, {}, state) or found
1237 found = display(fn, rev, {}, state) or found
1238 return (not found and 1) or 0
1238 return (not found and 1) or 0
1239
1239
1240 def heads(ui, repo, **opts):
1240 def heads(ui, repo, **opts):
1241 """show current repository heads
1241 """show current repository heads
1242
1242
1243 Show all repository head changesets.
1243 Show all repository head changesets.
1244
1244
1245 Repository "heads" are changesets that don't have children
1245 Repository "heads" are changesets that don't have children
1246 changesets. They are where development generally takes place and
1246 changesets. They are where development generally takes place and
1247 are the usual targets for update and merge operations.
1247 are the usual targets for update and merge operations.
1248 """
1248 """
1249 if opts['rev']:
1249 if opts['rev']:
1250 heads = repo.heads(repo.lookup(opts['rev']))
1250 heads = repo.heads(repo.lookup(opts['rev']))
1251 else:
1251 else:
1252 heads = repo.heads()
1252 heads = repo.heads()
1253 displayer = cmdutil.show_changeset(ui, repo, opts)
1253 displayer = cmdutil.show_changeset(ui, repo, opts)
1254 for n in heads:
1254 for n in heads:
1255 displayer.show(changenode=n)
1255 displayer.show(changenode=n)
1256
1256
1257 def help_(ui, name=None, with_version=False):
1257 def help_(ui, name=None, with_version=False):
1258 """show help for a command, extension, or list of commands
1258 """show help for a command, extension, or list of commands
1259
1259
1260 With no arguments, print a list of commands and short help.
1260 With no arguments, print a list of commands and short help.
1261
1261
1262 Given a command name, print help for that command.
1262 Given a command name, print help for that command.
1263
1263
1264 Given an extension name, print help for that extension, and the
1264 Given an extension name, print help for that extension, and the
1265 commands it provides."""
1265 commands it provides."""
1266 option_lists = []
1266 option_lists = []
1267
1267
1268 def helpcmd(name):
1268 def helpcmd(name):
1269 if with_version:
1269 if with_version:
1270 version_(ui)
1270 version_(ui)
1271 ui.write('\n')
1271 ui.write('\n')
1272 aliases, i = findcmd(ui, name)
1272 aliases, i = findcmd(ui, name)
1273 # synopsis
1273 # synopsis
1274 ui.write("%s\n\n" % i[2])
1274 ui.write("%s\n\n" % i[2])
1275
1275
1276 # description
1276 # description
1277 doc = i[0].__doc__
1277 doc = i[0].__doc__
1278 if not doc:
1278 if not doc:
1279 doc = _("(No help text available)")
1279 doc = _("(No help text available)")
1280 if ui.quiet:
1280 if ui.quiet:
1281 doc = doc.splitlines(0)[0]
1281 doc = doc.splitlines(0)[0]
1282 ui.write("%s\n" % doc.rstrip())
1282 ui.write("%s\n" % doc.rstrip())
1283
1283
1284 if not ui.quiet:
1284 if not ui.quiet:
1285 # aliases
1285 # aliases
1286 if len(aliases) > 1:
1286 if len(aliases) > 1:
1287 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1287 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1288
1288
1289 # options
1289 # options
1290 if i[1]:
1290 if i[1]:
1291 option_lists.append(("options", i[1]))
1291 option_lists.append(("options", i[1]))
1292
1292
1293 def helplist(select=None):
1293 def helplist(select=None):
1294 h = {}
1294 h = {}
1295 cmds = {}
1295 cmds = {}
1296 for c, e in table.items():
1296 for c, e in table.items():
1297 f = c.split("|", 1)[0]
1297 f = c.split("|", 1)[0]
1298 if select and not select(f):
1298 if select and not select(f):
1299 continue
1299 continue
1300 if name == "shortlist" and not f.startswith("^"):
1300 if name == "shortlist" and not f.startswith("^"):
1301 continue
1301 continue
1302 f = f.lstrip("^")
1302 f = f.lstrip("^")
1303 if not ui.debugflag and f.startswith("debug"):
1303 if not ui.debugflag and f.startswith("debug"):
1304 continue
1304 continue
1305 doc = e[0].__doc__
1305 doc = e[0].__doc__
1306 if not doc:
1306 if not doc:
1307 doc = _("(No help text available)")
1307 doc = _("(No help text available)")
1308 h[f] = doc.splitlines(0)[0].rstrip()
1308 h[f] = doc.splitlines(0)[0].rstrip()
1309 cmds[f] = c.lstrip("^")
1309 cmds[f] = c.lstrip("^")
1310
1310
1311 fns = h.keys()
1311 fns = h.keys()
1312 fns.sort()
1312 fns.sort()
1313 m = max(map(len, fns))
1313 m = max(map(len, fns))
1314 for f in fns:
1314 for f in fns:
1315 if ui.verbose:
1315 if ui.verbose:
1316 commands = cmds[f].replace("|",", ")
1316 commands = cmds[f].replace("|",", ")
1317 ui.write(" %s:\n %s\n"%(commands, h[f]))
1317 ui.write(" %s:\n %s\n"%(commands, h[f]))
1318 else:
1318 else:
1319 ui.write(' %-*s %s\n' % (m, f, h[f]))
1319 ui.write(' %-*s %s\n' % (m, f, h[f]))
1320
1320
1321 def helptopic(name):
1321 def helptopic(name):
1322 v = None
1322 v = None
1323 for i in help.helptable:
1323 for i in help.helptable:
1324 l = i.split('|')
1324 l = i.split('|')
1325 if name in l:
1325 if name in l:
1326 v = i
1326 v = i
1327 header = l[-1]
1327 header = l[-1]
1328 if not v:
1328 if not v:
1329 raise UnknownCommand(name)
1329 raise UnknownCommand(name)
1330
1330
1331 # description
1331 # description
1332 doc = help.helptable[v]
1332 doc = help.helptable[v]
1333 if not doc:
1333 if not doc:
1334 doc = _("(No help text available)")
1334 doc = _("(No help text available)")
1335 if callable(doc):
1335 if callable(doc):
1336 doc = doc()
1336 doc = doc()
1337
1337
1338 ui.write("%s\n" % header)
1338 ui.write("%s\n" % header)
1339 ui.write("%s\n" % doc.rstrip())
1339 ui.write("%s\n" % doc.rstrip())
1340
1340
1341 def helpext(name):
1341 def helpext(name):
1342 try:
1342 try:
1343 mod = findext(name)
1343 mod = findext(name)
1344 except KeyError:
1344 except KeyError:
1345 raise UnknownCommand(name)
1345 raise UnknownCommand(name)
1346
1346
1347 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
1347 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
1348 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1348 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1349 for d in doc[1:]:
1349 for d in doc[1:]:
1350 ui.write(d, '\n')
1350 ui.write(d, '\n')
1351
1351
1352 ui.status('\n')
1352 ui.status('\n')
1353
1353
1354 try:
1354 try:
1355 ct = mod.cmdtable
1355 ct = mod.cmdtable
1356 except AttributeError:
1356 except AttributeError:
1357 ui.status(_('no commands defined\n'))
1357 ui.status(_('no commands defined\n'))
1358 return
1358 return
1359
1359
1360 if ui.verbose:
1360 if ui.verbose:
1361 ui.status(_('list of commands:\n\n'))
1361 ui.status(_('list of commands:\n\n'))
1362 else:
1362 else:
1363 ui.status(_('list of commands (use "hg help -v %s" '
1363 ui.status(_('list of commands (use "hg help -v %s" '
1364 'to show aliases and global options):\n\n') % name)
1364 'to show aliases and global options):\n\n') % name)
1365
1365
1366 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1366 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1367 helplist(modcmds.has_key)
1367 helplist(modcmds.has_key)
1368
1368
1369 if name and name != 'shortlist':
1369 if name and name != 'shortlist':
1370 i = None
1370 i = None
1371 for f in (helpcmd, helptopic, helpext):
1371 for f in (helpcmd, helptopic, helpext):
1372 try:
1372 try:
1373 f(name)
1373 f(name)
1374 i = None
1374 i = None
1375 break
1375 break
1376 except UnknownCommand, inst:
1376 except UnknownCommand, inst:
1377 i = inst
1377 i = inst
1378 if i:
1378 if i:
1379 raise i
1379 raise i
1380
1380
1381 else:
1381 else:
1382 # program name
1382 # program name
1383 if ui.verbose or with_version:
1383 if ui.verbose or with_version:
1384 version_(ui)
1384 version_(ui)
1385 else:
1385 else:
1386 ui.status(_("Mercurial Distributed SCM\n"))
1386 ui.status(_("Mercurial Distributed SCM\n"))
1387 ui.status('\n')
1387 ui.status('\n')
1388
1388
1389 # list of commands
1389 # list of commands
1390 if name == "shortlist":
1390 if name == "shortlist":
1391 ui.status(_('basic commands (use "hg help" '
1391 ui.status(_('basic commands (use "hg help" '
1392 'for the full list or option "-v" for details):\n\n'))
1392 'for the full list or option "-v" for details):\n\n'))
1393 elif ui.verbose:
1393 elif ui.verbose:
1394 ui.status(_('list of commands:\n\n'))
1394 ui.status(_('list of commands:\n\n'))
1395 else:
1395 else:
1396 ui.status(_('list of commands (use "hg help -v" '
1396 ui.status(_('list of commands (use "hg help -v" '
1397 'to show aliases and global options):\n\n'))
1397 'to show aliases and global options):\n\n'))
1398
1398
1399 helplist()
1399 helplist()
1400
1400
1401 # global options
1401 # global options
1402 if ui.verbose:
1402 if ui.verbose:
1403 option_lists.append(("global options", globalopts))
1403 option_lists.append(("global options", globalopts))
1404
1404
1405 # list all option lists
1405 # list all option lists
1406 opt_output = []
1406 opt_output = []
1407 for title, options in option_lists:
1407 for title, options in option_lists:
1408 opt_output.append(("\n%s:\n" % title, None))
1408 opt_output.append(("\n%s:\n" % title, None))
1409 for shortopt, longopt, default, desc in options:
1409 for shortopt, longopt, default, desc in options:
1410 if "DEPRECATED" in desc and not ui.verbose: continue
1410 if "DEPRECATED" in desc and not ui.verbose: continue
1411 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1411 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1412 longopt and " --%s" % longopt),
1412 longopt and " --%s" % longopt),
1413 "%s%s" % (desc,
1413 "%s%s" % (desc,
1414 default
1414 default
1415 and _(" (default: %s)") % default
1415 and _(" (default: %s)") % default
1416 or "")))
1416 or "")))
1417
1417
1418 if opt_output:
1418 if opt_output:
1419 opts_len = max([len(line[0]) for line in opt_output if line[1]])
1419 opts_len = max([len(line[0]) for line in opt_output if line[1]])
1420 for first, second in opt_output:
1420 for first, second in opt_output:
1421 if second:
1421 if second:
1422 ui.write(" %-*s %s\n" % (opts_len, first, second))
1422 ui.write(" %-*s %s\n" % (opts_len, first, second))
1423 else:
1423 else:
1424 ui.write("%s\n" % first)
1424 ui.write("%s\n" % first)
1425
1425
1426 def identify(ui, repo):
1426 def identify(ui, repo):
1427 """print information about the working copy
1427 """print information about the working copy
1428
1428
1429 Print a short summary of the current state of the repo.
1429 Print a short summary of the current state of the repo.
1430
1430
1431 This summary identifies the repository state using one or two parent
1431 This summary identifies the repository state using one or two parent
1432 hash identifiers, followed by a "+" if there are uncommitted changes
1432 hash identifiers, followed by a "+" if there are uncommitted changes
1433 in the working directory, followed by a list of tags for this revision.
1433 in the working directory, followed by a list of tags for this revision.
1434 """
1434 """
1435 parents = [p for p in repo.dirstate.parents() if p != nullid]
1435 parents = [p for p in repo.dirstate.parents() if p != nullid]
1436 if not parents:
1436 if not parents:
1437 ui.write(_("unknown\n"))
1437 ui.write(_("unknown\n"))
1438 return
1438 return
1439
1439
1440 hexfunc = ui.debugflag and hex or short
1440 hexfunc = ui.debugflag and hex or short
1441 modified, added, removed, deleted = repo.status()[:4]
1441 modified, added, removed, deleted = repo.status()[:4]
1442 output = ["%s%s" %
1442 output = ["%s%s" %
1443 ('+'.join([hexfunc(parent) for parent in parents]),
1443 ('+'.join([hexfunc(parent) for parent in parents]),
1444 (modified or added or removed or deleted) and "+" or "")]
1444 (modified or added or removed or deleted) and "+" or "")]
1445
1445
1446 if not ui.quiet:
1446 if not ui.quiet:
1447
1447
1448 branch = util.tolocal(repo.workingctx().branch())
1448 branch = util.tolocal(repo.workingctx().branch())
1449 if branch:
1449 if branch:
1450 output.append("(%s)" % branch)
1450 output.append("(%s)" % branch)
1451
1451
1452 # multiple tags for a single parent separated by '/'
1452 # multiple tags for a single parent separated by '/'
1453 parenttags = ['/'.join(tags)
1453 parenttags = ['/'.join(tags)
1454 for tags in map(repo.nodetags, parents) if tags]
1454 for tags in map(repo.nodetags, parents) if tags]
1455 # tags for multiple parents separated by ' + '
1455 # tags for multiple parents separated by ' + '
1456 if parenttags:
1456 if parenttags:
1457 output.append(' + '.join(parenttags))
1457 output.append(' + '.join(parenttags))
1458
1458
1459 ui.write("%s\n" % ' '.join(output))
1459 ui.write("%s\n" % ' '.join(output))
1460
1460
1461 def import_(ui, repo, patch1, *patches, **opts):
1461 def import_(ui, repo, patch1, *patches, **opts):
1462 """import an ordered set of patches
1462 """import an ordered set of patches
1463
1463
1464 Import a list of patches and commit them individually.
1464 Import a list of patches and commit them individually.
1465
1465
1466 If there are outstanding changes in the working directory, import
1466 If there are outstanding changes in the working directory, import
1467 will abort unless given the -f flag.
1467 will abort unless given the -f flag.
1468
1468
1469 You can import a patch straight from a mail message. Even patches
1469 You can import a patch straight from a mail message. Even patches
1470 as attachments work (body part must be type text/plain or
1470 as attachments work (body part must be type text/plain or
1471 text/x-patch to be used). From and Subject headers of email
1471 text/x-patch to be used). From and Subject headers of email
1472 message are used as default committer and commit message. All
1472 message are used as default committer and commit message. All
1473 text/plain body parts before first diff are added to commit
1473 text/plain body parts before first diff are added to commit
1474 message.
1474 message.
1475
1475
1476 If imported patch was generated by hg export, user and description
1476 If imported patch was generated by hg export, user and description
1477 from patch override values from message headers and body. Values
1477 from patch override values from message headers and body. Values
1478 given on command line with -m and -u override these.
1478 given on command line with -m and -u override these.
1479
1479
1480 To read a patch from standard input, use patch name "-".
1480 To read a patch from standard input, use patch name "-".
1481 """
1481 """
1482 patches = (patch1,) + patches
1482 patches = (patch1,) + patches
1483
1483
1484 if not opts['force']:
1484 if not opts['force']:
1485 bail_if_changed(repo)
1485 bail_if_changed(repo)
1486
1486
1487 d = opts["base"]
1487 d = opts["base"]
1488 strip = opts["strip"]
1488 strip = opts["strip"]
1489
1489
1490 wlock = repo.wlock()
1490 wlock = repo.wlock()
1491 lock = repo.lock()
1491 lock = repo.lock()
1492
1492
1493 for p in patches:
1493 for p in patches:
1494 pf = os.path.join(d, p)
1494 pf = os.path.join(d, p)
1495
1495
1496 if pf == '-':
1496 if pf == '-':
1497 ui.status(_("applying patch from stdin\n"))
1497 ui.status(_("applying patch from stdin\n"))
1498 tmpname, message, user, date = patch.extract(ui, sys.stdin)
1498 tmpname, message, user, date = patch.extract(ui, sys.stdin)
1499 else:
1499 else:
1500 ui.status(_("applying %s\n") % p)
1500 ui.status(_("applying %s\n") % p)
1501 tmpname, message, user, date = patch.extract(ui, file(pf))
1501 tmpname, message, user, date = patch.extract(ui, file(pf))
1502
1502
1503 if tmpname is None:
1503 if tmpname is None:
1504 raise util.Abort(_('no diffs found'))
1504 raise util.Abort(_('no diffs found'))
1505
1505
1506 try:
1506 try:
1507 cmdline_message = logmessage(opts)
1507 cmdline_message = logmessage(opts)
1508 if cmdline_message:
1508 if cmdline_message:
1509 # pickup the cmdline msg
1509 # pickup the cmdline msg
1510 message = cmdline_message
1510 message = cmdline_message
1511 elif message:
1511 elif message:
1512 # pickup the patch msg
1512 # pickup the patch msg
1513 message = message.strip()
1513 message = message.strip()
1514 else:
1514 else:
1515 # launch the editor
1515 # launch the editor
1516 message = None
1516 message = None
1517 ui.debug(_('message:\n%s\n') % message)
1517 ui.debug(_('message:\n%s\n') % message)
1518
1518
1519 files = {}
1519 files = {}
1520 try:
1520 try:
1521 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1521 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1522 files=files)
1522 files=files)
1523 finally:
1523 finally:
1524 files = patch.updatedir(ui, repo, files, wlock=wlock)
1524 files = patch.updatedir(ui, repo, files, wlock=wlock)
1525 repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1525 repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1526 finally:
1526 finally:
1527 os.unlink(tmpname)
1527 os.unlink(tmpname)
1528
1528
1529 def incoming(ui, repo, source="default", **opts):
1529 def incoming(ui, repo, source="default", **opts):
1530 """show new changesets found in source
1530 """show new changesets found in source
1531
1531
1532 Show new changesets found in the specified path/URL or the default
1532 Show new changesets found in the specified path/URL or the default
1533 pull location. These are the changesets that would be pulled if a pull
1533 pull location. These are the changesets that would be pulled if a pull
1534 was requested.
1534 was requested.
1535
1535
1536 For remote repository, using --bundle avoids downloading the changesets
1536 For remote repository, using --bundle avoids downloading the changesets
1537 twice if the incoming is followed by a pull.
1537 twice if the incoming is followed by a pull.
1538
1538
1539 See pull for valid source format details.
1539 See pull for valid source format details.
1540 """
1540 """
1541 source = ui.expandpath(source)
1541 source = ui.expandpath(source)
1542 setremoteconfig(ui, opts)
1542 setremoteconfig(ui, opts)
1543
1543
1544 other = hg.repository(ui, source)
1544 other = hg.repository(ui, source)
1545 ui.status(_('comparing with %s\n') % source)
1545 ui.status(_('comparing with %s\n') % source)
1546 incoming = repo.findincoming(other, force=opts["force"])
1546 incoming = repo.findincoming(other, force=opts["force"])
1547 if not incoming:
1547 if not incoming:
1548 try:
1548 try:
1549 os.unlink(opts["bundle"])
1549 os.unlink(opts["bundle"])
1550 except:
1550 except:
1551 pass
1551 pass
1552 ui.status(_("no changes found\n"))
1552 ui.status(_("no changes found\n"))
1553 return 1
1553 return 1
1554
1554
1555 cleanup = None
1555 cleanup = None
1556 try:
1556 try:
1557 fname = opts["bundle"]
1557 fname = opts["bundle"]
1558 if fname or not other.local():
1558 if fname or not other.local():
1559 # create a bundle (uncompressed if other repo is not local)
1559 # create a bundle (uncompressed if other repo is not local)
1560 cg = other.changegroup(incoming, "incoming")
1560 cg = other.changegroup(incoming, "incoming")
1561 bundletype = other.local() and "HG10BZ" or "HG10UN"
1561 bundletype = other.local() and "HG10BZ" or "HG10UN"
1562 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1562 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1563 # keep written bundle?
1563 # keep written bundle?
1564 if opts["bundle"]:
1564 if opts["bundle"]:
1565 cleanup = None
1565 cleanup = None
1566 if not other.local():
1566 if not other.local():
1567 # use the created uncompressed bundlerepo
1567 # use the created uncompressed bundlerepo
1568 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1568 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1569
1569
1570 revs = None
1570 revs = None
1571 if opts['rev']:
1571 if opts['rev']:
1572 revs = [other.lookup(rev) for rev in opts['rev']]
1572 revs = [other.lookup(rev) for rev in opts['rev']]
1573 o = other.changelog.nodesbetween(incoming, revs)[0]
1573 o = other.changelog.nodesbetween(incoming, revs)[0]
1574 if opts['newest_first']:
1574 if opts['newest_first']:
1575 o.reverse()
1575 o.reverse()
1576 displayer = cmdutil.show_changeset(ui, other, opts)
1576 displayer = cmdutil.show_changeset(ui, other, opts)
1577 for n in o:
1577 for n in o:
1578 parents = [p for p in other.changelog.parents(n) if p != nullid]
1578 parents = [p for p in other.changelog.parents(n) if p != nullid]
1579 if opts['no_merges'] and len(parents) == 2:
1579 if opts['no_merges'] and len(parents) == 2:
1580 continue
1580 continue
1581 displayer.show(changenode=n)
1581 displayer.show(changenode=n)
1582 finally:
1582 finally:
1583 if hasattr(other, 'close'):
1583 if hasattr(other, 'close'):
1584 other.close()
1584 other.close()
1585 if cleanup:
1585 if cleanup:
1586 os.unlink(cleanup)
1586 os.unlink(cleanup)
1587
1587
1588 def init(ui, dest=".", **opts):
1588 def init(ui, dest=".", **opts):
1589 """create a new repository in the given directory
1589 """create a new repository in the given directory
1590
1590
1591 Initialize a new repository in the given directory. If the given
1591 Initialize a new repository in the given directory. If the given
1592 directory does not exist, it is created.
1592 directory does not exist, it is created.
1593
1593
1594 If no directory is given, the current directory is used.
1594 If no directory is given, the current directory is used.
1595
1595
1596 It is possible to specify an ssh:// URL as the destination.
1596 It is possible to specify an ssh:// URL as the destination.
1597 Look at the help text for the pull command for important details
1597 Look at the help text for the pull command for important details
1598 about ssh:// URLs.
1598 about ssh:// URLs.
1599 """
1599 """
1600 setremoteconfig(ui, opts)
1600 setremoteconfig(ui, opts)
1601 hg.repository(ui, dest, create=1)
1601 hg.repository(ui, dest, create=1)
1602
1602
1603 def locate(ui, repo, *pats, **opts):
1603 def locate(ui, repo, *pats, **opts):
1604 """locate files matching specific patterns
1604 """locate files matching specific patterns
1605
1605
1606 Print all files under Mercurial control whose names match the
1606 Print all files under Mercurial control whose names match the
1607 given patterns.
1607 given patterns.
1608
1608
1609 This command searches the entire repository by default. To search
1609 This command searches the entire repository by default. To search
1610 just the current directory and its subdirectories, use "--include .".
1610 just the current directory and its subdirectories, use "--include .".
1611
1611
1612 If no patterns are given to match, this command prints all file
1612 If no patterns are given to match, this command prints all file
1613 names.
1613 names.
1614
1614
1615 If you want to feed the output of this command into the "xargs"
1615 If you want to feed the output of this command into the "xargs"
1616 command, use the "-0" option to both this command and "xargs".
1616 command, use the "-0" option to both this command and "xargs".
1617 This will avoid the problem of "xargs" treating single filenames
1617 This will avoid the problem of "xargs" treating single filenames
1618 that contain white space as multiple filenames.
1618 that contain white space as multiple filenames.
1619 """
1619 """
1620 end = opts['print0'] and '\0' or '\n'
1620 end = opts['print0'] and '\0' or '\n'
1621 rev = opts['rev']
1621 rev = opts['rev']
1622 if rev:
1622 if rev:
1623 node = repo.lookup(rev)
1623 node = repo.lookup(rev)
1624 else:
1624 else:
1625 node = None
1625 node = None
1626
1626
1627 ret = 1
1627 ret = 1
1628 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1628 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1629 default='relglob'):
1629 default='relglob'):
1630 if not node and repo.dirstate.state(abs) == '?':
1630 if not node and repo.dirstate.state(abs) == '?':
1631 continue
1631 continue
1632 if opts['fullpath']:
1632 if opts['fullpath']:
1633 ui.write(os.path.join(repo.root, abs), end)
1633 ui.write(os.path.join(repo.root, abs), end)
1634 else:
1634 else:
1635 ui.write(((pats and rel) or abs), end)
1635 ui.write(((pats and rel) or abs), end)
1636 ret = 0
1636 ret = 0
1637
1637
1638 return ret
1638 return ret
1639
1639
1640 def log(ui, repo, *pats, **opts):
1640 def log(ui, repo, *pats, **opts):
1641 """show revision history of entire repository or files
1641 """show revision history of entire repository or files
1642
1642
1643 Print the revision history of the specified files or the entire
1643 Print the revision history of the specified files or the entire
1644 project.
1644 project.
1645
1645
1646 File history is shown without following rename or copy history of
1646 File history is shown without following rename or copy history of
1647 files. Use -f/--follow with a file name to follow history across
1647 files. Use -f/--follow with a file name to follow history across
1648 renames and copies. --follow without a file name will only show
1648 renames and copies. --follow without a file name will only show
1649 ancestors or descendants of the starting revision. --follow-first
1649 ancestors or descendants of the starting revision. --follow-first
1650 only follows the first parent of merge revisions.
1650 only follows the first parent of merge revisions.
1651
1651
1652 If no revision range is specified, the default is tip:0 unless
1652 If no revision range is specified, the default is tip:0 unless
1653 --follow is set, in which case the working directory parent is
1653 --follow is set, in which case the working directory parent is
1654 used as the starting revision.
1654 used as the starting revision.
1655
1655
1656 By default this command outputs: changeset id and hash, tags,
1656 By default this command outputs: changeset id and hash, tags,
1657 non-trivial parents, user, date and time, and a summary for each
1657 non-trivial parents, user, date and time, and a summary for each
1658 commit. When the -v/--verbose switch is used, the list of changed
1658 commit. When the -v/--verbose switch is used, the list of changed
1659 files and full commit message is shown.
1659 files and full commit message is shown.
1660
1660
1661 NOTE: log -p may generate unexpected diff output for merge
1661 NOTE: log -p may generate unexpected diff output for merge
1662 changesets, as it will compare the merge changeset against its
1662 changesets, as it will compare the merge changeset against its
1663 first parent only. Also, the files: list will only reflect files
1663 first parent only. Also, the files: list will only reflect files
1664 that are different from BOTH parents.
1664 that are different from BOTH parents.
1665
1665
1666 """
1666 """
1667
1667
1668 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1668 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1669 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1669 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1670
1670
1671 if opts['limit']:
1671 if opts['limit']:
1672 try:
1672 try:
1673 limit = int(opts['limit'])
1673 limit = int(opts['limit'])
1674 except ValueError:
1674 except ValueError:
1675 raise util.Abort(_('limit must be a positive integer'))
1675 raise util.Abort(_('limit must be a positive integer'))
1676 if limit <= 0: raise util.Abort(_('limit must be positive'))
1676 if limit <= 0: raise util.Abort(_('limit must be positive'))
1677 else:
1677 else:
1678 limit = sys.maxint
1678 limit = sys.maxint
1679 count = 0
1679 count = 0
1680
1680
1681 if opts['copies'] and opts['rev']:
1681 if opts['copies'] and opts['rev']:
1682 endrev = max(cmdutil.revrange(repo, opts['rev'])) + 1
1682 endrev = max(cmdutil.revrange(repo, opts['rev'])) + 1
1683 else:
1683 else:
1684 endrev = repo.changelog.count()
1684 endrev = repo.changelog.count()
1685 rcache = {}
1685 rcache = {}
1686 ncache = {}
1686 ncache = {}
1687 dcache = []
1687 dcache = []
1688 def getrenamed(fn, rev, man):
1688 def getrenamed(fn, rev, man):
1689 '''looks up all renames for a file (up to endrev) the first
1689 '''looks up all renames for a file (up to endrev) the first
1690 time the file is given. It indexes on the changerev and only
1690 time the file is given. It indexes on the changerev and only
1691 parses the manifest if linkrev != changerev.
1691 parses the manifest if linkrev != changerev.
1692 Returns rename info for fn at changerev rev.'''
1692 Returns rename info for fn at changerev rev.'''
1693 if fn not in rcache:
1693 if fn not in rcache:
1694 rcache[fn] = {}
1694 rcache[fn] = {}
1695 ncache[fn] = {}
1695 ncache[fn] = {}
1696 fl = repo.file(fn)
1696 fl = repo.file(fn)
1697 for i in xrange(fl.count()):
1697 for i in xrange(fl.count()):
1698 node = fl.node(i)
1698 node = fl.node(i)
1699 lr = fl.linkrev(node)
1699 lr = fl.linkrev(node)
1700 renamed = fl.renamed(node)
1700 renamed = fl.renamed(node)
1701 rcache[fn][lr] = renamed
1701 rcache[fn][lr] = renamed
1702 if renamed:
1702 if renamed:
1703 ncache[fn][node] = renamed
1703 ncache[fn][node] = renamed
1704 if lr >= endrev:
1704 if lr >= endrev:
1705 break
1705 break
1706 if rev in rcache[fn]:
1706 if rev in rcache[fn]:
1707 return rcache[fn][rev]
1707 return rcache[fn][rev]
1708 mr = repo.manifest.rev(man)
1708 mr = repo.manifest.rev(man)
1709 if repo.manifest.parentrevs(mr) != (mr - 1, nullrev):
1709 if repo.manifest.parentrevs(mr) != (mr - 1, nullrev):
1710 return ncache[fn].get(repo.manifest.find(man, fn)[0])
1710 return ncache[fn].get(repo.manifest.find(man, fn)[0])
1711 if not dcache or dcache[0] != man:
1711 if not dcache or dcache[0] != man:
1712 dcache[:] = [man, repo.manifest.readdelta(man)]
1712 dcache[:] = [man, repo.manifest.readdelta(man)]
1713 if fn in dcache[1]:
1713 if fn in dcache[1]:
1714 return ncache[fn].get(dcache[1][fn])
1714 return ncache[fn].get(dcache[1][fn])
1715 return None
1715 return None
1716
1716
1717 df = False
1717 df = False
1718 if opts["date"]:
1718 if opts["date"]:
1719 df = util.matchdate(opts["date"])
1719 df = util.matchdate(opts["date"])
1720
1720
1721 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1721 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1722 for st, rev, fns in changeiter:
1722 for st, rev, fns in changeiter:
1723 if st == 'add':
1723 if st == 'add':
1724 changenode = repo.changelog.node(rev)
1724 changenode = repo.changelog.node(rev)
1725 parents = [p for p in repo.changelog.parentrevs(rev)
1725 parents = [p for p in repo.changelog.parentrevs(rev)
1726 if p != nullrev]
1726 if p != nullrev]
1727 if opts['no_merges'] and len(parents) == 2:
1727 if opts['no_merges'] and len(parents) == 2:
1728 continue
1728 continue
1729 if opts['only_merges'] and len(parents) != 2:
1729 if opts['only_merges'] and len(parents) != 2:
1730 continue
1730 continue
1731
1731
1732 if df:
1732 if df:
1733 changes = get(rev)
1733 changes = get(rev)
1734 if not df(changes[2][0]):
1734 if not df(changes[2][0]):
1735 continue
1735 continue
1736
1736
1737 if opts['keyword']:
1737 if opts['keyword']:
1738 changes = get(rev)
1738 changes = get(rev)
1739 miss = 0
1739 miss = 0
1740 for k in [kw.lower() for kw in opts['keyword']]:
1740 for k in [kw.lower() for kw in opts['keyword']]:
1741 if not (k in changes[1].lower() or
1741 if not (k in changes[1].lower() or
1742 k in changes[4].lower() or
1742 k in changes[4].lower() or
1743 k in " ".join(changes[3][:20]).lower()):
1743 k in " ".join(changes[3][:20]).lower()):
1744 miss = 1
1744 miss = 1
1745 break
1745 break
1746 if miss:
1746 if miss:
1747 continue
1747 continue
1748
1748
1749 copies = []
1749 copies = []
1750 if opts.get('copies') and rev:
1750 if opts.get('copies') and rev:
1751 mf = get(rev)[0]
1751 mf = get(rev)[0]
1752 for fn in get(rev)[3]:
1752 for fn in get(rev)[3]:
1753 rename = getrenamed(fn, rev, mf)
1753 rename = getrenamed(fn, rev, mf)
1754 if rename:
1754 if rename:
1755 copies.append((fn, rename[0]))
1755 copies.append((fn, rename[0]))
1756 displayer.show(rev, changenode, copies=copies)
1756 displayer.show(rev, changenode, copies=copies)
1757 elif st == 'iter':
1757 elif st == 'iter':
1758 if count == limit: break
1758 if count == limit: break
1759 if displayer.flush(rev):
1759 if displayer.flush(rev):
1760 count += 1
1760 count += 1
1761
1761
1762 def manifest(ui, repo, rev=None):
1762 def manifest(ui, repo, rev=None):
1763 """output the current or given revision of the project manifest
1763 """output the current or given revision of the project manifest
1764
1764
1765 Print a list of version controlled files for the given revision.
1765 Print a list of version controlled files for the given revision.
1766 If no revision is given, the parent of the working directory is used,
1766 If no revision is given, the parent of the working directory is used,
1767 or tip if no revision is checked out.
1767 or tip if no revision is checked out.
1768
1768
1769 The manifest is the list of files being version controlled. If no revision
1769 The manifest is the list of files being version controlled. If no revision
1770 is given then the first parent of the working directory is used.
1770 is given then the first parent of the working directory is used.
1771
1771
1772 With -v flag, print file permissions. With --debug flag, print
1772 With -v flag, print file permissions. With --debug flag, print
1773 file revision hashes.
1773 file revision hashes.
1774 """
1774 """
1775
1775
1776 m = repo.changectx(rev).manifest()
1776 m = repo.changectx(rev).manifest()
1777 files = m.keys()
1777 files = m.keys()
1778 files.sort()
1778 files.sort()
1779
1779
1780 for f in files:
1780 for f in files:
1781 if ui.debugflag:
1781 if ui.debugflag:
1782 ui.write("%40s " % hex(m[f]))
1782 ui.write("%40s " % hex(m[f]))
1783 if ui.verbose:
1783 if ui.verbose:
1784 ui.write("%3s " % (m.execf(f) and "755" or "644"))
1784 ui.write("%3s " % (m.execf(f) and "755" or "644"))
1785 ui.write("%s\n" % f)
1785 ui.write("%s\n" % f)
1786
1786
1787 def merge(ui, repo, node=None, force=None):
1787 def merge(ui, repo, node=None, force=None):
1788 """merge working directory with another revision
1788 """merge working directory with another revision
1789
1789
1790 Merge the contents of the current working directory and the
1790 Merge the contents of the current working directory and the
1791 requested revision. Files that changed between either parent are
1791 requested revision. Files that changed between either parent are
1792 marked as changed for the next commit and a commit must be
1792 marked as changed for the next commit and a commit must be
1793 performed before any further updates are allowed.
1793 performed before any further updates are allowed.
1794
1794
1795 If no revision is specified, the working directory's parent is a
1795 If no revision is specified, the working directory's parent is a
1796 head revision, and the repository contains exactly one other head,
1796 head revision, and the repository contains exactly one other head,
1797 the other head is merged with by default. Otherwise, an explicit
1797 the other head is merged with by default. Otherwise, an explicit
1798 revision to merge with must be provided.
1798 revision to merge with must be provided.
1799 """
1799 """
1800
1800
1801 if not node:
1801 if not node:
1802 heads = repo.heads()
1802 heads = repo.heads()
1803 if len(heads) > 2:
1803 if len(heads) > 2:
1804 raise util.Abort(_('repo has %d heads - '
1804 raise util.Abort(_('repo has %d heads - '
1805 'please merge with an explicit rev') %
1805 'please merge with an explicit rev') %
1806 len(heads))
1806 len(heads))
1807 if len(heads) == 1:
1807 if len(heads) == 1:
1808 raise util.Abort(_('there is nothing to merge - '
1808 raise util.Abort(_('there is nothing to merge - '
1809 'use "hg update" instead'))
1809 'use "hg update" instead'))
1810 parent = repo.dirstate.parents()[0]
1810 parent = repo.dirstate.parents()[0]
1811 if parent not in heads:
1811 if parent not in heads:
1812 raise util.Abort(_('working dir not at a head rev - '
1812 raise util.Abort(_('working dir not at a head rev - '
1813 'use "hg update" or merge with an explicit rev'))
1813 'use "hg update" or merge with an explicit rev'))
1814 node = parent == heads[0] and heads[-1] or heads[0]
1814 node = parent == heads[0] and heads[-1] or heads[0]
1815 return hg.merge(repo, node, force=force)
1815 return hg.merge(repo, node, force=force)
1816
1816
1817 def outgoing(ui, repo, dest=None, **opts):
1817 def outgoing(ui, repo, dest=None, **opts):
1818 """show changesets not found in destination
1818 """show changesets not found in destination
1819
1819
1820 Show changesets not found in the specified destination repository or
1820 Show changesets not found in the specified destination repository or
1821 the default push location. These are the changesets that would be pushed
1821 the default push location. These are the changesets that would be pushed
1822 if a push was requested.
1822 if a push was requested.
1823
1823
1824 See pull for valid destination format details.
1824 See pull for valid destination format details.
1825 """
1825 """
1826 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1826 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1827 setremoteconfig(ui, opts)
1827 setremoteconfig(ui, opts)
1828 revs = None
1828 revs = None
1829 if opts['rev']:
1829 if opts['rev']:
1830 revs = [repo.lookup(rev) for rev in opts['rev']]
1830 revs = [repo.lookup(rev) for rev in opts['rev']]
1831
1831
1832 other = hg.repository(ui, dest)
1832 other = hg.repository(ui, dest)
1833 ui.status(_('comparing with %s\n') % dest)
1833 ui.status(_('comparing with %s\n') % dest)
1834 o = repo.findoutgoing(other, force=opts['force'])
1834 o = repo.findoutgoing(other, force=opts['force'])
1835 if not o:
1835 if not o:
1836 ui.status(_("no changes found\n"))
1836 ui.status(_("no changes found\n"))
1837 return 1
1837 return 1
1838 o = repo.changelog.nodesbetween(o, revs)[0]
1838 o = repo.changelog.nodesbetween(o, revs)[0]
1839 if opts['newest_first']:
1839 if opts['newest_first']:
1840 o.reverse()
1840 o.reverse()
1841 displayer = cmdutil.show_changeset(ui, repo, opts)
1841 displayer = cmdutil.show_changeset(ui, repo, opts)
1842 for n in o:
1842 for n in o:
1843 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1843 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1844 if opts['no_merges'] and len(parents) == 2:
1844 if opts['no_merges'] and len(parents) == 2:
1845 continue
1845 continue
1846 displayer.show(changenode=n)
1846 displayer.show(changenode=n)
1847
1847
1848 def parents(ui, repo, file_=None, **opts):
1848 def parents(ui, repo, file_=None, **opts):
1849 """show the parents of the working dir or revision
1849 """show the parents of the working dir or revision
1850
1850
1851 Print the working directory's parent revisions.
1851 Print the working directory's parent revisions.
1852 """
1852 """
1853 rev = opts.get('rev')
1853 rev = opts.get('rev')
1854 if rev:
1854 if rev:
1855 if file_:
1855 if file_:
1856 ctx = repo.filectx(file_, changeid=rev)
1856 ctx = repo.filectx(file_, changeid=rev)
1857 else:
1857 else:
1858 ctx = repo.changectx(rev)
1858 ctx = repo.changectx(rev)
1859 p = [cp.node() for cp in ctx.parents()]
1859 p = [cp.node() for cp in ctx.parents()]
1860 else:
1860 else:
1861 p = repo.dirstate.parents()
1861 p = repo.dirstate.parents()
1862
1862
1863 displayer = cmdutil.show_changeset(ui, repo, opts)
1863 displayer = cmdutil.show_changeset(ui, repo, opts)
1864 for n in p:
1864 for n in p:
1865 if n != nullid:
1865 if n != nullid:
1866 displayer.show(changenode=n)
1866 displayer.show(changenode=n)
1867
1867
1868 def paths(ui, repo, search=None):
1868 def paths(ui, repo, search=None):
1869 """show definition of symbolic path names
1869 """show definition of symbolic path names
1870
1870
1871 Show definition of symbolic path name NAME. If no name is given, show
1871 Show definition of symbolic path name NAME. If no name is given, show
1872 definition of available names.
1872 definition of available names.
1873
1873
1874 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1874 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1875 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1875 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1876 """
1876 """
1877 if search:
1877 if search:
1878 for name, path in ui.configitems("paths"):
1878 for name, path in ui.configitems("paths"):
1879 if name == search:
1879 if name == search:
1880 ui.write("%s\n" % path)
1880 ui.write("%s\n" % path)
1881 return
1881 return
1882 ui.warn(_("not found!\n"))
1882 ui.warn(_("not found!\n"))
1883 return 1
1883 return 1
1884 else:
1884 else:
1885 for name, path in ui.configitems("paths"):
1885 for name, path in ui.configitems("paths"):
1886 ui.write("%s = %s\n" % (name, path))
1886 ui.write("%s = %s\n" % (name, path))
1887
1887
1888 def postincoming(ui, repo, modheads, optupdate):
1888 def postincoming(ui, repo, modheads, optupdate):
1889 if modheads == 0:
1889 if modheads == 0:
1890 return
1890 return
1891 if optupdate:
1891 if optupdate:
1892 if modheads == 1:
1892 if modheads == 1:
1893 return hg.update(repo, repo.changelog.tip()) # update
1893 return hg.update(repo, repo.changelog.tip()) # update
1894 else:
1894 else:
1895 ui.status(_("not updating, since new heads added\n"))
1895 ui.status(_("not updating, since new heads added\n"))
1896 if modheads > 1:
1896 if modheads > 1:
1897 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
1897 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
1898 else:
1898 else:
1899 ui.status(_("(run 'hg update' to get a working copy)\n"))
1899 ui.status(_("(run 'hg update' to get a working copy)\n"))
1900
1900
1901 def pull(ui, repo, source="default", **opts):
1901 def pull(ui, repo, source="default", **opts):
1902 """pull changes from the specified source
1902 """pull changes from the specified source
1903
1903
1904 Pull changes from a remote repository to a local one.
1904 Pull changes from a remote repository to a local one.
1905
1905
1906 This finds all changes from the repository at the specified path
1906 This finds all changes from the repository at the specified path
1907 or URL and adds them to the local repository. By default, this
1907 or URL and adds them to the local repository. By default, this
1908 does not update the copy of the project in the working directory.
1908 does not update the copy of the project in the working directory.
1909
1909
1910 Valid URLs are of the form:
1910 Valid URLs are of the form:
1911
1911
1912 local/filesystem/path (or file://local/filesystem/path)
1912 local/filesystem/path (or file://local/filesystem/path)
1913 http://[user@]host[:port]/[path]
1913 http://[user@]host[:port]/[path]
1914 https://[user@]host[:port]/[path]
1914 https://[user@]host[:port]/[path]
1915 ssh://[user@]host[:port]/[path]
1915 ssh://[user@]host[:port]/[path]
1916 static-http://host[:port]/[path]
1916 static-http://host[:port]/[path]
1917
1917
1918 Paths in the local filesystem can either point to Mercurial
1918 Paths in the local filesystem can either point to Mercurial
1919 repositories or to bundle files (as created by 'hg bundle' or
1919 repositories or to bundle files (as created by 'hg bundle' or
1920 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
1920 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
1921 allows access to a Mercurial repository where you simply use a web
1921 allows access to a Mercurial repository where you simply use a web
1922 server to publish the .hg directory as static content.
1922 server to publish the .hg directory as static content.
1923
1923
1924 Some notes about using SSH with Mercurial:
1924 Some notes about using SSH with Mercurial:
1925 - SSH requires an accessible shell account on the destination machine
1925 - SSH requires an accessible shell account on the destination machine
1926 and a copy of hg in the remote path or specified with as remotecmd.
1926 and a copy of hg in the remote path or specified with as remotecmd.
1927 - path is relative to the remote user's home directory by default.
1927 - path is relative to the remote user's home directory by default.
1928 Use an extra slash at the start of a path to specify an absolute path:
1928 Use an extra slash at the start of a path to specify an absolute path:
1929 ssh://example.com//tmp/repository
1929 ssh://example.com//tmp/repository
1930 - Mercurial doesn't use its own compression via SSH; the right thing
1930 - Mercurial doesn't use its own compression via SSH; the right thing
1931 to do is to configure it in your ~/.ssh/config, e.g.:
1931 to do is to configure it in your ~/.ssh/config, e.g.:
1932 Host *.mylocalnetwork.example.com
1932 Host *.mylocalnetwork.example.com
1933 Compression no
1933 Compression no
1934 Host *
1934 Host *
1935 Compression yes
1935 Compression yes
1936 Alternatively specify "ssh -C" as your ssh command in your hgrc or
1936 Alternatively specify "ssh -C" as your ssh command in your hgrc or
1937 with the --ssh command line option.
1937 with the --ssh command line option.
1938 """
1938 """
1939 source = ui.expandpath(source)
1939 source = ui.expandpath(source)
1940 setremoteconfig(ui, opts)
1940 setremoteconfig(ui, opts)
1941
1941
1942 other = hg.repository(ui, source)
1942 other = hg.repository(ui, source)
1943 ui.status(_('pulling from %s\n') % (source))
1943 ui.status(_('pulling from %s\n') % (source))
1944 revs = None
1944 revs = None
1945 if opts['rev']:
1945 if opts['rev']:
1946 if 'lookup' in other.capabilities:
1946 if 'lookup' in other.capabilities:
1947 revs = [other.lookup(rev) for rev in opts['rev']]
1947 revs = [other.lookup(rev) for rev in opts['rev']]
1948 else:
1948 else:
1949 error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
1949 error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
1950 raise util.Abort(error)
1950 raise util.Abort(error)
1951 modheads = repo.pull(other, heads=revs, force=opts['force'])
1951 modheads = repo.pull(other, heads=revs, force=opts['force'])
1952 return postincoming(ui, repo, modheads, opts['update'])
1952 return postincoming(ui, repo, modheads, opts['update'])
1953
1953
1954 def push(ui, repo, dest=None, **opts):
1954 def push(ui, repo, dest=None, **opts):
1955 """push changes to the specified destination
1955 """push changes to the specified destination
1956
1956
1957 Push changes from the local repository to the given destination.
1957 Push changes from the local repository to the given destination.
1958
1958
1959 This is the symmetrical operation for pull. It helps to move
1959 This is the symmetrical operation for pull. It helps to move
1960 changes from the current repository to a different one. If the
1960 changes from the current repository to a different one. If the
1961 destination is local this is identical to a pull in that directory
1961 destination is local this is identical to a pull in that directory
1962 from the current one.
1962 from the current one.
1963
1963
1964 By default, push will refuse to run if it detects the result would
1964 By default, push will refuse to run if it detects the result would
1965 increase the number of remote heads. This generally indicates the
1965 increase the number of remote heads. This generally indicates the
1966 the client has forgotten to sync and merge before pushing.
1966 the client has forgotten to sync and merge before pushing.
1967
1967
1968 Valid URLs are of the form:
1968 Valid URLs are of the form:
1969
1969
1970 local/filesystem/path (or file://local/filesystem/path)
1970 local/filesystem/path (or file://local/filesystem/path)
1971 ssh://[user@]host[:port]/[path]
1971 ssh://[user@]host[:port]/[path]
1972 http://[user@]host[:port]/[path]
1972 http://[user@]host[:port]/[path]
1973 https://[user@]host[:port]/[path]
1973 https://[user@]host[:port]/[path]
1974
1974
1975 Look at the help text for the pull command for important details
1975 Look at the help text for the pull command for important details
1976 about ssh:// URLs.
1976 about ssh:// URLs.
1977
1977
1978 Pushing to http:// and https:// URLs is only possible, if this
1978 Pushing to http:// and https:// URLs is only possible, if this
1979 feature is explicitly enabled on the remote Mercurial server.
1979 feature is explicitly enabled on the remote Mercurial server.
1980 """
1980 """
1981 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1981 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1982 setremoteconfig(ui, opts)
1982 setremoteconfig(ui, opts)
1983
1983
1984 other = hg.repository(ui, dest)
1984 other = hg.repository(ui, dest)
1985 ui.status('pushing to %s\n' % (dest))
1985 ui.status('pushing to %s\n' % (dest))
1986 revs = None
1986 revs = None
1987 if opts['rev']:
1987 if opts['rev']:
1988 revs = [repo.lookup(rev) for rev in opts['rev']]
1988 revs = [repo.lookup(rev) for rev in opts['rev']]
1989 r = repo.push(other, opts['force'], revs=revs)
1989 r = repo.push(other, opts['force'], revs=revs)
1990 return r == 0
1990 return r == 0
1991
1991
1992 def rawcommit(ui, repo, *pats, **opts):
1992 def rawcommit(ui, repo, *pats, **opts):
1993 """raw commit interface (DEPRECATED)
1993 """raw commit interface (DEPRECATED)
1994
1994
1995 (DEPRECATED)
1995 (DEPRECATED)
1996 Lowlevel commit, for use in helper scripts.
1996 Lowlevel commit, for use in helper scripts.
1997
1997
1998 This command is not intended to be used by normal users, as it is
1998 This command is not intended to be used by normal users, as it is
1999 primarily useful for importing from other SCMs.
1999 primarily useful for importing from other SCMs.
2000
2000
2001 This command is now deprecated and will be removed in a future
2001 This command is now deprecated and will be removed in a future
2002 release, please use debugsetparents and commit instead.
2002 release, please use debugsetparents and commit instead.
2003 """
2003 """
2004
2004
2005 ui.warn(_("(the rawcommit command is deprecated)\n"))
2005 ui.warn(_("(the rawcommit command is deprecated)\n"))
2006
2006
2007 message = logmessage(opts)
2007 message = logmessage(opts)
2008
2008
2009 files, match, anypats = cmdutil.matchpats(repo, pats, opts)
2009 files, match, anypats = cmdutil.matchpats(repo, pats, opts)
2010 if opts['files']:
2010 if opts['files']:
2011 files += open(opts['files']).read().splitlines()
2011 files += open(opts['files']).read().splitlines()
2012
2012
2013 parents = [repo.lookup(p) for p in opts['parent']]
2013 parents = [repo.lookup(p) for p in opts['parent']]
2014
2014
2015 try:
2015 try:
2016 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2016 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2017 except ValueError, inst:
2017 except ValueError, inst:
2018 raise util.Abort(str(inst))
2018 raise util.Abort(str(inst))
2019
2019
2020 def recover(ui, repo):
2020 def recover(ui, repo):
2021 """roll back an interrupted transaction
2021 """roll back an interrupted transaction
2022
2022
2023 Recover from an interrupted commit or pull.
2023 Recover from an interrupted commit or pull.
2024
2024
2025 This command tries to fix the repository status after an interrupted
2025 This command tries to fix the repository status after an interrupted
2026 operation. It should only be necessary when Mercurial suggests it.
2026 operation. It should only be necessary when Mercurial suggests it.
2027 """
2027 """
2028 if repo.recover():
2028 if repo.recover():
2029 return hg.verify(repo)
2029 return hg.verify(repo)
2030 return 1
2030 return 1
2031
2031
2032 def remove(ui, repo, *pats, **opts):
2032 def remove(ui, repo, *pats, **opts):
2033 """remove the specified files on the next commit
2033 """remove the specified files on the next commit
2034
2034
2035 Schedule the indicated files for removal from the repository.
2035 Schedule the indicated files for removal from the repository.
2036
2036
2037 This only removes files from the current branch, not from the
2037 This only removes files from the current branch, not from the
2038 entire project history. If the files still exist in the working
2038 entire project history. If the files still exist in the working
2039 directory, they will be deleted from it. If invoked with --after,
2039 directory, they will be deleted from it. If invoked with --after,
2040 files that have been manually deleted are marked as removed.
2040 files that have been manually deleted are marked as removed.
2041
2041
2042 This command schedules the files to be removed at the next commit.
2042 This command schedules the files to be removed at the next commit.
2043 To undo a remove before that, see hg revert.
2043 To undo a remove before that, see hg revert.
2044
2044
2045 Modified files and added files are not removed by default. To
2045 Modified files and added files are not removed by default. To
2046 remove them, use the -f/--force option.
2046 remove them, use the -f/--force option.
2047 """
2047 """
2048 names = []
2048 names = []
2049 if not opts['after'] and not pats:
2049 if not opts['after'] and not pats:
2050 raise util.Abort(_('no files specified'))
2050 raise util.Abort(_('no files specified'))
2051 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2051 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2052 exact = dict.fromkeys(files)
2052 exact = dict.fromkeys(files)
2053 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2053 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2054 modified, added, removed, deleted, unknown = mardu
2054 modified, added, removed, deleted, unknown = mardu
2055 remove, forget = [], []
2055 remove, forget = [], []
2056 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2056 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2057 reason = None
2057 reason = None
2058 if abs not in deleted and opts['after']:
2058 if abs not in deleted and opts['after']:
2059 reason = _('is still present')
2059 reason = _('is still present')
2060 elif abs in modified and not opts['force']:
2060 elif abs in modified and not opts['force']:
2061 reason = _('is modified (use -f to force removal)')
2061 reason = _('is modified (use -f to force removal)')
2062 elif abs in added:
2062 elif abs in added:
2063 if opts['force']:
2063 if opts['force']:
2064 forget.append(abs)
2064 forget.append(abs)
2065 continue
2065 continue
2066 reason = _('has been marked for add (use -f to force removal)')
2066 reason = _('has been marked for add (use -f to force removal)')
2067 elif abs in unknown:
2067 elif abs in unknown:
2068 reason = _('is not managed')
2068 reason = _('is not managed')
2069 elif abs in removed:
2069 elif abs in removed:
2070 continue
2070 continue
2071 if reason:
2071 if reason:
2072 if exact:
2072 if exact:
2073 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2073 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2074 else:
2074 else:
2075 if ui.verbose or not exact:
2075 if ui.verbose or not exact:
2076 ui.status(_('removing %s\n') % rel)
2076 ui.status(_('removing %s\n') % rel)
2077 remove.append(abs)
2077 remove.append(abs)
2078 repo.forget(forget)
2078 repo.forget(forget)
2079 repo.remove(remove, unlink=not opts['after'])
2079 repo.remove(remove, unlink=not opts['after'])
2080
2080
2081 def rename(ui, repo, *pats, **opts):
2081 def rename(ui, repo, *pats, **opts):
2082 """rename files; equivalent of copy + remove
2082 """rename files; equivalent of copy + remove
2083
2083
2084 Mark dest as copies of sources; mark sources for deletion. If
2084 Mark dest as copies of sources; mark sources for deletion. If
2085 dest is a directory, copies are put in that directory. If dest is
2085 dest is a directory, copies are put in that directory. If dest is
2086 a file, there can only be one source.
2086 a file, there can only be one source.
2087
2087
2088 By default, this command copies the contents of files as they
2088 By default, this command copies the contents of files as they
2089 stand in the working directory. If invoked with --after, the
2089 stand in the working directory. If invoked with --after, the
2090 operation is recorded, but no copying is performed.
2090 operation is recorded, but no copying is performed.
2091
2091
2092 This command takes effect in the next commit. To undo a rename
2092 This command takes effect in the next commit. To undo a rename
2093 before that, see hg revert.
2093 before that, see hg revert.
2094 """
2094 """
2095 wlock = repo.wlock(0)
2095 wlock = repo.wlock(0)
2096 errs, copied = docopy(ui, repo, pats, opts, wlock)
2096 errs, copied = docopy(ui, repo, pats, opts, wlock)
2097 names = []
2097 names = []
2098 for abs, rel, exact in copied:
2098 for abs, rel, exact in copied:
2099 if ui.verbose or not exact:
2099 if ui.verbose or not exact:
2100 ui.status(_('removing %s\n') % rel)
2100 ui.status(_('removing %s\n') % rel)
2101 names.append(abs)
2101 names.append(abs)
2102 if not opts.get('dry_run'):
2102 if not opts.get('dry_run'):
2103 repo.remove(names, True, wlock)
2103 repo.remove(names, True, wlock)
2104 return errs
2104 return errs
2105
2105
2106 def revert(ui, repo, *pats, **opts):
2106 def revert(ui, repo, *pats, **opts):
2107 """revert files or dirs to their states as of some revision
2107 """revert files or dirs to their states as of some revision
2108
2108
2109 With no revision specified, revert the named files or directories
2109 With no revision specified, revert the named files or directories
2110 to the contents they had in the parent of the working directory.
2110 to the contents they had in the parent of the working directory.
2111 This restores the contents of the affected files to an unmodified
2111 This restores the contents of the affected files to an unmodified
2112 state and unschedules adds, removes, copies, and renames. If the
2112 state and unschedules adds, removes, copies, and renames. If the
2113 working directory has two parents, you must explicitly specify the
2113 working directory has two parents, you must explicitly specify the
2114 revision to revert to.
2114 revision to revert to.
2115
2115
2116 Modified files are saved with a .orig suffix before reverting.
2116 Modified files are saved with a .orig suffix before reverting.
2117 To disable these backups, use --no-backup.
2117 To disable these backups, use --no-backup.
2118
2118
2119 Using the -r option, revert the given files or directories to their
2119 Using the -r option, revert the given files or directories to their
2120 contents as of a specific revision. This can be helpful to "roll
2120 contents as of a specific revision. This can be helpful to "roll
2121 back" some or all of a change that should not have been committed.
2121 back" some or all of a change that should not have been committed.
2122
2122
2123 Revert modifies the working directory. It does not commit any
2123 Revert modifies the working directory. It does not commit any
2124 changes, or change the parent of the working directory. If you
2124 changes, or change the parent of the working directory. If you
2125 revert to a revision other than the parent of the working
2125 revert to a revision other than the parent of the working
2126 directory, the reverted files will thus appear modified
2126 directory, the reverted files will thus appear modified
2127 afterwards.
2127 afterwards.
2128
2128
2129 If a file has been deleted, it is recreated. If the executable
2129 If a file has been deleted, it is recreated. If the executable
2130 mode of a file was changed, it is reset.
2130 mode of a file was changed, it is reset.
2131
2131
2132 If names are given, all files matching the names are reverted.
2132 If names are given, all files matching the names are reverted.
2133
2133
2134 If no arguments are given, no files are reverted.
2134 If no arguments are given, no files are reverted.
2135 """
2135 """
2136
2136
2137 if opts["date"]:
2137 if opts["date"]:
2138 if opts["rev"]:
2138 if opts["rev"]:
2139 raise util.Abort(_("you can't specify a revision and a date"))
2139 raise util.Abort(_("you can't specify a revision and a date"))
2140 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2140 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2141
2141
2142 if not pats and not opts['all']:
2142 if not pats and not opts['all']:
2143 raise util.Abort(_('no files or directories specified; '
2143 raise util.Abort(_('no files or directories specified; '
2144 'use --all to revert the whole repo'))
2144 'use --all to revert the whole repo'))
2145
2145
2146 parent, p2 = repo.dirstate.parents()
2146 parent, p2 = repo.dirstate.parents()
2147 if not opts['rev'] and p2 != nullid:
2147 if not opts['rev'] and p2 != nullid:
2148 raise util.Abort(_('uncommitted merge - please provide a '
2148 raise util.Abort(_('uncommitted merge - please provide a '
2149 'specific revision'))
2149 'specific revision'))
2150 ctx = repo.changectx(opts['rev'])
2150 ctx = repo.changectx(opts['rev'])
2151 node = ctx.node()
2151 node = ctx.node()
2152 mf = ctx.manifest()
2152 mf = ctx.manifest()
2153 if node == parent:
2153 if node == parent:
2154 pmf = mf
2154 pmf = mf
2155 else:
2155 else:
2156 pmf = None
2156 pmf = None
2157
2157
2158 wlock = repo.wlock()
2158 wlock = repo.wlock()
2159
2159
2160 # need all matching names in dirstate and manifest of target rev,
2160 # need all matching names in dirstate and manifest of target rev,
2161 # so have to walk both. do not print errors if files exist in one
2161 # so have to walk both. do not print errors if files exist in one
2162 # but not other.
2162 # but not other.
2163
2163
2164 names = {}
2164 names = {}
2165 target_only = {}
2165 target_only = {}
2166
2166
2167 # walk dirstate.
2167 # walk dirstate.
2168
2168
2169 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2169 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2170 badmatch=mf.has_key):
2170 badmatch=mf.has_key):
2171 names[abs] = (rel, exact)
2171 names[abs] = (rel, exact)
2172 if src == 'b':
2172 if src == 'b':
2173 target_only[abs] = True
2173 target_only[abs] = True
2174
2174
2175 # walk target manifest.
2175 # walk target manifest.
2176
2176
2177 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2177 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2178 badmatch=names.has_key):
2178 badmatch=names.has_key):
2179 if abs in names: continue
2179 if abs in names: continue
2180 names[abs] = (rel, exact)
2180 names[abs] = (rel, exact)
2181 target_only[abs] = True
2181 target_only[abs] = True
2182
2182
2183 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2183 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2184 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2184 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2185
2185
2186 revert = ([], _('reverting %s\n'))
2186 revert = ([], _('reverting %s\n'))
2187 add = ([], _('adding %s\n'))
2187 add = ([], _('adding %s\n'))
2188 remove = ([], _('removing %s\n'))
2188 remove = ([], _('removing %s\n'))
2189 forget = ([], _('forgetting %s\n'))
2189 forget = ([], _('forgetting %s\n'))
2190 undelete = ([], _('undeleting %s\n'))
2190 undelete = ([], _('undeleting %s\n'))
2191 update = {}
2191 update = {}
2192
2192
2193 disptable = (
2193 disptable = (
2194 # dispatch table:
2194 # dispatch table:
2195 # file state
2195 # file state
2196 # action if in target manifest
2196 # action if in target manifest
2197 # action if not in target manifest
2197 # action if not in target manifest
2198 # make backup if in target manifest
2198 # make backup if in target manifest
2199 # make backup if not in target manifest
2199 # make backup if not in target manifest
2200 (modified, revert, remove, True, True),
2200 (modified, revert, remove, True, True),
2201 (added, revert, forget, True, False),
2201 (added, revert, forget, True, False),
2202 (removed, undelete, None, False, False),
2202 (removed, undelete, None, False, False),
2203 (deleted, revert, remove, False, False),
2203 (deleted, revert, remove, False, False),
2204 (unknown, add, None, True, False),
2204 (unknown, add, None, True, False),
2205 (target_only, add, None, False, False),
2205 (target_only, add, None, False, False),
2206 )
2206 )
2207
2207
2208 entries = names.items()
2208 entries = names.items()
2209 entries.sort()
2209 entries.sort()
2210
2210
2211 for abs, (rel, exact) in entries:
2211 for abs, (rel, exact) in entries:
2212 mfentry = mf.get(abs)
2212 mfentry = mf.get(abs)
2213 def handle(xlist, dobackup):
2213 def handle(xlist, dobackup):
2214 xlist[0].append(abs)
2214 xlist[0].append(abs)
2215 update[abs] = 1
2215 update[abs] = 1
2216 if dobackup and not opts['no_backup'] and os.path.exists(rel):
2216 if dobackup and not opts['no_backup'] and os.path.exists(rel):
2217 bakname = "%s.orig" % rel
2217 bakname = "%s.orig" % rel
2218 ui.note(_('saving current version of %s as %s\n') %
2218 ui.note(_('saving current version of %s as %s\n') %
2219 (rel, bakname))
2219 (rel, bakname))
2220 if not opts.get('dry_run'):
2220 if not opts.get('dry_run'):
2221 util.copyfile(rel, bakname)
2221 util.copyfile(rel, bakname)
2222 if ui.verbose or not exact:
2222 if ui.verbose or not exact:
2223 ui.status(xlist[1] % rel)
2223 ui.status(xlist[1] % rel)
2224 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2224 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2225 if abs not in table: continue
2225 if abs not in table: continue
2226 # file has changed in dirstate
2226 # file has changed in dirstate
2227 if mfentry:
2227 if mfentry:
2228 handle(hitlist, backuphit)
2228 handle(hitlist, backuphit)
2229 elif misslist is not None:
2229 elif misslist is not None:
2230 handle(misslist, backupmiss)
2230 handle(misslist, backupmiss)
2231 else:
2231 else:
2232 if exact: ui.warn(_('file not managed: %s\n') % rel)
2232 if exact: ui.warn(_('file not managed: %s\n') % rel)
2233 break
2233 break
2234 else:
2234 else:
2235 # file has not changed in dirstate
2235 # file has not changed in dirstate
2236 if node == parent:
2236 if node == parent:
2237 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2237 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2238 continue
2238 continue
2239 if pmf is None:
2239 if pmf is None:
2240 # only need parent manifest in this unlikely case,
2240 # only need parent manifest in this unlikely case,
2241 # so do not read by default
2241 # so do not read by default
2242 pmf = repo.changectx(parent).manifest()
2242 pmf = repo.changectx(parent).manifest()
2243 if abs in pmf:
2243 if abs in pmf:
2244 if mfentry:
2244 if mfentry:
2245 # if version of file is same in parent and target
2245 # if version of file is same in parent and target
2246 # manifests, do nothing
2246 # manifests, do nothing
2247 if pmf[abs] != mfentry:
2247 if pmf[abs] != mfentry:
2248 handle(revert, False)
2248 handle(revert, False)
2249 else:
2249 else:
2250 handle(remove, False)
2250 handle(remove, False)
2251
2251
2252 if not opts.get('dry_run'):
2252 if not opts.get('dry_run'):
2253 repo.dirstate.forget(forget[0])
2253 repo.dirstate.forget(forget[0])
2254 r = hg.revert(repo, node, update.has_key, wlock)
2254 r = hg.revert(repo, node, update.has_key, wlock)
2255 repo.dirstate.update(add[0], 'a')
2255 repo.dirstate.update(add[0], 'a')
2256 repo.dirstate.update(undelete[0], 'n')
2256 repo.dirstate.update(undelete[0], 'n')
2257 repo.dirstate.update(remove[0], 'r')
2257 repo.dirstate.update(remove[0], 'r')
2258 return r
2258 return r
2259
2259
2260 def rollback(ui, repo):
2260 def rollback(ui, repo):
2261 """roll back the last transaction in this repository
2261 """roll back the last transaction in this repository
2262
2262
2263 Roll back the last transaction in this repository, restoring the
2263 Roll back the last transaction in this repository, restoring the
2264 project to its state prior to the transaction.
2264 project to its state prior to the transaction.
2265
2265
2266 Transactions are used to encapsulate the effects of all commands
2266 Transactions are used to encapsulate the effects of all commands
2267 that create new changesets or propagate existing changesets into a
2267 that create new changesets or propagate existing changesets into a
2268 repository. For example, the following commands are transactional,
2268 repository. For example, the following commands are transactional,
2269 and their effects can be rolled back:
2269 and their effects can be rolled back:
2270
2270
2271 commit
2271 commit
2272 import
2272 import
2273 pull
2273 pull
2274 push (with this repository as destination)
2274 push (with this repository as destination)
2275 unbundle
2275 unbundle
2276
2276
2277 This command should be used with care. There is only one level of
2277 This command should be used with care. There is only one level of
2278 rollback, and there is no way to undo a rollback.
2278 rollback, and there is no way to undo a rollback.
2279
2279
2280 This command is not intended for use on public repositories. Once
2280 This command is not intended for use on public repositories. Once
2281 changes are visible for pull by other users, rolling a transaction
2281 changes are visible for pull by other users, rolling a transaction
2282 back locally is ineffective (someone else may already have pulled
2282 back locally is ineffective (someone else may already have pulled
2283 the changes). Furthermore, a race is possible with readers of the
2283 the changes). Furthermore, a race is possible with readers of the
2284 repository; for example an in-progress pull from the repository
2284 repository; for example an in-progress pull from the repository
2285 may fail if a rollback is performed.
2285 may fail if a rollback is performed.
2286 """
2286 """
2287 repo.rollback()
2287 repo.rollback()
2288
2288
2289 def root(ui, repo):
2289 def root(ui, repo):
2290 """print the root (top) of the current working dir
2290 """print the root (top) of the current working dir
2291
2291
2292 Print the root directory of the current repository.
2292 Print the root directory of the current repository.
2293 """
2293 """
2294 ui.write(repo.root + "\n")
2294 ui.write(repo.root + "\n")
2295
2295
2296 def serve(ui, repo, **opts):
2296 def serve(ui, repo, **opts):
2297 """export the repository via HTTP
2297 """export the repository via HTTP
2298
2298
2299 Start a local HTTP repository browser and pull server.
2299 Start a local HTTP repository browser and pull server.
2300
2300
2301 By default, the server logs accesses to stdout and errors to
2301 By default, the server logs accesses to stdout and errors to
2302 stderr. Use the "-A" and "-E" options to log to files.
2302 stderr. Use the "-A" and "-E" options to log to files.
2303 """
2303 """
2304
2304
2305 if opts["stdio"]:
2305 if opts["stdio"]:
2306 if repo is None:
2306 if repo is None:
2307 raise hg.RepoError(_("There is no Mercurial repository here"
2307 raise hg.RepoError(_("There is no Mercurial repository here"
2308 " (.hg not found)"))
2308 " (.hg not found)"))
2309 s = sshserver.sshserver(ui, repo)
2309 s = sshserver.sshserver(ui, repo)
2310 s.serve_forever()
2310 s.serve_forever()
2311
2311
2312 parentui = ui.parentui or ui
2312 parentui = ui.parentui or ui
2313 optlist = ("name templates style address port ipv6"
2313 optlist = ("name templates style address port ipv6"
2314 " accesslog errorlog webdir_conf")
2314 " accesslog errorlog webdir_conf")
2315 for o in optlist.split():
2315 for o in optlist.split():
2316 if opts[o]:
2316 if opts[o]:
2317 parentui.setconfig("web", o, str(opts[o]))
2317 parentui.setconfig("web", o, str(opts[o]))
2318
2318
2319 if repo is None and not ui.config("web", "webdir_conf"):
2319 if repo is None and not ui.config("web", "webdir_conf"):
2320 raise hg.RepoError(_("There is no Mercurial repository here"
2320 raise hg.RepoError(_("There is no Mercurial repository here"
2321 " (.hg not found)"))
2321 " (.hg not found)"))
2322
2322
2323 if opts['daemon'] and not opts['daemon_pipefds']:
2323 if opts['daemon'] and not opts['daemon_pipefds']:
2324 rfd, wfd = os.pipe()
2324 rfd, wfd = os.pipe()
2325 args = sys.argv[:]
2325 args = sys.argv[:]
2326 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2326 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2327 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2327 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2328 args[0], args)
2328 args[0], args)
2329 os.close(wfd)
2329 os.close(wfd)
2330 os.read(rfd, 1)
2330 os.read(rfd, 1)
2331 os._exit(0)
2331 os._exit(0)
2332
2332
2333 httpd = hgweb.server.create_server(parentui, repo)
2333 httpd = hgweb.server.create_server(parentui, repo)
2334
2334
2335 if ui.verbose:
2335 if ui.verbose:
2336 if httpd.port != 80:
2336 if httpd.port != 80:
2337 ui.status(_('listening at http://%s:%d/\n') %
2337 ui.status(_('listening at http://%s:%d/\n') %
2338 (httpd.addr, httpd.port))
2338 (httpd.addr, httpd.port))
2339 else:
2339 else:
2340 ui.status(_('listening at http://%s/\n') % httpd.addr)
2340 ui.status(_('listening at http://%s/\n') % httpd.addr)
2341
2341
2342 if opts['pid_file']:
2342 if opts['pid_file']:
2343 fp = open(opts['pid_file'], 'w')
2343 fp = open(opts['pid_file'], 'w')
2344 fp.write(str(os.getpid()) + '\n')
2344 fp.write(str(os.getpid()) + '\n')
2345 fp.close()
2345 fp.close()
2346
2346
2347 if opts['daemon_pipefds']:
2347 if opts['daemon_pipefds']:
2348 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2348 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2349 os.close(rfd)
2349 os.close(rfd)
2350 os.write(wfd, 'y')
2350 os.write(wfd, 'y')
2351 os.close(wfd)
2351 os.close(wfd)
2352 sys.stdout.flush()
2352 sys.stdout.flush()
2353 sys.stderr.flush()
2353 sys.stderr.flush()
2354 fd = os.open(util.nulldev, os.O_RDWR)
2354 fd = os.open(util.nulldev, os.O_RDWR)
2355 if fd != 0: os.dup2(fd, 0)
2355 if fd != 0: os.dup2(fd, 0)
2356 if fd != 1: os.dup2(fd, 1)
2356 if fd != 1: os.dup2(fd, 1)
2357 if fd != 2: os.dup2(fd, 2)
2357 if fd != 2: os.dup2(fd, 2)
2358 if fd not in (0, 1, 2): os.close(fd)
2358 if fd not in (0, 1, 2): os.close(fd)
2359
2359
2360 httpd.serve_forever()
2360 httpd.serve_forever()
2361
2361
2362 def status(ui, repo, *pats, **opts):
2362 def status(ui, repo, *pats, **opts):
2363 """show changed files in the working directory
2363 """show changed files in the working directory
2364
2364
2365 Show status of files in the repository. If names are given, only
2365 Show status of files in the repository. If names are given, only
2366 files that match are shown. Files that are clean or ignored, are
2366 files that match are shown. Files that are clean or ignored, are
2367 not listed unless -c (clean), -i (ignored) or -A is given.
2367 not listed unless -c (clean), -i (ignored) or -A is given.
2368
2368
2369 NOTE: status may appear to disagree with diff if permissions have
2369 NOTE: status may appear to disagree with diff if permissions have
2370 changed or a merge has occurred. The standard diff format does not
2370 changed or a merge has occurred. The standard diff format does not
2371 report permission changes and diff only reports changes relative
2371 report permission changes and diff only reports changes relative
2372 to one merge parent.
2372 to one merge parent.
2373
2373
2374 If one revision is given, it is used as the base revision.
2374 If one revision is given, it is used as the base revision.
2375 If two revisions are given, the difference between them is shown.
2375 If two revisions are given, the difference between them is shown.
2376
2376
2377 The codes used to show the status of files are:
2377 The codes used to show the status of files are:
2378 M = modified
2378 M = modified
2379 A = added
2379 A = added
2380 R = removed
2380 R = removed
2381 C = clean
2381 C = clean
2382 ! = deleted, but still tracked
2382 ! = deleted, but still tracked
2383 ? = not tracked
2383 ? = not tracked
2384 I = ignored (not shown by default)
2384 I = ignored (not shown by default)
2385 = the previous added file was copied from here
2385 = the previous added file was copied from here
2386 """
2386 """
2387
2387
2388 all = opts['all']
2388 all = opts['all']
2389 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2389 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2390
2390
2391 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2391 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2392 cwd = (pats and repo.getcwd()) or ''
2392 cwd = (pats and repo.getcwd()) or ''
2393 modified, added, removed, deleted, unknown, ignored, clean = [
2393 modified, added, removed, deleted, unknown, ignored, clean = [
2394 n for n in repo.status(node1=node1, node2=node2, files=files,
2394 n for n in repo.status(node1=node1, node2=node2, files=files,
2395 match=matchfn,
2395 match=matchfn,
2396 list_ignored=all or opts['ignored'],
2396 list_ignored=all or opts['ignored'],
2397 list_clean=all or opts['clean'])]
2397 list_clean=all or opts['clean'])]
2398
2398
2399 changetypes = (('modified', 'M', modified),
2399 changetypes = (('modified', 'M', modified),
2400 ('added', 'A', added),
2400 ('added', 'A', added),
2401 ('removed', 'R', removed),
2401 ('removed', 'R', removed),
2402 ('deleted', '!', deleted),
2402 ('deleted', '!', deleted),
2403 ('unknown', '?', unknown),
2403 ('unknown', '?', unknown),
2404 ('ignored', 'I', ignored))
2404 ('ignored', 'I', ignored))
2405
2405
2406 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2406 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2407
2407
2408 end = opts['print0'] and '\0' or '\n'
2408 end = opts['print0'] and '\0' or '\n'
2409
2409
2410 for opt, char, changes in ([ct for ct in explicit_changetypes
2410 for opt, char, changes in ([ct for ct in explicit_changetypes
2411 if all or opts[ct[0]]]
2411 if all or opts[ct[0]]]
2412 or changetypes):
2412 or changetypes):
2413 if opts['no_status']:
2413 if opts['no_status']:
2414 format = "%%s%s" % end
2414 format = "%%s%s" % end
2415 else:
2415 else:
2416 format = "%s %%s%s" % (char, end)
2416 format = "%s %%s%s" % (char, end)
2417
2417
2418 for f in changes:
2418 for f in changes:
2419 ui.write(format % util.pathto(cwd, f))
2419 ui.write(format % util.pathto(cwd, f))
2420 if ((all or opts.get('copies')) and not opts.get('no_status')):
2420 if ((all or opts.get('copies')) and not opts.get('no_status')):
2421 copied = repo.dirstate.copied(f)
2421 copied = repo.dirstate.copied(f)
2422 if copied:
2422 if copied:
2423 ui.write(' %s%s' % (util.pathto(cwd, copied), end))
2423 ui.write(' %s%s' % (util.pathto(cwd, copied), end))
2424
2424
2425 def tag(ui, repo, name, rev_=None, **opts):
2425 def tag(ui, repo, name, rev_=None, **opts):
2426 """add a tag for the current or given revision
2426 """add a tag for the current or given revision
2427
2427
2428 Name a particular revision using <name>.
2428 Name a particular revision using <name>.
2429
2429
2430 Tags are used to name particular revisions of the repository and are
2430 Tags are used to name particular revisions of the repository and are
2431 very useful to compare different revision, to go back to significant
2431 very useful to compare different revision, to go back to significant
2432 earlier versions or to mark branch points as releases, etc.
2432 earlier versions or to mark branch points as releases, etc.
2433
2433
2434 If no revision is given, the parent of the working directory is used,
2434 If no revision is given, the parent of the working directory is used,
2435 or tip if no revision is checked out.
2435 or tip if no revision is checked out.
2436
2436
2437 To facilitate version control, distribution, and merging of tags,
2437 To facilitate version control, distribution, and merging of tags,
2438 they are stored as a file named ".hgtags" which is managed
2438 they are stored as a file named ".hgtags" which is managed
2439 similarly to other project files and can be hand-edited if
2439 similarly to other project files and can be hand-edited if
2440 necessary. The file '.hg/localtags' is used for local tags (not
2440 necessary. The file '.hg/localtags' is used for local tags (not
2441 shared among repositories).
2441 shared among repositories).
2442 """
2442 """
2443 if name in ['tip', '.', 'null']:
2443 if name in ['tip', '.', 'null']:
2444 raise util.Abort(_("the name '%s' is reserved") % name)
2444 raise util.Abort(_("the name '%s' is reserved") % name)
2445 if rev_ is not None:
2445 if rev_ is not None:
2446 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2446 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2447 "please use 'hg tag [-r REV] NAME' instead\n"))
2447 "please use 'hg tag [-r REV] NAME' instead\n"))
2448 if opts['rev']:
2448 if opts['rev']:
2449 raise util.Abort(_("use only one form to specify the revision"))
2449 raise util.Abort(_("use only one form to specify the revision"))
2450 if opts['rev']:
2450 if opts['rev']:
2451 rev_ = opts['rev']
2451 rev_ = opts['rev']
2452 if not rev_ and repo.dirstate.parents()[1] != nullid:
2452 if not rev_ and repo.dirstate.parents()[1] != nullid:
2453 raise util.Abort(_('uncommitted merge - please provide a '
2453 raise util.Abort(_('uncommitted merge - please provide a '
2454 'specific revision'))
2454 'specific revision'))
2455 r = repo.changectx(rev_).node()
2455 r = repo.changectx(rev_).node()
2456
2456
2457 message = opts['message']
2457 message = opts['message']
2458 if not message:
2458 if not message:
2459 message = _('Added tag %s for changeset %s') % (name, short(r))
2459 message = _('Added tag %s for changeset %s') % (name, short(r))
2460
2460
2461 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2461 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2462
2462
2463 def tags(ui, repo):
2463 def tags(ui, repo):
2464 """list repository tags
2464 """list repository tags
2465
2465
2466 List the repository tags.
2466 List the repository tags.
2467
2467
2468 This lists both regular and local tags.
2468 This lists both regular and local tags.
2469 """
2469 """
2470
2470
2471 l = repo.tagslist()
2471 l = repo.tagslist()
2472 l.reverse()
2472 l.reverse()
2473 hexfunc = ui.debugflag and hex or short
2473 hexfunc = ui.debugflag and hex or short
2474 for t, n in l:
2474 for t, n in l:
2475 try:
2475 try:
2476 hn = hexfunc(n)
2476 hn = hexfunc(n)
2477 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
2477 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
2478 except revlog.LookupError:
2478 except revlog.LookupError:
2479 r = " ?:%s" % hn
2479 r = " ?:%s" % hn
2480 if ui.quiet:
2480 if ui.quiet:
2481 ui.write("%s\n" % t)
2481 ui.write("%s\n" % t)
2482 else:
2482 else:
2483 spaces = " " * (30 - util.locallen(t))
2483 spaces = " " * (30 - util.locallen(t))
2484 ui.write("%s%s %s\n" % (t, spaces, r))
2484 ui.write("%s%s %s\n" % (t, spaces, r))
2485
2485
2486 def tip(ui, repo, **opts):
2486 def tip(ui, repo, **opts):
2487 """show the tip revision
2487 """show the tip revision
2488
2488
2489 Show the tip revision.
2489 Show the tip revision.
2490 """
2490 """
2491 cmdutil.show_changeset(ui, repo, opts).show(nullrev+repo.changelog.count())
2491 cmdutil.show_changeset(ui, repo, opts).show(nullrev+repo.changelog.count())
2492
2492
2493 def unbundle(ui, repo, fname, **opts):
2493 def unbundle(ui, repo, fname, **opts):
2494 """apply a changegroup file
2494 """apply a changegroup file
2495
2495
2496 Apply a compressed changegroup file generated by the bundle
2496 Apply a compressed changegroup file generated by the bundle
2497 command.
2497 command.
2498 """
2498 """
2499 if os.path.exists(fname):
2499 if os.path.exists(fname):
2500 f = open(fname, "rb")
2500 f = open(fname, "rb")
2501 else:
2501 else:
2502 f = urllib.urlopen(fname)
2502 f = urllib.urlopen(fname)
2503 gen = changegroup.readbundle(f, fname)
2503 gen = changegroup.readbundle(f, fname)
2504 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2504 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2505 return postincoming(ui, repo, modheads, opts['update'])
2505 return postincoming(ui, repo, modheads, opts['update'])
2506
2506
2507 def update(ui, repo, node=None, clean=False, date=None):
2507 def update(ui, repo, node=None, clean=False, date=None):
2508 """update working directory
2508 """update working directory
2509
2509
2510 Update the working directory to the specified revision.
2510 Update the working directory to the specified revision, or the
2511 tip of the current branch if none is specified.
2511
2512
2512 If there are no outstanding changes in the working directory and
2513 If there are no outstanding changes in the working directory and
2513 there is a linear relationship between the current version and the
2514 there is a linear relationship between the current version and the
2514 requested version, the result is the requested version.
2515 requested version, the result is the requested version.
2515
2516
2516 To merge the working directory with another revision, use the
2517 To merge the working directory with another revision, use the
2517 merge command.
2518 merge command.
2518
2519
2519 By default, update will refuse to run if doing so would require
2520 By default, update will refuse to run if doing so would require
2520 discarding local changes.
2521 discarding local changes.
2521 """
2522 """
2522 if date:
2523 if date:
2523 if node:
2524 if node:
2524 raise util.Abort(_("you can't specify a revision and a date"))
2525 raise util.Abort(_("you can't specify a revision and a date"))
2525 node = cmdutil.finddate(ui, repo, date)
2526 node = cmdutil.finddate(ui, repo, date)
2526
2527
2527 if clean:
2528 if clean:
2528 return hg.clean(repo, node)
2529 return hg.clean(repo, node)
2529 else:
2530 else:
2530 return hg.update(repo, node)
2531 return hg.update(repo, node)
2531
2532
2532 def verify(ui, repo):
2533 def verify(ui, repo):
2533 """verify the integrity of the repository
2534 """verify the integrity of the repository
2534
2535
2535 Verify the integrity of the current repository.
2536 Verify the integrity of the current repository.
2536
2537
2537 This will perform an extensive check of the repository's
2538 This will perform an extensive check of the repository's
2538 integrity, validating the hashes and checksums of each entry in
2539 integrity, validating the hashes and checksums of each entry in
2539 the changelog, manifest, and tracked files, as well as the
2540 the changelog, manifest, and tracked files, as well as the
2540 integrity of their crosslinks and indices.
2541 integrity of their crosslinks and indices.
2541 """
2542 """
2542 return hg.verify(repo)
2543 return hg.verify(repo)
2543
2544
2544 def version_(ui):
2545 def version_(ui):
2545 """output version and copyright information"""
2546 """output version and copyright information"""
2546 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2547 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2547 % version.get_version())
2548 % version.get_version())
2548 ui.status(_(
2549 ui.status(_(
2549 "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
2550 "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
2550 "This is free software; see the source for copying conditions. "
2551 "This is free software; see the source for copying conditions. "
2551 "There is NO\nwarranty; "
2552 "There is NO\nwarranty; "
2552 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2553 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2553 ))
2554 ))
2554
2555
2555 # Command options and aliases are listed here, alphabetically
2556 # Command options and aliases are listed here, alphabetically
2556
2557
2557 globalopts = [
2558 globalopts = [
2558 ('R', 'repository', '',
2559 ('R', 'repository', '',
2559 _('repository root directory or symbolic path name')),
2560 _('repository root directory or symbolic path name')),
2560 ('', 'cwd', '', _('change working directory')),
2561 ('', 'cwd', '', _('change working directory')),
2561 ('y', 'noninteractive', None,
2562 ('y', 'noninteractive', None,
2562 _('do not prompt, assume \'yes\' for any required answers')),
2563 _('do not prompt, assume \'yes\' for any required answers')),
2563 ('q', 'quiet', None, _('suppress output')),
2564 ('q', 'quiet', None, _('suppress output')),
2564 ('v', 'verbose', None, _('enable additional output')),
2565 ('v', 'verbose', None, _('enable additional output')),
2565 ('', 'config', [], _('set/override config option')),
2566 ('', 'config', [], _('set/override config option')),
2566 ('', 'debug', None, _('enable debugging output')),
2567 ('', 'debug', None, _('enable debugging output')),
2567 ('', 'debugger', None, _('start debugger')),
2568 ('', 'debugger', None, _('start debugger')),
2568 ('', 'encoding', util._encoding, _('set the charset encoding')),
2569 ('', 'encoding', util._encoding, _('set the charset encoding')),
2569 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2570 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2570 ('', 'lsprof', None, _('print improved command execution profile')),
2571 ('', 'lsprof', None, _('print improved command execution profile')),
2571 ('', 'traceback', None, _('print traceback on exception')),
2572 ('', 'traceback', None, _('print traceback on exception')),
2572 ('', 'time', None, _('time how long the command takes')),
2573 ('', 'time', None, _('time how long the command takes')),
2573 ('', 'profile', None, _('print command execution profile')),
2574 ('', 'profile', None, _('print command execution profile')),
2574 ('', 'version', None, _('output version information and exit')),
2575 ('', 'version', None, _('output version information and exit')),
2575 ('h', 'help', None, _('display help and exit')),
2576 ('h', 'help', None, _('display help and exit')),
2576 ]
2577 ]
2577
2578
2578 dryrunopts = [('n', 'dry-run', None,
2579 dryrunopts = [('n', 'dry-run', None,
2579 _('do not perform actions, just print output'))]
2580 _('do not perform actions, just print output'))]
2580
2581
2581 remoteopts = [
2582 remoteopts = [
2582 ('e', 'ssh', '', _('specify ssh command to use')),
2583 ('e', 'ssh', '', _('specify ssh command to use')),
2583 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2584 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2584 ]
2585 ]
2585
2586
2586 walkopts = [
2587 walkopts = [
2587 ('I', 'include', [], _('include names matching the given patterns')),
2588 ('I', 'include', [], _('include names matching the given patterns')),
2588 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2589 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2589 ]
2590 ]
2590
2591
2591 commitopts = [
2592 commitopts = [
2592 ('m', 'message', '', _('use <text> as commit message')),
2593 ('m', 'message', '', _('use <text> as commit message')),
2593 ('l', 'logfile', '', _('read commit message from <file>')),
2594 ('l', 'logfile', '', _('read commit message from <file>')),
2594 ]
2595 ]
2595
2596
2596 table = {
2597 table = {
2597 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2598 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2598 "addremove":
2599 "addremove":
2599 (addremove,
2600 (addremove,
2600 [('s', 'similarity', '',
2601 [('s', 'similarity', '',
2601 _('guess renamed files by similarity (0<=s<=100)')),
2602 _('guess renamed files by similarity (0<=s<=100)')),
2602 ] + walkopts + dryrunopts,
2603 ] + walkopts + dryrunopts,
2603 _('hg addremove [OPTION]... [FILE]...')),
2604 _('hg addremove [OPTION]... [FILE]...')),
2604 "^annotate":
2605 "^annotate":
2605 (annotate,
2606 (annotate,
2606 [('r', 'rev', '', _('annotate the specified revision')),
2607 [('r', 'rev', '', _('annotate the specified revision')),
2607 ('f', 'follow', None, _('follow file copies and renames')),
2608 ('f', 'follow', None, _('follow file copies and renames')),
2608 ('a', 'text', None, _('treat all files as text')),
2609 ('a', 'text', None, _('treat all files as text')),
2609 ('u', 'user', None, _('list the author')),
2610 ('u', 'user', None, _('list the author')),
2610 ('d', 'date', None, _('list the date')),
2611 ('d', 'date', None, _('list the date')),
2611 ('n', 'number', None, _('list the revision number (default)')),
2612 ('n', 'number', None, _('list the revision number (default)')),
2612 ('c', 'changeset', None, _('list the changeset')),
2613 ('c', 'changeset', None, _('list the changeset')),
2613 ] + walkopts,
2614 ] + walkopts,
2614 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] FILE...')),
2615 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] FILE...')),
2615 "archive":
2616 "archive":
2616 (archive,
2617 (archive,
2617 [('', 'no-decode', None, _('do not pass files through decoders')),
2618 [('', 'no-decode', None, _('do not pass files through decoders')),
2618 ('p', 'prefix', '', _('directory prefix for files in archive')),
2619 ('p', 'prefix', '', _('directory prefix for files in archive')),
2619 ('r', 'rev', '', _('revision to distribute')),
2620 ('r', 'rev', '', _('revision to distribute')),
2620 ('t', 'type', '', _('type of distribution to create')),
2621 ('t', 'type', '', _('type of distribution to create')),
2621 ] + walkopts,
2622 ] + walkopts,
2622 _('hg archive [OPTION]... DEST')),
2623 _('hg archive [OPTION]... DEST')),
2623 "backout":
2624 "backout":
2624 (backout,
2625 (backout,
2625 [('', 'merge', None,
2626 [('', 'merge', None,
2626 _('merge with old dirstate parent after backout')),
2627 _('merge with old dirstate parent after backout')),
2627 ('d', 'date', '', _('record datecode as commit date')),
2628 ('d', 'date', '', _('record datecode as commit date')),
2628 ('', 'parent', '', _('parent to choose when backing out merge')),
2629 ('', 'parent', '', _('parent to choose when backing out merge')),
2629 ('u', 'user', '', _('record user as committer')),
2630 ('u', 'user', '', _('record user as committer')),
2630 ] + walkopts + commitopts,
2631 ] + walkopts + commitopts,
2631 _('hg backout [OPTION]... REV')),
2632 _('hg backout [OPTION]... REV')),
2632 "branch": (branch,
2633 "branch": (branch,
2633 [('f', 'force', None,
2634 [('f', 'force', None,
2634 _('set branch name even if it shadows an existing branch'))],
2635 _('set branch name even if it shadows an existing branch'))],
2635 _('hg branch [NAME]')),
2636 _('hg branch [NAME]')),
2636 "branches": (branches, [], _('hg branches')),
2637 "branches": (branches, [], _('hg branches')),
2637 "bundle":
2638 "bundle":
2638 (bundle,
2639 (bundle,
2639 [('f', 'force', None,
2640 [('f', 'force', None,
2640 _('run even when remote repository is unrelated')),
2641 _('run even when remote repository is unrelated')),
2641 ('r', 'rev', [],
2642 ('r', 'rev', [],
2642 _('a changeset you would like to bundle')),
2643 _('a changeset you would like to bundle')),
2643 ('', 'base', [],
2644 ('', 'base', [],
2644 _('a base changeset to specify instead of a destination')),
2645 _('a base changeset to specify instead of a destination')),
2645 ] + remoteopts,
2646 ] + remoteopts,
2646 _('hg bundle [-f] [-r REV]... [--base REV]... FILE [DEST]')),
2647 _('hg bundle [-f] [-r REV]... [--base REV]... FILE [DEST]')),
2647 "cat":
2648 "cat":
2648 (cat,
2649 (cat,
2649 [('o', 'output', '', _('print output to file with formatted name')),
2650 [('o', 'output', '', _('print output to file with formatted name')),
2650 ('r', 'rev', '', _('print the given revision')),
2651 ('r', 'rev', '', _('print the given revision')),
2651 ] + walkopts,
2652 ] + walkopts,
2652 _('hg cat [OPTION]... FILE...')),
2653 _('hg cat [OPTION]... FILE...')),
2653 "^clone":
2654 "^clone":
2654 (clone,
2655 (clone,
2655 [('U', 'noupdate', None, _('do not update the new working directory')),
2656 [('U', 'noupdate', None, _('do not update the new working directory')),
2656 ('r', 'rev', [],
2657 ('r', 'rev', [],
2657 _('a changeset you would like to have after cloning')),
2658 _('a changeset you would like to have after cloning')),
2658 ('', 'pull', None, _('use pull protocol to copy metadata')),
2659 ('', 'pull', None, _('use pull protocol to copy metadata')),
2659 ('', 'uncompressed', None,
2660 ('', 'uncompressed', None,
2660 _('use uncompressed transfer (fast over LAN)')),
2661 _('use uncompressed transfer (fast over LAN)')),
2661 ] + remoteopts,
2662 ] + remoteopts,
2662 _('hg clone [OPTION]... SOURCE [DEST]')),
2663 _('hg clone [OPTION]... SOURCE [DEST]')),
2663 "^commit|ci":
2664 "^commit|ci":
2664 (commit,
2665 (commit,
2665 [('A', 'addremove', None,
2666 [('A', 'addremove', None,
2666 _('mark new/missing files as added/removed before committing')),
2667 _('mark new/missing files as added/removed before committing')),
2667 ('d', 'date', '', _('record datecode as commit date')),
2668 ('d', 'date', '', _('record datecode as commit date')),
2668 ('u', 'user', '', _('record user as commiter')),
2669 ('u', 'user', '', _('record user as commiter')),
2669 ] + walkopts + commitopts,
2670 ] + walkopts + commitopts,
2670 _('hg commit [OPTION]... [FILE]...')),
2671 _('hg commit [OPTION]... [FILE]...')),
2671 "copy|cp":
2672 "copy|cp":
2672 (copy,
2673 (copy,
2673 [('A', 'after', None, _('record a copy that has already occurred')),
2674 [('A', 'after', None, _('record a copy that has already occurred')),
2674 ('f', 'force', None,
2675 ('f', 'force', None,
2675 _('forcibly copy over an existing managed file')),
2676 _('forcibly copy over an existing managed file')),
2676 ] + walkopts + dryrunopts,
2677 ] + walkopts + dryrunopts,
2677 _('hg copy [OPTION]... [SOURCE]... DEST')),
2678 _('hg copy [OPTION]... [SOURCE]... DEST')),
2678 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2679 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2679 "debugcomplete":
2680 "debugcomplete":
2680 (debugcomplete,
2681 (debugcomplete,
2681 [('o', 'options', None, _('show the command options'))],
2682 [('o', 'options', None, _('show the command options'))],
2682 _('debugcomplete [-o] CMD')),
2683 _('debugcomplete [-o] CMD')),
2683 "debuginstall": (debuginstall, [], _('debuginstall')),
2684 "debuginstall": (debuginstall, [], _('debuginstall')),
2684 "debugrebuildstate":
2685 "debugrebuildstate":
2685 (debugrebuildstate,
2686 (debugrebuildstate,
2686 [('r', 'rev', '', _('revision to rebuild to'))],
2687 [('r', 'rev', '', _('revision to rebuild to'))],
2687 _('debugrebuildstate [-r REV] [REV]')),
2688 _('debugrebuildstate [-r REV] [REV]')),
2688 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2689 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2689 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2690 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2690 "debugstate": (debugstate, [], _('debugstate')),
2691 "debugstate": (debugstate, [], _('debugstate')),
2691 "debugdate":
2692 "debugdate":
2692 (debugdate,
2693 (debugdate,
2693 [('e', 'extended', None, _('try extended date formats'))],
2694 [('e', 'extended', None, _('try extended date formats'))],
2694 _('debugdate [-e] DATE [RANGE]')),
2695 _('debugdate [-e] DATE [RANGE]')),
2695 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2696 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2696 "debugindex": (debugindex, [], _('debugindex FILE')),
2697 "debugindex": (debugindex, [], _('debugindex FILE')),
2697 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2698 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2698 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2699 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2699 "debugwalk": (debugwalk, walkopts, _('debugwalk [OPTION]... [FILE]...')),
2700 "debugwalk": (debugwalk, walkopts, _('debugwalk [OPTION]... [FILE]...')),
2700 "^diff":
2701 "^diff":
2701 (diff,
2702 (diff,
2702 [('r', 'rev', [], _('revision')),
2703 [('r', 'rev', [], _('revision')),
2703 ('a', 'text', None, _('treat all files as text')),
2704 ('a', 'text', None, _('treat all files as text')),
2704 ('p', 'show-function', None,
2705 ('p', 'show-function', None,
2705 _('show which function each change is in')),
2706 _('show which function each change is in')),
2706 ('g', 'git', None, _('use git extended diff format')),
2707 ('g', 'git', None, _('use git extended diff format')),
2707 ('', 'nodates', None, _("don't include dates in diff headers")),
2708 ('', 'nodates', None, _("don't include dates in diff headers")),
2708 ('w', 'ignore-all-space', None,
2709 ('w', 'ignore-all-space', None,
2709 _('ignore white space when comparing lines')),
2710 _('ignore white space when comparing lines')),
2710 ('b', 'ignore-space-change', None,
2711 ('b', 'ignore-space-change', None,
2711 _('ignore changes in the amount of white space')),
2712 _('ignore changes in the amount of white space')),
2712 ('B', 'ignore-blank-lines', None,
2713 ('B', 'ignore-blank-lines', None,
2713 _('ignore changes whose lines are all blank')),
2714 _('ignore changes whose lines are all blank')),
2714 ] + walkopts,
2715 ] + walkopts,
2715 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
2716 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
2716 "^export":
2717 "^export":
2717 (export,
2718 (export,
2718 [('o', 'output', '', _('print output to file with formatted name')),
2719 [('o', 'output', '', _('print output to file with formatted name')),
2719 ('a', 'text', None, _('treat all files as text')),
2720 ('a', 'text', None, _('treat all files as text')),
2720 ('g', 'git', None, _('use git extended diff format')),
2721 ('g', 'git', None, _('use git extended diff format')),
2721 ('', 'nodates', None, _("don't include dates in diff headers")),
2722 ('', 'nodates', None, _("don't include dates in diff headers")),
2722 ('', 'switch-parent', None, _('diff against the second parent'))],
2723 ('', 'switch-parent', None, _('diff against the second parent'))],
2723 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
2724 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
2724 "grep":
2725 "grep":
2725 (grep,
2726 (grep,
2726 [('0', 'print0', None, _('end fields with NUL')),
2727 [('0', 'print0', None, _('end fields with NUL')),
2727 ('', 'all', None, _('print all revisions that match')),
2728 ('', 'all', None, _('print all revisions that match')),
2728 ('f', 'follow', None,
2729 ('f', 'follow', None,
2729 _('follow changeset history, or file history across copies and renames')),
2730 _('follow changeset history, or file history across copies and renames')),
2730 ('i', 'ignore-case', None, _('ignore case when matching')),
2731 ('i', 'ignore-case', None, _('ignore case when matching')),
2731 ('l', 'files-with-matches', None,
2732 ('l', 'files-with-matches', None,
2732 _('print only filenames and revs that match')),
2733 _('print only filenames and revs that match')),
2733 ('n', 'line-number', None, _('print matching line numbers')),
2734 ('n', 'line-number', None, _('print matching line numbers')),
2734 ('r', 'rev', [], _('search in given revision range')),
2735 ('r', 'rev', [], _('search in given revision range')),
2735 ('u', 'user', None, _('print user who committed change')),
2736 ('u', 'user', None, _('print user who committed change')),
2736 ] + walkopts,
2737 ] + walkopts,
2737 _('hg grep [OPTION]... PATTERN [FILE]...')),
2738 _('hg grep [OPTION]... PATTERN [FILE]...')),
2738 "heads":
2739 "heads":
2739 (heads,
2740 (heads,
2740 [('', 'style', '', _('display using template map file')),
2741 [('', 'style', '', _('display using template map file')),
2741 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2742 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2742 ('', 'template', '', _('display with template'))],
2743 ('', 'template', '', _('display with template'))],
2743 _('hg heads [-r REV]')),
2744 _('hg heads [-r REV]')),
2744 "help": (help_, [], _('hg help [COMMAND]')),
2745 "help": (help_, [], _('hg help [COMMAND]')),
2745 "identify|id": (identify, [], _('hg identify')),
2746 "identify|id": (identify, [], _('hg identify')),
2746 "import|patch":
2747 "import|patch":
2747 (import_,
2748 (import_,
2748 [('p', 'strip', 1,
2749 [('p', 'strip', 1,
2749 _('directory strip option for patch. This has the same\n'
2750 _('directory strip option for patch. This has the same\n'
2750 'meaning as the corresponding patch option')),
2751 'meaning as the corresponding patch option')),
2751 ('b', 'base', '', _('base path')),
2752 ('b', 'base', '', _('base path')),
2752 ('f', 'force', None,
2753 ('f', 'force', None,
2753 _('skip check for outstanding uncommitted changes'))] + commitopts,
2754 _('skip check for outstanding uncommitted changes'))] + commitopts,
2754 _('hg import [-p NUM] [-m MESSAGE] [-f] PATCH...')),
2755 _('hg import [-p NUM] [-m MESSAGE] [-f] PATCH...')),
2755 "incoming|in": (incoming,
2756 "incoming|in": (incoming,
2756 [('M', 'no-merges', None, _('do not show merges')),
2757 [('M', 'no-merges', None, _('do not show merges')),
2757 ('f', 'force', None,
2758 ('f', 'force', None,
2758 _('run even when remote repository is unrelated')),
2759 _('run even when remote repository is unrelated')),
2759 ('', 'style', '', _('display using template map file')),
2760 ('', 'style', '', _('display using template map file')),
2760 ('n', 'newest-first', None, _('show newest record first')),
2761 ('n', 'newest-first', None, _('show newest record first')),
2761 ('', 'bundle', '', _('file to store the bundles into')),
2762 ('', 'bundle', '', _('file to store the bundles into')),
2762 ('p', 'patch', None, _('show patch')),
2763 ('p', 'patch', None, _('show patch')),
2763 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2764 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2764 ('', 'template', '', _('display with template')),
2765 ('', 'template', '', _('display with template')),
2765 ] + remoteopts,
2766 ] + remoteopts,
2766 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
2767 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
2767 ' [--bundle FILENAME] [SOURCE]')),
2768 ' [--bundle FILENAME] [SOURCE]')),
2768 "^init":
2769 "^init":
2769 (init,
2770 (init,
2770 remoteopts,
2771 remoteopts,
2771 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
2772 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
2772 "locate":
2773 "locate":
2773 (locate,
2774 (locate,
2774 [('r', 'rev', '', _('search the repository as it stood at rev')),
2775 [('r', 'rev', '', _('search the repository as it stood at rev')),
2775 ('0', 'print0', None,
2776 ('0', 'print0', None,
2776 _('end filenames with NUL, for use with xargs')),
2777 _('end filenames with NUL, for use with xargs')),
2777 ('f', 'fullpath', None,
2778 ('f', 'fullpath', None,
2778 _('print complete paths from the filesystem root')),
2779 _('print complete paths from the filesystem root')),
2779 ] + walkopts,
2780 ] + walkopts,
2780 _('hg locate [OPTION]... [PATTERN]...')),
2781 _('hg locate [OPTION]... [PATTERN]...')),
2781 "^log|history":
2782 "^log|history":
2782 (log,
2783 (log,
2783 [('f', 'follow', None,
2784 [('f', 'follow', None,
2784 _('follow changeset history, or file history across copies and renames')),
2785 _('follow changeset history, or file history across copies and renames')),
2785 ('', 'follow-first', None,
2786 ('', 'follow-first', None,
2786 _('only follow the first parent of merge changesets')),
2787 _('only follow the first parent of merge changesets')),
2787 ('d', 'date', '', _('show revs matching date spec')),
2788 ('d', 'date', '', _('show revs matching date spec')),
2788 ('C', 'copies', None, _('show copied files')),
2789 ('C', 'copies', None, _('show copied files')),
2789 ('k', 'keyword', [], _('search for a keyword')),
2790 ('k', 'keyword', [], _('search for a keyword')),
2790 ('l', 'limit', '', _('limit number of changes displayed')),
2791 ('l', 'limit', '', _('limit number of changes displayed')),
2791 ('r', 'rev', [], _('show the specified revision or range')),
2792 ('r', 'rev', [], _('show the specified revision or range')),
2792 ('', 'removed', None, _('include revs where files were removed')),
2793 ('', 'removed', None, _('include revs where files were removed')),
2793 ('M', 'no-merges', None, _('do not show merges')),
2794 ('M', 'no-merges', None, _('do not show merges')),
2794 ('', 'style', '', _('display using template map file')),
2795 ('', 'style', '', _('display using template map file')),
2795 ('m', 'only-merges', None, _('show only merges')),
2796 ('m', 'only-merges', None, _('show only merges')),
2796 ('p', 'patch', None, _('show patch')),
2797 ('p', 'patch', None, _('show patch')),
2797 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2798 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2798 ('', 'template', '', _('display with template')),
2799 ('', 'template', '', _('display with template')),
2799 ] + walkopts,
2800 ] + walkopts,
2800 _('hg log [OPTION]... [FILE]')),
2801 _('hg log [OPTION]... [FILE]')),
2801 "manifest": (manifest, [], _('hg manifest [REV]')),
2802 "manifest": (manifest, [], _('hg manifest [REV]')),
2802 "^merge":
2803 "^merge":
2803 (merge,
2804 (merge,
2804 [('f', 'force', None, _('force a merge with outstanding changes'))],
2805 [('f', 'force', None, _('force a merge with outstanding changes'))],
2805 _('hg merge [-f] [REV]')),
2806 _('hg merge [-f] [REV]')),
2806 "outgoing|out": (outgoing,
2807 "outgoing|out": (outgoing,
2807 [('M', 'no-merges', None, _('do not show merges')),
2808 [('M', 'no-merges', None, _('do not show merges')),
2808 ('f', 'force', None,
2809 ('f', 'force', None,
2809 _('run even when remote repository is unrelated')),
2810 _('run even when remote repository is unrelated')),
2810 ('p', 'patch', None, _('show patch')),
2811 ('p', 'patch', None, _('show patch')),
2811 ('', 'style', '', _('display using template map file')),
2812 ('', 'style', '', _('display using template map file')),
2812 ('r', 'rev', [], _('a specific revision you would like to push')),
2813 ('r', 'rev', [], _('a specific revision you would like to push')),
2813 ('n', 'newest-first', None, _('show newest record first')),
2814 ('n', 'newest-first', None, _('show newest record first')),
2814 ('', 'template', '', _('display with template')),
2815 ('', 'template', '', _('display with template')),
2815 ] + remoteopts,
2816 ] + remoteopts,
2816 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
2817 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
2817 "^parents":
2818 "^parents":
2818 (parents,
2819 (parents,
2819 [('r', 'rev', '', _('show parents from the specified rev')),
2820 [('r', 'rev', '', _('show parents from the specified rev')),
2820 ('', 'style', '', _('display using template map file')),
2821 ('', 'style', '', _('display using template map file')),
2821 ('', 'template', '', _('display with template'))],
2822 ('', 'template', '', _('display with template'))],
2822 _('hg parents [-r REV] [FILE]')),
2823 _('hg parents [-r REV] [FILE]')),
2823 "paths": (paths, [], _('hg paths [NAME]')),
2824 "paths": (paths, [], _('hg paths [NAME]')),
2824 "^pull":
2825 "^pull":
2825 (pull,
2826 (pull,
2826 [('u', 'update', None,
2827 [('u', 'update', None,
2827 _('update to new tip if changesets were pulled')),
2828 _('update to new tip if changesets were pulled')),
2828 ('f', 'force', None,
2829 ('f', 'force', None,
2829 _('run even when remote repository is unrelated')),
2830 _('run even when remote repository is unrelated')),
2830 ('r', 'rev', [],
2831 ('r', 'rev', [],
2831 _('a specific revision up to which you would like to pull')),
2832 _('a specific revision up to which you would like to pull')),
2832 ] + remoteopts,
2833 ] + remoteopts,
2833 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
2834 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
2834 "^push":
2835 "^push":
2835 (push,
2836 (push,
2836 [('f', 'force', None, _('force push')),
2837 [('f', 'force', None, _('force push')),
2837 ('r', 'rev', [], _('a specific revision you would like to push')),
2838 ('r', 'rev', [], _('a specific revision you would like to push')),
2838 ] + remoteopts,
2839 ] + remoteopts,
2839 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
2840 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
2840 "debugrawcommit|rawcommit":
2841 "debugrawcommit|rawcommit":
2841 (rawcommit,
2842 (rawcommit,
2842 [('p', 'parent', [], _('parent')),
2843 [('p', 'parent', [], _('parent')),
2843 ('d', 'date', '', _('date code')),
2844 ('d', 'date', '', _('date code')),
2844 ('u', 'user', '', _('user')),
2845 ('u', 'user', '', _('user')),
2845 ('F', 'files', '', _('file list'))
2846 ('F', 'files', '', _('file list'))
2846 ] + commitopts,
2847 ] + commitopts,
2847 _('hg debugrawcommit [OPTION]... [FILE]...')),
2848 _('hg debugrawcommit [OPTION]... [FILE]...')),
2848 "recover": (recover, [], _('hg recover')),
2849 "recover": (recover, [], _('hg recover')),
2849 "^remove|rm":
2850 "^remove|rm":
2850 (remove,
2851 (remove,
2851 [('A', 'after', None, _('record remove that has already occurred')),
2852 [('A', 'after', None, _('record remove that has already occurred')),
2852 ('f', 'force', None, _('remove file even if modified')),
2853 ('f', 'force', None, _('remove file even if modified')),
2853 ] + walkopts,
2854 ] + walkopts,
2854 _('hg remove [OPTION]... FILE...')),
2855 _('hg remove [OPTION]... FILE...')),
2855 "rename|mv":
2856 "rename|mv":
2856 (rename,
2857 (rename,
2857 [('A', 'after', None, _('record a rename that has already occurred')),
2858 [('A', 'after', None, _('record a rename that has already occurred')),
2858 ('f', 'force', None,
2859 ('f', 'force', None,
2859 _('forcibly copy over an existing managed file')),
2860 _('forcibly copy over an existing managed file')),
2860 ] + walkopts + dryrunopts,
2861 ] + walkopts + dryrunopts,
2861 _('hg rename [OPTION]... SOURCE... DEST')),
2862 _('hg rename [OPTION]... SOURCE... DEST')),
2862 "^revert":
2863 "^revert":
2863 (revert,
2864 (revert,
2864 [('a', 'all', None, _('revert all changes when no arguments given')),
2865 [('a', 'all', None, _('revert all changes when no arguments given')),
2865 ('d', 'date', '', _('tipmost revision matching date')),
2866 ('d', 'date', '', _('tipmost revision matching date')),
2866 ('r', 'rev', '', _('revision to revert to')),
2867 ('r', 'rev', '', _('revision to revert to')),
2867 ('', 'no-backup', None, _('do not save backup copies of files')),
2868 ('', 'no-backup', None, _('do not save backup copies of files')),
2868 ] + walkopts + dryrunopts,
2869 ] + walkopts + dryrunopts,
2869 _('hg revert [OPTION]... [-r REV] [NAME]...')),
2870 _('hg revert [OPTION]... [-r REV] [NAME]...')),
2870 "rollback": (rollback, [], _('hg rollback')),
2871 "rollback": (rollback, [], _('hg rollback')),
2871 "root": (root, [], _('hg root')),
2872 "root": (root, [], _('hg root')),
2872 "showconfig|debugconfig":
2873 "showconfig|debugconfig":
2873 (showconfig,
2874 (showconfig,
2874 [('u', 'untrusted', None, _('show untrusted configuration options'))],
2875 [('u', 'untrusted', None, _('show untrusted configuration options'))],
2875 _('showconfig [-u] [NAME]...')),
2876 _('showconfig [-u] [NAME]...')),
2876 "^serve":
2877 "^serve":
2877 (serve,
2878 (serve,
2878 [('A', 'accesslog', '', _('name of access log file to write to')),
2879 [('A', 'accesslog', '', _('name of access log file to write to')),
2879 ('d', 'daemon', None, _('run server in background')),
2880 ('d', 'daemon', None, _('run server in background')),
2880 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
2881 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
2881 ('E', 'errorlog', '', _('name of error log file to write to')),
2882 ('E', 'errorlog', '', _('name of error log file to write to')),
2882 ('p', 'port', 0, _('port to use (default: 8000)')),
2883 ('p', 'port', 0, _('port to use (default: 8000)')),
2883 ('a', 'address', '', _('address to use')),
2884 ('a', 'address', '', _('address to use')),
2884 ('n', 'name', '',
2885 ('n', 'name', '',
2885 _('name to show in web pages (default: working dir)')),
2886 _('name to show in web pages (default: working dir)')),
2886 ('', 'webdir-conf', '', _('name of the webdir config file'
2887 ('', 'webdir-conf', '', _('name of the webdir config file'
2887 ' (serve more than one repo)')),
2888 ' (serve more than one repo)')),
2888 ('', 'pid-file', '', _('name of file to write process ID to')),
2889 ('', 'pid-file', '', _('name of file to write process ID to')),
2889 ('', 'stdio', None, _('for remote clients')),
2890 ('', 'stdio', None, _('for remote clients')),
2890 ('t', 'templates', '', _('web templates to use')),
2891 ('t', 'templates', '', _('web templates to use')),
2891 ('', 'style', '', _('template style to use')),
2892 ('', 'style', '', _('template style to use')),
2892 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2893 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2893 _('hg serve [OPTION]...')),
2894 _('hg serve [OPTION]...')),
2894 "^status|st":
2895 "^status|st":
2895 (status,
2896 (status,
2896 [('A', 'all', None, _('show status of all files')),
2897 [('A', 'all', None, _('show status of all files')),
2897 ('m', 'modified', None, _('show only modified files')),
2898 ('m', 'modified', None, _('show only modified files')),
2898 ('a', 'added', None, _('show only added files')),
2899 ('a', 'added', None, _('show only added files')),
2899 ('r', 'removed', None, _('show only removed files')),
2900 ('r', 'removed', None, _('show only removed files')),
2900 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
2901 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
2901 ('c', 'clean', None, _('show only files without changes')),
2902 ('c', 'clean', None, _('show only files without changes')),
2902 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2903 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2903 ('i', 'ignored', None, _('show only ignored files')),
2904 ('i', 'ignored', None, _('show only ignored files')),
2904 ('n', 'no-status', None, _('hide status prefix')),
2905 ('n', 'no-status', None, _('hide status prefix')),
2905 ('C', 'copies', None, _('show source of copied files')),
2906 ('C', 'copies', None, _('show source of copied files')),
2906 ('0', 'print0', None,
2907 ('0', 'print0', None,
2907 _('end filenames with NUL, for use with xargs')),
2908 _('end filenames with NUL, for use with xargs')),
2908 ('', 'rev', [], _('show difference from revision')),
2909 ('', 'rev', [], _('show difference from revision')),
2909 ] + walkopts,
2910 ] + walkopts,
2910 _('hg status [OPTION]... [FILE]...')),
2911 _('hg status [OPTION]... [FILE]...')),
2911 "tag":
2912 "tag":
2912 (tag,
2913 (tag,
2913 [('l', 'local', None, _('make the tag local')),
2914 [('l', 'local', None, _('make the tag local')),
2914 ('m', 'message', '', _('message for tag commit log entry')),
2915 ('m', 'message', '', _('message for tag commit log entry')),
2915 ('d', 'date', '', _('record datecode as commit date')),
2916 ('d', 'date', '', _('record datecode as commit date')),
2916 ('u', 'user', '', _('record user as commiter')),
2917 ('u', 'user', '', _('record user as commiter')),
2917 ('r', 'rev', '', _('revision to tag'))],
2918 ('r', 'rev', '', _('revision to tag'))],
2918 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
2919 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
2919 "tags": (tags, [], _('hg tags')),
2920 "tags": (tags, [], _('hg tags')),
2920 "tip":
2921 "tip":
2921 (tip,
2922 (tip,
2922 [('', 'style', '', _('display using template map file')),
2923 [('', 'style', '', _('display using template map file')),
2923 ('p', 'patch', None, _('show patch')),
2924 ('p', 'patch', None, _('show patch')),
2924 ('', 'template', '', _('display with template'))],
2925 ('', 'template', '', _('display with template'))],
2925 _('hg tip [-p]')),
2926 _('hg tip [-p]')),
2926 "unbundle":
2927 "unbundle":
2927 (unbundle,
2928 (unbundle,
2928 [('u', 'update', None,
2929 [('u', 'update', None,
2929 _('update to new tip if changesets were unbundled'))],
2930 _('update to new tip if changesets were unbundled'))],
2930 _('hg unbundle [-u] FILE')),
2931 _('hg unbundle [-u] FILE')),
2931 "^update|up|checkout|co":
2932 "^update|up|checkout|co":
2932 (update,
2933 (update,
2933 [('C', 'clean', None, _('overwrite locally modified files')),
2934 [('C', 'clean', None, _('overwrite locally modified files')),
2934 ('d', 'date', '', _('tipmost revision matching date'))],
2935 ('d', 'date', '', _('tipmost revision matching date'))],
2935 _('hg update [-C] [-d DATE] [REV]')),
2936 _('hg update [-C] [-d DATE] [REV]')),
2936 "verify": (verify, [], _('hg verify')),
2937 "verify": (verify, [], _('hg verify')),
2937 "version": (version_, [], _('hg version')),
2938 "version": (version_, [], _('hg version')),
2938 }
2939 }
2939
2940
2940 norepo = ("clone init version help debugancestor debugcomplete debugdata"
2941 norepo = ("clone init version help debugancestor debugcomplete debugdata"
2941 " debugindex debugindexdot debugdate debuginstall")
2942 " debugindex debugindexdot debugdate debuginstall")
2942 optionalrepo = ("paths serve showconfig")
2943 optionalrepo = ("paths serve showconfig")
2943
2944
2944 def findpossible(ui, cmd):
2945 def findpossible(ui, cmd):
2945 """
2946 """
2946 Return cmd -> (aliases, command table entry)
2947 Return cmd -> (aliases, command table entry)
2947 for each matching command.
2948 for each matching command.
2948 Return debug commands (or their aliases) only if no normal command matches.
2949 Return debug commands (or their aliases) only if no normal command matches.
2949 """
2950 """
2950 choice = {}
2951 choice = {}
2951 debugchoice = {}
2952 debugchoice = {}
2952 for e in table.keys():
2953 for e in table.keys():
2953 aliases = e.lstrip("^").split("|")
2954 aliases = e.lstrip("^").split("|")
2954 found = None
2955 found = None
2955 if cmd in aliases:
2956 if cmd in aliases:
2956 found = cmd
2957 found = cmd
2957 elif not ui.config("ui", "strict"):
2958 elif not ui.config("ui", "strict"):
2958 for a in aliases:
2959 for a in aliases:
2959 if a.startswith(cmd):
2960 if a.startswith(cmd):
2960 found = a
2961 found = a
2961 break
2962 break
2962 if found is not None:
2963 if found is not None:
2963 if aliases[0].startswith("debug") or found.startswith("debug"):
2964 if aliases[0].startswith("debug") or found.startswith("debug"):
2964 debugchoice[found] = (aliases, table[e])
2965 debugchoice[found] = (aliases, table[e])
2965 else:
2966 else:
2966 choice[found] = (aliases, table[e])
2967 choice[found] = (aliases, table[e])
2967
2968
2968 if not choice and debugchoice:
2969 if not choice and debugchoice:
2969 choice = debugchoice
2970 choice = debugchoice
2970
2971
2971 return choice
2972 return choice
2972
2973
2973 def findcmd(ui, cmd):
2974 def findcmd(ui, cmd):
2974 """Return (aliases, command table entry) for command string."""
2975 """Return (aliases, command table entry) for command string."""
2975 choice = findpossible(ui, cmd)
2976 choice = findpossible(ui, cmd)
2976
2977
2977 if choice.has_key(cmd):
2978 if choice.has_key(cmd):
2978 return choice[cmd]
2979 return choice[cmd]
2979
2980
2980 if len(choice) > 1:
2981 if len(choice) > 1:
2981 clist = choice.keys()
2982 clist = choice.keys()
2982 clist.sort()
2983 clist.sort()
2983 raise AmbiguousCommand(cmd, clist)
2984 raise AmbiguousCommand(cmd, clist)
2984
2985
2985 if choice:
2986 if choice:
2986 return choice.values()[0]
2987 return choice.values()[0]
2987
2988
2988 raise UnknownCommand(cmd)
2989 raise UnknownCommand(cmd)
2989
2990
2990 def catchterm(*args):
2991 def catchterm(*args):
2991 raise util.SignalInterrupt
2992 raise util.SignalInterrupt
2992
2993
2993 def run():
2994 def run():
2994 sys.exit(dispatch(sys.argv[1:]))
2995 sys.exit(dispatch(sys.argv[1:]))
2995
2996
2996 class ParseError(Exception):
2997 class ParseError(Exception):
2997 """Exception raised on errors in parsing the command line."""
2998 """Exception raised on errors in parsing the command line."""
2998
2999
2999 def parse(ui, args):
3000 def parse(ui, args):
3000 options = {}
3001 options = {}
3001 cmdoptions = {}
3002 cmdoptions = {}
3002
3003
3003 try:
3004 try:
3004 args = fancyopts.fancyopts(args, globalopts, options)
3005 args = fancyopts.fancyopts(args, globalopts, options)
3005 except fancyopts.getopt.GetoptError, inst:
3006 except fancyopts.getopt.GetoptError, inst:
3006 raise ParseError(None, inst)
3007 raise ParseError(None, inst)
3007
3008
3008 if args:
3009 if args:
3009 cmd, args = args[0], args[1:]
3010 cmd, args = args[0], args[1:]
3010 aliases, i = findcmd(ui, cmd)
3011 aliases, i = findcmd(ui, cmd)
3011 cmd = aliases[0]
3012 cmd = aliases[0]
3012 defaults = ui.config("defaults", cmd)
3013 defaults = ui.config("defaults", cmd)
3013 if defaults:
3014 if defaults:
3014 args = shlex.split(defaults) + args
3015 args = shlex.split(defaults) + args
3015 c = list(i[1])
3016 c = list(i[1])
3016 else:
3017 else:
3017 cmd = None
3018 cmd = None
3018 c = []
3019 c = []
3019
3020
3020 # combine global options into local
3021 # combine global options into local
3021 for o in globalopts:
3022 for o in globalopts:
3022 c.append((o[0], o[1], options[o[1]], o[3]))
3023 c.append((o[0], o[1], options[o[1]], o[3]))
3023
3024
3024 try:
3025 try:
3025 args = fancyopts.fancyopts(args, c, cmdoptions)
3026 args = fancyopts.fancyopts(args, c, cmdoptions)
3026 except fancyopts.getopt.GetoptError, inst:
3027 except fancyopts.getopt.GetoptError, inst:
3027 raise ParseError(cmd, inst)
3028 raise ParseError(cmd, inst)
3028
3029
3029 # separate global options back out
3030 # separate global options back out
3030 for o in globalopts:
3031 for o in globalopts:
3031 n = o[1]
3032 n = o[1]
3032 options[n] = cmdoptions[n]
3033 options[n] = cmdoptions[n]
3033 del cmdoptions[n]
3034 del cmdoptions[n]
3034
3035
3035 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
3036 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
3036
3037
3037 external = {}
3038 external = {}
3038
3039
3039 def findext(name):
3040 def findext(name):
3040 '''return module with given extension name'''
3041 '''return module with given extension name'''
3041 try:
3042 try:
3042 return sys.modules[external[name]]
3043 return sys.modules[external[name]]
3043 except KeyError:
3044 except KeyError:
3044 for k, v in external.iteritems():
3045 for k, v in external.iteritems():
3045 if k.endswith('.' + name) or k.endswith('/' + name) or v == name:
3046 if k.endswith('.' + name) or k.endswith('/' + name) or v == name:
3046 return sys.modules[v]
3047 return sys.modules[v]
3047 raise KeyError(name)
3048 raise KeyError(name)
3048
3049
3049 def load_extensions(ui):
3050 def load_extensions(ui):
3050 added = []
3051 added = []
3051 for ext_name, load_from_name in ui.extensions():
3052 for ext_name, load_from_name in ui.extensions():
3052 if ext_name in external:
3053 if ext_name in external:
3053 continue
3054 continue
3054 try:
3055 try:
3055 if load_from_name:
3056 if load_from_name:
3056 # the module will be loaded in sys.modules
3057 # the module will be loaded in sys.modules
3057 # choose an unique name so that it doesn't
3058 # choose an unique name so that it doesn't
3058 # conflicts with other modules
3059 # conflicts with other modules
3059 module_name = "hgext_%s" % ext_name.replace('.', '_')
3060 module_name = "hgext_%s" % ext_name.replace('.', '_')
3060 mod = imp.load_source(module_name, load_from_name)
3061 mod = imp.load_source(module_name, load_from_name)
3061 else:
3062 else:
3062 def importh(name):
3063 def importh(name):
3063 mod = __import__(name)
3064 mod = __import__(name)
3064 components = name.split('.')
3065 components = name.split('.')
3065 for comp in components[1:]:
3066 for comp in components[1:]:
3066 mod = getattr(mod, comp)
3067 mod = getattr(mod, comp)
3067 return mod
3068 return mod
3068 try:
3069 try:
3069 mod = importh("hgext.%s" % ext_name)
3070 mod = importh("hgext.%s" % ext_name)
3070 except ImportError:
3071 except ImportError:
3071 mod = importh(ext_name)
3072 mod = importh(ext_name)
3072 external[ext_name] = mod.__name__
3073 external[ext_name] = mod.__name__
3073 added.append((mod, ext_name))
3074 added.append((mod, ext_name))
3074 except (util.SignalInterrupt, KeyboardInterrupt):
3075 except (util.SignalInterrupt, KeyboardInterrupt):
3075 raise
3076 raise
3076 except Exception, inst:
3077 except Exception, inst:
3077 ui.warn(_("*** failed to import extension %s: %s\n") %
3078 ui.warn(_("*** failed to import extension %s: %s\n") %
3078 (ext_name, inst))
3079 (ext_name, inst))
3079 if ui.print_exc():
3080 if ui.print_exc():
3080 return 1
3081 return 1
3081
3082
3082 for mod, name in added:
3083 for mod, name in added:
3083 uisetup = getattr(mod, 'uisetup', None)
3084 uisetup = getattr(mod, 'uisetup', None)
3084 if uisetup:
3085 if uisetup:
3085 uisetup(ui)
3086 uisetup(ui)
3086 reposetup = getattr(mod, 'reposetup', None)
3087 reposetup = getattr(mod, 'reposetup', None)
3087 if reposetup:
3088 if reposetup:
3088 hg.repo_setup_hooks.append(reposetup)
3089 hg.repo_setup_hooks.append(reposetup)
3089 cmdtable = getattr(mod, 'cmdtable', {})
3090 cmdtable = getattr(mod, 'cmdtable', {})
3090 overrides = [cmd for cmd in cmdtable if cmd in table]
3091 overrides = [cmd for cmd in cmdtable if cmd in table]
3091 if overrides:
3092 if overrides:
3092 ui.warn(_("extension '%s' overrides commands: %s\n")
3093 ui.warn(_("extension '%s' overrides commands: %s\n")
3093 % (name, " ".join(overrides)))
3094 % (name, " ".join(overrides)))
3094 table.update(cmdtable)
3095 table.update(cmdtable)
3095
3096
3096 def parseconfig(config):
3097 def parseconfig(config):
3097 """parse the --config options from the command line"""
3098 """parse the --config options from the command line"""
3098 parsed = []
3099 parsed = []
3099 for cfg in config:
3100 for cfg in config:
3100 try:
3101 try:
3101 name, value = cfg.split('=', 1)
3102 name, value = cfg.split('=', 1)
3102 section, name = name.split('.', 1)
3103 section, name = name.split('.', 1)
3103 if not section or not name:
3104 if not section or not name:
3104 raise IndexError
3105 raise IndexError
3105 parsed.append((section, name, value))
3106 parsed.append((section, name, value))
3106 except (IndexError, ValueError):
3107 except (IndexError, ValueError):
3107 raise util.Abort(_('malformed --config option: %s') % cfg)
3108 raise util.Abort(_('malformed --config option: %s') % cfg)
3108 return parsed
3109 return parsed
3109
3110
3110 def dispatch(args):
3111 def dispatch(args):
3111 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
3112 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
3112 num = getattr(signal, name, None)
3113 num = getattr(signal, name, None)
3113 if num: signal.signal(num, catchterm)
3114 if num: signal.signal(num, catchterm)
3114
3115
3115 try:
3116 try:
3116 u = ui.ui(traceback='--traceback' in sys.argv[1:])
3117 u = ui.ui(traceback='--traceback' in sys.argv[1:])
3117 except util.Abort, inst:
3118 except util.Abort, inst:
3118 sys.stderr.write(_("abort: %s\n") % inst)
3119 sys.stderr.write(_("abort: %s\n") % inst)
3119 return -1
3120 return -1
3120
3121
3121 load_extensions(u)
3122 load_extensions(u)
3122 u.addreadhook(load_extensions)
3123 u.addreadhook(load_extensions)
3123
3124
3124 try:
3125 try:
3125 cmd, func, args, options, cmdoptions = parse(u, args)
3126 cmd, func, args, options, cmdoptions = parse(u, args)
3126 if options["encoding"]:
3127 if options["encoding"]:
3127 util._encoding = options["encoding"]
3128 util._encoding = options["encoding"]
3128 if options["encodingmode"]:
3129 if options["encodingmode"]:
3129 util._encodingmode = options["encodingmode"]
3130 util._encodingmode = options["encodingmode"]
3130 if options["time"]:
3131 if options["time"]:
3131 def get_times():
3132 def get_times():
3132 t = os.times()
3133 t = os.times()
3133 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
3134 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
3134 t = (t[0], t[1], t[2], t[3], time.clock())
3135 t = (t[0], t[1], t[2], t[3], time.clock())
3135 return t
3136 return t
3136 s = get_times()
3137 s = get_times()
3137 def print_time():
3138 def print_time():
3138 t = get_times()
3139 t = get_times()
3139 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
3140 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
3140 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
3141 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
3141 atexit.register(print_time)
3142 atexit.register(print_time)
3142
3143
3143 # enter the debugger before command execution
3144 # enter the debugger before command execution
3144 if options['debugger']:
3145 if options['debugger']:
3145 pdb.set_trace()
3146 pdb.set_trace()
3146
3147
3147 try:
3148 try:
3148 if options['cwd']:
3149 if options['cwd']:
3149 os.chdir(options['cwd'])
3150 os.chdir(options['cwd'])
3150
3151
3151 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3152 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3152 not options["noninteractive"], options["traceback"],
3153 not options["noninteractive"], options["traceback"],
3153 parseconfig(options["config"]))
3154 parseconfig(options["config"]))
3154
3155
3155 path = u.expandpath(options["repository"]) or ""
3156 path = u.expandpath(options["repository"]) or ""
3156 repo = path and hg.repository(u, path=path) or None
3157 repo = path and hg.repository(u, path=path) or None
3157 if repo and not repo.local():
3158 if repo and not repo.local():
3158 raise util.Abort(_("repository '%s' is not local") % path)
3159 raise util.Abort(_("repository '%s' is not local") % path)
3159
3160
3160 if options['help']:
3161 if options['help']:
3161 return help_(u, cmd, options['version'])
3162 return help_(u, cmd, options['version'])
3162 elif options['version']:
3163 elif options['version']:
3163 return version_(u)
3164 return version_(u)
3164 elif not cmd:
3165 elif not cmd:
3165 return help_(u, 'shortlist')
3166 return help_(u, 'shortlist')
3166
3167
3167 if cmd not in norepo.split():
3168 if cmd not in norepo.split():
3168 try:
3169 try:
3169 if not repo:
3170 if not repo:
3170 repo = hg.repository(u, path=path)
3171 repo = hg.repository(u, path=path)
3171 u = repo.ui
3172 u = repo.ui
3172 except hg.RepoError:
3173 except hg.RepoError:
3173 if cmd not in optionalrepo.split():
3174 if cmd not in optionalrepo.split():
3174 raise
3175 raise
3175 d = lambda: func(u, repo, *args, **cmdoptions)
3176 d = lambda: func(u, repo, *args, **cmdoptions)
3176 else:
3177 else:
3177 d = lambda: func(u, *args, **cmdoptions)
3178 d = lambda: func(u, *args, **cmdoptions)
3178
3179
3179 try:
3180 try:
3180 if options['profile']:
3181 if options['profile']:
3181 import hotshot, hotshot.stats
3182 import hotshot, hotshot.stats
3182 prof = hotshot.Profile("hg.prof")
3183 prof = hotshot.Profile("hg.prof")
3183 try:
3184 try:
3184 try:
3185 try:
3185 return prof.runcall(d)
3186 return prof.runcall(d)
3186 except:
3187 except:
3187 try:
3188 try:
3188 u.warn(_('exception raised - generating '
3189 u.warn(_('exception raised - generating '
3189 'profile anyway\n'))
3190 'profile anyway\n'))
3190 except:
3191 except:
3191 pass
3192 pass
3192 raise
3193 raise
3193 finally:
3194 finally:
3194 prof.close()
3195 prof.close()
3195 stats = hotshot.stats.load("hg.prof")
3196 stats = hotshot.stats.load("hg.prof")
3196 stats.strip_dirs()
3197 stats.strip_dirs()
3197 stats.sort_stats('time', 'calls')
3198 stats.sort_stats('time', 'calls')
3198 stats.print_stats(40)
3199 stats.print_stats(40)
3199 elif options['lsprof']:
3200 elif options['lsprof']:
3200 try:
3201 try:
3201 from mercurial import lsprof
3202 from mercurial import lsprof
3202 except ImportError:
3203 except ImportError:
3203 raise util.Abort(_(
3204 raise util.Abort(_(
3204 'lsprof not available - install from '
3205 'lsprof not available - install from '
3205 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
3206 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
3206 p = lsprof.Profiler()
3207 p = lsprof.Profiler()
3207 p.enable(subcalls=True)
3208 p.enable(subcalls=True)
3208 try:
3209 try:
3209 return d()
3210 return d()
3210 finally:
3211 finally:
3211 p.disable()
3212 p.disable()
3212 stats = lsprof.Stats(p.getstats())
3213 stats = lsprof.Stats(p.getstats())
3213 stats.sort()
3214 stats.sort()
3214 stats.pprint(top=10, file=sys.stderr, climit=5)
3215 stats.pprint(top=10, file=sys.stderr, climit=5)
3215 else:
3216 else:
3216 return d()
3217 return d()
3217 finally:
3218 finally:
3218 u.flush()
3219 u.flush()
3219 except:
3220 except:
3220 # enter the debugger when we hit an exception
3221 # enter the debugger when we hit an exception
3221 if options['debugger']:
3222 if options['debugger']:
3222 pdb.post_mortem(sys.exc_info()[2])
3223 pdb.post_mortem(sys.exc_info()[2])
3223 u.print_exc()
3224 u.print_exc()
3224 raise
3225 raise
3225 except ParseError, inst:
3226 except ParseError, inst:
3226 if inst.args[0]:
3227 if inst.args[0]:
3227 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
3228 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
3228 help_(u, inst.args[0])
3229 help_(u, inst.args[0])
3229 else:
3230 else:
3230 u.warn(_("hg: %s\n") % inst.args[1])
3231 u.warn(_("hg: %s\n") % inst.args[1])
3231 help_(u, 'shortlist')
3232 help_(u, 'shortlist')
3232 except AmbiguousCommand, inst:
3233 except AmbiguousCommand, inst:
3233 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
3234 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
3234 (inst.args[0], " ".join(inst.args[1])))
3235 (inst.args[0], " ".join(inst.args[1])))
3235 except UnknownCommand, inst:
3236 except UnknownCommand, inst:
3236 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
3237 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
3237 help_(u, 'shortlist')
3238 help_(u, 'shortlist')
3238 except hg.RepoError, inst:
3239 except hg.RepoError, inst:
3239 u.warn(_("abort: %s!\n") % inst)
3240 u.warn(_("abort: %s!\n") % inst)
3240 except lock.LockHeld, inst:
3241 except lock.LockHeld, inst:
3241 if inst.errno == errno.ETIMEDOUT:
3242 if inst.errno == errno.ETIMEDOUT:
3242 reason = _('timed out waiting for lock held by %s') % inst.locker
3243 reason = _('timed out waiting for lock held by %s') % inst.locker
3243 else:
3244 else:
3244 reason = _('lock held by %s') % inst.locker
3245 reason = _('lock held by %s') % inst.locker
3245 u.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
3246 u.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
3246 except lock.LockUnavailable, inst:
3247 except lock.LockUnavailable, inst:
3247 u.warn(_("abort: could not lock %s: %s\n") %
3248 u.warn(_("abort: could not lock %s: %s\n") %
3248 (inst.desc or inst.filename, inst.strerror))
3249 (inst.desc or inst.filename, inst.strerror))
3249 except revlog.RevlogError, inst:
3250 except revlog.RevlogError, inst:
3250 u.warn(_("abort: %s!\n") % inst)
3251 u.warn(_("abort: %s!\n") % inst)
3251 except util.SignalInterrupt:
3252 except util.SignalInterrupt:
3252 u.warn(_("killed!\n"))
3253 u.warn(_("killed!\n"))
3253 except KeyboardInterrupt:
3254 except KeyboardInterrupt:
3254 try:
3255 try:
3255 u.warn(_("interrupted!\n"))
3256 u.warn(_("interrupted!\n"))
3256 except IOError, inst:
3257 except IOError, inst:
3257 if inst.errno == errno.EPIPE:
3258 if inst.errno == errno.EPIPE:
3258 if u.debugflag:
3259 if u.debugflag:
3259 u.warn(_("\nbroken pipe\n"))
3260 u.warn(_("\nbroken pipe\n"))
3260 else:
3261 else:
3261 raise
3262 raise
3262 except socket.error, inst:
3263 except socket.error, inst:
3263 u.warn(_("abort: %s\n") % inst[1])
3264 u.warn(_("abort: %s\n") % inst[1])
3264 except IOError, inst:
3265 except IOError, inst:
3265 if hasattr(inst, "code"):
3266 if hasattr(inst, "code"):
3266 u.warn(_("abort: %s\n") % inst)
3267 u.warn(_("abort: %s\n") % inst)
3267 elif hasattr(inst, "reason"):
3268 elif hasattr(inst, "reason"):
3268 try: # usually it is in the form (errno, strerror)
3269 try: # usually it is in the form (errno, strerror)
3269 reason = inst.reason.args[1]
3270 reason = inst.reason.args[1]
3270 except: # it might be anything, for example a string
3271 except: # it might be anything, for example a string
3271 reason = inst.reason
3272 reason = inst.reason
3272 u.warn(_("abort: error: %s\n") % reason)
3273 u.warn(_("abort: error: %s\n") % reason)
3273 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
3274 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
3274 if u.debugflag:
3275 if u.debugflag:
3275 u.warn(_("broken pipe\n"))
3276 u.warn(_("broken pipe\n"))
3276 elif getattr(inst, "strerror", None):
3277 elif getattr(inst, "strerror", None):
3277 if getattr(inst, "filename", None):
3278 if getattr(inst, "filename", None):
3278 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3279 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3279 else:
3280 else:
3280 u.warn(_("abort: %s\n") % inst.strerror)
3281 u.warn(_("abort: %s\n") % inst.strerror)
3281 else:
3282 else:
3282 raise
3283 raise
3283 except OSError, inst:
3284 except OSError, inst:
3284 if getattr(inst, "filename", None):
3285 if getattr(inst, "filename", None):
3285 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3286 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3286 else:
3287 else:
3287 u.warn(_("abort: %s\n") % inst.strerror)
3288 u.warn(_("abort: %s\n") % inst.strerror)
3288 except util.UnexpectedOutput, inst:
3289 except util.UnexpectedOutput, inst:
3289 u.warn(_("abort: %s") % inst[0])
3290 u.warn(_("abort: %s") % inst[0])
3290 if not isinstance(inst[1], basestring):
3291 if not isinstance(inst[1], basestring):
3291 u.warn(" %r\n" % (inst[1],))
3292 u.warn(" %r\n" % (inst[1],))
3292 elif not inst[1]:
3293 elif not inst[1]:
3293 u.warn(_(" empty string\n"))
3294 u.warn(_(" empty string\n"))
3294 else:
3295 else:
3295 u.warn("\n%r\n" % util.ellipsis(inst[1]))
3296 u.warn("\n%r\n" % util.ellipsis(inst[1]))
3296 except util.Abort, inst:
3297 except util.Abort, inst:
3297 u.warn(_("abort: %s\n") % inst)
3298 u.warn(_("abort: %s\n") % inst)
3298 except TypeError, inst:
3299 except TypeError, inst:
3299 # was this an argument error?
3300 # was this an argument error?
3300 tb = traceback.extract_tb(sys.exc_info()[2])
3301 tb = traceback.extract_tb(sys.exc_info()[2])
3301 if len(tb) > 2: # no
3302 if len(tb) > 2: # no
3302 raise
3303 raise
3303 u.debug(inst, "\n")
3304 u.debug(inst, "\n")
3304 u.warn(_("%s: invalid arguments\n") % cmd)
3305 u.warn(_("%s: invalid arguments\n") % cmd)
3305 help_(u, cmd)
3306 help_(u, cmd)
3306 except SystemExit, inst:
3307 except SystemExit, inst:
3307 # Commands shouldn't sys.exit directly, but give a return code.
3308 # Commands shouldn't sys.exit directly, but give a return code.
3308 # Just in case catch this and and pass exit code to caller.
3309 # Just in case catch this and and pass exit code to caller.
3309 return inst.code
3310 return inst.code
3310 except:
3311 except:
3311 u.warn(_("** unknown exception encountered, details follow\n"))
3312 u.warn(_("** unknown exception encountered, details follow\n"))
3312 u.warn(_("** report bug details to "
3313 u.warn(_("** report bug details to "
3313 "http://www.selenic.com/mercurial/bts\n"))
3314 "http://www.selenic.com/mercurial/bts\n"))
3314 u.warn(_("** or mercurial@selenic.com\n"))
3315 u.warn(_("** or mercurial@selenic.com\n"))
3315 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
3316 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
3316 % version.get_version())
3317 % version.get_version())
3317 raise
3318 raise
3318
3319
3319 return -1
3320 return -1
General Comments 0
You need to be logged in to leave comments. Login now