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