##// END OF EJS Templates
help: don't display bogus help messages for invalid aliases
Brodie Rao -
r10021:0022f5c5 default
parent child Browse files
Show More
@@ -1,3715 +1,3720 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 of the
6 6 # GNU General Public License version 2, incorporated herein by reference.
7 7
8 8 from node import hex, nullid, nullrev, short
9 9 from lock import release
10 10 from i18n import _, gettext
11 11 import os, re, sys, difflib, time, tempfile
12 12 import hg, util, revlog, bundlerepo, extensions, copies, error
13 13 import patch, help, mdiff, url, encoding
14 14 import archival, changegroup, cmdutil, sshserver, hbisect
15 15 from hgweb import server
16 16 import merge as merge_
17 17 import minirst
18 18
19 19 # Commands start here, listed alphabetically
20 20
21 21 def add(ui, repo, *pats, **opts):
22 22 """add the specified files on the next commit
23 23
24 24 Schedule files to be version controlled and added to the
25 25 repository.
26 26
27 27 The files will be added to the repository at the next commit. To
28 28 undo an add before that, see hg forget.
29 29
30 30 If no names are given, add all files to the repository.
31 31 """
32 32
33 33 bad = []
34 34 names = []
35 35 m = cmdutil.match(repo, pats, opts)
36 36 oldbad = m.bad
37 37 m.bad = lambda x,y: bad.append(x) or oldbad(x,y)
38 38
39 39 for f in repo.walk(m):
40 40 exact = m.exact(f)
41 41 if exact or f not in repo.dirstate:
42 42 names.append(f)
43 43 if ui.verbose or not exact:
44 44 ui.status(_('adding %s\n') % m.rel(f))
45 45 if not opts.get('dry_run'):
46 46 bad += [f for f in repo.add(names) if f in m.files()]
47 47 return bad and 1 or 0
48 48
49 49 def addremove(ui, repo, *pats, **opts):
50 50 """add all new files, delete all missing files
51 51
52 52 Add all new files and remove all missing files from the
53 53 repository.
54 54
55 55 New files are ignored if they match any of the patterns in
56 56 .hgignore. As with add, these changes take effect at the next
57 57 commit.
58 58
59 59 Use the -s/--similarity option to detect renamed files. With a
60 60 parameter greater than 0, this compares every removed file with
61 61 every added file and records those similar enough as renames. This
62 62 option takes a percentage between 0 (disabled) and 100 (files must
63 63 be identical) as its parameter. Detecting renamed files this way
64 64 can be expensive.
65 65 """
66 66 try:
67 67 sim = float(opts.get('similarity') or 0)
68 68 except ValueError:
69 69 raise util.Abort(_('similarity must be a number'))
70 70 if sim < 0 or sim > 100:
71 71 raise util.Abort(_('similarity must be between 0 and 100'))
72 72 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
73 73
74 74 def annotate(ui, repo, *pats, **opts):
75 75 """show changeset information by line for each file
76 76
77 77 List changes in files, showing the revision id responsible for
78 78 each line
79 79
80 80 This command is useful for discovering when a change was made and
81 81 by whom.
82 82
83 83 Without the -a/--text option, annotate will avoid processing files
84 84 it detects as binary. With -a, annotate will annotate the file
85 85 anyway, although the results will probably be neither useful
86 86 nor desirable.
87 87 """
88 88 datefunc = ui.quiet and util.shortdate or util.datestr
89 89 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
90 90
91 91 if not pats:
92 92 raise util.Abort(_('at least one filename or pattern is required'))
93 93
94 94 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
95 95 ('number', lambda x: str(x[0].rev())),
96 96 ('changeset', lambda x: short(x[0].node())),
97 97 ('date', getdate),
98 98 ('follow', lambda x: x[0].path()),
99 99 ]
100 100
101 101 if (not opts.get('user') and not opts.get('changeset') and not opts.get('date')
102 102 and not opts.get('follow')):
103 103 opts['number'] = 1
104 104
105 105 linenumber = opts.get('line_number') is not None
106 106 if (linenumber and (not opts.get('changeset')) and (not opts.get('number'))):
107 107 raise util.Abort(_('at least one of -n/-c is required for -l'))
108 108
109 109 funcmap = [func for op, func in opmap if opts.get(op)]
110 110 if linenumber:
111 111 lastfunc = funcmap[-1]
112 112 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
113 113
114 114 ctx = repo[opts.get('rev')]
115 115
116 116 m = cmdutil.match(repo, pats, opts)
117 117 for abs in ctx.walk(m):
118 118 fctx = ctx[abs]
119 119 if not opts.get('text') and util.binary(fctx.data()):
120 120 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
121 121 continue
122 122
123 123 lines = fctx.annotate(follow=opts.get('follow'),
124 124 linenumber=linenumber)
125 125 pieces = []
126 126
127 127 for f in funcmap:
128 128 l = [f(n) for n, dummy in lines]
129 129 if l:
130 130 ml = max(map(len, l))
131 131 pieces.append(["%*s" % (ml, x) for x in l])
132 132
133 133 if pieces:
134 134 for p, l in zip(zip(*pieces), lines):
135 135 ui.write("%s: %s" % (" ".join(p), l[1]))
136 136
137 137 def archive(ui, repo, dest, **opts):
138 138 '''create an unversioned archive of a repository revision
139 139
140 140 By default, the revision used is the parent of the working
141 141 directory; use -r/--rev to specify a different revision.
142 142
143 143 To specify the type of archive to create, use -t/--type. Valid
144 144 types are:
145 145
146 146 :``files``: a directory full of files (default)
147 147 :``tar``: tar archive, uncompressed
148 148 :``tbz2``: tar archive, compressed using bzip2
149 149 :``tgz``: tar archive, compressed using gzip
150 150 :``uzip``: zip archive, uncompressed
151 151 :``zip``: zip archive, compressed using deflate
152 152
153 153 The exact name of the destination archive or directory is given
154 154 using a format string; see 'hg help export' for details.
155 155
156 156 Each member added to an archive file has a directory prefix
157 157 prepended. Use -p/--prefix to specify a format string for the
158 158 prefix. The default is the basename of the archive, with suffixes
159 159 removed.
160 160 '''
161 161
162 162 ctx = repo[opts.get('rev')]
163 163 if not ctx:
164 164 raise util.Abort(_('no working directory: please specify a revision'))
165 165 node = ctx.node()
166 166 dest = cmdutil.make_filename(repo, dest, node)
167 167 if os.path.realpath(dest) == repo.root:
168 168 raise util.Abort(_('repository root cannot be destination'))
169 169 matchfn = cmdutil.match(repo, [], opts)
170 170 kind = opts.get('type') or 'files'
171 171 prefix = opts.get('prefix')
172 172 if dest == '-':
173 173 if kind == 'files':
174 174 raise util.Abort(_('cannot archive plain files to stdout'))
175 175 dest = sys.stdout
176 176 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
177 177 prefix = cmdutil.make_filename(repo, prefix, node)
178 178 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
179 179 matchfn, prefix)
180 180
181 181 def backout(ui, repo, node=None, rev=None, **opts):
182 182 '''reverse effect of earlier changeset
183 183
184 184 Commit the backed out changes as a new changeset. The new
185 185 changeset is a child of the backed out changeset.
186 186
187 187 If you backout a changeset other than the tip, a new head is
188 188 created. This head will be the new tip and you should merge this
189 189 backout changeset with another head.
190 190
191 191 The --merge option remembers the parent of the working directory
192 192 before starting the backout, then merges the new head with that
193 193 changeset afterwards. This saves you from doing the merge by hand.
194 194 The result of this merge is not committed, as with a normal merge.
195 195
196 196 See 'hg help dates' for a list of formats valid for -d/--date.
197 197 '''
198 198 if rev and node:
199 199 raise util.Abort(_("please specify just one revision"))
200 200
201 201 if not rev:
202 202 rev = node
203 203
204 204 if not rev:
205 205 raise util.Abort(_("please specify a revision to backout"))
206 206
207 207 date = opts.get('date')
208 208 if date:
209 209 opts['date'] = util.parsedate(date)
210 210
211 211 cmdutil.bail_if_changed(repo)
212 212 node = repo.lookup(rev)
213 213
214 214 op1, op2 = repo.dirstate.parents()
215 215 a = repo.changelog.ancestor(op1, node)
216 216 if a != node:
217 217 raise util.Abort(_('cannot backout change on a different branch'))
218 218
219 219 p1, p2 = repo.changelog.parents(node)
220 220 if p1 == nullid:
221 221 raise util.Abort(_('cannot backout a change with no parents'))
222 222 if p2 != nullid:
223 223 if not opts.get('parent'):
224 224 raise util.Abort(_('cannot backout a merge changeset without '
225 225 '--parent'))
226 226 p = repo.lookup(opts['parent'])
227 227 if p not in (p1, p2):
228 228 raise util.Abort(_('%s is not a parent of %s') %
229 229 (short(p), short(node)))
230 230 parent = p
231 231 else:
232 232 if opts.get('parent'):
233 233 raise util.Abort(_('cannot use --parent on non-merge changeset'))
234 234 parent = p1
235 235
236 236 # the backout should appear on the same branch
237 237 branch = repo.dirstate.branch()
238 238 hg.clean(repo, node, show_stats=False)
239 239 repo.dirstate.setbranch(branch)
240 240 revert_opts = opts.copy()
241 241 revert_opts['date'] = None
242 242 revert_opts['all'] = True
243 243 revert_opts['rev'] = hex(parent)
244 244 revert_opts['no_backup'] = None
245 245 revert(ui, repo, **revert_opts)
246 246 commit_opts = opts.copy()
247 247 commit_opts['addremove'] = False
248 248 if not commit_opts['message'] and not commit_opts['logfile']:
249 249 # we don't translate commit messages
250 250 commit_opts['message'] = "Backed out changeset %s" % short(node)
251 251 commit_opts['force_editor'] = True
252 252 commit(ui, repo, **commit_opts)
253 253 def nice(node):
254 254 return '%d:%s' % (repo.changelog.rev(node), short(node))
255 255 ui.status(_('changeset %s backs out changeset %s\n') %
256 256 (nice(repo.changelog.tip()), nice(node)))
257 257 if op1 != node:
258 258 hg.clean(repo, op1, show_stats=False)
259 259 if opts.get('merge'):
260 260 ui.status(_('merging with changeset %s\n') % nice(repo.changelog.tip()))
261 261 hg.merge(repo, hex(repo.changelog.tip()))
262 262 else:
263 263 ui.status(_('the backout changeset is a new head - '
264 264 'do not forget to merge\n'))
265 265 ui.status(_('(use "backout --merge" '
266 266 'if you want to auto-merge)\n'))
267 267
268 268 def bisect(ui, repo, rev=None, extra=None, command=None,
269 269 reset=None, good=None, bad=None, skip=None, noupdate=None):
270 270 """subdivision search of changesets
271 271
272 272 This command helps to find changesets which introduce problems. To
273 273 use, mark the earliest changeset you know exhibits the problem as
274 274 bad, then mark the latest changeset which is free from the problem
275 275 as good. Bisect will update your working directory to a revision
276 276 for testing (unless the -U/--noupdate option is specified). Once
277 277 you have performed tests, mark the working directory as good or
278 278 bad, and bisect will either update to another candidate changeset
279 279 or announce that it has found the bad revision.
280 280
281 281 As a shortcut, you can also use the revision argument to mark a
282 282 revision as good or bad without checking it out first.
283 283
284 284 If you supply a command, it will be used for automatic bisection.
285 285 Its exit status will be used to mark revisions as good or bad:
286 286 status 0 means good, 125 means to skip the revision, 127
287 287 (command not found) will abort the bisection, and any other
288 288 non-zero exit status means the revision is bad.
289 289 """
290 290 def print_result(nodes, good):
291 291 displayer = cmdutil.show_changeset(ui, repo, {})
292 292 if len(nodes) == 1:
293 293 # narrowed it down to a single revision
294 294 if good:
295 295 ui.write(_("The first good revision is:\n"))
296 296 else:
297 297 ui.write(_("The first bad revision is:\n"))
298 298 displayer.show(repo[nodes[0]])
299 299 else:
300 300 # multiple possible revisions
301 301 if good:
302 302 ui.write(_("Due to skipped revisions, the first "
303 303 "good revision could be any of:\n"))
304 304 else:
305 305 ui.write(_("Due to skipped revisions, the first "
306 306 "bad revision could be any of:\n"))
307 307 for n in nodes:
308 308 displayer.show(repo[n])
309 309
310 310 def check_state(state, interactive=True):
311 311 if not state['good'] or not state['bad']:
312 312 if (good or bad or skip or reset) and interactive:
313 313 return
314 314 if not state['good']:
315 315 raise util.Abort(_('cannot bisect (no known good revisions)'))
316 316 else:
317 317 raise util.Abort(_('cannot bisect (no known bad revisions)'))
318 318 return True
319 319
320 320 # backward compatibility
321 321 if rev in "good bad reset init".split():
322 322 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
323 323 cmd, rev, extra = rev, extra, None
324 324 if cmd == "good":
325 325 good = True
326 326 elif cmd == "bad":
327 327 bad = True
328 328 else:
329 329 reset = True
330 330 elif extra or good + bad + skip + reset + bool(command) > 1:
331 331 raise util.Abort(_('incompatible arguments'))
332 332
333 333 if reset:
334 334 p = repo.join("bisect.state")
335 335 if os.path.exists(p):
336 336 os.unlink(p)
337 337 return
338 338
339 339 state = hbisect.load_state(repo)
340 340
341 341 if command:
342 342 changesets = 1
343 343 try:
344 344 while changesets:
345 345 # update state
346 346 status = util.system(command)
347 347 if status == 125:
348 348 transition = "skip"
349 349 elif status == 0:
350 350 transition = "good"
351 351 # status < 0 means process was killed
352 352 elif status == 127:
353 353 raise util.Abort(_("failed to execute %s") % command)
354 354 elif status < 0:
355 355 raise util.Abort(_("%s killed") % command)
356 356 else:
357 357 transition = "bad"
358 358 ctx = repo[rev or '.']
359 359 state[transition].append(ctx.node())
360 360 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
361 361 check_state(state, interactive=False)
362 362 # bisect
363 363 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
364 364 # update to next check
365 365 cmdutil.bail_if_changed(repo)
366 366 hg.clean(repo, nodes[0], show_stats=False)
367 367 finally:
368 368 hbisect.save_state(repo, state)
369 369 return print_result(nodes, good)
370 370
371 371 # update state
372 372 node = repo.lookup(rev or '.')
373 373 if good or bad or skip:
374 374 if good:
375 375 state['good'].append(node)
376 376 elif bad:
377 377 state['bad'].append(node)
378 378 elif skip:
379 379 state['skip'].append(node)
380 380 hbisect.save_state(repo, state)
381 381
382 382 if not check_state(state):
383 383 return
384 384
385 385 # actually bisect
386 386 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
387 387 if changesets == 0:
388 388 print_result(nodes, good)
389 389 else:
390 390 assert len(nodes) == 1 # only a single node can be tested next
391 391 node = nodes[0]
392 392 # compute the approximate number of remaining tests
393 393 tests, size = 0, 2
394 394 while size <= changesets:
395 395 tests, size = tests + 1, size * 2
396 396 rev = repo.changelog.rev(node)
397 397 ui.write(_("Testing changeset %d:%s "
398 398 "(%d changesets remaining, ~%d tests)\n")
399 399 % (rev, short(node), changesets, tests))
400 400 if not noupdate:
401 401 cmdutil.bail_if_changed(repo)
402 402 return hg.clean(repo, node)
403 403
404 404 def branch(ui, repo, label=None, **opts):
405 405 """set or show the current branch name
406 406
407 407 With no argument, show the current branch name. With one argument,
408 408 set the working directory branch name (the branch will not exist
409 409 in the repository until the next commit). Standard practice
410 410 recommends that primary development take place on the 'default'
411 411 branch.
412 412
413 413 Unless -f/--force is specified, branch will not let you set a
414 414 branch name that already exists, even if it's inactive.
415 415
416 416 Use -C/--clean to reset the working directory branch to that of
417 417 the parent of the working directory, negating a previous branch
418 418 change.
419 419
420 420 Use the command 'hg update' to switch to an existing branch. Use
421 421 'hg commit --close-branch' to mark this branch as closed.
422 422 """
423 423
424 424 if opts.get('clean'):
425 425 label = repo[None].parents()[0].branch()
426 426 repo.dirstate.setbranch(label)
427 427 ui.status(_('reset working directory to branch %s\n') % label)
428 428 elif label:
429 429 if not opts.get('force') and label in repo.branchtags():
430 430 if label not in [p.branch() for p in repo.parents()]:
431 431 raise util.Abort(_('a branch of the same name already exists'
432 432 ' (use --force to override)'))
433 433 repo.dirstate.setbranch(encoding.fromlocal(label))
434 434 ui.status(_('marked working directory as branch %s\n') % label)
435 435 else:
436 436 ui.write("%s\n" % encoding.tolocal(repo.dirstate.branch()))
437 437
438 438 def branches(ui, repo, active=False, closed=False):
439 439 """list repository named branches
440 440
441 441 List the repository's named branches, indicating which ones are
442 442 inactive. If -c/--closed is specified, also list branches which have
443 443 been marked closed (see hg commit --close-branch).
444 444
445 445 If -a/--active is specified, only show active branches. A branch
446 446 is considered active if it contains repository heads.
447 447
448 448 Use the command 'hg update' to switch to an existing branch.
449 449 """
450 450
451 451 hexfunc = ui.debugflag and hex or short
452 452 activebranches = [repo[n].branch() for n in repo.heads()]
453 453 def testactive(tag, node):
454 454 realhead = tag in activebranches
455 455 open = node in repo.branchheads(tag, closed=False)
456 456 return realhead and open
457 457 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
458 458 for tag, node in repo.branchtags().items()],
459 459 reverse=True)
460 460
461 461 for isactive, node, tag in branches:
462 462 if (not active) or isactive:
463 463 encodedtag = encoding.tolocal(tag)
464 464 if ui.quiet:
465 465 ui.write("%s\n" % encodedtag)
466 466 else:
467 467 hn = repo.lookup(node)
468 468 if isactive:
469 469 notice = ''
470 470 elif hn not in repo.branchheads(tag, closed=False):
471 471 if not closed:
472 472 continue
473 473 notice = _(' (closed)')
474 474 else:
475 475 notice = _(' (inactive)')
476 476 rev = str(node).rjust(31 - encoding.colwidth(encodedtag))
477 477 data = encodedtag, rev, hexfunc(hn), notice
478 478 ui.write("%s %s:%s%s\n" % data)
479 479
480 480 def bundle(ui, repo, fname, dest=None, **opts):
481 481 """create a changegroup file
482 482
483 483 Generate a compressed changegroup file collecting changesets not
484 484 known to be in another repository.
485 485
486 486 If no destination repository is specified the destination is
487 487 assumed to have all the nodes specified by one or more --base
488 488 parameters. To create a bundle containing all changesets, use
489 489 -a/--all (or --base null).
490 490
491 491 You can change compression method with the -t/--type option.
492 492 The available compression methods are: none, bzip2, and
493 493 gzip (by default, bundles are compressed using bzip2).
494 494
495 495 The bundle file can then be transferred using conventional means
496 496 and applied to another repository with the unbundle or pull
497 497 command. This is useful when direct push and pull are not
498 498 available or when exporting an entire repository is undesirable.
499 499
500 500 Applying bundles preserves all changeset contents including
501 501 permissions, copy/rename information, and revision history.
502 502 """
503 503 revs = opts.get('rev') or None
504 504 if revs:
505 505 revs = [repo.lookup(rev) for rev in revs]
506 506 if opts.get('all'):
507 507 base = ['null']
508 508 else:
509 509 base = opts.get('base')
510 510 if base:
511 511 if dest:
512 512 raise util.Abort(_("--base is incompatible with specifying "
513 513 "a destination"))
514 514 base = [repo.lookup(rev) for rev in base]
515 515 # create the right base
516 516 # XXX: nodesbetween / changegroup* should be "fixed" instead
517 517 o = []
518 518 has = set((nullid,))
519 519 for n in base:
520 520 has.update(repo.changelog.reachable(n))
521 521 if revs:
522 522 visit = list(revs)
523 523 else:
524 524 visit = repo.changelog.heads()
525 525 seen = {}
526 526 while visit:
527 527 n = visit.pop(0)
528 528 parents = [p for p in repo.changelog.parents(n) if p not in has]
529 529 if len(parents) == 0:
530 530 o.insert(0, n)
531 531 else:
532 532 for p in parents:
533 533 if p not in seen:
534 534 seen[p] = 1
535 535 visit.append(p)
536 536 else:
537 537 dest, revs, checkout = hg.parseurl(
538 538 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
539 539 other = hg.repository(cmdutil.remoteui(repo, opts), dest)
540 540 o = repo.findoutgoing(other, force=opts.get('force'))
541 541
542 542 if revs:
543 543 cg = repo.changegroupsubset(o, revs, 'bundle')
544 544 else:
545 545 cg = repo.changegroup(o, 'bundle')
546 546
547 547 bundletype = opts.get('type', 'bzip2').lower()
548 548 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
549 549 bundletype = btypes.get(bundletype)
550 550 if bundletype not in changegroup.bundletypes:
551 551 raise util.Abort(_('unknown bundle type specified with --type'))
552 552
553 553 changegroup.writebundle(cg, fname, bundletype)
554 554
555 555 def cat(ui, repo, file1, *pats, **opts):
556 556 """output the current or given revision of files
557 557
558 558 Print the specified files as they were at the given revision. If
559 559 no revision is given, the parent of the working directory is used,
560 560 or tip if no revision is checked out.
561 561
562 562 Output may be to a file, in which case the name of the file is
563 563 given using a format string. The formatting rules are the same as
564 564 for the export command, with the following additions:
565 565
566 566 :``%s``: basename of file being printed
567 567 :``%d``: dirname of file being printed, or '.' if in repository root
568 568 :``%p``: root-relative path name of file being printed
569 569 """
570 570 ctx = repo[opts.get('rev')]
571 571 err = 1
572 572 m = cmdutil.match(repo, (file1,) + pats, opts)
573 573 for abs in ctx.walk(m):
574 574 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
575 575 data = ctx[abs].data()
576 576 if opts.get('decode'):
577 577 data = repo.wwritedata(abs, data)
578 578 fp.write(data)
579 579 err = 0
580 580 return err
581 581
582 582 def clone(ui, source, dest=None, **opts):
583 583 """make a copy of an existing repository
584 584
585 585 Create a copy of an existing repository in a new directory.
586 586
587 587 If no destination directory name is specified, it defaults to the
588 588 basename of the source.
589 589
590 590 The location of the source is added to the new repository's
591 591 .hg/hgrc file, as the default to be used for future pulls.
592 592
593 593 See 'hg help urls' for valid source format details.
594 594
595 595 It is possible to specify an ``ssh://`` URL as the destination, but no
596 596 .hg/hgrc and working directory will be created on the remote side.
597 597 Please see 'hg help urls' for important details about ``ssh://`` URLs.
598 598
599 599 If the -U/--noupdate option is specified, the new clone will contain
600 600 only a repository (.hg) and no working copy (the working copy parent
601 601 will be the null changeset). Otherwise, clone will initially check
602 602 out (in order of precedence):
603 603
604 604 a) the changeset, tag or branch specified with -u/--updaterev
605 605 b) the changeset, tag or branch given with the first -r/--rev
606 606 c) the head of the default branch
607 607
608 608 Use 'hg clone -u . src dst' to checkout the source repository's
609 609 parent changeset (applicable for local source repositories only).
610 610
611 611 A set of changesets (tags, or branch names) to pull may be specified
612 612 by listing each changeset (tag, or branch name) with -r/--rev.
613 613 If -r/--rev is used, the cloned repository will contain only a subset
614 614 of the changesets of the source repository. Only the set of changesets
615 615 defined by all -r/--rev options (including all their ancestors)
616 616 will be pulled into the destination repository.
617 617 No subsequent changesets (including subsequent tags) will be present
618 618 in the destination.
619 619
620 620 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
621 621 local source repositories.
622 622
623 623 For efficiency, hardlinks are used for cloning whenever the source
624 624 and destination are on the same filesystem (note this applies only
625 625 to the repository data, not to the checked out files). Some
626 626 filesystems, such as AFS, implement hardlinking incorrectly, but
627 627 do not report errors. In these cases, use the --pull option to
628 628 avoid hardlinking.
629 629
630 630 In some cases, you can clone repositories and checked out files
631 631 using full hardlinks with ::
632 632
633 633 $ cp -al REPO REPOCLONE
634 634
635 635 This is the fastest way to clone, but it is not always safe. The
636 636 operation is not atomic (making sure REPO is not modified during
637 637 the operation is up to you) and you have to make sure your editor
638 638 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
639 639 this is not compatible with certain extensions that place their
640 640 metadata under the .hg directory, such as mq.
641 641 """
642 642 if opts.get('noupdate') and opts.get('updaterev'):
643 643 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
644 644
645 645 hg.clone(cmdutil.remoteui(ui, opts), source, dest,
646 646 pull=opts.get('pull'),
647 647 stream=opts.get('uncompressed'),
648 648 rev=opts.get('rev'),
649 649 update=opts.get('updaterev') or not opts.get('noupdate'))
650 650
651 651 def commit(ui, repo, *pats, **opts):
652 652 """commit the specified files or all outstanding changes
653 653
654 654 Commit changes to the given files into the repository. Unlike a
655 655 centralized RCS, this operation is a local operation. See hg push
656 656 for a way to actively distribute your changes.
657 657
658 658 If a list of files is omitted, all changes reported by "hg status"
659 659 will be committed.
660 660
661 661 If you are committing the result of a merge, do not provide any
662 662 filenames or -I/-X filters.
663 663
664 664 If no commit message is specified, the configured editor is
665 665 started to prompt you for a message.
666 666
667 667 See 'hg help dates' for a list of formats valid for -d/--date.
668 668 """
669 669 extra = {}
670 670 if opts.get('close_branch'):
671 671 extra['close'] = 1
672 672 e = cmdutil.commiteditor
673 673 if opts.get('force_editor'):
674 674 e = cmdutil.commitforceeditor
675 675
676 676 def commitfunc(ui, repo, message, match, opts):
677 677 return repo.commit(message, opts.get('user'), opts.get('date'), match,
678 678 editor=e, extra=extra)
679 679
680 680 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
681 681 if not node:
682 682 ui.status(_("nothing changed\n"))
683 683 return
684 684 cl = repo.changelog
685 685 rev = cl.rev(node)
686 686 parents = cl.parentrevs(rev)
687 687 if rev - 1 in parents:
688 688 # one of the parents was the old tip
689 689 pass
690 690 elif (parents == (nullrev, nullrev) or
691 691 len(cl.heads(cl.node(parents[0]))) > 1 and
692 692 (parents[1] == nullrev or len(cl.heads(cl.node(parents[1]))) > 1)):
693 693 ui.status(_('created new head\n'))
694 694
695 695 if ui.debugflag:
696 696 ui.write(_('committed changeset %d:%s\n') % (rev, hex(node)))
697 697 elif ui.verbose:
698 698 ui.write(_('committed changeset %d:%s\n') % (rev, short(node)))
699 699
700 700 def copy(ui, repo, *pats, **opts):
701 701 """mark files as copied for the next commit
702 702
703 703 Mark dest as having copies of source files. If dest is a
704 704 directory, copies are put in that directory. If dest is a file,
705 705 the source must be a single file.
706 706
707 707 By default, this command copies the contents of files as they
708 708 exist in the working directory. If invoked with -A/--after, the
709 709 operation is recorded, but no copying is performed.
710 710
711 711 This command takes effect with the next commit. To undo a copy
712 712 before that, see hg revert.
713 713 """
714 714 wlock = repo.wlock(False)
715 715 try:
716 716 return cmdutil.copy(ui, repo, pats, opts)
717 717 finally:
718 718 wlock.release()
719 719
720 720 def debugancestor(ui, repo, *args):
721 721 """find the ancestor revision of two revisions in a given index"""
722 722 if len(args) == 3:
723 723 index, rev1, rev2 = args
724 724 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
725 725 lookup = r.lookup
726 726 elif len(args) == 2:
727 727 if not repo:
728 728 raise util.Abort(_("There is no Mercurial repository here "
729 729 "(.hg not found)"))
730 730 rev1, rev2 = args
731 731 r = repo.changelog
732 732 lookup = repo.lookup
733 733 else:
734 734 raise util.Abort(_('either two or three arguments required'))
735 735 a = r.ancestor(lookup(rev1), lookup(rev2))
736 736 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
737 737
738 738 def debugcommands(ui, cmd='', *args):
739 739 for cmd, vals in sorted(table.iteritems()):
740 740 cmd = cmd.split('|')[0].strip('^')
741 741 opts = ', '.join([i[1] for i in vals[1]])
742 742 ui.write('%s: %s\n' % (cmd, opts))
743 743
744 744 def debugcomplete(ui, cmd='', **opts):
745 745 """returns the completion list associated with the given command"""
746 746
747 747 if opts.get('options'):
748 748 options = []
749 749 otables = [globalopts]
750 750 if cmd:
751 751 aliases, entry = cmdutil.findcmd(cmd, table, False)
752 752 otables.append(entry[1])
753 753 for t in otables:
754 754 for o in t:
755 755 if o[0]:
756 756 options.append('-%s' % o[0])
757 757 options.append('--%s' % o[1])
758 758 ui.write("%s\n" % "\n".join(options))
759 759 return
760 760
761 761 cmdlist = cmdutil.findpossible(cmd, table)
762 762 if ui.verbose:
763 763 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
764 764 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
765 765
766 766 def debugfsinfo(ui, path = "."):
767 767 open('.debugfsinfo', 'w').write('')
768 768 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
769 769 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
770 770 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
771 771 and 'yes' or 'no'))
772 772 os.unlink('.debugfsinfo')
773 773
774 774 def debugrebuildstate(ui, repo, rev="tip"):
775 775 """rebuild the dirstate as it would look like for the given revision"""
776 776 ctx = repo[rev]
777 777 wlock = repo.wlock()
778 778 try:
779 779 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
780 780 finally:
781 781 wlock.release()
782 782
783 783 def debugcheckstate(ui, repo):
784 784 """validate the correctness of the current dirstate"""
785 785 parent1, parent2 = repo.dirstate.parents()
786 786 m1 = repo[parent1].manifest()
787 787 m2 = repo[parent2].manifest()
788 788 errors = 0
789 789 for f in repo.dirstate:
790 790 state = repo.dirstate[f]
791 791 if state in "nr" and f not in m1:
792 792 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
793 793 errors += 1
794 794 if state in "a" and f in m1:
795 795 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
796 796 errors += 1
797 797 if state in "m" and f not in m1 and f not in m2:
798 798 ui.warn(_("%s in state %s, but not in either manifest\n") %
799 799 (f, state))
800 800 errors += 1
801 801 for f in m1:
802 802 state = repo.dirstate[f]
803 803 if state not in "nrm":
804 804 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
805 805 errors += 1
806 806 if errors:
807 807 error = _(".hg/dirstate inconsistent with current parent's manifest")
808 808 raise util.Abort(error)
809 809
810 810 def showconfig(ui, repo, *values, **opts):
811 811 """show combined config settings from all hgrc files
812 812
813 813 With no arguments, print names and values of all config items.
814 814
815 815 With one argument of the form section.name, print just the value
816 816 of that config item.
817 817
818 818 With multiple arguments, print names and values of all config
819 819 items with matching section names.
820 820
821 821 With --debug, the source (filename and line number) is printed
822 822 for each config item.
823 823 """
824 824
825 825 untrusted = bool(opts.get('untrusted'))
826 826 if values:
827 827 if len([v for v in values if '.' in v]) > 1:
828 828 raise util.Abort(_('only one config item permitted'))
829 829 for section, name, value in ui.walkconfig(untrusted=untrusted):
830 830 sectname = section + '.' + name
831 831 if values:
832 832 for v in values:
833 833 if v == section:
834 834 ui.debug('%s: ' %
835 835 ui.configsource(section, name, untrusted))
836 836 ui.write('%s=%s\n' % (sectname, value))
837 837 elif v == sectname:
838 838 ui.debug('%s: ' %
839 839 ui.configsource(section, name, untrusted))
840 840 ui.write(value, '\n')
841 841 else:
842 842 ui.debug('%s: ' %
843 843 ui.configsource(section, name, untrusted))
844 844 ui.write('%s=%s\n' % (sectname, value))
845 845
846 846 def debugsetparents(ui, repo, rev1, rev2=None):
847 847 """manually set the parents of the current working directory
848 848
849 849 This is useful for writing repository conversion tools, but should
850 850 be used with care.
851 851 """
852 852
853 853 if not rev2:
854 854 rev2 = hex(nullid)
855 855
856 856 wlock = repo.wlock()
857 857 try:
858 858 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
859 859 finally:
860 860 wlock.release()
861 861
862 862 def debugstate(ui, repo, nodates=None):
863 863 """show the contents of the current dirstate"""
864 864 timestr = ""
865 865 showdate = not nodates
866 866 for file_, ent in sorted(repo.dirstate._map.iteritems()):
867 867 if showdate:
868 868 if ent[3] == -1:
869 869 # Pad or slice to locale representation
870 870 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(0)))
871 871 timestr = 'unset'
872 872 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
873 873 else:
874 874 timestr = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(ent[3]))
875 875 if ent[1] & 020000:
876 876 mode = 'lnk'
877 877 else:
878 878 mode = '%3o' % (ent[1] & 0777)
879 879 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
880 880 for f in repo.dirstate.copies():
881 881 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
882 882
883 883 def debugsub(ui, repo, rev=None):
884 884 if rev == '':
885 885 rev = None
886 886 for k,v in sorted(repo[rev].substate.items()):
887 887 ui.write('path %s\n' % k)
888 888 ui.write(' source %s\n' % v[0])
889 889 ui.write(' revision %s\n' % v[1])
890 890
891 891 def debugdata(ui, file_, rev):
892 892 """dump the contents of a data file revision"""
893 893 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
894 894 try:
895 895 ui.write(r.revision(r.lookup(rev)))
896 896 except KeyError:
897 897 raise util.Abort(_('invalid revision identifier %s') % rev)
898 898
899 899 def debugdate(ui, date, range=None, **opts):
900 900 """parse and display a date"""
901 901 if opts["extended"]:
902 902 d = util.parsedate(date, util.extendeddateformats)
903 903 else:
904 904 d = util.parsedate(date)
905 905 ui.write("internal: %s %s\n" % d)
906 906 ui.write("standard: %s\n" % util.datestr(d))
907 907 if range:
908 908 m = util.matchdate(range)
909 909 ui.write("match: %s\n" % m(d[0]))
910 910
911 911 def debugindex(ui, file_):
912 912 """dump the contents of an index file"""
913 913 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
914 914 ui.write(" rev offset length base linkrev"
915 915 " nodeid p1 p2\n")
916 916 for i in r:
917 917 node = r.node(i)
918 918 try:
919 919 pp = r.parents(node)
920 920 except:
921 921 pp = [nullid, nullid]
922 922 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
923 923 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
924 924 short(node), short(pp[0]), short(pp[1])))
925 925
926 926 def debugindexdot(ui, file_):
927 927 """dump an index DAG as a graphviz dot file"""
928 928 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
929 929 ui.write("digraph G {\n")
930 930 for i in r:
931 931 node = r.node(i)
932 932 pp = r.parents(node)
933 933 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
934 934 if pp[1] != nullid:
935 935 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
936 936 ui.write("}\n")
937 937
938 938 def debuginstall(ui):
939 939 '''test Mercurial installation'''
940 940
941 941 def writetemp(contents):
942 942 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
943 943 f = os.fdopen(fd, "wb")
944 944 f.write(contents)
945 945 f.close()
946 946 return name
947 947
948 948 problems = 0
949 949
950 950 # encoding
951 951 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
952 952 try:
953 953 encoding.fromlocal("test")
954 954 except util.Abort, inst:
955 955 ui.write(" %s\n" % inst)
956 956 ui.write(_(" (check that your locale is properly set)\n"))
957 957 problems += 1
958 958
959 959 # compiled modules
960 960 ui.status(_("Checking extensions...\n"))
961 961 try:
962 962 import bdiff, mpatch, base85
963 963 except Exception, inst:
964 964 ui.write(" %s\n" % inst)
965 965 ui.write(_(" One or more extensions could not be found"))
966 966 ui.write(_(" (check that you compiled the extensions)\n"))
967 967 problems += 1
968 968
969 969 # templates
970 970 ui.status(_("Checking templates...\n"))
971 971 try:
972 972 import templater
973 973 templater.templater(templater.templatepath("map-cmdline.default"))
974 974 except Exception, inst:
975 975 ui.write(" %s\n" % inst)
976 976 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
977 977 problems += 1
978 978
979 979 # patch
980 980 ui.status(_("Checking patch...\n"))
981 981 patchproblems = 0
982 982 a = "1\n2\n3\n4\n"
983 983 b = "1\n2\n3\ninsert\n4\n"
984 984 fa = writetemp(a)
985 985 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
986 986 os.path.basename(fa))
987 987 fd = writetemp(d)
988 988
989 989 files = {}
990 990 try:
991 991 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
992 992 except util.Abort, e:
993 993 ui.write(_(" patch call failed:\n"))
994 994 ui.write(" " + str(e) + "\n")
995 995 patchproblems += 1
996 996 else:
997 997 if list(files) != [os.path.basename(fa)]:
998 998 ui.write(_(" unexpected patch output!\n"))
999 999 patchproblems += 1
1000 1000 a = open(fa).read()
1001 1001 if a != b:
1002 1002 ui.write(_(" patch test failed!\n"))
1003 1003 patchproblems += 1
1004 1004
1005 1005 if patchproblems:
1006 1006 if ui.config('ui', 'patch'):
1007 1007 ui.write(_(" (Current patch tool may be incompatible with patch,"
1008 1008 " or misconfigured. Please check your .hgrc file)\n"))
1009 1009 else:
1010 1010 ui.write(_(" Internal patcher failure, please report this error"
1011 1011 " to http://mercurial.selenic.com/bts/\n"))
1012 1012 problems += patchproblems
1013 1013
1014 1014 os.unlink(fa)
1015 1015 os.unlink(fd)
1016 1016
1017 1017 # editor
1018 1018 ui.status(_("Checking commit editor...\n"))
1019 1019 editor = ui.geteditor()
1020 1020 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1021 1021 if not cmdpath:
1022 1022 if editor == 'vi':
1023 1023 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1024 1024 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
1025 1025 else:
1026 1026 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1027 1027 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
1028 1028 problems += 1
1029 1029
1030 1030 # check username
1031 1031 ui.status(_("Checking username...\n"))
1032 1032 try:
1033 1033 user = ui.username()
1034 1034 except util.Abort, e:
1035 1035 ui.write(" %s\n" % e)
1036 1036 ui.write(_(" (specify a username in your .hgrc file)\n"))
1037 1037 problems += 1
1038 1038
1039 1039 if not problems:
1040 1040 ui.status(_("No problems detected\n"))
1041 1041 else:
1042 1042 ui.write(_("%s problems detected,"
1043 1043 " please check your install!\n") % problems)
1044 1044
1045 1045 return problems
1046 1046
1047 1047 def debugrename(ui, repo, file1, *pats, **opts):
1048 1048 """dump rename information"""
1049 1049
1050 1050 ctx = repo[opts.get('rev')]
1051 1051 m = cmdutil.match(repo, (file1,) + pats, opts)
1052 1052 for abs in ctx.walk(m):
1053 1053 fctx = ctx[abs]
1054 1054 o = fctx.filelog().renamed(fctx.filenode())
1055 1055 rel = m.rel(abs)
1056 1056 if o:
1057 1057 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1058 1058 else:
1059 1059 ui.write(_("%s not renamed\n") % rel)
1060 1060
1061 1061 def debugwalk(ui, repo, *pats, **opts):
1062 1062 """show how files match on given patterns"""
1063 1063 m = cmdutil.match(repo, pats, opts)
1064 1064 items = list(repo.walk(m))
1065 1065 if not items:
1066 1066 return
1067 1067 fmt = 'f %%-%ds %%-%ds %%s' % (
1068 1068 max([len(abs) for abs in items]),
1069 1069 max([len(m.rel(abs)) for abs in items]))
1070 1070 for abs in items:
1071 1071 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1072 1072 ui.write("%s\n" % line.rstrip())
1073 1073
1074 1074 def diff(ui, repo, *pats, **opts):
1075 1075 """diff repository (or selected files)
1076 1076
1077 1077 Show differences between revisions for the specified files.
1078 1078
1079 1079 Differences between files are shown using the unified diff format.
1080 1080
1081 1081 NOTE: diff may generate unexpected results for merges, as it will
1082 1082 default to comparing against the working directory's first parent
1083 1083 changeset if no revisions are specified.
1084 1084
1085 1085 When two revision arguments are given, then changes are shown
1086 1086 between those revisions. If only one revision is specified then
1087 1087 that revision is compared to the working directory, and, when no
1088 1088 revisions are specified, the working directory files are compared
1089 1089 to its parent.
1090 1090
1091 1091 Without the -a/--text option, diff will avoid generating diffs of
1092 1092 files it detects as binary. With -a, diff will generate a diff
1093 1093 anyway, probably with undesirable results.
1094 1094
1095 1095 Use the -g/--git option to generate diffs in the git extended diff
1096 1096 format. For more information, read 'hg help diffs'.
1097 1097 """
1098 1098
1099 1099 revs = opts.get('rev')
1100 1100 change = opts.get('change')
1101 1101 stat = opts.get('stat')
1102 1102 reverse = opts.get('reverse')
1103 1103
1104 1104 if revs and change:
1105 1105 msg = _('cannot specify --rev and --change at the same time')
1106 1106 raise util.Abort(msg)
1107 1107 elif change:
1108 1108 node2 = repo.lookup(change)
1109 1109 node1 = repo[node2].parents()[0].node()
1110 1110 else:
1111 1111 node1, node2 = cmdutil.revpair(repo, revs)
1112 1112
1113 1113 if reverse:
1114 1114 node1, node2 = node2, node1
1115 1115
1116 1116 if stat:
1117 1117 opts['unified'] = '0'
1118 1118 diffopts = patch.diffopts(ui, opts)
1119 1119
1120 1120 m = cmdutil.match(repo, pats, opts)
1121 1121 it = patch.diff(repo, node1, node2, match=m, opts=diffopts)
1122 1122 if stat:
1123 1123 width = ui.interactive() and util.termwidth() or 80
1124 1124 ui.write(patch.diffstat(util.iterlines(it), width=width,
1125 1125 git=diffopts.git))
1126 1126 else:
1127 1127 for chunk in it:
1128 1128 ui.write(chunk)
1129 1129
1130 1130 def export(ui, repo, *changesets, **opts):
1131 1131 """dump the header and diffs for one or more changesets
1132 1132
1133 1133 Print the changeset header and diffs for one or more revisions.
1134 1134
1135 1135 The information shown in the changeset header is: author,
1136 1136 changeset hash, parent(s) and commit comment.
1137 1137
1138 1138 NOTE: export may generate unexpected diff output for merge
1139 1139 changesets, as it will compare the merge changeset against its
1140 1140 first parent only.
1141 1141
1142 1142 Output may be to a file, in which case the name of the file is
1143 1143 given using a format string. The formatting rules are as follows:
1144 1144
1145 1145 :``%%``: literal "%" character
1146 1146 :``%H``: changeset hash (40 bytes of hexadecimal)
1147 1147 :``%N``: number of patches being generated
1148 1148 :``%R``: changeset revision number
1149 1149 :``%b``: basename of the exporting repository
1150 1150 :``%h``: short-form changeset hash (12 bytes of hexadecimal)
1151 1151 :``%n``: zero-padded sequence number, starting at 1
1152 1152 :``%r``: zero-padded changeset revision number
1153 1153
1154 1154 Without the -a/--text option, export will avoid generating diffs
1155 1155 of files it detects as binary. With -a, export will generate a
1156 1156 diff anyway, probably with undesirable results.
1157 1157
1158 1158 Use the -g/--git option to generate diffs in the git extended diff
1159 1159 format. See 'hg help diffs' for more information.
1160 1160
1161 1161 With the --switch-parent option, the diff will be against the
1162 1162 second parent. It can be useful to review a merge.
1163 1163 """
1164 1164 changesets += tuple(opts.get('rev', []))
1165 1165 if not changesets:
1166 1166 raise util.Abort(_("export requires at least one changeset"))
1167 1167 revs = cmdutil.revrange(repo, changesets)
1168 1168 if len(revs) > 1:
1169 1169 ui.note(_('exporting patches:\n'))
1170 1170 else:
1171 1171 ui.note(_('exporting patch:\n'))
1172 1172 patch.export(repo, revs, template=opts.get('output'),
1173 1173 switch_parent=opts.get('switch_parent'),
1174 1174 opts=patch.diffopts(ui, opts))
1175 1175
1176 1176 def forget(ui, repo, *pats, **opts):
1177 1177 """forget the specified files on the next commit
1178 1178
1179 1179 Mark the specified files so they will no longer be tracked
1180 1180 after the next commit.
1181 1181
1182 1182 This only removes files from the current branch, not from the
1183 1183 entire project history, and it does not delete them from the
1184 1184 working directory.
1185 1185
1186 1186 To undo a forget before the next commit, see hg add.
1187 1187 """
1188 1188
1189 1189 if not pats:
1190 1190 raise util.Abort(_('no files specified'))
1191 1191
1192 1192 m = cmdutil.match(repo, pats, opts)
1193 1193 s = repo.status(match=m, clean=True)
1194 1194 forget = sorted(s[0] + s[1] + s[3] + s[6])
1195 1195
1196 1196 for f in m.files():
1197 1197 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1198 1198 ui.warn(_('not removing %s: file is already untracked\n')
1199 1199 % m.rel(f))
1200 1200
1201 1201 for f in forget:
1202 1202 if ui.verbose or not m.exact(f):
1203 1203 ui.status(_('removing %s\n') % m.rel(f))
1204 1204
1205 1205 repo.remove(forget, unlink=False)
1206 1206
1207 1207 def grep(ui, repo, pattern, *pats, **opts):
1208 1208 """search for a pattern in specified files and revisions
1209 1209
1210 1210 Search revisions of files for a regular expression.
1211 1211
1212 1212 This command behaves differently than Unix grep. It only accepts
1213 1213 Python/Perl regexps. It searches repository history, not the
1214 1214 working directory. It always prints the revision number in which a
1215 1215 match appears.
1216 1216
1217 1217 By default, grep only prints output for the first revision of a
1218 1218 file in which it finds a match. To get it to print every revision
1219 1219 that contains a change in match status ("-" for a match that
1220 1220 becomes a non-match, or "+" for a non-match that becomes a match),
1221 1221 use the --all flag.
1222 1222 """
1223 1223 reflags = 0
1224 1224 if opts.get('ignore_case'):
1225 1225 reflags |= re.I
1226 1226 try:
1227 1227 regexp = re.compile(pattern, reflags)
1228 1228 except Exception, inst:
1229 1229 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1230 1230 return None
1231 1231 sep, eol = ':', '\n'
1232 1232 if opts.get('print0'):
1233 1233 sep = eol = '\0'
1234 1234
1235 1235 getfile = util.lrucachefunc(repo.file)
1236 1236
1237 1237 def matchlines(body):
1238 1238 begin = 0
1239 1239 linenum = 0
1240 1240 while True:
1241 1241 match = regexp.search(body, begin)
1242 1242 if not match:
1243 1243 break
1244 1244 mstart, mend = match.span()
1245 1245 linenum += body.count('\n', begin, mstart) + 1
1246 1246 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1247 1247 begin = body.find('\n', mend) + 1 or len(body)
1248 1248 lend = begin - 1
1249 1249 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1250 1250
1251 1251 class linestate(object):
1252 1252 def __init__(self, line, linenum, colstart, colend):
1253 1253 self.line = line
1254 1254 self.linenum = linenum
1255 1255 self.colstart = colstart
1256 1256 self.colend = colend
1257 1257
1258 1258 def __hash__(self):
1259 1259 return hash((self.linenum, self.line))
1260 1260
1261 1261 def __eq__(self, other):
1262 1262 return self.line == other.line
1263 1263
1264 1264 matches = {}
1265 1265 copies = {}
1266 1266 def grepbody(fn, rev, body):
1267 1267 matches[rev].setdefault(fn, [])
1268 1268 m = matches[rev][fn]
1269 1269 for lnum, cstart, cend, line in matchlines(body):
1270 1270 s = linestate(line, lnum, cstart, cend)
1271 1271 m.append(s)
1272 1272
1273 1273 def difflinestates(a, b):
1274 1274 sm = difflib.SequenceMatcher(None, a, b)
1275 1275 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1276 1276 if tag == 'insert':
1277 1277 for i in xrange(blo, bhi):
1278 1278 yield ('+', b[i])
1279 1279 elif tag == 'delete':
1280 1280 for i in xrange(alo, ahi):
1281 1281 yield ('-', a[i])
1282 1282 elif tag == 'replace':
1283 1283 for i in xrange(alo, ahi):
1284 1284 yield ('-', a[i])
1285 1285 for i in xrange(blo, bhi):
1286 1286 yield ('+', b[i])
1287 1287
1288 1288 def display(fn, ctx, pstates, states):
1289 1289 rev = ctx.rev()
1290 1290 datefunc = ui.quiet and util.shortdate or util.datestr
1291 1291 found = False
1292 1292 filerevmatches = {}
1293 1293 if opts.get('all'):
1294 1294 iter = difflinestates(pstates, states)
1295 1295 else:
1296 1296 iter = [('', l) for l in states]
1297 1297 for change, l in iter:
1298 1298 cols = [fn, str(rev)]
1299 1299 if opts.get('line_number'):
1300 1300 cols.append(str(l.linenum))
1301 1301 if opts.get('all'):
1302 1302 cols.append(change)
1303 1303 if opts.get('user'):
1304 1304 cols.append(ui.shortuser(ctx.user()))
1305 1305 if opts.get('date'):
1306 1306 cols.append(datefunc(ctx.date()))
1307 1307 if opts.get('files_with_matches'):
1308 1308 c = (fn, rev)
1309 1309 if c in filerevmatches:
1310 1310 continue
1311 1311 filerevmatches[c] = 1
1312 1312 else:
1313 1313 cols.append(l.line)
1314 1314 ui.write(sep.join(cols), eol)
1315 1315 found = True
1316 1316 return found
1317 1317
1318 1318 skip = {}
1319 1319 revfiles = {}
1320 1320 matchfn = cmdutil.match(repo, pats, opts)
1321 1321 found = False
1322 1322 follow = opts.get('follow')
1323 1323
1324 1324 def prep(ctx, fns):
1325 1325 rev = ctx.rev()
1326 1326 pctx = ctx.parents()[0]
1327 1327 parent = pctx.rev()
1328 1328 matches.setdefault(rev, {})
1329 1329 matches.setdefault(parent, {})
1330 1330 files = revfiles.setdefault(rev, [])
1331 1331 for fn in fns:
1332 1332 flog = getfile(fn)
1333 1333 try:
1334 1334 fnode = ctx.filenode(fn)
1335 1335 except error.LookupError:
1336 1336 continue
1337 1337
1338 1338 copied = flog.renamed(fnode)
1339 1339 copy = follow and copied and copied[0]
1340 1340 if copy:
1341 1341 copies.setdefault(rev, {})[fn] = copy
1342 1342 if fn in skip:
1343 1343 if copy:
1344 1344 skip[copy] = True
1345 1345 continue
1346 1346 files.append(fn)
1347 1347
1348 1348 if fn not in matches[rev]:
1349 1349 grepbody(fn, rev, flog.read(fnode))
1350 1350
1351 1351 pfn = copy or fn
1352 1352 if pfn not in matches[parent]:
1353 1353 try:
1354 1354 fnode = pctx.filenode(pfn)
1355 1355 grepbody(pfn, parent, flog.read(fnode))
1356 1356 except error.LookupError:
1357 1357 pass
1358 1358
1359 1359 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
1360 1360 rev = ctx.rev()
1361 1361 parent = ctx.parents()[0].rev()
1362 1362 for fn in sorted(revfiles.get(rev, [])):
1363 1363 states = matches[rev][fn]
1364 1364 copy = copies.get(rev, {}).get(fn)
1365 1365 if fn in skip:
1366 1366 if copy:
1367 1367 skip[copy] = True
1368 1368 continue
1369 1369 pstates = matches.get(parent, {}).get(copy or fn, [])
1370 1370 if pstates or states:
1371 1371 r = display(fn, ctx, pstates, states)
1372 1372 found = found or r
1373 1373 if r and not opts.get('all'):
1374 1374 skip[fn] = True
1375 1375 if copy:
1376 1376 skip[copy] = True
1377 1377 del matches[rev]
1378 1378 del revfiles[rev]
1379 1379
1380 1380 def heads(ui, repo, *branchrevs, **opts):
1381 1381 """show current repository heads or show branch heads
1382 1382
1383 1383 With no arguments, show all repository head changesets.
1384 1384
1385 1385 Repository "heads" are changesets with no child changesets. They are
1386 1386 where development generally takes place and are the usual targets
1387 1387 for update and merge operations.
1388 1388
1389 1389 If one or more REV is given, the "branch heads" will be shown for
1390 1390 the named branch associated with the specified changeset(s).
1391 1391
1392 1392 Branch heads are changesets on a named branch with no descendants on
1393 1393 the same branch. A branch head could be a "true" (repository) head,
1394 1394 or it could be the last changeset on that branch before it was
1395 1395 merged into another branch, or it could be the last changeset on the
1396 1396 branch before a new branch was created. If none of the branch heads
1397 1397 are true heads, the branch is considered inactive.
1398 1398
1399 1399 If -c/--closed is specified, also show branch heads marked closed
1400 1400 (see hg commit --close-branch).
1401 1401
1402 1402 If STARTREV is specified, only those heads that are descendants of
1403 1403 STARTREV will be displayed.
1404 1404 """
1405 1405 if opts.get('rev'):
1406 1406 start = repo.lookup(opts['rev'])
1407 1407 else:
1408 1408 start = None
1409 1409 closed = opts.get('closed')
1410 1410 hideinactive, _heads = opts.get('active'), None
1411 1411 if not branchrevs:
1412 1412 if closed:
1413 1413 raise error.Abort(_('you must specify a branch to use --closed'))
1414 1414 # Assume we're looking repo-wide heads if no revs were specified.
1415 1415 heads = repo.heads(start)
1416 1416 else:
1417 1417 if hideinactive:
1418 1418 _heads = repo.heads(start)
1419 1419 heads = []
1420 1420 visitedset = set()
1421 1421 for branchrev in branchrevs:
1422 1422 branch = repo[encoding.fromlocal(branchrev)].branch()
1423 1423 encodedbranch = encoding.tolocal(branch)
1424 1424 if branch in visitedset:
1425 1425 continue
1426 1426 visitedset.add(branch)
1427 1427 bheads = repo.branchheads(branch, start, closed=closed)
1428 1428 if not bheads:
1429 1429 if not opts.get('rev'):
1430 1430 ui.warn(_("no open branch heads on branch %s\n") % encodedbranch)
1431 1431 elif branch != branchrev:
1432 1432 ui.warn(_("no changes on branch %s containing %s are "
1433 1433 "reachable from %s\n")
1434 1434 % (encodedbranch, branchrev, opts.get('rev')))
1435 1435 else:
1436 1436 ui.warn(_("no changes on branch %s are reachable from %s\n")
1437 1437 % (encodedbranch, opts.get('rev')))
1438 1438 if hideinactive:
1439 1439 bheads = [bhead for bhead in bheads if bhead in _heads]
1440 1440 heads.extend(bheads)
1441 1441 if not heads:
1442 1442 return 1
1443 1443 displayer = cmdutil.show_changeset(ui, repo, opts)
1444 1444 for n in heads:
1445 1445 displayer.show(repo[n])
1446 1446
1447 1447 def help_(ui, name=None, with_version=False):
1448 1448 """show help for a given topic or a help overview
1449 1449
1450 1450 With no arguments, print a list of commands with short help messages.
1451 1451
1452 1452 Given a topic, extension, or command name, print help for that
1453 1453 topic."""
1454 1454 option_lists = []
1455 1455 textwidth = util.termwidth() - 2
1456 1456
1457 1457 def addglobalopts(aliases):
1458 1458 if ui.verbose:
1459 1459 option_lists.append((_("global options:"), globalopts))
1460 1460 if name == 'shortlist':
1461 1461 option_lists.append((_('use "hg help" for the full list '
1462 1462 'of commands'), ()))
1463 1463 else:
1464 1464 if name == 'shortlist':
1465 1465 msg = _('use "hg help" for the full list of commands '
1466 1466 'or "hg -v" for details')
1467 1467 elif aliases:
1468 1468 msg = _('use "hg -v help%s" to show aliases and '
1469 1469 'global options') % (name and " " + name or "")
1470 1470 else:
1471 1471 msg = _('use "hg -v help %s" to show global options') % name
1472 1472 option_lists.append((msg, ()))
1473 1473
1474 1474 def helpcmd(name):
1475 1475 if with_version:
1476 1476 version_(ui)
1477 1477 ui.write('\n')
1478 1478
1479 1479 try:
1480 1480 aliases, entry = cmdutil.findcmd(name, table, False)
1481 1481 except error.AmbiguousCommand, inst:
1482 1482 # py3k fix: except vars can't be used outside the scope of the
1483 1483 # except block, nor can be used inside a lambda. python issue4617
1484 1484 prefix = inst.args[0]
1485 1485 select = lambda c: c.lstrip('^').startswith(prefix)
1486 1486 helplist(_('list of commands:\n\n'), select)
1487 1487 return
1488 1488
1489 # check if it's an invalid alias and display its error if it is
1490 if getattr(entry[0], 'badalias', False):
1491 entry[0](ui)
1492 return
1493
1489 1494 # synopsis
1490 1495 if len(entry) > 2:
1491 1496 if entry[2].startswith('hg'):
1492 1497 ui.write("%s\n" % entry[2])
1493 1498 else:
1494 1499 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
1495 1500 else:
1496 1501 ui.write('hg %s\n' % aliases[0])
1497 1502
1498 1503 # aliases
1499 1504 if not ui.quiet and len(aliases) > 1:
1500 1505 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1501 1506
1502 1507 # description
1503 1508 doc = gettext(entry[0].__doc__)
1504 1509 if not doc:
1505 1510 doc = _("(no help text available)")
1506 1511 if ui.quiet:
1507 1512 doc = doc.splitlines()[0]
1508 1513 ui.write("\n%s\n" % minirst.format(doc, textwidth))
1509 1514
1510 1515 if not ui.quiet:
1511 1516 # options
1512 1517 if entry[1]:
1513 1518 option_lists.append((_("options:\n"), entry[1]))
1514 1519
1515 1520 addglobalopts(False)
1516 1521
1517 1522 def helplist(header, select=None):
1518 1523 h = {}
1519 1524 cmds = {}
1520 1525 for c, e in table.iteritems():
1521 1526 f = c.split("|", 1)[0]
1522 1527 if select and not select(f):
1523 1528 continue
1524 1529 if (not select and name != 'shortlist' and
1525 1530 e[0].__module__ != __name__):
1526 1531 continue
1527 1532 if name == "shortlist" and not f.startswith("^"):
1528 1533 continue
1529 1534 f = f.lstrip("^")
1530 1535 if not ui.debugflag and f.startswith("debug"):
1531 1536 continue
1532 1537 doc = e[0].__doc__
1533 1538 if doc and 'DEPRECATED' in doc and not ui.verbose:
1534 1539 continue
1535 1540 doc = gettext(doc)
1536 1541 if not doc:
1537 1542 doc = _("(no help text available)")
1538 1543 h[f] = doc.splitlines()[0].rstrip()
1539 1544 cmds[f] = c.lstrip("^")
1540 1545
1541 1546 if not h:
1542 1547 ui.status(_('no commands defined\n'))
1543 1548 return
1544 1549
1545 1550 ui.status(header)
1546 1551 fns = sorted(h)
1547 1552 m = max(map(len, fns))
1548 1553 for f in fns:
1549 1554 if ui.verbose:
1550 1555 commands = cmds[f].replace("|",", ")
1551 1556 ui.write(" %s:\n %s\n"%(commands, h[f]))
1552 1557 else:
1553 1558 ui.write(' %-*s %s\n' % (m, f, util.wrap(h[f], m + 4)))
1554 1559
1555 1560 if not ui.quiet:
1556 1561 addglobalopts(True)
1557 1562
1558 1563 def helptopic(name):
1559 1564 for names, header, doc in help.helptable:
1560 1565 if name in names:
1561 1566 break
1562 1567 else:
1563 1568 raise error.UnknownCommand(name)
1564 1569
1565 1570 # description
1566 1571 if not doc:
1567 1572 doc = _("(no help text available)")
1568 1573 if hasattr(doc, '__call__'):
1569 1574 doc = doc()
1570 1575
1571 1576 ui.write("%s\n\n" % header)
1572 1577 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
1573 1578
1574 1579 def helpext(name):
1575 1580 try:
1576 1581 mod = extensions.find(name)
1577 1582 except KeyError:
1578 1583 raise error.UnknownCommand(name)
1579 1584
1580 1585 doc = gettext(mod.__doc__) or _('no help text available')
1581 1586 if '\n' not in doc:
1582 1587 head, tail = doc, ""
1583 1588 else:
1584 1589 head, tail = doc.split('\n', 1)
1585 1590 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
1586 1591 if tail:
1587 1592 ui.write(minirst.format(tail, textwidth))
1588 1593 ui.status('\n\n')
1589 1594
1590 1595 try:
1591 1596 ct = mod.cmdtable
1592 1597 except AttributeError:
1593 1598 ct = {}
1594 1599
1595 1600 modcmds = set([c.split('|', 1)[0] for c in ct])
1596 1601 helplist(_('list of commands:\n\n'), modcmds.__contains__)
1597 1602
1598 1603 if name and name != 'shortlist':
1599 1604 i = None
1600 1605 for f in (helptopic, helpcmd, helpext):
1601 1606 try:
1602 1607 f(name)
1603 1608 i = None
1604 1609 break
1605 1610 except error.UnknownCommand, inst:
1606 1611 i = inst
1607 1612 if i:
1608 1613 raise i
1609 1614
1610 1615 else:
1611 1616 # program name
1612 1617 if ui.verbose or with_version:
1613 1618 version_(ui)
1614 1619 else:
1615 1620 ui.status(_("Mercurial Distributed SCM\n"))
1616 1621 ui.status('\n')
1617 1622
1618 1623 # list of commands
1619 1624 if name == "shortlist":
1620 1625 header = _('basic commands:\n\n')
1621 1626 else:
1622 1627 header = _('list of commands:\n\n')
1623 1628
1624 1629 helplist(header)
1625 1630 if name != 'shortlist':
1626 1631 exts, maxlength = extensions.enabled()
1627 1632 text = help.listexts(_('enabled extensions:'), exts, maxlength)
1628 1633 if text:
1629 1634 ui.write("\n%s\n" % minirst.format(text, textwidth))
1630 1635
1631 1636 # list all option lists
1632 1637 opt_output = []
1633 1638 for title, options in option_lists:
1634 1639 opt_output.append(("\n%s" % title, None))
1635 1640 for shortopt, longopt, default, desc in options:
1636 1641 if _("DEPRECATED") in desc and not ui.verbose: continue
1637 1642 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1638 1643 longopt and " --%s" % longopt),
1639 1644 "%s%s" % (desc,
1640 1645 default
1641 1646 and _(" (default: %s)") % default
1642 1647 or "")))
1643 1648
1644 1649 if not name:
1645 1650 ui.write(_("\nadditional help topics:\n\n"))
1646 1651 topics = []
1647 1652 for names, header, doc in help.helptable:
1648 1653 topics.append((sorted(names, key=len, reverse=True)[0], header))
1649 1654 topics_len = max([len(s[0]) for s in topics])
1650 1655 for t, desc in topics:
1651 1656 ui.write(" %-*s %s\n" % (topics_len, t, desc))
1652 1657
1653 1658 if opt_output:
1654 1659 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1655 1660 for first, second in opt_output:
1656 1661 if second:
1657 1662 second = util.wrap(second, opts_len + 3)
1658 1663 ui.write(" %-*s %s\n" % (opts_len, first, second))
1659 1664 else:
1660 1665 ui.write("%s\n" % first)
1661 1666
1662 1667 def identify(ui, repo, source=None,
1663 1668 rev=None, num=None, id=None, branch=None, tags=None):
1664 1669 """identify the working copy or specified revision
1665 1670
1666 1671 With no revision, print a summary of the current state of the
1667 1672 repository.
1668 1673
1669 1674 Specifying a path to a repository root or Mercurial bundle will
1670 1675 cause lookup to operate on that repository/bundle.
1671 1676
1672 1677 This summary identifies the repository state using one or two
1673 1678 parent hash identifiers, followed by a "+" if there are
1674 1679 uncommitted changes in the working directory, a list of tags for
1675 1680 this revision and a branch name for non-default branches.
1676 1681 """
1677 1682
1678 1683 if not repo and not source:
1679 1684 raise util.Abort(_("There is no Mercurial repository here "
1680 1685 "(.hg not found)"))
1681 1686
1682 1687 hexfunc = ui.debugflag and hex or short
1683 1688 default = not (num or id or branch or tags)
1684 1689 output = []
1685 1690
1686 1691 revs = []
1687 1692 if source:
1688 1693 source, revs, checkout = hg.parseurl(ui.expandpath(source), [])
1689 1694 repo = hg.repository(ui, source)
1690 1695
1691 1696 if not repo.local():
1692 1697 if not rev and revs:
1693 1698 rev = revs[0]
1694 1699 if not rev:
1695 1700 rev = "tip"
1696 1701 if num or branch or tags:
1697 1702 raise util.Abort(
1698 1703 "can't query remote revision number, branch, or tags")
1699 1704 output = [hexfunc(repo.lookup(rev))]
1700 1705 elif not rev:
1701 1706 ctx = repo[None]
1702 1707 parents = ctx.parents()
1703 1708 changed = False
1704 1709 if default or id or num:
1705 1710 changed = ctx.files() + ctx.deleted()
1706 1711 if default or id:
1707 1712 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
1708 1713 (changed) and "+" or "")]
1709 1714 if num:
1710 1715 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
1711 1716 (changed) and "+" or ""))
1712 1717 else:
1713 1718 ctx = repo[rev]
1714 1719 if default or id:
1715 1720 output = [hexfunc(ctx.node())]
1716 1721 if num:
1717 1722 output.append(str(ctx.rev()))
1718 1723
1719 1724 if repo.local() and default and not ui.quiet:
1720 1725 b = encoding.tolocal(ctx.branch())
1721 1726 if b != 'default':
1722 1727 output.append("(%s)" % b)
1723 1728
1724 1729 # multiple tags for a single parent separated by '/'
1725 1730 t = "/".join(ctx.tags())
1726 1731 if t:
1727 1732 output.append(t)
1728 1733
1729 1734 if branch:
1730 1735 output.append(encoding.tolocal(ctx.branch()))
1731 1736
1732 1737 if tags:
1733 1738 output.extend(ctx.tags())
1734 1739
1735 1740 ui.write("%s\n" % ' '.join(output))
1736 1741
1737 1742 def import_(ui, repo, patch1, *patches, **opts):
1738 1743 """import an ordered set of patches
1739 1744
1740 1745 Import a list of patches and commit them individually (unless
1741 1746 --no-commit is specified).
1742 1747
1743 1748 If there are outstanding changes in the working directory, import
1744 1749 will abort unless given the -f/--force flag.
1745 1750
1746 1751 You can import a patch straight from a mail message. Even patches
1747 1752 as attachments work (to use the body part, it must have type
1748 1753 text/plain or text/x-patch). From and Subject headers of email
1749 1754 message are used as default committer and commit message. All
1750 1755 text/plain body parts before first diff are added to commit
1751 1756 message.
1752 1757
1753 1758 If the imported patch was generated by hg export, user and
1754 1759 description from patch override values from message headers and
1755 1760 body. Values given on command line with -m/--message and -u/--user
1756 1761 override these.
1757 1762
1758 1763 If --exact is specified, import will set the working directory to
1759 1764 the parent of each patch before applying it, and will abort if the
1760 1765 resulting changeset has a different ID than the one recorded in
1761 1766 the patch. This may happen due to character set problems or other
1762 1767 deficiencies in the text patch format.
1763 1768
1764 1769 With -s/--similarity, hg will attempt to discover renames and
1765 1770 copies in the patch in the same way as 'addremove'.
1766 1771
1767 1772 To read a patch from standard input, use "-" as the patch name. If
1768 1773 a URL is specified, the patch will be downloaded from it.
1769 1774 See 'hg help dates' for a list of formats valid for -d/--date.
1770 1775 """
1771 1776 patches = (patch1,) + patches
1772 1777
1773 1778 date = opts.get('date')
1774 1779 if date:
1775 1780 opts['date'] = util.parsedate(date)
1776 1781
1777 1782 try:
1778 1783 sim = float(opts.get('similarity') or 0)
1779 1784 except ValueError:
1780 1785 raise util.Abort(_('similarity must be a number'))
1781 1786 if sim < 0 or sim > 100:
1782 1787 raise util.Abort(_('similarity must be between 0 and 100'))
1783 1788
1784 1789 if opts.get('exact') or not opts.get('force'):
1785 1790 cmdutil.bail_if_changed(repo)
1786 1791
1787 1792 d = opts["base"]
1788 1793 strip = opts["strip"]
1789 1794 wlock = lock = None
1790 1795 try:
1791 1796 wlock = repo.wlock()
1792 1797 lock = repo.lock()
1793 1798 for p in patches:
1794 1799 pf = os.path.join(d, p)
1795 1800
1796 1801 if pf == '-':
1797 1802 ui.status(_("applying patch from stdin\n"))
1798 1803 pf = sys.stdin
1799 1804 else:
1800 1805 ui.status(_("applying %s\n") % p)
1801 1806 pf = url.open(ui, pf)
1802 1807 data = patch.extract(ui, pf)
1803 1808 tmpname, message, user, date, branch, nodeid, p1, p2 = data
1804 1809
1805 1810 if tmpname is None:
1806 1811 raise util.Abort(_('no diffs found'))
1807 1812
1808 1813 try:
1809 1814 cmdline_message = cmdutil.logmessage(opts)
1810 1815 if cmdline_message:
1811 1816 # pickup the cmdline msg
1812 1817 message = cmdline_message
1813 1818 elif message:
1814 1819 # pickup the patch msg
1815 1820 message = message.strip()
1816 1821 else:
1817 1822 # launch the editor
1818 1823 message = None
1819 1824 ui.debug('message:\n%s\n' % message)
1820 1825
1821 1826 wp = repo.parents()
1822 1827 if opts.get('exact'):
1823 1828 if not nodeid or not p1:
1824 1829 raise util.Abort(_('not a Mercurial patch'))
1825 1830 p1 = repo.lookup(p1)
1826 1831 p2 = repo.lookup(p2 or hex(nullid))
1827 1832
1828 1833 if p1 != wp[0].node():
1829 1834 hg.clean(repo, p1)
1830 1835 repo.dirstate.setparents(p1, p2)
1831 1836 elif p2:
1832 1837 try:
1833 1838 p1 = repo.lookup(p1)
1834 1839 p2 = repo.lookup(p2)
1835 1840 if p1 == wp[0].node():
1836 1841 repo.dirstate.setparents(p1, p2)
1837 1842 except error.RepoError:
1838 1843 pass
1839 1844 if opts.get('exact') or opts.get('import_branch'):
1840 1845 repo.dirstate.setbranch(branch or 'default')
1841 1846
1842 1847 files = {}
1843 1848 try:
1844 1849 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1845 1850 files=files, eolmode=None)
1846 1851 finally:
1847 1852 files = patch.updatedir(ui, repo, files, similarity=sim/100.)
1848 1853 if not opts.get('no_commit'):
1849 1854 m = cmdutil.matchfiles(repo, files or [])
1850 1855 n = repo.commit(message, opts.get('user') or user,
1851 1856 opts.get('date') or date, match=m,
1852 1857 editor=cmdutil.commiteditor)
1853 1858 if opts.get('exact'):
1854 1859 if hex(n) != nodeid:
1855 1860 repo.rollback()
1856 1861 raise util.Abort(_('patch is damaged'
1857 1862 ' or loses information'))
1858 1863 # Force a dirstate write so that the next transaction
1859 1864 # backups an up-do-date file.
1860 1865 repo.dirstate.write()
1861 1866 finally:
1862 1867 os.unlink(tmpname)
1863 1868 finally:
1864 1869 release(lock, wlock)
1865 1870
1866 1871 def incoming(ui, repo, source="default", **opts):
1867 1872 """show new changesets found in source
1868 1873
1869 1874 Show new changesets found in the specified path/URL or the default
1870 1875 pull location. These are the changesets that would have been pulled
1871 1876 if a pull at the time you issued this command.
1872 1877
1873 1878 For remote repository, using --bundle avoids downloading the
1874 1879 changesets twice if the incoming is followed by a pull.
1875 1880
1876 1881 See pull for valid source format details.
1877 1882 """
1878 1883 limit = cmdutil.loglimit(opts)
1879 1884 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts.get('rev'))
1880 1885 other = hg.repository(cmdutil.remoteui(repo, opts), source)
1881 1886 ui.status(_('comparing with %s\n') % url.hidepassword(source))
1882 1887 if revs:
1883 1888 revs = [other.lookup(rev) for rev in revs]
1884 1889 common, incoming, rheads = repo.findcommonincoming(other, heads=revs,
1885 1890 force=opts["force"])
1886 1891 if not incoming:
1887 1892 try:
1888 1893 os.unlink(opts["bundle"])
1889 1894 except:
1890 1895 pass
1891 1896 ui.status(_("no changes found\n"))
1892 1897 return 1
1893 1898
1894 1899 cleanup = None
1895 1900 try:
1896 1901 fname = opts["bundle"]
1897 1902 if fname or not other.local():
1898 1903 # create a bundle (uncompressed if other repo is not local)
1899 1904
1900 1905 if revs is None and other.capable('changegroupsubset'):
1901 1906 revs = rheads
1902 1907
1903 1908 if revs is None:
1904 1909 cg = other.changegroup(incoming, "incoming")
1905 1910 else:
1906 1911 cg = other.changegroupsubset(incoming, revs, 'incoming')
1907 1912 bundletype = other.local() and "HG10BZ" or "HG10UN"
1908 1913 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1909 1914 # keep written bundle?
1910 1915 if opts["bundle"]:
1911 1916 cleanup = None
1912 1917 if not other.local():
1913 1918 # use the created uncompressed bundlerepo
1914 1919 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1915 1920
1916 1921 o = other.changelog.nodesbetween(incoming, revs)[0]
1917 1922 if opts.get('newest_first'):
1918 1923 o.reverse()
1919 1924 displayer = cmdutil.show_changeset(ui, other, opts)
1920 1925 count = 0
1921 1926 for n in o:
1922 1927 if count >= limit:
1923 1928 break
1924 1929 parents = [p for p in other.changelog.parents(n) if p != nullid]
1925 1930 if opts.get('no_merges') and len(parents) == 2:
1926 1931 continue
1927 1932 count += 1
1928 1933 displayer.show(other[n])
1929 1934 finally:
1930 1935 if hasattr(other, 'close'):
1931 1936 other.close()
1932 1937 if cleanup:
1933 1938 os.unlink(cleanup)
1934 1939
1935 1940 def init(ui, dest=".", **opts):
1936 1941 """create a new repository in the given directory
1937 1942
1938 1943 Initialize a new repository in the given directory. If the given
1939 1944 directory does not exist, it will be created.
1940 1945
1941 1946 If no directory is given, the current directory is used.
1942 1947
1943 1948 It is possible to specify an ``ssh://`` URL as the destination.
1944 1949 See 'hg help urls' for more information.
1945 1950 """
1946 1951 hg.repository(cmdutil.remoteui(ui, opts), dest, create=1)
1947 1952
1948 1953 def locate(ui, repo, *pats, **opts):
1949 1954 """locate files matching specific patterns
1950 1955
1951 1956 Print files under Mercurial control in the working directory whose
1952 1957 names match the given patterns.
1953 1958
1954 1959 By default, this command searches all directories in the working
1955 1960 directory. To search just the current directory and its
1956 1961 subdirectories, use "--include .".
1957 1962
1958 1963 If no patterns are given to match, this command prints the names
1959 1964 of all files under Mercurial control in the working directory.
1960 1965
1961 1966 If you want to feed the output of this command into the "xargs"
1962 1967 command, use the -0 option to both this command and "xargs". This
1963 1968 will avoid the problem of "xargs" treating single filenames that
1964 1969 contain whitespace as multiple filenames.
1965 1970 """
1966 1971 end = opts.get('print0') and '\0' or '\n'
1967 1972 rev = opts.get('rev') or None
1968 1973
1969 1974 ret = 1
1970 1975 m = cmdutil.match(repo, pats, opts, default='relglob')
1971 1976 m.bad = lambda x,y: False
1972 1977 for abs in repo[rev].walk(m):
1973 1978 if not rev and abs not in repo.dirstate:
1974 1979 continue
1975 1980 if opts.get('fullpath'):
1976 1981 ui.write(repo.wjoin(abs), end)
1977 1982 else:
1978 1983 ui.write(((pats and m.rel(abs)) or abs), end)
1979 1984 ret = 0
1980 1985
1981 1986 return ret
1982 1987
1983 1988 def log(ui, repo, *pats, **opts):
1984 1989 """show revision history of entire repository or files
1985 1990
1986 1991 Print the revision history of the specified files or the entire
1987 1992 project.
1988 1993
1989 1994 File history is shown without following rename or copy history of
1990 1995 files. Use -f/--follow with a filename to follow history across
1991 1996 renames and copies. --follow without a filename will only show
1992 1997 ancestors or descendants of the starting revision. --follow-first
1993 1998 only follows the first parent of merge revisions.
1994 1999
1995 2000 If no revision range is specified, the default is tip:0 unless
1996 2001 --follow is set, in which case the working directory parent is
1997 2002 used as the starting revision.
1998 2003
1999 2004 See 'hg help dates' for a list of formats valid for -d/--date.
2000 2005
2001 2006 By default this command prints revision number and changeset id,
2002 2007 tags, non-trivial parents, user, date and time, and a summary for
2003 2008 each commit. When the -v/--verbose switch is used, the list of
2004 2009 changed files and full commit message are shown.
2005 2010
2006 2011 NOTE: log -p/--patch may generate unexpected diff output for merge
2007 2012 changesets, as it will only compare the merge changeset against
2008 2013 its first parent. Also, only files different from BOTH parents
2009 2014 will appear in files:.
2010 2015 """
2011 2016
2012 2017 matchfn = cmdutil.match(repo, pats, opts)
2013 2018 limit = cmdutil.loglimit(opts)
2014 2019 count = 0
2015 2020
2016 2021 if opts.get('copies') and opts.get('rev'):
2017 2022 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2018 2023 else:
2019 2024 endrev = len(repo)
2020 2025 rcache = {}
2021 2026 def getrenamed(fn, rev):
2022 2027 '''looks up all renames for a file (up to endrev) the first
2023 2028 time the file is given. It indexes on the changerev and only
2024 2029 parses the manifest if linkrev != changerev.
2025 2030 Returns rename info for fn at changerev rev.'''
2026 2031 if fn not in rcache:
2027 2032 rcache[fn] = {}
2028 2033 fl = repo.file(fn)
2029 2034 for i in fl:
2030 2035 lr = fl.linkrev(i)
2031 2036 renamed = fl.renamed(fl.node(i))
2032 2037 rcache[fn][lr] = renamed
2033 2038 if lr >= endrev:
2034 2039 break
2035 2040 if rev in rcache[fn]:
2036 2041 return rcache[fn][rev]
2037 2042
2038 2043 # If linkrev != rev (i.e. rev not found in rcache) fallback to
2039 2044 # filectx logic.
2040 2045 try:
2041 2046 return repo[rev][fn].renamed()
2042 2047 except error.LookupError:
2043 2048 return None
2044 2049
2045 2050 df = False
2046 2051 if opts["date"]:
2047 2052 df = util.matchdate(opts["date"])
2048 2053
2049 2054 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
2050 2055 def prep(ctx, fns):
2051 2056 rev = ctx.rev()
2052 2057 parents = [p for p in repo.changelog.parentrevs(rev)
2053 2058 if p != nullrev]
2054 2059 if opts.get('no_merges') and len(parents) == 2:
2055 2060 return
2056 2061 if opts.get('only_merges') and len(parents) != 2:
2057 2062 return
2058 2063 if opts.get('only_branch') and ctx.branch() not in opts['only_branch']:
2059 2064 return
2060 2065 if df and not df(ctx.date()[0]):
2061 2066 return
2062 2067 if opts['user'] and not [k for k in opts['user'] if k in ctx.user()]:
2063 2068 return
2064 2069 if opts.get('keyword'):
2065 2070 for k in [kw.lower() for kw in opts['keyword']]:
2066 2071 if (k in ctx.user().lower() or
2067 2072 k in ctx.description().lower() or
2068 2073 k in " ".join(ctx.files()).lower()):
2069 2074 break
2070 2075 else:
2071 2076 return
2072 2077
2073 2078 copies = []
2074 2079 if opts.get('copies') and rev:
2075 2080 for fn in ctx.files():
2076 2081 rename = getrenamed(fn, rev)
2077 2082 if rename:
2078 2083 copies.append((fn, rename[0]))
2079 2084
2080 2085 displayer.show(ctx, copies=copies)
2081 2086
2082 2087 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2083 2088 if count == limit:
2084 2089 break
2085 2090 if displayer.flush(ctx.rev()):
2086 2091 count += 1
2087 2092
2088 2093 def manifest(ui, repo, node=None, rev=None):
2089 2094 """output the current or given revision of the project manifest
2090 2095
2091 2096 Print a list of version controlled files for the given revision.
2092 2097 If no revision is given, the first parent of the working directory
2093 2098 is used, or the null revision if no revision is checked out.
2094 2099
2095 2100 With -v, print file permissions, symlink and executable bits.
2096 2101 With --debug, print file revision hashes.
2097 2102 """
2098 2103
2099 2104 if rev and node:
2100 2105 raise util.Abort(_("please specify just one revision"))
2101 2106
2102 2107 if not node:
2103 2108 node = rev
2104 2109
2105 2110 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2106 2111 ctx = repo[node]
2107 2112 for f in ctx:
2108 2113 if ui.debugflag:
2109 2114 ui.write("%40s " % hex(ctx.manifest()[f]))
2110 2115 if ui.verbose:
2111 2116 ui.write(decor[ctx.flags(f)])
2112 2117 ui.write("%s\n" % f)
2113 2118
2114 2119 def merge(ui, repo, node=None, **opts):
2115 2120 """merge working directory with another revision
2116 2121
2117 2122 The current working directory is updated with all changes made in
2118 2123 the requested revision since the last common predecessor revision.
2119 2124
2120 2125 Files that changed between either parent are marked as changed for
2121 2126 the next commit and a commit must be performed before any further
2122 2127 updates to the repository are allowed. The next commit will have
2123 2128 two parents.
2124 2129
2125 2130 If no revision is specified, the working directory's parent is a
2126 2131 head revision, and the current branch contains exactly one other
2127 2132 head, the other head is merged with by default. Otherwise, an
2128 2133 explicit revision with which to merge with must be provided.
2129 2134 """
2130 2135
2131 2136 if opts.get('rev') and node:
2132 2137 raise util.Abort(_("please specify just one revision"))
2133 2138 if not node:
2134 2139 node = opts.get('rev')
2135 2140
2136 2141 if not node:
2137 2142 branch = repo.changectx(None).branch()
2138 2143 bheads = repo.branchheads(branch)
2139 2144 if len(bheads) > 2:
2140 2145 raise util.Abort(_("branch '%s' has %d heads - "
2141 2146 "please merge with an explicit rev") %
2142 2147 (branch, len(bheads)))
2143 2148
2144 2149 parent = repo.dirstate.parents()[0]
2145 2150 if len(bheads) == 1:
2146 2151 if len(repo.heads()) > 1:
2147 2152 raise util.Abort(_("branch '%s' has one head - "
2148 2153 "please merge with an explicit rev") %
2149 2154 branch)
2150 2155 msg = _('there is nothing to merge')
2151 2156 if parent != repo.lookup(repo[None].branch()):
2152 2157 msg = _('%s - use "hg update" instead') % msg
2153 2158 raise util.Abort(msg)
2154 2159
2155 2160 if parent not in bheads:
2156 2161 raise util.Abort(_('working dir not at a head rev - '
2157 2162 'use "hg update" or merge with an explicit rev'))
2158 2163 node = parent == bheads[0] and bheads[-1] or bheads[0]
2159 2164
2160 2165 if opts.get('preview'):
2161 2166 p1 = repo['.']
2162 2167 p2 = repo[node]
2163 2168 common = p1.ancestor(p2)
2164 2169 roots, heads = [common.node()], [p2.node()]
2165 2170 displayer = cmdutil.show_changeset(ui, repo, opts)
2166 2171 for node in repo.changelog.nodesbetween(roots=roots, heads=heads)[0]:
2167 2172 if node not in roots:
2168 2173 displayer.show(repo[node])
2169 2174 return 0
2170 2175
2171 2176 return hg.merge(repo, node, force=opts.get('force'))
2172 2177
2173 2178 def outgoing(ui, repo, dest=None, **opts):
2174 2179 """show changesets not found in destination
2175 2180
2176 2181 Show changesets not found in the specified destination repository
2177 2182 or the default push location. These are the changesets that would
2178 2183 be pushed if a push was requested.
2179 2184
2180 2185 See pull for valid destination format details.
2181 2186 """
2182 2187 limit = cmdutil.loglimit(opts)
2183 2188 dest, revs, checkout = hg.parseurl(
2184 2189 ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev'))
2185 2190 if revs:
2186 2191 revs = [repo.lookup(rev) for rev in revs]
2187 2192
2188 2193 other = hg.repository(cmdutil.remoteui(repo, opts), dest)
2189 2194 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
2190 2195 o = repo.findoutgoing(other, force=opts.get('force'))
2191 2196 if not o:
2192 2197 ui.status(_("no changes found\n"))
2193 2198 return 1
2194 2199 o = repo.changelog.nodesbetween(o, revs)[0]
2195 2200 if opts.get('newest_first'):
2196 2201 o.reverse()
2197 2202 displayer = cmdutil.show_changeset(ui, repo, opts)
2198 2203 count = 0
2199 2204 for n in o:
2200 2205 if count >= limit:
2201 2206 break
2202 2207 parents = [p for p in repo.changelog.parents(n) if p != nullid]
2203 2208 if opts.get('no_merges') and len(parents) == 2:
2204 2209 continue
2205 2210 count += 1
2206 2211 displayer.show(repo[n])
2207 2212
2208 2213 def parents(ui, repo, file_=None, **opts):
2209 2214 """show the parents of the working directory or revision
2210 2215
2211 2216 Print the working directory's parent revisions. If a revision is
2212 2217 given via -r/--rev, the parent of that revision will be printed.
2213 2218 If a file argument is given, the revision in which the file was
2214 2219 last changed (before the working directory revision or the
2215 2220 argument to --rev if given) is printed.
2216 2221 """
2217 2222 rev = opts.get('rev')
2218 2223 if rev:
2219 2224 ctx = repo[rev]
2220 2225 else:
2221 2226 ctx = repo[None]
2222 2227
2223 2228 if file_:
2224 2229 m = cmdutil.match(repo, (file_,), opts)
2225 2230 if m.anypats() or len(m.files()) != 1:
2226 2231 raise util.Abort(_('can only specify an explicit filename'))
2227 2232 file_ = m.files()[0]
2228 2233 filenodes = []
2229 2234 for cp in ctx.parents():
2230 2235 if not cp:
2231 2236 continue
2232 2237 try:
2233 2238 filenodes.append(cp.filenode(file_))
2234 2239 except error.LookupError:
2235 2240 pass
2236 2241 if not filenodes:
2237 2242 raise util.Abort(_("'%s' not found in manifest!") % file_)
2238 2243 fl = repo.file(file_)
2239 2244 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2240 2245 else:
2241 2246 p = [cp.node() for cp in ctx.parents()]
2242 2247
2243 2248 displayer = cmdutil.show_changeset(ui, repo, opts)
2244 2249 for n in p:
2245 2250 if n != nullid:
2246 2251 displayer.show(repo[n])
2247 2252
2248 2253 def paths(ui, repo, search=None):
2249 2254 """show aliases for remote repositories
2250 2255
2251 2256 Show definition of symbolic path name NAME. If no name is given,
2252 2257 show definition of all available names.
2253 2258
2254 2259 Path names are defined in the [paths] section of /etc/mercurial/hgrc
2255 2260 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
2256 2261
2257 2262 See 'hg help urls' for more information.
2258 2263 """
2259 2264 if search:
2260 2265 for name, path in ui.configitems("paths"):
2261 2266 if name == search:
2262 2267 ui.write("%s\n" % url.hidepassword(path))
2263 2268 return
2264 2269 ui.warn(_("not found!\n"))
2265 2270 return 1
2266 2271 else:
2267 2272 for name, path in ui.configitems("paths"):
2268 2273 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2269 2274
2270 2275 def postincoming(ui, repo, modheads, optupdate, checkout):
2271 2276 if modheads == 0:
2272 2277 return
2273 2278 if optupdate:
2274 2279 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2275 2280 return hg.update(repo, checkout)
2276 2281 else:
2277 2282 ui.status(_("not updating, since new heads added\n"))
2278 2283 if modheads > 1:
2279 2284 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2280 2285 else:
2281 2286 ui.status(_("(run 'hg update' to get a working copy)\n"))
2282 2287
2283 2288 def pull(ui, repo, source="default", **opts):
2284 2289 """pull changes from the specified source
2285 2290
2286 2291 Pull changes from a remote repository to a local one.
2287 2292
2288 2293 This finds all changes from the repository at the specified path
2289 2294 or URL and adds them to a local repository (the current one unless
2290 2295 -R is specified). By default, this does not update the copy of the
2291 2296 project in the working directory.
2292 2297
2293 2298 Use hg incoming if you want to see what would have been added by a
2294 2299 pull at the time you issued this command. If you then decide to
2295 2300 added those changes to the repository, you should use pull -r X
2296 2301 where X is the last changeset listed by hg incoming.
2297 2302
2298 2303 If SOURCE is omitted, the 'default' path will be used.
2299 2304 See 'hg help urls' for more information.
2300 2305 """
2301 2306 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts.get('rev'))
2302 2307 other = hg.repository(cmdutil.remoteui(repo, opts), source)
2303 2308 ui.status(_('pulling from %s\n') % url.hidepassword(source))
2304 2309 if revs:
2305 2310 try:
2306 2311 revs = [other.lookup(rev) for rev in revs]
2307 2312 except error.CapabilityError:
2308 2313 err = _("Other repository doesn't support revision lookup, "
2309 2314 "so a rev cannot be specified.")
2310 2315 raise util.Abort(err)
2311 2316
2312 2317 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2313 2318 if checkout:
2314 2319 checkout = str(repo.changelog.rev(other.lookup(checkout)))
2315 2320 return postincoming(ui, repo, modheads, opts.get('update'), checkout)
2316 2321
2317 2322 def push(ui, repo, dest=None, **opts):
2318 2323 """push changes to the specified destination
2319 2324
2320 2325 Push changes from the local repository to the given destination.
2321 2326
2322 2327 This is the symmetrical operation for pull. It moves changes from
2323 2328 the current repository to a different one. If the destination is
2324 2329 local this is identical to a pull in that directory from the
2325 2330 current one.
2326 2331
2327 2332 By default, push will refuse to run if it detects the result would
2328 2333 increase the number of remote heads. This generally indicates the
2329 2334 user forgot to pull and merge before pushing.
2330 2335
2331 2336 If -r/--rev is used, the named revision and all its ancestors will
2332 2337 be pushed to the remote repository.
2333 2338
2334 2339 Please see 'hg help urls' for important details about ``ssh://``
2335 2340 URLs. If DESTINATION is omitted, a default path will be used.
2336 2341 """
2337 2342 dest, revs, checkout = hg.parseurl(
2338 2343 ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev'))
2339 2344 other = hg.repository(cmdutil.remoteui(repo, opts), dest)
2340 2345 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
2341 2346 if revs:
2342 2347 revs = [repo.lookup(rev) for rev in revs]
2343 2348
2344 2349 # push subrepos depth-first for coherent ordering
2345 2350 c = repo['']
2346 2351 subs = c.substate # only repos that are committed
2347 2352 for s in sorted(subs):
2348 2353 c.sub(s).push(opts.get('force'))
2349 2354
2350 2355 r = repo.push(other, opts.get('force'), revs=revs)
2351 2356 return r == 0
2352 2357
2353 2358 def recover(ui, repo):
2354 2359 """roll back an interrupted transaction
2355 2360
2356 2361 Recover from an interrupted commit or pull.
2357 2362
2358 2363 This command tries to fix the repository status after an
2359 2364 interrupted operation. It should only be necessary when Mercurial
2360 2365 suggests it.
2361 2366 """
2362 2367 if repo.recover():
2363 2368 return hg.verify(repo)
2364 2369 return 1
2365 2370
2366 2371 def remove(ui, repo, *pats, **opts):
2367 2372 """remove the specified files on the next commit
2368 2373
2369 2374 Schedule the indicated files for removal from the repository.
2370 2375
2371 2376 This only removes files from the current branch, not from the
2372 2377 entire project history. -A/--after can be used to remove only
2373 2378 files that have already been deleted, -f/--force can be used to
2374 2379 force deletion, and -Af can be used to remove files from the next
2375 2380 revision without deleting them from the working directory.
2376 2381
2377 2382 The following table details the behavior of remove for different
2378 2383 file states (columns) and option combinations (rows). The file
2379 2384 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
2380 2385 reported by hg status). The actions are Warn, Remove (from branch)
2381 2386 and Delete (from disk)::
2382 2387
2383 2388 A C M !
2384 2389 none W RD W R
2385 2390 -f R RD RD R
2386 2391 -A W W W R
2387 2392 -Af R R R R
2388 2393
2389 2394 This command schedules the files to be removed at the next commit.
2390 2395 To undo a remove before that, see hg revert.
2391 2396 """
2392 2397
2393 2398 after, force = opts.get('after'), opts.get('force')
2394 2399 if not pats and not after:
2395 2400 raise util.Abort(_('no files specified'))
2396 2401
2397 2402 m = cmdutil.match(repo, pats, opts)
2398 2403 s = repo.status(match=m, clean=True)
2399 2404 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2400 2405
2401 2406 for f in m.files():
2402 2407 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2403 2408 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
2404 2409
2405 2410 def warn(files, reason):
2406 2411 for f in files:
2407 2412 ui.warn(_('not removing %s: file %s (use -f to force removal)\n')
2408 2413 % (m.rel(f), reason))
2409 2414
2410 2415 if force:
2411 2416 remove, forget = modified + deleted + clean, added
2412 2417 elif after:
2413 2418 remove, forget = deleted, []
2414 2419 warn(modified + added + clean, _('still exists'))
2415 2420 else:
2416 2421 remove, forget = deleted + clean, []
2417 2422 warn(modified, _('is modified'))
2418 2423 warn(added, _('has been marked for add'))
2419 2424
2420 2425 for f in sorted(remove + forget):
2421 2426 if ui.verbose or not m.exact(f):
2422 2427 ui.status(_('removing %s\n') % m.rel(f))
2423 2428
2424 2429 repo.forget(forget)
2425 2430 repo.remove(remove, unlink=not after)
2426 2431
2427 2432 def rename(ui, repo, *pats, **opts):
2428 2433 """rename files; equivalent of copy + remove
2429 2434
2430 2435 Mark dest as copies of sources; mark sources for deletion. If dest
2431 2436 is a directory, copies are put in that directory. If dest is a
2432 2437 file, there can only be one source.
2433 2438
2434 2439 By default, this command copies the contents of files as they
2435 2440 exist in the working directory. If invoked with -A/--after, the
2436 2441 operation is recorded, but no copying is performed.
2437 2442
2438 2443 This command takes effect at the next commit. To undo a rename
2439 2444 before that, see hg revert.
2440 2445 """
2441 2446 wlock = repo.wlock(False)
2442 2447 try:
2443 2448 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2444 2449 finally:
2445 2450 wlock.release()
2446 2451
2447 2452 def resolve(ui, repo, *pats, **opts):
2448 2453 """retry file merges from a merge or update
2449 2454
2450 2455 This command can cleanly retry unresolved file merges using file
2451 2456 revisions preserved from the last update or merge.
2452 2457
2453 2458 If a conflict is resolved manually, please note that the changes
2454 2459 will be overwritten if the merge is retried with resolve. The
2455 2460 -m/--mark switch should be used to mark the file as resolved.
2456 2461
2457 2462 You can specify a set of files to operate on, or use the -a/-all
2458 2463 switch to select all unresolved files.
2459 2464
2460 2465 This command also allows listing resolved files and manually
2461 2466 indicating whether or not files are resolved. All files must be
2462 2467 marked as resolved before a commit is permitted.
2463 2468
2464 2469 The codes used to show the status of files are::
2465 2470
2466 2471 U = unresolved
2467 2472 R = resolved
2468 2473 """
2469 2474
2470 2475 all, mark, unmark, show, nostatus = \
2471 2476 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
2472 2477
2473 2478 if (show and (mark or unmark)) or (mark and unmark):
2474 2479 raise util.Abort(_("too many options specified"))
2475 2480 if pats and all:
2476 2481 raise util.Abort(_("can't specify --all and patterns"))
2477 2482 if not (all or pats or show or mark or unmark):
2478 2483 raise util.Abort(_('no files or directories specified; '
2479 2484 'use --all to remerge all files'))
2480 2485
2481 2486 ms = merge_.mergestate(repo)
2482 2487 m = cmdutil.match(repo, pats, opts)
2483 2488
2484 2489 for f in ms:
2485 2490 if m(f):
2486 2491 if show:
2487 2492 if nostatus:
2488 2493 ui.write("%s\n" % f)
2489 2494 else:
2490 2495 ui.write("%s %s\n" % (ms[f].upper(), f))
2491 2496 elif mark:
2492 2497 ms.mark(f, "r")
2493 2498 elif unmark:
2494 2499 ms.mark(f, "u")
2495 2500 else:
2496 2501 wctx = repo[None]
2497 2502 mctx = wctx.parents()[-1]
2498 2503
2499 2504 # backup pre-resolve (merge uses .orig for its own purposes)
2500 2505 a = repo.wjoin(f)
2501 2506 util.copyfile(a, a + ".resolve")
2502 2507
2503 2508 # resolve file
2504 2509 ms.resolve(f, wctx, mctx)
2505 2510
2506 2511 # replace filemerge's .orig file with our resolve file
2507 2512 util.rename(a + ".resolve", a + ".orig")
2508 2513
2509 2514 def revert(ui, repo, *pats, **opts):
2510 2515 """restore individual files or directories to an earlier state
2511 2516
2512 2517 (Use update -r to check out earlier revisions, revert does not
2513 2518 change the working directory parents.)
2514 2519
2515 2520 With no revision specified, revert the named files or directories
2516 2521 to the contents they had in the parent of the working directory.
2517 2522 This restores the contents of the affected files to an unmodified
2518 2523 state and unschedules adds, removes, copies, and renames. If the
2519 2524 working directory has two parents, you must explicitly specify the
2520 2525 revision to revert to.
2521 2526
2522 2527 Using the -r/--rev option, revert the given files or directories
2523 2528 to their contents as of a specific revision. This can be helpful
2524 2529 to "roll back" some or all of an earlier change. See 'hg help
2525 2530 dates' for a list of formats valid for -d/--date.
2526 2531
2527 2532 Revert modifies the working directory. It does not commit any
2528 2533 changes, or change the parent of the working directory. If you
2529 2534 revert to a revision other than the parent of the working
2530 2535 directory, the reverted files will thus appear modified
2531 2536 afterwards.
2532 2537
2533 2538 If a file has been deleted, it is restored. If the executable mode
2534 2539 of a file was changed, it is reset.
2535 2540
2536 2541 If names are given, all files matching the names are reverted.
2537 2542 If no arguments are given, no files are reverted.
2538 2543
2539 2544 Modified files are saved with a .orig suffix before reverting.
2540 2545 To disable these backups, use --no-backup.
2541 2546 """
2542 2547
2543 2548 if opts["date"]:
2544 2549 if opts["rev"]:
2545 2550 raise util.Abort(_("you can't specify a revision and a date"))
2546 2551 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2547 2552
2548 2553 if not pats and not opts.get('all'):
2549 2554 raise util.Abort(_('no files or directories specified; '
2550 2555 'use --all to revert the whole repo'))
2551 2556
2552 2557 parent, p2 = repo.dirstate.parents()
2553 2558 if not opts.get('rev') and p2 != nullid:
2554 2559 raise util.Abort(_('uncommitted merge - please provide a '
2555 2560 'specific revision'))
2556 2561 ctx = repo[opts.get('rev')]
2557 2562 node = ctx.node()
2558 2563 mf = ctx.manifest()
2559 2564 if node == parent:
2560 2565 pmf = mf
2561 2566 else:
2562 2567 pmf = None
2563 2568
2564 2569 # need all matching names in dirstate and manifest of target rev,
2565 2570 # so have to walk both. do not print errors if files exist in one
2566 2571 # but not other.
2567 2572
2568 2573 names = {}
2569 2574
2570 2575 wlock = repo.wlock()
2571 2576 try:
2572 2577 # walk dirstate.
2573 2578
2574 2579 m = cmdutil.match(repo, pats, opts)
2575 2580 m.bad = lambda x,y: False
2576 2581 for abs in repo.walk(m):
2577 2582 names[abs] = m.rel(abs), m.exact(abs)
2578 2583
2579 2584 # walk target manifest.
2580 2585
2581 2586 def badfn(path, msg):
2582 2587 if path in names:
2583 2588 return
2584 2589 path_ = path + '/'
2585 2590 for f in names:
2586 2591 if f.startswith(path_):
2587 2592 return
2588 2593 ui.warn("%s: %s\n" % (m.rel(path), msg))
2589 2594
2590 2595 m = cmdutil.match(repo, pats, opts)
2591 2596 m.bad = badfn
2592 2597 for abs in repo[node].walk(m):
2593 2598 if abs not in names:
2594 2599 names[abs] = m.rel(abs), m.exact(abs)
2595 2600
2596 2601 m = cmdutil.matchfiles(repo, names)
2597 2602 changes = repo.status(match=m)[:4]
2598 2603 modified, added, removed, deleted = map(set, changes)
2599 2604
2600 2605 # if f is a rename, also revert the source
2601 2606 cwd = repo.getcwd()
2602 2607 for f in added:
2603 2608 src = repo.dirstate.copied(f)
2604 2609 if src and src not in names and repo.dirstate[src] == 'r':
2605 2610 removed.add(src)
2606 2611 names[src] = (repo.pathto(src, cwd), True)
2607 2612
2608 2613 def removeforget(abs):
2609 2614 if repo.dirstate[abs] == 'a':
2610 2615 return _('forgetting %s\n')
2611 2616 return _('removing %s\n')
2612 2617
2613 2618 revert = ([], _('reverting %s\n'))
2614 2619 add = ([], _('adding %s\n'))
2615 2620 remove = ([], removeforget)
2616 2621 undelete = ([], _('undeleting %s\n'))
2617 2622
2618 2623 disptable = (
2619 2624 # dispatch table:
2620 2625 # file state
2621 2626 # action if in target manifest
2622 2627 # action if not in target manifest
2623 2628 # make backup if in target manifest
2624 2629 # make backup if not in target manifest
2625 2630 (modified, revert, remove, True, True),
2626 2631 (added, revert, remove, True, False),
2627 2632 (removed, undelete, None, False, False),
2628 2633 (deleted, revert, remove, False, False),
2629 2634 )
2630 2635
2631 2636 for abs, (rel, exact) in sorted(names.items()):
2632 2637 mfentry = mf.get(abs)
2633 2638 target = repo.wjoin(abs)
2634 2639 def handle(xlist, dobackup):
2635 2640 xlist[0].append(abs)
2636 2641 if dobackup and not opts.get('no_backup') and util.lexists(target):
2637 2642 bakname = "%s.orig" % rel
2638 2643 ui.note(_('saving current version of %s as %s\n') %
2639 2644 (rel, bakname))
2640 2645 if not opts.get('dry_run'):
2641 2646 util.copyfile(target, bakname)
2642 2647 if ui.verbose or not exact:
2643 2648 msg = xlist[1]
2644 2649 if not isinstance(msg, basestring):
2645 2650 msg = msg(abs)
2646 2651 ui.status(msg % rel)
2647 2652 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2648 2653 if abs not in table: continue
2649 2654 # file has changed in dirstate
2650 2655 if mfentry:
2651 2656 handle(hitlist, backuphit)
2652 2657 elif misslist is not None:
2653 2658 handle(misslist, backupmiss)
2654 2659 break
2655 2660 else:
2656 2661 if abs not in repo.dirstate:
2657 2662 if mfentry:
2658 2663 handle(add, True)
2659 2664 elif exact:
2660 2665 ui.warn(_('file not managed: %s\n') % rel)
2661 2666 continue
2662 2667 # file has not changed in dirstate
2663 2668 if node == parent:
2664 2669 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2665 2670 continue
2666 2671 if pmf is None:
2667 2672 # only need parent manifest in this unlikely case,
2668 2673 # so do not read by default
2669 2674 pmf = repo[parent].manifest()
2670 2675 if abs in pmf:
2671 2676 if mfentry:
2672 2677 # if version of file is same in parent and target
2673 2678 # manifests, do nothing
2674 2679 if (pmf[abs] != mfentry or
2675 2680 pmf.flags(abs) != mf.flags(abs)):
2676 2681 handle(revert, False)
2677 2682 else:
2678 2683 handle(remove, False)
2679 2684
2680 2685 if not opts.get('dry_run'):
2681 2686 def checkout(f):
2682 2687 fc = ctx[f]
2683 2688 repo.wwrite(f, fc.data(), fc.flags())
2684 2689
2685 2690 audit_path = util.path_auditor(repo.root)
2686 2691 for f in remove[0]:
2687 2692 if repo.dirstate[f] == 'a':
2688 2693 repo.dirstate.forget(f)
2689 2694 continue
2690 2695 audit_path(f)
2691 2696 try:
2692 2697 util.unlink(repo.wjoin(f))
2693 2698 except OSError:
2694 2699 pass
2695 2700 repo.dirstate.remove(f)
2696 2701
2697 2702 normal = None
2698 2703 if node == parent:
2699 2704 # We're reverting to our parent. If possible, we'd like status
2700 2705 # to report the file as clean. We have to use normallookup for
2701 2706 # merges to avoid losing information about merged/dirty files.
2702 2707 if p2 != nullid:
2703 2708 normal = repo.dirstate.normallookup
2704 2709 else:
2705 2710 normal = repo.dirstate.normal
2706 2711 for f in revert[0]:
2707 2712 checkout(f)
2708 2713 if normal:
2709 2714 normal(f)
2710 2715
2711 2716 for f in add[0]:
2712 2717 checkout(f)
2713 2718 repo.dirstate.add(f)
2714 2719
2715 2720 normal = repo.dirstate.normallookup
2716 2721 if node == parent and p2 == nullid:
2717 2722 normal = repo.dirstate.normal
2718 2723 for f in undelete[0]:
2719 2724 checkout(f)
2720 2725 normal(f)
2721 2726
2722 2727 finally:
2723 2728 wlock.release()
2724 2729
2725 2730 def rollback(ui, repo):
2726 2731 """roll back the last transaction
2727 2732
2728 2733 This command should be used with care. There is only one level of
2729 2734 rollback, and there is no way to undo a rollback. It will also
2730 2735 restore the dirstate at the time of the last transaction, losing
2731 2736 any dirstate changes since that time. This command does not alter
2732 2737 the working directory.
2733 2738
2734 2739 Transactions are used to encapsulate the effects of all commands
2735 2740 that create new changesets or propagate existing changesets into a
2736 2741 repository. For example, the following commands are transactional,
2737 2742 and their effects can be rolled back:
2738 2743
2739 2744 - commit
2740 2745 - import
2741 2746 - pull
2742 2747 - push (with this repository as destination)
2743 2748 - unbundle
2744 2749
2745 2750 This command is not intended for use on public repositories. Once
2746 2751 changes are visible for pull by other users, rolling a transaction
2747 2752 back locally is ineffective (someone else may already have pulled
2748 2753 the changes). Furthermore, a race is possible with readers of the
2749 2754 repository; for example an in-progress pull from the repository
2750 2755 may fail if a rollback is performed.
2751 2756 """
2752 2757 repo.rollback()
2753 2758
2754 2759 def root(ui, repo):
2755 2760 """print the root (top) of the current working directory
2756 2761
2757 2762 Print the root directory of the current repository.
2758 2763 """
2759 2764 ui.write(repo.root + "\n")
2760 2765
2761 2766 def serve(ui, repo, **opts):
2762 2767 """export the repository via HTTP
2763 2768
2764 2769 Start a local HTTP repository browser and pull server.
2765 2770
2766 2771 By default, the server logs accesses to stdout and errors to
2767 2772 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
2768 2773 files.
2769 2774 """
2770 2775
2771 2776 if opts["stdio"]:
2772 2777 if repo is None:
2773 2778 raise error.RepoError(_("There is no Mercurial repository here"
2774 2779 " (.hg not found)"))
2775 2780 s = sshserver.sshserver(ui, repo)
2776 2781 s.serve_forever()
2777 2782
2778 2783 baseui = repo and repo.baseui or ui
2779 2784 optlist = ("name templates style address port prefix ipv6"
2780 2785 " accesslog errorlog webdir_conf certificate encoding")
2781 2786 for o in optlist.split():
2782 2787 if opts.get(o, None):
2783 2788 baseui.setconfig("web", o, str(opts[o]))
2784 2789 if (repo is not None) and (repo.ui != baseui):
2785 2790 repo.ui.setconfig("web", o, str(opts[o]))
2786 2791
2787 2792 if repo is None and not ui.config("web", "webdir_conf"):
2788 2793 raise error.RepoError(_("There is no Mercurial repository here"
2789 2794 " (.hg not found)"))
2790 2795
2791 2796 class service(object):
2792 2797 def init(self):
2793 2798 util.set_signal_handler()
2794 2799 self.httpd = server.create_server(baseui, repo)
2795 2800
2796 2801 if not ui.verbose: return
2797 2802
2798 2803 if self.httpd.prefix:
2799 2804 prefix = self.httpd.prefix.strip('/') + '/'
2800 2805 else:
2801 2806 prefix = ''
2802 2807
2803 2808 port = ':%d' % self.httpd.port
2804 2809 if port == ':80':
2805 2810 port = ''
2806 2811
2807 2812 bindaddr = self.httpd.addr
2808 2813 if bindaddr == '0.0.0.0':
2809 2814 bindaddr = '*'
2810 2815 elif ':' in bindaddr: # IPv6
2811 2816 bindaddr = '[%s]' % bindaddr
2812 2817
2813 2818 fqaddr = self.httpd.fqaddr
2814 2819 if ':' in fqaddr:
2815 2820 fqaddr = '[%s]' % fqaddr
2816 2821 ui.status(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
2817 2822 (fqaddr, port, prefix, bindaddr, self.httpd.port))
2818 2823
2819 2824 def run(self):
2820 2825 self.httpd.serve_forever()
2821 2826
2822 2827 service = service()
2823 2828
2824 2829 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2825 2830
2826 2831 def status(ui, repo, *pats, **opts):
2827 2832 """show changed files in the working directory
2828 2833
2829 2834 Show status of files in the repository. If names are given, only
2830 2835 files that match are shown. Files that are clean or ignored or
2831 2836 the source of a copy/move operation, are not listed unless
2832 2837 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
2833 2838 Unless options described with "show only ..." are given, the
2834 2839 options -mardu are used.
2835 2840
2836 2841 Option -q/--quiet hides untracked (unknown and ignored) files
2837 2842 unless explicitly requested with -u/--unknown or -i/--ignored.
2838 2843
2839 2844 NOTE: status may appear to disagree with diff if permissions have
2840 2845 changed or a merge has occurred. The standard diff format does not
2841 2846 report permission changes and diff only reports changes relative
2842 2847 to one merge parent.
2843 2848
2844 2849 If one revision is given, it is used as the base revision.
2845 2850 If two revisions are given, the differences between them are
2846 2851 shown. The --change option can also be used as a shortcut to list
2847 2852 the changed files of a revision from its first parent.
2848 2853
2849 2854 The codes used to show the status of files are::
2850 2855
2851 2856 M = modified
2852 2857 A = added
2853 2858 R = removed
2854 2859 C = clean
2855 2860 ! = missing (deleted by non-hg command, but still tracked)
2856 2861 ? = not tracked
2857 2862 I = ignored
2858 2863 = origin of the previous file listed as A (added)
2859 2864 """
2860 2865
2861 2866 revs = opts.get('rev')
2862 2867 change = opts.get('change')
2863 2868
2864 2869 if revs and change:
2865 2870 msg = _('cannot specify --rev and --change at the same time')
2866 2871 raise util.Abort(msg)
2867 2872 elif change:
2868 2873 node2 = repo.lookup(change)
2869 2874 node1 = repo[node2].parents()[0].node()
2870 2875 else:
2871 2876 node1, node2 = cmdutil.revpair(repo, revs)
2872 2877
2873 2878 cwd = (pats and repo.getcwd()) or ''
2874 2879 end = opts.get('print0') and '\0' or '\n'
2875 2880 copy = {}
2876 2881 states = 'modified added removed deleted unknown ignored clean'.split()
2877 2882 show = [k for k in states if opts.get(k)]
2878 2883 if opts.get('all'):
2879 2884 show += ui.quiet and (states[:4] + ['clean']) or states
2880 2885 if not show:
2881 2886 show = ui.quiet and states[:4] or states[:5]
2882 2887
2883 2888 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
2884 2889 'ignored' in show, 'clean' in show, 'unknown' in show)
2885 2890 changestates = zip(states, 'MAR!?IC', stat)
2886 2891
2887 2892 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
2888 2893 ctxn = repo[nullid]
2889 2894 ctx1 = repo[node1]
2890 2895 ctx2 = repo[node2]
2891 2896 added = stat[1]
2892 2897 if node2 is None:
2893 2898 added = stat[0] + stat[1] # merged?
2894 2899
2895 2900 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
2896 2901 if k in added:
2897 2902 copy[k] = v
2898 2903 elif v in added:
2899 2904 copy[v] = k
2900 2905
2901 2906 for state, char, files in changestates:
2902 2907 if state in show:
2903 2908 format = "%s %%s%s" % (char, end)
2904 2909 if opts.get('no_status'):
2905 2910 format = "%%s%s" % end
2906 2911
2907 2912 for f in files:
2908 2913 ui.write(format % repo.pathto(f, cwd))
2909 2914 if f in copy:
2910 2915 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end))
2911 2916
2912 2917 def summary(ui, repo, **opts):
2913 2918 """summarize working directory state
2914 2919
2915 2920 This generates a brief summary of the working directory state,
2916 2921 including parents, branch, commit status, and available updates.
2917 2922
2918 2923 With the --remote option, this will check the default paths for
2919 2924 incoming and outgoing changes. This can be time-consuming.
2920 2925 """
2921 2926
2922 2927 ctx = repo[None]
2923 2928 parents = ctx.parents()
2924 2929 pnode = parents[0].node()
2925 2930 tags = repo.tags()
2926 2931
2927 2932 for p in parents:
2928 2933 t = ' '.join([t for t in tags if tags[t] == p.node()])
2929 2934 if p.rev() == -1:
2930 2935 if not len(repo):
2931 2936 t += _(' (empty repository)')
2932 2937 else:
2933 2938 t += _(' (no revision checked out)')
2934 2939 ui.write(_('parent: %d:%s %s\n') % (p.rev(), str(p), t))
2935 2940 if p.description():
2936 2941 ui.status(' ' + p.description().splitlines()[0].strip() + '\n')
2937 2942
2938 2943 branch = ctx.branch()
2939 2944 bheads = repo.branchheads(branch)
2940 2945 m = _('branch: %s\n') % branch
2941 2946 if branch != 'default':
2942 2947 ui.write(m)
2943 2948 else:
2944 2949 ui.status(m)
2945 2950
2946 2951 st = list(repo.status(unknown=True))[:7]
2947 2952 ms = merge_.mergestate(repo)
2948 2953 st.append([f for f in ms if f == 'u'])
2949 2954 labels = [_('%d modified'), _('%d added'), _('%d removed'),
2950 2955 _('%d deleted'), _('%d unknown'), _('%d ignored'),
2951 2956 _('%d unresolved')]
2952 2957 t = []
2953 2958 for s,l in zip(st, labels):
2954 2959 if s:
2955 2960 t.append(l % len(s))
2956 2961
2957 2962 t = ', '.join(t)
2958 2963
2959 2964 if len(parents) > 1:
2960 2965 t += _(' (merge)')
2961 2966 elif branch != parents[0].branch():
2962 2967 t += _(' (new branch)')
2963 2968 elif (not st[0] and not st[1] and not st[2]):
2964 2969 t += _(' (clean)')
2965 2970 elif pnode not in bheads:
2966 2971 t += _(' (new branch head)')
2967 2972
2968 2973 if 'clean' in t:
2969 2974 ui.status(_('commit: %s\n') % t.strip())
2970 2975 else:
2971 2976 ui.write(_('commit: %s\n') % t.strip())
2972 2977
2973 2978 # all ancestors of branch heads - all ancestors of parent = new csets
2974 2979 new = [0] * len(repo)
2975 2980 cl = repo.changelog
2976 2981 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
2977 2982 new[a] = 1
2978 2983 for a in cl.ancestors(*[p.rev() for p in parents]):
2979 2984 new[a] = 0
2980 2985 new = sum(new)
2981 2986
2982 2987 if new == 0:
2983 2988 ui.status(_('update: (current)\n'))
2984 2989 elif pnode not in bheads:
2985 2990 ui.write(_('update: %d new changesets (update)\n') % new)
2986 2991 else:
2987 2992 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
2988 2993 (new, len(bheads)))
2989 2994
2990 2995 if opts.get('remote'):
2991 2996 t = []
2992 2997 source, revs, checkout = hg.parseurl(ui.expandpath('default'),
2993 2998 opts.get('rev'))
2994 2999 other = hg.repository(cmdutil.remoteui(repo, {}), source)
2995 3000 ui.debug('comparing with %s\n' % url.hidepassword(source))
2996 3001 repo.ui.pushbuffer()
2997 3002 common, incoming, rheads = repo.findcommonincoming(other)
2998 3003 repo.ui.popbuffer()
2999 3004 if incoming:
3000 3005 t.append(_('1 or more incoming'))
3001 3006
3002 3007 dest, revs, checkout = hg.parseurl(
3003 3008 ui.expandpath('default-push', 'default'))
3004 3009 other = hg.repository(cmdutil.remoteui(repo, {}), dest)
3005 3010 ui.debug('comparing with %s\n' % url.hidepassword(dest))
3006 3011 repo.ui.pushbuffer()
3007 3012 o = repo.findoutgoing(other)
3008 3013 repo.ui.popbuffer()
3009 3014 o = repo.changelog.nodesbetween(o, revs)[0]
3010 3015 if o:
3011 3016 t.append(_('%d outgoing') % len(o))
3012 3017
3013 3018 if t:
3014 3019 ui.write(_('remote: %s\n') % (', '.join(t)))
3015 3020 else:
3016 3021 ui.status(_('remote: (synced)\n'))
3017 3022
3018 3023 def tag(ui, repo, name1, *names, **opts):
3019 3024 """add one or more tags for the current or given revision
3020 3025
3021 3026 Name a particular revision using <name>.
3022 3027
3023 3028 Tags are used to name particular revisions of the repository and are
3024 3029 very useful to compare different revisions, to go back to significant
3025 3030 earlier versions or to mark branch points as releases, etc.
3026 3031
3027 3032 If no revision is given, the parent of the working directory is
3028 3033 used, or tip if no revision is checked out.
3029 3034
3030 3035 To facilitate version control, distribution, and merging of tags,
3031 3036 they are stored as a file named ".hgtags" which is managed
3032 3037 similarly to other project files and can be hand-edited if
3033 3038 necessary. The file '.hg/localtags' is used for local tags (not
3034 3039 shared among repositories).
3035 3040
3036 3041 See 'hg help dates' for a list of formats valid for -d/--date.
3037 3042 """
3038 3043
3039 3044 rev_ = "."
3040 3045 names = (name1,) + names
3041 3046 if len(names) != len(set(names)):
3042 3047 raise util.Abort(_('tag names must be unique'))
3043 3048 for n in names:
3044 3049 if n in ['tip', '.', 'null']:
3045 3050 raise util.Abort(_('the name \'%s\' is reserved') % n)
3046 3051 if opts.get('rev') and opts.get('remove'):
3047 3052 raise util.Abort(_("--rev and --remove are incompatible"))
3048 3053 if opts.get('rev'):
3049 3054 rev_ = opts['rev']
3050 3055 message = opts.get('message')
3051 3056 if opts.get('remove'):
3052 3057 expectedtype = opts.get('local') and 'local' or 'global'
3053 3058 for n in names:
3054 3059 if not repo.tagtype(n):
3055 3060 raise util.Abort(_('tag \'%s\' does not exist') % n)
3056 3061 if repo.tagtype(n) != expectedtype:
3057 3062 if expectedtype == 'global':
3058 3063 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
3059 3064 else:
3060 3065 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
3061 3066 rev_ = nullid
3062 3067 if not message:
3063 3068 # we don't translate commit messages
3064 3069 message = 'Removed tag %s' % ', '.join(names)
3065 3070 elif not opts.get('force'):
3066 3071 for n in names:
3067 3072 if n in repo.tags():
3068 3073 raise util.Abort(_('tag \'%s\' already exists '
3069 3074 '(use -f to force)') % n)
3070 3075 if not rev_ and repo.dirstate.parents()[1] != nullid:
3071 3076 raise util.Abort(_('uncommitted merge - please provide a '
3072 3077 'specific revision'))
3073 3078 r = repo[rev_].node()
3074 3079
3075 3080 if not message:
3076 3081 # we don't translate commit messages
3077 3082 message = ('Added tag %s for changeset %s' %
3078 3083 (', '.join(names), short(r)))
3079 3084
3080 3085 date = opts.get('date')
3081 3086 if date:
3082 3087 date = util.parsedate(date)
3083 3088
3084 3089 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
3085 3090
3086 3091 def tags(ui, repo):
3087 3092 """list repository tags
3088 3093
3089 3094 This lists both regular and local tags. When the -v/--verbose
3090 3095 switch is used, a third column "local" is printed for local tags.
3091 3096 """
3092 3097
3093 3098 hexfunc = ui.debugflag and hex or short
3094 3099 tagtype = ""
3095 3100
3096 3101 for t, n in reversed(repo.tagslist()):
3097 3102 if ui.quiet:
3098 3103 ui.write("%s\n" % t)
3099 3104 continue
3100 3105
3101 3106 try:
3102 3107 hn = hexfunc(n)
3103 3108 r = "%5d:%s" % (repo.changelog.rev(n), hn)
3104 3109 except error.LookupError:
3105 3110 r = " ?:%s" % hn
3106 3111 else:
3107 3112 spaces = " " * (30 - encoding.colwidth(t))
3108 3113 if ui.verbose:
3109 3114 if repo.tagtype(t) == 'local':
3110 3115 tagtype = " local"
3111 3116 else:
3112 3117 tagtype = ""
3113 3118 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
3114 3119
3115 3120 def tip(ui, repo, **opts):
3116 3121 """show the tip revision
3117 3122
3118 3123 The tip revision (usually just called the tip) is the changeset
3119 3124 most recently added to the repository (and therefore the most
3120 3125 recently changed head).
3121 3126
3122 3127 If you have just made a commit, that commit will be the tip. If
3123 3128 you have just pulled changes from another repository, the tip of
3124 3129 that repository becomes the current tip. The "tip" tag is special
3125 3130 and cannot be renamed or assigned to a different changeset.
3126 3131 """
3127 3132 cmdutil.show_changeset(ui, repo, opts).show(repo[len(repo) - 1])
3128 3133
3129 3134 def unbundle(ui, repo, fname1, *fnames, **opts):
3130 3135 """apply one or more changegroup files
3131 3136
3132 3137 Apply one or more compressed changegroup files generated by the
3133 3138 bundle command.
3134 3139 """
3135 3140 fnames = (fname1,) + fnames
3136 3141
3137 3142 lock = repo.lock()
3138 3143 try:
3139 3144 for fname in fnames:
3140 3145 f = url.open(ui, fname)
3141 3146 gen = changegroup.readbundle(f, fname)
3142 3147 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
3143 3148 finally:
3144 3149 lock.release()
3145 3150
3146 3151 return postincoming(ui, repo, modheads, opts.get('update'), None)
3147 3152
3148 3153 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
3149 3154 """update working directory
3150 3155
3151 3156 Update the repository's working directory to the specified
3152 3157 changeset.
3153 3158
3154 3159 If no changeset is specified, attempt to update to the head of the
3155 3160 current branch. If this head is a descendant of the working
3156 3161 directory's parent, update to it, otherwise abort.
3157 3162
3158 3163 The following rules apply when the working directory contains
3159 3164 uncommitted changes:
3160 3165
3161 3166 1. If neither -c/--check nor -C/--clean is specified, and if
3162 3167 the requested changeset is an ancestor or descendant of
3163 3168 the working directory's parent, the uncommitted changes
3164 3169 are merged into the requested changeset and the merged
3165 3170 result is left uncommitted. If the requested changeset is
3166 3171 not an ancestor or descendant (that is, it is on another
3167 3172 branch), the update is aborted and the uncommitted changes
3168 3173 are preserved.
3169 3174
3170 3175 2. With the -c/--check option, the update is aborted and the
3171 3176 uncommitted changes are preserved.
3172 3177
3173 3178 3. With the -C/--clean option, uncommitted changes are discarded and
3174 3179 the working directory is updated to the requested changeset.
3175 3180
3176 3181 Use null as the changeset to remove the working directory (like 'hg
3177 3182 clone -U').
3178 3183
3179 3184 If you want to update just one file to an older changeset, use 'hg revert'.
3180 3185
3181 3186 See 'hg help dates' for a list of formats valid for -d/--date.
3182 3187 """
3183 3188 if rev and node:
3184 3189 raise util.Abort(_("please specify just one revision"))
3185 3190
3186 3191 if not rev:
3187 3192 rev = node
3188 3193
3189 3194 if check and clean:
3190 3195 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
3191 3196
3192 3197 if check:
3193 3198 # we could use dirty() but we can ignore merge and branch trivia
3194 3199 c = repo[None]
3195 3200 if c.modified() or c.added() or c.removed():
3196 3201 raise util.Abort(_("uncommitted local changes"))
3197 3202
3198 3203 if date:
3199 3204 if rev:
3200 3205 raise util.Abort(_("you can't specify a revision and a date"))
3201 3206 rev = cmdutil.finddate(ui, repo, date)
3202 3207
3203 3208 if clean or check:
3204 3209 return hg.clean(repo, rev)
3205 3210 else:
3206 3211 return hg.update(repo, rev)
3207 3212
3208 3213 def verify(ui, repo):
3209 3214 """verify the integrity of the repository
3210 3215
3211 3216 Verify the integrity of the current repository.
3212 3217
3213 3218 This will perform an extensive check of the repository's
3214 3219 integrity, validating the hashes and checksums of each entry in
3215 3220 the changelog, manifest, and tracked files, as well as the
3216 3221 integrity of their crosslinks and indices.
3217 3222 """
3218 3223 return hg.verify(repo)
3219 3224
3220 3225 def version_(ui):
3221 3226 """output version and copyright information"""
3222 3227 ui.write(_("Mercurial Distributed SCM (version %s)\n")
3223 3228 % util.version())
3224 3229 ui.status(_(
3225 3230 "\nCopyright (C) 2005-2009 Matt Mackall <mpm@selenic.com> and others\n"
3226 3231 "This is free software; see the source for copying conditions. "
3227 3232 "There is NO\nwarranty; "
3228 3233 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
3229 3234 ))
3230 3235
3231 3236 # Command options and aliases are listed here, alphabetically
3232 3237
3233 3238 globalopts = [
3234 3239 ('R', 'repository', '',
3235 3240 _('repository root directory or name of overlay bundle file')),
3236 3241 ('', 'cwd', '', _('change working directory')),
3237 3242 ('y', 'noninteractive', None,
3238 3243 _('do not prompt, assume \'yes\' for any required answers')),
3239 3244 ('q', 'quiet', None, _('suppress output')),
3240 3245 ('v', 'verbose', None, _('enable additional output')),
3241 3246 ('', 'config', [], _('set/override config option')),
3242 3247 ('', 'debug', None, _('enable debugging output')),
3243 3248 ('', 'debugger', None, _('start debugger')),
3244 3249 ('', 'encoding', encoding.encoding, _('set the charset encoding')),
3245 3250 ('', 'encodingmode', encoding.encodingmode,
3246 3251 _('set the charset encoding mode')),
3247 3252 ('', 'traceback', None, _('always print a traceback on exception')),
3248 3253 ('', 'time', None, _('time how long the command takes')),
3249 3254 ('', 'profile', None, _('print command execution profile')),
3250 3255 ('', 'version', None, _('output version information and exit')),
3251 3256 ('h', 'help', None, _('display help and exit')),
3252 3257 ]
3253 3258
3254 3259 dryrunopts = [('n', 'dry-run', None,
3255 3260 _('do not perform actions, just print output'))]
3256 3261
3257 3262 remoteopts = [
3258 3263 ('e', 'ssh', '', _('specify ssh command to use')),
3259 3264 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
3260 3265 ]
3261 3266
3262 3267 walkopts = [
3263 3268 ('I', 'include', [], _('include names matching the given patterns')),
3264 3269 ('X', 'exclude', [], _('exclude names matching the given patterns')),
3265 3270 ]
3266 3271
3267 3272 commitopts = [
3268 3273 ('m', 'message', '', _('use <text> as commit message')),
3269 3274 ('l', 'logfile', '', _('read commit message from <file>')),
3270 3275 ]
3271 3276
3272 3277 commitopts2 = [
3273 3278 ('d', 'date', '', _('record datecode as commit date')),
3274 3279 ('u', 'user', '', _('record the specified user as committer')),
3275 3280 ]
3276 3281
3277 3282 templateopts = [
3278 3283 ('', 'style', '', _('display using template map file')),
3279 3284 ('', 'template', '', _('display with template')),
3280 3285 ]
3281 3286
3282 3287 logopts = [
3283 3288 ('p', 'patch', None, _('show patch')),
3284 3289 ('g', 'git', None, _('use git extended diff format')),
3285 3290 ('l', 'limit', '', _('limit number of changes displayed')),
3286 3291 ('M', 'no-merges', None, _('do not show merges')),
3287 3292 ] + templateopts
3288 3293
3289 3294 diffopts = [
3290 3295 ('a', 'text', None, _('treat all files as text')),
3291 3296 ('g', 'git', None, _('use git extended diff format')),
3292 3297 ('', 'nodates', None, _("don't include dates in diff headers"))
3293 3298 ]
3294 3299
3295 3300 diffopts2 = [
3296 3301 ('p', 'show-function', None, _('show which function each change is in')),
3297 3302 ('', 'reverse', None, _('produce a diff that undoes the changes')),
3298 3303 ('w', 'ignore-all-space', None,
3299 3304 _('ignore white space when comparing lines')),
3300 3305 ('b', 'ignore-space-change', None,
3301 3306 _('ignore changes in the amount of white space')),
3302 3307 ('B', 'ignore-blank-lines', None,
3303 3308 _('ignore changes whose lines are all blank')),
3304 3309 ('U', 'unified', '', _('number of lines of context to show')),
3305 3310 ('', 'stat', None, _('output diffstat-style summary of changes')),
3306 3311 ]
3307 3312
3308 3313 similarityopts = [
3309 3314 ('s', 'similarity', '',
3310 3315 _('guess renamed files by similarity (0<=s<=100)'))
3311 3316 ]
3312 3317
3313 3318 table = {
3314 3319 "^add": (add, walkopts + dryrunopts, _('[OPTION]... [FILE]...')),
3315 3320 "addremove":
3316 3321 (addremove, similarityopts + walkopts + dryrunopts,
3317 3322 _('[OPTION]... [FILE]...')),
3318 3323 "^annotate|blame":
3319 3324 (annotate,
3320 3325 [('r', 'rev', '', _('annotate the specified revision')),
3321 3326 ('f', 'follow', None, _('follow file copies and renames')),
3322 3327 ('a', 'text', None, _('treat all files as text')),
3323 3328 ('u', 'user', None, _('list the author (long with -v)')),
3324 3329 ('d', 'date', None, _('list the date (short with -q)')),
3325 3330 ('n', 'number', None, _('list the revision number (default)')),
3326 3331 ('c', 'changeset', None, _('list the changeset')),
3327 3332 ('l', 'line-number', None,
3328 3333 _('show line number at the first appearance'))
3329 3334 ] + walkopts,
3330 3335 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
3331 3336 "archive":
3332 3337 (archive,
3333 3338 [('', 'no-decode', None, _('do not pass files through decoders')),
3334 3339 ('p', 'prefix', '', _('directory prefix for files in archive')),
3335 3340 ('r', 'rev', '', _('revision to distribute')),
3336 3341 ('t', 'type', '', _('type of distribution to create')),
3337 3342 ] + walkopts,
3338 3343 _('[OPTION]... DEST')),
3339 3344 "backout":
3340 3345 (backout,
3341 3346 [('', 'merge', None,
3342 3347 _('merge with old dirstate parent after backout')),
3343 3348 ('', 'parent', '', _('parent to choose when backing out merge')),
3344 3349 ('r', 'rev', '', _('revision to backout')),
3345 3350 ] + walkopts + commitopts + commitopts2,
3346 3351 _('[OPTION]... [-r] REV')),
3347 3352 "bisect":
3348 3353 (bisect,
3349 3354 [('r', 'reset', False, _('reset bisect state')),
3350 3355 ('g', 'good', False, _('mark changeset good')),
3351 3356 ('b', 'bad', False, _('mark changeset bad')),
3352 3357 ('s', 'skip', False, _('skip testing changeset')),
3353 3358 ('c', 'command', '', _('use command to check changeset state')),
3354 3359 ('U', 'noupdate', False, _('do not update to target'))],
3355 3360 _("[-gbsr] [-U] [-c CMD] [REV]")),
3356 3361 "branch":
3357 3362 (branch,
3358 3363 [('f', 'force', None,
3359 3364 _('set branch name even if it shadows an existing branch')),
3360 3365 ('C', 'clean', None, _('reset branch name to parent branch name'))],
3361 3366 _('[-fC] [NAME]')),
3362 3367 "branches":
3363 3368 (branches,
3364 3369 [('a', 'active', False,
3365 3370 _('show only branches that have unmerged heads')),
3366 3371 ('c', 'closed', False,
3367 3372 _('show normal and closed branches'))],
3368 3373 _('[-ac]')),
3369 3374 "bundle":
3370 3375 (bundle,
3371 3376 [('f', 'force', None,
3372 3377 _('run even when remote repository is unrelated')),
3373 3378 ('r', 'rev', [],
3374 3379 _('a changeset up to which you would like to bundle')),
3375 3380 ('', 'base', [],
3376 3381 _('a base changeset to specify instead of a destination')),
3377 3382 ('a', 'all', None, _('bundle all changesets in the repository')),
3378 3383 ('t', 'type', 'bzip2', _('bundle compression type to use')),
3379 3384 ] + remoteopts,
3380 3385 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
3381 3386 "cat":
3382 3387 (cat,
3383 3388 [('o', 'output', '', _('print output to file with formatted name')),
3384 3389 ('r', 'rev', '', _('print the given revision')),
3385 3390 ('', 'decode', None, _('apply any matching decode filter')),
3386 3391 ] + walkopts,
3387 3392 _('[OPTION]... FILE...')),
3388 3393 "^clone":
3389 3394 (clone,
3390 3395 [('U', 'noupdate', None,
3391 3396 _('the clone will only contain a repository (no working copy)')),
3392 3397 ('u', 'updaterev', '',
3393 3398 _('revision, tag or branch to check out')),
3394 3399 ('r', 'rev', [],
3395 3400 _('clone only the specified revisions and ancestors')),
3396 3401 ('', 'pull', None, _('use pull protocol to copy metadata')),
3397 3402 ('', 'uncompressed', None,
3398 3403 _('use uncompressed transfer (fast over LAN)')),
3399 3404 ] + remoteopts,
3400 3405 _('[OPTION]... SOURCE [DEST]')),
3401 3406 "^commit|ci":
3402 3407 (commit,
3403 3408 [('A', 'addremove', None,
3404 3409 _('mark new/missing files as added/removed before committing')),
3405 3410 ('', 'close-branch', None,
3406 3411 _('mark a branch as closed, hiding it from the branch list')),
3407 3412 ] + walkopts + commitopts + commitopts2,
3408 3413 _('[OPTION]... [FILE]...')),
3409 3414 "copy|cp":
3410 3415 (copy,
3411 3416 [('A', 'after', None, _('record a copy that has already occurred')),
3412 3417 ('f', 'force', None,
3413 3418 _('forcibly copy over an existing managed file')),
3414 3419 ] + walkopts + dryrunopts,
3415 3420 _('[OPTION]... [SOURCE]... DEST')),
3416 3421 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
3417 3422 "debugcheckstate": (debugcheckstate, [], ''),
3418 3423 "debugcommands": (debugcommands, [], _('[COMMAND]')),
3419 3424 "debugcomplete":
3420 3425 (debugcomplete,
3421 3426 [('o', 'options', None, _('show the command options'))],
3422 3427 _('[-o] CMD')),
3423 3428 "debugdate":
3424 3429 (debugdate,
3425 3430 [('e', 'extended', None, _('try extended date formats'))],
3426 3431 _('[-e] DATE [RANGE]')),
3427 3432 "debugdata": (debugdata, [], _('FILE REV')),
3428 3433 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
3429 3434 "debugindex": (debugindex, [], _('FILE')),
3430 3435 "debugindexdot": (debugindexdot, [], _('FILE')),
3431 3436 "debuginstall": (debuginstall, [], ''),
3432 3437 "debugrebuildstate":
3433 3438 (debugrebuildstate,
3434 3439 [('r', 'rev', '', _('revision to rebuild to'))],
3435 3440 _('[-r REV] [REV]')),
3436 3441 "debugrename":
3437 3442 (debugrename,
3438 3443 [('r', 'rev', '', _('revision to debug'))],
3439 3444 _('[-r REV] FILE')),
3440 3445 "debugsetparents":
3441 3446 (debugsetparents, [], _('REV1 [REV2]')),
3442 3447 "debugstate":
3443 3448 (debugstate,
3444 3449 [('', 'nodates', None, _('do not display the saved mtime'))],
3445 3450 _('[OPTION]...')),
3446 3451 "debugsub":
3447 3452 (debugsub,
3448 3453 [('r', 'rev', '', _('revision to check'))],
3449 3454 _('[-r REV] [REV]')),
3450 3455 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
3451 3456 "^diff":
3452 3457 (diff,
3453 3458 [('r', 'rev', [], _('revision')),
3454 3459 ('c', 'change', '', _('change made by revision'))
3455 3460 ] + diffopts + diffopts2 + walkopts,
3456 3461 _('[OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
3457 3462 "^export":
3458 3463 (export,
3459 3464 [('o', 'output', '', _('print output to file with formatted name')),
3460 3465 ('', 'switch-parent', None, _('diff against the second parent')),
3461 3466 ('r', 'rev', [], _('revisions to export')),
3462 3467 ] + diffopts,
3463 3468 _('[OPTION]... [-o OUTFILESPEC] REV...')),
3464 3469 "^forget":
3465 3470 (forget,
3466 3471 [] + walkopts,
3467 3472 _('[OPTION]... FILE...')),
3468 3473 "grep":
3469 3474 (grep,
3470 3475 [('0', 'print0', None, _('end fields with NUL')),
3471 3476 ('', 'all', None, _('print all revisions that match')),
3472 3477 ('f', 'follow', None,
3473 3478 _('follow changeset history, or file history across copies and renames')),
3474 3479 ('i', 'ignore-case', None, _('ignore case when matching')),
3475 3480 ('l', 'files-with-matches', None,
3476 3481 _('print only filenames and revisions that match')),
3477 3482 ('n', 'line-number', None, _('print matching line numbers')),
3478 3483 ('r', 'rev', [], _('search in given revision range')),
3479 3484 ('u', 'user', None, _('list the author (long with -v)')),
3480 3485 ('d', 'date', None, _('list the date (short with -q)')),
3481 3486 ] + walkopts,
3482 3487 _('[OPTION]... PATTERN [FILE]...')),
3483 3488 "heads":
3484 3489 (heads,
3485 3490 [('r', 'rev', '', _('show only heads which are descendants of REV')),
3486 3491 ('a', 'active', False,
3487 3492 _('show only the active branch heads from open branches')),
3488 3493 ('c', 'closed', False,
3489 3494 _('show normal and closed branch heads')),
3490 3495 ] + templateopts,
3491 3496 _('[-ac] [-r STARTREV] [REV]...')),
3492 3497 "help": (help_, [], _('[TOPIC]')),
3493 3498 "identify|id":
3494 3499 (identify,
3495 3500 [('r', 'rev', '', _('identify the specified revision')),
3496 3501 ('n', 'num', None, _('show local revision number')),
3497 3502 ('i', 'id', None, _('show global revision id')),
3498 3503 ('b', 'branch', None, _('show branch')),
3499 3504 ('t', 'tags', None, _('show tags'))],
3500 3505 _('[-nibt] [-r REV] [SOURCE]')),
3501 3506 "import|patch":
3502 3507 (import_,
3503 3508 [('p', 'strip', 1,
3504 3509 _('directory strip option for patch. This has the same '
3505 3510 'meaning as the corresponding patch option')),
3506 3511 ('b', 'base', '', _('base path')),
3507 3512 ('f', 'force', None,
3508 3513 _('skip check for outstanding uncommitted changes')),
3509 3514 ('', 'no-commit', None, _("don't commit, just update the working directory")),
3510 3515 ('', 'exact', None,
3511 3516 _('apply patch to the nodes from which it was generated')),
3512 3517 ('', 'import-branch', None,
3513 3518 _('use any branch information in patch (implied by --exact)'))] +
3514 3519 commitopts + commitopts2 + similarityopts,
3515 3520 _('[OPTION]... PATCH...')),
3516 3521 "incoming|in":
3517 3522 (incoming,
3518 3523 [('f', 'force', None,
3519 3524 _('run even when remote repository is unrelated')),
3520 3525 ('n', 'newest-first', None, _('show newest record first')),
3521 3526 ('', 'bundle', '', _('file to store the bundles into')),
3522 3527 ('r', 'rev', [],
3523 3528 _('a specific remote revision up to which you would like to pull')),
3524 3529 ] + logopts + remoteopts,
3525 3530 _('[-p] [-n] [-M] [-f] [-r REV]...'
3526 3531 ' [--bundle FILENAME] [SOURCE]')),
3527 3532 "^init":
3528 3533 (init,
3529 3534 remoteopts,
3530 3535 _('[-e CMD] [--remotecmd CMD] [DEST]')),
3531 3536 "locate":
3532 3537 (locate,
3533 3538 [('r', 'rev', '', _('search the repository as it stood at REV')),
3534 3539 ('0', 'print0', None,
3535 3540 _('end filenames with NUL, for use with xargs')),
3536 3541 ('f', 'fullpath', None,
3537 3542 _('print complete paths from the filesystem root')),
3538 3543 ] + walkopts,
3539 3544 _('[OPTION]... [PATTERN]...')),
3540 3545 "^log|history":
3541 3546 (log,
3542 3547 [('f', 'follow', None,
3543 3548 _('follow changeset history, or file history across copies and renames')),
3544 3549 ('', 'follow-first', None,
3545 3550 _('only follow the first parent of merge changesets')),
3546 3551 ('d', 'date', '', _('show revisions matching date spec')),
3547 3552 ('C', 'copies', None, _('show copied files')),
3548 3553 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
3549 3554 ('r', 'rev', [], _('show the specified revision or range')),
3550 3555 ('', 'removed', None, _('include revisions where files were removed')),
3551 3556 ('m', 'only-merges', None, _('show only merges')),
3552 3557 ('u', 'user', [], _('revisions committed by user')),
3553 3558 ('b', 'only-branch', [],
3554 3559 _('show only changesets within the given named branch')),
3555 3560 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
3556 3561 ] + logopts + walkopts,
3557 3562 _('[OPTION]... [FILE]')),
3558 3563 "manifest":
3559 3564 (manifest,
3560 3565 [('r', 'rev', '', _('revision to display'))],
3561 3566 _('[-r REV]')),
3562 3567 "^merge":
3563 3568 (merge,
3564 3569 [('f', 'force', None, _('force a merge with outstanding changes')),
3565 3570 ('r', 'rev', '', _('revision to merge')),
3566 3571 ('P', 'preview', None,
3567 3572 _('review revisions to merge (no merge is performed)'))],
3568 3573 _('[-P] [-f] [[-r] REV]')),
3569 3574 "outgoing|out":
3570 3575 (outgoing,
3571 3576 [('f', 'force', None,
3572 3577 _('run even when remote repository is unrelated')),
3573 3578 ('r', 'rev', [],
3574 3579 _('a specific revision up to which you would like to push')),
3575 3580 ('n', 'newest-first', None, _('show newest record first')),
3576 3581 ] + logopts + remoteopts,
3577 3582 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
3578 3583 "parents":
3579 3584 (parents,
3580 3585 [('r', 'rev', '', _('show parents from the specified revision')),
3581 3586 ] + templateopts,
3582 3587 _('[-r REV] [FILE]')),
3583 3588 "paths": (paths, [], _('[NAME]')),
3584 3589 "^pull":
3585 3590 (pull,
3586 3591 [('u', 'update', None,
3587 3592 _('update to new tip if changesets were pulled')),
3588 3593 ('f', 'force', None,
3589 3594 _('run even when remote repository is unrelated')),
3590 3595 ('r', 'rev', [],
3591 3596 _('a specific remote revision up to which you would like to pull')),
3592 3597 ] + remoteopts,
3593 3598 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
3594 3599 "^push":
3595 3600 (push,
3596 3601 [('f', 'force', None, _('force push')),
3597 3602 ('r', 'rev', [],
3598 3603 _('a specific revision up to which you would like to push')),
3599 3604 ] + remoteopts,
3600 3605 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
3601 3606 "recover": (recover, []),
3602 3607 "^remove|rm":
3603 3608 (remove,
3604 3609 [('A', 'after', None, _('record delete for missing files')),
3605 3610 ('f', 'force', None,
3606 3611 _('remove (and delete) file even if added or modified')),
3607 3612 ] + walkopts,
3608 3613 _('[OPTION]... FILE...')),
3609 3614 "rename|mv":
3610 3615 (rename,
3611 3616 [('A', 'after', None, _('record a rename that has already occurred')),
3612 3617 ('f', 'force', None,
3613 3618 _('forcibly copy over an existing managed file')),
3614 3619 ] + walkopts + dryrunopts,
3615 3620 _('[OPTION]... SOURCE... DEST')),
3616 3621 "resolve":
3617 3622 (resolve,
3618 3623 [('a', 'all', None, _('select all unresolved files')),
3619 3624 ('l', 'list', None, _('list state of files needing merge')),
3620 3625 ('m', 'mark', None, _('mark files as resolved')),
3621 3626 ('u', 'unmark', None, _('unmark files as resolved')),
3622 3627 ('n', 'no-status', None, _('hide status prefix'))]
3623 3628 + walkopts,
3624 3629 _('[OPTION]... [FILE]...')),
3625 3630 "revert":
3626 3631 (revert,
3627 3632 [('a', 'all', None, _('revert all changes when no arguments given')),
3628 3633 ('d', 'date', '', _('tipmost revision matching date')),
3629 3634 ('r', 'rev', '', _('revision to revert to')),
3630 3635 ('', 'no-backup', None, _('do not save backup copies of files')),
3631 3636 ] + walkopts + dryrunopts,
3632 3637 _('[OPTION]... [-r REV] [NAME]...')),
3633 3638 "rollback": (rollback, []),
3634 3639 "root": (root, []),
3635 3640 "^serve":
3636 3641 (serve,
3637 3642 [('A', 'accesslog', '', _('name of access log file to write to')),
3638 3643 ('d', 'daemon', None, _('run server in background')),
3639 3644 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3640 3645 ('E', 'errorlog', '', _('name of error log file to write to')),
3641 3646 ('p', 'port', 0, _('port to listen on (default: 8000)')),
3642 3647 ('a', 'address', '', _('address to listen on (default: all interfaces)')),
3643 3648 ('', 'prefix', '', _('prefix path to serve from (default: server root)')),
3644 3649 ('n', 'name', '',
3645 3650 _('name to show in web pages (default: working directory)')),
3646 3651 ('', 'webdir-conf', '', _('name of the webdir config file'
3647 3652 ' (serve more than one repository)')),
3648 3653 ('', 'pid-file', '', _('name of file to write process ID to')),
3649 3654 ('', 'stdio', None, _('for remote clients')),
3650 3655 ('t', 'templates', '', _('web templates to use')),
3651 3656 ('', 'style', '', _('template style to use')),
3652 3657 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
3653 3658 ('', 'certificate', '', _('SSL certificate file'))],
3654 3659 _('[OPTION]...')),
3655 3660 "showconfig|debugconfig":
3656 3661 (showconfig,
3657 3662 [('u', 'untrusted', None, _('show untrusted configuration options'))],
3658 3663 _('[-u] [NAME]...')),
3659 3664 "^summary|sum":
3660 3665 (summary,
3661 3666 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
3662 3667 "^status|st":
3663 3668 (status,
3664 3669 [('A', 'all', None, _('show status of all files')),
3665 3670 ('m', 'modified', None, _('show only modified files')),
3666 3671 ('a', 'added', None, _('show only added files')),
3667 3672 ('r', 'removed', None, _('show only removed files')),
3668 3673 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3669 3674 ('c', 'clean', None, _('show only files without changes')),
3670 3675 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3671 3676 ('i', 'ignored', None, _('show only ignored files')),
3672 3677 ('n', 'no-status', None, _('hide status prefix')),
3673 3678 ('C', 'copies', None, _('show source of copied files')),
3674 3679 ('0', 'print0', None,
3675 3680 _('end filenames with NUL, for use with xargs')),
3676 3681 ('', 'rev', [], _('show difference from revision')),
3677 3682 ('', 'change', '', _('list the changed files of a revision')),
3678 3683 ] + walkopts,
3679 3684 _('[OPTION]... [FILE]...')),
3680 3685 "tag":
3681 3686 (tag,
3682 3687 [('f', 'force', None, _('replace existing tag')),
3683 3688 ('l', 'local', None, _('make the tag local')),
3684 3689 ('r', 'rev', '', _('revision to tag')),
3685 3690 ('', 'remove', None, _('remove a tag')),
3686 3691 # -l/--local is already there, commitopts cannot be used
3687 3692 ('m', 'message', '', _('use <text> as commit message')),
3688 3693 ] + commitopts2,
3689 3694 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
3690 3695 "tags": (tags, [], ''),
3691 3696 "tip":
3692 3697 (tip,
3693 3698 [('p', 'patch', None, _('show patch')),
3694 3699 ('g', 'git', None, _('use git extended diff format')),
3695 3700 ] + templateopts,
3696 3701 _('[-p] [-g]')),
3697 3702 "unbundle":
3698 3703 (unbundle,
3699 3704 [('u', 'update', None,
3700 3705 _('update to new tip if changesets were unbundled'))],
3701 3706 _('[-u] FILE...')),
3702 3707 "^update|up|checkout|co":
3703 3708 (update,
3704 3709 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
3705 3710 ('c', 'check', None, _('check for uncommitted changes')),
3706 3711 ('d', 'date', '', _('tipmost revision matching date')),
3707 3712 ('r', 'rev', '', _('revision'))],
3708 3713 _('[-c] [-C] [-d DATE] [[-r] REV]')),
3709 3714 "verify": (verify, []),
3710 3715 "version": (version_, []),
3711 3716 }
3712 3717
3713 3718 norepo = ("clone init version help debugcommands debugcomplete debugdata"
3714 3719 " debugindex debugindexdot debugdate debuginstall debugfsinfo")
3715 3720 optionalrepo = ("identify paths serve showconfig debugancestor")
@@ -1,511 +1,515 b''
1 1 # dispatch.py - command dispatching 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 of the
6 6 # GNU General Public License version 2, incorporated herein by reference.
7 7
8 8 from i18n import _
9 9 import os, sys, atexit, signal, pdb, socket, errno, shlex, time
10 10 import util, commands, hg, fancyopts, extensions, hook, error
11 11 import cmdutil, encoding
12 12 import ui as _ui
13 13
14 14 def run():
15 15 "run the command in sys.argv"
16 16 sys.exit(dispatch(sys.argv[1:]))
17 17
18 18 def dispatch(args):
19 19 "run the command specified in args"
20 20 try:
21 21 u = _ui.ui()
22 22 if '--traceback' in args:
23 23 u.setconfig('ui', 'traceback', 'on')
24 24 except util.Abort, inst:
25 25 sys.stderr.write(_("abort: %s\n") % inst)
26 26 return -1
27 27 except error.ConfigError, inst:
28 28 sys.stderr.write(_("hg: %s\n") % inst)
29 29 return -1
30 30 return _runcatch(u, args)
31 31
32 32 def _runcatch(ui, args):
33 33 def catchterm(*args):
34 34 raise error.SignalInterrupt
35 35
36 36 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
37 37 num = getattr(signal, name, None)
38 38 if num: signal.signal(num, catchterm)
39 39
40 40 try:
41 41 try:
42 42 # enter the debugger before command execution
43 43 if '--debugger' in args:
44 44 pdb.set_trace()
45 45 try:
46 46 return _dispatch(ui, args)
47 47 finally:
48 48 ui.flush()
49 49 except:
50 50 # enter the debugger when we hit an exception
51 51 if '--debugger' in args:
52 52 pdb.post_mortem(sys.exc_info()[2])
53 53 ui.traceback()
54 54 raise
55 55
56 56 # Global exception handling, alphabetically
57 57 # Mercurial-specific first, followed by built-in and library exceptions
58 58 except error.AmbiguousCommand, inst:
59 59 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
60 60 (inst.args[0], " ".join(inst.args[1])))
61 61 except error.ConfigError, inst:
62 62 ui.warn(_("hg: %s\n") % inst.args[0])
63 63 except error.LockHeld, inst:
64 64 if inst.errno == errno.ETIMEDOUT:
65 65 reason = _('timed out waiting for lock held by %s') % inst.locker
66 66 else:
67 67 reason = _('lock held by %s') % inst.locker
68 68 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
69 69 except error.LockUnavailable, inst:
70 70 ui.warn(_("abort: could not lock %s: %s\n") %
71 71 (inst.desc or inst.filename, inst.strerror))
72 72 except error.ParseError, inst:
73 73 if inst.args[0]:
74 74 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
75 75 commands.help_(ui, inst.args[0])
76 76 else:
77 77 ui.warn(_("hg: %s\n") % inst.args[1])
78 78 commands.help_(ui, 'shortlist')
79 79 except error.RepoError, inst:
80 80 ui.warn(_("abort: %s!\n") % inst)
81 81 except error.ResponseError, inst:
82 82 ui.warn(_("abort: %s") % inst.args[0])
83 83 if not isinstance(inst.args[1], basestring):
84 84 ui.warn(" %r\n" % (inst.args[1],))
85 85 elif not inst.args[1]:
86 86 ui.warn(_(" empty string\n"))
87 87 else:
88 88 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
89 89 except error.RevlogError, inst:
90 90 ui.warn(_("abort: %s!\n") % inst)
91 91 except error.SignalInterrupt:
92 92 ui.warn(_("killed!\n"))
93 93 except error.UnknownCommand, inst:
94 94 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
95 95 commands.help_(ui, 'shortlist')
96 96 except util.Abort, inst:
97 97 ui.warn(_("abort: %s\n") % inst)
98 98 except ImportError, inst:
99 99 m = str(inst).split()[-1]
100 100 ui.warn(_("abort: could not import module %s!\n") % m)
101 101 if m in "mpatch bdiff".split():
102 102 ui.warn(_("(did you forget to compile extensions?)\n"))
103 103 elif m in "zlib".split():
104 104 ui.warn(_("(is your Python install correct?)\n"))
105 105 except IOError, inst:
106 106 if hasattr(inst, "code"):
107 107 ui.warn(_("abort: %s\n") % inst)
108 108 elif hasattr(inst, "reason"):
109 109 try: # usually it is in the form (errno, strerror)
110 110 reason = inst.reason.args[1]
111 111 except: # it might be anything, for example a string
112 112 reason = inst.reason
113 113 ui.warn(_("abort: error: %s\n") % reason)
114 114 elif hasattr(inst, "args") and inst.args[0] == errno.EPIPE:
115 115 if ui.debugflag:
116 116 ui.warn(_("broken pipe\n"))
117 117 elif getattr(inst, "strerror", None):
118 118 if getattr(inst, "filename", None):
119 119 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
120 120 else:
121 121 ui.warn(_("abort: %s\n") % inst.strerror)
122 122 else:
123 123 raise
124 124 except OSError, inst:
125 125 if getattr(inst, "filename", None):
126 126 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
127 127 else:
128 128 ui.warn(_("abort: %s\n") % inst.strerror)
129 129 except KeyboardInterrupt:
130 130 try:
131 131 ui.warn(_("interrupted!\n"))
132 132 except IOError, inst:
133 133 if inst.errno == errno.EPIPE:
134 134 if ui.debugflag:
135 135 ui.warn(_("\nbroken pipe\n"))
136 136 else:
137 137 raise
138 138 except MemoryError:
139 139 ui.warn(_("abort: out of memory\n"))
140 140 except SystemExit, inst:
141 141 # Commands shouldn't sys.exit directly, but give a return code.
142 142 # Just in case catch this and and pass exit code to caller.
143 143 return inst.code
144 144 except socket.error, inst:
145 145 ui.warn(_("abort: %s\n") % inst.args[-1])
146 146 except:
147 147 ui.warn(_("** unknown exception encountered, details follow\n"))
148 148 ui.warn(_("** report bug details to "
149 149 "http://mercurial.selenic.com/bts/\n"))
150 150 ui.warn(_("** or mercurial@selenic.com\n"))
151 151 ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
152 152 % util.version())
153 153 ui.warn(_("** Extensions loaded: %s\n")
154 154 % ", ".join([x[0] for x in extensions.extensions()]))
155 155 raise
156 156
157 157 return -1
158 158
159 159 def _findrepo(p):
160 160 while not os.path.isdir(os.path.join(p, ".hg")):
161 161 oldp, p = p, os.path.dirname(p)
162 162 if p == oldp:
163 163 return None
164 164
165 165 return p
166 166
167 167 def aliasargs(fn):
168 168 if hasattr(fn, 'args'):
169 169 return fn.args
170 170 return []
171 171
172 172 class cmdalias(object):
173 173 def __init__(self, name, definition, cmdtable):
174 174 self.name = name
175 175 self.definition = definition
176 176 self.args = []
177 177 self.opts = []
178 178 self.help = ''
179 179 self.norepo = True
180 self.badalias = False
180 181
181 182 try:
182 183 cmdutil.findcmd(self.name, cmdtable, True)
183 184 self.shadows = True
184 185 except error.UnknownCommand:
185 186 self.shadows = False
186 187
187 188 if not self.definition:
188 189 def fn(ui, *args):
189 190 ui.warn(_("no definition for alias '%s'\n") % self.name)
190 191 return 1
191 192 self.fn = fn
193 self.badalias = True
192 194
193 195 return
194 196
195 197 args = shlex.split(self.definition)
196 198 cmd = args.pop(0)
197 199
198 200 try:
199 201 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
200 202 if len(tableentry) > 2:
201 203 self.fn, self.opts, self.help = tableentry
202 204 else:
203 205 self.fn, self.opts = tableentry
204 206
205 207 self.args = aliasargs(self.fn) + args
206 208 if cmd not in commands.norepo.split(' '):
207 209 self.norepo = False
208 210 if self.help.startswith("hg " + cmd):
209 211 # drop prefix in old-style help lines so hg shows the alias
210 212 self.help = self.help[4 + len(cmd):]
211 213 self.__doc__ = _("alias for: hg %s\n\n%s") \
212 214 % (definition, self.fn.__doc__)
213 215
214 216 except error.UnknownCommand:
215 217 def fn(ui, *args):
216 218 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
217 219 % (self.name, cmd))
218 220 return 1
219 221 self.fn = fn
222 self.badalias = True
220 223 except error.AmbiguousCommand:
221 224 def fn(ui, *args):
222 225 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
223 226 % (self.name, cmd))
224 227 return 1
225 228 self.fn = fn
229 self.badalias = True
226 230
227 231 def __call__(self, ui, *args, **opts):
228 232 if self.shadows:
229 233 ui.debug("alias '%s' shadows command\n" % self.name)
230 234
231 235 return self.fn(ui, *args, **opts)
232 236
233 237 def addaliases(ui, cmdtable):
234 238 # aliases are processed after extensions have been loaded, so they
235 239 # may use extension commands. Aliases can also use other alias definitions,
236 240 # but only if they have been defined prior to the current definition.
237 241 for alias, definition in ui.configitems('alias'):
238 242 aliasdef = cmdalias(alias, definition, cmdtable)
239 243 cmdtable[alias] = (aliasdef, aliasdef.opts, aliasdef.help)
240 244 if aliasdef.norepo:
241 245 commands.norepo += ' %s' % alias
242 246
243 247 def _parse(ui, args):
244 248 options = {}
245 249 cmdoptions = {}
246 250
247 251 try:
248 252 args = fancyopts.fancyopts(args, commands.globalopts, options)
249 253 except fancyopts.getopt.GetoptError, inst:
250 254 raise error.ParseError(None, inst)
251 255
252 256 if args:
253 257 cmd, args = args[0], args[1:]
254 258 aliases, entry = cmdutil.findcmd(cmd, commands.table,
255 259 ui.config("ui", "strict"))
256 260 cmd = aliases[0]
257 261 args = aliasargs(entry[0]) + args
258 262 defaults = ui.config("defaults", cmd)
259 263 if defaults:
260 264 args = map(util.expandpath, shlex.split(defaults)) + args
261 265 c = list(entry[1])
262 266 else:
263 267 cmd = None
264 268 c = []
265 269
266 270 # combine global options into local
267 271 for o in commands.globalopts:
268 272 c.append((o[0], o[1], options[o[1]], o[3]))
269 273
270 274 try:
271 275 args = fancyopts.fancyopts(args, c, cmdoptions, True)
272 276 except fancyopts.getopt.GetoptError, inst:
273 277 raise error.ParseError(cmd, inst)
274 278
275 279 # separate global options back out
276 280 for o in commands.globalopts:
277 281 n = o[1]
278 282 options[n] = cmdoptions[n]
279 283 del cmdoptions[n]
280 284
281 285 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
282 286
283 287 def _parseconfig(ui, config):
284 288 """parse the --config options from the command line"""
285 289 for cfg in config:
286 290 try:
287 291 name, value = cfg.split('=', 1)
288 292 section, name = name.split('.', 1)
289 293 if not section or not name:
290 294 raise IndexError
291 295 ui.setconfig(section, name, value)
292 296 except (IndexError, ValueError):
293 297 raise util.Abort(_('malformed --config option: %r '
294 298 '(use --config section.name=value)') % cfg)
295 299
296 300 def _earlygetopt(aliases, args):
297 301 """Return list of values for an option (or aliases).
298 302
299 303 The values are listed in the order they appear in args.
300 304 The options and values are removed from args.
301 305 """
302 306 try:
303 307 argcount = args.index("--")
304 308 except ValueError:
305 309 argcount = len(args)
306 310 shortopts = [opt for opt in aliases if len(opt) == 2]
307 311 values = []
308 312 pos = 0
309 313 while pos < argcount:
310 314 if args[pos] in aliases:
311 315 if pos + 1 >= argcount:
312 316 # ignore and let getopt report an error if there is no value
313 317 break
314 318 del args[pos]
315 319 values.append(args.pop(pos))
316 320 argcount -= 2
317 321 elif args[pos][:2] in shortopts:
318 322 # short option can have no following space, e.g. hg log -Rfoo
319 323 values.append(args.pop(pos)[2:])
320 324 argcount -= 1
321 325 else:
322 326 pos += 1
323 327 return values
324 328
325 329 def runcommand(lui, repo, cmd, fullargs, ui, options, d):
326 330 # run pre-hook, and abort if it fails
327 331 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs))
328 332 if ret:
329 333 return ret
330 334 ret = _runcommand(ui, options, cmd, d)
331 335 # run post-hook, passing command result
332 336 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
333 337 result = ret)
334 338 return ret
335 339
336 340 _loaded = set()
337 341 def _dispatch(ui, args):
338 342 # read --config before doing anything else
339 343 # (e.g. to change trust settings for reading .hg/hgrc)
340 344 _parseconfig(ui, _earlygetopt(['--config'], args))
341 345
342 346 # check for cwd
343 347 cwd = _earlygetopt(['--cwd'], args)
344 348 if cwd:
345 349 os.chdir(cwd[-1])
346 350
347 351 # read the local repository .hgrc into a local ui object
348 352 path = _findrepo(os.getcwd()) or ""
349 353 if not path:
350 354 lui = ui
351 355 else:
352 356 try:
353 357 lui = ui.copy()
354 358 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
355 359 except IOError:
356 360 pass
357 361
358 362 # now we can expand paths, even ones in .hg/hgrc
359 363 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
360 364 if rpath:
361 365 path = lui.expandpath(rpath[-1])
362 366 lui = ui.copy()
363 367 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
364 368
365 369 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
366 370 # reposetup. Programs like TortoiseHg will call _dispatch several
367 371 # times so we keep track of configured extensions in _loaded.
368 372 extensions.loadall(lui)
369 373 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
370 374
371 375 # (uisetup and extsetup are handled in extensions.loadall)
372 376
373 377 for name, module in exts:
374 378 cmdtable = getattr(module, 'cmdtable', {})
375 379 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
376 380 if overrides:
377 381 ui.warn(_("extension '%s' overrides commands: %s\n")
378 382 % (name, " ".join(overrides)))
379 383 commands.table.update(cmdtable)
380 384 _loaded.add(name)
381 385
382 386 # (reposetup is handled in hg.repository)
383 387
384 388 addaliases(lui, commands.table)
385 389
386 390 # check for fallback encoding
387 391 fallback = lui.config('ui', 'fallbackencoding')
388 392 if fallback:
389 393 encoding.fallbackencoding = fallback
390 394
391 395 fullargs = args
392 396 cmd, func, args, options, cmdoptions = _parse(lui, args)
393 397
394 398 if options["config"]:
395 399 raise util.Abort(_("Option --config may not be abbreviated!"))
396 400 if options["cwd"]:
397 401 raise util.Abort(_("Option --cwd may not be abbreviated!"))
398 402 if options["repository"]:
399 403 raise util.Abort(_(
400 404 "Option -R has to be separated from other options (e.g. not -qR) "
401 405 "and --repository may only be abbreviated as --repo!"))
402 406
403 407 if options["encoding"]:
404 408 encoding.encoding = options["encoding"]
405 409 if options["encodingmode"]:
406 410 encoding.encodingmode = options["encodingmode"]
407 411 if options["time"]:
408 412 def get_times():
409 413 t = os.times()
410 414 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
411 415 t = (t[0], t[1], t[2], t[3], time.clock())
412 416 return t
413 417 s = get_times()
414 418 def print_time():
415 419 t = get_times()
416 420 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
417 421 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
418 422 atexit.register(print_time)
419 423
420 424 if options['verbose'] or options['debug'] or options['quiet']:
421 425 ui.setconfig('ui', 'verbose', str(bool(options['verbose'])))
422 426 ui.setconfig('ui', 'debug', str(bool(options['debug'])))
423 427 ui.setconfig('ui', 'quiet', str(bool(options['quiet'])))
424 428 if options['traceback']:
425 429 ui.setconfig('ui', 'traceback', 'on')
426 430 if options['noninteractive']:
427 431 ui.setconfig('ui', 'interactive', 'off')
428 432
429 433 if options['help']:
430 434 return commands.help_(ui, cmd, options['version'])
431 435 elif options['version']:
432 436 return commands.version_(ui)
433 437 elif not cmd:
434 438 return commands.help_(ui, 'shortlist')
435 439
436 440 repo = None
437 441 if cmd not in commands.norepo.split():
438 442 try:
439 443 repo = hg.repository(ui, path=path)
440 444 ui = repo.ui
441 445 if not repo.local():
442 446 raise util.Abort(_("repository '%s' is not local") % path)
443 447 ui.setconfig("bundle", "mainreporoot", repo.root)
444 448 except error.RepoError:
445 449 if cmd not in commands.optionalrepo.split():
446 450 if args and not path: # try to infer -R from command args
447 451 repos = map(_findrepo, args)
448 452 guess = repos[0]
449 453 if guess and repos.count(guess) == len(repos):
450 454 return _dispatch(ui, ['--repository', guess] + fullargs)
451 455 if not path:
452 456 raise error.RepoError(_("There is no Mercurial repository"
453 457 " here (.hg not found)"))
454 458 raise
455 459 args.insert(0, repo)
456 460 elif rpath:
457 461 ui.warn("warning: --repository ignored\n")
458 462
459 463 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
460 464 return runcommand(lui, repo, cmd, fullargs, ui, options, d)
461 465
462 466 def _runcommand(ui, options, cmd, cmdfunc):
463 467 def checkargs():
464 468 try:
465 469 return cmdfunc()
466 470 except error.SignatureError:
467 471 raise error.ParseError(cmd, _("invalid arguments"))
468 472
469 473 if options['profile']:
470 474 format = ui.config('profiling', 'format', default='text')
471 475
472 476 if not format in ['text', 'kcachegrind']:
473 477 ui.warn(_("unrecognized profiling format '%s'"
474 478 " - Ignored\n") % format)
475 479 format = 'text'
476 480
477 481 output = ui.config('profiling', 'output')
478 482
479 483 if output:
480 484 path = ui.expandpath(output)
481 485 ostream = open(path, 'wb')
482 486 else:
483 487 ostream = sys.stderr
484 488
485 489 try:
486 490 from mercurial import lsprof
487 491 except ImportError:
488 492 raise util.Abort(_(
489 493 'lsprof not available - install from '
490 494 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
491 495 p = lsprof.Profiler()
492 496 p.enable(subcalls=True)
493 497 try:
494 498 return checkargs()
495 499 finally:
496 500 p.disable()
497 501
498 502 if format == 'kcachegrind':
499 503 import lsprofcalltree
500 504 calltree = lsprofcalltree.KCacheGrind(p)
501 505 calltree.output(ostream)
502 506 else:
503 507 # format == 'text'
504 508 stats = lsprof.Stats(p.getstats())
505 509 stats.sort()
506 510 stats.pprint(top=10, file=ostream, climit=5)
507 511
508 512 if output:
509 513 ostream.close()
510 514 else:
511 515 return checkargs()
@@ -1,57 +1,61 b''
1 1 #!/bin/sh
2 2
3 3 cat >> $HGRCPATH <<EOF
4 4 [alias]
5 5 myinit = init
6 6 cleanstatus = status -c
7 7 unknown = bargle
8 8 ambiguous = s
9 9 recursive = recursive
10 10 nodefinition =
11 11 mylog = log
12 12 lognull = log -r null
13 13 shortlog = log --template '{rev} {node|short} | {date|isodate}\n'
14 14 dln = lognull --debug
15 15 nousage = rollback
16 16
17 17 [defaults]
18 18 mylog = -q
19 19 lognull = -q
20 20 log = -v
21 21 EOF
22 22
23 23 echo '% basic'
24 24 hg myinit alias
25 25
26 26 echo '% unknown'
27 27 hg unknown
28 hg help unknown
28 29
29 30 echo '% ambiguous'
30 31 hg ambiguous
32 hg help ambiguous
31 33
32 34 echo '% recursive'
33 35 hg recursive
36 hg help recursive
34 37
35 38 echo '% no definition'
36 39 hg nodef
40 hg help nodef
37 41
38 42 cd alias
39 43
40 44 echo '% no usage'
41 45 hg nousage
42 46
43 47 echo foo > foo
44 48 hg ci -Amfoo
45 49
46 50 echo '% with opts'
47 51 hg cleanst
48 52
49 53 echo '% with opts and whitespace'
50 54 hg shortlog
51 55
52 56 echo '% interaction with defaults'
53 57 hg mylog
54 58 hg lognull
55 59
56 60 echo '% properly recursive'
57 61 hg dln
@@ -1,28 +1,32 b''
1 1 % basic
2 2 % unknown
3 3 alias 'unknown' resolves to unknown command 'bargle'
4 alias 'unknown' resolves to unknown command 'bargle'
4 5 % ambiguous
5 6 alias 'ambiguous' resolves to ambiguous command 's'
7 alias 'ambiguous' resolves to ambiguous command 's'
6 8 % recursive
7 9 alias 'recursive' resolves to unknown command 'recursive'
10 alias 'recursive' resolves to unknown command 'recursive'
8 11 % no definition
9 12 no definition for alias 'nodefinition'
13 no definition for alias 'nodefinition'
10 14 % no usage
11 15 no rollback information available
12 16 adding foo
13 17 % with opts
14 18 C foo
15 19 % with opts and whitespace
16 20 0 e63c23eaa88a | 1970-01-01 00:00 +0000
17 21 % interaction with defaults
18 22 0:e63c23eaa88a
19 23 -1:000000000000
20 24 % properly recursive
21 25 changeset: -1:0000000000000000000000000000000000000000
22 26 parent: -1:0000000000000000000000000000000000000000
23 27 parent: -1:0000000000000000000000000000000000000000
24 28 manifest: -1:0000000000000000000000000000000000000000
25 29 user:
26 30 date: Thu Jan 01 00:00:00 1970 +0000
27 31 extra: branch=default
28 32
General Comments 0
You need to be logged in to leave comments. Login now