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