##// END OF EJS Templates
tags: no need to check for valid nodes...
Idan Kamara -
r13893:1aea8667 default
parent child Browse files
Show More
@@ -1,4877 +1,4874
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].p1().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 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 1347 if datesort:
1348 1348 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
1349 1349 else:
1350 1350 keyfunc = None # sort by filename
1351 1351 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
1352 1352 if showdate:
1353 1353 if ent[3] == -1:
1354 1354 # Pad or slice to locale representation
1355 1355 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1356 1356 time.localtime(0)))
1357 1357 timestr = 'unset'
1358 1358 timestr = (timestr[:locale_len] +
1359 1359 ' ' * (locale_len - len(timestr)))
1360 1360 else:
1361 1361 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1362 1362 time.localtime(ent[3]))
1363 1363 if ent[1] & 020000:
1364 1364 mode = 'lnk'
1365 1365 else:
1366 1366 mode = '%3o' % (ent[1] & 0777)
1367 1367 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1368 1368 for f in repo.dirstate.copies():
1369 1369 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1370 1370
1371 1371 def debugsub(ui, repo, rev=None):
1372 1372 ctx = cmdutil.revsingle(repo, rev, None)
1373 1373 for k, v in sorted(ctx.substate.items()):
1374 1374 ui.write('path %s\n' % k)
1375 1375 ui.write(' source %s\n' % v[0])
1376 1376 ui.write(' revision %s\n' % v[1])
1377 1377
1378 1378 def debugdag(ui, repo, file_=None, *revs, **opts):
1379 1379 """format the changelog or an index DAG as a concise textual description
1380 1380
1381 1381 If you pass a revlog index, the revlog's DAG is emitted. If you list
1382 1382 revision numbers, they get labelled in the output as rN.
1383 1383
1384 1384 Otherwise, the changelog DAG of the current repo is emitted.
1385 1385 """
1386 1386 spaces = opts.get('spaces')
1387 1387 dots = opts.get('dots')
1388 1388 if file_:
1389 1389 rlog = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1390 1390 revs = set((int(r) for r in revs))
1391 1391 def events():
1392 1392 for r in rlog:
1393 1393 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1394 1394 if r in revs:
1395 1395 yield 'l', (r, "r%i" % r)
1396 1396 elif repo:
1397 1397 cl = repo.changelog
1398 1398 tags = opts.get('tags')
1399 1399 branches = opts.get('branches')
1400 1400 if tags:
1401 1401 labels = {}
1402 1402 for l, n in repo.tags().items():
1403 1403 labels.setdefault(cl.rev(n), []).append(l)
1404 1404 def events():
1405 1405 b = "default"
1406 1406 for r in cl:
1407 1407 if branches:
1408 1408 newb = cl.read(cl.node(r))[5]['branch']
1409 1409 if newb != b:
1410 1410 yield 'a', newb
1411 1411 b = newb
1412 1412 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1413 1413 if tags:
1414 1414 ls = labels.get(r)
1415 1415 if ls:
1416 1416 for l in ls:
1417 1417 yield 'l', (r, l)
1418 1418 else:
1419 1419 raise util.Abort(_('need repo for changelog dag'))
1420 1420
1421 1421 for line in dagparser.dagtextlines(events(),
1422 1422 addspaces=spaces,
1423 1423 wraplabels=True,
1424 1424 wrapannotations=True,
1425 1425 wrapnonlinear=dots,
1426 1426 usedots=dots,
1427 1427 maxlinewidth=70):
1428 1428 ui.write(line)
1429 1429 ui.write("\n")
1430 1430
1431 1431 def debugdata(ui, repo, file_, rev):
1432 1432 """dump the contents of a data file revision"""
1433 1433 r = None
1434 1434 if repo:
1435 1435 filelog = repo.file(file_)
1436 1436 if len(filelog):
1437 1437 r = filelog
1438 1438 if not r:
1439 1439 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
1440 1440 try:
1441 1441 ui.write(r.revision(r.lookup(rev)))
1442 1442 except KeyError:
1443 1443 raise util.Abort(_('invalid revision identifier %s') % rev)
1444 1444
1445 1445 def debugdate(ui, date, range=None, **opts):
1446 1446 """parse and display a date"""
1447 1447 if opts["extended"]:
1448 1448 d = util.parsedate(date, util.extendeddateformats)
1449 1449 else:
1450 1450 d = util.parsedate(date)
1451 1451 ui.write("internal: %s %s\n" % d)
1452 1452 ui.write("standard: %s\n" % util.datestr(d))
1453 1453 if range:
1454 1454 m = util.matchdate(range)
1455 1455 ui.write("match: %s\n" % m(d[0]))
1456 1456
1457 1457 def debugignore(ui, repo, *values, **opts):
1458 1458 """display the combined ignore pattern"""
1459 1459 ignore = repo.dirstate._ignore
1460 1460 if hasattr(ignore, 'includepat'):
1461 1461 ui.write("%s\n" % ignore.includepat)
1462 1462 else:
1463 1463 raise util.Abort(_("no ignore patterns found"))
1464 1464
1465 1465 def debugindex(ui, repo, file_, **opts):
1466 1466 """dump the contents of an index file"""
1467 1467 r = None
1468 1468 if repo:
1469 1469 filelog = repo.file(file_)
1470 1470 if len(filelog):
1471 1471 r = filelog
1472 1472
1473 1473 format = opts.get('format', 0)
1474 1474 if format not in (0, 1):
1475 1475 raise util.Abort(_("unknown format %d") % format)
1476 1476
1477 1477 if not r:
1478 1478 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1479 1479
1480 1480 if format == 0:
1481 1481 ui.write(" rev offset length base linkrev"
1482 1482 " nodeid p1 p2\n")
1483 1483 elif format == 1:
1484 1484 ui.write(" rev flag offset length"
1485 1485 " size base link p1 p2 nodeid\n")
1486 1486
1487 1487 for i in r:
1488 1488 node = r.node(i)
1489 1489 if format == 0:
1490 1490 try:
1491 1491 pp = r.parents(node)
1492 1492 except:
1493 1493 pp = [nullid, nullid]
1494 1494 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1495 1495 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1496 1496 short(node), short(pp[0]), short(pp[1])))
1497 1497 elif format == 1:
1498 1498 pr = r.parentrevs(i)
1499 1499 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1500 1500 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1501 1501 r.base(i), r.linkrev(i), pr[0], pr[1], short(node)))
1502 1502
1503 1503 def debugindexdot(ui, repo, file_):
1504 1504 """dump an index DAG as a graphviz dot file"""
1505 1505 r = None
1506 1506 if repo:
1507 1507 filelog = repo.file(file_)
1508 1508 if len(filelog):
1509 1509 r = filelog
1510 1510 if not r:
1511 1511 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1512 1512 ui.write("digraph G {\n")
1513 1513 for i in r:
1514 1514 node = r.node(i)
1515 1515 pp = r.parents(node)
1516 1516 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1517 1517 if pp[1] != nullid:
1518 1518 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1519 1519 ui.write("}\n")
1520 1520
1521 1521 def debuginstall(ui):
1522 1522 '''test Mercurial installation
1523 1523
1524 1524 Returns 0 on success.
1525 1525 '''
1526 1526
1527 1527 def writetemp(contents):
1528 1528 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1529 1529 f = os.fdopen(fd, "wb")
1530 1530 f.write(contents)
1531 1531 f.close()
1532 1532 return name
1533 1533
1534 1534 problems = 0
1535 1535
1536 1536 # encoding
1537 1537 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1538 1538 try:
1539 1539 encoding.fromlocal("test")
1540 1540 except util.Abort, inst:
1541 1541 ui.write(" %s\n" % inst)
1542 1542 ui.write(_(" (check that your locale is properly set)\n"))
1543 1543 problems += 1
1544 1544
1545 1545 # compiled modules
1546 1546 ui.status(_("Checking installed modules (%s)...\n")
1547 1547 % os.path.dirname(__file__))
1548 1548 try:
1549 1549 import bdiff, mpatch, base85, osutil
1550 1550 except Exception, inst:
1551 1551 ui.write(" %s\n" % inst)
1552 1552 ui.write(_(" One or more extensions could not be found"))
1553 1553 ui.write(_(" (check that you compiled the extensions)\n"))
1554 1554 problems += 1
1555 1555
1556 1556 # templates
1557 1557 ui.status(_("Checking templates...\n"))
1558 1558 try:
1559 1559 import templater
1560 1560 templater.templater(templater.templatepath("map-cmdline.default"))
1561 1561 except Exception, inst:
1562 1562 ui.write(" %s\n" % inst)
1563 1563 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1564 1564 problems += 1
1565 1565
1566 1566 # editor
1567 1567 ui.status(_("Checking commit editor...\n"))
1568 1568 editor = ui.geteditor()
1569 1569 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1570 1570 if not cmdpath:
1571 1571 if editor == 'vi':
1572 1572 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1573 1573 ui.write(_(" (specify a commit editor in your configuration"
1574 1574 " file)\n"))
1575 1575 else:
1576 1576 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1577 1577 ui.write(_(" (specify a commit editor in your configuration"
1578 1578 " file)\n"))
1579 1579 problems += 1
1580 1580
1581 1581 # check username
1582 1582 ui.status(_("Checking username...\n"))
1583 1583 try:
1584 1584 ui.username()
1585 1585 except util.Abort, e:
1586 1586 ui.write(" %s\n" % e)
1587 1587 ui.write(_(" (specify a username in your configuration file)\n"))
1588 1588 problems += 1
1589 1589
1590 1590 if not problems:
1591 1591 ui.status(_("No problems detected\n"))
1592 1592 else:
1593 1593 ui.write(_("%s problems detected,"
1594 1594 " please check your install!\n") % problems)
1595 1595
1596 1596 return problems
1597 1597
1598 1598 def debugrename(ui, repo, file1, *pats, **opts):
1599 1599 """dump rename information"""
1600 1600
1601 1601 ctx = cmdutil.revsingle(repo, opts.get('rev'))
1602 1602 m = cmdutil.match(repo, (file1,) + pats, opts)
1603 1603 for abs in ctx.walk(m):
1604 1604 fctx = ctx[abs]
1605 1605 o = fctx.filelog().renamed(fctx.filenode())
1606 1606 rel = m.rel(abs)
1607 1607 if o:
1608 1608 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1609 1609 else:
1610 1610 ui.write(_("%s not renamed\n") % rel)
1611 1611
1612 1612 def debugwalk(ui, repo, *pats, **opts):
1613 1613 """show how files match on given patterns"""
1614 1614 m = cmdutil.match(repo, pats, opts)
1615 1615 items = list(repo.walk(m))
1616 1616 if not items:
1617 1617 return
1618 1618 fmt = 'f %%-%ds %%-%ds %%s' % (
1619 1619 max([len(abs) for abs in items]),
1620 1620 max([len(m.rel(abs)) for abs in items]))
1621 1621 for abs in items:
1622 1622 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1623 1623 ui.write("%s\n" % line.rstrip())
1624 1624
1625 1625 def debugwireargs(ui, repopath, *vals, **opts):
1626 1626 repo = hg.repository(hg.remoteui(ui, opts), repopath)
1627 1627 for opt in remoteopts:
1628 1628 del opts[opt[1]]
1629 1629 args = {}
1630 1630 for k, v in opts.iteritems():
1631 1631 if v:
1632 1632 args[k] = v
1633 1633 # run twice to check that we don't mess up the stream for the next command
1634 1634 res1 = repo.debugwireargs(*vals, **args)
1635 1635 res2 = repo.debugwireargs(*vals, **args)
1636 1636 ui.write("%s\n" % res1)
1637 1637 if res1 != res2:
1638 1638 ui.warn("%s\n" % res2)
1639 1639
1640 1640 def diff(ui, repo, *pats, **opts):
1641 1641 """diff repository (or selected files)
1642 1642
1643 1643 Show differences between revisions for the specified files.
1644 1644
1645 1645 Differences between files are shown using the unified diff format.
1646 1646
1647 1647 .. note::
1648 1648 diff may generate unexpected results for merges, as it will
1649 1649 default to comparing against the working directory's first
1650 1650 parent changeset if no revisions are specified.
1651 1651
1652 1652 When two revision arguments are given, then changes are shown
1653 1653 between those revisions. If only one revision is specified then
1654 1654 that revision is compared to the working directory, and, when no
1655 1655 revisions are specified, the working directory files are compared
1656 1656 to its parent.
1657 1657
1658 1658 Alternatively you can specify -c/--change with a revision to see
1659 1659 the changes in that changeset relative to its first parent.
1660 1660
1661 1661 Without the -a/--text option, diff will avoid generating diffs of
1662 1662 files it detects as binary. With -a, diff will generate a diff
1663 1663 anyway, probably with undesirable results.
1664 1664
1665 1665 Use the -g/--git option to generate diffs in the git extended diff
1666 1666 format. For more information, read :hg:`help diffs`.
1667 1667
1668 1668 Returns 0 on success.
1669 1669 """
1670 1670
1671 1671 revs = opts.get('rev')
1672 1672 change = opts.get('change')
1673 1673 stat = opts.get('stat')
1674 1674 reverse = opts.get('reverse')
1675 1675
1676 1676 if revs and change:
1677 1677 msg = _('cannot specify --rev and --change at the same time')
1678 1678 raise util.Abort(msg)
1679 1679 elif change:
1680 1680 node2 = cmdutil.revsingle(repo, change, None).node()
1681 1681 node1 = repo[node2].p1().node()
1682 1682 else:
1683 1683 node1, node2 = cmdutil.revpair(repo, revs)
1684 1684
1685 1685 if reverse:
1686 1686 node1, node2 = node2, node1
1687 1687
1688 1688 diffopts = patch.diffopts(ui, opts)
1689 1689 m = cmdutil.match(repo, pats, opts)
1690 1690 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1691 1691 listsubrepos=opts.get('subrepos'))
1692 1692
1693 1693 def export(ui, repo, *changesets, **opts):
1694 1694 """dump the header and diffs for one or more changesets
1695 1695
1696 1696 Print the changeset header and diffs for one or more revisions.
1697 1697
1698 1698 The information shown in the changeset header is: author, date,
1699 1699 branch name (if non-default), changeset hash, parent(s) and commit
1700 1700 comment.
1701 1701
1702 1702 .. note::
1703 1703 export may generate unexpected diff output for merge
1704 1704 changesets, as it will compare the merge changeset against its
1705 1705 first parent only.
1706 1706
1707 1707 Output may be to a file, in which case the name of the file is
1708 1708 given using a format string. The formatting rules are as follows:
1709 1709
1710 1710 :``%%``: literal "%" character
1711 1711 :``%H``: changeset hash (40 hexadecimal digits)
1712 1712 :``%N``: number of patches being generated
1713 1713 :``%R``: changeset revision number
1714 1714 :``%b``: basename of the exporting repository
1715 1715 :``%h``: short-form changeset hash (12 hexadecimal digits)
1716 1716 :``%n``: zero-padded sequence number, starting at 1
1717 1717 :``%r``: zero-padded changeset revision number
1718 1718
1719 1719 Without the -a/--text option, export will avoid generating diffs
1720 1720 of files it detects as binary. With -a, export will generate a
1721 1721 diff anyway, probably with undesirable results.
1722 1722
1723 1723 Use the -g/--git option to generate diffs in the git extended diff
1724 1724 format. See :hg:`help diffs` for more information.
1725 1725
1726 1726 With the --switch-parent option, the diff will be against the
1727 1727 second parent. It can be useful to review a merge.
1728 1728
1729 1729 Returns 0 on success.
1730 1730 """
1731 1731 changesets += tuple(opts.get('rev', []))
1732 1732 if not changesets:
1733 1733 raise util.Abort(_("export requires at least one changeset"))
1734 1734 revs = cmdutil.revrange(repo, changesets)
1735 1735 if len(revs) > 1:
1736 1736 ui.note(_('exporting patches:\n'))
1737 1737 else:
1738 1738 ui.note(_('exporting patch:\n'))
1739 1739 cmdutil.export(repo, revs, template=opts.get('output'),
1740 1740 switch_parent=opts.get('switch_parent'),
1741 1741 opts=patch.diffopts(ui, opts))
1742 1742
1743 1743 def forget(ui, repo, *pats, **opts):
1744 1744 """forget the specified files on the next commit
1745 1745
1746 1746 Mark the specified files so they will no longer be tracked
1747 1747 after the next commit.
1748 1748
1749 1749 This only removes files from the current branch, not from the
1750 1750 entire project history, and it does not delete them from the
1751 1751 working directory.
1752 1752
1753 1753 To undo a forget before the next commit, see :hg:`add`.
1754 1754
1755 1755 Returns 0 on success.
1756 1756 """
1757 1757
1758 1758 if not pats:
1759 1759 raise util.Abort(_('no files specified'))
1760 1760
1761 1761 m = cmdutil.match(repo, pats, opts)
1762 1762 s = repo.status(match=m, clean=True)
1763 1763 forget = sorted(s[0] + s[1] + s[3] + s[6])
1764 1764 errs = 0
1765 1765
1766 1766 for f in m.files():
1767 1767 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1768 1768 ui.warn(_('not removing %s: file is already untracked\n')
1769 1769 % m.rel(f))
1770 1770 errs = 1
1771 1771
1772 1772 for f in forget:
1773 1773 if ui.verbose or not m.exact(f):
1774 1774 ui.status(_('removing %s\n') % m.rel(f))
1775 1775
1776 1776 repo[None].remove(forget, unlink=False)
1777 1777 return errs
1778 1778
1779 1779 def grep(ui, repo, pattern, *pats, **opts):
1780 1780 """search for a pattern in specified files and revisions
1781 1781
1782 1782 Search revisions of files for a regular expression.
1783 1783
1784 1784 This command behaves differently than Unix grep. It only accepts
1785 1785 Python/Perl regexps. It searches repository history, not the
1786 1786 working directory. It always prints the revision number in which a
1787 1787 match appears.
1788 1788
1789 1789 By default, grep only prints output for the first revision of a
1790 1790 file in which it finds a match. To get it to print every revision
1791 1791 that contains a change in match status ("-" for a match that
1792 1792 becomes a non-match, or "+" for a non-match that becomes a match),
1793 1793 use the --all flag.
1794 1794
1795 1795 Returns 0 if a match is found, 1 otherwise.
1796 1796 """
1797 1797 reflags = 0
1798 1798 if opts.get('ignore_case'):
1799 1799 reflags |= re.I
1800 1800 try:
1801 1801 regexp = re.compile(pattern, reflags)
1802 1802 except re.error, inst:
1803 1803 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1804 1804 return 1
1805 1805 sep, eol = ':', '\n'
1806 1806 if opts.get('print0'):
1807 1807 sep = eol = '\0'
1808 1808
1809 1809 getfile = util.lrucachefunc(repo.file)
1810 1810
1811 1811 def matchlines(body):
1812 1812 begin = 0
1813 1813 linenum = 0
1814 1814 while True:
1815 1815 match = regexp.search(body, begin)
1816 1816 if not match:
1817 1817 break
1818 1818 mstart, mend = match.span()
1819 1819 linenum += body.count('\n', begin, mstart) + 1
1820 1820 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1821 1821 begin = body.find('\n', mend) + 1 or len(body)
1822 1822 lend = begin - 1
1823 1823 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1824 1824
1825 1825 class linestate(object):
1826 1826 def __init__(self, line, linenum, colstart, colend):
1827 1827 self.line = line
1828 1828 self.linenum = linenum
1829 1829 self.colstart = colstart
1830 1830 self.colend = colend
1831 1831
1832 1832 def __hash__(self):
1833 1833 return hash((self.linenum, self.line))
1834 1834
1835 1835 def __eq__(self, other):
1836 1836 return self.line == other.line
1837 1837
1838 1838 matches = {}
1839 1839 copies = {}
1840 1840 def grepbody(fn, rev, body):
1841 1841 matches[rev].setdefault(fn, [])
1842 1842 m = matches[rev][fn]
1843 1843 for lnum, cstart, cend, line in matchlines(body):
1844 1844 s = linestate(line, lnum, cstart, cend)
1845 1845 m.append(s)
1846 1846
1847 1847 def difflinestates(a, b):
1848 1848 sm = difflib.SequenceMatcher(None, a, b)
1849 1849 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1850 1850 if tag == 'insert':
1851 1851 for i in xrange(blo, bhi):
1852 1852 yield ('+', b[i])
1853 1853 elif tag == 'delete':
1854 1854 for i in xrange(alo, ahi):
1855 1855 yield ('-', a[i])
1856 1856 elif tag == 'replace':
1857 1857 for i in xrange(alo, ahi):
1858 1858 yield ('-', a[i])
1859 1859 for i in xrange(blo, bhi):
1860 1860 yield ('+', b[i])
1861 1861
1862 1862 def display(fn, ctx, pstates, states):
1863 1863 rev = ctx.rev()
1864 1864 datefunc = ui.quiet and util.shortdate or util.datestr
1865 1865 found = False
1866 1866 filerevmatches = {}
1867 1867 if opts.get('all'):
1868 1868 iter = difflinestates(pstates, states)
1869 1869 else:
1870 1870 iter = [('', l) for l in states]
1871 1871 for change, l in iter:
1872 1872 cols = [fn, str(rev)]
1873 1873 before, match, after = None, None, None
1874 1874 if opts.get('line_number'):
1875 1875 cols.append(str(l.linenum))
1876 1876 if opts.get('all'):
1877 1877 cols.append(change)
1878 1878 if opts.get('user'):
1879 1879 cols.append(ui.shortuser(ctx.user()))
1880 1880 if opts.get('date'):
1881 1881 cols.append(datefunc(ctx.date()))
1882 1882 if opts.get('files_with_matches'):
1883 1883 c = (fn, rev)
1884 1884 if c in filerevmatches:
1885 1885 continue
1886 1886 filerevmatches[c] = 1
1887 1887 else:
1888 1888 before = l.line[:l.colstart]
1889 1889 match = l.line[l.colstart:l.colend]
1890 1890 after = l.line[l.colend:]
1891 1891 ui.write(sep.join(cols))
1892 1892 if before is not None:
1893 1893 ui.write(sep + before)
1894 1894 ui.write(match, label='grep.match')
1895 1895 ui.write(after)
1896 1896 ui.write(eol)
1897 1897 found = True
1898 1898 return found
1899 1899
1900 1900 skip = {}
1901 1901 revfiles = {}
1902 1902 matchfn = cmdutil.match(repo, pats, opts)
1903 1903 found = False
1904 1904 follow = opts.get('follow')
1905 1905
1906 1906 def prep(ctx, fns):
1907 1907 rev = ctx.rev()
1908 1908 pctx = ctx.p1()
1909 1909 parent = pctx.rev()
1910 1910 matches.setdefault(rev, {})
1911 1911 matches.setdefault(parent, {})
1912 1912 files = revfiles.setdefault(rev, [])
1913 1913 for fn in fns:
1914 1914 flog = getfile(fn)
1915 1915 try:
1916 1916 fnode = ctx.filenode(fn)
1917 1917 except error.LookupError:
1918 1918 continue
1919 1919
1920 1920 copied = flog.renamed(fnode)
1921 1921 copy = follow and copied and copied[0]
1922 1922 if copy:
1923 1923 copies.setdefault(rev, {})[fn] = copy
1924 1924 if fn in skip:
1925 1925 if copy:
1926 1926 skip[copy] = True
1927 1927 continue
1928 1928 files.append(fn)
1929 1929
1930 1930 if fn not in matches[rev]:
1931 1931 grepbody(fn, rev, flog.read(fnode))
1932 1932
1933 1933 pfn = copy or fn
1934 1934 if pfn not in matches[parent]:
1935 1935 try:
1936 1936 fnode = pctx.filenode(pfn)
1937 1937 grepbody(pfn, parent, flog.read(fnode))
1938 1938 except error.LookupError:
1939 1939 pass
1940 1940
1941 1941 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
1942 1942 rev = ctx.rev()
1943 1943 parent = ctx.p1().rev()
1944 1944 for fn in sorted(revfiles.get(rev, [])):
1945 1945 states = matches[rev][fn]
1946 1946 copy = copies.get(rev, {}).get(fn)
1947 1947 if fn in skip:
1948 1948 if copy:
1949 1949 skip[copy] = True
1950 1950 continue
1951 1951 pstates = matches.get(parent, {}).get(copy or fn, [])
1952 1952 if pstates or states:
1953 1953 r = display(fn, ctx, pstates, states)
1954 1954 found = found or r
1955 1955 if r and not opts.get('all'):
1956 1956 skip[fn] = True
1957 1957 if copy:
1958 1958 skip[copy] = True
1959 1959 del matches[rev]
1960 1960 del revfiles[rev]
1961 1961
1962 1962 return not found
1963 1963
1964 1964 def heads(ui, repo, *branchrevs, **opts):
1965 1965 """show current repository heads or show branch heads
1966 1966
1967 1967 With no arguments, show all repository branch heads.
1968 1968
1969 1969 Repository "heads" are changesets with no child changesets. They are
1970 1970 where development generally takes place and are the usual targets
1971 1971 for update and merge operations. Branch heads are changesets that have
1972 1972 no child changeset on the same branch.
1973 1973
1974 1974 If one or more REVs are given, only branch heads on the branches
1975 1975 associated with the specified changesets are shown.
1976 1976
1977 1977 If -c/--closed is specified, also show branch heads marked closed
1978 1978 (see :hg:`commit --close-branch`).
1979 1979
1980 1980 If STARTREV is specified, only those heads that are descendants of
1981 1981 STARTREV will be displayed.
1982 1982
1983 1983 If -t/--topo is specified, named branch mechanics will be ignored and only
1984 1984 changesets without children will be shown.
1985 1985
1986 1986 Returns 0 if matching heads are found, 1 if not.
1987 1987 """
1988 1988
1989 1989 start = None
1990 1990 if 'rev' in opts:
1991 1991 start = cmdutil.revsingle(repo, opts['rev'], None).node()
1992 1992
1993 1993 if opts.get('topo'):
1994 1994 heads = [repo[h] for h in repo.heads(start)]
1995 1995 else:
1996 1996 heads = []
1997 1997 for b, ls in repo.branchmap().iteritems():
1998 1998 if start is None:
1999 1999 heads += [repo[h] for h in ls]
2000 2000 continue
2001 2001 startrev = repo.changelog.rev(start)
2002 2002 descendants = set(repo.changelog.descendants(startrev))
2003 2003 descendants.add(startrev)
2004 2004 rev = repo.changelog.rev
2005 2005 heads += [repo[h] for h in ls if rev(h) in descendants]
2006 2006
2007 2007 if branchrevs:
2008 2008 branches = set(repo[br].branch() for br in branchrevs)
2009 2009 heads = [h for h in heads if h.branch() in branches]
2010 2010
2011 2011 if not opts.get('closed'):
2012 2012 heads = [h for h in heads if not h.extra().get('close')]
2013 2013
2014 2014 if opts.get('active') and branchrevs:
2015 2015 dagheads = repo.heads(start)
2016 2016 heads = [h for h in heads if h.node() in dagheads]
2017 2017
2018 2018 if branchrevs:
2019 2019 haveheads = set(h.branch() for h in heads)
2020 2020 if branches - haveheads:
2021 2021 headless = ', '.join(b for b in branches - haveheads)
2022 2022 msg = _('no open branch heads found on branches %s')
2023 2023 if opts.get('rev'):
2024 2024 msg += _(' (started at %s)' % opts['rev'])
2025 2025 ui.warn((msg + '\n') % headless)
2026 2026
2027 2027 if not heads:
2028 2028 return 1
2029 2029
2030 2030 heads = sorted(heads, key=lambda x: -x.rev())
2031 2031 displayer = cmdutil.show_changeset(ui, repo, opts)
2032 2032 for ctx in heads:
2033 2033 displayer.show(ctx)
2034 2034 displayer.close()
2035 2035
2036 2036 def help_(ui, name=None, with_version=False, unknowncmd=False):
2037 2037 """show help for a given topic or a help overview
2038 2038
2039 2039 With no arguments, print a list of commands with short help messages.
2040 2040
2041 2041 Given a topic, extension, or command name, print help for that
2042 2042 topic.
2043 2043
2044 2044 Returns 0 if successful.
2045 2045 """
2046 2046 option_lists = []
2047 2047 textwidth = min(ui.termwidth(), 80) - 2
2048 2048
2049 2049 def addglobalopts(aliases):
2050 2050 if ui.verbose:
2051 2051 option_lists.append((_("global options:"), globalopts))
2052 2052 if name == 'shortlist':
2053 2053 option_lists.append((_('use "hg help" for the full list '
2054 2054 'of commands'), ()))
2055 2055 else:
2056 2056 if name == 'shortlist':
2057 2057 msg = _('use "hg help" for the full list of commands '
2058 2058 'or "hg -v" for details')
2059 2059 elif aliases:
2060 2060 msg = _('use "hg -v help%s" to show builtin aliases and '
2061 2061 'global options') % (name and " " + name or "")
2062 2062 else:
2063 2063 msg = _('use "hg -v help %s" to show global options') % name
2064 2064 option_lists.append((msg, ()))
2065 2065
2066 2066 def helpcmd(name):
2067 2067 if with_version:
2068 2068 version_(ui)
2069 2069 ui.write('\n')
2070 2070
2071 2071 try:
2072 2072 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2073 2073 except error.AmbiguousCommand, inst:
2074 2074 # py3k fix: except vars can't be used outside the scope of the
2075 2075 # except block, nor can be used inside a lambda. python issue4617
2076 2076 prefix = inst.args[0]
2077 2077 select = lambda c: c.lstrip('^').startswith(prefix)
2078 2078 helplist(_('list of commands:\n\n'), select)
2079 2079 return
2080 2080
2081 2081 # check if it's an invalid alias and display its error if it is
2082 2082 if getattr(entry[0], 'badalias', False):
2083 2083 if not unknowncmd:
2084 2084 entry[0](ui)
2085 2085 return
2086 2086
2087 2087 # synopsis
2088 2088 if len(entry) > 2:
2089 2089 if entry[2].startswith('hg'):
2090 2090 ui.write("%s\n" % entry[2])
2091 2091 else:
2092 2092 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2093 2093 else:
2094 2094 ui.write('hg %s\n' % aliases[0])
2095 2095
2096 2096 # aliases
2097 2097 if not ui.quiet and len(aliases) > 1:
2098 2098 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2099 2099
2100 2100 # description
2101 2101 doc = gettext(entry[0].__doc__)
2102 2102 if not doc:
2103 2103 doc = _("(no help text available)")
2104 2104 if hasattr(entry[0], 'definition'): # aliased command
2105 2105 if entry[0].definition.startswith('!'): # shell alias
2106 2106 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2107 2107 else:
2108 2108 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2109 2109 if ui.quiet:
2110 2110 doc = doc.splitlines()[0]
2111 2111 keep = ui.verbose and ['verbose'] or []
2112 2112 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2113 2113 ui.write("\n%s\n" % formatted)
2114 2114 if pruned:
2115 2115 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2116 2116
2117 2117 if not ui.quiet:
2118 2118 # options
2119 2119 if entry[1]:
2120 2120 option_lists.append((_("options:\n"), entry[1]))
2121 2121
2122 2122 addglobalopts(False)
2123 2123
2124 2124 def helplist(header, select=None):
2125 2125 h = {}
2126 2126 cmds = {}
2127 2127 for c, e in table.iteritems():
2128 2128 f = c.split("|", 1)[0]
2129 2129 if select and not select(f):
2130 2130 continue
2131 2131 if (not select and name != 'shortlist' and
2132 2132 e[0].__module__ != __name__):
2133 2133 continue
2134 2134 if name == "shortlist" and not f.startswith("^"):
2135 2135 continue
2136 2136 f = f.lstrip("^")
2137 2137 if not ui.debugflag and f.startswith("debug"):
2138 2138 continue
2139 2139 doc = e[0].__doc__
2140 2140 if doc and 'DEPRECATED' in doc and not ui.verbose:
2141 2141 continue
2142 2142 doc = gettext(doc)
2143 2143 if not doc:
2144 2144 doc = _("(no help text available)")
2145 2145 h[f] = doc.splitlines()[0].rstrip()
2146 2146 cmds[f] = c.lstrip("^")
2147 2147
2148 2148 if not h:
2149 2149 ui.status(_('no commands defined\n'))
2150 2150 return
2151 2151
2152 2152 ui.status(header)
2153 2153 fns = sorted(h)
2154 2154 m = max(map(len, fns))
2155 2155 for f in fns:
2156 2156 if ui.verbose:
2157 2157 commands = cmds[f].replace("|",", ")
2158 2158 ui.write(" %s:\n %s\n"%(commands, h[f]))
2159 2159 else:
2160 2160 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2161 2161 initindent=' %-*s ' % (m, f),
2162 2162 hangindent=' ' * (m + 4))))
2163 2163
2164 2164 if not ui.quiet:
2165 2165 addglobalopts(True)
2166 2166
2167 2167 def helptopic(name):
2168 2168 for names, header, doc in help.helptable:
2169 2169 if name in names:
2170 2170 break
2171 2171 else:
2172 2172 raise error.UnknownCommand(name)
2173 2173
2174 2174 # description
2175 2175 if not doc:
2176 2176 doc = _("(no help text available)")
2177 2177 if hasattr(doc, '__call__'):
2178 2178 doc = doc()
2179 2179
2180 2180 ui.write("%s\n\n" % header)
2181 2181 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2182 2182
2183 2183 def helpext(name):
2184 2184 try:
2185 2185 mod = extensions.find(name)
2186 2186 doc = gettext(mod.__doc__) or _('no help text available')
2187 2187 except KeyError:
2188 2188 mod = None
2189 2189 doc = extensions.disabledext(name)
2190 2190 if not doc:
2191 2191 raise error.UnknownCommand(name)
2192 2192
2193 2193 if '\n' not in doc:
2194 2194 head, tail = doc, ""
2195 2195 else:
2196 2196 head, tail = doc.split('\n', 1)
2197 2197 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2198 2198 if tail:
2199 2199 ui.write(minirst.format(tail, textwidth))
2200 2200 ui.status('\n\n')
2201 2201
2202 2202 if mod:
2203 2203 try:
2204 2204 ct = mod.cmdtable
2205 2205 except AttributeError:
2206 2206 ct = {}
2207 2207 modcmds = set([c.split('|', 1)[0] for c in ct])
2208 2208 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2209 2209 else:
2210 2210 ui.write(_('use "hg help extensions" for information on enabling '
2211 2211 'extensions\n'))
2212 2212
2213 2213 def helpextcmd(name):
2214 2214 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2215 2215 doc = gettext(mod.__doc__).splitlines()[0]
2216 2216
2217 2217 msg = help.listexts(_("'%s' is provided by the following "
2218 2218 "extension:") % cmd, {ext: doc}, len(ext),
2219 2219 indent=4)
2220 2220 ui.write(minirst.format(msg, textwidth))
2221 2221 ui.write('\n\n')
2222 2222 ui.write(_('use "hg help extensions" for information on enabling '
2223 2223 'extensions\n'))
2224 2224
2225 2225 help.addtopichook('revsets', revset.makedoc)
2226 2226 help.addtopichook('templates', templatekw.makedoc)
2227 2227 help.addtopichook('templates', templatefilters.makedoc)
2228 2228
2229 2229 if name and name != 'shortlist':
2230 2230 i = None
2231 2231 if unknowncmd:
2232 2232 queries = (helpextcmd,)
2233 2233 else:
2234 2234 queries = (helptopic, helpcmd, helpext, helpextcmd)
2235 2235 for f in queries:
2236 2236 try:
2237 2237 f(name)
2238 2238 i = None
2239 2239 break
2240 2240 except error.UnknownCommand, inst:
2241 2241 i = inst
2242 2242 if i:
2243 2243 raise i
2244 2244
2245 2245 else:
2246 2246 # program name
2247 2247 if ui.verbose or with_version:
2248 2248 version_(ui)
2249 2249 else:
2250 2250 ui.status(_("Mercurial Distributed SCM\n"))
2251 2251 ui.status('\n')
2252 2252
2253 2253 # list of commands
2254 2254 if name == "shortlist":
2255 2255 header = _('basic commands:\n\n')
2256 2256 else:
2257 2257 header = _('list of commands:\n\n')
2258 2258
2259 2259 helplist(header)
2260 2260 if name != 'shortlist':
2261 2261 exts, maxlength = extensions.enabled()
2262 2262 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2263 2263 if text:
2264 2264 ui.write("\n%s\n" % minirst.format(text, textwidth))
2265 2265
2266 2266 # list all option lists
2267 2267 opt_output = []
2268 2268 multioccur = False
2269 2269 for title, options in option_lists:
2270 2270 opt_output.append(("\n%s" % title, None))
2271 2271 for option in options:
2272 2272 if len(option) == 5:
2273 2273 shortopt, longopt, default, desc, optlabel = option
2274 2274 else:
2275 2275 shortopt, longopt, default, desc = option
2276 2276 optlabel = _("VALUE") # default label
2277 2277
2278 2278 if _("DEPRECATED") in desc and not ui.verbose:
2279 2279 continue
2280 2280 if isinstance(default, list):
2281 2281 numqualifier = " %s [+]" % optlabel
2282 2282 multioccur = True
2283 2283 elif (default is not None) and not isinstance(default, bool):
2284 2284 numqualifier = " %s" % optlabel
2285 2285 else:
2286 2286 numqualifier = ""
2287 2287 opt_output.append(("%2s%s" %
2288 2288 (shortopt and "-%s" % shortopt,
2289 2289 longopt and " --%s%s" %
2290 2290 (longopt, numqualifier)),
2291 2291 "%s%s" % (desc,
2292 2292 default
2293 2293 and _(" (default: %s)") % default
2294 2294 or "")))
2295 2295 if multioccur:
2296 2296 msg = _("\n[+] marked option can be specified multiple times")
2297 2297 if ui.verbose and name != 'shortlist':
2298 2298 opt_output.append((msg, None))
2299 2299 else:
2300 2300 opt_output.insert(-1, (msg, None))
2301 2301
2302 2302 if not name:
2303 2303 ui.write(_("\nadditional help topics:\n\n"))
2304 2304 topics = []
2305 2305 for names, header, doc in help.helptable:
2306 2306 topics.append((sorted(names, key=len, reverse=True)[0], header))
2307 2307 topics_len = max([len(s[0]) for s in topics])
2308 2308 for t, desc in topics:
2309 2309 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2310 2310
2311 2311 if opt_output:
2312 2312 colwidth = encoding.colwidth
2313 2313 # normalize: (opt or message, desc or None, width of opt)
2314 2314 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2315 2315 for opt, desc in opt_output]
2316 2316 hanging = max([e[2] for e in entries])
2317 2317 for opt, desc, width in entries:
2318 2318 if desc:
2319 2319 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2320 2320 hangindent = ' ' * (hanging + 3)
2321 2321 ui.write('%s\n' % (util.wrap(desc, textwidth,
2322 2322 initindent=initindent,
2323 2323 hangindent=hangindent)))
2324 2324 else:
2325 2325 ui.write("%s\n" % opt)
2326 2326
2327 2327 def identify(ui, repo, source=None, rev=None,
2328 2328 num=None, id=None, branch=None, tags=None, bookmarks=None):
2329 2329 """identify the working copy or specified revision
2330 2330
2331 2331 With no revision, print a summary of the current state of the
2332 2332 repository.
2333 2333
2334 2334 Specifying a path to a repository root or Mercurial bundle will
2335 2335 cause lookup to operate on that repository/bundle.
2336 2336
2337 2337 This summary identifies the repository state using one or two
2338 2338 parent hash identifiers, followed by a "+" if there are
2339 2339 uncommitted changes in the working directory, a list of tags for
2340 2340 this revision and a branch name for non-default branches.
2341 2341
2342 2342 Returns 0 if successful.
2343 2343 """
2344 2344
2345 2345 if not repo and not source:
2346 2346 raise util.Abort(_("there is no Mercurial repository here "
2347 2347 "(.hg not found)"))
2348 2348
2349 2349 hexfunc = ui.debugflag and hex or short
2350 2350 default = not (num or id or branch or tags or bookmarks)
2351 2351 output = []
2352 2352
2353 2353 revs = []
2354 2354 bms = []
2355 2355 if source:
2356 2356 source, branches = hg.parseurl(ui.expandpath(source))
2357 2357 repo = hg.repository(ui, source)
2358 2358 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2359 2359
2360 2360 if not repo.local():
2361 2361 if not rev and revs:
2362 2362 rev = revs[0]
2363 2363 if not rev:
2364 2364 rev = "tip"
2365 2365 if num or branch or tags:
2366 2366 raise util.Abort(
2367 2367 _("can't query remote revision number, branch, or tags"))
2368 2368
2369 2369 remoterev = repo.lookup(rev)
2370 2370 if default or id:
2371 2371 output = [hexfunc(remoterev)]
2372 2372
2373 2373 if 'bookmarks' in repo.listkeys('namespaces'):
2374 2374 hexremoterev = hex(remoterev)
2375 2375 bms = [bm for bm, bmrev in repo.listkeys('bookmarks').iteritems()
2376 2376 if bmrev == hexremoterev]
2377 2377
2378 2378 elif not rev:
2379 2379 ctx = repo[None]
2380 2380 parents = ctx.parents()
2381 2381 changed = False
2382 2382 if default or id or num:
2383 2383 changed = util.any(repo.status())
2384 2384 if default or id:
2385 2385 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
2386 2386 (changed) and "+" or "")]
2387 2387 if num:
2388 2388 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
2389 2389 (changed) and "+" or ""))
2390 2390 else:
2391 2391 ctx = cmdutil.revsingle(repo, rev)
2392 2392 if default or id:
2393 2393 output = [hexfunc(ctx.node())]
2394 2394 if num:
2395 2395 output.append(str(ctx.rev()))
2396 2396
2397 2397 if repo.local():
2398 2398 bms = ctx.bookmarks()
2399 2399
2400 2400 if repo.local() and default and not ui.quiet:
2401 2401 b = ctx.branch()
2402 2402 if b != 'default':
2403 2403 output.append("(%s)" % b)
2404 2404
2405 2405 # multiple tags for a single parent separated by '/'
2406 2406 t = "/".join(ctx.tags())
2407 2407 if t:
2408 2408 output.append(t)
2409 2409
2410 2410 if default and not ui.quiet:
2411 2411 # multiple bookmarks for a single parent separated by '/'
2412 2412 bm = '/'.join(bms)
2413 2413 if bm:
2414 2414 output.append(bm)
2415 2415
2416 2416 if branch:
2417 2417 output.append(ctx.branch())
2418 2418
2419 2419 if tags:
2420 2420 output.extend(ctx.tags())
2421 2421
2422 2422 if bookmarks:
2423 2423 output.extend(bms)
2424 2424
2425 2425 ui.write("%s\n" % ' '.join(output))
2426 2426
2427 2427 def import_(ui, repo, patch1, *patches, **opts):
2428 2428 """import an ordered set of patches
2429 2429
2430 2430 Import a list of patches and commit them individually (unless
2431 2431 --no-commit is specified).
2432 2432
2433 2433 If there are outstanding changes in the working directory, import
2434 2434 will abort unless given the -f/--force flag.
2435 2435
2436 2436 You can import a patch straight from a mail message. Even patches
2437 2437 as attachments work (to use the body part, it must have type
2438 2438 text/plain or text/x-patch). From and Subject headers of email
2439 2439 message are used as default committer and commit message. All
2440 2440 text/plain body parts before first diff are added to commit
2441 2441 message.
2442 2442
2443 2443 If the imported patch was generated by :hg:`export`, user and
2444 2444 description from patch override values from message headers and
2445 2445 body. Values given on command line with -m/--message and -u/--user
2446 2446 override these.
2447 2447
2448 2448 If --exact is specified, import will set the working directory to
2449 2449 the parent of each patch before applying it, and will abort if the
2450 2450 resulting changeset has a different ID than the one recorded in
2451 2451 the patch. This may happen due to character set problems or other
2452 2452 deficiencies in the text patch format.
2453 2453
2454 2454 With -s/--similarity, hg will attempt to discover renames and
2455 2455 copies in the patch in the same way as 'addremove'.
2456 2456
2457 2457 To read a patch from standard input, use "-" as the patch name. If
2458 2458 a URL is specified, the patch will be downloaded from it.
2459 2459 See :hg:`help dates` for a list of formats valid for -d/--date.
2460 2460
2461 2461 Returns 0 on success.
2462 2462 """
2463 2463 patches = (patch1,) + patches
2464 2464
2465 2465 date = opts.get('date')
2466 2466 if date:
2467 2467 opts['date'] = util.parsedate(date)
2468 2468
2469 2469 try:
2470 2470 sim = float(opts.get('similarity') or 0)
2471 2471 except ValueError:
2472 2472 raise util.Abort(_('similarity must be a number'))
2473 2473 if sim < 0 or sim > 100:
2474 2474 raise util.Abort(_('similarity must be between 0 and 100'))
2475 2475
2476 2476 if opts.get('exact') or not opts.get('force'):
2477 2477 cmdutil.bail_if_changed(repo)
2478 2478
2479 2479 d = opts["base"]
2480 2480 strip = opts["strip"]
2481 2481 wlock = lock = None
2482 2482 msgs = []
2483 2483
2484 2484 def tryone(ui, hunk):
2485 2485 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2486 2486 patch.extract(ui, hunk)
2487 2487
2488 2488 if not tmpname:
2489 2489 return None
2490 2490 commitid = _('to working directory')
2491 2491
2492 2492 try:
2493 2493 cmdline_message = cmdutil.logmessage(opts)
2494 2494 if cmdline_message:
2495 2495 # pickup the cmdline msg
2496 2496 message = cmdline_message
2497 2497 elif message:
2498 2498 # pickup the patch msg
2499 2499 message = message.strip()
2500 2500 else:
2501 2501 # launch the editor
2502 2502 message = None
2503 2503 ui.debug('message:\n%s\n' % message)
2504 2504
2505 2505 wp = repo.parents()
2506 2506 if opts.get('exact'):
2507 2507 if not nodeid or not p1:
2508 2508 raise util.Abort(_('not a Mercurial patch'))
2509 2509 p1 = repo.lookup(p1)
2510 2510 p2 = repo.lookup(p2 or hex(nullid))
2511 2511
2512 2512 if p1 != wp[0].node():
2513 2513 hg.clean(repo, p1)
2514 2514 repo.dirstate.setparents(p1, p2)
2515 2515 elif p2:
2516 2516 try:
2517 2517 p1 = repo.lookup(p1)
2518 2518 p2 = repo.lookup(p2)
2519 2519 if p1 == wp[0].node():
2520 2520 repo.dirstate.setparents(p1, p2)
2521 2521 except error.RepoError:
2522 2522 pass
2523 2523 if opts.get('exact') or opts.get('import_branch'):
2524 2524 repo.dirstate.setbranch(branch or 'default')
2525 2525
2526 2526 files = {}
2527 2527 try:
2528 2528 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2529 2529 files=files, eolmode=None)
2530 2530 finally:
2531 2531 files = cmdutil.updatedir(ui, repo, files,
2532 2532 similarity=sim / 100.0)
2533 2533 if opts.get('no_commit'):
2534 2534 if message:
2535 2535 msgs.append(message)
2536 2536 else:
2537 2537 if opts.get('exact'):
2538 2538 m = None
2539 2539 else:
2540 2540 m = cmdutil.matchfiles(repo, files or [])
2541 2541 n = repo.commit(message, opts.get('user') or user,
2542 2542 opts.get('date') or date, match=m,
2543 2543 editor=cmdutil.commiteditor)
2544 2544 if opts.get('exact'):
2545 2545 if hex(n) != nodeid:
2546 2546 repo.rollback()
2547 2547 raise util.Abort(_('patch is damaged'
2548 2548 ' or loses information'))
2549 2549 # Force a dirstate write so that the next transaction
2550 2550 # backups an up-do-date file.
2551 2551 repo.dirstate.write()
2552 2552 if n:
2553 2553 commitid = short(n)
2554 2554
2555 2555 return commitid
2556 2556 finally:
2557 2557 os.unlink(tmpname)
2558 2558
2559 2559 try:
2560 2560 wlock = repo.wlock()
2561 2561 lock = repo.lock()
2562 2562 lastcommit = None
2563 2563 for p in patches:
2564 2564 pf = os.path.join(d, p)
2565 2565
2566 2566 if pf == '-':
2567 2567 ui.status(_("applying patch from stdin\n"))
2568 2568 pf = sys.stdin
2569 2569 else:
2570 2570 ui.status(_("applying %s\n") % p)
2571 2571 pf = url.open(ui, pf)
2572 2572
2573 2573 haspatch = False
2574 2574 for hunk in patch.split(pf):
2575 2575 commitid = tryone(ui, hunk)
2576 2576 if commitid:
2577 2577 haspatch = True
2578 2578 if lastcommit:
2579 2579 ui.status(_('applied %s\n') % lastcommit)
2580 2580 lastcommit = commitid
2581 2581
2582 2582 if not haspatch:
2583 2583 raise util.Abort(_('no diffs found'))
2584 2584
2585 2585 if msgs:
2586 2586 repo.opener('last-message.txt', 'wb').write('\n* * *\n'.join(msgs))
2587 2587 finally:
2588 2588 release(lock, wlock)
2589 2589
2590 2590 def incoming(ui, repo, source="default", **opts):
2591 2591 """show new changesets found in source
2592 2592
2593 2593 Show new changesets found in the specified path/URL or the default
2594 2594 pull location. These are the changesets that would have been pulled
2595 2595 if a pull at the time you issued this command.
2596 2596
2597 2597 For remote repository, using --bundle avoids downloading the
2598 2598 changesets twice if the incoming is followed by a pull.
2599 2599
2600 2600 See pull for valid source format details.
2601 2601
2602 2602 Returns 0 if there are incoming changes, 1 otherwise.
2603 2603 """
2604 2604 if opts.get('bundle') and opts.get('subrepos'):
2605 2605 raise util.Abort(_('cannot combine --bundle and --subrepos'))
2606 2606
2607 2607 if opts.get('bookmarks'):
2608 2608 source, branches = hg.parseurl(ui.expandpath(source),
2609 2609 opts.get('branch'))
2610 2610 other = hg.repository(hg.remoteui(repo, opts), source)
2611 2611 if 'bookmarks' not in other.listkeys('namespaces'):
2612 2612 ui.warn(_("remote doesn't support bookmarks\n"))
2613 2613 return 0
2614 2614 ui.status(_('comparing with %s\n') % url.hidepassword(source))
2615 2615 return bookmarks.diff(ui, repo, other)
2616 2616
2617 2617 ret = hg.incoming(ui, repo, source, opts)
2618 2618 return ret
2619 2619
2620 2620 def init(ui, dest=".", **opts):
2621 2621 """create a new repository in the given directory
2622 2622
2623 2623 Initialize a new repository in the given directory. If the given
2624 2624 directory does not exist, it will be created.
2625 2625
2626 2626 If no directory is given, the current directory is used.
2627 2627
2628 2628 It is possible to specify an ``ssh://`` URL as the destination.
2629 2629 See :hg:`help urls` for more information.
2630 2630
2631 2631 Returns 0 on success.
2632 2632 """
2633 2633 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
2634 2634
2635 2635 def locate(ui, repo, *pats, **opts):
2636 2636 """locate files matching specific patterns
2637 2637
2638 2638 Print files under Mercurial control in the working directory whose
2639 2639 names match the given patterns.
2640 2640
2641 2641 By default, this command searches all directories in the working
2642 2642 directory. To search just the current directory and its
2643 2643 subdirectories, use "--include .".
2644 2644
2645 2645 If no patterns are given to match, this command prints the names
2646 2646 of all files under Mercurial control in the working directory.
2647 2647
2648 2648 If you want to feed the output of this command into the "xargs"
2649 2649 command, use the -0 option to both this command and "xargs". This
2650 2650 will avoid the problem of "xargs" treating single filenames that
2651 2651 contain whitespace as multiple filenames.
2652 2652
2653 2653 Returns 0 if a match is found, 1 otherwise.
2654 2654 """
2655 2655 end = opts.get('print0') and '\0' or '\n'
2656 2656 rev = cmdutil.revsingle(repo, opts.get('rev'), None).node()
2657 2657
2658 2658 ret = 1
2659 2659 m = cmdutil.match(repo, pats, opts, default='relglob')
2660 2660 m.bad = lambda x, y: False
2661 2661 for abs in repo[rev].walk(m):
2662 2662 if not rev and abs not in repo.dirstate:
2663 2663 continue
2664 2664 if opts.get('fullpath'):
2665 2665 ui.write(repo.wjoin(abs), end)
2666 2666 else:
2667 2667 ui.write(((pats and m.rel(abs)) or abs), end)
2668 2668 ret = 0
2669 2669
2670 2670 return ret
2671 2671
2672 2672 def log(ui, repo, *pats, **opts):
2673 2673 """show revision history of entire repository or files
2674 2674
2675 2675 Print the revision history of the specified files or the entire
2676 2676 project.
2677 2677
2678 2678 File history is shown without following rename or copy history of
2679 2679 files. Use -f/--follow with a filename to follow history across
2680 2680 renames and copies. --follow without a filename will only show
2681 2681 ancestors or descendants of the starting revision. --follow-first
2682 2682 only follows the first parent of merge revisions.
2683 2683
2684 2684 If no revision range is specified, the default is ``tip:0`` unless
2685 2685 --follow is set, in which case the working directory parent is
2686 2686 used as the starting revision. You can specify a revision set for
2687 2687 log, see :hg:`help revsets` for more information.
2688 2688
2689 2689 See :hg:`help dates` for a list of formats valid for -d/--date.
2690 2690
2691 2691 By default this command prints revision number and changeset id,
2692 2692 tags, non-trivial parents, user, date and time, and a summary for
2693 2693 each commit. When the -v/--verbose switch is used, the list of
2694 2694 changed files and full commit message are shown.
2695 2695
2696 2696 .. note::
2697 2697 log -p/--patch may generate unexpected diff output for merge
2698 2698 changesets, as it will only compare the merge changeset against
2699 2699 its first parent. Also, only files different from BOTH parents
2700 2700 will appear in files:.
2701 2701
2702 2702 Returns 0 on success.
2703 2703 """
2704 2704
2705 2705 matchfn = cmdutil.match(repo, pats, opts)
2706 2706 limit = cmdutil.loglimit(opts)
2707 2707 count = 0
2708 2708
2709 2709 endrev = None
2710 2710 if opts.get('copies') and opts.get('rev'):
2711 2711 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2712 2712
2713 2713 df = False
2714 2714 if opts["date"]:
2715 2715 df = util.matchdate(opts["date"])
2716 2716
2717 2717 branches = opts.get('branch', []) + opts.get('only_branch', [])
2718 2718 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2719 2719
2720 2720 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2721 2721 def prep(ctx, fns):
2722 2722 rev = ctx.rev()
2723 2723 parents = [p for p in repo.changelog.parentrevs(rev)
2724 2724 if p != nullrev]
2725 2725 if opts.get('no_merges') and len(parents) == 2:
2726 2726 return
2727 2727 if opts.get('only_merges') and len(parents) != 2:
2728 2728 return
2729 2729 if opts.get('branch') and ctx.branch() not in opts['branch']:
2730 2730 return
2731 2731 if df and not df(ctx.date()[0]):
2732 2732 return
2733 2733 if opts['user'] and not [k for k in opts['user']
2734 2734 if k.lower() in ctx.user().lower()]:
2735 2735 return
2736 2736 if opts.get('keyword'):
2737 2737 for k in [kw.lower() for kw in opts['keyword']]:
2738 2738 if (k in ctx.user().lower() or
2739 2739 k in ctx.description().lower() or
2740 2740 k in " ".join(ctx.files()).lower()):
2741 2741 break
2742 2742 else:
2743 2743 return
2744 2744
2745 2745 copies = None
2746 2746 if opts.get('copies') and rev:
2747 2747 copies = []
2748 2748 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2749 2749 for fn in ctx.files():
2750 2750 rename = getrenamed(fn, rev)
2751 2751 if rename:
2752 2752 copies.append((fn, rename[0]))
2753 2753
2754 2754 revmatchfn = None
2755 2755 if opts.get('patch') or opts.get('stat'):
2756 2756 if opts.get('follow') or opts.get('follow_first'):
2757 2757 # note: this might be wrong when following through merges
2758 2758 revmatchfn = cmdutil.match(repo, fns, default='path')
2759 2759 else:
2760 2760 revmatchfn = matchfn
2761 2761
2762 2762 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2763 2763
2764 2764 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2765 2765 if count == limit:
2766 2766 break
2767 2767 if displayer.flush(ctx.rev()):
2768 2768 count += 1
2769 2769 displayer.close()
2770 2770
2771 2771 def manifest(ui, repo, node=None, rev=None):
2772 2772 """output the current or given revision of the project manifest
2773 2773
2774 2774 Print a list of version controlled files for the given revision.
2775 2775 If no revision is given, the first parent of the working directory
2776 2776 is used, or the null revision if no revision is checked out.
2777 2777
2778 2778 With -v, print file permissions, symlink and executable bits.
2779 2779 With --debug, print file revision hashes.
2780 2780
2781 2781 Returns 0 on success.
2782 2782 """
2783 2783
2784 2784 if rev and node:
2785 2785 raise util.Abort(_("please specify just one revision"))
2786 2786
2787 2787 if not node:
2788 2788 node = rev
2789 2789
2790 2790 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2791 2791 ctx = cmdutil.revsingle(repo, node)
2792 2792 for f in ctx:
2793 2793 if ui.debugflag:
2794 2794 ui.write("%40s " % hex(ctx.manifest()[f]))
2795 2795 if ui.verbose:
2796 2796 ui.write(decor[ctx.flags(f)])
2797 2797 ui.write("%s\n" % f)
2798 2798
2799 2799 def merge(ui, repo, node=None, **opts):
2800 2800 """merge working directory with another revision
2801 2801
2802 2802 The current working directory is updated with all changes made in
2803 2803 the requested revision since the last common predecessor revision.
2804 2804
2805 2805 Files that changed between either parent are marked as changed for
2806 2806 the next commit and a commit must be performed before any further
2807 2807 updates to the repository are allowed. The next commit will have
2808 2808 two parents.
2809 2809
2810 2810 ``--tool`` can be used to specify the merge tool used for file
2811 2811 merges. It overrides the HGMERGE environment variable and your
2812 2812 configuration files. See :hg:`help merge-tools` for options.
2813 2813
2814 2814 If no revision is specified, the working directory's parent is a
2815 2815 head revision, and the current branch contains exactly one other
2816 2816 head, the other head is merged with by default. Otherwise, an
2817 2817 explicit revision with which to merge with must be provided.
2818 2818
2819 2819 :hg:`resolve` must be used to resolve unresolved files.
2820 2820
2821 2821 To undo an uncommitted merge, use :hg:`update --clean .` which
2822 2822 will check out a clean copy of the original merge parent, losing
2823 2823 all changes.
2824 2824
2825 2825 Returns 0 on success, 1 if there are unresolved files.
2826 2826 """
2827 2827
2828 2828 if opts.get('rev') and node:
2829 2829 raise util.Abort(_("please specify just one revision"))
2830 2830 if not node:
2831 2831 node = opts.get('rev')
2832 2832
2833 2833 if not node:
2834 2834 branch = repo[None].branch()
2835 2835 bheads = repo.branchheads(branch)
2836 2836 if len(bheads) > 2:
2837 2837 raise util.Abort(_(
2838 2838 'branch \'%s\' has %d heads - '
2839 2839 'please merge with an explicit rev\n'
2840 2840 '(run \'hg heads .\' to see heads)')
2841 2841 % (branch, len(bheads)))
2842 2842
2843 2843 parent = repo.dirstate.p1()
2844 2844 if len(bheads) == 1:
2845 2845 if len(repo.heads()) > 1:
2846 2846 raise util.Abort(_(
2847 2847 'branch \'%s\' has one head - '
2848 2848 'please merge with an explicit rev\n'
2849 2849 '(run \'hg heads\' to see all heads)')
2850 2850 % branch)
2851 2851 msg = _('there is nothing to merge')
2852 2852 if parent != repo.lookup(repo[None].branch()):
2853 2853 msg = _('%s - use "hg update" instead') % msg
2854 2854 raise util.Abort(msg)
2855 2855
2856 2856 if parent not in bheads:
2857 2857 raise util.Abort(_('working dir not at a head rev - '
2858 2858 'use "hg update" or merge with an explicit rev'))
2859 2859 node = parent == bheads[0] and bheads[-1] or bheads[0]
2860 2860 else:
2861 2861 node = cmdutil.revsingle(repo, node).node()
2862 2862
2863 2863 if opts.get('preview'):
2864 2864 # find nodes that are ancestors of p2 but not of p1
2865 2865 p1 = repo.lookup('.')
2866 2866 p2 = repo.lookup(node)
2867 2867 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2868 2868
2869 2869 displayer = cmdutil.show_changeset(ui, repo, opts)
2870 2870 for node in nodes:
2871 2871 displayer.show(repo[node])
2872 2872 displayer.close()
2873 2873 return 0
2874 2874
2875 2875 try:
2876 2876 # ui.forcemerge is an internal variable, do not document
2877 2877 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2878 2878 return hg.merge(repo, node, force=opts.get('force'))
2879 2879 finally:
2880 2880 ui.setconfig('ui', 'forcemerge', '')
2881 2881
2882 2882 def outgoing(ui, repo, dest=None, **opts):
2883 2883 """show changesets not found in the destination
2884 2884
2885 2885 Show changesets not found in the specified destination repository
2886 2886 or the default push location. These are the changesets that would
2887 2887 be pushed if a push was requested.
2888 2888
2889 2889 See pull for details of valid destination formats.
2890 2890
2891 2891 Returns 0 if there are outgoing changes, 1 otherwise.
2892 2892 """
2893 2893
2894 2894 if opts.get('bookmarks'):
2895 2895 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2896 2896 dest, branches = hg.parseurl(dest, opts.get('branch'))
2897 2897 other = hg.repository(hg.remoteui(repo, opts), dest)
2898 2898 if 'bookmarks' not in other.listkeys('namespaces'):
2899 2899 ui.warn(_("remote doesn't support bookmarks\n"))
2900 2900 return 0
2901 2901 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
2902 2902 return bookmarks.diff(ui, other, repo)
2903 2903
2904 2904 ret = hg.outgoing(ui, repo, dest, opts)
2905 2905 return ret
2906 2906
2907 2907 def parents(ui, repo, file_=None, **opts):
2908 2908 """show the parents of the working directory or revision
2909 2909
2910 2910 Print the working directory's parent revisions. If a revision is
2911 2911 given via -r/--rev, the parent of that revision will be printed.
2912 2912 If a file argument is given, the revision in which the file was
2913 2913 last changed (before the working directory revision or the
2914 2914 argument to --rev if given) is printed.
2915 2915
2916 2916 Returns 0 on success.
2917 2917 """
2918 2918
2919 2919 ctx = cmdutil.revsingle(repo, opts.get('rev'), None)
2920 2920
2921 2921 if file_:
2922 2922 m = cmdutil.match(repo, (file_,), opts)
2923 2923 if m.anypats() or len(m.files()) != 1:
2924 2924 raise util.Abort(_('can only specify an explicit filename'))
2925 2925 file_ = m.files()[0]
2926 2926 filenodes = []
2927 2927 for cp in ctx.parents():
2928 2928 if not cp:
2929 2929 continue
2930 2930 try:
2931 2931 filenodes.append(cp.filenode(file_))
2932 2932 except error.LookupError:
2933 2933 pass
2934 2934 if not filenodes:
2935 2935 raise util.Abort(_("'%s' not found in manifest!") % file_)
2936 2936 fl = repo.file(file_)
2937 2937 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2938 2938 else:
2939 2939 p = [cp.node() for cp in ctx.parents()]
2940 2940
2941 2941 displayer = cmdutil.show_changeset(ui, repo, opts)
2942 2942 for n in p:
2943 2943 if n != nullid:
2944 2944 displayer.show(repo[n])
2945 2945 displayer.close()
2946 2946
2947 2947 def paths(ui, repo, search=None):
2948 2948 """show aliases for remote repositories
2949 2949
2950 2950 Show definition of symbolic path name NAME. If no name is given,
2951 2951 show definition of all available names.
2952 2952
2953 2953 Path names are defined in the [paths] section of your
2954 2954 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
2955 2955 repository, ``.hg/hgrc`` is used, too.
2956 2956
2957 2957 The path names ``default`` and ``default-push`` have a special
2958 2958 meaning. When performing a push or pull operation, they are used
2959 2959 as fallbacks if no location is specified on the command-line.
2960 2960 When ``default-push`` is set, it will be used for push and
2961 2961 ``default`` will be used for pull; otherwise ``default`` is used
2962 2962 as the fallback for both. When cloning a repository, the clone
2963 2963 source is written as ``default`` in ``.hg/hgrc``. Note that
2964 2964 ``default`` and ``default-push`` apply to all inbound (e.g.
2965 2965 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
2966 2966 :hg:`bundle`) operations.
2967 2967
2968 2968 See :hg:`help urls` for more information.
2969 2969
2970 2970 Returns 0 on success.
2971 2971 """
2972 2972 if search:
2973 2973 for name, path in ui.configitems("paths"):
2974 2974 if name == search:
2975 2975 ui.write("%s\n" % url.hidepassword(path))
2976 2976 return
2977 2977 ui.warn(_("not found!\n"))
2978 2978 return 1
2979 2979 else:
2980 2980 for name, path in ui.configitems("paths"):
2981 2981 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2982 2982
2983 2983 def postincoming(ui, repo, modheads, optupdate, checkout):
2984 2984 if modheads == 0:
2985 2985 return
2986 2986 if optupdate:
2987 2987 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2988 2988 return hg.update(repo, checkout)
2989 2989 else:
2990 2990 ui.status(_("not updating, since new heads added\n"))
2991 2991 if modheads > 1:
2992 2992 currentbranchheads = len(repo.branchheads())
2993 2993 if currentbranchheads == modheads:
2994 2994 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2995 2995 elif currentbranchheads > 1:
2996 2996 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
2997 2997 else:
2998 2998 ui.status(_("(run 'hg heads' to see heads)\n"))
2999 2999 else:
3000 3000 ui.status(_("(run 'hg update' to get a working copy)\n"))
3001 3001
3002 3002 def pull(ui, repo, source="default", **opts):
3003 3003 """pull changes from the specified source
3004 3004
3005 3005 Pull changes from a remote repository to a local one.
3006 3006
3007 3007 This finds all changes from the repository at the specified path
3008 3008 or URL and adds them to a local repository (the current one unless
3009 3009 -R is specified). By default, this does not update the copy of the
3010 3010 project in the working directory.
3011 3011
3012 3012 Use :hg:`incoming` if you want to see what would have been added
3013 3013 by a pull at the time you issued this command. If you then decide
3014 3014 to add those changes to the repository, you should use :hg:`pull
3015 3015 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3016 3016
3017 3017 If SOURCE is omitted, the 'default' path will be used.
3018 3018 See :hg:`help urls` for more information.
3019 3019
3020 3020 Returns 0 on success, 1 if an update had unresolved files.
3021 3021 """
3022 3022 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3023 3023 other = hg.repository(hg.remoteui(repo, opts), source)
3024 3024 ui.status(_('pulling from %s\n') % url.hidepassword(source))
3025 3025 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3026 3026
3027 3027 if opts.get('bookmark'):
3028 3028 if not revs:
3029 3029 revs = []
3030 3030 rb = other.listkeys('bookmarks')
3031 3031 for b in opts['bookmark']:
3032 3032 if b not in rb:
3033 3033 raise util.Abort(_('remote bookmark %s not found!') % b)
3034 3034 revs.append(rb[b])
3035 3035
3036 3036 if revs:
3037 3037 try:
3038 3038 revs = [other.lookup(rev) for rev in revs]
3039 3039 except error.CapabilityError:
3040 3040 err = _("other repository doesn't support revision lookup, "
3041 3041 "so a rev cannot be specified.")
3042 3042 raise util.Abort(err)
3043 3043
3044 3044 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3045 3045 bookmarks.updatefromremote(ui, repo, other)
3046 3046 if checkout:
3047 3047 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3048 3048 repo._subtoppath = source
3049 3049 try:
3050 3050 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3051 3051
3052 3052 finally:
3053 3053 del repo._subtoppath
3054 3054
3055 3055 # update specified bookmarks
3056 3056 if opts.get('bookmark'):
3057 3057 for b in opts['bookmark']:
3058 3058 # explicit pull overrides local bookmark if any
3059 3059 ui.status(_("importing bookmark %s\n") % b)
3060 3060 repo._bookmarks[b] = repo[rb[b]].node()
3061 3061 bookmarks.write(repo)
3062 3062
3063 3063 return ret
3064 3064
3065 3065 def push(ui, repo, dest=None, **opts):
3066 3066 """push changes to the specified destination
3067 3067
3068 3068 Push changesets from the local repository to the specified
3069 3069 destination.
3070 3070
3071 3071 This operation is symmetrical to pull: it is identical to a pull
3072 3072 in the destination repository from the current one.
3073 3073
3074 3074 By default, push will not allow creation of new heads at the
3075 3075 destination, since multiple heads would make it unclear which head
3076 3076 to use. In this situation, it is recommended to pull and merge
3077 3077 before pushing.
3078 3078
3079 3079 Use --new-branch if you want to allow push to create a new named
3080 3080 branch that is not present at the destination. This allows you to
3081 3081 only create a new branch without forcing other changes.
3082 3082
3083 3083 Use -f/--force to override the default behavior and push all
3084 3084 changesets on all branches.
3085 3085
3086 3086 If -r/--rev is used, the specified revision and all its ancestors
3087 3087 will be pushed to the remote repository.
3088 3088
3089 3089 Please see :hg:`help urls` for important details about ``ssh://``
3090 3090 URLs. If DESTINATION is omitted, a default path will be used.
3091 3091
3092 3092 Returns 0 if push was successful, 1 if nothing to push.
3093 3093 """
3094 3094
3095 3095 if opts.get('bookmark'):
3096 3096 for b in opts['bookmark']:
3097 3097 # translate -B options to -r so changesets get pushed
3098 3098 if b in repo._bookmarks:
3099 3099 opts.setdefault('rev', []).append(b)
3100 3100 else:
3101 3101 # if we try to push a deleted bookmark, translate it to null
3102 3102 # this lets simultaneous -r, -b options continue working
3103 3103 opts.setdefault('rev', []).append("null")
3104 3104
3105 3105 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3106 3106 dest, branches = hg.parseurl(dest, opts.get('branch'))
3107 3107 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
3108 3108 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3109 3109 other = hg.repository(hg.remoteui(repo, opts), dest)
3110 3110 if revs:
3111 3111 revs = [repo.lookup(rev) for rev in revs]
3112 3112
3113 3113 repo._subtoppath = dest
3114 3114 try:
3115 3115 # push subrepos depth-first for coherent ordering
3116 3116 c = repo['']
3117 3117 subs = c.substate # only repos that are committed
3118 3118 for s in sorted(subs):
3119 3119 if not c.sub(s).push(opts.get('force')):
3120 3120 return False
3121 3121 finally:
3122 3122 del repo._subtoppath
3123 3123 result = repo.push(other, opts.get('force'), revs=revs,
3124 3124 newbranch=opts.get('new_branch'))
3125 3125
3126 3126 result = (result == 0)
3127 3127
3128 3128 if opts.get('bookmark'):
3129 3129 rb = other.listkeys('bookmarks')
3130 3130 for b in opts['bookmark']:
3131 3131 # explicit push overrides remote bookmark if any
3132 3132 if b in repo._bookmarks:
3133 3133 ui.status(_("exporting bookmark %s\n") % b)
3134 3134 new = repo[b].hex()
3135 3135 elif b in rb:
3136 3136 ui.status(_("deleting remote bookmark %s\n") % b)
3137 3137 new = '' # delete
3138 3138 else:
3139 3139 ui.warn(_('bookmark %s does not exist on the local '
3140 3140 'or remote repository!\n') % b)
3141 3141 return 2
3142 3142 old = rb.get(b, '')
3143 3143 r = other.pushkey('bookmarks', b, old, new)
3144 3144 if not r:
3145 3145 ui.warn(_('updating bookmark %s failed!\n') % b)
3146 3146 if not result:
3147 3147 result = 2
3148 3148
3149 3149 return result
3150 3150
3151 3151 def recover(ui, repo):
3152 3152 """roll back an interrupted transaction
3153 3153
3154 3154 Recover from an interrupted commit or pull.
3155 3155
3156 3156 This command tries to fix the repository status after an
3157 3157 interrupted operation. It should only be necessary when Mercurial
3158 3158 suggests it.
3159 3159
3160 3160 Returns 0 if successful, 1 if nothing to recover or verify fails.
3161 3161 """
3162 3162 if repo.recover():
3163 3163 return hg.verify(repo)
3164 3164 return 1
3165 3165
3166 3166 def remove(ui, repo, *pats, **opts):
3167 3167 """remove the specified files on the next commit
3168 3168
3169 3169 Schedule the indicated files for removal from the repository.
3170 3170
3171 3171 This only removes files from the current branch, not from the
3172 3172 entire project history. -A/--after can be used to remove only
3173 3173 files that have already been deleted, -f/--force can be used to
3174 3174 force deletion, and -Af can be used to remove files from the next
3175 3175 revision without deleting them from the working directory.
3176 3176
3177 3177 The following table details the behavior of remove for different
3178 3178 file states (columns) and option combinations (rows). The file
3179 3179 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3180 3180 reported by :hg:`status`). The actions are Warn, Remove (from
3181 3181 branch) and Delete (from disk)::
3182 3182
3183 3183 A C M !
3184 3184 none W RD W R
3185 3185 -f R RD RD R
3186 3186 -A W W W R
3187 3187 -Af R R R R
3188 3188
3189 3189 This command schedules the files to be removed at the next commit.
3190 3190 To undo a remove before that, see :hg:`revert`.
3191 3191
3192 3192 Returns 0 on success, 1 if any warnings encountered.
3193 3193 """
3194 3194
3195 3195 ret = 0
3196 3196 after, force = opts.get('after'), opts.get('force')
3197 3197 if not pats and not after:
3198 3198 raise util.Abort(_('no files specified'))
3199 3199
3200 3200 m = cmdutil.match(repo, pats, opts)
3201 3201 s = repo.status(match=m, clean=True)
3202 3202 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3203 3203
3204 3204 for f in m.files():
3205 3205 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3206 3206 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3207 3207 ret = 1
3208 3208
3209 3209 if force:
3210 3210 remove, forget = modified + deleted + clean, added
3211 3211 elif after:
3212 3212 remove, forget = deleted, []
3213 3213 for f in modified + added + clean:
3214 3214 ui.warn(_('not removing %s: file still exists (use -f'
3215 3215 ' to force removal)\n') % m.rel(f))
3216 3216 ret = 1
3217 3217 else:
3218 3218 remove, forget = deleted + clean, []
3219 3219 for f in modified:
3220 3220 ui.warn(_('not removing %s: file is modified (use -f'
3221 3221 ' to force removal)\n') % m.rel(f))
3222 3222 ret = 1
3223 3223 for f in added:
3224 3224 ui.warn(_('not removing %s: file has been marked for add (use -f'
3225 3225 ' to force removal)\n') % m.rel(f))
3226 3226 ret = 1
3227 3227
3228 3228 for f in sorted(remove + forget):
3229 3229 if ui.verbose or not m.exact(f):
3230 3230 ui.status(_('removing %s\n') % m.rel(f))
3231 3231
3232 3232 repo[None].forget(forget)
3233 3233 repo[None].remove(remove, unlink=not after)
3234 3234 return ret
3235 3235
3236 3236 def rename(ui, repo, *pats, **opts):
3237 3237 """rename files; equivalent of copy + remove
3238 3238
3239 3239 Mark dest as copies of sources; mark sources for deletion. If dest
3240 3240 is a directory, copies are put in that directory. If dest is a
3241 3241 file, there can only be one source.
3242 3242
3243 3243 By default, this command copies the contents of files as they
3244 3244 exist in the working directory. If invoked with -A/--after, the
3245 3245 operation is recorded, but no copying is performed.
3246 3246
3247 3247 This command takes effect at the next commit. To undo a rename
3248 3248 before that, see :hg:`revert`.
3249 3249
3250 3250 Returns 0 on success, 1 if errors are encountered.
3251 3251 """
3252 3252 wlock = repo.wlock(False)
3253 3253 try:
3254 3254 return cmdutil.copy(ui, repo, pats, opts, rename=True)
3255 3255 finally:
3256 3256 wlock.release()
3257 3257
3258 3258 def resolve(ui, repo, *pats, **opts):
3259 3259 """redo merges or set/view the merge status of files
3260 3260
3261 3261 Merges with unresolved conflicts are often the result of
3262 3262 non-interactive merging using the ``internal:merge`` configuration
3263 3263 setting, or a command-line merge tool like ``diff3``. The resolve
3264 3264 command is used to manage the files involved in a merge, after
3265 3265 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
3266 3266 working directory must have two parents).
3267 3267
3268 3268 The resolve command can be used in the following ways:
3269 3269
3270 3270 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
3271 3271 files, discarding any previous merge attempts. Re-merging is not
3272 3272 performed for files already marked as resolved. Use ``--all/-a``
3273 3273 to selects all unresolved files. ``--tool`` can be used to specify
3274 3274 the merge tool used for the given files. It overrides the HGMERGE
3275 3275 environment variable and your configuration files.
3276 3276
3277 3277 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
3278 3278 (e.g. after having manually fixed-up the files). The default is
3279 3279 to mark all unresolved files.
3280 3280
3281 3281 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
3282 3282 default is to mark all resolved files.
3283 3283
3284 3284 - :hg:`resolve -l`: list files which had or still have conflicts.
3285 3285 In the printed list, ``U`` = unresolved and ``R`` = resolved.
3286 3286
3287 3287 Note that Mercurial will not let you commit files with unresolved
3288 3288 merge conflicts. You must use :hg:`resolve -m ...` before you can
3289 3289 commit after a conflicting merge.
3290 3290
3291 3291 Returns 0 on success, 1 if any files fail a resolve attempt.
3292 3292 """
3293 3293
3294 3294 all, mark, unmark, show, nostatus = \
3295 3295 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
3296 3296
3297 3297 if (show and (mark or unmark)) or (mark and unmark):
3298 3298 raise util.Abort(_("too many options specified"))
3299 3299 if pats and all:
3300 3300 raise util.Abort(_("can't specify --all and patterns"))
3301 3301 if not (all or pats or show or mark or unmark):
3302 3302 raise util.Abort(_('no files or directories specified; '
3303 3303 'use --all to remerge all files'))
3304 3304
3305 3305 ms = mergemod.mergestate(repo)
3306 3306 m = cmdutil.match(repo, pats, opts)
3307 3307 ret = 0
3308 3308
3309 3309 for f in ms:
3310 3310 if m(f):
3311 3311 if show:
3312 3312 if nostatus:
3313 3313 ui.write("%s\n" % f)
3314 3314 else:
3315 3315 ui.write("%s %s\n" % (ms[f].upper(), f),
3316 3316 label='resolve.' +
3317 3317 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3318 3318 elif mark:
3319 3319 ms.mark(f, "r")
3320 3320 elif unmark:
3321 3321 ms.mark(f, "u")
3322 3322 else:
3323 3323 wctx = repo[None]
3324 3324 mctx = wctx.parents()[-1]
3325 3325
3326 3326 # backup pre-resolve (merge uses .orig for its own purposes)
3327 3327 a = repo.wjoin(f)
3328 3328 util.copyfile(a, a + ".resolve")
3329 3329
3330 3330 try:
3331 3331 # resolve file
3332 3332 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3333 3333 if ms.resolve(f, wctx, mctx):
3334 3334 ret = 1
3335 3335 finally:
3336 3336 ui.setconfig('ui', 'forcemerge', '')
3337 3337
3338 3338 # replace filemerge's .orig file with our resolve file
3339 3339 util.rename(a + ".resolve", a + ".orig")
3340 3340
3341 3341 ms.commit()
3342 3342 return ret
3343 3343
3344 3344 def revert(ui, repo, *pats, **opts):
3345 3345 """restore individual files or directories to an earlier state
3346 3346
3347 3347 .. note::
3348 3348 This command is most likely not what you are looking for.
3349 3349 Revert will partially overwrite content in the working
3350 3350 directory without changing the working directory parents. Use
3351 3351 :hg:`update -r rev` to check out earlier revisions, or
3352 3352 :hg:`update --clean .` to undo a merge which has added another
3353 3353 parent.
3354 3354
3355 3355 With no revision specified, revert the named files or directories
3356 3356 to the contents they had in the parent of the working directory.
3357 3357 This restores the contents of the affected files to an unmodified
3358 3358 state and unschedules adds, removes, copies, and renames. If the
3359 3359 working directory has two parents, you must explicitly specify a
3360 3360 revision.
3361 3361
3362 3362 Using the -r/--rev option, revert the given files or directories
3363 3363 to their contents as of a specific revision. This can be helpful
3364 3364 to "roll back" some or all of an earlier change. See :hg:`help
3365 3365 dates` for a list of formats valid for -d/--date.
3366 3366
3367 3367 Revert modifies the working directory. It does not commit any
3368 3368 changes, or change the parent of the working directory. If you
3369 3369 revert to a revision other than the parent of the working
3370 3370 directory, the reverted files will thus appear modified
3371 3371 afterwards.
3372 3372
3373 3373 If a file has been deleted, it is restored. Files scheduled for
3374 3374 addition are just unscheduled and left as they are. If the
3375 3375 executable mode of a file was changed, it is reset.
3376 3376
3377 3377 If names are given, all files matching the names are reverted.
3378 3378 If no arguments are given, no files are reverted.
3379 3379
3380 3380 Modified files are saved with a .orig suffix before reverting.
3381 3381 To disable these backups, use --no-backup.
3382 3382
3383 3383 Returns 0 on success.
3384 3384 """
3385 3385
3386 3386 if opts.get("date"):
3387 3387 if opts.get("rev"):
3388 3388 raise util.Abort(_("you can't specify a revision and a date"))
3389 3389 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3390 3390
3391 3391 parent, p2 = repo.dirstate.parents()
3392 3392 if not opts.get('rev') and p2 != nullid:
3393 3393 raise util.Abort(_('uncommitted merge - '
3394 3394 'use "hg update", see "hg help revert"'))
3395 3395
3396 3396 if not pats and not opts.get('all'):
3397 3397 raise util.Abort(_('no files or directories specified; '
3398 3398 'use --all to revert the whole repo'))
3399 3399
3400 3400 ctx = cmdutil.revsingle(repo, opts.get('rev'))
3401 3401 node = ctx.node()
3402 3402 mf = ctx.manifest()
3403 3403 if node == parent:
3404 3404 pmf = mf
3405 3405 else:
3406 3406 pmf = None
3407 3407
3408 3408 # need all matching names in dirstate and manifest of target rev,
3409 3409 # so have to walk both. do not print errors if files exist in one
3410 3410 # but not other.
3411 3411
3412 3412 names = {}
3413 3413
3414 3414 wlock = repo.wlock()
3415 3415 try:
3416 3416 # walk dirstate.
3417 3417
3418 3418 m = cmdutil.match(repo, pats, opts)
3419 3419 m.bad = lambda x, y: False
3420 3420 for abs in repo.walk(m):
3421 3421 names[abs] = m.rel(abs), m.exact(abs)
3422 3422
3423 3423 # walk target manifest.
3424 3424
3425 3425 def badfn(path, msg):
3426 3426 if path in names:
3427 3427 return
3428 3428 path_ = path + '/'
3429 3429 for f in names:
3430 3430 if f.startswith(path_):
3431 3431 return
3432 3432 ui.warn("%s: %s\n" % (m.rel(path), msg))
3433 3433
3434 3434 m = cmdutil.match(repo, pats, opts)
3435 3435 m.bad = badfn
3436 3436 for abs in repo[node].walk(m):
3437 3437 if abs not in names:
3438 3438 names[abs] = m.rel(abs), m.exact(abs)
3439 3439
3440 3440 m = cmdutil.matchfiles(repo, names)
3441 3441 changes = repo.status(match=m)[:4]
3442 3442 modified, added, removed, deleted = map(set, changes)
3443 3443
3444 3444 # if f is a rename, also revert the source
3445 3445 cwd = repo.getcwd()
3446 3446 for f in added:
3447 3447 src = repo.dirstate.copied(f)
3448 3448 if src and src not in names and repo.dirstate[src] == 'r':
3449 3449 removed.add(src)
3450 3450 names[src] = (repo.pathto(src, cwd), True)
3451 3451
3452 3452 def removeforget(abs):
3453 3453 if repo.dirstate[abs] == 'a':
3454 3454 return _('forgetting %s\n')
3455 3455 return _('removing %s\n')
3456 3456
3457 3457 revert = ([], _('reverting %s\n'))
3458 3458 add = ([], _('adding %s\n'))
3459 3459 remove = ([], removeforget)
3460 3460 undelete = ([], _('undeleting %s\n'))
3461 3461
3462 3462 disptable = (
3463 3463 # dispatch table:
3464 3464 # file state
3465 3465 # action if in target manifest
3466 3466 # action if not in target manifest
3467 3467 # make backup if in target manifest
3468 3468 # make backup if not in target manifest
3469 3469 (modified, revert, remove, True, True),
3470 3470 (added, revert, remove, True, False),
3471 3471 (removed, undelete, None, False, False),
3472 3472 (deleted, revert, remove, False, False),
3473 3473 )
3474 3474
3475 3475 for abs, (rel, exact) in sorted(names.items()):
3476 3476 mfentry = mf.get(abs)
3477 3477 target = repo.wjoin(abs)
3478 3478 def handle(xlist, dobackup):
3479 3479 xlist[0].append(abs)
3480 3480 if (dobackup and not opts.get('no_backup') and
3481 3481 os.path.lexists(target)):
3482 3482 bakname = "%s.orig" % rel
3483 3483 ui.note(_('saving current version of %s as %s\n') %
3484 3484 (rel, bakname))
3485 3485 if not opts.get('dry_run'):
3486 3486 util.rename(target, bakname)
3487 3487 if ui.verbose or not exact:
3488 3488 msg = xlist[1]
3489 3489 if not isinstance(msg, basestring):
3490 3490 msg = msg(abs)
3491 3491 ui.status(msg % rel)
3492 3492 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3493 3493 if abs not in table:
3494 3494 continue
3495 3495 # file has changed in dirstate
3496 3496 if mfentry:
3497 3497 handle(hitlist, backuphit)
3498 3498 elif misslist is not None:
3499 3499 handle(misslist, backupmiss)
3500 3500 break
3501 3501 else:
3502 3502 if abs not in repo.dirstate:
3503 3503 if mfentry:
3504 3504 handle(add, True)
3505 3505 elif exact:
3506 3506 ui.warn(_('file not managed: %s\n') % rel)
3507 3507 continue
3508 3508 # file has not changed in dirstate
3509 3509 if node == parent:
3510 3510 if exact:
3511 3511 ui.warn(_('no changes needed to %s\n') % rel)
3512 3512 continue
3513 3513 if pmf is None:
3514 3514 # only need parent manifest in this unlikely case,
3515 3515 # so do not read by default
3516 3516 pmf = repo[parent].manifest()
3517 3517 if abs in pmf:
3518 3518 if mfentry:
3519 3519 # if version of file is same in parent and target
3520 3520 # manifests, do nothing
3521 3521 if (pmf[abs] != mfentry or
3522 3522 pmf.flags(abs) != mf.flags(abs)):
3523 3523 handle(revert, False)
3524 3524 else:
3525 3525 handle(remove, False)
3526 3526
3527 3527 if not opts.get('dry_run'):
3528 3528 def checkout(f):
3529 3529 fc = ctx[f]
3530 3530 repo.wwrite(f, fc.data(), fc.flags())
3531 3531
3532 3532 audit_path = util.path_auditor(repo.root)
3533 3533 for f in remove[0]:
3534 3534 if repo.dirstate[f] == 'a':
3535 3535 repo.dirstate.forget(f)
3536 3536 continue
3537 3537 audit_path(f)
3538 3538 try:
3539 3539 util.unlinkpath(repo.wjoin(f))
3540 3540 except OSError:
3541 3541 pass
3542 3542 repo.dirstate.remove(f)
3543 3543
3544 3544 normal = None
3545 3545 if node == parent:
3546 3546 # We're reverting to our parent. If possible, we'd like status
3547 3547 # to report the file as clean. We have to use normallookup for
3548 3548 # merges to avoid losing information about merged/dirty files.
3549 3549 if p2 != nullid:
3550 3550 normal = repo.dirstate.normallookup
3551 3551 else:
3552 3552 normal = repo.dirstate.normal
3553 3553 for f in revert[0]:
3554 3554 checkout(f)
3555 3555 if normal:
3556 3556 normal(f)
3557 3557
3558 3558 for f in add[0]:
3559 3559 checkout(f)
3560 3560 repo.dirstate.add(f)
3561 3561
3562 3562 normal = repo.dirstate.normallookup
3563 3563 if node == parent and p2 == nullid:
3564 3564 normal = repo.dirstate.normal
3565 3565 for f in undelete[0]:
3566 3566 checkout(f)
3567 3567 normal(f)
3568 3568
3569 3569 finally:
3570 3570 wlock.release()
3571 3571
3572 3572 def rollback(ui, repo, **opts):
3573 3573 """roll back the last transaction (dangerous)
3574 3574
3575 3575 This command should be used with care. There is only one level of
3576 3576 rollback, and there is no way to undo a rollback. It will also
3577 3577 restore the dirstate at the time of the last transaction, losing
3578 3578 any dirstate changes since that time. This command does not alter
3579 3579 the working directory.
3580 3580
3581 3581 Transactions are used to encapsulate the effects of all commands
3582 3582 that create new changesets or propagate existing changesets into a
3583 3583 repository. For example, the following commands are transactional,
3584 3584 and their effects can be rolled back:
3585 3585
3586 3586 - commit
3587 3587 - import
3588 3588 - pull
3589 3589 - push (with this repository as the destination)
3590 3590 - unbundle
3591 3591
3592 3592 This command is not intended for use on public repositories. Once
3593 3593 changes are visible for pull by other users, rolling a transaction
3594 3594 back locally is ineffective (someone else may already have pulled
3595 3595 the changes). Furthermore, a race is possible with readers of the
3596 3596 repository; for example an in-progress pull from the repository
3597 3597 may fail if a rollback is performed.
3598 3598
3599 3599 Returns 0 on success, 1 if no rollback data is available.
3600 3600 """
3601 3601 return repo.rollback(opts.get('dry_run'))
3602 3602
3603 3603 def root(ui, repo):
3604 3604 """print the root (top) of the current working directory
3605 3605
3606 3606 Print the root directory of the current repository.
3607 3607
3608 3608 Returns 0 on success.
3609 3609 """
3610 3610 ui.write(repo.root + "\n")
3611 3611
3612 3612 def serve(ui, repo, **opts):
3613 3613 """start stand-alone webserver
3614 3614
3615 3615 Start a local HTTP repository browser and pull server. You can use
3616 3616 this for ad-hoc sharing and browsing of repositories. It is
3617 3617 recommended to use a real web server to serve a repository for
3618 3618 longer periods of time.
3619 3619
3620 3620 Please note that the server does not implement access control.
3621 3621 This means that, by default, anybody can read from the server and
3622 3622 nobody can write to it by default. Set the ``web.allow_push``
3623 3623 option to ``*`` to allow everybody to push to the server. You
3624 3624 should use a real web server if you need to authenticate users.
3625 3625
3626 3626 By default, the server logs accesses to stdout and errors to
3627 3627 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3628 3628 files.
3629 3629
3630 3630 To have the server choose a free port number to listen on, specify
3631 3631 a port number of 0; in this case, the server will print the port
3632 3632 number it uses.
3633 3633
3634 3634 Returns 0 on success.
3635 3635 """
3636 3636
3637 3637 if opts["stdio"]:
3638 3638 if repo is None:
3639 3639 raise error.RepoError(_("There is no Mercurial repository here"
3640 3640 " (.hg not found)"))
3641 3641 s = sshserver.sshserver(ui, repo)
3642 3642 s.serve_forever()
3643 3643
3644 3644 # this way we can check if something was given in the command-line
3645 3645 if opts.get('port'):
3646 3646 opts['port'] = util.getport(opts.get('port'))
3647 3647
3648 3648 baseui = repo and repo.baseui or ui
3649 3649 optlist = ("name templates style address port prefix ipv6"
3650 3650 " accesslog errorlog certificate encoding")
3651 3651 for o in optlist.split():
3652 3652 val = opts.get(o, '')
3653 3653 if val in (None, ''): # should check against default options instead
3654 3654 continue
3655 3655 baseui.setconfig("web", o, val)
3656 3656 if repo and repo.ui != baseui:
3657 3657 repo.ui.setconfig("web", o, val)
3658 3658
3659 3659 o = opts.get('web_conf') or opts.get('webdir_conf')
3660 3660 if not o:
3661 3661 if not repo:
3662 3662 raise error.RepoError(_("There is no Mercurial repository"
3663 3663 " here (.hg not found)"))
3664 3664 o = repo.root
3665 3665
3666 3666 app = hgweb.hgweb(o, baseui=ui)
3667 3667
3668 3668 class service(object):
3669 3669 def init(self):
3670 3670 util.set_signal_handler()
3671 3671 self.httpd = hgweb.server.create_server(ui, app)
3672 3672
3673 3673 if opts['port'] and not ui.verbose:
3674 3674 return
3675 3675
3676 3676 if self.httpd.prefix:
3677 3677 prefix = self.httpd.prefix.strip('/') + '/'
3678 3678 else:
3679 3679 prefix = ''
3680 3680
3681 3681 port = ':%d' % self.httpd.port
3682 3682 if port == ':80':
3683 3683 port = ''
3684 3684
3685 3685 bindaddr = self.httpd.addr
3686 3686 if bindaddr == '0.0.0.0':
3687 3687 bindaddr = '*'
3688 3688 elif ':' in bindaddr: # IPv6
3689 3689 bindaddr = '[%s]' % bindaddr
3690 3690
3691 3691 fqaddr = self.httpd.fqaddr
3692 3692 if ':' in fqaddr:
3693 3693 fqaddr = '[%s]' % fqaddr
3694 3694 if opts['port']:
3695 3695 write = ui.status
3696 3696 else:
3697 3697 write = ui.write
3698 3698 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3699 3699 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3700 3700
3701 3701 def run(self):
3702 3702 self.httpd.serve_forever()
3703 3703
3704 3704 service = service()
3705 3705
3706 3706 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3707 3707
3708 3708 def status(ui, repo, *pats, **opts):
3709 3709 """show changed files in the working directory
3710 3710
3711 3711 Show status of files in the repository. If names are given, only
3712 3712 files that match are shown. Files that are clean or ignored or
3713 3713 the source of a copy/move operation, are not listed unless
3714 3714 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3715 3715 Unless options described with "show only ..." are given, the
3716 3716 options -mardu are used.
3717 3717
3718 3718 Option -q/--quiet hides untracked (unknown and ignored) files
3719 3719 unless explicitly requested with -u/--unknown or -i/--ignored.
3720 3720
3721 3721 .. note::
3722 3722 status may appear to disagree with diff if permissions have
3723 3723 changed or a merge has occurred. The standard diff format does
3724 3724 not report permission changes and diff only reports changes
3725 3725 relative to one merge parent.
3726 3726
3727 3727 If one revision is given, it is used as the base revision.
3728 3728 If two revisions are given, the differences between them are
3729 3729 shown. The --change option can also be used as a shortcut to list
3730 3730 the changed files of a revision from its first parent.
3731 3731
3732 3732 The codes used to show the status of files are::
3733 3733
3734 3734 M = modified
3735 3735 A = added
3736 3736 R = removed
3737 3737 C = clean
3738 3738 ! = missing (deleted by non-hg command, but still tracked)
3739 3739 ? = not tracked
3740 3740 I = ignored
3741 3741 = origin of the previous file listed as A (added)
3742 3742
3743 3743 Returns 0 on success.
3744 3744 """
3745 3745
3746 3746 revs = opts.get('rev')
3747 3747 change = opts.get('change')
3748 3748
3749 3749 if revs and change:
3750 3750 msg = _('cannot specify --rev and --change at the same time')
3751 3751 raise util.Abort(msg)
3752 3752 elif change:
3753 3753 node2 = repo.lookup(change)
3754 3754 node1 = repo[node2].p1().node()
3755 3755 else:
3756 3756 node1, node2 = cmdutil.revpair(repo, revs)
3757 3757
3758 3758 cwd = (pats and repo.getcwd()) or ''
3759 3759 end = opts.get('print0') and '\0' or '\n'
3760 3760 copy = {}
3761 3761 states = 'modified added removed deleted unknown ignored clean'.split()
3762 3762 show = [k for k in states if opts.get(k)]
3763 3763 if opts.get('all'):
3764 3764 show += ui.quiet and (states[:4] + ['clean']) or states
3765 3765 if not show:
3766 3766 show = ui.quiet and states[:4] or states[:5]
3767 3767
3768 3768 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3769 3769 'ignored' in show, 'clean' in show, 'unknown' in show,
3770 3770 opts.get('subrepos'))
3771 3771 changestates = zip(states, 'MAR!?IC', stat)
3772 3772
3773 3773 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3774 3774 ctxn = repo[nullid]
3775 3775 ctx1 = repo[node1]
3776 3776 ctx2 = repo[node2]
3777 3777 added = stat[1]
3778 3778 if node2 is None:
3779 3779 added = stat[0] + stat[1] # merged?
3780 3780
3781 3781 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3782 3782 if k in added:
3783 3783 copy[k] = v
3784 3784 elif v in added:
3785 3785 copy[v] = k
3786 3786
3787 3787 for state, char, files in changestates:
3788 3788 if state in show:
3789 3789 format = "%s %%s%s" % (char, end)
3790 3790 if opts.get('no_status'):
3791 3791 format = "%%s%s" % end
3792 3792
3793 3793 for f in files:
3794 3794 ui.write(format % repo.pathto(f, cwd),
3795 3795 label='status.' + state)
3796 3796 if f in copy:
3797 3797 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3798 3798 label='status.copied')
3799 3799
3800 3800 def summary(ui, repo, **opts):
3801 3801 """summarize working directory state
3802 3802
3803 3803 This generates a brief summary of the working directory state,
3804 3804 including parents, branch, commit status, and available updates.
3805 3805
3806 3806 With the --remote option, this will check the default paths for
3807 3807 incoming and outgoing changes. This can be time-consuming.
3808 3808
3809 3809 Returns 0 on success.
3810 3810 """
3811 3811
3812 3812 ctx = repo[None]
3813 3813 parents = ctx.parents()
3814 3814 pnode = parents[0].node()
3815 3815
3816 3816 for p in parents:
3817 3817 # label with log.changeset (instead of log.parent) since this
3818 3818 # shows a working directory parent *changeset*:
3819 3819 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3820 3820 label='log.changeset')
3821 3821 ui.write(' '.join(p.tags()), label='log.tag')
3822 3822 if p.bookmarks():
3823 3823 ui.write(' ' + ' '.join(p.bookmarks()), label='log.bookmark')
3824 3824 if p.rev() == -1:
3825 3825 if not len(repo):
3826 3826 ui.write(_(' (empty repository)'))
3827 3827 else:
3828 3828 ui.write(_(' (no revision checked out)'))
3829 3829 ui.write('\n')
3830 3830 if p.description():
3831 3831 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3832 3832 label='log.summary')
3833 3833
3834 3834 branch = ctx.branch()
3835 3835 bheads = repo.branchheads(branch)
3836 3836 m = _('branch: %s\n') % branch
3837 3837 if branch != 'default':
3838 3838 ui.write(m, label='log.branch')
3839 3839 else:
3840 3840 ui.status(m, label='log.branch')
3841 3841
3842 3842 st = list(repo.status(unknown=True))[:6]
3843 3843
3844 3844 c = repo.dirstate.copies()
3845 3845 copied, renamed = [], []
3846 3846 for d, s in c.iteritems():
3847 3847 if s in st[2]:
3848 3848 st[2].remove(s)
3849 3849 renamed.append(d)
3850 3850 else:
3851 3851 copied.append(d)
3852 3852 if d in st[1]:
3853 3853 st[1].remove(d)
3854 3854 st.insert(3, renamed)
3855 3855 st.insert(4, copied)
3856 3856
3857 3857 ms = mergemod.mergestate(repo)
3858 3858 st.append([f for f in ms if ms[f] == 'u'])
3859 3859
3860 3860 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3861 3861 st.append(subs)
3862 3862
3863 3863 labels = [ui.label(_('%d modified'), 'status.modified'),
3864 3864 ui.label(_('%d added'), 'status.added'),
3865 3865 ui.label(_('%d removed'), 'status.removed'),
3866 3866 ui.label(_('%d renamed'), 'status.copied'),
3867 3867 ui.label(_('%d copied'), 'status.copied'),
3868 3868 ui.label(_('%d deleted'), 'status.deleted'),
3869 3869 ui.label(_('%d unknown'), 'status.unknown'),
3870 3870 ui.label(_('%d ignored'), 'status.ignored'),
3871 3871 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3872 3872 ui.label(_('%d subrepos'), 'status.modified')]
3873 3873 t = []
3874 3874 for s, l in zip(st, labels):
3875 3875 if s:
3876 3876 t.append(l % len(s))
3877 3877
3878 3878 t = ', '.join(t)
3879 3879 cleanworkdir = False
3880 3880
3881 3881 if len(parents) > 1:
3882 3882 t += _(' (merge)')
3883 3883 elif branch != parents[0].branch():
3884 3884 t += _(' (new branch)')
3885 3885 elif (parents[0].extra().get('close') and
3886 3886 pnode in repo.branchheads(branch, closed=True)):
3887 3887 t += _(' (head closed)')
3888 3888 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3889 3889 t += _(' (clean)')
3890 3890 cleanworkdir = True
3891 3891 elif pnode not in bheads:
3892 3892 t += _(' (new branch head)')
3893 3893
3894 3894 if cleanworkdir:
3895 3895 ui.status(_('commit: %s\n') % t.strip())
3896 3896 else:
3897 3897 ui.write(_('commit: %s\n') % t.strip())
3898 3898
3899 3899 # all ancestors of branch heads - all ancestors of parent = new csets
3900 3900 new = [0] * len(repo)
3901 3901 cl = repo.changelog
3902 3902 for a in [cl.rev(n) for n in bheads]:
3903 3903 new[a] = 1
3904 3904 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3905 3905 new[a] = 1
3906 3906 for a in [p.rev() for p in parents]:
3907 3907 if a >= 0:
3908 3908 new[a] = 0
3909 3909 for a in cl.ancestors(*[p.rev() for p in parents]):
3910 3910 new[a] = 0
3911 3911 new = sum(new)
3912 3912
3913 3913 if new == 0:
3914 3914 ui.status(_('update: (current)\n'))
3915 3915 elif pnode not in bheads:
3916 3916 ui.write(_('update: %d new changesets (update)\n') % new)
3917 3917 else:
3918 3918 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
3919 3919 (new, len(bheads)))
3920 3920
3921 3921 if opts.get('remote'):
3922 3922 t = []
3923 3923 source, branches = hg.parseurl(ui.expandpath('default'))
3924 3924 other = hg.repository(hg.remoteui(repo, {}), source)
3925 3925 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3926 3926 ui.debug('comparing with %s\n' % url.hidepassword(source))
3927 3927 repo.ui.pushbuffer()
3928 3928 common, incoming, rheads = discovery.findcommonincoming(repo, other)
3929 3929 repo.ui.popbuffer()
3930 3930 if incoming:
3931 3931 t.append(_('1 or more incoming'))
3932 3932
3933 3933 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
3934 3934 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3935 3935 other = hg.repository(hg.remoteui(repo, {}), dest)
3936 3936 ui.debug('comparing with %s\n' % url.hidepassword(dest))
3937 3937 repo.ui.pushbuffer()
3938 3938 o = discovery.findoutgoing(repo, other)
3939 3939 repo.ui.popbuffer()
3940 3940 o = repo.changelog.nodesbetween(o, None)[0]
3941 3941 if o:
3942 3942 t.append(_('%d outgoing') % len(o))
3943 3943 if 'bookmarks' in other.listkeys('namespaces'):
3944 3944 lmarks = repo.listkeys('bookmarks')
3945 3945 rmarks = other.listkeys('bookmarks')
3946 3946 diff = set(rmarks) - set(lmarks)
3947 3947 if len(diff) > 0:
3948 3948 t.append(_('%d incoming bookmarks') % len(diff))
3949 3949 diff = set(lmarks) - set(rmarks)
3950 3950 if len(diff) > 0:
3951 3951 t.append(_('%d outgoing bookmarks') % len(diff))
3952 3952
3953 3953 if t:
3954 3954 ui.write(_('remote: %s\n') % (', '.join(t)))
3955 3955 else:
3956 3956 ui.status(_('remote: (synced)\n'))
3957 3957
3958 3958 def tag(ui, repo, name1, *names, **opts):
3959 3959 """add one or more tags for the current or given revision
3960 3960
3961 3961 Name a particular revision using <name>.
3962 3962
3963 3963 Tags are used to name particular revisions of the repository and are
3964 3964 very useful to compare different revisions, to go back to significant
3965 3965 earlier versions or to mark branch points as releases, etc. Changing
3966 3966 an existing tag is normally disallowed; use -f/--force to override.
3967 3967
3968 3968 If no revision is given, the parent of the working directory is
3969 3969 used, or tip if no revision is checked out.
3970 3970
3971 3971 To facilitate version control, distribution, and merging of tags,
3972 3972 they are stored as a file named ".hgtags" which is managed similarly
3973 3973 to other project files and can be hand-edited if necessary. This
3974 3974 also means that tagging creates a new commit. The file
3975 3975 ".hg/localtags" is used for local tags (not shared among
3976 3976 repositories).
3977 3977
3978 3978 Tag commits are usually made at the head of a branch. If the parent
3979 3979 of the working directory is not a branch head, :hg:`tag` aborts; use
3980 3980 -f/--force to force the tag commit to be based on a non-head
3981 3981 changeset.
3982 3982
3983 3983 See :hg:`help dates` for a list of formats valid for -d/--date.
3984 3984
3985 3985 Since tag names have priority over branch names during revision
3986 3986 lookup, using an existing branch name as a tag name is discouraged.
3987 3987
3988 3988 Returns 0 on success.
3989 3989 """
3990 3990
3991 3991 rev_ = "."
3992 3992 names = [t.strip() for t in (name1,) + names]
3993 3993 if len(names) != len(set(names)):
3994 3994 raise util.Abort(_('tag names must be unique'))
3995 3995 for n in names:
3996 3996 if n in ['tip', '.', 'null']:
3997 3997 raise util.Abort(_('the name \'%s\' is reserved') % n)
3998 3998 if not n:
3999 3999 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
4000 4000 if opts.get('rev') and opts.get('remove'):
4001 4001 raise util.Abort(_("--rev and --remove are incompatible"))
4002 4002 if opts.get('rev'):
4003 4003 rev_ = opts['rev']
4004 4004 message = opts.get('message')
4005 4005 if opts.get('remove'):
4006 4006 expectedtype = opts.get('local') and 'local' or 'global'
4007 4007 for n in names:
4008 4008 if not repo.tagtype(n):
4009 4009 raise util.Abort(_('tag \'%s\' does not exist') % n)
4010 4010 if repo.tagtype(n) != expectedtype:
4011 4011 if expectedtype == 'global':
4012 4012 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
4013 4013 else:
4014 4014 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
4015 4015 rev_ = nullid
4016 4016 if not message:
4017 4017 # we don't translate commit messages
4018 4018 message = 'Removed tag %s' % ', '.join(names)
4019 4019 elif not opts.get('force'):
4020 4020 for n in names:
4021 4021 if n in repo.tags():
4022 4022 raise util.Abort(_('tag \'%s\' already exists '
4023 4023 '(use -f to force)') % n)
4024 4024 if not opts.get('local'):
4025 4025 p1, p2 = repo.dirstate.parents()
4026 4026 if p2 != nullid:
4027 4027 raise util.Abort(_('uncommitted merge'))
4028 4028 bheads = repo.branchheads()
4029 4029 if not opts.get('force') and bheads and p1 not in bheads:
4030 4030 raise util.Abort(_('not at a branch head (use -f to force)'))
4031 4031 r = cmdutil.revsingle(repo, rev_).node()
4032 4032
4033 4033 if not message:
4034 4034 # we don't translate commit messages
4035 4035 message = ('Added tag %s for changeset %s' %
4036 4036 (', '.join(names), short(r)))
4037 4037
4038 4038 date = opts.get('date')
4039 4039 if date:
4040 4040 date = util.parsedate(date)
4041 4041
4042 4042 if opts.get('edit'):
4043 4043 message = ui.edit(message, ui.username())
4044 4044
4045 4045 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
4046 4046
4047 4047 def tags(ui, repo):
4048 4048 """list repository tags
4049 4049
4050 4050 This lists both regular and local tags. When the -v/--verbose
4051 4051 switch is used, a third column "local" is printed for local tags.
4052 4052
4053 4053 Returns 0 on success.
4054 4054 """
4055 4055
4056 4056 hexfunc = ui.debugflag and hex or short
4057 4057 tagtype = ""
4058 4058
4059 4059 for t, n in reversed(repo.tagslist()):
4060 4060 if ui.quiet:
4061 4061 ui.write("%s\n" % t)
4062 4062 continue
4063 4063
4064 try:
4065 hn = hexfunc(n)
4066 r = "%5d:%s" % (repo.changelog.rev(n), hn)
4067 except error.LookupError:
4068 r = " ?:%s" % hn
4069 else:
4070 spaces = " " * (30 - encoding.colwidth(t))
4071 if ui.verbose:
4072 if repo.tagtype(t) == 'local':
4073 tagtype = " local"
4074 else:
4075 tagtype = ""
4076 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
4064 hn = hexfunc(n)
4065 r = "%5d:%s" % (repo.changelog.rev(n), hn)
4066 spaces = " " * (30 - encoding.colwidth(t))
4067
4068 if ui.verbose:
4069 if repo.tagtype(t) == 'local':
4070 tagtype = " local"
4071 else:
4072 tagtype = ""
4073 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
4077 4074
4078 4075 def tip(ui, repo, **opts):
4079 4076 """show the tip revision
4080 4077
4081 4078 The tip revision (usually just called the tip) is the changeset
4082 4079 most recently added to the repository (and therefore the most
4083 4080 recently changed head).
4084 4081
4085 4082 If you have just made a commit, that commit will be the tip. If
4086 4083 you have just pulled changes from another repository, the tip of
4087 4084 that repository becomes the current tip. The "tip" tag is special
4088 4085 and cannot be renamed or assigned to a different changeset.
4089 4086
4090 4087 Returns 0 on success.
4091 4088 """
4092 4089 displayer = cmdutil.show_changeset(ui, repo, opts)
4093 4090 displayer.show(repo[len(repo) - 1])
4094 4091 displayer.close()
4095 4092
4096 4093 def unbundle(ui, repo, fname1, *fnames, **opts):
4097 4094 """apply one or more changegroup files
4098 4095
4099 4096 Apply one or more compressed changegroup files generated by the
4100 4097 bundle command.
4101 4098
4102 4099 Returns 0 on success, 1 if an update has unresolved files.
4103 4100 """
4104 4101 fnames = (fname1,) + fnames
4105 4102
4106 4103 lock = repo.lock()
4107 4104 wc = repo['.']
4108 4105 try:
4109 4106 for fname in fnames:
4110 4107 f = url.open(ui, fname)
4111 4108 gen = changegroup.readbundle(f, fname)
4112 4109 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
4113 4110 lock=lock)
4114 4111 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
4115 4112 finally:
4116 4113 lock.release()
4117 4114 return postincoming(ui, repo, modheads, opts.get('update'), None)
4118 4115
4119 4116 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
4120 4117 """update working directory (or switch revisions)
4121 4118
4122 4119 Update the repository's working directory to the specified
4123 4120 changeset. If no changeset is specified, update to the tip of the
4124 4121 current named branch.
4125 4122
4126 4123 If the changeset is not a descendant of the working directory's
4127 4124 parent, the update is aborted. With the -c/--check option, the
4128 4125 working directory is checked for uncommitted changes; if none are
4129 4126 found, the working directory is updated to the specified
4130 4127 changeset.
4131 4128
4132 4129 The following rules apply when the working directory contains
4133 4130 uncommitted changes:
4134 4131
4135 4132 1. If neither -c/--check nor -C/--clean is specified, and if
4136 4133 the requested changeset is an ancestor or descendant of
4137 4134 the working directory's parent, the uncommitted changes
4138 4135 are merged into the requested changeset and the merged
4139 4136 result is left uncommitted. If the requested changeset is
4140 4137 not an ancestor or descendant (that is, it is on another
4141 4138 branch), the update is aborted and the uncommitted changes
4142 4139 are preserved.
4143 4140
4144 4141 2. With the -c/--check option, the update is aborted and the
4145 4142 uncommitted changes are preserved.
4146 4143
4147 4144 3. With the -C/--clean option, uncommitted changes are discarded and
4148 4145 the working directory is updated to the requested changeset.
4149 4146
4150 4147 Use null as the changeset to remove the working directory (like
4151 4148 :hg:`clone -U`).
4152 4149
4153 4150 If you want to update just one file to an older changeset, use
4154 4151 :hg:`revert`.
4155 4152
4156 4153 See :hg:`help dates` for a list of formats valid for -d/--date.
4157 4154
4158 4155 Returns 0 on success, 1 if there are unresolved files.
4159 4156 """
4160 4157 if rev and node:
4161 4158 raise util.Abort(_("please specify just one revision"))
4162 4159
4163 4160 if rev is None or rev == '':
4164 4161 rev = node
4165 4162
4166 4163 # if we defined a bookmark, we have to remember the original bookmark name
4167 4164 brev = rev
4168 4165 rev = cmdutil.revsingle(repo, rev, rev).rev()
4169 4166
4170 4167 if check and clean:
4171 4168 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
4172 4169
4173 4170 if check:
4174 4171 # we could use dirty() but we can ignore merge and branch trivia
4175 4172 c = repo[None]
4176 4173 if c.modified() or c.added() or c.removed():
4177 4174 raise util.Abort(_("uncommitted local changes"))
4178 4175
4179 4176 if date:
4180 4177 if rev:
4181 4178 raise util.Abort(_("you can't specify a revision and a date"))
4182 4179 rev = cmdutil.finddate(ui, repo, date)
4183 4180
4184 4181 if clean or check:
4185 4182 ret = hg.clean(repo, rev)
4186 4183 else:
4187 4184 ret = hg.update(repo, rev)
4188 4185
4189 4186 if brev in repo._bookmarks:
4190 4187 bookmarks.setcurrent(repo, brev)
4191 4188
4192 4189 return ret
4193 4190
4194 4191 def verify(ui, repo):
4195 4192 """verify the integrity of the repository
4196 4193
4197 4194 Verify the integrity of the current repository.
4198 4195
4199 4196 This will perform an extensive check of the repository's
4200 4197 integrity, validating the hashes and checksums of each entry in
4201 4198 the changelog, manifest, and tracked files, as well as the
4202 4199 integrity of their crosslinks and indices.
4203 4200
4204 4201 Returns 0 on success, 1 if errors are encountered.
4205 4202 """
4206 4203 return hg.verify(repo)
4207 4204
4208 4205 def version_(ui):
4209 4206 """output version and copyright information"""
4210 4207 ui.write(_("Mercurial Distributed SCM (version %s)\n")
4211 4208 % util.version())
4212 4209 ui.status(_(
4213 4210 "(see http://mercurial.selenic.com for more information)\n"
4214 4211 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
4215 4212 "This is free software; see the source for copying conditions. "
4216 4213 "There is NO\nwarranty; "
4217 4214 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
4218 4215 ))
4219 4216
4220 4217 # Command options and aliases are listed here, alphabetically
4221 4218
4222 4219 globalopts = [
4223 4220 ('R', 'repository', '',
4224 4221 _('repository root directory or name of overlay bundle file'),
4225 4222 _('REPO')),
4226 4223 ('', 'cwd', '',
4227 4224 _('change working directory'), _('DIR')),
4228 4225 ('y', 'noninteractive', None,
4229 4226 _('do not prompt, assume \'yes\' for any required answers')),
4230 4227 ('q', 'quiet', None, _('suppress output')),
4231 4228 ('v', 'verbose', None, _('enable additional output')),
4232 4229 ('', 'config', [],
4233 4230 _('set/override config option (use \'section.name=value\')'),
4234 4231 _('CONFIG')),
4235 4232 ('', 'debug', None, _('enable debugging output')),
4236 4233 ('', 'debugger', None, _('start debugger')),
4237 4234 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
4238 4235 _('ENCODE')),
4239 4236 ('', 'encodingmode', encoding.encodingmode,
4240 4237 _('set the charset encoding mode'), _('MODE')),
4241 4238 ('', 'traceback', None, _('always print a traceback on exception')),
4242 4239 ('', 'time', None, _('time how long the command takes')),
4243 4240 ('', 'profile', None, _('print command execution profile')),
4244 4241 ('', 'version', None, _('output version information and exit')),
4245 4242 ('h', 'help', None, _('display help and exit')),
4246 4243 ]
4247 4244
4248 4245 dryrunopts = [('n', 'dry-run', None,
4249 4246 _('do not perform actions, just print output'))]
4250 4247
4251 4248 remoteopts = [
4252 4249 ('e', 'ssh', '',
4253 4250 _('specify ssh command to use'), _('CMD')),
4254 4251 ('', 'remotecmd', '',
4255 4252 _('specify hg command to run on the remote side'), _('CMD')),
4256 4253 ('', 'insecure', None,
4257 4254 _('do not verify server certificate (ignoring web.cacerts config)')),
4258 4255 ]
4259 4256
4260 4257 walkopts = [
4261 4258 ('I', 'include', [],
4262 4259 _('include names matching the given patterns'), _('PATTERN')),
4263 4260 ('X', 'exclude', [],
4264 4261 _('exclude names matching the given patterns'), _('PATTERN')),
4265 4262 ]
4266 4263
4267 4264 commitopts = [
4268 4265 ('m', 'message', '',
4269 4266 _('use text as commit message'), _('TEXT')),
4270 4267 ('l', 'logfile', '',
4271 4268 _('read commit message from file'), _('FILE')),
4272 4269 ]
4273 4270
4274 4271 commitopts2 = [
4275 4272 ('d', 'date', '',
4276 4273 _('record datecode as commit date'), _('DATE')),
4277 4274 ('u', 'user', '',
4278 4275 _('record the specified user as committer'), _('USER')),
4279 4276 ]
4280 4277
4281 4278 templateopts = [
4282 4279 ('', 'style', '',
4283 4280 _('display using template map file'), _('STYLE')),
4284 4281 ('', 'template', '',
4285 4282 _('display with template'), _('TEMPLATE')),
4286 4283 ]
4287 4284
4288 4285 logopts = [
4289 4286 ('p', 'patch', None, _('show patch')),
4290 4287 ('g', 'git', None, _('use git extended diff format')),
4291 4288 ('l', 'limit', '',
4292 4289 _('limit number of changes displayed'), _('NUM')),
4293 4290 ('M', 'no-merges', None, _('do not show merges')),
4294 4291 ('', 'stat', None, _('output diffstat-style summary of changes')),
4295 4292 ] + templateopts
4296 4293
4297 4294 diffopts = [
4298 4295 ('a', 'text', None, _('treat all files as text')),
4299 4296 ('g', 'git', None, _('use git extended diff format')),
4300 4297 ('', 'nodates', None, _('omit dates from diff headers'))
4301 4298 ]
4302 4299
4303 4300 diffopts2 = [
4304 4301 ('p', 'show-function', None, _('show which function each change is in')),
4305 4302 ('', 'reverse', None, _('produce a diff that undoes the changes')),
4306 4303 ('w', 'ignore-all-space', None,
4307 4304 _('ignore white space when comparing lines')),
4308 4305 ('b', 'ignore-space-change', None,
4309 4306 _('ignore changes in the amount of white space')),
4310 4307 ('B', 'ignore-blank-lines', None,
4311 4308 _('ignore changes whose lines are all blank')),
4312 4309 ('U', 'unified', '',
4313 4310 _('number of lines of context to show'), _('NUM')),
4314 4311 ('', 'stat', None, _('output diffstat-style summary of changes')),
4315 4312 ]
4316 4313
4317 4314 similarityopts = [
4318 4315 ('s', 'similarity', '',
4319 4316 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
4320 4317 ]
4321 4318
4322 4319 subrepoopts = [
4323 4320 ('S', 'subrepos', None,
4324 4321 _('recurse into subrepositories'))
4325 4322 ]
4326 4323
4327 4324 table = {
4328 4325 "^add": (add, walkopts + subrepoopts + dryrunopts,
4329 4326 _('[OPTION]... [FILE]...')),
4330 4327 "addremove":
4331 4328 (addremove, similarityopts + walkopts + dryrunopts,
4332 4329 _('[OPTION]... [FILE]...')),
4333 4330 "^annotate|blame":
4334 4331 (annotate,
4335 4332 [('r', 'rev', '',
4336 4333 _('annotate the specified revision'), _('REV')),
4337 4334 ('', 'follow', None,
4338 4335 _('follow copies/renames and list the filename (DEPRECATED)')),
4339 4336 ('', 'no-follow', None, _("don't follow copies and renames")),
4340 4337 ('a', 'text', None, _('treat all files as text')),
4341 4338 ('u', 'user', None, _('list the author (long with -v)')),
4342 4339 ('f', 'file', None, _('list the filename')),
4343 4340 ('d', 'date', None, _('list the date (short with -q)')),
4344 4341 ('n', 'number', None, _('list the revision number (default)')),
4345 4342 ('c', 'changeset', None, _('list the changeset')),
4346 4343 ('l', 'line-number', None,
4347 4344 _('show line number at the first appearance'))
4348 4345 ] + walkopts,
4349 4346 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
4350 4347 "archive":
4351 4348 (archive,
4352 4349 [('', 'no-decode', None, _('do not pass files through decoders')),
4353 4350 ('p', 'prefix', '',
4354 4351 _('directory prefix for files in archive'), _('PREFIX')),
4355 4352 ('r', 'rev', '',
4356 4353 _('revision to distribute'), _('REV')),
4357 4354 ('t', 'type', '',
4358 4355 _('type of distribution to create'), _('TYPE')),
4359 4356 ] + subrepoopts + walkopts,
4360 4357 _('[OPTION]... DEST')),
4361 4358 "backout":
4362 4359 (backout,
4363 4360 [('', 'merge', None,
4364 4361 _('merge with old dirstate parent after backout')),
4365 4362 ('', 'parent', '',
4366 4363 _('parent to choose when backing out merge'), _('REV')),
4367 4364 ('t', 'tool', '',
4368 4365 _('specify merge tool')),
4369 4366 ('r', 'rev', '',
4370 4367 _('revision to backout'), _('REV')),
4371 4368 ] + walkopts + commitopts + commitopts2,
4372 4369 _('[OPTION]... [-r] REV')),
4373 4370 "bisect":
4374 4371 (bisect,
4375 4372 [('r', 'reset', False, _('reset bisect state')),
4376 4373 ('g', 'good', False, _('mark changeset good')),
4377 4374 ('b', 'bad', False, _('mark changeset bad')),
4378 4375 ('s', 'skip', False, _('skip testing changeset')),
4379 4376 ('e', 'extend', False, _('extend the bisect range')),
4380 4377 ('c', 'command', '',
4381 4378 _('use command to check changeset state'), _('CMD')),
4382 4379 ('U', 'noupdate', False, _('do not update to target'))],
4383 4380 _("[-gbsr] [-U] [-c CMD] [REV]")),
4384 4381 "bookmarks":
4385 4382 (bookmark,
4386 4383 [('f', 'force', False, _('force')),
4387 4384 ('r', 'rev', '', _('revision'), _('REV')),
4388 4385 ('d', 'delete', False, _('delete a given bookmark')),
4389 4386 ('m', 'rename', '', _('rename a given bookmark'), _('NAME'))],
4390 4387 _('hg bookmarks [-f] [-d] [-m NAME] [-r REV] [NAME]')),
4391 4388 "branch":
4392 4389 (branch,
4393 4390 [('f', 'force', None,
4394 4391 _('set branch name even if it shadows an existing branch')),
4395 4392 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4396 4393 _('[-fC] [NAME]')),
4397 4394 "branches":
4398 4395 (branches,
4399 4396 [('a', 'active', False,
4400 4397 _('show only branches that have unmerged heads')),
4401 4398 ('c', 'closed', False,
4402 4399 _('show normal and closed branches'))],
4403 4400 _('[-ac]')),
4404 4401 "bundle":
4405 4402 (bundle,
4406 4403 [('f', 'force', None,
4407 4404 _('run even when the destination is unrelated')),
4408 4405 ('r', 'rev', [],
4409 4406 _('a changeset intended to be added to the destination'),
4410 4407 _('REV')),
4411 4408 ('b', 'branch', [],
4412 4409 _('a specific branch you would like to bundle'),
4413 4410 _('BRANCH')),
4414 4411 ('', 'base', [],
4415 4412 _('a base changeset assumed to be available at the destination'),
4416 4413 _('REV')),
4417 4414 ('a', 'all', None, _('bundle all changesets in the repository')),
4418 4415 ('t', 'type', 'bzip2',
4419 4416 _('bundle compression type to use'), _('TYPE')),
4420 4417 ] + remoteopts,
4421 4418 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4422 4419 "cat":
4423 4420 (cat,
4424 4421 [('o', 'output', '',
4425 4422 _('print output to file with formatted name'), _('FORMAT')),
4426 4423 ('r', 'rev', '',
4427 4424 _('print the given revision'), _('REV')),
4428 4425 ('', 'decode', None, _('apply any matching decode filter')),
4429 4426 ] + walkopts,
4430 4427 _('[OPTION]... FILE...')),
4431 4428 "^clone":
4432 4429 (clone,
4433 4430 [('U', 'noupdate', None,
4434 4431 _('the clone will include an empty working copy (only a repository)')),
4435 4432 ('u', 'updaterev', '',
4436 4433 _('revision, tag or branch to check out'), _('REV')),
4437 4434 ('r', 'rev', [],
4438 4435 _('include the specified changeset'), _('REV')),
4439 4436 ('b', 'branch', [],
4440 4437 _('clone only the specified branch'), _('BRANCH')),
4441 4438 ('', 'pull', None, _('use pull protocol to copy metadata')),
4442 4439 ('', 'uncompressed', None,
4443 4440 _('use uncompressed transfer (fast over LAN)')),
4444 4441 ] + remoteopts,
4445 4442 _('[OPTION]... SOURCE [DEST]')),
4446 4443 "^commit|ci":
4447 4444 (commit,
4448 4445 [('A', 'addremove', None,
4449 4446 _('mark new/missing files as added/removed before committing')),
4450 4447 ('', 'close-branch', None,
4451 4448 _('mark a branch as closed, hiding it from the branch list')),
4452 4449 ] + walkopts + commitopts + commitopts2,
4453 4450 _('[OPTION]... [FILE]...')),
4454 4451 "copy|cp":
4455 4452 (copy,
4456 4453 [('A', 'after', None, _('record a copy that has already occurred')),
4457 4454 ('f', 'force', None,
4458 4455 _('forcibly copy over an existing managed file')),
4459 4456 ] + walkopts + dryrunopts,
4460 4457 _('[OPTION]... [SOURCE]... DEST')),
4461 4458 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4462 4459 "debugbuilddag":
4463 4460 (debugbuilddag,
4464 4461 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4465 4462 ('a', 'appended-file', None, _('add single file all revs append to')),
4466 4463 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4467 4464 ('n', 'new-file', None, _('add new file at each rev')),
4468 4465 ],
4469 4466 _('[OPTION]... TEXT')),
4470 4467 "debugbundle":
4471 4468 (debugbundle,
4472 4469 [('a', 'all', None, _('show all details')),
4473 4470 ],
4474 4471 _('FILE')),
4475 4472 "debugcheckstate": (debugcheckstate, [], ''),
4476 4473 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4477 4474 "debugcomplete":
4478 4475 (debugcomplete,
4479 4476 [('o', 'options', None, _('show the command options'))],
4480 4477 _('[-o] CMD')),
4481 4478 "debugdag":
4482 4479 (debugdag,
4483 4480 [('t', 'tags', None, _('use tags as labels')),
4484 4481 ('b', 'branches', None, _('annotate with branch names')),
4485 4482 ('', 'dots', None, _('use dots for runs')),
4486 4483 ('s', 'spaces', None, _('separate elements by spaces')),
4487 4484 ],
4488 4485 _('[OPTION]... [FILE [REV]...]')),
4489 4486 "debugdate":
4490 4487 (debugdate,
4491 4488 [('e', 'extended', None, _('try extended date formats'))],
4492 4489 _('[-e] DATE [RANGE]')),
4493 4490 "debugdata": (debugdata, [], _('FILE REV')),
4494 4491 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4495 4492 "debuggetbundle":
4496 4493 (debuggetbundle,
4497 4494 [('H', 'head', [], _('id of head node'), _('ID')),
4498 4495 ('C', 'common', [], _('id of common node'), _('ID')),
4499 4496 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
4500 4497 ],
4501 4498 _('REPO FILE [-H|-C ID]...')),
4502 4499 "debugignore": (debugignore, [], ''),
4503 4500 "debugindex": (debugindex,
4504 4501 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
4505 4502 _('FILE')),
4506 4503 "debugindexdot": (debugindexdot, [], _('FILE')),
4507 4504 "debuginstall": (debuginstall, [], ''),
4508 4505 "debugknown": (debugknown, [], _('REPO ID...')),
4509 4506 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4510 4507 "debugrebuildstate":
4511 4508 (debugrebuildstate,
4512 4509 [('r', 'rev', '',
4513 4510 _('revision to rebuild to'), _('REV'))],
4514 4511 _('[-r REV] [REV]')),
4515 4512 "debugrename":
4516 4513 (debugrename,
4517 4514 [('r', 'rev', '',
4518 4515 _('revision to debug'), _('REV'))],
4519 4516 _('[-r REV] FILE')),
4520 4517 "debugrevspec":
4521 4518 (debugrevspec, [], ('REVSPEC')),
4522 4519 "debugsetparents":
4523 4520 (debugsetparents, [], _('REV1 [REV2]')),
4524 4521 "debugstate":
4525 4522 (debugstate,
4526 4523 [('', 'nodates', None, _('do not display the saved mtime')),
4527 4524 ('', 'datesort', None, _('sort by saved mtime'))],
4528 4525 _('[OPTION]...')),
4529 4526 "debugsub":
4530 4527 (debugsub,
4531 4528 [('r', 'rev', '',
4532 4529 _('revision to check'), _('REV'))],
4533 4530 _('[-r REV] [REV]')),
4534 4531 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4535 4532 "debugwireargs":
4536 4533 (debugwireargs,
4537 4534 [('', 'three', '', 'three'),
4538 4535 ('', 'four', '', 'four'),
4539 4536 ] + remoteopts,
4540 4537 _('REPO [OPTIONS]... [ONE [TWO]]')),
4541 4538 "^diff":
4542 4539 (diff,
4543 4540 [('r', 'rev', [],
4544 4541 _('revision'), _('REV')),
4545 4542 ('c', 'change', '',
4546 4543 _('change made by revision'), _('REV'))
4547 4544 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4548 4545 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4549 4546 "^export":
4550 4547 (export,
4551 4548 [('o', 'output', '',
4552 4549 _('print output to file with formatted name'), _('FORMAT')),
4553 4550 ('', 'switch-parent', None, _('diff against the second parent')),
4554 4551 ('r', 'rev', [],
4555 4552 _('revisions to export'), _('REV')),
4556 4553 ] + diffopts,
4557 4554 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4558 4555 "^forget":
4559 4556 (forget,
4560 4557 [] + walkopts,
4561 4558 _('[OPTION]... FILE...')),
4562 4559 "grep":
4563 4560 (grep,
4564 4561 [('0', 'print0', None, _('end fields with NUL')),
4565 4562 ('', 'all', None, _('print all revisions that match')),
4566 4563 ('f', 'follow', None,
4567 4564 _('follow changeset history,'
4568 4565 ' or file history across copies and renames')),
4569 4566 ('i', 'ignore-case', None, _('ignore case when matching')),
4570 4567 ('l', 'files-with-matches', None,
4571 4568 _('print only filenames and revisions that match')),
4572 4569 ('n', 'line-number', None, _('print matching line numbers')),
4573 4570 ('r', 'rev', [],
4574 4571 _('only search files changed within revision range'), _('REV')),
4575 4572 ('u', 'user', None, _('list the author (long with -v)')),
4576 4573 ('d', 'date', None, _('list the date (short with -q)')),
4577 4574 ] + walkopts,
4578 4575 _('[OPTION]... PATTERN [FILE]...')),
4579 4576 "heads":
4580 4577 (heads,
4581 4578 [('r', 'rev', '',
4582 4579 _('show only heads which are descendants of STARTREV'),
4583 4580 _('STARTREV')),
4584 4581 ('t', 'topo', False, _('show topological heads only')),
4585 4582 ('a', 'active', False,
4586 4583 _('show active branchheads only (DEPRECATED)')),
4587 4584 ('c', 'closed', False,
4588 4585 _('show normal and closed branch heads')),
4589 4586 ] + templateopts,
4590 4587 _('[-ac] [-r STARTREV] [REV]...')),
4591 4588 "help": (help_, [], _('[TOPIC]')),
4592 4589 "identify|id":
4593 4590 (identify,
4594 4591 [('r', 'rev', '',
4595 4592 _('identify the specified revision'), _('REV')),
4596 4593 ('n', 'num', None, _('show local revision number')),
4597 4594 ('i', 'id', None, _('show global revision id')),
4598 4595 ('b', 'branch', None, _('show branch')),
4599 4596 ('t', 'tags', None, _('show tags')),
4600 4597 ('B', 'bookmarks', None, _('show bookmarks'))],
4601 4598 _('[-nibtB] [-r REV] [SOURCE]')),
4602 4599 "import|patch":
4603 4600 (import_,
4604 4601 [('p', 'strip', 1,
4605 4602 _('directory strip option for patch. This has the same '
4606 4603 'meaning as the corresponding patch option'),
4607 4604 _('NUM')),
4608 4605 ('b', 'base', '',
4609 4606 _('base path'), _('PATH')),
4610 4607 ('f', 'force', None,
4611 4608 _('skip check for outstanding uncommitted changes')),
4612 4609 ('', 'no-commit', None,
4613 4610 _("don't commit, just update the working directory")),
4614 4611 ('', 'exact', None,
4615 4612 _('apply patch to the nodes from which it was generated')),
4616 4613 ('', 'import-branch', None,
4617 4614 _('use any branch information in patch (implied by --exact)'))] +
4618 4615 commitopts + commitopts2 + similarityopts,
4619 4616 _('[OPTION]... PATCH...')),
4620 4617 "incoming|in":
4621 4618 (incoming,
4622 4619 [('f', 'force', None,
4623 4620 _('run even if remote repository is unrelated')),
4624 4621 ('n', 'newest-first', None, _('show newest record first')),
4625 4622 ('', 'bundle', '',
4626 4623 _('file to store the bundles into'), _('FILE')),
4627 4624 ('r', 'rev', [],
4628 4625 _('a remote changeset intended to be added'), _('REV')),
4629 4626 ('B', 'bookmarks', False, _("compare bookmarks")),
4630 4627 ('b', 'branch', [],
4631 4628 _('a specific branch you would like to pull'), _('BRANCH')),
4632 4629 ] + logopts + remoteopts + subrepoopts,
4633 4630 _('[-p] [-n] [-M] [-f] [-r REV]...'
4634 4631 ' [--bundle FILENAME] [SOURCE]')),
4635 4632 "^init":
4636 4633 (init,
4637 4634 remoteopts,
4638 4635 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4639 4636 "locate":
4640 4637 (locate,
4641 4638 [('r', 'rev', '',
4642 4639 _('search the repository as it is in REV'), _('REV')),
4643 4640 ('0', 'print0', None,
4644 4641 _('end filenames with NUL, for use with xargs')),
4645 4642 ('f', 'fullpath', None,
4646 4643 _('print complete paths from the filesystem root')),
4647 4644 ] + walkopts,
4648 4645 _('[OPTION]... [PATTERN]...')),
4649 4646 "^log|history":
4650 4647 (log,
4651 4648 [('f', 'follow', None,
4652 4649 _('follow changeset history,'
4653 4650 ' or file history across copies and renames')),
4654 4651 ('', 'follow-first', None,
4655 4652 _('only follow the first parent of merge changesets')),
4656 4653 ('d', 'date', '',
4657 4654 _('show revisions matching date spec'), _('DATE')),
4658 4655 ('C', 'copies', None, _('show copied files')),
4659 4656 ('k', 'keyword', [],
4660 4657 _('do case-insensitive search for a given text'), _('TEXT')),
4661 4658 ('r', 'rev', [],
4662 4659 _('show the specified revision or range'), _('REV')),
4663 4660 ('', 'removed', None, _('include revisions where files were removed')),
4664 4661 ('m', 'only-merges', None, _('show only merges')),
4665 4662 ('u', 'user', [],
4666 4663 _('revisions committed by user'), _('USER')),
4667 4664 ('', 'only-branch', [],
4668 4665 _('show only changesets within the given named branch (DEPRECATED)'),
4669 4666 _('BRANCH')),
4670 4667 ('b', 'branch', [],
4671 4668 _('show changesets within the given named branch'), _('BRANCH')),
4672 4669 ('P', 'prune', [],
4673 4670 _('do not display revision or any of its ancestors'), _('REV')),
4674 4671 ] + logopts + walkopts,
4675 4672 _('[OPTION]... [FILE]')),
4676 4673 "manifest":
4677 4674 (manifest,
4678 4675 [('r', 'rev', '',
4679 4676 _('revision to display'), _('REV'))],
4680 4677 _('[-r REV]')),
4681 4678 "^merge":
4682 4679 (merge,
4683 4680 [('f', 'force', None, _('force a merge with outstanding changes')),
4684 4681 ('t', 'tool', '', _('specify merge tool')),
4685 4682 ('r', 'rev', '',
4686 4683 _('revision to merge'), _('REV')),
4687 4684 ('P', 'preview', None,
4688 4685 _('review revisions to merge (no merge is performed)'))],
4689 4686 _('[-P] [-f] [[-r] REV]')),
4690 4687 "outgoing|out":
4691 4688 (outgoing,
4692 4689 [('f', 'force', None,
4693 4690 _('run even when the destination is unrelated')),
4694 4691 ('r', 'rev', [],
4695 4692 _('a changeset intended to be included in the destination'),
4696 4693 _('REV')),
4697 4694 ('n', 'newest-first', None, _('show newest record first')),
4698 4695 ('B', 'bookmarks', False, _("compare bookmarks")),
4699 4696 ('b', 'branch', [],
4700 4697 _('a specific branch you would like to push'), _('BRANCH')),
4701 4698 ] + logopts + remoteopts + subrepoopts,
4702 4699 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4703 4700 "parents":
4704 4701 (parents,
4705 4702 [('r', 'rev', '',
4706 4703 _('show parents of the specified revision'), _('REV')),
4707 4704 ] + templateopts,
4708 4705 _('[-r REV] [FILE]')),
4709 4706 "paths": (paths, [], _('[NAME]')),
4710 4707 "^pull":
4711 4708 (pull,
4712 4709 [('u', 'update', None,
4713 4710 _('update to new branch head if changesets were pulled')),
4714 4711 ('f', 'force', None,
4715 4712 _('run even when remote repository is unrelated')),
4716 4713 ('r', 'rev', [],
4717 4714 _('a remote changeset intended to be added'), _('REV')),
4718 4715 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4719 4716 ('b', 'branch', [],
4720 4717 _('a specific branch you would like to pull'), _('BRANCH')),
4721 4718 ] + remoteopts,
4722 4719 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4723 4720 "^push":
4724 4721 (push,
4725 4722 [('f', 'force', None, _('force push')),
4726 4723 ('r', 'rev', [],
4727 4724 _('a changeset intended to be included in the destination'),
4728 4725 _('REV')),
4729 4726 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4730 4727 ('b', 'branch', [],
4731 4728 _('a specific branch you would like to push'), _('BRANCH')),
4732 4729 ('', 'new-branch', False, _('allow pushing a new branch')),
4733 4730 ] + remoteopts,
4734 4731 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4735 4732 "recover": (recover, []),
4736 4733 "^remove|rm":
4737 4734 (remove,
4738 4735 [('A', 'after', None, _('record delete for missing files')),
4739 4736 ('f', 'force', None,
4740 4737 _('remove (and delete) file even if added or modified')),
4741 4738 ] + walkopts,
4742 4739 _('[OPTION]... FILE...')),
4743 4740 "rename|move|mv":
4744 4741 (rename,
4745 4742 [('A', 'after', None, _('record a rename that has already occurred')),
4746 4743 ('f', 'force', None,
4747 4744 _('forcibly copy over an existing managed file')),
4748 4745 ] + walkopts + dryrunopts,
4749 4746 _('[OPTION]... SOURCE... DEST')),
4750 4747 "resolve":
4751 4748 (resolve,
4752 4749 [('a', 'all', None, _('select all unresolved files')),
4753 4750 ('l', 'list', None, _('list state of files needing merge')),
4754 4751 ('m', 'mark', None, _('mark files as resolved')),
4755 4752 ('u', 'unmark', None, _('mark files as unresolved')),
4756 4753 ('t', 'tool', '', _('specify merge tool')),
4757 4754 ('n', 'no-status', None, _('hide status prefix'))]
4758 4755 + walkopts,
4759 4756 _('[OPTION]... [FILE]...')),
4760 4757 "revert":
4761 4758 (revert,
4762 4759 [('a', 'all', None, _('revert all changes when no arguments given')),
4763 4760 ('d', 'date', '',
4764 4761 _('tipmost revision matching date'), _('DATE')),
4765 4762 ('r', 'rev', '',
4766 4763 _('revert to the specified revision'), _('REV')),
4767 4764 ('', 'no-backup', None, _('do not save backup copies of files')),
4768 4765 ] + walkopts + dryrunopts,
4769 4766 _('[OPTION]... [-r REV] [NAME]...')),
4770 4767 "rollback": (rollback, dryrunopts),
4771 4768 "root": (root, []),
4772 4769 "^serve":
4773 4770 (serve,
4774 4771 [('A', 'accesslog', '',
4775 4772 _('name of access log file to write to'), _('FILE')),
4776 4773 ('d', 'daemon', None, _('run server in background')),
4777 4774 ('', 'daemon-pipefds', '',
4778 4775 _('used internally by daemon mode'), _('NUM')),
4779 4776 ('E', 'errorlog', '',
4780 4777 _('name of error log file to write to'), _('FILE')),
4781 4778 # use string type, then we can check if something was passed
4782 4779 ('p', 'port', '',
4783 4780 _('port to listen on (default: 8000)'), _('PORT')),
4784 4781 ('a', 'address', '',
4785 4782 _('address to listen on (default: all interfaces)'), _('ADDR')),
4786 4783 ('', 'prefix', '',
4787 4784 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4788 4785 ('n', 'name', '',
4789 4786 _('name to show in web pages (default: working directory)'),
4790 4787 _('NAME')),
4791 4788 ('', 'web-conf', '',
4792 4789 _('name of the hgweb config file (see "hg help hgweb")'),
4793 4790 _('FILE')),
4794 4791 ('', 'webdir-conf', '',
4795 4792 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4796 4793 ('', 'pid-file', '',
4797 4794 _('name of file to write process ID to'), _('FILE')),
4798 4795 ('', 'stdio', None, _('for remote clients')),
4799 4796 ('t', 'templates', '',
4800 4797 _('web templates to use'), _('TEMPLATE')),
4801 4798 ('', 'style', '',
4802 4799 _('template style to use'), _('STYLE')),
4803 4800 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4804 4801 ('', 'certificate', '',
4805 4802 _('SSL certificate file'), _('FILE'))],
4806 4803 _('[OPTION]...')),
4807 4804 "showconfig|debugconfig":
4808 4805 (showconfig,
4809 4806 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4810 4807 _('[-u] [NAME]...')),
4811 4808 "^summary|sum":
4812 4809 (summary,
4813 4810 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4814 4811 "^status|st":
4815 4812 (status,
4816 4813 [('A', 'all', None, _('show status of all files')),
4817 4814 ('m', 'modified', None, _('show only modified files')),
4818 4815 ('a', 'added', None, _('show only added files')),
4819 4816 ('r', 'removed', None, _('show only removed files')),
4820 4817 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4821 4818 ('c', 'clean', None, _('show only files without changes')),
4822 4819 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4823 4820 ('i', 'ignored', None, _('show only ignored files')),
4824 4821 ('n', 'no-status', None, _('hide status prefix')),
4825 4822 ('C', 'copies', None, _('show source of copied files')),
4826 4823 ('0', 'print0', None,
4827 4824 _('end filenames with NUL, for use with xargs')),
4828 4825 ('', 'rev', [],
4829 4826 _('show difference from revision'), _('REV')),
4830 4827 ('', 'change', '',
4831 4828 _('list the changed files of a revision'), _('REV')),
4832 4829 ] + walkopts + subrepoopts,
4833 4830 _('[OPTION]... [FILE]...')),
4834 4831 "tag":
4835 4832 (tag,
4836 4833 [('f', 'force', None, _('force tag')),
4837 4834 ('l', 'local', None, _('make the tag local')),
4838 4835 ('r', 'rev', '',
4839 4836 _('revision to tag'), _('REV')),
4840 4837 ('', 'remove', None, _('remove a tag')),
4841 4838 # -l/--local is already there, commitopts cannot be used
4842 4839 ('e', 'edit', None, _('edit commit message')),
4843 4840 ('m', 'message', '',
4844 4841 _('use <text> as commit message'), _('TEXT')),
4845 4842 ] + commitopts2,
4846 4843 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4847 4844 "tags": (tags, [], ''),
4848 4845 "tip":
4849 4846 (tip,
4850 4847 [('p', 'patch', None, _('show patch')),
4851 4848 ('g', 'git', None, _('use git extended diff format')),
4852 4849 ] + templateopts,
4853 4850 _('[-p] [-g]')),
4854 4851 "unbundle":
4855 4852 (unbundle,
4856 4853 [('u', 'update', None,
4857 4854 _('update to new branch head if changesets were unbundled'))],
4858 4855 _('[-u] FILE...')),
4859 4856 "^update|up|checkout|co":
4860 4857 (update,
4861 4858 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4862 4859 ('c', 'check', None,
4863 4860 _('update across branches if no uncommitted changes')),
4864 4861 ('d', 'date', '',
4865 4862 _('tipmost revision matching date'), _('DATE')),
4866 4863 ('r', 'rev', '',
4867 4864 _('revision'), _('REV'))],
4868 4865 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4869 4866 "verify": (verify, []),
4870 4867 "version": (version_, []),
4871 4868 }
4872 4869
4873 4870 norepo = ("clone init version help debugcommands debugcomplete"
4874 4871 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
4875 4872 " debugknown debuggetbundle debugbundle")
4876 4873 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
4877 4874 " debugdata debugindex debugindexdot")
General Comments 0
You need to be logged in to leave comments. Login now