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