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