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