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