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