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