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