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