##// END OF EJS Templates
debugrevspec: add option to skip optimize() and evaluate unoptimized tree...
Yuya Nishihara -
r29923:429fd274 default
parent child Browse files
Show More
@@ -1,7348 +1,7351
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 __future__ import absolute_import
9 9
10 10 import difflib
11 11 import errno
12 12 import operator
13 13 import os
14 14 import random
15 15 import re
16 16 import shlex
17 17 import socket
18 18 import sys
19 19 import tempfile
20 20 import time
21 21
22 22 from .i18n import _
23 23 from .node import (
24 24 bin,
25 25 hex,
26 26 nullhex,
27 27 nullid,
28 28 nullrev,
29 29 short,
30 30 )
31 31 from . import (
32 32 archival,
33 33 bookmarks,
34 34 bundle2,
35 35 changegroup,
36 36 cmdutil,
37 37 commandserver,
38 38 context,
39 39 copies,
40 40 dagparser,
41 41 dagutil,
42 42 destutil,
43 43 discovery,
44 44 encoding,
45 45 error,
46 46 exchange,
47 47 extensions,
48 48 fileset,
49 49 formatter,
50 50 graphmod,
51 51 hbisect,
52 52 help,
53 53 hg,
54 54 hgweb,
55 55 localrepo,
56 56 lock as lockmod,
57 57 merge as mergemod,
58 58 minirst,
59 59 obsolete,
60 60 patch,
61 61 phases,
62 62 policy,
63 63 pvec,
64 64 repair,
65 65 revlog,
66 66 revset,
67 67 scmutil,
68 68 setdiscovery,
69 69 simplemerge,
70 70 sshserver,
71 71 streamclone,
72 72 templatekw,
73 73 templater,
74 74 treediscovery,
75 75 ui as uimod,
76 76 util,
77 77 )
78 78
79 79 release = lockmod.release
80 80
81 81 table = {}
82 82
83 83 command = cmdutil.command(table)
84 84
85 85 # label constants
86 86 # until 3.5, bookmarks.current was the advertised name, not
87 87 # bookmarks.active, so we must use both to avoid breaking old
88 88 # custom styles
89 89 activebookmarklabel = 'bookmarks.active bookmarks.current'
90 90
91 91 # common command options
92 92
93 93 globalopts = [
94 94 ('R', 'repository', '',
95 95 _('repository root directory or name of overlay bundle file'),
96 96 _('REPO')),
97 97 ('', 'cwd', '',
98 98 _('change working directory'), _('DIR')),
99 99 ('y', 'noninteractive', None,
100 100 _('do not prompt, automatically pick the first choice for all prompts')),
101 101 ('q', 'quiet', None, _('suppress output')),
102 102 ('v', 'verbose', None, _('enable additional output')),
103 103 ('', 'config', [],
104 104 _('set/override config option (use \'section.name=value\')'),
105 105 _('CONFIG')),
106 106 ('', 'debug', None, _('enable debugging output')),
107 107 ('', 'debugger', None, _('start debugger')),
108 108 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
109 109 _('ENCODE')),
110 110 ('', 'encodingmode', encoding.encodingmode,
111 111 _('set the charset encoding mode'), _('MODE')),
112 112 ('', 'traceback', None, _('always print a traceback on exception')),
113 113 ('', 'time', None, _('time how long the command takes')),
114 114 ('', 'profile', None, _('print command execution profile')),
115 115 ('', 'version', None, _('output version information and exit')),
116 116 ('h', 'help', None, _('display help and exit')),
117 117 ('', 'hidden', False, _('consider hidden changesets')),
118 118 ]
119 119
120 120 dryrunopts = [('n', 'dry-run', None,
121 121 _('do not perform actions, just print output'))]
122 122
123 123 remoteopts = [
124 124 ('e', 'ssh', '',
125 125 _('specify ssh command to use'), _('CMD')),
126 126 ('', 'remotecmd', '',
127 127 _('specify hg command to run on the remote side'), _('CMD')),
128 128 ('', 'insecure', None,
129 129 _('do not verify server certificate (ignoring web.cacerts config)')),
130 130 ]
131 131
132 132 walkopts = [
133 133 ('I', 'include', [],
134 134 _('include names matching the given patterns'), _('PATTERN')),
135 135 ('X', 'exclude', [],
136 136 _('exclude names matching the given patterns'), _('PATTERN')),
137 137 ]
138 138
139 139 commitopts = [
140 140 ('m', 'message', '',
141 141 _('use text as commit message'), _('TEXT')),
142 142 ('l', 'logfile', '',
143 143 _('read commit message from file'), _('FILE')),
144 144 ]
145 145
146 146 commitopts2 = [
147 147 ('d', 'date', '',
148 148 _('record the specified date as commit date'), _('DATE')),
149 149 ('u', 'user', '',
150 150 _('record the specified user as committer'), _('USER')),
151 151 ]
152 152
153 153 # hidden for now
154 154 formatteropts = [
155 155 ('T', 'template', '',
156 156 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
157 157 ]
158 158
159 159 templateopts = [
160 160 ('', 'style', '',
161 161 _('display using template map file (DEPRECATED)'), _('STYLE')),
162 162 ('T', 'template', '',
163 163 _('display with template'), _('TEMPLATE')),
164 164 ]
165 165
166 166 logopts = [
167 167 ('p', 'patch', None, _('show patch')),
168 168 ('g', 'git', None, _('use git extended diff format')),
169 169 ('l', 'limit', '',
170 170 _('limit number of changes displayed'), _('NUM')),
171 171 ('M', 'no-merges', None, _('do not show merges')),
172 172 ('', 'stat', None, _('output diffstat-style summary of changes')),
173 173 ('G', 'graph', None, _("show the revision DAG")),
174 174 ] + templateopts
175 175
176 176 diffopts = [
177 177 ('a', 'text', None, _('treat all files as text')),
178 178 ('g', 'git', None, _('use git extended diff format')),
179 179 ('', 'nodates', None, _('omit dates from diff headers'))
180 180 ]
181 181
182 182 diffwsopts = [
183 183 ('w', 'ignore-all-space', None,
184 184 _('ignore white space when comparing lines')),
185 185 ('b', 'ignore-space-change', None,
186 186 _('ignore changes in the amount of white space')),
187 187 ('B', 'ignore-blank-lines', None,
188 188 _('ignore changes whose lines are all blank')),
189 189 ]
190 190
191 191 diffopts2 = [
192 192 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
193 193 ('p', 'show-function', None, _('show which function each change is in')),
194 194 ('', 'reverse', None, _('produce a diff that undoes the changes')),
195 195 ] + diffwsopts + [
196 196 ('U', 'unified', '',
197 197 _('number of lines of context to show'), _('NUM')),
198 198 ('', 'stat', None, _('output diffstat-style summary of changes')),
199 199 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
200 200 ]
201 201
202 202 mergetoolopts = [
203 203 ('t', 'tool', '', _('specify merge tool')),
204 204 ]
205 205
206 206 similarityopts = [
207 207 ('s', 'similarity', '',
208 208 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
209 209 ]
210 210
211 211 subrepoopts = [
212 212 ('S', 'subrepos', None,
213 213 _('recurse into subrepositories'))
214 214 ]
215 215
216 216 debugrevlogopts = [
217 217 ('c', 'changelog', False, _('open changelog')),
218 218 ('m', 'manifest', False, _('open manifest')),
219 219 ('', 'dir', '', _('open directory manifest')),
220 220 ]
221 221
222 222 # Commands start here, listed alphabetically
223 223
224 224 @command('^add',
225 225 walkopts + subrepoopts + dryrunopts,
226 226 _('[OPTION]... [FILE]...'),
227 227 inferrepo=True)
228 228 def add(ui, repo, *pats, **opts):
229 229 """add the specified files on the next commit
230 230
231 231 Schedule files to be version controlled and added to the
232 232 repository.
233 233
234 234 The files will be added to the repository at the next commit. To
235 235 undo an add before that, see :hg:`forget`.
236 236
237 237 If no names are given, add all files to the repository (except
238 238 files matching ``.hgignore``).
239 239
240 240 .. container:: verbose
241 241
242 242 Examples:
243 243
244 244 - New (unknown) files are added
245 245 automatically by :hg:`add`::
246 246
247 247 $ ls
248 248 foo.c
249 249 $ hg status
250 250 ? foo.c
251 251 $ hg add
252 252 adding foo.c
253 253 $ hg status
254 254 A foo.c
255 255
256 256 - Specific files to be added can be specified::
257 257
258 258 $ ls
259 259 bar.c foo.c
260 260 $ hg status
261 261 ? bar.c
262 262 ? foo.c
263 263 $ hg add bar.c
264 264 $ hg status
265 265 A bar.c
266 266 ? foo.c
267 267
268 268 Returns 0 if all files are successfully added.
269 269 """
270 270
271 271 m = scmutil.match(repo[None], pats, opts)
272 272 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
273 273 return rejected and 1 or 0
274 274
275 275 @command('addremove',
276 276 similarityopts + subrepoopts + walkopts + dryrunopts,
277 277 _('[OPTION]... [FILE]...'),
278 278 inferrepo=True)
279 279 def addremove(ui, repo, *pats, **opts):
280 280 """add all new files, delete all missing files
281 281
282 282 Add all new files and remove all missing files from the
283 283 repository.
284 284
285 285 Unless names are given, new files are ignored if they match any of
286 286 the patterns in ``.hgignore``. As with add, these changes take
287 287 effect at the next commit.
288 288
289 289 Use the -s/--similarity option to detect renamed files. This
290 290 option takes a percentage between 0 (disabled) and 100 (files must
291 291 be identical) as its parameter. With a parameter greater than 0,
292 292 this compares every removed file with every added file and records
293 293 those similar enough as renames. Detecting renamed files this way
294 294 can be expensive. After using this option, :hg:`status -C` can be
295 295 used to check which files were identified as moved or renamed. If
296 296 not specified, -s/--similarity defaults to 100 and only renames of
297 297 identical files are detected.
298 298
299 299 .. container:: verbose
300 300
301 301 Examples:
302 302
303 303 - A number of files (bar.c and foo.c) are new,
304 304 while foobar.c has been removed (without using :hg:`remove`)
305 305 from the repository::
306 306
307 307 $ ls
308 308 bar.c foo.c
309 309 $ hg status
310 310 ! foobar.c
311 311 ? bar.c
312 312 ? foo.c
313 313 $ hg addremove
314 314 adding bar.c
315 315 adding foo.c
316 316 removing foobar.c
317 317 $ hg status
318 318 A bar.c
319 319 A foo.c
320 320 R foobar.c
321 321
322 322 - A file foobar.c was moved to foo.c without using :hg:`rename`.
323 323 Afterwards, it was edited slightly::
324 324
325 325 $ ls
326 326 foo.c
327 327 $ hg status
328 328 ! foobar.c
329 329 ? foo.c
330 330 $ hg addremove --similarity 90
331 331 removing foobar.c
332 332 adding foo.c
333 333 recording removal of foobar.c as rename to foo.c (94% similar)
334 334 $ hg status -C
335 335 A foo.c
336 336 foobar.c
337 337 R foobar.c
338 338
339 339 Returns 0 if all files are successfully added.
340 340 """
341 341 try:
342 342 sim = float(opts.get('similarity') or 100)
343 343 except ValueError:
344 344 raise error.Abort(_('similarity must be a number'))
345 345 if sim < 0 or sim > 100:
346 346 raise error.Abort(_('similarity must be between 0 and 100'))
347 347 matcher = scmutil.match(repo[None], pats, opts)
348 348 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
349 349
350 350 @command('^annotate|blame',
351 351 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
352 352 ('', 'follow', None,
353 353 _('follow copies/renames and list the filename (DEPRECATED)')),
354 354 ('', 'no-follow', None, _("don't follow copies and renames")),
355 355 ('a', 'text', None, _('treat all files as text')),
356 356 ('u', 'user', None, _('list the author (long with -v)')),
357 357 ('f', 'file', None, _('list the filename')),
358 358 ('d', 'date', None, _('list the date (short with -q)')),
359 359 ('n', 'number', None, _('list the revision number (default)')),
360 360 ('c', 'changeset', None, _('list the changeset')),
361 361 ('l', 'line-number', None, _('show line number at the first appearance'))
362 362 ] + diffwsopts + walkopts + formatteropts,
363 363 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
364 364 inferrepo=True)
365 365 def annotate(ui, repo, *pats, **opts):
366 366 """show changeset information by line for each file
367 367
368 368 List changes in files, showing the revision id responsible for
369 369 each line.
370 370
371 371 This command is useful for discovering when a change was made and
372 372 by whom.
373 373
374 374 If you include --file, --user, or --date, the revision number is
375 375 suppressed unless you also include --number.
376 376
377 377 Without the -a/--text option, annotate will avoid processing files
378 378 it detects as binary. With -a, annotate will annotate the file
379 379 anyway, although the results will probably be neither useful
380 380 nor desirable.
381 381
382 382 Returns 0 on success.
383 383 """
384 384 if not pats:
385 385 raise error.Abort(_('at least one filename or pattern is required'))
386 386
387 387 if opts.get('follow'):
388 388 # --follow is deprecated and now just an alias for -f/--file
389 389 # to mimic the behavior of Mercurial before version 1.5
390 390 opts['file'] = True
391 391
392 392 ctx = scmutil.revsingle(repo, opts.get('rev'))
393 393
394 394 fm = ui.formatter('annotate', opts)
395 395 if ui.quiet:
396 396 datefunc = util.shortdate
397 397 else:
398 398 datefunc = util.datestr
399 399 if ctx.rev() is None:
400 400 def hexfn(node):
401 401 if node is None:
402 402 return None
403 403 else:
404 404 return fm.hexfunc(node)
405 405 if opts.get('changeset'):
406 406 # omit "+" suffix which is appended to node hex
407 407 def formatrev(rev):
408 408 if rev is None:
409 409 return '%d' % ctx.p1().rev()
410 410 else:
411 411 return '%d' % rev
412 412 else:
413 413 def formatrev(rev):
414 414 if rev is None:
415 415 return '%d+' % ctx.p1().rev()
416 416 else:
417 417 return '%d ' % rev
418 418 def formathex(hex):
419 419 if hex is None:
420 420 return '%s+' % fm.hexfunc(ctx.p1().node())
421 421 else:
422 422 return '%s ' % hex
423 423 else:
424 424 hexfn = fm.hexfunc
425 425 formatrev = formathex = str
426 426
427 427 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
428 428 ('number', ' ', lambda x: x[0].rev(), formatrev),
429 429 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
430 430 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
431 431 ('file', ' ', lambda x: x[0].path(), str),
432 432 ('line_number', ':', lambda x: x[1], str),
433 433 ]
434 434 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
435 435
436 436 if (not opts.get('user') and not opts.get('changeset')
437 437 and not opts.get('date') and not opts.get('file')):
438 438 opts['number'] = True
439 439
440 440 linenumber = opts.get('line_number') is not None
441 441 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
442 442 raise error.Abort(_('at least one of -n/-c is required for -l'))
443 443
444 444 if fm:
445 445 def makefunc(get, fmt):
446 446 return get
447 447 else:
448 448 def makefunc(get, fmt):
449 449 return lambda x: fmt(get(x))
450 450 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
451 451 if opts.get(op)]
452 452 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
453 453 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
454 454 if opts.get(op))
455 455
456 456 def bad(x, y):
457 457 raise error.Abort("%s: %s" % (x, y))
458 458
459 459 m = scmutil.match(ctx, pats, opts, badfn=bad)
460 460
461 461 follow = not opts.get('no_follow')
462 462 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
463 463 whitespace=True)
464 464 for abs in ctx.walk(m):
465 465 fctx = ctx[abs]
466 466 if not opts.get('text') and util.binary(fctx.data()):
467 467 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
468 468 continue
469 469
470 470 lines = fctx.annotate(follow=follow, linenumber=linenumber,
471 471 diffopts=diffopts)
472 472 if not lines:
473 473 continue
474 474 formats = []
475 475 pieces = []
476 476
477 477 for f, sep in funcmap:
478 478 l = [f(n) for n, dummy in lines]
479 479 if fm:
480 480 formats.append(['%s' for x in l])
481 481 else:
482 482 sizes = [encoding.colwidth(x) for x in l]
483 483 ml = max(sizes)
484 484 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
485 485 pieces.append(l)
486 486
487 487 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
488 488 fm.startitem()
489 489 fm.write(fields, "".join(f), *p)
490 490 fm.write('line', ": %s", l[1])
491 491
492 492 if not lines[-1][1].endswith('\n'):
493 493 fm.plain('\n')
494 494
495 495 fm.end()
496 496
497 497 @command('archive',
498 498 [('', 'no-decode', None, _('do not pass files through decoders')),
499 499 ('p', 'prefix', '', _('directory prefix for files in archive'),
500 500 _('PREFIX')),
501 501 ('r', 'rev', '', _('revision to distribute'), _('REV')),
502 502 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
503 503 ] + subrepoopts + walkopts,
504 504 _('[OPTION]... DEST'))
505 505 def archive(ui, repo, dest, **opts):
506 506 '''create an unversioned archive of a repository revision
507 507
508 508 By default, the revision used is the parent of the working
509 509 directory; use -r/--rev to specify a different revision.
510 510
511 511 The archive type is automatically detected based on file
512 512 extension (to override, use -t/--type).
513 513
514 514 .. container:: verbose
515 515
516 516 Examples:
517 517
518 518 - create a zip file containing the 1.0 release::
519 519
520 520 hg archive -r 1.0 project-1.0.zip
521 521
522 522 - create a tarball excluding .hg files::
523 523
524 524 hg archive project.tar.gz -X ".hg*"
525 525
526 526 Valid types are:
527 527
528 528 :``files``: a directory full of files (default)
529 529 :``tar``: tar archive, uncompressed
530 530 :``tbz2``: tar archive, compressed using bzip2
531 531 :``tgz``: tar archive, compressed using gzip
532 532 :``uzip``: zip archive, uncompressed
533 533 :``zip``: zip archive, compressed using deflate
534 534
535 535 The exact name of the destination archive or directory is given
536 536 using a format string; see :hg:`help export` for details.
537 537
538 538 Each member added to an archive file has a directory prefix
539 539 prepended. Use -p/--prefix to specify a format string for the
540 540 prefix. The default is the basename of the archive, with suffixes
541 541 removed.
542 542
543 543 Returns 0 on success.
544 544 '''
545 545
546 546 ctx = scmutil.revsingle(repo, opts.get('rev'))
547 547 if not ctx:
548 548 raise error.Abort(_('no working directory: please specify a revision'))
549 549 node = ctx.node()
550 550 dest = cmdutil.makefilename(repo, dest, node)
551 551 if os.path.realpath(dest) == repo.root:
552 552 raise error.Abort(_('repository root cannot be destination'))
553 553
554 554 kind = opts.get('type') or archival.guesskind(dest) or 'files'
555 555 prefix = opts.get('prefix')
556 556
557 557 if dest == '-':
558 558 if kind == 'files':
559 559 raise error.Abort(_('cannot archive plain files to stdout'))
560 560 dest = cmdutil.makefileobj(repo, dest)
561 561 if not prefix:
562 562 prefix = os.path.basename(repo.root) + '-%h'
563 563
564 564 prefix = cmdutil.makefilename(repo, prefix, node)
565 565 matchfn = scmutil.match(ctx, [], opts)
566 566 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
567 567 matchfn, prefix, subrepos=opts.get('subrepos'))
568 568
569 569 @command('backout',
570 570 [('', 'merge', None, _('merge with old dirstate parent after backout')),
571 571 ('', 'commit', None,
572 572 _('commit if no conflicts were encountered (DEPRECATED)')),
573 573 ('', 'no-commit', None, _('do not commit')),
574 574 ('', 'parent', '',
575 575 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
576 576 ('r', 'rev', '', _('revision to backout'), _('REV')),
577 577 ('e', 'edit', False, _('invoke editor on commit messages')),
578 578 ] + mergetoolopts + walkopts + commitopts + commitopts2,
579 579 _('[OPTION]... [-r] REV'))
580 580 def backout(ui, repo, node=None, rev=None, **opts):
581 581 '''reverse effect of earlier changeset
582 582
583 583 Prepare a new changeset with the effect of REV undone in the
584 584 current working directory. If no conflicts were encountered,
585 585 it will be committed immediately.
586 586
587 587 If REV is the parent of the working directory, then this new changeset
588 588 is committed automatically (unless --no-commit is specified).
589 589
590 590 .. note::
591 591
592 592 :hg:`backout` cannot be used to fix either an unwanted or
593 593 incorrect merge.
594 594
595 595 .. container:: verbose
596 596
597 597 Examples:
598 598
599 599 - Reverse the effect of the parent of the working directory.
600 600 This backout will be committed immediately::
601 601
602 602 hg backout -r .
603 603
604 604 - Reverse the effect of previous bad revision 23::
605 605
606 606 hg backout -r 23
607 607
608 608 - Reverse the effect of previous bad revision 23 and
609 609 leave changes uncommitted::
610 610
611 611 hg backout -r 23 --no-commit
612 612 hg commit -m "Backout revision 23"
613 613
614 614 By default, the pending changeset will have one parent,
615 615 maintaining a linear history. With --merge, the pending
616 616 changeset will instead have two parents: the old parent of the
617 617 working directory and a new child of REV that simply undoes REV.
618 618
619 619 Before version 1.7, the behavior without --merge was equivalent
620 620 to specifying --merge followed by :hg:`update --clean .` to
621 621 cancel the merge and leave the child of REV as a head to be
622 622 merged separately.
623 623
624 624 See :hg:`help dates` for a list of formats valid for -d/--date.
625 625
626 626 See :hg:`help revert` for a way to restore files to the state
627 627 of another revision.
628 628
629 629 Returns 0 on success, 1 if nothing to backout or there are unresolved
630 630 files.
631 631 '''
632 632 wlock = lock = None
633 633 try:
634 634 wlock = repo.wlock()
635 635 lock = repo.lock()
636 636 return _dobackout(ui, repo, node, rev, **opts)
637 637 finally:
638 638 release(lock, wlock)
639 639
640 640 def _dobackout(ui, repo, node=None, rev=None, **opts):
641 641 if opts.get('commit') and opts.get('no_commit'):
642 642 raise error.Abort(_("cannot use --commit with --no-commit"))
643 643 if opts.get('merge') and opts.get('no_commit'):
644 644 raise error.Abort(_("cannot use --merge with --no-commit"))
645 645
646 646 if rev and node:
647 647 raise error.Abort(_("please specify just one revision"))
648 648
649 649 if not rev:
650 650 rev = node
651 651
652 652 if not rev:
653 653 raise error.Abort(_("please specify a revision to backout"))
654 654
655 655 date = opts.get('date')
656 656 if date:
657 657 opts['date'] = util.parsedate(date)
658 658
659 659 cmdutil.checkunfinished(repo)
660 660 cmdutil.bailifchanged(repo)
661 661 node = scmutil.revsingle(repo, rev).node()
662 662
663 663 op1, op2 = repo.dirstate.parents()
664 664 if not repo.changelog.isancestor(node, op1):
665 665 raise error.Abort(_('cannot backout change that is not an ancestor'))
666 666
667 667 p1, p2 = repo.changelog.parents(node)
668 668 if p1 == nullid:
669 669 raise error.Abort(_('cannot backout a change with no parents'))
670 670 if p2 != nullid:
671 671 if not opts.get('parent'):
672 672 raise error.Abort(_('cannot backout a merge changeset'))
673 673 p = repo.lookup(opts['parent'])
674 674 if p not in (p1, p2):
675 675 raise error.Abort(_('%s is not a parent of %s') %
676 676 (short(p), short(node)))
677 677 parent = p
678 678 else:
679 679 if opts.get('parent'):
680 680 raise error.Abort(_('cannot use --parent on non-merge changeset'))
681 681 parent = p1
682 682
683 683 # the backout should appear on the same branch
684 684 branch = repo.dirstate.branch()
685 685 bheads = repo.branchheads(branch)
686 686 rctx = scmutil.revsingle(repo, hex(parent))
687 687 if not opts.get('merge') and op1 != node:
688 688 dsguard = cmdutil.dirstateguard(repo, 'backout')
689 689 try:
690 690 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
691 691 'backout')
692 692 stats = mergemod.update(repo, parent, True, True, node, False)
693 693 repo.setparents(op1, op2)
694 694 dsguard.close()
695 695 hg._showstats(repo, stats)
696 696 if stats[3]:
697 697 repo.ui.status(_("use 'hg resolve' to retry unresolved "
698 698 "file merges\n"))
699 699 return 1
700 700 finally:
701 701 ui.setconfig('ui', 'forcemerge', '', '')
702 702 lockmod.release(dsguard)
703 703 else:
704 704 hg.clean(repo, node, show_stats=False)
705 705 repo.dirstate.setbranch(branch)
706 706 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
707 707
708 708 if opts.get('no_commit'):
709 709 msg = _("changeset %s backed out, "
710 710 "don't forget to commit.\n")
711 711 ui.status(msg % short(node))
712 712 return 0
713 713
714 714 def commitfunc(ui, repo, message, match, opts):
715 715 editform = 'backout'
716 716 e = cmdutil.getcommiteditor(editform=editform, **opts)
717 717 if not message:
718 718 # we don't translate commit messages
719 719 message = "Backed out changeset %s" % short(node)
720 720 e = cmdutil.getcommiteditor(edit=True, editform=editform)
721 721 return repo.commit(message, opts.get('user'), opts.get('date'),
722 722 match, editor=e)
723 723 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
724 724 if not newnode:
725 725 ui.status(_("nothing changed\n"))
726 726 return 1
727 727 cmdutil.commitstatus(repo, newnode, branch, bheads)
728 728
729 729 def nice(node):
730 730 return '%d:%s' % (repo.changelog.rev(node), short(node))
731 731 ui.status(_('changeset %s backs out changeset %s\n') %
732 732 (nice(repo.changelog.tip()), nice(node)))
733 733 if opts.get('merge') and op1 != node:
734 734 hg.clean(repo, op1, show_stats=False)
735 735 ui.status(_('merging with changeset %s\n')
736 736 % nice(repo.changelog.tip()))
737 737 try:
738 738 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
739 739 'backout')
740 740 return hg.merge(repo, hex(repo.changelog.tip()))
741 741 finally:
742 742 ui.setconfig('ui', 'forcemerge', '', '')
743 743 return 0
744 744
745 745 @command('bisect',
746 746 [('r', 'reset', False, _('reset bisect state')),
747 747 ('g', 'good', False, _('mark changeset good')),
748 748 ('b', 'bad', False, _('mark changeset bad')),
749 749 ('s', 'skip', False, _('skip testing changeset')),
750 750 ('e', 'extend', False, _('extend the bisect range')),
751 751 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
752 752 ('U', 'noupdate', False, _('do not update to target'))],
753 753 _("[-gbsr] [-U] [-c CMD] [REV]"))
754 754 def bisect(ui, repo, rev=None, extra=None, command=None,
755 755 reset=None, good=None, bad=None, skip=None, extend=None,
756 756 noupdate=None):
757 757 """subdivision search of changesets
758 758
759 759 This command helps to find changesets which introduce problems. To
760 760 use, mark the earliest changeset you know exhibits the problem as
761 761 bad, then mark the latest changeset which is free from the problem
762 762 as good. Bisect will update your working directory to a revision
763 763 for testing (unless the -U/--noupdate option is specified). Once
764 764 you have performed tests, mark the working directory as good or
765 765 bad, and bisect will either update to another candidate changeset
766 766 or announce that it has found the bad revision.
767 767
768 768 As a shortcut, you can also use the revision argument to mark a
769 769 revision as good or bad without checking it out first.
770 770
771 771 If you supply a command, it will be used for automatic bisection.
772 772 The environment variable HG_NODE will contain the ID of the
773 773 changeset being tested. The exit status of the command will be
774 774 used to mark revisions as good or bad: status 0 means good, 125
775 775 means to skip the revision, 127 (command not found) will abort the
776 776 bisection, and any other non-zero exit status means the revision
777 777 is bad.
778 778
779 779 .. container:: verbose
780 780
781 781 Some examples:
782 782
783 783 - start a bisection with known bad revision 34, and good revision 12::
784 784
785 785 hg bisect --bad 34
786 786 hg bisect --good 12
787 787
788 788 - advance the current bisection by marking current revision as good or
789 789 bad::
790 790
791 791 hg bisect --good
792 792 hg bisect --bad
793 793
794 794 - mark the current revision, or a known revision, to be skipped (e.g. if
795 795 that revision is not usable because of another issue)::
796 796
797 797 hg bisect --skip
798 798 hg bisect --skip 23
799 799
800 800 - skip all revisions that do not touch directories ``foo`` or ``bar``::
801 801
802 802 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
803 803
804 804 - forget the current bisection::
805 805
806 806 hg bisect --reset
807 807
808 808 - use 'make && make tests' to automatically find the first broken
809 809 revision::
810 810
811 811 hg bisect --reset
812 812 hg bisect --bad 34
813 813 hg bisect --good 12
814 814 hg bisect --command "make && make tests"
815 815
816 816 - see all changesets whose states are already known in the current
817 817 bisection::
818 818
819 819 hg log -r "bisect(pruned)"
820 820
821 821 - see the changeset currently being bisected (especially useful
822 822 if running with -U/--noupdate)::
823 823
824 824 hg log -r "bisect(current)"
825 825
826 826 - see all changesets that took part in the current bisection::
827 827
828 828 hg log -r "bisect(range)"
829 829
830 830 - you can even get a nice graph::
831 831
832 832 hg log --graph -r "bisect(range)"
833 833
834 834 See :hg:`help revsets` for more about the `bisect()` keyword.
835 835
836 836 Returns 0 on success.
837 837 """
838 838 def extendbisectrange(nodes, good):
839 839 # bisect is incomplete when it ends on a merge node and
840 840 # one of the parent was not checked.
841 841 parents = repo[nodes[0]].parents()
842 842 if len(parents) > 1:
843 843 if good:
844 844 side = state['bad']
845 845 else:
846 846 side = state['good']
847 847 num = len(set(i.node() for i in parents) & set(side))
848 848 if num == 1:
849 849 return parents[0].ancestor(parents[1])
850 850 return None
851 851
852 852 def print_result(nodes, good):
853 853 displayer = cmdutil.show_changeset(ui, repo, {})
854 854 if len(nodes) == 1:
855 855 # narrowed it down to a single revision
856 856 if good:
857 857 ui.write(_("The first good revision is:\n"))
858 858 else:
859 859 ui.write(_("The first bad revision is:\n"))
860 860 displayer.show(repo[nodes[0]])
861 861 extendnode = extendbisectrange(nodes, good)
862 862 if extendnode is not None:
863 863 ui.write(_('Not all ancestors of this changeset have been'
864 864 ' checked.\nUse bisect --extend to continue the '
865 865 'bisection from\nthe common ancestor, %s.\n')
866 866 % extendnode)
867 867 else:
868 868 # multiple possible revisions
869 869 if good:
870 870 ui.write(_("Due to skipped revisions, the first "
871 871 "good revision could be any of:\n"))
872 872 else:
873 873 ui.write(_("Due to skipped revisions, the first "
874 874 "bad revision could be any of:\n"))
875 875 for n in nodes:
876 876 displayer.show(repo[n])
877 877 displayer.close()
878 878
879 879 def check_state(state, interactive=True):
880 880 if not state['good'] or not state['bad']:
881 881 if (good or bad or skip or reset) and interactive:
882 882 return
883 883 if not state['good']:
884 884 raise error.Abort(_('cannot bisect (no known good revisions)'))
885 885 else:
886 886 raise error.Abort(_('cannot bisect (no known bad revisions)'))
887 887 return True
888 888
889 889 # backward compatibility
890 890 if rev in "good bad reset init".split():
891 891 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
892 892 cmd, rev, extra = rev, extra, None
893 893 if cmd == "good":
894 894 good = True
895 895 elif cmd == "bad":
896 896 bad = True
897 897 else:
898 898 reset = True
899 899 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
900 900 raise error.Abort(_('incompatible arguments'))
901 901
902 902 cmdutil.checkunfinished(repo)
903 903
904 904 if reset:
905 905 p = repo.join("bisect.state")
906 906 if os.path.exists(p):
907 907 os.unlink(p)
908 908 return
909 909
910 910 state = hbisect.load_state(repo)
911 911
912 912 if command:
913 913 changesets = 1
914 914 if noupdate:
915 915 try:
916 916 node = state['current'][0]
917 917 except LookupError:
918 918 raise error.Abort(_('current bisect revision is unknown - '
919 919 'start a new bisect to fix'))
920 920 else:
921 921 node, p2 = repo.dirstate.parents()
922 922 if p2 != nullid:
923 923 raise error.Abort(_('current bisect revision is a merge'))
924 924 try:
925 925 while changesets:
926 926 # update state
927 927 state['current'] = [node]
928 928 hbisect.save_state(repo, state)
929 929 status = ui.system(command, environ={'HG_NODE': hex(node)})
930 930 if status == 125:
931 931 transition = "skip"
932 932 elif status == 0:
933 933 transition = "good"
934 934 # status < 0 means process was killed
935 935 elif status == 127:
936 936 raise error.Abort(_("failed to execute %s") % command)
937 937 elif status < 0:
938 938 raise error.Abort(_("%s killed") % command)
939 939 else:
940 940 transition = "bad"
941 941 ctx = scmutil.revsingle(repo, rev, node)
942 942 rev = None # clear for future iterations
943 943 state[transition].append(ctx.node())
944 944 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
945 945 check_state(state, interactive=False)
946 946 # bisect
947 947 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
948 948 # update to next check
949 949 node = nodes[0]
950 950 if not noupdate:
951 951 cmdutil.bailifchanged(repo)
952 952 hg.clean(repo, node, show_stats=False)
953 953 finally:
954 954 state['current'] = [node]
955 955 hbisect.save_state(repo, state)
956 956 print_result(nodes, bgood)
957 957 return
958 958
959 959 # update state
960 960
961 961 if rev:
962 962 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
963 963 else:
964 964 nodes = [repo.lookup('.')]
965 965
966 966 if good or bad or skip:
967 967 if good:
968 968 state['good'] += nodes
969 969 elif bad:
970 970 state['bad'] += nodes
971 971 elif skip:
972 972 state['skip'] += nodes
973 973 hbisect.save_state(repo, state)
974 974
975 975 if not check_state(state):
976 976 return
977 977
978 978 # actually bisect
979 979 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
980 980 if extend:
981 981 if not changesets:
982 982 extendnode = extendbisectrange(nodes, good)
983 983 if extendnode is not None:
984 984 ui.write(_("Extending search to changeset %d:%s\n")
985 985 % (extendnode.rev(), extendnode))
986 986 state['current'] = [extendnode.node()]
987 987 hbisect.save_state(repo, state)
988 988 if noupdate:
989 989 return
990 990 cmdutil.bailifchanged(repo)
991 991 return hg.clean(repo, extendnode.node())
992 992 raise error.Abort(_("nothing to extend"))
993 993
994 994 if changesets == 0:
995 995 print_result(nodes, good)
996 996 else:
997 997 assert len(nodes) == 1 # only a single node can be tested next
998 998 node = nodes[0]
999 999 # compute the approximate number of remaining tests
1000 1000 tests, size = 0, 2
1001 1001 while size <= changesets:
1002 1002 tests, size = tests + 1, size * 2
1003 1003 rev = repo.changelog.rev(node)
1004 1004 ui.write(_("Testing changeset %d:%s "
1005 1005 "(%d changesets remaining, ~%d tests)\n")
1006 1006 % (rev, short(node), changesets, tests))
1007 1007 state['current'] = [node]
1008 1008 hbisect.save_state(repo, state)
1009 1009 if not noupdate:
1010 1010 cmdutil.bailifchanged(repo)
1011 1011 return hg.clean(repo, node)
1012 1012
1013 1013 @command('bookmarks|bookmark',
1014 1014 [('f', 'force', False, _('force')),
1015 1015 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
1016 1016 ('d', 'delete', False, _('delete a given bookmark')),
1017 1017 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
1018 1018 ('i', 'inactive', False, _('mark a bookmark inactive')),
1019 1019 ] + formatteropts,
1020 1020 _('hg bookmarks [OPTIONS]... [NAME]...'))
1021 1021 def bookmark(ui, repo, *names, **opts):
1022 1022 '''create a new bookmark or list existing bookmarks
1023 1023
1024 1024 Bookmarks are labels on changesets to help track lines of development.
1025 1025 Bookmarks are unversioned and can be moved, renamed and deleted.
1026 1026 Deleting or moving a bookmark has no effect on the associated changesets.
1027 1027
1028 1028 Creating or updating to a bookmark causes it to be marked as 'active'.
1029 1029 The active bookmark is indicated with a '*'.
1030 1030 When a commit is made, the active bookmark will advance to the new commit.
1031 1031 A plain :hg:`update` will also advance an active bookmark, if possible.
1032 1032 Updating away from a bookmark will cause it to be deactivated.
1033 1033
1034 1034 Bookmarks can be pushed and pulled between repositories (see
1035 1035 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1036 1036 diverged, a new 'divergent bookmark' of the form 'name@path' will
1037 1037 be created. Using :hg:`merge` will resolve the divergence.
1038 1038
1039 1039 A bookmark named '@' has the special property that :hg:`clone` will
1040 1040 check it out by default if it exists.
1041 1041
1042 1042 .. container:: verbose
1043 1043
1044 1044 Examples:
1045 1045
1046 1046 - create an active bookmark for a new line of development::
1047 1047
1048 1048 hg book new-feature
1049 1049
1050 1050 - create an inactive bookmark as a place marker::
1051 1051
1052 1052 hg book -i reviewed
1053 1053
1054 1054 - create an inactive bookmark on another changeset::
1055 1055
1056 1056 hg book -r .^ tested
1057 1057
1058 1058 - rename bookmark turkey to dinner::
1059 1059
1060 1060 hg book -m turkey dinner
1061 1061
1062 1062 - move the '@' bookmark from another branch::
1063 1063
1064 1064 hg book -f @
1065 1065 '''
1066 1066 force = opts.get('force')
1067 1067 rev = opts.get('rev')
1068 1068 delete = opts.get('delete')
1069 1069 rename = opts.get('rename')
1070 1070 inactive = opts.get('inactive')
1071 1071
1072 1072 def checkformat(mark):
1073 1073 mark = mark.strip()
1074 1074 if not mark:
1075 1075 raise error.Abort(_("bookmark names cannot consist entirely of "
1076 1076 "whitespace"))
1077 1077 scmutil.checknewlabel(repo, mark, 'bookmark')
1078 1078 return mark
1079 1079
1080 1080 def checkconflict(repo, mark, cur, force=False, target=None):
1081 1081 if mark in marks and not force:
1082 1082 if target:
1083 1083 if marks[mark] == target and target == cur:
1084 1084 # re-activating a bookmark
1085 1085 return
1086 1086 anc = repo.changelog.ancestors([repo[target].rev()])
1087 1087 bmctx = repo[marks[mark]]
1088 1088 divs = [repo[b].node() for b in marks
1089 1089 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1090 1090
1091 1091 # allow resolving a single divergent bookmark even if moving
1092 1092 # the bookmark across branches when a revision is specified
1093 1093 # that contains a divergent bookmark
1094 1094 if bmctx.rev() not in anc and target in divs:
1095 1095 bookmarks.deletedivergent(repo, [target], mark)
1096 1096 return
1097 1097
1098 1098 deletefrom = [b for b in divs
1099 1099 if repo[b].rev() in anc or b == target]
1100 1100 bookmarks.deletedivergent(repo, deletefrom, mark)
1101 1101 if bookmarks.validdest(repo, bmctx, repo[target]):
1102 1102 ui.status(_("moving bookmark '%s' forward from %s\n") %
1103 1103 (mark, short(bmctx.node())))
1104 1104 return
1105 1105 raise error.Abort(_("bookmark '%s' already exists "
1106 1106 "(use -f to force)") % mark)
1107 1107 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1108 1108 and not force):
1109 1109 raise error.Abort(
1110 1110 _("a bookmark cannot have the name of an existing branch"))
1111 1111
1112 1112 if delete and rename:
1113 1113 raise error.Abort(_("--delete and --rename are incompatible"))
1114 1114 if delete and rev:
1115 1115 raise error.Abort(_("--rev is incompatible with --delete"))
1116 1116 if rename and rev:
1117 1117 raise error.Abort(_("--rev is incompatible with --rename"))
1118 1118 if not names and (delete or rev):
1119 1119 raise error.Abort(_("bookmark name required"))
1120 1120
1121 1121 if delete or rename or names or inactive:
1122 1122 wlock = lock = tr = None
1123 1123 try:
1124 1124 wlock = repo.wlock()
1125 1125 lock = repo.lock()
1126 1126 cur = repo.changectx('.').node()
1127 1127 marks = repo._bookmarks
1128 1128 if delete:
1129 1129 tr = repo.transaction('bookmark')
1130 1130 for mark in names:
1131 1131 if mark not in marks:
1132 1132 raise error.Abort(_("bookmark '%s' does not exist") %
1133 1133 mark)
1134 1134 if mark == repo._activebookmark:
1135 1135 bookmarks.deactivate(repo)
1136 1136 del marks[mark]
1137 1137
1138 1138 elif rename:
1139 1139 tr = repo.transaction('bookmark')
1140 1140 if not names:
1141 1141 raise error.Abort(_("new bookmark name required"))
1142 1142 elif len(names) > 1:
1143 1143 raise error.Abort(_("only one new bookmark name allowed"))
1144 1144 mark = checkformat(names[0])
1145 1145 if rename not in marks:
1146 1146 raise error.Abort(_("bookmark '%s' does not exist")
1147 1147 % rename)
1148 1148 checkconflict(repo, mark, cur, force)
1149 1149 marks[mark] = marks[rename]
1150 1150 if repo._activebookmark == rename and not inactive:
1151 1151 bookmarks.activate(repo, mark)
1152 1152 del marks[rename]
1153 1153 elif names:
1154 1154 tr = repo.transaction('bookmark')
1155 1155 newact = None
1156 1156 for mark in names:
1157 1157 mark = checkformat(mark)
1158 1158 if newact is None:
1159 1159 newact = mark
1160 1160 if inactive and mark == repo._activebookmark:
1161 1161 bookmarks.deactivate(repo)
1162 1162 return
1163 1163 tgt = cur
1164 1164 if rev:
1165 1165 tgt = scmutil.revsingle(repo, rev).node()
1166 1166 checkconflict(repo, mark, cur, force, tgt)
1167 1167 marks[mark] = tgt
1168 1168 if not inactive and cur == marks[newact] and not rev:
1169 1169 bookmarks.activate(repo, newact)
1170 1170 elif cur != tgt and newact == repo._activebookmark:
1171 1171 bookmarks.deactivate(repo)
1172 1172 elif inactive:
1173 1173 if len(marks) == 0:
1174 1174 ui.status(_("no bookmarks set\n"))
1175 1175 elif not repo._activebookmark:
1176 1176 ui.status(_("no active bookmark\n"))
1177 1177 else:
1178 1178 bookmarks.deactivate(repo)
1179 1179 if tr is not None:
1180 1180 marks.recordchange(tr)
1181 1181 tr.close()
1182 1182 finally:
1183 1183 lockmod.release(tr, lock, wlock)
1184 1184 else: # show bookmarks
1185 1185 fm = ui.formatter('bookmarks', opts)
1186 1186 hexfn = fm.hexfunc
1187 1187 marks = repo._bookmarks
1188 1188 if len(marks) == 0 and not fm:
1189 1189 ui.status(_("no bookmarks set\n"))
1190 1190 for bmark, n in sorted(marks.iteritems()):
1191 1191 active = repo._activebookmark
1192 1192 if bmark == active:
1193 1193 prefix, label = '*', activebookmarklabel
1194 1194 else:
1195 1195 prefix, label = ' ', ''
1196 1196
1197 1197 fm.startitem()
1198 1198 if not ui.quiet:
1199 1199 fm.plain(' %s ' % prefix, label=label)
1200 1200 fm.write('bookmark', '%s', bmark, label=label)
1201 1201 pad = " " * (25 - encoding.colwidth(bmark))
1202 1202 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1203 1203 repo.changelog.rev(n), hexfn(n), label=label)
1204 1204 fm.data(active=(bmark == active))
1205 1205 fm.plain('\n')
1206 1206 fm.end()
1207 1207
1208 1208 @command('branch',
1209 1209 [('f', 'force', None,
1210 1210 _('set branch name even if it shadows an existing branch')),
1211 1211 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1212 1212 _('[-fC] [NAME]'))
1213 1213 def branch(ui, repo, label=None, **opts):
1214 1214 """set or show the current branch name
1215 1215
1216 1216 .. note::
1217 1217
1218 1218 Branch names are permanent and global. Use :hg:`bookmark` to create a
1219 1219 light-weight bookmark instead. See :hg:`help glossary` for more
1220 1220 information about named branches and bookmarks.
1221 1221
1222 1222 With no argument, show the current branch name. With one argument,
1223 1223 set the working directory branch name (the branch will not exist
1224 1224 in the repository until the next commit). Standard practice
1225 1225 recommends that primary development take place on the 'default'
1226 1226 branch.
1227 1227
1228 1228 Unless -f/--force is specified, branch will not let you set a
1229 1229 branch name that already exists.
1230 1230
1231 1231 Use -C/--clean to reset the working directory branch to that of
1232 1232 the parent of the working directory, negating a previous branch
1233 1233 change.
1234 1234
1235 1235 Use the command :hg:`update` to switch to an existing branch. Use
1236 1236 :hg:`commit --close-branch` to mark this branch head as closed.
1237 1237 When all heads of a branch are closed, the branch will be
1238 1238 considered closed.
1239 1239
1240 1240 Returns 0 on success.
1241 1241 """
1242 1242 if label:
1243 1243 label = label.strip()
1244 1244
1245 1245 if not opts.get('clean') and not label:
1246 1246 ui.write("%s\n" % repo.dirstate.branch())
1247 1247 return
1248 1248
1249 1249 with repo.wlock():
1250 1250 if opts.get('clean'):
1251 1251 label = repo[None].p1().branch()
1252 1252 repo.dirstate.setbranch(label)
1253 1253 ui.status(_('reset working directory to branch %s\n') % label)
1254 1254 elif label:
1255 1255 if not opts.get('force') and label in repo.branchmap():
1256 1256 if label not in [p.branch() for p in repo[None].parents()]:
1257 1257 raise error.Abort(_('a branch of the same name already'
1258 1258 ' exists'),
1259 1259 # i18n: "it" refers to an existing branch
1260 1260 hint=_("use 'hg update' to switch to it"))
1261 1261 scmutil.checknewlabel(repo, label, 'branch')
1262 1262 repo.dirstate.setbranch(label)
1263 1263 ui.status(_('marked working directory as branch %s\n') % label)
1264 1264
1265 1265 # find any open named branches aside from default
1266 1266 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1267 1267 if n != "default" and not c]
1268 1268 if not others:
1269 1269 ui.status(_('(branches are permanent and global, '
1270 1270 'did you want a bookmark?)\n'))
1271 1271
1272 1272 @command('branches',
1273 1273 [('a', 'active', False,
1274 1274 _('show only branches that have unmerged heads (DEPRECATED)')),
1275 1275 ('c', 'closed', False, _('show normal and closed branches')),
1276 1276 ] + formatteropts,
1277 1277 _('[-c]'))
1278 1278 def branches(ui, repo, active=False, closed=False, **opts):
1279 1279 """list repository named branches
1280 1280
1281 1281 List the repository's named branches, indicating which ones are
1282 1282 inactive. If -c/--closed is specified, also list branches which have
1283 1283 been marked closed (see :hg:`commit --close-branch`).
1284 1284
1285 1285 Use the command :hg:`update` to switch to an existing branch.
1286 1286
1287 1287 Returns 0.
1288 1288 """
1289 1289
1290 1290 fm = ui.formatter('branches', opts)
1291 1291 hexfunc = fm.hexfunc
1292 1292
1293 1293 allheads = set(repo.heads())
1294 1294 branches = []
1295 1295 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1296 1296 isactive = not isclosed and bool(set(heads) & allheads)
1297 1297 branches.append((tag, repo[tip], isactive, not isclosed))
1298 1298 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1299 1299 reverse=True)
1300 1300
1301 1301 for tag, ctx, isactive, isopen in branches:
1302 1302 if active and not isactive:
1303 1303 continue
1304 1304 if isactive:
1305 1305 label = 'branches.active'
1306 1306 notice = ''
1307 1307 elif not isopen:
1308 1308 if not closed:
1309 1309 continue
1310 1310 label = 'branches.closed'
1311 1311 notice = _(' (closed)')
1312 1312 else:
1313 1313 label = 'branches.inactive'
1314 1314 notice = _(' (inactive)')
1315 1315 current = (tag == repo.dirstate.branch())
1316 1316 if current:
1317 1317 label = 'branches.current'
1318 1318
1319 1319 fm.startitem()
1320 1320 fm.write('branch', '%s', tag, label=label)
1321 1321 rev = ctx.rev()
1322 1322 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1323 1323 fmt = ' ' * padsize + ' %d:%s'
1324 1324 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1325 1325 label='log.changeset changeset.%s' % ctx.phasestr())
1326 1326 fm.data(active=isactive, closed=not isopen, current=current)
1327 1327 if not ui.quiet:
1328 1328 fm.plain(notice)
1329 1329 fm.plain('\n')
1330 1330 fm.end()
1331 1331
1332 1332 @command('bundle',
1333 1333 [('f', 'force', None, _('run even when the destination is unrelated')),
1334 1334 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1335 1335 _('REV')),
1336 1336 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1337 1337 _('BRANCH')),
1338 1338 ('', 'base', [],
1339 1339 _('a base changeset assumed to be available at the destination'),
1340 1340 _('REV')),
1341 1341 ('a', 'all', None, _('bundle all changesets in the repository')),
1342 1342 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1343 1343 ] + remoteopts,
1344 1344 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1345 1345 def bundle(ui, repo, fname, dest=None, **opts):
1346 1346 """create a changegroup file
1347 1347
1348 1348 Generate a changegroup file collecting changesets to be added
1349 1349 to a repository.
1350 1350
1351 1351 To create a bundle containing all changesets, use -a/--all
1352 1352 (or --base null). Otherwise, hg assumes the destination will have
1353 1353 all the nodes you specify with --base parameters. Otherwise, hg
1354 1354 will assume the repository has all the nodes in destination, or
1355 1355 default-push/default if no destination is specified.
1356 1356
1357 1357 You can change bundle format with the -t/--type option. You can
1358 1358 specify a compression, a bundle version or both using a dash
1359 1359 (comp-version). The available compression methods are: none, bzip2,
1360 1360 and gzip (by default, bundles are compressed using bzip2). The
1361 1361 available formats are: v1, v2 (default to most suitable).
1362 1362
1363 1363 The bundle file can then be transferred using conventional means
1364 1364 and applied to another repository with the unbundle or pull
1365 1365 command. This is useful when direct push and pull are not
1366 1366 available or when exporting an entire repository is undesirable.
1367 1367
1368 1368 Applying bundles preserves all changeset contents including
1369 1369 permissions, copy/rename information, and revision history.
1370 1370
1371 1371 Returns 0 on success, 1 if no changes found.
1372 1372 """
1373 1373 revs = None
1374 1374 if 'rev' in opts:
1375 1375 revstrings = opts['rev']
1376 1376 revs = scmutil.revrange(repo, revstrings)
1377 1377 if revstrings and not revs:
1378 1378 raise error.Abort(_('no commits to bundle'))
1379 1379
1380 1380 bundletype = opts.get('type', 'bzip2').lower()
1381 1381 try:
1382 1382 bcompression, cgversion, params = exchange.parsebundlespec(
1383 1383 repo, bundletype, strict=False)
1384 1384 except error.UnsupportedBundleSpecification as e:
1385 1385 raise error.Abort(str(e),
1386 1386 hint=_('see "hg help bundle" for supported '
1387 1387 'values for --type'))
1388 1388
1389 1389 # Packed bundles are a pseudo bundle format for now.
1390 1390 if cgversion == 's1':
1391 1391 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1392 1392 hint=_("use 'hg debugcreatestreamclonebundle'"))
1393 1393
1394 1394 if opts.get('all'):
1395 1395 if dest:
1396 1396 raise error.Abort(_("--all is incompatible with specifying "
1397 1397 "a destination"))
1398 1398 if opts.get('base'):
1399 1399 ui.warn(_("ignoring --base because --all was specified\n"))
1400 1400 base = ['null']
1401 1401 else:
1402 1402 base = scmutil.revrange(repo, opts.get('base'))
1403 1403 # TODO: get desired bundlecaps from command line.
1404 1404 bundlecaps = None
1405 1405 if cgversion not in changegroup.supportedoutgoingversions(repo):
1406 1406 raise error.Abort(_("repository does not support bundle version %s") %
1407 1407 cgversion)
1408 1408
1409 1409 if base:
1410 1410 if dest:
1411 1411 raise error.Abort(_("--base is incompatible with specifying "
1412 1412 "a destination"))
1413 1413 common = [repo.lookup(rev) for rev in base]
1414 1414 heads = revs and map(repo.lookup, revs) or None
1415 1415 outgoing = discovery.outgoing(repo, common, heads)
1416 1416 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1417 1417 bundlecaps=bundlecaps,
1418 1418 version=cgversion)
1419 1419 outgoing = None
1420 1420 else:
1421 1421 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1422 1422 dest, branches = hg.parseurl(dest, opts.get('branch'))
1423 1423 other = hg.peer(repo, opts, dest)
1424 1424 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1425 1425 heads = revs and map(repo.lookup, revs) or revs
1426 1426 outgoing = discovery.findcommonoutgoing(repo, other,
1427 1427 onlyheads=heads,
1428 1428 force=opts.get('force'),
1429 1429 portable=True)
1430 1430 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1431 1431 bundlecaps, version=cgversion)
1432 1432 if not cg:
1433 1433 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1434 1434 return 1
1435 1435
1436 1436 if cgversion == '01': #bundle1
1437 1437 if bcompression is None:
1438 1438 bcompression = 'UN'
1439 1439 bversion = 'HG10' + bcompression
1440 1440 bcompression = None
1441 1441 else:
1442 1442 assert cgversion == '02'
1443 1443 bversion = 'HG20'
1444 1444
1445 1445 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression)
1446 1446
1447 1447 @command('cat',
1448 1448 [('o', 'output', '',
1449 1449 _('print output to file with formatted name'), _('FORMAT')),
1450 1450 ('r', 'rev', '', _('print the given revision'), _('REV')),
1451 1451 ('', 'decode', None, _('apply any matching decode filter')),
1452 1452 ] + walkopts,
1453 1453 _('[OPTION]... FILE...'),
1454 1454 inferrepo=True)
1455 1455 def cat(ui, repo, file1, *pats, **opts):
1456 1456 """output the current or given revision of files
1457 1457
1458 1458 Print the specified files as they were at the given revision. If
1459 1459 no revision is given, the parent of the working directory is used.
1460 1460
1461 1461 Output may be to a file, in which case the name of the file is
1462 1462 given using a format string. The formatting rules as follows:
1463 1463
1464 1464 :``%%``: literal "%" character
1465 1465 :``%s``: basename of file being printed
1466 1466 :``%d``: dirname of file being printed, or '.' if in repository root
1467 1467 :``%p``: root-relative path name of file being printed
1468 1468 :``%H``: changeset hash (40 hexadecimal digits)
1469 1469 :``%R``: changeset revision number
1470 1470 :``%h``: short-form changeset hash (12 hexadecimal digits)
1471 1471 :``%r``: zero-padded changeset revision number
1472 1472 :``%b``: basename of the exporting repository
1473 1473
1474 1474 Returns 0 on success.
1475 1475 """
1476 1476 ctx = scmutil.revsingle(repo, opts.get('rev'))
1477 1477 m = scmutil.match(ctx, (file1,) + pats, opts)
1478 1478
1479 1479 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1480 1480
1481 1481 @command('^clone',
1482 1482 [('U', 'noupdate', None, _('the clone will include an empty working '
1483 1483 'directory (only a repository)')),
1484 1484 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1485 1485 _('REV')),
1486 1486 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1487 1487 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1488 1488 ('', 'pull', None, _('use pull protocol to copy metadata')),
1489 1489 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1490 1490 ] + remoteopts,
1491 1491 _('[OPTION]... SOURCE [DEST]'),
1492 1492 norepo=True)
1493 1493 def clone(ui, source, dest=None, **opts):
1494 1494 """make a copy of an existing repository
1495 1495
1496 1496 Create a copy of an existing repository in a new directory.
1497 1497
1498 1498 If no destination directory name is specified, it defaults to the
1499 1499 basename of the source.
1500 1500
1501 1501 The location of the source is added to the new repository's
1502 1502 ``.hg/hgrc`` file, as the default to be used for future pulls.
1503 1503
1504 1504 Only local paths and ``ssh://`` URLs are supported as
1505 1505 destinations. For ``ssh://`` destinations, no working directory or
1506 1506 ``.hg/hgrc`` will be created on the remote side.
1507 1507
1508 1508 If the source repository has a bookmark called '@' set, that
1509 1509 revision will be checked out in the new repository by default.
1510 1510
1511 1511 To check out a particular version, use -u/--update, or
1512 1512 -U/--noupdate to create a clone with no working directory.
1513 1513
1514 1514 To pull only a subset of changesets, specify one or more revisions
1515 1515 identifiers with -r/--rev or branches with -b/--branch. The
1516 1516 resulting clone will contain only the specified changesets and
1517 1517 their ancestors. These options (or 'clone src#rev dest') imply
1518 1518 --pull, even for local source repositories.
1519 1519
1520 1520 .. note::
1521 1521
1522 1522 Specifying a tag will include the tagged changeset but not the
1523 1523 changeset containing the tag.
1524 1524
1525 1525 .. container:: verbose
1526 1526
1527 1527 For efficiency, hardlinks are used for cloning whenever the
1528 1528 source and destination are on the same filesystem (note this
1529 1529 applies only to the repository data, not to the working
1530 1530 directory). Some filesystems, such as AFS, implement hardlinking
1531 1531 incorrectly, but do not report errors. In these cases, use the
1532 1532 --pull option to avoid hardlinking.
1533 1533
1534 1534 In some cases, you can clone repositories and the working
1535 1535 directory using full hardlinks with ::
1536 1536
1537 1537 $ cp -al REPO REPOCLONE
1538 1538
1539 1539 This is the fastest way to clone, but it is not always safe. The
1540 1540 operation is not atomic (making sure REPO is not modified during
1541 1541 the operation is up to you) and you have to make sure your
1542 1542 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1543 1543 so). Also, this is not compatible with certain extensions that
1544 1544 place their metadata under the .hg directory, such as mq.
1545 1545
1546 1546 Mercurial will update the working directory to the first applicable
1547 1547 revision from this list:
1548 1548
1549 1549 a) null if -U or the source repository has no changesets
1550 1550 b) if -u . and the source repository is local, the first parent of
1551 1551 the source repository's working directory
1552 1552 c) the changeset specified with -u (if a branch name, this means the
1553 1553 latest head of that branch)
1554 1554 d) the changeset specified with -r
1555 1555 e) the tipmost head specified with -b
1556 1556 f) the tipmost head specified with the url#branch source syntax
1557 1557 g) the revision marked with the '@' bookmark, if present
1558 1558 h) the tipmost head of the default branch
1559 1559 i) tip
1560 1560
1561 1561 When cloning from servers that support it, Mercurial may fetch
1562 1562 pre-generated data from a server-advertised URL. When this is done,
1563 1563 hooks operating on incoming changesets and changegroups may fire twice,
1564 1564 once for the bundle fetched from the URL and another for any additional
1565 1565 data not fetched from this URL. In addition, if an error occurs, the
1566 1566 repository may be rolled back to a partial clone. This behavior may
1567 1567 change in future releases. See :hg:`help -e clonebundles` for more.
1568 1568
1569 1569 Examples:
1570 1570
1571 1571 - clone a remote repository to a new directory named hg/::
1572 1572
1573 1573 hg clone http://selenic.com/hg
1574 1574
1575 1575 - create a lightweight local clone::
1576 1576
1577 1577 hg clone project/ project-feature/
1578 1578
1579 1579 - clone from an absolute path on an ssh server (note double-slash)::
1580 1580
1581 1581 hg clone ssh://user@server//home/projects/alpha/
1582 1582
1583 1583 - do a high-speed clone over a LAN while checking out a
1584 1584 specified version::
1585 1585
1586 1586 hg clone --uncompressed http://server/repo -u 1.5
1587 1587
1588 1588 - create a repository without changesets after a particular revision::
1589 1589
1590 1590 hg clone -r 04e544 experimental/ good/
1591 1591
1592 1592 - clone (and track) a particular named branch::
1593 1593
1594 1594 hg clone http://selenic.com/hg#stable
1595 1595
1596 1596 See :hg:`help urls` for details on specifying URLs.
1597 1597
1598 1598 Returns 0 on success.
1599 1599 """
1600 1600 if opts.get('noupdate') and opts.get('updaterev'):
1601 1601 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1602 1602
1603 1603 r = hg.clone(ui, opts, source, dest,
1604 1604 pull=opts.get('pull'),
1605 1605 stream=opts.get('uncompressed'),
1606 1606 rev=opts.get('rev'),
1607 1607 update=opts.get('updaterev') or not opts.get('noupdate'),
1608 1608 branch=opts.get('branch'),
1609 1609 shareopts=opts.get('shareopts'))
1610 1610
1611 1611 return r is None
1612 1612
1613 1613 @command('^commit|ci',
1614 1614 [('A', 'addremove', None,
1615 1615 _('mark new/missing files as added/removed before committing')),
1616 1616 ('', 'close-branch', None,
1617 1617 _('mark a branch head as closed')),
1618 1618 ('', 'amend', None, _('amend the parent of the working directory')),
1619 1619 ('s', 'secret', None, _('use the secret phase for committing')),
1620 1620 ('e', 'edit', None, _('invoke editor on commit messages')),
1621 1621 ('i', 'interactive', None, _('use interactive mode')),
1622 1622 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1623 1623 _('[OPTION]... [FILE]...'),
1624 1624 inferrepo=True)
1625 1625 def commit(ui, repo, *pats, **opts):
1626 1626 """commit the specified files or all outstanding changes
1627 1627
1628 1628 Commit changes to the given files into the repository. Unlike a
1629 1629 centralized SCM, this operation is a local operation. See
1630 1630 :hg:`push` for a way to actively distribute your changes.
1631 1631
1632 1632 If a list of files is omitted, all changes reported by :hg:`status`
1633 1633 will be committed.
1634 1634
1635 1635 If you are committing the result of a merge, do not provide any
1636 1636 filenames or -I/-X filters.
1637 1637
1638 1638 If no commit message is specified, Mercurial starts your
1639 1639 configured editor where you can enter a message. In case your
1640 1640 commit fails, you will find a backup of your message in
1641 1641 ``.hg/last-message.txt``.
1642 1642
1643 1643 The --close-branch flag can be used to mark the current branch
1644 1644 head closed. When all heads of a branch are closed, the branch
1645 1645 will be considered closed and no longer listed.
1646 1646
1647 1647 The --amend flag can be used to amend the parent of the
1648 1648 working directory with a new commit that contains the changes
1649 1649 in the parent in addition to those currently reported by :hg:`status`,
1650 1650 if there are any. The old commit is stored in a backup bundle in
1651 1651 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1652 1652 on how to restore it).
1653 1653
1654 1654 Message, user and date are taken from the amended commit unless
1655 1655 specified. When a message isn't specified on the command line,
1656 1656 the editor will open with the message of the amended commit.
1657 1657
1658 1658 It is not possible to amend public changesets (see :hg:`help phases`)
1659 1659 or changesets that have children.
1660 1660
1661 1661 See :hg:`help dates` for a list of formats valid for -d/--date.
1662 1662
1663 1663 Returns 0 on success, 1 if nothing changed.
1664 1664
1665 1665 .. container:: verbose
1666 1666
1667 1667 Examples:
1668 1668
1669 1669 - commit all files ending in .py::
1670 1670
1671 1671 hg commit --include "set:**.py"
1672 1672
1673 1673 - commit all non-binary files::
1674 1674
1675 1675 hg commit --exclude "set:binary()"
1676 1676
1677 1677 - amend the current commit and set the date to now::
1678 1678
1679 1679 hg commit --amend --date now
1680 1680 """
1681 1681 wlock = lock = None
1682 1682 try:
1683 1683 wlock = repo.wlock()
1684 1684 lock = repo.lock()
1685 1685 return _docommit(ui, repo, *pats, **opts)
1686 1686 finally:
1687 1687 release(lock, wlock)
1688 1688
1689 1689 def _docommit(ui, repo, *pats, **opts):
1690 1690 if opts.get('interactive'):
1691 1691 opts.pop('interactive')
1692 1692 cmdutil.dorecord(ui, repo, commit, None, False,
1693 1693 cmdutil.recordfilter, *pats, **opts)
1694 1694 return
1695 1695
1696 1696 if opts.get('subrepos'):
1697 1697 if opts.get('amend'):
1698 1698 raise error.Abort(_('cannot amend with --subrepos'))
1699 1699 # Let --subrepos on the command line override config setting.
1700 1700 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1701 1701
1702 1702 cmdutil.checkunfinished(repo, commit=True)
1703 1703
1704 1704 branch = repo[None].branch()
1705 1705 bheads = repo.branchheads(branch)
1706 1706
1707 1707 extra = {}
1708 1708 if opts.get('close_branch'):
1709 1709 extra['close'] = 1
1710 1710
1711 1711 if not bheads:
1712 1712 raise error.Abort(_('can only close branch heads'))
1713 1713 elif opts.get('amend'):
1714 1714 if repo[None].parents()[0].p1().branch() != branch and \
1715 1715 repo[None].parents()[0].p2().branch() != branch:
1716 1716 raise error.Abort(_('can only close branch heads'))
1717 1717
1718 1718 if opts.get('amend'):
1719 1719 if ui.configbool('ui', 'commitsubrepos'):
1720 1720 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1721 1721
1722 1722 old = repo['.']
1723 1723 if not old.mutable():
1724 1724 raise error.Abort(_('cannot amend public changesets'))
1725 1725 if len(repo[None].parents()) > 1:
1726 1726 raise error.Abort(_('cannot amend while merging'))
1727 1727 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1728 1728 if not allowunstable and old.children():
1729 1729 raise error.Abort(_('cannot amend changeset with children'))
1730 1730
1731 1731 # Currently histedit gets confused if an amend happens while histedit
1732 1732 # is in progress. Since we have a checkunfinished command, we are
1733 1733 # temporarily honoring it.
1734 1734 #
1735 1735 # Note: eventually this guard will be removed. Please do not expect
1736 1736 # this behavior to remain.
1737 1737 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1738 1738 cmdutil.checkunfinished(repo)
1739 1739
1740 1740 # commitfunc is used only for temporary amend commit by cmdutil.amend
1741 1741 def commitfunc(ui, repo, message, match, opts):
1742 1742 return repo.commit(message,
1743 1743 opts.get('user') or old.user(),
1744 1744 opts.get('date') or old.date(),
1745 1745 match,
1746 1746 extra=extra)
1747 1747
1748 1748 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1749 1749 if node == old.node():
1750 1750 ui.status(_("nothing changed\n"))
1751 1751 return 1
1752 1752 else:
1753 1753 def commitfunc(ui, repo, message, match, opts):
1754 1754 backup = ui.backupconfig('phases', 'new-commit')
1755 1755 baseui = repo.baseui
1756 1756 basebackup = baseui.backupconfig('phases', 'new-commit')
1757 1757 try:
1758 1758 if opts.get('secret'):
1759 1759 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1760 1760 # Propagate to subrepos
1761 1761 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1762 1762
1763 1763 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1764 1764 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1765 1765 return repo.commit(message, opts.get('user'), opts.get('date'),
1766 1766 match,
1767 1767 editor=editor,
1768 1768 extra=extra)
1769 1769 finally:
1770 1770 ui.restoreconfig(backup)
1771 1771 repo.baseui.restoreconfig(basebackup)
1772 1772
1773 1773
1774 1774 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1775 1775
1776 1776 if not node:
1777 1777 stat = cmdutil.postcommitstatus(repo, pats, opts)
1778 1778 if stat[3]:
1779 1779 ui.status(_("nothing changed (%d missing files, see "
1780 1780 "'hg status')\n") % len(stat[3]))
1781 1781 else:
1782 1782 ui.status(_("nothing changed\n"))
1783 1783 return 1
1784 1784
1785 1785 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1786 1786
1787 1787 @command('config|showconfig|debugconfig',
1788 1788 [('u', 'untrusted', None, _('show untrusted configuration options')),
1789 1789 ('e', 'edit', None, _('edit user config')),
1790 1790 ('l', 'local', None, _('edit repository config')),
1791 1791 ('g', 'global', None, _('edit global config'))],
1792 1792 _('[-u] [NAME]...'),
1793 1793 optionalrepo=True)
1794 1794 def config(ui, repo, *values, **opts):
1795 1795 """show combined config settings from all hgrc files
1796 1796
1797 1797 With no arguments, print names and values of all config items.
1798 1798
1799 1799 With one argument of the form section.name, print just the value
1800 1800 of that config item.
1801 1801
1802 1802 With multiple arguments, print names and values of all config
1803 1803 items with matching section names.
1804 1804
1805 1805 With --edit, start an editor on the user-level config file. With
1806 1806 --global, edit the system-wide config file. With --local, edit the
1807 1807 repository-level config file.
1808 1808
1809 1809 With --debug, the source (filename and line number) is printed
1810 1810 for each config item.
1811 1811
1812 1812 See :hg:`help config` for more information about config files.
1813 1813
1814 1814 Returns 0 on success, 1 if NAME does not exist.
1815 1815
1816 1816 """
1817 1817
1818 1818 if opts.get('edit') or opts.get('local') or opts.get('global'):
1819 1819 if opts.get('local') and opts.get('global'):
1820 1820 raise error.Abort(_("can't use --local and --global together"))
1821 1821
1822 1822 if opts.get('local'):
1823 1823 if not repo:
1824 1824 raise error.Abort(_("can't use --local outside a repository"))
1825 1825 paths = [repo.join('hgrc')]
1826 1826 elif opts.get('global'):
1827 1827 paths = scmutil.systemrcpath()
1828 1828 else:
1829 1829 paths = scmutil.userrcpath()
1830 1830
1831 1831 for f in paths:
1832 1832 if os.path.exists(f):
1833 1833 break
1834 1834 else:
1835 1835 if opts.get('global'):
1836 1836 samplehgrc = uimod.samplehgrcs['global']
1837 1837 elif opts.get('local'):
1838 1838 samplehgrc = uimod.samplehgrcs['local']
1839 1839 else:
1840 1840 samplehgrc = uimod.samplehgrcs['user']
1841 1841
1842 1842 f = paths[0]
1843 1843 fp = open(f, "w")
1844 1844 fp.write(samplehgrc)
1845 1845 fp.close()
1846 1846
1847 1847 editor = ui.geteditor()
1848 1848 ui.system("%s \"%s\"" % (editor, f),
1849 1849 onerr=error.Abort, errprefix=_("edit failed"))
1850 1850 return
1851 1851
1852 1852 for f in scmutil.rcpath():
1853 1853 ui.debug('read config from: %s\n' % f)
1854 1854 untrusted = bool(opts.get('untrusted'))
1855 1855 if values:
1856 1856 sections = [v for v in values if '.' not in v]
1857 1857 items = [v for v in values if '.' in v]
1858 1858 if len(items) > 1 or items and sections:
1859 1859 raise error.Abort(_('only one config item permitted'))
1860 1860 matched = False
1861 1861 for section, name, value in ui.walkconfig(untrusted=untrusted):
1862 1862 value = str(value).replace('\n', '\\n')
1863 1863 sectname = section + '.' + name
1864 1864 if values:
1865 1865 for v in values:
1866 1866 if v == section:
1867 1867 ui.debug('%s: ' %
1868 1868 ui.configsource(section, name, untrusted))
1869 1869 ui.write('%s=%s\n' % (sectname, value))
1870 1870 matched = True
1871 1871 elif v == sectname:
1872 1872 ui.debug('%s: ' %
1873 1873 ui.configsource(section, name, untrusted))
1874 1874 ui.write(value, '\n')
1875 1875 matched = True
1876 1876 else:
1877 1877 ui.debug('%s: ' %
1878 1878 ui.configsource(section, name, untrusted))
1879 1879 ui.write('%s=%s\n' % (sectname, value))
1880 1880 matched = True
1881 1881 if matched:
1882 1882 return 0
1883 1883 return 1
1884 1884
1885 1885 @command('copy|cp',
1886 1886 [('A', 'after', None, _('record a copy that has already occurred')),
1887 1887 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1888 1888 ] + walkopts + dryrunopts,
1889 1889 _('[OPTION]... [SOURCE]... DEST'))
1890 1890 def copy(ui, repo, *pats, **opts):
1891 1891 """mark files as copied for the next commit
1892 1892
1893 1893 Mark dest as having copies of source files. If dest is a
1894 1894 directory, copies are put in that directory. If dest is a file,
1895 1895 the source must be a single file.
1896 1896
1897 1897 By default, this command copies the contents of files as they
1898 1898 exist in the working directory. If invoked with -A/--after, the
1899 1899 operation is recorded, but no copying is performed.
1900 1900
1901 1901 This command takes effect with the next commit. To undo a copy
1902 1902 before that, see :hg:`revert`.
1903 1903
1904 1904 Returns 0 on success, 1 if errors are encountered.
1905 1905 """
1906 1906 with repo.wlock(False):
1907 1907 return cmdutil.copy(ui, repo, pats, opts)
1908 1908
1909 1909 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1910 1910 def debugancestor(ui, repo, *args):
1911 1911 """find the ancestor revision of two revisions in a given index"""
1912 1912 if len(args) == 3:
1913 1913 index, rev1, rev2 = args
1914 1914 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1915 1915 lookup = r.lookup
1916 1916 elif len(args) == 2:
1917 1917 if not repo:
1918 1918 raise error.Abort(_("there is no Mercurial repository here "
1919 1919 "(.hg not found)"))
1920 1920 rev1, rev2 = args
1921 1921 r = repo.changelog
1922 1922 lookup = repo.lookup
1923 1923 else:
1924 1924 raise error.Abort(_('either two or three arguments required'))
1925 1925 a = r.ancestor(lookup(rev1), lookup(rev2))
1926 1926 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1927 1927
1928 1928 @command('debugbuilddag',
1929 1929 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1930 1930 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1931 1931 ('n', 'new-file', None, _('add new file at each rev'))],
1932 1932 _('[OPTION]... [TEXT]'))
1933 1933 def debugbuilddag(ui, repo, text=None,
1934 1934 mergeable_file=False,
1935 1935 overwritten_file=False,
1936 1936 new_file=False):
1937 1937 """builds a repo with a given DAG from scratch in the current empty repo
1938 1938
1939 1939 The description of the DAG is read from stdin if not given on the
1940 1940 command line.
1941 1941
1942 1942 Elements:
1943 1943
1944 1944 - "+n" is a linear run of n nodes based on the current default parent
1945 1945 - "." is a single node based on the current default parent
1946 1946 - "$" resets the default parent to null (implied at the start);
1947 1947 otherwise the default parent is always the last node created
1948 1948 - "<p" sets the default parent to the backref p
1949 1949 - "*p" is a fork at parent p, which is a backref
1950 1950 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1951 1951 - "/p2" is a merge of the preceding node and p2
1952 1952 - ":tag" defines a local tag for the preceding node
1953 1953 - "@branch" sets the named branch for subsequent nodes
1954 1954 - "#...\\n" is a comment up to the end of the line
1955 1955
1956 1956 Whitespace between the above elements is ignored.
1957 1957
1958 1958 A backref is either
1959 1959
1960 1960 - a number n, which references the node curr-n, where curr is the current
1961 1961 node, or
1962 1962 - the name of a local tag you placed earlier using ":tag", or
1963 1963 - empty to denote the default parent.
1964 1964
1965 1965 All string valued-elements are either strictly alphanumeric, or must
1966 1966 be enclosed in double quotes ("..."), with "\\" as escape character.
1967 1967 """
1968 1968
1969 1969 if text is None:
1970 1970 ui.status(_("reading DAG from stdin\n"))
1971 1971 text = ui.fin.read()
1972 1972
1973 1973 cl = repo.changelog
1974 1974 if len(cl) > 0:
1975 1975 raise error.Abort(_('repository is not empty'))
1976 1976
1977 1977 # determine number of revs in DAG
1978 1978 total = 0
1979 1979 for type, data in dagparser.parsedag(text):
1980 1980 if type == 'n':
1981 1981 total += 1
1982 1982
1983 1983 if mergeable_file:
1984 1984 linesperrev = 2
1985 1985 # make a file with k lines per rev
1986 1986 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1987 1987 initialmergedlines.append("")
1988 1988
1989 1989 tags = []
1990 1990
1991 1991 wlock = lock = tr = None
1992 1992 try:
1993 1993 wlock = repo.wlock()
1994 1994 lock = repo.lock()
1995 1995 tr = repo.transaction("builddag")
1996 1996
1997 1997 at = -1
1998 1998 atbranch = 'default'
1999 1999 nodeids = []
2000 2000 id = 0
2001 2001 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2002 2002 for type, data in dagparser.parsedag(text):
2003 2003 if type == 'n':
2004 2004 ui.note(('node %s\n' % str(data)))
2005 2005 id, ps = data
2006 2006
2007 2007 files = []
2008 2008 fctxs = {}
2009 2009
2010 2010 p2 = None
2011 2011 if mergeable_file:
2012 2012 fn = "mf"
2013 2013 p1 = repo[ps[0]]
2014 2014 if len(ps) > 1:
2015 2015 p2 = repo[ps[1]]
2016 2016 pa = p1.ancestor(p2)
2017 2017 base, local, other = [x[fn].data() for x in (pa, p1,
2018 2018 p2)]
2019 2019 m3 = simplemerge.Merge3Text(base, local, other)
2020 2020 ml = [l.strip() for l in m3.merge_lines()]
2021 2021 ml.append("")
2022 2022 elif at > 0:
2023 2023 ml = p1[fn].data().split("\n")
2024 2024 else:
2025 2025 ml = initialmergedlines
2026 2026 ml[id * linesperrev] += " r%i" % id
2027 2027 mergedtext = "\n".join(ml)
2028 2028 files.append(fn)
2029 2029 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
2030 2030
2031 2031 if overwritten_file:
2032 2032 fn = "of"
2033 2033 files.append(fn)
2034 2034 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2035 2035
2036 2036 if new_file:
2037 2037 fn = "nf%i" % id
2038 2038 files.append(fn)
2039 2039 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2040 2040 if len(ps) > 1:
2041 2041 if not p2:
2042 2042 p2 = repo[ps[1]]
2043 2043 for fn in p2:
2044 2044 if fn.startswith("nf"):
2045 2045 files.append(fn)
2046 2046 fctxs[fn] = p2[fn]
2047 2047
2048 2048 def fctxfn(repo, cx, path):
2049 2049 return fctxs.get(path)
2050 2050
2051 2051 if len(ps) == 0 or ps[0] < 0:
2052 2052 pars = [None, None]
2053 2053 elif len(ps) == 1:
2054 2054 pars = [nodeids[ps[0]], None]
2055 2055 else:
2056 2056 pars = [nodeids[p] for p in ps]
2057 2057 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2058 2058 date=(id, 0),
2059 2059 user="debugbuilddag",
2060 2060 extra={'branch': atbranch})
2061 2061 nodeid = repo.commitctx(cx)
2062 2062 nodeids.append(nodeid)
2063 2063 at = id
2064 2064 elif type == 'l':
2065 2065 id, name = data
2066 2066 ui.note(('tag %s\n' % name))
2067 2067 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2068 2068 elif type == 'a':
2069 2069 ui.note(('branch %s\n' % data))
2070 2070 atbranch = data
2071 2071 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2072 2072 tr.close()
2073 2073
2074 2074 if tags:
2075 2075 repo.vfs.write("localtags", "".join(tags))
2076 2076 finally:
2077 2077 ui.progress(_('building'), None)
2078 2078 release(tr, lock, wlock)
2079 2079
2080 2080 @command('debugbundle',
2081 2081 [('a', 'all', None, _('show all details')),
2082 2082 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2083 2083 _('FILE'),
2084 2084 norepo=True)
2085 2085 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2086 2086 """lists the contents of a bundle"""
2087 2087 with hg.openpath(ui, bundlepath) as f:
2088 2088 if spec:
2089 2089 spec = exchange.getbundlespec(ui, f)
2090 2090 ui.write('%s\n' % spec)
2091 2091 return
2092 2092
2093 2093 gen = exchange.readbundle(ui, f, bundlepath)
2094 2094 if isinstance(gen, bundle2.unbundle20):
2095 2095 return _debugbundle2(ui, gen, all=all, **opts)
2096 2096 _debugchangegroup(ui, gen, all=all, **opts)
2097 2097
2098 2098 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
2099 2099 indent_string = ' ' * indent
2100 2100 if all:
2101 2101 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
2102 2102 % indent_string)
2103 2103
2104 2104 def showchunks(named):
2105 2105 ui.write("\n%s%s\n" % (indent_string, named))
2106 2106 chain = None
2107 2107 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
2108 2108 node = chunkdata['node']
2109 2109 p1 = chunkdata['p1']
2110 2110 p2 = chunkdata['p2']
2111 2111 cs = chunkdata['cs']
2112 2112 deltabase = chunkdata['deltabase']
2113 2113 delta = chunkdata['delta']
2114 2114 ui.write("%s%s %s %s %s %s %s\n" %
2115 2115 (indent_string, hex(node), hex(p1), hex(p2),
2116 2116 hex(cs), hex(deltabase), len(delta)))
2117 2117 chain = node
2118 2118
2119 2119 chunkdata = gen.changelogheader()
2120 2120 showchunks("changelog")
2121 2121 chunkdata = gen.manifestheader()
2122 2122 showchunks("manifest")
2123 2123 for chunkdata in iter(gen.filelogheader, {}):
2124 2124 fname = chunkdata['filename']
2125 2125 showchunks(fname)
2126 2126 else:
2127 2127 if isinstance(gen, bundle2.unbundle20):
2128 2128 raise error.Abort(_('use debugbundle2 for this file'))
2129 2129 chunkdata = gen.changelogheader()
2130 2130 chain = None
2131 2131 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
2132 2132 node = chunkdata['node']
2133 2133 ui.write("%s%s\n" % (indent_string, hex(node)))
2134 2134 chain = node
2135 2135
2136 2136 def _debugbundle2(ui, gen, all=None, **opts):
2137 2137 """lists the contents of a bundle2"""
2138 2138 if not isinstance(gen, bundle2.unbundle20):
2139 2139 raise error.Abort(_('not a bundle2 file'))
2140 2140 ui.write(('Stream params: %s\n' % repr(gen.params)))
2141 2141 for part in gen.iterparts():
2142 2142 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2143 2143 if part.type == 'changegroup':
2144 2144 version = part.params.get('version', '01')
2145 2145 cg = changegroup.getunbundler(version, part, 'UN')
2146 2146 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
2147 2147
2148 2148 @command('debugcreatestreamclonebundle', [], 'FILE')
2149 2149 def debugcreatestreamclonebundle(ui, repo, fname):
2150 2150 """create a stream clone bundle file
2151 2151
2152 2152 Stream bundles are special bundles that are essentially archives of
2153 2153 revlog files. They are commonly used for cloning very quickly.
2154 2154 """
2155 2155 requirements, gen = streamclone.generatebundlev1(repo)
2156 2156 changegroup.writechunks(ui, gen, fname)
2157 2157
2158 2158 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2159 2159
2160 2160 @command('debugapplystreamclonebundle', [], 'FILE')
2161 2161 def debugapplystreamclonebundle(ui, repo, fname):
2162 2162 """apply a stream clone bundle file"""
2163 2163 f = hg.openpath(ui, fname)
2164 2164 gen = exchange.readbundle(ui, f, fname)
2165 2165 gen.apply(repo)
2166 2166
2167 2167 @command('debugcheckstate', [], '')
2168 2168 def debugcheckstate(ui, repo):
2169 2169 """validate the correctness of the current dirstate"""
2170 2170 parent1, parent2 = repo.dirstate.parents()
2171 2171 m1 = repo[parent1].manifest()
2172 2172 m2 = repo[parent2].manifest()
2173 2173 errors = 0
2174 2174 for f in repo.dirstate:
2175 2175 state = repo.dirstate[f]
2176 2176 if state in "nr" and f not in m1:
2177 2177 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2178 2178 errors += 1
2179 2179 if state in "a" and f in m1:
2180 2180 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2181 2181 errors += 1
2182 2182 if state in "m" and f not in m1 and f not in m2:
2183 2183 ui.warn(_("%s in state %s, but not in either manifest\n") %
2184 2184 (f, state))
2185 2185 errors += 1
2186 2186 for f in m1:
2187 2187 state = repo.dirstate[f]
2188 2188 if state not in "nrm":
2189 2189 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2190 2190 errors += 1
2191 2191 if errors:
2192 2192 error = _(".hg/dirstate inconsistent with current parent's manifest")
2193 2193 raise error.Abort(error)
2194 2194
2195 2195 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2196 2196 def debugcommands(ui, cmd='', *args):
2197 2197 """list all available commands and options"""
2198 2198 for cmd, vals in sorted(table.iteritems()):
2199 2199 cmd = cmd.split('|')[0].strip('^')
2200 2200 opts = ', '.join([i[1] for i in vals[1]])
2201 2201 ui.write('%s: %s\n' % (cmd, opts))
2202 2202
2203 2203 @command('debugcomplete',
2204 2204 [('o', 'options', None, _('show the command options'))],
2205 2205 _('[-o] CMD'),
2206 2206 norepo=True)
2207 2207 def debugcomplete(ui, cmd='', **opts):
2208 2208 """returns the completion list associated with the given command"""
2209 2209
2210 2210 if opts.get('options'):
2211 2211 options = []
2212 2212 otables = [globalopts]
2213 2213 if cmd:
2214 2214 aliases, entry = cmdutil.findcmd(cmd, table, False)
2215 2215 otables.append(entry[1])
2216 2216 for t in otables:
2217 2217 for o in t:
2218 2218 if "(DEPRECATED)" in o[3]:
2219 2219 continue
2220 2220 if o[0]:
2221 2221 options.append('-%s' % o[0])
2222 2222 options.append('--%s' % o[1])
2223 2223 ui.write("%s\n" % "\n".join(options))
2224 2224 return
2225 2225
2226 2226 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2227 2227 if ui.verbose:
2228 2228 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2229 2229 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2230 2230
2231 2231 @command('debugdag',
2232 2232 [('t', 'tags', None, _('use tags as labels')),
2233 2233 ('b', 'branches', None, _('annotate with branch names')),
2234 2234 ('', 'dots', None, _('use dots for runs')),
2235 2235 ('s', 'spaces', None, _('separate elements by spaces'))],
2236 2236 _('[OPTION]... [FILE [REV]...]'),
2237 2237 optionalrepo=True)
2238 2238 def debugdag(ui, repo, file_=None, *revs, **opts):
2239 2239 """format the changelog or an index DAG as a concise textual description
2240 2240
2241 2241 If you pass a revlog index, the revlog's DAG is emitted. If you list
2242 2242 revision numbers, they get labeled in the output as rN.
2243 2243
2244 2244 Otherwise, the changelog DAG of the current repo is emitted.
2245 2245 """
2246 2246 spaces = opts.get('spaces')
2247 2247 dots = opts.get('dots')
2248 2248 if file_:
2249 2249 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2250 2250 revs = set((int(r) for r in revs))
2251 2251 def events():
2252 2252 for r in rlog:
2253 2253 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2254 2254 if p != -1))
2255 2255 if r in revs:
2256 2256 yield 'l', (r, "r%i" % r)
2257 2257 elif repo:
2258 2258 cl = repo.changelog
2259 2259 tags = opts.get('tags')
2260 2260 branches = opts.get('branches')
2261 2261 if tags:
2262 2262 labels = {}
2263 2263 for l, n in repo.tags().items():
2264 2264 labels.setdefault(cl.rev(n), []).append(l)
2265 2265 def events():
2266 2266 b = "default"
2267 2267 for r in cl:
2268 2268 if branches:
2269 2269 newb = cl.read(cl.node(r))[5]['branch']
2270 2270 if newb != b:
2271 2271 yield 'a', newb
2272 2272 b = newb
2273 2273 yield 'n', (r, list(p for p in cl.parentrevs(r)
2274 2274 if p != -1))
2275 2275 if tags:
2276 2276 ls = labels.get(r)
2277 2277 if ls:
2278 2278 for l in ls:
2279 2279 yield 'l', (r, l)
2280 2280 else:
2281 2281 raise error.Abort(_('need repo for changelog dag'))
2282 2282
2283 2283 for line in dagparser.dagtextlines(events(),
2284 2284 addspaces=spaces,
2285 2285 wraplabels=True,
2286 2286 wrapannotations=True,
2287 2287 wrapnonlinear=dots,
2288 2288 usedots=dots,
2289 2289 maxlinewidth=70):
2290 2290 ui.write(line)
2291 2291 ui.write("\n")
2292 2292
2293 2293 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2294 2294 def debugdata(ui, repo, file_, rev=None, **opts):
2295 2295 """dump the contents of a data file revision"""
2296 2296 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
2297 2297 if rev is not None:
2298 2298 raise error.CommandError('debugdata', _('invalid arguments'))
2299 2299 file_, rev = None, file_
2300 2300 elif rev is None:
2301 2301 raise error.CommandError('debugdata', _('invalid arguments'))
2302 2302 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2303 2303 try:
2304 2304 ui.write(r.revision(r.lookup(rev)))
2305 2305 except KeyError:
2306 2306 raise error.Abort(_('invalid revision identifier %s') % rev)
2307 2307
2308 2308 @command('debugdate',
2309 2309 [('e', 'extended', None, _('try extended date formats'))],
2310 2310 _('[-e] DATE [RANGE]'),
2311 2311 norepo=True, optionalrepo=True)
2312 2312 def debugdate(ui, date, range=None, **opts):
2313 2313 """parse and display a date"""
2314 2314 if opts["extended"]:
2315 2315 d = util.parsedate(date, util.extendeddateformats)
2316 2316 else:
2317 2317 d = util.parsedate(date)
2318 2318 ui.write(("internal: %s %s\n") % d)
2319 2319 ui.write(("standard: %s\n") % util.datestr(d))
2320 2320 if range:
2321 2321 m = util.matchdate(range)
2322 2322 ui.write(("match: %s\n") % m(d[0]))
2323 2323
2324 2324 @command('debugdiscovery',
2325 2325 [('', 'old', None, _('use old-style discovery')),
2326 2326 ('', 'nonheads', None,
2327 2327 _('use old-style discovery with non-heads included')),
2328 2328 ] + remoteopts,
2329 2329 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2330 2330 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2331 2331 """runs the changeset discovery protocol in isolation"""
2332 2332 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2333 2333 opts.get('branch'))
2334 2334 remote = hg.peer(repo, opts, remoteurl)
2335 2335 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2336 2336
2337 2337 # make sure tests are repeatable
2338 2338 random.seed(12323)
2339 2339
2340 2340 def doit(localheads, remoteheads, remote=remote):
2341 2341 if opts.get('old'):
2342 2342 if localheads:
2343 2343 raise error.Abort('cannot use localheads with old style '
2344 2344 'discovery')
2345 2345 if not util.safehasattr(remote, 'branches'):
2346 2346 # enable in-client legacy support
2347 2347 remote = localrepo.locallegacypeer(remote.local())
2348 2348 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2349 2349 force=True)
2350 2350 common = set(common)
2351 2351 if not opts.get('nonheads'):
2352 2352 ui.write(("unpruned common: %s\n") %
2353 2353 " ".join(sorted(short(n) for n in common)))
2354 2354 dag = dagutil.revlogdag(repo.changelog)
2355 2355 all = dag.ancestorset(dag.internalizeall(common))
2356 2356 common = dag.externalizeall(dag.headsetofconnecteds(all))
2357 2357 else:
2358 2358 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2359 2359 common = set(common)
2360 2360 rheads = set(hds)
2361 2361 lheads = set(repo.heads())
2362 2362 ui.write(("common heads: %s\n") %
2363 2363 " ".join(sorted(short(n) for n in common)))
2364 2364 if lheads <= common:
2365 2365 ui.write(("local is subset\n"))
2366 2366 elif rheads <= common:
2367 2367 ui.write(("remote is subset\n"))
2368 2368
2369 2369 serverlogs = opts.get('serverlog')
2370 2370 if serverlogs:
2371 2371 for filename in serverlogs:
2372 2372 with open(filename, 'r') as logfile:
2373 2373 line = logfile.readline()
2374 2374 while line:
2375 2375 parts = line.strip().split(';')
2376 2376 op = parts[1]
2377 2377 if op == 'cg':
2378 2378 pass
2379 2379 elif op == 'cgss':
2380 2380 doit(parts[2].split(' '), parts[3].split(' '))
2381 2381 elif op == 'unb':
2382 2382 doit(parts[3].split(' '), parts[2].split(' '))
2383 2383 line = logfile.readline()
2384 2384 else:
2385 2385 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2386 2386 opts.get('remote_head'))
2387 2387 localrevs = opts.get('local_head')
2388 2388 doit(localrevs, remoterevs)
2389 2389
2390 2390 @command('debugextensions', formatteropts, [], norepo=True)
2391 2391 def debugextensions(ui, **opts):
2392 2392 '''show information about active extensions'''
2393 2393 exts = extensions.extensions(ui)
2394 2394 hgver = util.version()
2395 2395 fm = ui.formatter('debugextensions', opts)
2396 2396 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2397 2397 isinternal = extensions.ismoduleinternal(extmod)
2398 2398 extsource = extmod.__file__
2399 2399 if isinternal:
2400 2400 exttestedwith = [] # never expose magic string to users
2401 2401 else:
2402 2402 exttestedwith = getattr(extmod, 'testedwith', '').split()
2403 2403 extbuglink = getattr(extmod, 'buglink', None)
2404 2404
2405 2405 fm.startitem()
2406 2406
2407 2407 if ui.quiet or ui.verbose:
2408 2408 fm.write('name', '%s\n', extname)
2409 2409 else:
2410 2410 fm.write('name', '%s', extname)
2411 2411 if isinternal or hgver in exttestedwith:
2412 2412 fm.plain('\n')
2413 2413 elif not exttestedwith:
2414 2414 fm.plain(_(' (untested!)\n'))
2415 2415 else:
2416 2416 lasttestedversion = exttestedwith[-1]
2417 2417 fm.plain(' (%s!)\n' % lasttestedversion)
2418 2418
2419 2419 fm.condwrite(ui.verbose and extsource, 'source',
2420 2420 _(' location: %s\n'), extsource or "")
2421 2421
2422 2422 if ui.verbose:
2423 2423 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
2424 2424 fm.data(bundled=isinternal)
2425 2425
2426 2426 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2427 2427 _(' tested with: %s\n'),
2428 2428 fm.formatlist(exttestedwith, name='ver'))
2429 2429
2430 2430 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2431 2431 _(' bug reporting: %s\n'), extbuglink or "")
2432 2432
2433 2433 fm.end()
2434 2434
2435 2435 @command('debugfileset',
2436 2436 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2437 2437 _('[-r REV] FILESPEC'))
2438 2438 def debugfileset(ui, repo, expr, **opts):
2439 2439 '''parse and apply a fileset specification'''
2440 2440 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2441 2441 if ui.verbose:
2442 2442 tree = fileset.parse(expr)
2443 2443 ui.note(fileset.prettyformat(tree), "\n")
2444 2444
2445 2445 for f in ctx.getfileset(expr):
2446 2446 ui.write("%s\n" % f)
2447 2447
2448 2448 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2449 2449 def debugfsinfo(ui, path="."):
2450 2450 """show information detected about current filesystem"""
2451 2451 util.writefile('.debugfsinfo', '')
2452 2452 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2453 2453 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2454 2454 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2455 2455 ui.write(('case-sensitive: %s\n') % (util.fscasesensitive('.debugfsinfo')
2456 2456 and 'yes' or 'no'))
2457 2457 os.unlink('.debugfsinfo')
2458 2458
2459 2459 @command('debuggetbundle',
2460 2460 [('H', 'head', [], _('id of head node'), _('ID')),
2461 2461 ('C', 'common', [], _('id of common node'), _('ID')),
2462 2462 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2463 2463 _('REPO FILE [-H|-C ID]...'),
2464 2464 norepo=True)
2465 2465 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2466 2466 """retrieves a bundle from a repo
2467 2467
2468 2468 Every ID must be a full-length hex node id string. Saves the bundle to the
2469 2469 given file.
2470 2470 """
2471 2471 repo = hg.peer(ui, opts, repopath)
2472 2472 if not repo.capable('getbundle'):
2473 2473 raise error.Abort("getbundle() not supported by target repository")
2474 2474 args = {}
2475 2475 if common:
2476 2476 args['common'] = [bin(s) for s in common]
2477 2477 if head:
2478 2478 args['heads'] = [bin(s) for s in head]
2479 2479 # TODO: get desired bundlecaps from command line.
2480 2480 args['bundlecaps'] = None
2481 2481 bundle = repo.getbundle('debug', **args)
2482 2482
2483 2483 bundletype = opts.get('type', 'bzip2').lower()
2484 2484 btypes = {'none': 'HG10UN',
2485 2485 'bzip2': 'HG10BZ',
2486 2486 'gzip': 'HG10GZ',
2487 2487 'bundle2': 'HG20'}
2488 2488 bundletype = btypes.get(bundletype)
2489 2489 if bundletype not in bundle2.bundletypes:
2490 2490 raise error.Abort(_('unknown bundle type specified with --type'))
2491 2491 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2492 2492
2493 2493 @command('debugignore', [], '[FILE]')
2494 2494 def debugignore(ui, repo, *files, **opts):
2495 2495 """display the combined ignore pattern and information about ignored files
2496 2496
2497 2497 With no argument display the combined ignore pattern.
2498 2498
2499 2499 Given space separated file names, shows if the given file is ignored and
2500 2500 if so, show the ignore rule (file and line number) that matched it.
2501 2501 """
2502 2502 ignore = repo.dirstate._ignore
2503 2503 if not files:
2504 2504 # Show all the patterns
2505 2505 includepat = getattr(ignore, 'includepat', None)
2506 2506 if includepat is not None:
2507 2507 ui.write("%s\n" % includepat)
2508 2508 else:
2509 2509 raise error.Abort(_("no ignore patterns found"))
2510 2510 else:
2511 2511 for f in files:
2512 2512 nf = util.normpath(f)
2513 2513 ignored = None
2514 2514 ignoredata = None
2515 2515 if nf != '.':
2516 2516 if ignore(nf):
2517 2517 ignored = nf
2518 2518 ignoredata = repo.dirstate._ignorefileandline(nf)
2519 2519 else:
2520 2520 for p in util.finddirs(nf):
2521 2521 if ignore(p):
2522 2522 ignored = p
2523 2523 ignoredata = repo.dirstate._ignorefileandline(p)
2524 2524 break
2525 2525 if ignored:
2526 2526 if ignored == nf:
2527 2527 ui.write(_("%s is ignored\n") % f)
2528 2528 else:
2529 2529 ui.write(_("%s is ignored because of "
2530 2530 "containing folder %s\n")
2531 2531 % (f, ignored))
2532 2532 ignorefile, lineno, line = ignoredata
2533 2533 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
2534 2534 % (ignorefile, lineno, line))
2535 2535 else:
2536 2536 ui.write(_("%s is not ignored\n") % f)
2537 2537
2538 2538 @command('debugindex', debugrevlogopts +
2539 2539 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2540 2540 _('[-f FORMAT] -c|-m|FILE'),
2541 2541 optionalrepo=True)
2542 2542 def debugindex(ui, repo, file_=None, **opts):
2543 2543 """dump the contents of an index file"""
2544 2544 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2545 2545 format = opts.get('format', 0)
2546 2546 if format not in (0, 1):
2547 2547 raise error.Abort(_("unknown format %d") % format)
2548 2548
2549 2549 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2550 2550 if generaldelta:
2551 2551 basehdr = ' delta'
2552 2552 else:
2553 2553 basehdr = ' base'
2554 2554
2555 2555 if ui.debugflag:
2556 2556 shortfn = hex
2557 2557 else:
2558 2558 shortfn = short
2559 2559
2560 2560 # There might not be anything in r, so have a sane default
2561 2561 idlen = 12
2562 2562 for i in r:
2563 2563 idlen = len(shortfn(r.node(i)))
2564 2564 break
2565 2565
2566 2566 if format == 0:
2567 2567 ui.write((" rev offset length " + basehdr + " linkrev"
2568 2568 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2569 2569 elif format == 1:
2570 2570 ui.write((" rev flag offset length"
2571 2571 " size " + basehdr + " link p1 p2"
2572 2572 " %s\n") % "nodeid".rjust(idlen))
2573 2573
2574 2574 for i in r:
2575 2575 node = r.node(i)
2576 2576 if generaldelta:
2577 2577 base = r.deltaparent(i)
2578 2578 else:
2579 2579 base = r.chainbase(i)
2580 2580 if format == 0:
2581 2581 try:
2582 2582 pp = r.parents(node)
2583 2583 except Exception:
2584 2584 pp = [nullid, nullid]
2585 2585 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2586 2586 i, r.start(i), r.length(i), base, r.linkrev(i),
2587 2587 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2588 2588 elif format == 1:
2589 2589 pr = r.parentrevs(i)
2590 2590 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2591 2591 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2592 2592 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2593 2593
2594 2594 @command('debugindexdot', debugrevlogopts,
2595 2595 _('-c|-m|FILE'), optionalrepo=True)
2596 2596 def debugindexdot(ui, repo, file_=None, **opts):
2597 2597 """dump an index DAG as a graphviz dot file"""
2598 2598 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2599 2599 ui.write(("digraph G {\n"))
2600 2600 for i in r:
2601 2601 node = r.node(i)
2602 2602 pp = r.parents(node)
2603 2603 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2604 2604 if pp[1] != nullid:
2605 2605 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2606 2606 ui.write("}\n")
2607 2607
2608 2608 @command('debugdeltachain',
2609 2609 debugrevlogopts + formatteropts,
2610 2610 _('-c|-m|FILE'),
2611 2611 optionalrepo=True)
2612 2612 def debugdeltachain(ui, repo, file_=None, **opts):
2613 2613 """dump information about delta chains in a revlog
2614 2614
2615 2615 Output can be templatized. Available template keywords are:
2616 2616
2617 2617 :``rev``: revision number
2618 2618 :``chainid``: delta chain identifier (numbered by unique base)
2619 2619 :``chainlen``: delta chain length to this revision
2620 2620 :``prevrev``: previous revision in delta chain
2621 2621 :``deltatype``: role of delta / how it was computed
2622 2622 :``compsize``: compressed size of revision
2623 2623 :``uncompsize``: uncompressed size of revision
2624 2624 :``chainsize``: total size of compressed revisions in chain
2625 2625 :``chainratio``: total chain size divided by uncompressed revision size
2626 2626 (new delta chains typically start at ratio 2.00)
2627 2627 :``lindist``: linear distance from base revision in delta chain to end
2628 2628 of this revision
2629 2629 :``extradist``: total size of revisions not part of this delta chain from
2630 2630 base of delta chain to end of this revision; a measurement
2631 2631 of how much extra data we need to read/seek across to read
2632 2632 the delta chain for this revision
2633 2633 :``extraratio``: extradist divided by chainsize; another representation of
2634 2634 how much unrelated data is needed to load this delta chain
2635 2635 """
2636 2636 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2637 2637 index = r.index
2638 2638 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2639 2639
2640 2640 def revinfo(rev):
2641 2641 e = index[rev]
2642 2642 compsize = e[1]
2643 2643 uncompsize = e[2]
2644 2644 chainsize = 0
2645 2645
2646 2646 if generaldelta:
2647 2647 if e[3] == e[5]:
2648 2648 deltatype = 'p1'
2649 2649 elif e[3] == e[6]:
2650 2650 deltatype = 'p2'
2651 2651 elif e[3] == rev - 1:
2652 2652 deltatype = 'prev'
2653 2653 elif e[3] == rev:
2654 2654 deltatype = 'base'
2655 2655 else:
2656 2656 deltatype = 'other'
2657 2657 else:
2658 2658 if e[3] == rev:
2659 2659 deltatype = 'base'
2660 2660 else:
2661 2661 deltatype = 'prev'
2662 2662
2663 2663 chain = r._deltachain(rev)[0]
2664 2664 for iterrev in chain:
2665 2665 e = index[iterrev]
2666 2666 chainsize += e[1]
2667 2667
2668 2668 return compsize, uncompsize, deltatype, chain, chainsize
2669 2669
2670 2670 fm = ui.formatter('debugdeltachain', opts)
2671 2671
2672 2672 fm.plain(' rev chain# chainlen prev delta '
2673 2673 'size rawsize chainsize ratio lindist extradist '
2674 2674 'extraratio\n')
2675 2675
2676 2676 chainbases = {}
2677 2677 for rev in r:
2678 2678 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2679 2679 chainbase = chain[0]
2680 2680 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2681 2681 basestart = r.start(chainbase)
2682 2682 revstart = r.start(rev)
2683 2683 lineardist = revstart + comp - basestart
2684 2684 extradist = lineardist - chainsize
2685 2685 try:
2686 2686 prevrev = chain[-2]
2687 2687 except IndexError:
2688 2688 prevrev = -1
2689 2689
2690 2690 chainratio = float(chainsize) / float(uncomp)
2691 2691 extraratio = float(extradist) / float(chainsize)
2692 2692
2693 2693 fm.startitem()
2694 2694 fm.write('rev chainid chainlen prevrev deltatype compsize '
2695 2695 'uncompsize chainsize chainratio lindist extradist '
2696 2696 'extraratio',
2697 2697 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2698 2698 rev, chainid, len(chain), prevrev, deltatype, comp,
2699 2699 uncomp, chainsize, chainratio, lineardist, extradist,
2700 2700 extraratio,
2701 2701 rev=rev, chainid=chainid, chainlen=len(chain),
2702 2702 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2703 2703 uncompsize=uncomp, chainsize=chainsize,
2704 2704 chainratio=chainratio, lindist=lineardist,
2705 2705 extradist=extradist, extraratio=extraratio)
2706 2706
2707 2707 fm.end()
2708 2708
2709 2709 @command('debuginstall', [] + formatteropts, '', norepo=True)
2710 2710 def debuginstall(ui, **opts):
2711 2711 '''test Mercurial installation
2712 2712
2713 2713 Returns 0 on success.
2714 2714 '''
2715 2715
2716 2716 def writetemp(contents):
2717 2717 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2718 2718 f = os.fdopen(fd, "wb")
2719 2719 f.write(contents)
2720 2720 f.close()
2721 2721 return name
2722 2722
2723 2723 problems = 0
2724 2724
2725 2725 fm = ui.formatter('debuginstall', opts)
2726 2726 fm.startitem()
2727 2727
2728 2728 # encoding
2729 2729 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2730 2730 err = None
2731 2731 try:
2732 2732 encoding.fromlocal("test")
2733 2733 except error.Abort as inst:
2734 2734 err = inst
2735 2735 problems += 1
2736 2736 fm.condwrite(err, 'encodingerror', _(" %s\n"
2737 2737 " (check that your locale is properly set)\n"), err)
2738 2738
2739 2739 # Python
2740 2740 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2741 2741 sys.executable)
2742 2742 fm.write('pythonver', _("checking Python version (%s)\n"),
2743 2743 ("%s.%s.%s" % sys.version_info[:3]))
2744 2744 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2745 2745 os.path.dirname(os.__file__))
2746 2746
2747 2747 # hg version
2748 2748 hgver = util.version()
2749 2749 fm.write('hgver', _("checking Mercurial version (%s)\n"),
2750 2750 hgver.split('+')[0])
2751 2751 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
2752 2752 '+'.join(hgver.split('+')[1:]))
2753 2753
2754 2754 # compiled modules
2755 2755 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
2756 2756 policy.policy)
2757 2757 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2758 2758 os.path.dirname(__file__))
2759 2759
2760 2760 err = None
2761 2761 try:
2762 2762 from . import (
2763 2763 base85,
2764 2764 bdiff,
2765 2765 mpatch,
2766 2766 osutil,
2767 2767 )
2768 2768 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2769 2769 except Exception as inst:
2770 2770 err = inst
2771 2771 problems += 1
2772 2772 fm.condwrite(err, 'extensionserror', " %s\n", err)
2773 2773
2774 2774 # templates
2775 2775 p = templater.templatepaths()
2776 2776 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2777 2777 fm.condwrite(not p, '', _(" no template directories found\n"))
2778 2778 if p:
2779 2779 m = templater.templatepath("map-cmdline.default")
2780 2780 if m:
2781 2781 # template found, check if it is working
2782 2782 err = None
2783 2783 try:
2784 2784 templater.templater.frommapfile(m)
2785 2785 except Exception as inst:
2786 2786 err = inst
2787 2787 p = None
2788 2788 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2789 2789 else:
2790 2790 p = None
2791 2791 fm.condwrite(p, 'defaulttemplate',
2792 2792 _("checking default template (%s)\n"), m)
2793 2793 fm.condwrite(not m, 'defaulttemplatenotfound',
2794 2794 _(" template '%s' not found\n"), "default")
2795 2795 if not p:
2796 2796 problems += 1
2797 2797 fm.condwrite(not p, '',
2798 2798 _(" (templates seem to have been installed incorrectly)\n"))
2799 2799
2800 2800 # editor
2801 2801 editor = ui.geteditor()
2802 2802 editor = util.expandpath(editor)
2803 2803 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2804 2804 cmdpath = util.findexe(shlex.split(editor)[0])
2805 2805 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2806 2806 _(" No commit editor set and can't find %s in PATH\n"
2807 2807 " (specify a commit editor in your configuration"
2808 2808 " file)\n"), not cmdpath and editor == 'vi' and editor)
2809 2809 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2810 2810 _(" Can't find editor '%s' in PATH\n"
2811 2811 " (specify a commit editor in your configuration"
2812 2812 " file)\n"), not cmdpath and editor)
2813 2813 if not cmdpath and editor != 'vi':
2814 2814 problems += 1
2815 2815
2816 2816 # check username
2817 2817 username = None
2818 2818 err = None
2819 2819 try:
2820 2820 username = ui.username()
2821 2821 except error.Abort as e:
2822 2822 err = e
2823 2823 problems += 1
2824 2824
2825 2825 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2826 2826 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2827 2827 " (specify a username in your configuration file)\n"), err)
2828 2828
2829 2829 fm.condwrite(not problems, '',
2830 2830 _("no problems detected\n"))
2831 2831 if not problems:
2832 2832 fm.data(problems=problems)
2833 2833 fm.condwrite(problems, 'problems',
2834 2834 _("%s problems detected,"
2835 2835 " please check your install!\n"), problems)
2836 2836 fm.end()
2837 2837
2838 2838 return problems
2839 2839
2840 2840 @command('debugknown', [], _('REPO ID...'), norepo=True)
2841 2841 def debugknown(ui, repopath, *ids, **opts):
2842 2842 """test whether node ids are known to a repo
2843 2843
2844 2844 Every ID must be a full-length hex node id string. Returns a list of 0s
2845 2845 and 1s indicating unknown/known.
2846 2846 """
2847 2847 repo = hg.peer(ui, opts, repopath)
2848 2848 if not repo.capable('known'):
2849 2849 raise error.Abort("known() not supported by target repository")
2850 2850 flags = repo.known([bin(s) for s in ids])
2851 2851 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2852 2852
2853 2853 @command('debuglabelcomplete', [], _('LABEL...'))
2854 2854 def debuglabelcomplete(ui, repo, *args):
2855 2855 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2856 2856 debugnamecomplete(ui, repo, *args)
2857 2857
2858 2858 @command('debugmergestate', [], '')
2859 2859 def debugmergestate(ui, repo, *args):
2860 2860 """print merge state
2861 2861
2862 2862 Use --verbose to print out information about whether v1 or v2 merge state
2863 2863 was chosen."""
2864 2864 def _hashornull(h):
2865 2865 if h == nullhex:
2866 2866 return 'null'
2867 2867 else:
2868 2868 return h
2869 2869
2870 2870 def printrecords(version):
2871 2871 ui.write(('* version %s records\n') % version)
2872 2872 if version == 1:
2873 2873 records = v1records
2874 2874 else:
2875 2875 records = v2records
2876 2876
2877 2877 for rtype, record in records:
2878 2878 # pretty print some record types
2879 2879 if rtype == 'L':
2880 2880 ui.write(('local: %s\n') % record)
2881 2881 elif rtype == 'O':
2882 2882 ui.write(('other: %s\n') % record)
2883 2883 elif rtype == 'm':
2884 2884 driver, mdstate = record.split('\0', 1)
2885 2885 ui.write(('merge driver: %s (state "%s")\n')
2886 2886 % (driver, mdstate))
2887 2887 elif rtype in 'FDC':
2888 2888 r = record.split('\0')
2889 2889 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2890 2890 if version == 1:
2891 2891 onode = 'not stored in v1 format'
2892 2892 flags = r[7]
2893 2893 else:
2894 2894 onode, flags = r[7:9]
2895 2895 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2896 2896 % (f, rtype, state, _hashornull(hash)))
2897 2897 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2898 2898 ui.write((' ancestor path: %s (node %s)\n')
2899 2899 % (afile, _hashornull(anode)))
2900 2900 ui.write((' other path: %s (node %s)\n')
2901 2901 % (ofile, _hashornull(onode)))
2902 2902 elif rtype == 'f':
2903 2903 filename, rawextras = record.split('\0', 1)
2904 2904 extras = rawextras.split('\0')
2905 2905 i = 0
2906 2906 extrastrings = []
2907 2907 while i < len(extras):
2908 2908 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2909 2909 i += 2
2910 2910
2911 2911 ui.write(('file extras: %s (%s)\n')
2912 2912 % (filename, ', '.join(extrastrings)))
2913 2913 elif rtype == 'l':
2914 2914 labels = record.split('\0', 2)
2915 2915 labels = [l for l in labels if len(l) > 0]
2916 2916 ui.write(('labels:\n'))
2917 2917 ui.write((' local: %s\n' % labels[0]))
2918 2918 ui.write((' other: %s\n' % labels[1]))
2919 2919 if len(labels) > 2:
2920 2920 ui.write((' base: %s\n' % labels[2]))
2921 2921 else:
2922 2922 ui.write(('unrecognized entry: %s\t%s\n')
2923 2923 % (rtype, record.replace('\0', '\t')))
2924 2924
2925 2925 # Avoid mergestate.read() since it may raise an exception for unsupported
2926 2926 # merge state records. We shouldn't be doing this, but this is OK since this
2927 2927 # command is pretty low-level.
2928 2928 ms = mergemod.mergestate(repo)
2929 2929
2930 2930 # sort so that reasonable information is on top
2931 2931 v1records = ms._readrecordsv1()
2932 2932 v2records = ms._readrecordsv2()
2933 2933 order = 'LOml'
2934 2934 def key(r):
2935 2935 idx = order.find(r[0])
2936 2936 if idx == -1:
2937 2937 return (1, r[1])
2938 2938 else:
2939 2939 return (0, idx)
2940 2940 v1records.sort(key=key)
2941 2941 v2records.sort(key=key)
2942 2942
2943 2943 if not v1records and not v2records:
2944 2944 ui.write(('no merge state found\n'))
2945 2945 elif not v2records:
2946 2946 ui.note(('no version 2 merge state\n'))
2947 2947 printrecords(1)
2948 2948 elif ms._v1v2match(v1records, v2records):
2949 2949 ui.note(('v1 and v2 states match: using v2\n'))
2950 2950 printrecords(2)
2951 2951 else:
2952 2952 ui.note(('v1 and v2 states mismatch: using v1\n'))
2953 2953 printrecords(1)
2954 2954 if ui.verbose:
2955 2955 printrecords(2)
2956 2956
2957 2957 @command('debugnamecomplete', [], _('NAME...'))
2958 2958 def debugnamecomplete(ui, repo, *args):
2959 2959 '''complete "names" - tags, open branch names, bookmark names'''
2960 2960
2961 2961 names = set()
2962 2962 # since we previously only listed open branches, we will handle that
2963 2963 # specially (after this for loop)
2964 2964 for name, ns in repo.names.iteritems():
2965 2965 if name != 'branches':
2966 2966 names.update(ns.listnames(repo))
2967 2967 names.update(tag for (tag, heads, tip, closed)
2968 2968 in repo.branchmap().iterbranches() if not closed)
2969 2969 completions = set()
2970 2970 if not args:
2971 2971 args = ['']
2972 2972 for a in args:
2973 2973 completions.update(n for n in names if n.startswith(a))
2974 2974 ui.write('\n'.join(sorted(completions)))
2975 2975 ui.write('\n')
2976 2976
2977 2977 @command('debuglocks',
2978 2978 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2979 2979 ('W', 'force-wlock', None,
2980 2980 _('free the working state lock (DANGEROUS)'))],
2981 2981 _('[OPTION]...'))
2982 2982 def debuglocks(ui, repo, **opts):
2983 2983 """show or modify state of locks
2984 2984
2985 2985 By default, this command will show which locks are held. This
2986 2986 includes the user and process holding the lock, the amount of time
2987 2987 the lock has been held, and the machine name where the process is
2988 2988 running if it's not local.
2989 2989
2990 2990 Locks protect the integrity of Mercurial's data, so should be
2991 2991 treated with care. System crashes or other interruptions may cause
2992 2992 locks to not be properly released, though Mercurial will usually
2993 2993 detect and remove such stale locks automatically.
2994 2994
2995 2995 However, detecting stale locks may not always be possible (for
2996 2996 instance, on a shared filesystem). Removing locks may also be
2997 2997 blocked by filesystem permissions.
2998 2998
2999 2999 Returns 0 if no locks are held.
3000 3000
3001 3001 """
3002 3002
3003 3003 if opts.get('force_lock'):
3004 3004 repo.svfs.unlink('lock')
3005 3005 if opts.get('force_wlock'):
3006 3006 repo.vfs.unlink('wlock')
3007 3007 if opts.get('force_lock') or opts.get('force_lock'):
3008 3008 return 0
3009 3009
3010 3010 now = time.time()
3011 3011 held = 0
3012 3012
3013 3013 def report(vfs, name, method):
3014 3014 # this causes stale locks to get reaped for more accurate reporting
3015 3015 try:
3016 3016 l = method(False)
3017 3017 except error.LockHeld:
3018 3018 l = None
3019 3019
3020 3020 if l:
3021 3021 l.release()
3022 3022 else:
3023 3023 try:
3024 3024 stat = vfs.lstat(name)
3025 3025 age = now - stat.st_mtime
3026 3026 user = util.username(stat.st_uid)
3027 3027 locker = vfs.readlock(name)
3028 3028 if ":" in locker:
3029 3029 host, pid = locker.split(':')
3030 3030 if host == socket.gethostname():
3031 3031 locker = 'user %s, process %s' % (user, pid)
3032 3032 else:
3033 3033 locker = 'user %s, process %s, host %s' \
3034 3034 % (user, pid, host)
3035 3035 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
3036 3036 return 1
3037 3037 except OSError as e:
3038 3038 if e.errno != errno.ENOENT:
3039 3039 raise
3040 3040
3041 3041 ui.write(("%-6s free\n") % (name + ":"))
3042 3042 return 0
3043 3043
3044 3044 held += report(repo.svfs, "lock", repo.lock)
3045 3045 held += report(repo.vfs, "wlock", repo.wlock)
3046 3046
3047 3047 return held
3048 3048
3049 3049 @command('debugobsolete',
3050 3050 [('', 'flags', 0, _('markers flag')),
3051 3051 ('', 'record-parents', False,
3052 3052 _('record parent information for the precursor')),
3053 3053 ('r', 'rev', [], _('display markers relevant to REV')),
3054 3054 ('', 'index', False, _('display index of the marker')),
3055 3055 ('', 'delete', [], _('delete markers specified by indices')),
3056 3056 ] + commitopts2 + formatteropts,
3057 3057 _('[OBSOLETED [REPLACEMENT ...]]'))
3058 3058 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3059 3059 """create arbitrary obsolete marker
3060 3060
3061 3061 With no arguments, displays the list of obsolescence markers."""
3062 3062
3063 3063 def parsenodeid(s):
3064 3064 try:
3065 3065 # We do not use revsingle/revrange functions here to accept
3066 3066 # arbitrary node identifiers, possibly not present in the
3067 3067 # local repository.
3068 3068 n = bin(s)
3069 3069 if len(n) != len(nullid):
3070 3070 raise TypeError()
3071 3071 return n
3072 3072 except TypeError:
3073 3073 raise error.Abort('changeset references must be full hexadecimal '
3074 3074 'node identifiers')
3075 3075
3076 3076 if opts.get('delete'):
3077 3077 indices = []
3078 3078 for v in opts.get('delete'):
3079 3079 try:
3080 3080 indices.append(int(v))
3081 3081 except ValueError:
3082 3082 raise error.Abort(_('invalid index value: %r') % v,
3083 3083 hint=_('use integers for indices'))
3084 3084
3085 3085 if repo.currenttransaction():
3086 3086 raise error.Abort(_('cannot delete obsmarkers in the middle '
3087 3087 'of transaction.'))
3088 3088
3089 3089 with repo.lock():
3090 3090 n = repair.deleteobsmarkers(repo.obsstore, indices)
3091 3091 ui.write(_('deleted %i obsolescense markers\n') % n)
3092 3092
3093 3093 return
3094 3094
3095 3095 if precursor is not None:
3096 3096 if opts['rev']:
3097 3097 raise error.Abort('cannot select revision when creating marker')
3098 3098 metadata = {}
3099 3099 metadata['user'] = opts['user'] or ui.username()
3100 3100 succs = tuple(parsenodeid(succ) for succ in successors)
3101 3101 l = repo.lock()
3102 3102 try:
3103 3103 tr = repo.transaction('debugobsolete')
3104 3104 try:
3105 3105 date = opts.get('date')
3106 3106 if date:
3107 3107 date = util.parsedate(date)
3108 3108 else:
3109 3109 date = None
3110 3110 prec = parsenodeid(precursor)
3111 3111 parents = None
3112 3112 if opts['record_parents']:
3113 3113 if prec not in repo.unfiltered():
3114 3114 raise error.Abort('cannot used --record-parents on '
3115 3115 'unknown changesets')
3116 3116 parents = repo.unfiltered()[prec].parents()
3117 3117 parents = tuple(p.node() for p in parents)
3118 3118 repo.obsstore.create(tr, prec, succs, opts['flags'],
3119 3119 parents=parents, date=date,
3120 3120 metadata=metadata)
3121 3121 tr.close()
3122 3122 except ValueError as exc:
3123 3123 raise error.Abort(_('bad obsmarker input: %s') % exc)
3124 3124 finally:
3125 3125 tr.release()
3126 3126 finally:
3127 3127 l.release()
3128 3128 else:
3129 3129 if opts['rev']:
3130 3130 revs = scmutil.revrange(repo, opts['rev'])
3131 3131 nodes = [repo[r].node() for r in revs]
3132 3132 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3133 3133 markers.sort(key=lambda x: x._data)
3134 3134 else:
3135 3135 markers = obsolete.getmarkers(repo)
3136 3136
3137 3137 markerstoiter = markers
3138 3138 isrelevant = lambda m: True
3139 3139 if opts.get('rev') and opts.get('index'):
3140 3140 markerstoiter = obsolete.getmarkers(repo)
3141 3141 markerset = set(markers)
3142 3142 isrelevant = lambda m: m in markerset
3143 3143
3144 3144 fm = ui.formatter('debugobsolete', opts)
3145 3145 for i, m in enumerate(markerstoiter):
3146 3146 if not isrelevant(m):
3147 3147 # marker can be irrelevant when we're iterating over a set
3148 3148 # of markers (markerstoiter) which is bigger than the set
3149 3149 # of markers we want to display (markers)
3150 3150 # this can happen if both --index and --rev options are
3151 3151 # provided and thus we need to iterate over all of the markers
3152 3152 # to get the correct indices, but only display the ones that
3153 3153 # are relevant to --rev value
3154 3154 continue
3155 3155 fm.startitem()
3156 3156 ind = i if opts.get('index') else None
3157 3157 cmdutil.showmarker(fm, m, index=ind)
3158 3158 fm.end()
3159 3159
3160 3160 @command('debugpathcomplete',
3161 3161 [('f', 'full', None, _('complete an entire path')),
3162 3162 ('n', 'normal', None, _('show only normal files')),
3163 3163 ('a', 'added', None, _('show only added files')),
3164 3164 ('r', 'removed', None, _('show only removed files'))],
3165 3165 _('FILESPEC...'))
3166 3166 def debugpathcomplete(ui, repo, *specs, **opts):
3167 3167 '''complete part or all of a tracked path
3168 3168
3169 3169 This command supports shells that offer path name completion. It
3170 3170 currently completes only files already known to the dirstate.
3171 3171
3172 3172 Completion extends only to the next path segment unless
3173 3173 --full is specified, in which case entire paths are used.'''
3174 3174
3175 3175 def complete(path, acceptable):
3176 3176 dirstate = repo.dirstate
3177 3177 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3178 3178 rootdir = repo.root + os.sep
3179 3179 if spec != repo.root and not spec.startswith(rootdir):
3180 3180 return [], []
3181 3181 if os.path.isdir(spec):
3182 3182 spec += '/'
3183 3183 spec = spec[len(rootdir):]
3184 3184 fixpaths = os.sep != '/'
3185 3185 if fixpaths:
3186 3186 spec = spec.replace(os.sep, '/')
3187 3187 speclen = len(spec)
3188 3188 fullpaths = opts['full']
3189 3189 files, dirs = set(), set()
3190 3190 adddir, addfile = dirs.add, files.add
3191 3191 for f, st in dirstate.iteritems():
3192 3192 if f.startswith(spec) and st[0] in acceptable:
3193 3193 if fixpaths:
3194 3194 f = f.replace('/', os.sep)
3195 3195 if fullpaths:
3196 3196 addfile(f)
3197 3197 continue
3198 3198 s = f.find(os.sep, speclen)
3199 3199 if s >= 0:
3200 3200 adddir(f[:s])
3201 3201 else:
3202 3202 addfile(f)
3203 3203 return files, dirs
3204 3204
3205 3205 acceptable = ''
3206 3206 if opts['normal']:
3207 3207 acceptable += 'nm'
3208 3208 if opts['added']:
3209 3209 acceptable += 'a'
3210 3210 if opts['removed']:
3211 3211 acceptable += 'r'
3212 3212 cwd = repo.getcwd()
3213 3213 if not specs:
3214 3214 specs = ['.']
3215 3215
3216 3216 files, dirs = set(), set()
3217 3217 for spec in specs:
3218 3218 f, d = complete(spec, acceptable or 'nmar')
3219 3219 files.update(f)
3220 3220 dirs.update(d)
3221 3221 files.update(dirs)
3222 3222 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3223 3223 ui.write('\n')
3224 3224
3225 3225 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3226 3226 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3227 3227 '''access the pushkey key/value protocol
3228 3228
3229 3229 With two args, list the keys in the given namespace.
3230 3230
3231 3231 With five args, set a key to new if it currently is set to old.
3232 3232 Reports success or failure.
3233 3233 '''
3234 3234
3235 3235 target = hg.peer(ui, {}, repopath)
3236 3236 if keyinfo:
3237 3237 key, old, new = keyinfo
3238 3238 r = target.pushkey(namespace, key, old, new)
3239 3239 ui.status(str(r) + '\n')
3240 3240 return not r
3241 3241 else:
3242 3242 for k, v in sorted(target.listkeys(namespace).iteritems()):
3243 3243 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3244 3244 v.encode('string-escape')))
3245 3245
3246 3246 @command('debugpvec', [], _('A B'))
3247 3247 def debugpvec(ui, repo, a, b=None):
3248 3248 ca = scmutil.revsingle(repo, a)
3249 3249 cb = scmutil.revsingle(repo, b)
3250 3250 pa = pvec.ctxpvec(ca)
3251 3251 pb = pvec.ctxpvec(cb)
3252 3252 if pa == pb:
3253 3253 rel = "="
3254 3254 elif pa > pb:
3255 3255 rel = ">"
3256 3256 elif pa < pb:
3257 3257 rel = "<"
3258 3258 elif pa | pb:
3259 3259 rel = "|"
3260 3260 ui.write(_("a: %s\n") % pa)
3261 3261 ui.write(_("b: %s\n") % pb)
3262 3262 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3263 3263 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3264 3264 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3265 3265 pa.distance(pb), rel))
3266 3266
3267 3267 @command('debugrebuilddirstate|debugrebuildstate',
3268 3268 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3269 3269 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3270 3270 'the working copy parent')),
3271 3271 ],
3272 3272 _('[-r REV]'))
3273 3273 def debugrebuilddirstate(ui, repo, rev, **opts):
3274 3274 """rebuild the dirstate as it would look like for the given revision
3275 3275
3276 3276 If no revision is specified the first current parent will be used.
3277 3277
3278 3278 The dirstate will be set to the files of the given revision.
3279 3279 The actual working directory content or existing dirstate
3280 3280 information such as adds or removes is not considered.
3281 3281
3282 3282 ``minimal`` will only rebuild the dirstate status for files that claim to be
3283 3283 tracked but are not in the parent manifest, or that exist in the parent
3284 3284 manifest but are not in the dirstate. It will not change adds, removes, or
3285 3285 modified files that are in the working copy parent.
3286 3286
3287 3287 One use of this command is to make the next :hg:`status` invocation
3288 3288 check the actual file content.
3289 3289 """
3290 3290 ctx = scmutil.revsingle(repo, rev)
3291 3291 with repo.wlock():
3292 3292 dirstate = repo.dirstate
3293 3293 changedfiles = None
3294 3294 # See command doc for what minimal does.
3295 3295 if opts.get('minimal'):
3296 3296 manifestfiles = set(ctx.manifest().keys())
3297 3297 dirstatefiles = set(dirstate)
3298 3298 manifestonly = manifestfiles - dirstatefiles
3299 3299 dsonly = dirstatefiles - manifestfiles
3300 3300 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3301 3301 changedfiles = manifestonly | dsnotadded
3302 3302
3303 3303 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3304 3304
3305 3305 @command('debugrebuildfncache', [], '')
3306 3306 def debugrebuildfncache(ui, repo):
3307 3307 """rebuild the fncache file"""
3308 3308 repair.rebuildfncache(ui, repo)
3309 3309
3310 3310 @command('debugrename',
3311 3311 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3312 3312 _('[-r REV] FILE'))
3313 3313 def debugrename(ui, repo, file1, *pats, **opts):
3314 3314 """dump rename information"""
3315 3315
3316 3316 ctx = scmutil.revsingle(repo, opts.get('rev'))
3317 3317 m = scmutil.match(ctx, (file1,) + pats, opts)
3318 3318 for abs in ctx.walk(m):
3319 3319 fctx = ctx[abs]
3320 3320 o = fctx.filelog().renamed(fctx.filenode())
3321 3321 rel = m.rel(abs)
3322 3322 if o:
3323 3323 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3324 3324 else:
3325 3325 ui.write(_("%s not renamed\n") % rel)
3326 3326
3327 3327 @command('debugrevlog', debugrevlogopts +
3328 3328 [('d', 'dump', False, _('dump index data'))],
3329 3329 _('-c|-m|FILE'),
3330 3330 optionalrepo=True)
3331 3331 def debugrevlog(ui, repo, file_=None, **opts):
3332 3332 """show data and statistics about a revlog"""
3333 3333 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3334 3334
3335 3335 if opts.get("dump"):
3336 3336 numrevs = len(r)
3337 3337 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
3338 3338 " rawsize totalsize compression heads chainlen\n"))
3339 3339 ts = 0
3340 3340 heads = set()
3341 3341
3342 3342 for rev in xrange(numrevs):
3343 3343 dbase = r.deltaparent(rev)
3344 3344 if dbase == -1:
3345 3345 dbase = rev
3346 3346 cbase = r.chainbase(rev)
3347 3347 clen = r.chainlen(rev)
3348 3348 p1, p2 = r.parentrevs(rev)
3349 3349 rs = r.rawsize(rev)
3350 3350 ts = ts + rs
3351 3351 heads -= set(r.parentrevs(rev))
3352 3352 heads.add(rev)
3353 3353 try:
3354 3354 compression = ts / r.end(rev)
3355 3355 except ZeroDivisionError:
3356 3356 compression = 0
3357 3357 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3358 3358 "%11d %5d %8d\n" %
3359 3359 (rev, p1, p2, r.start(rev), r.end(rev),
3360 3360 r.start(dbase), r.start(cbase),
3361 3361 r.start(p1), r.start(p2),
3362 3362 rs, ts, compression, len(heads), clen))
3363 3363 return 0
3364 3364
3365 3365 v = r.version
3366 3366 format = v & 0xFFFF
3367 3367 flags = []
3368 3368 gdelta = False
3369 3369 if v & revlog.REVLOGNGINLINEDATA:
3370 3370 flags.append('inline')
3371 3371 if v & revlog.REVLOGGENERALDELTA:
3372 3372 gdelta = True
3373 3373 flags.append('generaldelta')
3374 3374 if not flags:
3375 3375 flags = ['(none)']
3376 3376
3377 3377 nummerges = 0
3378 3378 numfull = 0
3379 3379 numprev = 0
3380 3380 nump1 = 0
3381 3381 nump2 = 0
3382 3382 numother = 0
3383 3383 nump1prev = 0
3384 3384 nump2prev = 0
3385 3385 chainlengths = []
3386 3386
3387 3387 datasize = [None, 0, 0]
3388 3388 fullsize = [None, 0, 0]
3389 3389 deltasize = [None, 0, 0]
3390 3390
3391 3391 def addsize(size, l):
3392 3392 if l[0] is None or size < l[0]:
3393 3393 l[0] = size
3394 3394 if size > l[1]:
3395 3395 l[1] = size
3396 3396 l[2] += size
3397 3397
3398 3398 numrevs = len(r)
3399 3399 for rev in xrange(numrevs):
3400 3400 p1, p2 = r.parentrevs(rev)
3401 3401 delta = r.deltaparent(rev)
3402 3402 if format > 0:
3403 3403 addsize(r.rawsize(rev), datasize)
3404 3404 if p2 != nullrev:
3405 3405 nummerges += 1
3406 3406 size = r.length(rev)
3407 3407 if delta == nullrev:
3408 3408 chainlengths.append(0)
3409 3409 numfull += 1
3410 3410 addsize(size, fullsize)
3411 3411 else:
3412 3412 chainlengths.append(chainlengths[delta] + 1)
3413 3413 addsize(size, deltasize)
3414 3414 if delta == rev - 1:
3415 3415 numprev += 1
3416 3416 if delta == p1:
3417 3417 nump1prev += 1
3418 3418 elif delta == p2:
3419 3419 nump2prev += 1
3420 3420 elif delta == p1:
3421 3421 nump1 += 1
3422 3422 elif delta == p2:
3423 3423 nump2 += 1
3424 3424 elif delta != nullrev:
3425 3425 numother += 1
3426 3426
3427 3427 # Adjust size min value for empty cases
3428 3428 for size in (datasize, fullsize, deltasize):
3429 3429 if size[0] is None:
3430 3430 size[0] = 0
3431 3431
3432 3432 numdeltas = numrevs - numfull
3433 3433 numoprev = numprev - nump1prev - nump2prev
3434 3434 totalrawsize = datasize[2]
3435 3435 datasize[2] /= numrevs
3436 3436 fulltotal = fullsize[2]
3437 3437 fullsize[2] /= numfull
3438 3438 deltatotal = deltasize[2]
3439 3439 if numrevs - numfull > 0:
3440 3440 deltasize[2] /= numrevs - numfull
3441 3441 totalsize = fulltotal + deltatotal
3442 3442 avgchainlen = sum(chainlengths) / numrevs
3443 3443 maxchainlen = max(chainlengths)
3444 3444 compratio = 1
3445 3445 if totalsize:
3446 3446 compratio = totalrawsize / totalsize
3447 3447
3448 3448 basedfmtstr = '%%%dd\n'
3449 3449 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3450 3450
3451 3451 def dfmtstr(max):
3452 3452 return basedfmtstr % len(str(max))
3453 3453 def pcfmtstr(max, padding=0):
3454 3454 return basepcfmtstr % (len(str(max)), ' ' * padding)
3455 3455
3456 3456 def pcfmt(value, total):
3457 3457 if total:
3458 3458 return (value, 100 * float(value) / total)
3459 3459 else:
3460 3460 return value, 100.0
3461 3461
3462 3462 ui.write(('format : %d\n') % format)
3463 3463 ui.write(('flags : %s\n') % ', '.join(flags))
3464 3464
3465 3465 ui.write('\n')
3466 3466 fmt = pcfmtstr(totalsize)
3467 3467 fmt2 = dfmtstr(totalsize)
3468 3468 ui.write(('revisions : ') + fmt2 % numrevs)
3469 3469 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3470 3470 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3471 3471 ui.write(('revisions : ') + fmt2 % numrevs)
3472 3472 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3473 3473 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3474 3474 ui.write(('revision size : ') + fmt2 % totalsize)
3475 3475 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3476 3476 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3477 3477
3478 3478 ui.write('\n')
3479 3479 fmt = dfmtstr(max(avgchainlen, compratio))
3480 3480 ui.write(('avg chain length : ') + fmt % avgchainlen)
3481 3481 ui.write(('max chain length : ') + fmt % maxchainlen)
3482 3482 ui.write(('compression ratio : ') + fmt % compratio)
3483 3483
3484 3484 if format > 0:
3485 3485 ui.write('\n')
3486 3486 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3487 3487 % tuple(datasize))
3488 3488 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3489 3489 % tuple(fullsize))
3490 3490 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3491 3491 % tuple(deltasize))
3492 3492
3493 3493 if numdeltas > 0:
3494 3494 ui.write('\n')
3495 3495 fmt = pcfmtstr(numdeltas)
3496 3496 fmt2 = pcfmtstr(numdeltas, 4)
3497 3497 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3498 3498 if numprev > 0:
3499 3499 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3500 3500 numprev))
3501 3501 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3502 3502 numprev))
3503 3503 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3504 3504 numprev))
3505 3505 if gdelta:
3506 3506 ui.write(('deltas against p1 : ')
3507 3507 + fmt % pcfmt(nump1, numdeltas))
3508 3508 ui.write(('deltas against p2 : ')
3509 3509 + fmt % pcfmt(nump2, numdeltas))
3510 3510 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3511 3511 numdeltas))
3512 3512
3513 3513 @command('debugrevspec',
3514 3514 [('', 'optimize', None,
3515 3515 _('print parsed tree after optimizing (DEPRECATED)')),
3516 3516 ('p', 'show-stage', [],
3517 3517 _('print parsed tree at the given stage'), _('NAME')),
3518 ('', 'no-optimized', False, _('evaluate tree without optimization')),
3518 3519 ],
3519 3520 ('REVSPEC'))
3520 3521 def debugrevspec(ui, repo, expr, **opts):
3521 3522 """parse and apply a revision specification
3522 3523
3523 3524 Use -p/--show-stage option to print the parsed tree at the given stages.
3524 3525 Use -p all to print tree at every stage.
3525 3526 """
3526 3527 stages = [
3527 3528 ('parsed', lambda tree: tree),
3528 3529 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
3529 3530 ('concatenated', revset.foldconcat),
3530 3531 ('analyzed', revset.analyze),
3531 3532 ('optimized', revset.optimize),
3532 3533 ]
3534 if opts['no_optimized']:
3535 stages = stages[:-1]
3533 3536 stagenames = set(n for n, f in stages)
3534 3537
3535 3538 showalways = set()
3536 3539 showchanged = set()
3537 3540 if ui.verbose and not opts['show_stage']:
3538 3541 # show parsed tree by --verbose (deprecated)
3539 3542 showalways.add('parsed')
3540 3543 showchanged.update(['expanded', 'concatenated'])
3541 3544 if opts['optimize']:
3542 3545 showalways.add('optimized')
3543 3546 if opts['show_stage'] and opts['optimize']:
3544 3547 raise error.Abort(_('cannot use --optimize with --show-stage'))
3545 3548 if opts['show_stage'] == ['all']:
3546 3549 showalways.update(stagenames)
3547 3550 else:
3548 3551 for n in opts['show_stage']:
3549 3552 if n not in stagenames:
3550 3553 raise error.Abort(_('invalid stage name: %s') % n)
3551 3554 showalways.update(opts['show_stage'])
3552 3555
3553 3556 printedtree = None
3554 3557 tree = revset.parse(expr, lookup=repo.__contains__)
3555 3558 for n, f in stages:
3556 3559 tree = f(tree)
3557 3560 if n in showalways or (n in showchanged and tree != printedtree):
3558 3561 if opts['show_stage'] or n != 'parsed':
3559 3562 ui.write(("* %s:\n") % n)
3560 3563 ui.write(revset.prettyformat(tree), "\n")
3561 3564 printedtree = tree
3562 3565
3563 3566 func = revset.makematcher(tree)
3564 3567 revs = func(repo)
3565 3568 if ui.verbose:
3566 3569 ui.note(("* set:\n"), revset.prettyformatset(revs), "\n")
3567 3570 for c in revs:
3568 3571 ui.write("%s\n" % c)
3569 3572
3570 3573 @command('debugsetparents', [], _('REV1 [REV2]'))
3571 3574 def debugsetparents(ui, repo, rev1, rev2=None):
3572 3575 """manually set the parents of the current working directory
3573 3576
3574 3577 This is useful for writing repository conversion tools, but should
3575 3578 be used with care. For example, neither the working directory nor the
3576 3579 dirstate is updated, so file status may be incorrect after running this
3577 3580 command.
3578 3581
3579 3582 Returns 0 on success.
3580 3583 """
3581 3584
3582 3585 r1 = scmutil.revsingle(repo, rev1).node()
3583 3586 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3584 3587
3585 3588 with repo.wlock():
3586 3589 repo.setparents(r1, r2)
3587 3590
3588 3591 @command('debugdirstate|debugstate',
3589 3592 [('', 'nodates', None, _('do not display the saved mtime')),
3590 3593 ('', 'datesort', None, _('sort by saved mtime'))],
3591 3594 _('[OPTION]...'))
3592 3595 def debugstate(ui, repo, **opts):
3593 3596 """show the contents of the current dirstate"""
3594 3597
3595 3598 nodates = opts.get('nodates')
3596 3599 datesort = opts.get('datesort')
3597 3600
3598 3601 timestr = ""
3599 3602 if datesort:
3600 3603 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3601 3604 else:
3602 3605 keyfunc = None # sort by filename
3603 3606 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3604 3607 if ent[3] == -1:
3605 3608 timestr = 'unset '
3606 3609 elif nodates:
3607 3610 timestr = 'set '
3608 3611 else:
3609 3612 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3610 3613 time.localtime(ent[3]))
3611 3614 if ent[1] & 0o20000:
3612 3615 mode = 'lnk'
3613 3616 else:
3614 3617 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3615 3618 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3616 3619 for f in repo.dirstate.copies():
3617 3620 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3618 3621
3619 3622 @command('debugsub',
3620 3623 [('r', 'rev', '',
3621 3624 _('revision to check'), _('REV'))],
3622 3625 _('[-r REV] [REV]'))
3623 3626 def debugsub(ui, repo, rev=None):
3624 3627 ctx = scmutil.revsingle(repo, rev, None)
3625 3628 for k, v in sorted(ctx.substate.items()):
3626 3629 ui.write(('path %s\n') % k)
3627 3630 ui.write((' source %s\n') % v[0])
3628 3631 ui.write((' revision %s\n') % v[1])
3629 3632
3630 3633 @command('debugsuccessorssets',
3631 3634 [],
3632 3635 _('[REV]'))
3633 3636 def debugsuccessorssets(ui, repo, *revs):
3634 3637 """show set of successors for revision
3635 3638
3636 3639 A successors set of changeset A is a consistent group of revisions that
3637 3640 succeed A. It contains non-obsolete changesets only.
3638 3641
3639 3642 In most cases a changeset A has a single successors set containing a single
3640 3643 successor (changeset A replaced by A').
3641 3644
3642 3645 A changeset that is made obsolete with no successors are called "pruned".
3643 3646 Such changesets have no successors sets at all.
3644 3647
3645 3648 A changeset that has been "split" will have a successors set containing
3646 3649 more than one successor.
3647 3650
3648 3651 A changeset that has been rewritten in multiple different ways is called
3649 3652 "divergent". Such changesets have multiple successor sets (each of which
3650 3653 may also be split, i.e. have multiple successors).
3651 3654
3652 3655 Results are displayed as follows::
3653 3656
3654 3657 <rev1>
3655 3658 <successors-1A>
3656 3659 <rev2>
3657 3660 <successors-2A>
3658 3661 <successors-2B1> <successors-2B2> <successors-2B3>
3659 3662
3660 3663 Here rev2 has two possible (i.e. divergent) successors sets. The first
3661 3664 holds one element, whereas the second holds three (i.e. the changeset has
3662 3665 been split).
3663 3666 """
3664 3667 # passed to successorssets caching computation from one call to another
3665 3668 cache = {}
3666 3669 ctx2str = str
3667 3670 node2str = short
3668 3671 if ui.debug():
3669 3672 def ctx2str(ctx):
3670 3673 return ctx.hex()
3671 3674 node2str = hex
3672 3675 for rev in scmutil.revrange(repo, revs):
3673 3676 ctx = repo[rev]
3674 3677 ui.write('%s\n'% ctx2str(ctx))
3675 3678 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3676 3679 if succsset:
3677 3680 ui.write(' ')
3678 3681 ui.write(node2str(succsset[0]))
3679 3682 for node in succsset[1:]:
3680 3683 ui.write(' ')
3681 3684 ui.write(node2str(node))
3682 3685 ui.write('\n')
3683 3686
3684 3687 @command('debugtemplate',
3685 3688 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3686 3689 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3687 3690 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3688 3691 optionalrepo=True)
3689 3692 def debugtemplate(ui, repo, tmpl, **opts):
3690 3693 """parse and apply a template
3691 3694
3692 3695 If -r/--rev is given, the template is processed as a log template and
3693 3696 applied to the given changesets. Otherwise, it is processed as a generic
3694 3697 template.
3695 3698
3696 3699 Use --verbose to print the parsed tree.
3697 3700 """
3698 3701 revs = None
3699 3702 if opts['rev']:
3700 3703 if repo is None:
3701 3704 raise error.RepoError(_('there is no Mercurial repository here '
3702 3705 '(.hg not found)'))
3703 3706 revs = scmutil.revrange(repo, opts['rev'])
3704 3707
3705 3708 props = {}
3706 3709 for d in opts['define']:
3707 3710 try:
3708 3711 k, v = (e.strip() for e in d.split('=', 1))
3709 3712 if not k:
3710 3713 raise ValueError
3711 3714 props[k] = v
3712 3715 except ValueError:
3713 3716 raise error.Abort(_('malformed keyword definition: %s') % d)
3714 3717
3715 3718 if ui.verbose:
3716 3719 aliases = ui.configitems('templatealias')
3717 3720 tree = templater.parse(tmpl)
3718 3721 ui.note(templater.prettyformat(tree), '\n')
3719 3722 newtree = templater.expandaliases(tree, aliases)
3720 3723 if newtree != tree:
3721 3724 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
3722 3725
3723 3726 mapfile = None
3724 3727 if revs is None:
3725 3728 k = 'debugtemplate'
3726 3729 t = formatter.maketemplater(ui, k, tmpl)
3727 3730 ui.write(templater.stringify(t(k, **props)))
3728 3731 else:
3729 3732 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3730 3733 mapfile, buffered=False)
3731 3734 for r in revs:
3732 3735 displayer.show(repo[r], **props)
3733 3736 displayer.close()
3734 3737
3735 3738 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3736 3739 def debugwalk(ui, repo, *pats, **opts):
3737 3740 """show how files match on given patterns"""
3738 3741 m = scmutil.match(repo[None], pats, opts)
3739 3742 items = list(repo.walk(m))
3740 3743 if not items:
3741 3744 return
3742 3745 f = lambda fn: fn
3743 3746 if ui.configbool('ui', 'slash') and os.sep != '/':
3744 3747 f = lambda fn: util.normpath(fn)
3745 3748 fmt = 'f %%-%ds %%-%ds %%s' % (
3746 3749 max([len(abs) for abs in items]),
3747 3750 max([len(m.rel(abs)) for abs in items]))
3748 3751 for abs in items:
3749 3752 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3750 3753 ui.write("%s\n" % line.rstrip())
3751 3754
3752 3755 @command('debugwireargs',
3753 3756 [('', 'three', '', 'three'),
3754 3757 ('', 'four', '', 'four'),
3755 3758 ('', 'five', '', 'five'),
3756 3759 ] + remoteopts,
3757 3760 _('REPO [OPTIONS]... [ONE [TWO]]'),
3758 3761 norepo=True)
3759 3762 def debugwireargs(ui, repopath, *vals, **opts):
3760 3763 repo = hg.peer(ui, opts, repopath)
3761 3764 for opt in remoteopts:
3762 3765 del opts[opt[1]]
3763 3766 args = {}
3764 3767 for k, v in opts.iteritems():
3765 3768 if v:
3766 3769 args[k] = v
3767 3770 # run twice to check that we don't mess up the stream for the next command
3768 3771 res1 = repo.debugwireargs(*vals, **args)
3769 3772 res2 = repo.debugwireargs(*vals, **args)
3770 3773 ui.write("%s\n" % res1)
3771 3774 if res1 != res2:
3772 3775 ui.warn("%s\n" % res2)
3773 3776
3774 3777 @command('^diff',
3775 3778 [('r', 'rev', [], _('revision'), _('REV')),
3776 3779 ('c', 'change', '', _('change made by revision'), _('REV'))
3777 3780 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3778 3781 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3779 3782 inferrepo=True)
3780 3783 def diff(ui, repo, *pats, **opts):
3781 3784 """diff repository (or selected files)
3782 3785
3783 3786 Show differences between revisions for the specified files.
3784 3787
3785 3788 Differences between files are shown using the unified diff format.
3786 3789
3787 3790 .. note::
3788 3791
3789 3792 :hg:`diff` may generate unexpected results for merges, as it will
3790 3793 default to comparing against the working directory's first
3791 3794 parent changeset if no revisions are specified.
3792 3795
3793 3796 When two revision arguments are given, then changes are shown
3794 3797 between those revisions. If only one revision is specified then
3795 3798 that revision is compared to the working directory, and, when no
3796 3799 revisions are specified, the working directory files are compared
3797 3800 to its first parent.
3798 3801
3799 3802 Alternatively you can specify -c/--change with a revision to see
3800 3803 the changes in that changeset relative to its first parent.
3801 3804
3802 3805 Without the -a/--text option, diff will avoid generating diffs of
3803 3806 files it detects as binary. With -a, diff will generate a diff
3804 3807 anyway, probably with undesirable results.
3805 3808
3806 3809 Use the -g/--git option to generate diffs in the git extended diff
3807 3810 format. For more information, read :hg:`help diffs`.
3808 3811
3809 3812 .. container:: verbose
3810 3813
3811 3814 Examples:
3812 3815
3813 3816 - compare a file in the current working directory to its parent::
3814 3817
3815 3818 hg diff foo.c
3816 3819
3817 3820 - compare two historical versions of a directory, with rename info::
3818 3821
3819 3822 hg diff --git -r 1.0:1.2 lib/
3820 3823
3821 3824 - get change stats relative to the last change on some date::
3822 3825
3823 3826 hg diff --stat -r "date('may 2')"
3824 3827
3825 3828 - diff all newly-added files that contain a keyword::
3826 3829
3827 3830 hg diff "set:added() and grep(GNU)"
3828 3831
3829 3832 - compare a revision and its parents::
3830 3833
3831 3834 hg diff -c 9353 # compare against first parent
3832 3835 hg diff -r 9353^:9353 # same using revset syntax
3833 3836 hg diff -r 9353^2:9353 # compare against the second parent
3834 3837
3835 3838 Returns 0 on success.
3836 3839 """
3837 3840
3838 3841 revs = opts.get('rev')
3839 3842 change = opts.get('change')
3840 3843 stat = opts.get('stat')
3841 3844 reverse = opts.get('reverse')
3842 3845
3843 3846 if revs and change:
3844 3847 msg = _('cannot specify --rev and --change at the same time')
3845 3848 raise error.Abort(msg)
3846 3849 elif change:
3847 3850 node2 = scmutil.revsingle(repo, change, None).node()
3848 3851 node1 = repo[node2].p1().node()
3849 3852 else:
3850 3853 node1, node2 = scmutil.revpair(repo, revs)
3851 3854
3852 3855 if reverse:
3853 3856 node1, node2 = node2, node1
3854 3857
3855 3858 diffopts = patch.diffallopts(ui, opts)
3856 3859 m = scmutil.match(repo[node2], pats, opts)
3857 3860 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3858 3861 listsubrepos=opts.get('subrepos'),
3859 3862 root=opts.get('root'))
3860 3863
3861 3864 @command('^export',
3862 3865 [('o', 'output', '',
3863 3866 _('print output to file with formatted name'), _('FORMAT')),
3864 3867 ('', 'switch-parent', None, _('diff against the second parent')),
3865 3868 ('r', 'rev', [], _('revisions to export'), _('REV')),
3866 3869 ] + diffopts,
3867 3870 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3868 3871 def export(ui, repo, *changesets, **opts):
3869 3872 """dump the header and diffs for one or more changesets
3870 3873
3871 3874 Print the changeset header and diffs for one or more revisions.
3872 3875 If no revision is given, the parent of the working directory is used.
3873 3876
3874 3877 The information shown in the changeset header is: author, date,
3875 3878 branch name (if non-default), changeset hash, parent(s) and commit
3876 3879 comment.
3877 3880
3878 3881 .. note::
3879 3882
3880 3883 :hg:`export` may generate unexpected diff output for merge
3881 3884 changesets, as it will compare the merge changeset against its
3882 3885 first parent only.
3883 3886
3884 3887 Output may be to a file, in which case the name of the file is
3885 3888 given using a format string. The formatting rules are as follows:
3886 3889
3887 3890 :``%%``: literal "%" character
3888 3891 :``%H``: changeset hash (40 hexadecimal digits)
3889 3892 :``%N``: number of patches being generated
3890 3893 :``%R``: changeset revision number
3891 3894 :``%b``: basename of the exporting repository
3892 3895 :``%h``: short-form changeset hash (12 hexadecimal digits)
3893 3896 :``%m``: first line of the commit message (only alphanumeric characters)
3894 3897 :``%n``: zero-padded sequence number, starting at 1
3895 3898 :``%r``: zero-padded changeset revision number
3896 3899
3897 3900 Without the -a/--text option, export will avoid generating diffs
3898 3901 of files it detects as binary. With -a, export will generate a
3899 3902 diff anyway, probably with undesirable results.
3900 3903
3901 3904 Use the -g/--git option to generate diffs in the git extended diff
3902 3905 format. See :hg:`help diffs` for more information.
3903 3906
3904 3907 With the --switch-parent option, the diff will be against the
3905 3908 second parent. It can be useful to review a merge.
3906 3909
3907 3910 .. container:: verbose
3908 3911
3909 3912 Examples:
3910 3913
3911 3914 - use export and import to transplant a bugfix to the current
3912 3915 branch::
3913 3916
3914 3917 hg export -r 9353 | hg import -
3915 3918
3916 3919 - export all the changesets between two revisions to a file with
3917 3920 rename information::
3918 3921
3919 3922 hg export --git -r 123:150 > changes.txt
3920 3923
3921 3924 - split outgoing changes into a series of patches with
3922 3925 descriptive names::
3923 3926
3924 3927 hg export -r "outgoing()" -o "%n-%m.patch"
3925 3928
3926 3929 Returns 0 on success.
3927 3930 """
3928 3931 changesets += tuple(opts.get('rev', []))
3929 3932 if not changesets:
3930 3933 changesets = ['.']
3931 3934 revs = scmutil.revrange(repo, changesets)
3932 3935 if not revs:
3933 3936 raise error.Abort(_("export requires at least one changeset"))
3934 3937 if len(revs) > 1:
3935 3938 ui.note(_('exporting patches:\n'))
3936 3939 else:
3937 3940 ui.note(_('exporting patch:\n'))
3938 3941 cmdutil.export(repo, revs, template=opts.get('output'),
3939 3942 switch_parent=opts.get('switch_parent'),
3940 3943 opts=patch.diffallopts(ui, opts))
3941 3944
3942 3945 @command('files',
3943 3946 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3944 3947 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3945 3948 ] + walkopts + formatteropts + subrepoopts,
3946 3949 _('[OPTION]... [FILE]...'))
3947 3950 def files(ui, repo, *pats, **opts):
3948 3951 """list tracked files
3949 3952
3950 3953 Print files under Mercurial control in the working directory or
3951 3954 specified revision for given files (excluding removed files).
3952 3955 Files can be specified as filenames or filesets.
3953 3956
3954 3957 If no files are given to match, this command prints the names
3955 3958 of all files under Mercurial control.
3956 3959
3957 3960 .. container:: verbose
3958 3961
3959 3962 Examples:
3960 3963
3961 3964 - list all files under the current directory::
3962 3965
3963 3966 hg files .
3964 3967
3965 3968 - shows sizes and flags for current revision::
3966 3969
3967 3970 hg files -vr .
3968 3971
3969 3972 - list all files named README::
3970 3973
3971 3974 hg files -I "**/README"
3972 3975
3973 3976 - list all binary files::
3974 3977
3975 3978 hg files "set:binary()"
3976 3979
3977 3980 - find files containing a regular expression::
3978 3981
3979 3982 hg files "set:grep('bob')"
3980 3983
3981 3984 - search tracked file contents with xargs and grep::
3982 3985
3983 3986 hg files -0 | xargs -0 grep foo
3984 3987
3985 3988 See :hg:`help patterns` and :hg:`help filesets` for more information
3986 3989 on specifying file patterns.
3987 3990
3988 3991 Returns 0 if a match is found, 1 otherwise.
3989 3992
3990 3993 """
3991 3994 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3992 3995
3993 3996 end = '\n'
3994 3997 if opts.get('print0'):
3995 3998 end = '\0'
3996 3999 fmt = '%s' + end
3997 4000
3998 4001 m = scmutil.match(ctx, pats, opts)
3999 4002 with ui.formatter('files', opts) as fm:
4000 4003 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
4001 4004
4002 4005 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
4003 4006 def forget(ui, repo, *pats, **opts):
4004 4007 """forget the specified files on the next commit
4005 4008
4006 4009 Mark the specified files so they will no longer be tracked
4007 4010 after the next commit.
4008 4011
4009 4012 This only removes files from the current branch, not from the
4010 4013 entire project history, and it does not delete them from the
4011 4014 working directory.
4012 4015
4013 4016 To delete the file from the working directory, see :hg:`remove`.
4014 4017
4015 4018 To undo a forget before the next commit, see :hg:`add`.
4016 4019
4017 4020 .. container:: verbose
4018 4021
4019 4022 Examples:
4020 4023
4021 4024 - forget newly-added binary files::
4022 4025
4023 4026 hg forget "set:added() and binary()"
4024 4027
4025 4028 - forget files that would be excluded by .hgignore::
4026 4029
4027 4030 hg forget "set:hgignore()"
4028 4031
4029 4032 Returns 0 on success.
4030 4033 """
4031 4034
4032 4035 if not pats:
4033 4036 raise error.Abort(_('no files specified'))
4034 4037
4035 4038 m = scmutil.match(repo[None], pats, opts)
4036 4039 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
4037 4040 return rejected and 1 or 0
4038 4041
4039 4042 @command(
4040 4043 'graft',
4041 4044 [('r', 'rev', [], _('revisions to graft'), _('REV')),
4042 4045 ('c', 'continue', False, _('resume interrupted graft')),
4043 4046 ('e', 'edit', False, _('invoke editor on commit messages')),
4044 4047 ('', 'log', None, _('append graft info to log message')),
4045 4048 ('f', 'force', False, _('force graft')),
4046 4049 ('D', 'currentdate', False,
4047 4050 _('record the current date as commit date')),
4048 4051 ('U', 'currentuser', False,
4049 4052 _('record the current user as committer'), _('DATE'))]
4050 4053 + commitopts2 + mergetoolopts + dryrunopts,
4051 4054 _('[OPTION]... [-r REV]... REV...'))
4052 4055 def graft(ui, repo, *revs, **opts):
4053 4056 '''copy changes from other branches onto the current branch
4054 4057
4055 4058 This command uses Mercurial's merge logic to copy individual
4056 4059 changes from other branches without merging branches in the
4057 4060 history graph. This is sometimes known as 'backporting' or
4058 4061 'cherry-picking'. By default, graft will copy user, date, and
4059 4062 description from the source changesets.
4060 4063
4061 4064 Changesets that are ancestors of the current revision, that have
4062 4065 already been grafted, or that are merges will be skipped.
4063 4066
4064 4067 If --log is specified, log messages will have a comment appended
4065 4068 of the form::
4066 4069
4067 4070 (grafted from CHANGESETHASH)
4068 4071
4069 4072 If --force is specified, revisions will be grafted even if they
4070 4073 are already ancestors of or have been grafted to the destination.
4071 4074 This is useful when the revisions have since been backed out.
4072 4075
4073 4076 If a graft merge results in conflicts, the graft process is
4074 4077 interrupted so that the current merge can be manually resolved.
4075 4078 Once all conflicts are addressed, the graft process can be
4076 4079 continued with the -c/--continue option.
4077 4080
4078 4081 .. note::
4079 4082
4080 4083 The -c/--continue option does not reapply earlier options, except
4081 4084 for --force.
4082 4085
4083 4086 .. container:: verbose
4084 4087
4085 4088 Examples:
4086 4089
4087 4090 - copy a single change to the stable branch and edit its description::
4088 4091
4089 4092 hg update stable
4090 4093 hg graft --edit 9393
4091 4094
4092 4095 - graft a range of changesets with one exception, updating dates::
4093 4096
4094 4097 hg graft -D "2085::2093 and not 2091"
4095 4098
4096 4099 - continue a graft after resolving conflicts::
4097 4100
4098 4101 hg graft -c
4099 4102
4100 4103 - show the source of a grafted changeset::
4101 4104
4102 4105 hg log --debug -r .
4103 4106
4104 4107 - show revisions sorted by date::
4105 4108
4106 4109 hg log -r "sort(all(), date)"
4107 4110
4108 4111 See :hg:`help revisions` and :hg:`help revsets` for more about
4109 4112 specifying revisions.
4110 4113
4111 4114 Returns 0 on successful completion.
4112 4115 '''
4113 4116 with repo.wlock():
4114 4117 return _dograft(ui, repo, *revs, **opts)
4115 4118
4116 4119 def _dograft(ui, repo, *revs, **opts):
4117 4120 if revs and opts.get('rev'):
4118 4121 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4119 4122 'revision ordering!\n'))
4120 4123
4121 4124 revs = list(revs)
4122 4125 revs.extend(opts.get('rev'))
4123 4126
4124 4127 if not opts.get('user') and opts.get('currentuser'):
4125 4128 opts['user'] = ui.username()
4126 4129 if not opts.get('date') and opts.get('currentdate'):
4127 4130 opts['date'] = "%d %d" % util.makedate()
4128 4131
4129 4132 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4130 4133
4131 4134 cont = False
4132 4135 if opts.get('continue'):
4133 4136 cont = True
4134 4137 if revs:
4135 4138 raise error.Abort(_("can't specify --continue and revisions"))
4136 4139 # read in unfinished revisions
4137 4140 try:
4138 4141 nodes = repo.vfs.read('graftstate').splitlines()
4139 4142 revs = [repo[node].rev() for node in nodes]
4140 4143 except IOError as inst:
4141 4144 if inst.errno != errno.ENOENT:
4142 4145 raise
4143 4146 cmdutil.wrongtooltocontinue(repo, _('graft'))
4144 4147 else:
4145 4148 cmdutil.checkunfinished(repo)
4146 4149 cmdutil.bailifchanged(repo)
4147 4150 if not revs:
4148 4151 raise error.Abort(_('no revisions specified'))
4149 4152 revs = scmutil.revrange(repo, revs)
4150 4153
4151 4154 skipped = set()
4152 4155 # check for merges
4153 4156 for rev in repo.revs('%ld and merge()', revs):
4154 4157 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4155 4158 skipped.add(rev)
4156 4159 revs = [r for r in revs if r not in skipped]
4157 4160 if not revs:
4158 4161 return -1
4159 4162
4160 4163 # Don't check in the --continue case, in effect retaining --force across
4161 4164 # --continues. That's because without --force, any revisions we decided to
4162 4165 # skip would have been filtered out here, so they wouldn't have made their
4163 4166 # way to the graftstate. With --force, any revisions we would have otherwise
4164 4167 # skipped would not have been filtered out, and if they hadn't been applied
4165 4168 # already, they'd have been in the graftstate.
4166 4169 if not (cont or opts.get('force')):
4167 4170 # check for ancestors of dest branch
4168 4171 crev = repo['.'].rev()
4169 4172 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4170 4173 # XXX make this lazy in the future
4171 4174 # don't mutate while iterating, create a copy
4172 4175 for rev in list(revs):
4173 4176 if rev in ancestors:
4174 4177 ui.warn(_('skipping ancestor revision %d:%s\n') %
4175 4178 (rev, repo[rev]))
4176 4179 # XXX remove on list is slow
4177 4180 revs.remove(rev)
4178 4181 if not revs:
4179 4182 return -1
4180 4183
4181 4184 # analyze revs for earlier grafts
4182 4185 ids = {}
4183 4186 for ctx in repo.set("%ld", revs):
4184 4187 ids[ctx.hex()] = ctx.rev()
4185 4188 n = ctx.extra().get('source')
4186 4189 if n:
4187 4190 ids[n] = ctx.rev()
4188 4191
4189 4192 # check ancestors for earlier grafts
4190 4193 ui.debug('scanning for duplicate grafts\n')
4191 4194
4192 4195 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4193 4196 ctx = repo[rev]
4194 4197 n = ctx.extra().get('source')
4195 4198 if n in ids:
4196 4199 try:
4197 4200 r = repo[n].rev()
4198 4201 except error.RepoLookupError:
4199 4202 r = None
4200 4203 if r in revs:
4201 4204 ui.warn(_('skipping revision %d:%s '
4202 4205 '(already grafted to %d:%s)\n')
4203 4206 % (r, repo[r], rev, ctx))
4204 4207 revs.remove(r)
4205 4208 elif ids[n] in revs:
4206 4209 if r is None:
4207 4210 ui.warn(_('skipping already grafted revision %d:%s '
4208 4211 '(%d:%s also has unknown origin %s)\n')
4209 4212 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4210 4213 else:
4211 4214 ui.warn(_('skipping already grafted revision %d:%s '
4212 4215 '(%d:%s also has origin %d:%s)\n')
4213 4216 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4214 4217 revs.remove(ids[n])
4215 4218 elif ctx.hex() in ids:
4216 4219 r = ids[ctx.hex()]
4217 4220 ui.warn(_('skipping already grafted revision %d:%s '
4218 4221 '(was grafted from %d:%s)\n') %
4219 4222 (r, repo[r], rev, ctx))
4220 4223 revs.remove(r)
4221 4224 if not revs:
4222 4225 return -1
4223 4226
4224 4227 for pos, ctx in enumerate(repo.set("%ld", revs)):
4225 4228 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4226 4229 ctx.description().split('\n', 1)[0])
4227 4230 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4228 4231 if names:
4229 4232 desc += ' (%s)' % ' '.join(names)
4230 4233 ui.status(_('grafting %s\n') % desc)
4231 4234 if opts.get('dry_run'):
4232 4235 continue
4233 4236
4234 4237 source = ctx.extra().get('source')
4235 4238 extra = {}
4236 4239 if source:
4237 4240 extra['source'] = source
4238 4241 extra['intermediate-source'] = ctx.hex()
4239 4242 else:
4240 4243 extra['source'] = ctx.hex()
4241 4244 user = ctx.user()
4242 4245 if opts.get('user'):
4243 4246 user = opts['user']
4244 4247 date = ctx.date()
4245 4248 if opts.get('date'):
4246 4249 date = opts['date']
4247 4250 message = ctx.description()
4248 4251 if opts.get('log'):
4249 4252 message += '\n(grafted from %s)' % ctx.hex()
4250 4253
4251 4254 # we don't merge the first commit when continuing
4252 4255 if not cont:
4253 4256 # perform the graft merge with p1(rev) as 'ancestor'
4254 4257 try:
4255 4258 # ui.forcemerge is an internal variable, do not document
4256 4259 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4257 4260 'graft')
4258 4261 stats = mergemod.graft(repo, ctx, ctx.p1(),
4259 4262 ['local', 'graft'])
4260 4263 finally:
4261 4264 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4262 4265 # report any conflicts
4263 4266 if stats and stats[3] > 0:
4264 4267 # write out state for --continue
4265 4268 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4266 4269 repo.vfs.write('graftstate', ''.join(nodelines))
4267 4270 extra = ''
4268 4271 if opts.get('user'):
4269 4272 extra += ' --user %s' % util.shellquote(opts['user'])
4270 4273 if opts.get('date'):
4271 4274 extra += ' --date %s' % util.shellquote(opts['date'])
4272 4275 if opts.get('log'):
4273 4276 extra += ' --log'
4274 4277 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
4275 4278 raise error.Abort(
4276 4279 _("unresolved conflicts, can't continue"),
4277 4280 hint=hint)
4278 4281 else:
4279 4282 cont = False
4280 4283
4281 4284 # commit
4282 4285 node = repo.commit(text=message, user=user,
4283 4286 date=date, extra=extra, editor=editor)
4284 4287 if node is None:
4285 4288 ui.warn(
4286 4289 _('note: graft of %d:%s created no changes to commit\n') %
4287 4290 (ctx.rev(), ctx))
4288 4291
4289 4292 # remove state when we complete successfully
4290 4293 if not opts.get('dry_run'):
4291 4294 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4292 4295
4293 4296 return 0
4294 4297
4295 4298 @command('grep',
4296 4299 [('0', 'print0', None, _('end fields with NUL')),
4297 4300 ('', 'all', None, _('print all revisions that match')),
4298 4301 ('a', 'text', None, _('treat all files as text')),
4299 4302 ('f', 'follow', None,
4300 4303 _('follow changeset history,'
4301 4304 ' or file history across copies and renames')),
4302 4305 ('i', 'ignore-case', None, _('ignore case when matching')),
4303 4306 ('l', 'files-with-matches', None,
4304 4307 _('print only filenames and revisions that match')),
4305 4308 ('n', 'line-number', None, _('print matching line numbers')),
4306 4309 ('r', 'rev', [],
4307 4310 _('only search files changed within revision range'), _('REV')),
4308 4311 ('u', 'user', None, _('list the author (long with -v)')),
4309 4312 ('d', 'date', None, _('list the date (short with -q)')),
4310 4313 ] + formatteropts + walkopts,
4311 4314 _('[OPTION]... PATTERN [FILE]...'),
4312 4315 inferrepo=True)
4313 4316 def grep(ui, repo, pattern, *pats, **opts):
4314 4317 """search for a pattern in specified files and revisions
4315 4318
4316 4319 Search revisions of files for a regular expression.
4317 4320
4318 4321 This command behaves differently than Unix grep. It only accepts
4319 4322 Python/Perl regexps. It searches repository history, not the
4320 4323 working directory. It always prints the revision number in which a
4321 4324 match appears.
4322 4325
4323 4326 By default, grep only prints output for the first revision of a
4324 4327 file in which it finds a match. To get it to print every revision
4325 4328 that contains a change in match status ("-" for a match that
4326 4329 becomes a non-match, or "+" for a non-match that becomes a match),
4327 4330 use the --all flag.
4328 4331
4329 4332 Returns 0 if a match is found, 1 otherwise.
4330 4333 """
4331 4334 reflags = re.M
4332 4335 if opts.get('ignore_case'):
4333 4336 reflags |= re.I
4334 4337 try:
4335 4338 regexp = util.re.compile(pattern, reflags)
4336 4339 except re.error as inst:
4337 4340 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4338 4341 return 1
4339 4342 sep, eol = ':', '\n'
4340 4343 if opts.get('print0'):
4341 4344 sep = eol = '\0'
4342 4345
4343 4346 getfile = util.lrucachefunc(repo.file)
4344 4347
4345 4348 def matchlines(body):
4346 4349 begin = 0
4347 4350 linenum = 0
4348 4351 while begin < len(body):
4349 4352 match = regexp.search(body, begin)
4350 4353 if not match:
4351 4354 break
4352 4355 mstart, mend = match.span()
4353 4356 linenum += body.count('\n', begin, mstart) + 1
4354 4357 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4355 4358 begin = body.find('\n', mend) + 1 or len(body) + 1
4356 4359 lend = begin - 1
4357 4360 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4358 4361
4359 4362 class linestate(object):
4360 4363 def __init__(self, line, linenum, colstart, colend):
4361 4364 self.line = line
4362 4365 self.linenum = linenum
4363 4366 self.colstart = colstart
4364 4367 self.colend = colend
4365 4368
4366 4369 def __hash__(self):
4367 4370 return hash((self.linenum, self.line))
4368 4371
4369 4372 def __eq__(self, other):
4370 4373 return self.line == other.line
4371 4374
4372 4375 def findpos(self):
4373 4376 """Iterate all (start, end) indices of matches"""
4374 4377 yield self.colstart, self.colend
4375 4378 p = self.colend
4376 4379 while p < len(self.line):
4377 4380 m = regexp.search(self.line, p)
4378 4381 if not m:
4379 4382 break
4380 4383 yield m.span()
4381 4384 p = m.end()
4382 4385
4383 4386 matches = {}
4384 4387 copies = {}
4385 4388 def grepbody(fn, rev, body):
4386 4389 matches[rev].setdefault(fn, [])
4387 4390 m = matches[rev][fn]
4388 4391 for lnum, cstart, cend, line in matchlines(body):
4389 4392 s = linestate(line, lnum, cstart, cend)
4390 4393 m.append(s)
4391 4394
4392 4395 def difflinestates(a, b):
4393 4396 sm = difflib.SequenceMatcher(None, a, b)
4394 4397 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4395 4398 if tag == 'insert':
4396 4399 for i in xrange(blo, bhi):
4397 4400 yield ('+', b[i])
4398 4401 elif tag == 'delete':
4399 4402 for i in xrange(alo, ahi):
4400 4403 yield ('-', a[i])
4401 4404 elif tag == 'replace':
4402 4405 for i in xrange(alo, ahi):
4403 4406 yield ('-', a[i])
4404 4407 for i in xrange(blo, bhi):
4405 4408 yield ('+', b[i])
4406 4409
4407 4410 def display(fm, fn, ctx, pstates, states):
4408 4411 rev = ctx.rev()
4409 4412 if fm:
4410 4413 formatuser = str
4411 4414 else:
4412 4415 formatuser = ui.shortuser
4413 4416 if ui.quiet:
4414 4417 datefmt = '%Y-%m-%d'
4415 4418 else:
4416 4419 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
4417 4420 found = False
4418 4421 @util.cachefunc
4419 4422 def binary():
4420 4423 flog = getfile(fn)
4421 4424 return util.binary(flog.read(ctx.filenode(fn)))
4422 4425
4423 4426 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
4424 4427 if opts.get('all'):
4425 4428 iter = difflinestates(pstates, states)
4426 4429 else:
4427 4430 iter = [('', l) for l in states]
4428 4431 for change, l in iter:
4429 4432 fm.startitem()
4430 4433 fm.data(node=fm.hexfunc(ctx.node()))
4431 4434 cols = [
4432 4435 ('filename', fn, True),
4433 4436 ('rev', rev, True),
4434 4437 ('linenumber', l.linenum, opts.get('line_number')),
4435 4438 ]
4436 4439 if opts.get('all'):
4437 4440 cols.append(('change', change, True))
4438 4441 cols.extend([
4439 4442 ('user', formatuser(ctx.user()), opts.get('user')),
4440 4443 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
4441 4444 ])
4442 4445 lastcol = next(name for name, data, cond in reversed(cols) if cond)
4443 4446 for name, data, cond in cols:
4444 4447 field = fieldnamemap.get(name, name)
4445 4448 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
4446 4449 if cond and name != lastcol:
4447 4450 fm.plain(sep, label='grep.sep')
4448 4451 if not opts.get('files_with_matches'):
4449 4452 fm.plain(sep, label='grep.sep')
4450 4453 if not opts.get('text') and binary():
4451 4454 fm.plain(_(" Binary file matches"))
4452 4455 else:
4453 4456 displaymatches(fm.nested('texts'), l)
4454 4457 fm.plain(eol)
4455 4458 found = True
4456 4459 if opts.get('files_with_matches'):
4457 4460 break
4458 4461 return found
4459 4462
4460 4463 def displaymatches(fm, l):
4461 4464 p = 0
4462 4465 for s, e in l.findpos():
4463 4466 if p < s:
4464 4467 fm.startitem()
4465 4468 fm.write('text', '%s', l.line[p:s])
4466 4469 fm.data(matched=False)
4467 4470 fm.startitem()
4468 4471 fm.write('text', '%s', l.line[s:e], label='grep.match')
4469 4472 fm.data(matched=True)
4470 4473 p = e
4471 4474 if p < len(l.line):
4472 4475 fm.startitem()
4473 4476 fm.write('text', '%s', l.line[p:])
4474 4477 fm.data(matched=False)
4475 4478 fm.end()
4476 4479
4477 4480 skip = {}
4478 4481 revfiles = {}
4479 4482 matchfn = scmutil.match(repo[None], pats, opts)
4480 4483 found = False
4481 4484 follow = opts.get('follow')
4482 4485
4483 4486 def prep(ctx, fns):
4484 4487 rev = ctx.rev()
4485 4488 pctx = ctx.p1()
4486 4489 parent = pctx.rev()
4487 4490 matches.setdefault(rev, {})
4488 4491 matches.setdefault(parent, {})
4489 4492 files = revfiles.setdefault(rev, [])
4490 4493 for fn in fns:
4491 4494 flog = getfile(fn)
4492 4495 try:
4493 4496 fnode = ctx.filenode(fn)
4494 4497 except error.LookupError:
4495 4498 continue
4496 4499
4497 4500 copied = flog.renamed(fnode)
4498 4501 copy = follow and copied and copied[0]
4499 4502 if copy:
4500 4503 copies.setdefault(rev, {})[fn] = copy
4501 4504 if fn in skip:
4502 4505 if copy:
4503 4506 skip[copy] = True
4504 4507 continue
4505 4508 files.append(fn)
4506 4509
4507 4510 if fn not in matches[rev]:
4508 4511 grepbody(fn, rev, flog.read(fnode))
4509 4512
4510 4513 pfn = copy or fn
4511 4514 if pfn not in matches[parent]:
4512 4515 try:
4513 4516 fnode = pctx.filenode(pfn)
4514 4517 grepbody(pfn, parent, flog.read(fnode))
4515 4518 except error.LookupError:
4516 4519 pass
4517 4520
4518 4521 fm = ui.formatter('grep', opts)
4519 4522 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4520 4523 rev = ctx.rev()
4521 4524 parent = ctx.p1().rev()
4522 4525 for fn in sorted(revfiles.get(rev, [])):
4523 4526 states = matches[rev][fn]
4524 4527 copy = copies.get(rev, {}).get(fn)
4525 4528 if fn in skip:
4526 4529 if copy:
4527 4530 skip[copy] = True
4528 4531 continue
4529 4532 pstates = matches.get(parent, {}).get(copy or fn, [])
4530 4533 if pstates or states:
4531 4534 r = display(fm, fn, ctx, pstates, states)
4532 4535 found = found or r
4533 4536 if r and not opts.get('all'):
4534 4537 skip[fn] = True
4535 4538 if copy:
4536 4539 skip[copy] = True
4537 4540 del matches[rev]
4538 4541 del revfiles[rev]
4539 4542 fm.end()
4540 4543
4541 4544 return not found
4542 4545
4543 4546 @command('heads',
4544 4547 [('r', 'rev', '',
4545 4548 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4546 4549 ('t', 'topo', False, _('show topological heads only')),
4547 4550 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4548 4551 ('c', 'closed', False, _('show normal and closed branch heads')),
4549 4552 ] + templateopts,
4550 4553 _('[-ct] [-r STARTREV] [REV]...'))
4551 4554 def heads(ui, repo, *branchrevs, **opts):
4552 4555 """show branch heads
4553 4556
4554 4557 With no arguments, show all open branch heads in the repository.
4555 4558 Branch heads are changesets that have no descendants on the
4556 4559 same branch. They are where development generally takes place and
4557 4560 are the usual targets for update and merge operations.
4558 4561
4559 4562 If one or more REVs are given, only open branch heads on the
4560 4563 branches associated with the specified changesets are shown. This
4561 4564 means that you can use :hg:`heads .` to see the heads on the
4562 4565 currently checked-out branch.
4563 4566
4564 4567 If -c/--closed is specified, also show branch heads marked closed
4565 4568 (see :hg:`commit --close-branch`).
4566 4569
4567 4570 If STARTREV is specified, only those heads that are descendants of
4568 4571 STARTREV will be displayed.
4569 4572
4570 4573 If -t/--topo is specified, named branch mechanics will be ignored and only
4571 4574 topological heads (changesets with no children) will be shown.
4572 4575
4573 4576 Returns 0 if matching heads are found, 1 if not.
4574 4577 """
4575 4578
4576 4579 start = None
4577 4580 if 'rev' in opts:
4578 4581 start = scmutil.revsingle(repo, opts['rev'], None).node()
4579 4582
4580 4583 if opts.get('topo'):
4581 4584 heads = [repo[h] for h in repo.heads(start)]
4582 4585 else:
4583 4586 heads = []
4584 4587 for branch in repo.branchmap():
4585 4588 heads += repo.branchheads(branch, start, opts.get('closed'))
4586 4589 heads = [repo[h] for h in heads]
4587 4590
4588 4591 if branchrevs:
4589 4592 branches = set(repo[br].branch() for br in branchrevs)
4590 4593 heads = [h for h in heads if h.branch() in branches]
4591 4594
4592 4595 if opts.get('active') and branchrevs:
4593 4596 dagheads = repo.heads(start)
4594 4597 heads = [h for h in heads if h.node() in dagheads]
4595 4598
4596 4599 if branchrevs:
4597 4600 haveheads = set(h.branch() for h in heads)
4598 4601 if branches - haveheads:
4599 4602 headless = ', '.join(b for b in branches - haveheads)
4600 4603 msg = _('no open branch heads found on branches %s')
4601 4604 if opts.get('rev'):
4602 4605 msg += _(' (started at %s)') % opts['rev']
4603 4606 ui.warn((msg + '\n') % headless)
4604 4607
4605 4608 if not heads:
4606 4609 return 1
4607 4610
4608 4611 heads = sorted(heads, key=lambda x: -x.rev())
4609 4612 displayer = cmdutil.show_changeset(ui, repo, opts)
4610 4613 for ctx in heads:
4611 4614 displayer.show(ctx)
4612 4615 displayer.close()
4613 4616
4614 4617 @command('help',
4615 4618 [('e', 'extension', None, _('show only help for extensions')),
4616 4619 ('c', 'command', None, _('show only help for commands')),
4617 4620 ('k', 'keyword', None, _('show topics matching keyword')),
4618 4621 ('s', 'system', [], _('show help for specific platform(s)')),
4619 4622 ],
4620 4623 _('[-ecks] [TOPIC]'),
4621 4624 norepo=True)
4622 4625 def help_(ui, name=None, **opts):
4623 4626 """show help for a given topic or a help overview
4624 4627
4625 4628 With no arguments, print a list of commands with short help messages.
4626 4629
4627 4630 Given a topic, extension, or command name, print help for that
4628 4631 topic.
4629 4632
4630 4633 Returns 0 if successful.
4631 4634 """
4632 4635
4633 4636 textwidth = ui.configint('ui', 'textwidth', 78)
4634 4637 termwidth = ui.termwidth() - 2
4635 4638 if textwidth <= 0 or termwidth < textwidth:
4636 4639 textwidth = termwidth
4637 4640
4638 4641 keep = opts.get('system') or []
4639 4642 if len(keep) == 0:
4640 4643 if sys.platform.startswith('win'):
4641 4644 keep.append('windows')
4642 4645 elif sys.platform == 'OpenVMS':
4643 4646 keep.append('vms')
4644 4647 elif sys.platform == 'plan9':
4645 4648 keep.append('plan9')
4646 4649 else:
4647 4650 keep.append('unix')
4648 4651 keep.append(sys.platform.lower())
4649 4652 if ui.verbose:
4650 4653 keep.append('verbose')
4651 4654
4652 4655 section = None
4653 4656 subtopic = None
4654 4657 if name and '.' in name:
4655 4658 name, remaining = name.split('.', 1)
4656 4659 remaining = encoding.lower(remaining)
4657 4660 if '.' in remaining:
4658 4661 subtopic, section = remaining.split('.', 1)
4659 4662 else:
4660 4663 if name in help.subtopics:
4661 4664 subtopic = remaining
4662 4665 else:
4663 4666 section = remaining
4664 4667
4665 4668 text = help.help_(ui, name, subtopic=subtopic, **opts)
4666 4669
4667 4670 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4668 4671 section=section)
4669 4672
4670 4673 # We could have been given a weird ".foo" section without a name
4671 4674 # to look for, or we could have simply failed to found "foo.bar"
4672 4675 # because bar isn't a section of foo
4673 4676 if section and not (formatted and name):
4674 4677 raise error.Abort(_("help section not found"))
4675 4678
4676 4679 if 'verbose' in pruned:
4677 4680 keep.append('omitted')
4678 4681 else:
4679 4682 keep.append('notomitted')
4680 4683 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4681 4684 section=section)
4682 4685 ui.write(formatted)
4683 4686
4684 4687
4685 4688 @command('identify|id',
4686 4689 [('r', 'rev', '',
4687 4690 _('identify the specified revision'), _('REV')),
4688 4691 ('n', 'num', None, _('show local revision number')),
4689 4692 ('i', 'id', None, _('show global revision id')),
4690 4693 ('b', 'branch', None, _('show branch')),
4691 4694 ('t', 'tags', None, _('show tags')),
4692 4695 ('B', 'bookmarks', None, _('show bookmarks')),
4693 4696 ] + remoteopts,
4694 4697 _('[-nibtB] [-r REV] [SOURCE]'),
4695 4698 optionalrepo=True)
4696 4699 def identify(ui, repo, source=None, rev=None,
4697 4700 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4698 4701 """identify the working directory or specified revision
4699 4702
4700 4703 Print a summary identifying the repository state at REV using one or
4701 4704 two parent hash identifiers, followed by a "+" if the working
4702 4705 directory has uncommitted changes, the branch name (if not default),
4703 4706 a list of tags, and a list of bookmarks.
4704 4707
4705 4708 When REV is not given, print a summary of the current state of the
4706 4709 repository.
4707 4710
4708 4711 Specifying a path to a repository root or Mercurial bundle will
4709 4712 cause lookup to operate on that repository/bundle.
4710 4713
4711 4714 .. container:: verbose
4712 4715
4713 4716 Examples:
4714 4717
4715 4718 - generate a build identifier for the working directory::
4716 4719
4717 4720 hg id --id > build-id.dat
4718 4721
4719 4722 - find the revision corresponding to a tag::
4720 4723
4721 4724 hg id -n -r 1.3
4722 4725
4723 4726 - check the most recent revision of a remote repository::
4724 4727
4725 4728 hg id -r tip http://selenic.com/hg/
4726 4729
4727 4730 See :hg:`log` for generating more information about specific revisions,
4728 4731 including full hash identifiers.
4729 4732
4730 4733 Returns 0 if successful.
4731 4734 """
4732 4735
4733 4736 if not repo and not source:
4734 4737 raise error.Abort(_("there is no Mercurial repository here "
4735 4738 "(.hg not found)"))
4736 4739
4737 4740 if ui.debugflag:
4738 4741 hexfunc = hex
4739 4742 else:
4740 4743 hexfunc = short
4741 4744 default = not (num or id or branch or tags or bookmarks)
4742 4745 output = []
4743 4746 revs = []
4744 4747
4745 4748 if source:
4746 4749 source, branches = hg.parseurl(ui.expandpath(source))
4747 4750 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4748 4751 repo = peer.local()
4749 4752 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4750 4753
4751 4754 if not repo:
4752 4755 if num or branch or tags:
4753 4756 raise error.Abort(
4754 4757 _("can't query remote revision number, branch, or tags"))
4755 4758 if not rev and revs:
4756 4759 rev = revs[0]
4757 4760 if not rev:
4758 4761 rev = "tip"
4759 4762
4760 4763 remoterev = peer.lookup(rev)
4761 4764 if default or id:
4762 4765 output = [hexfunc(remoterev)]
4763 4766
4764 4767 def getbms():
4765 4768 bms = []
4766 4769
4767 4770 if 'bookmarks' in peer.listkeys('namespaces'):
4768 4771 hexremoterev = hex(remoterev)
4769 4772 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4770 4773 if bmr == hexremoterev]
4771 4774
4772 4775 return sorted(bms)
4773 4776
4774 4777 if bookmarks:
4775 4778 output.extend(getbms())
4776 4779 elif default and not ui.quiet:
4777 4780 # multiple bookmarks for a single parent separated by '/'
4778 4781 bm = '/'.join(getbms())
4779 4782 if bm:
4780 4783 output.append(bm)
4781 4784 else:
4782 4785 ctx = scmutil.revsingle(repo, rev, None)
4783 4786
4784 4787 if ctx.rev() is None:
4785 4788 ctx = repo[None]
4786 4789 parents = ctx.parents()
4787 4790 taglist = []
4788 4791 for p in parents:
4789 4792 taglist.extend(p.tags())
4790 4793
4791 4794 changed = ""
4792 4795 if default or id or num:
4793 4796 if (any(repo.status())
4794 4797 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4795 4798 changed = '+'
4796 4799 if default or id:
4797 4800 output = ["%s%s" %
4798 4801 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4799 4802 if num:
4800 4803 output.append("%s%s" %
4801 4804 ('+'.join([str(p.rev()) for p in parents]), changed))
4802 4805 else:
4803 4806 if default or id:
4804 4807 output = [hexfunc(ctx.node())]
4805 4808 if num:
4806 4809 output.append(str(ctx.rev()))
4807 4810 taglist = ctx.tags()
4808 4811
4809 4812 if default and not ui.quiet:
4810 4813 b = ctx.branch()
4811 4814 if b != 'default':
4812 4815 output.append("(%s)" % b)
4813 4816
4814 4817 # multiple tags for a single parent separated by '/'
4815 4818 t = '/'.join(taglist)
4816 4819 if t:
4817 4820 output.append(t)
4818 4821
4819 4822 # multiple bookmarks for a single parent separated by '/'
4820 4823 bm = '/'.join(ctx.bookmarks())
4821 4824 if bm:
4822 4825 output.append(bm)
4823 4826 else:
4824 4827 if branch:
4825 4828 output.append(ctx.branch())
4826 4829
4827 4830 if tags:
4828 4831 output.extend(taglist)
4829 4832
4830 4833 if bookmarks:
4831 4834 output.extend(ctx.bookmarks())
4832 4835
4833 4836 ui.write("%s\n" % ' '.join(output))
4834 4837
4835 4838 @command('import|patch',
4836 4839 [('p', 'strip', 1,
4837 4840 _('directory strip option for patch. This has the same '
4838 4841 'meaning as the corresponding patch option'), _('NUM')),
4839 4842 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4840 4843 ('e', 'edit', False, _('invoke editor on commit messages')),
4841 4844 ('f', 'force', None,
4842 4845 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4843 4846 ('', 'no-commit', None,
4844 4847 _("don't commit, just update the working directory")),
4845 4848 ('', 'bypass', None,
4846 4849 _("apply patch without touching the working directory")),
4847 4850 ('', 'partial', None,
4848 4851 _('commit even if some hunks fail')),
4849 4852 ('', 'exact', None,
4850 4853 _('abort if patch would apply lossily')),
4851 4854 ('', 'prefix', '',
4852 4855 _('apply patch to subdirectory'), _('DIR')),
4853 4856 ('', 'import-branch', None,
4854 4857 _('use any branch information in patch (implied by --exact)'))] +
4855 4858 commitopts + commitopts2 + similarityopts,
4856 4859 _('[OPTION]... PATCH...'))
4857 4860 def import_(ui, repo, patch1=None, *patches, **opts):
4858 4861 """import an ordered set of patches
4859 4862
4860 4863 Import a list of patches and commit them individually (unless
4861 4864 --no-commit is specified).
4862 4865
4863 4866 To read a patch from standard input, use "-" as the patch name. If
4864 4867 a URL is specified, the patch will be downloaded from there.
4865 4868
4866 4869 Import first applies changes to the working directory (unless
4867 4870 --bypass is specified), import will abort if there are outstanding
4868 4871 changes.
4869 4872
4870 4873 Use --bypass to apply and commit patches directly to the
4871 4874 repository, without affecting the working directory. Without
4872 4875 --exact, patches will be applied on top of the working directory
4873 4876 parent revision.
4874 4877
4875 4878 You can import a patch straight from a mail message. Even patches
4876 4879 as attachments work (to use the body part, it must have type
4877 4880 text/plain or text/x-patch). From and Subject headers of email
4878 4881 message are used as default committer and commit message. All
4879 4882 text/plain body parts before first diff are added to the commit
4880 4883 message.
4881 4884
4882 4885 If the imported patch was generated by :hg:`export`, user and
4883 4886 description from patch override values from message headers and
4884 4887 body. Values given on command line with -m/--message and -u/--user
4885 4888 override these.
4886 4889
4887 4890 If --exact is specified, import will set the working directory to
4888 4891 the parent of each patch before applying it, and will abort if the
4889 4892 resulting changeset has a different ID than the one recorded in
4890 4893 the patch. This will guard against various ways that portable
4891 4894 patch formats and mail systems might fail to transfer Mercurial
4892 4895 data or metadata. See :hg:`bundle` for lossless transmission.
4893 4896
4894 4897 Use --partial to ensure a changeset will be created from the patch
4895 4898 even if some hunks fail to apply. Hunks that fail to apply will be
4896 4899 written to a <target-file>.rej file. Conflicts can then be resolved
4897 4900 by hand before :hg:`commit --amend` is run to update the created
4898 4901 changeset. This flag exists to let people import patches that
4899 4902 partially apply without losing the associated metadata (author,
4900 4903 date, description, ...).
4901 4904
4902 4905 .. note::
4903 4906
4904 4907 When no hunks apply cleanly, :hg:`import --partial` will create
4905 4908 an empty changeset, importing only the patch metadata.
4906 4909
4907 4910 With -s/--similarity, hg will attempt to discover renames and
4908 4911 copies in the patch in the same way as :hg:`addremove`.
4909 4912
4910 4913 It is possible to use external patch programs to perform the patch
4911 4914 by setting the ``ui.patch`` configuration option. For the default
4912 4915 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4913 4916 See :hg:`help config` for more information about configuration
4914 4917 files and how to use these options.
4915 4918
4916 4919 See :hg:`help dates` for a list of formats valid for -d/--date.
4917 4920
4918 4921 .. container:: verbose
4919 4922
4920 4923 Examples:
4921 4924
4922 4925 - import a traditional patch from a website and detect renames::
4923 4926
4924 4927 hg import -s 80 http://example.com/bugfix.patch
4925 4928
4926 4929 - import a changeset from an hgweb server::
4927 4930
4928 4931 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4929 4932
4930 4933 - import all the patches in an Unix-style mbox::
4931 4934
4932 4935 hg import incoming-patches.mbox
4933 4936
4934 4937 - attempt to exactly restore an exported changeset (not always
4935 4938 possible)::
4936 4939
4937 4940 hg import --exact proposed-fix.patch
4938 4941
4939 4942 - use an external tool to apply a patch which is too fuzzy for
4940 4943 the default internal tool.
4941 4944
4942 4945 hg import --config ui.patch="patch --merge" fuzzy.patch
4943 4946
4944 4947 - change the default fuzzing from 2 to a less strict 7
4945 4948
4946 4949 hg import --config ui.fuzz=7 fuzz.patch
4947 4950
4948 4951 Returns 0 on success, 1 on partial success (see --partial).
4949 4952 """
4950 4953
4951 4954 if not patch1:
4952 4955 raise error.Abort(_('need at least one patch to import'))
4953 4956
4954 4957 patches = (patch1,) + patches
4955 4958
4956 4959 date = opts.get('date')
4957 4960 if date:
4958 4961 opts['date'] = util.parsedate(date)
4959 4962
4960 4963 exact = opts.get('exact')
4961 4964 update = not opts.get('bypass')
4962 4965 if not update and opts.get('no_commit'):
4963 4966 raise error.Abort(_('cannot use --no-commit with --bypass'))
4964 4967 try:
4965 4968 sim = float(opts.get('similarity') or 0)
4966 4969 except ValueError:
4967 4970 raise error.Abort(_('similarity must be a number'))
4968 4971 if sim < 0 or sim > 100:
4969 4972 raise error.Abort(_('similarity must be between 0 and 100'))
4970 4973 if sim and not update:
4971 4974 raise error.Abort(_('cannot use --similarity with --bypass'))
4972 4975 if exact:
4973 4976 if opts.get('edit'):
4974 4977 raise error.Abort(_('cannot use --exact with --edit'))
4975 4978 if opts.get('prefix'):
4976 4979 raise error.Abort(_('cannot use --exact with --prefix'))
4977 4980
4978 4981 base = opts["base"]
4979 4982 wlock = dsguard = lock = tr = None
4980 4983 msgs = []
4981 4984 ret = 0
4982 4985
4983 4986
4984 4987 try:
4985 4988 wlock = repo.wlock()
4986 4989
4987 4990 if update:
4988 4991 cmdutil.checkunfinished(repo)
4989 4992 if (exact or not opts.get('force')):
4990 4993 cmdutil.bailifchanged(repo)
4991 4994
4992 4995 if not opts.get('no_commit'):
4993 4996 lock = repo.lock()
4994 4997 tr = repo.transaction('import')
4995 4998 else:
4996 4999 dsguard = cmdutil.dirstateguard(repo, 'import')
4997 5000 parents = repo[None].parents()
4998 5001 for patchurl in patches:
4999 5002 if patchurl == '-':
5000 5003 ui.status(_('applying patch from stdin\n'))
5001 5004 patchfile = ui.fin
5002 5005 patchurl = 'stdin' # for error message
5003 5006 else:
5004 5007 patchurl = os.path.join(base, patchurl)
5005 5008 ui.status(_('applying %s\n') % patchurl)
5006 5009 patchfile = hg.openpath(ui, patchurl)
5007 5010
5008 5011 haspatch = False
5009 5012 for hunk in patch.split(patchfile):
5010 5013 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
5011 5014 parents, opts,
5012 5015 msgs, hg.clean)
5013 5016 if msg:
5014 5017 haspatch = True
5015 5018 ui.note(msg + '\n')
5016 5019 if update or exact:
5017 5020 parents = repo[None].parents()
5018 5021 else:
5019 5022 parents = [repo[node]]
5020 5023 if rej:
5021 5024 ui.write_err(_("patch applied partially\n"))
5022 5025 ui.write_err(_("(fix the .rej files and run "
5023 5026 "`hg commit --amend`)\n"))
5024 5027 ret = 1
5025 5028 break
5026 5029
5027 5030 if not haspatch:
5028 5031 raise error.Abort(_('%s: no diffs found') % patchurl)
5029 5032
5030 5033 if tr:
5031 5034 tr.close()
5032 5035 if msgs:
5033 5036 repo.savecommitmessage('\n* * *\n'.join(msgs))
5034 5037 if dsguard:
5035 5038 dsguard.close()
5036 5039 return ret
5037 5040 finally:
5038 5041 if tr:
5039 5042 tr.release()
5040 5043 release(lock, dsguard, wlock)
5041 5044
5042 5045 @command('incoming|in',
5043 5046 [('f', 'force', None,
5044 5047 _('run even if remote repository is unrelated')),
5045 5048 ('n', 'newest-first', None, _('show newest record first')),
5046 5049 ('', 'bundle', '',
5047 5050 _('file to store the bundles into'), _('FILE')),
5048 5051 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5049 5052 ('B', 'bookmarks', False, _("compare bookmarks")),
5050 5053 ('b', 'branch', [],
5051 5054 _('a specific branch you would like to pull'), _('BRANCH')),
5052 5055 ] + logopts + remoteopts + subrepoopts,
5053 5056 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
5054 5057 def incoming(ui, repo, source="default", **opts):
5055 5058 """show new changesets found in source
5056 5059
5057 5060 Show new changesets found in the specified path/URL or the default
5058 5061 pull location. These are the changesets that would have been pulled
5059 5062 if a pull at the time you issued this command.
5060 5063
5061 5064 See pull for valid source format details.
5062 5065
5063 5066 .. container:: verbose
5064 5067
5065 5068 With -B/--bookmarks, the result of bookmark comparison between
5066 5069 local and remote repositories is displayed. With -v/--verbose,
5067 5070 status is also displayed for each bookmark like below::
5068 5071
5069 5072 BM1 01234567890a added
5070 5073 BM2 1234567890ab advanced
5071 5074 BM3 234567890abc diverged
5072 5075 BM4 34567890abcd changed
5073 5076
5074 5077 The action taken locally when pulling depends on the
5075 5078 status of each bookmark:
5076 5079
5077 5080 :``added``: pull will create it
5078 5081 :``advanced``: pull will update it
5079 5082 :``diverged``: pull will create a divergent bookmark
5080 5083 :``changed``: result depends on remote changesets
5081 5084
5082 5085 From the point of view of pulling behavior, bookmark
5083 5086 existing only in the remote repository are treated as ``added``,
5084 5087 even if it is in fact locally deleted.
5085 5088
5086 5089 .. container:: verbose
5087 5090
5088 5091 For remote repository, using --bundle avoids downloading the
5089 5092 changesets twice if the incoming is followed by a pull.
5090 5093
5091 5094 Examples:
5092 5095
5093 5096 - show incoming changes with patches and full description::
5094 5097
5095 5098 hg incoming -vp
5096 5099
5097 5100 - show incoming changes excluding merges, store a bundle::
5098 5101
5099 5102 hg in -vpM --bundle incoming.hg
5100 5103 hg pull incoming.hg
5101 5104
5102 5105 - briefly list changes inside a bundle::
5103 5106
5104 5107 hg in changes.hg -T "{desc|firstline}\\n"
5105 5108
5106 5109 Returns 0 if there are incoming changes, 1 otherwise.
5107 5110 """
5108 5111 if opts.get('graph'):
5109 5112 cmdutil.checkunsupportedgraphflags([], opts)
5110 5113 def display(other, chlist, displayer):
5111 5114 revdag = cmdutil.graphrevs(other, chlist, opts)
5112 5115 cmdutil.displaygraph(ui, repo, revdag, displayer,
5113 5116 graphmod.asciiedges)
5114 5117
5115 5118 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5116 5119 return 0
5117 5120
5118 5121 if opts.get('bundle') and opts.get('subrepos'):
5119 5122 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5120 5123
5121 5124 if opts.get('bookmarks'):
5122 5125 source, branches = hg.parseurl(ui.expandpath(source),
5123 5126 opts.get('branch'))
5124 5127 other = hg.peer(repo, opts, source)
5125 5128 if 'bookmarks' not in other.listkeys('namespaces'):
5126 5129 ui.warn(_("remote doesn't support bookmarks\n"))
5127 5130 return 0
5128 5131 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5129 5132 return bookmarks.incoming(ui, repo, other)
5130 5133
5131 5134 repo._subtoppath = ui.expandpath(source)
5132 5135 try:
5133 5136 return hg.incoming(ui, repo, source, opts)
5134 5137 finally:
5135 5138 del repo._subtoppath
5136 5139
5137 5140
5138 5141 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5139 5142 norepo=True)
5140 5143 def init(ui, dest=".", **opts):
5141 5144 """create a new repository in the given directory
5142 5145
5143 5146 Initialize a new repository in the given directory. If the given
5144 5147 directory does not exist, it will be created.
5145 5148
5146 5149 If no directory is given, the current directory is used.
5147 5150
5148 5151 It is possible to specify an ``ssh://`` URL as the destination.
5149 5152 See :hg:`help urls` for more information.
5150 5153
5151 5154 Returns 0 on success.
5152 5155 """
5153 5156 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5154 5157
5155 5158 @command('locate',
5156 5159 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5157 5160 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5158 5161 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5159 5162 ] + walkopts,
5160 5163 _('[OPTION]... [PATTERN]...'))
5161 5164 def locate(ui, repo, *pats, **opts):
5162 5165 """locate files matching specific patterns (DEPRECATED)
5163 5166
5164 5167 Print files under Mercurial control in the working directory whose
5165 5168 names match the given patterns.
5166 5169
5167 5170 By default, this command searches all directories in the working
5168 5171 directory. To search just the current directory and its
5169 5172 subdirectories, use "--include .".
5170 5173
5171 5174 If no patterns are given to match, this command prints the names
5172 5175 of all files under Mercurial control in the working directory.
5173 5176
5174 5177 If you want to feed the output of this command into the "xargs"
5175 5178 command, use the -0 option to both this command and "xargs". This
5176 5179 will avoid the problem of "xargs" treating single filenames that
5177 5180 contain whitespace as multiple filenames.
5178 5181
5179 5182 See :hg:`help files` for a more versatile command.
5180 5183
5181 5184 Returns 0 if a match is found, 1 otherwise.
5182 5185 """
5183 5186 if opts.get('print0'):
5184 5187 end = '\0'
5185 5188 else:
5186 5189 end = '\n'
5187 5190 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5188 5191
5189 5192 ret = 1
5190 5193 ctx = repo[rev]
5191 5194 m = scmutil.match(ctx, pats, opts, default='relglob',
5192 5195 badfn=lambda x, y: False)
5193 5196
5194 5197 for abs in ctx.matches(m):
5195 5198 if opts.get('fullpath'):
5196 5199 ui.write(repo.wjoin(abs), end)
5197 5200 else:
5198 5201 ui.write(((pats and m.rel(abs)) or abs), end)
5199 5202 ret = 0
5200 5203
5201 5204 return ret
5202 5205
5203 5206 @command('^log|history',
5204 5207 [('f', 'follow', None,
5205 5208 _('follow changeset history, or file history across copies and renames')),
5206 5209 ('', 'follow-first', None,
5207 5210 _('only follow the first parent of merge changesets (DEPRECATED)')),
5208 5211 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5209 5212 ('C', 'copies', None, _('show copied files')),
5210 5213 ('k', 'keyword', [],
5211 5214 _('do case-insensitive search for a given text'), _('TEXT')),
5212 5215 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5213 5216 ('', 'removed', None, _('include revisions where files were removed')),
5214 5217 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5215 5218 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5216 5219 ('', 'only-branch', [],
5217 5220 _('show only changesets within the given named branch (DEPRECATED)'),
5218 5221 _('BRANCH')),
5219 5222 ('b', 'branch', [],
5220 5223 _('show changesets within the given named branch'), _('BRANCH')),
5221 5224 ('P', 'prune', [],
5222 5225 _('do not display revision or any of its ancestors'), _('REV')),
5223 5226 ] + logopts + walkopts,
5224 5227 _('[OPTION]... [FILE]'),
5225 5228 inferrepo=True)
5226 5229 def log(ui, repo, *pats, **opts):
5227 5230 """show revision history of entire repository or files
5228 5231
5229 5232 Print the revision history of the specified files or the entire
5230 5233 project.
5231 5234
5232 5235 If no revision range is specified, the default is ``tip:0`` unless
5233 5236 --follow is set, in which case the working directory parent is
5234 5237 used as the starting revision.
5235 5238
5236 5239 File history is shown without following rename or copy history of
5237 5240 files. Use -f/--follow with a filename to follow history across
5238 5241 renames and copies. --follow without a filename will only show
5239 5242 ancestors or descendants of the starting revision.
5240 5243
5241 5244 By default this command prints revision number and changeset id,
5242 5245 tags, non-trivial parents, user, date and time, and a summary for
5243 5246 each commit. When the -v/--verbose switch is used, the list of
5244 5247 changed files and full commit message are shown.
5245 5248
5246 5249 With --graph the revisions are shown as an ASCII art DAG with the most
5247 5250 recent changeset at the top.
5248 5251 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5249 5252 and '+' represents a fork where the changeset from the lines below is a
5250 5253 parent of the 'o' merge on the same line.
5251 5254
5252 5255 .. note::
5253 5256
5254 5257 :hg:`log --patch` may generate unexpected diff output for merge
5255 5258 changesets, as it will only compare the merge changeset against
5256 5259 its first parent. Also, only files different from BOTH parents
5257 5260 will appear in files:.
5258 5261
5259 5262 .. note::
5260 5263
5261 5264 For performance reasons, :hg:`log FILE` may omit duplicate changes
5262 5265 made on branches and will not show removals or mode changes. To
5263 5266 see all such changes, use the --removed switch.
5264 5267
5265 5268 .. container:: verbose
5266 5269
5267 5270 Some examples:
5268 5271
5269 5272 - changesets with full descriptions and file lists::
5270 5273
5271 5274 hg log -v
5272 5275
5273 5276 - changesets ancestral to the working directory::
5274 5277
5275 5278 hg log -f
5276 5279
5277 5280 - last 10 commits on the current branch::
5278 5281
5279 5282 hg log -l 10 -b .
5280 5283
5281 5284 - changesets showing all modifications of a file, including removals::
5282 5285
5283 5286 hg log --removed file.c
5284 5287
5285 5288 - all changesets that touch a directory, with diffs, excluding merges::
5286 5289
5287 5290 hg log -Mp lib/
5288 5291
5289 5292 - all revision numbers that match a keyword::
5290 5293
5291 5294 hg log -k bug --template "{rev}\\n"
5292 5295
5293 5296 - the full hash identifier of the working directory parent::
5294 5297
5295 5298 hg log -r . --template "{node}\\n"
5296 5299
5297 5300 - list available log templates::
5298 5301
5299 5302 hg log -T list
5300 5303
5301 5304 - check if a given changeset is included in a tagged release::
5302 5305
5303 5306 hg log -r "a21ccf and ancestor(1.9)"
5304 5307
5305 5308 - find all changesets by some user in a date range::
5306 5309
5307 5310 hg log -k alice -d "may 2008 to jul 2008"
5308 5311
5309 5312 - summary of all changesets after the last tag::
5310 5313
5311 5314 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5312 5315
5313 5316 See :hg:`help dates` for a list of formats valid for -d/--date.
5314 5317
5315 5318 See :hg:`help revisions` and :hg:`help revsets` for more about
5316 5319 specifying and ordering revisions.
5317 5320
5318 5321 See :hg:`help templates` for more about pre-packaged styles and
5319 5322 specifying custom templates.
5320 5323
5321 5324 Returns 0 on success.
5322 5325
5323 5326 """
5324 5327 if opts.get('follow') and opts.get('rev'):
5325 5328 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5326 5329 del opts['follow']
5327 5330
5328 5331 if opts.get('graph'):
5329 5332 return cmdutil.graphlog(ui, repo, *pats, **opts)
5330 5333
5331 5334 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5332 5335 limit = cmdutil.loglimit(opts)
5333 5336 count = 0
5334 5337
5335 5338 getrenamed = None
5336 5339 if opts.get('copies'):
5337 5340 endrev = None
5338 5341 if opts.get('rev'):
5339 5342 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5340 5343 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5341 5344
5342 5345 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5343 5346 for rev in revs:
5344 5347 if count == limit:
5345 5348 break
5346 5349 ctx = repo[rev]
5347 5350 copies = None
5348 5351 if getrenamed is not None and rev:
5349 5352 copies = []
5350 5353 for fn in ctx.files():
5351 5354 rename = getrenamed(fn, rev)
5352 5355 if rename:
5353 5356 copies.append((fn, rename[0]))
5354 5357 if filematcher:
5355 5358 revmatchfn = filematcher(ctx.rev())
5356 5359 else:
5357 5360 revmatchfn = None
5358 5361 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5359 5362 if displayer.flush(ctx):
5360 5363 count += 1
5361 5364
5362 5365 displayer.close()
5363 5366
5364 5367 @command('manifest',
5365 5368 [('r', 'rev', '', _('revision to display'), _('REV')),
5366 5369 ('', 'all', False, _("list files from all revisions"))]
5367 5370 + formatteropts,
5368 5371 _('[-r REV]'))
5369 5372 def manifest(ui, repo, node=None, rev=None, **opts):
5370 5373 """output the current or given revision of the project manifest
5371 5374
5372 5375 Print a list of version controlled files for the given revision.
5373 5376 If no revision is given, the first parent of the working directory
5374 5377 is used, or the null revision if no revision is checked out.
5375 5378
5376 5379 With -v, print file permissions, symlink and executable bits.
5377 5380 With --debug, print file revision hashes.
5378 5381
5379 5382 If option --all is specified, the list of all files from all revisions
5380 5383 is printed. This includes deleted and renamed files.
5381 5384
5382 5385 Returns 0 on success.
5383 5386 """
5384 5387
5385 5388 fm = ui.formatter('manifest', opts)
5386 5389
5387 5390 if opts.get('all'):
5388 5391 if rev or node:
5389 5392 raise error.Abort(_("can't specify a revision with --all"))
5390 5393
5391 5394 res = []
5392 5395 prefix = "data/"
5393 5396 suffix = ".i"
5394 5397 plen = len(prefix)
5395 5398 slen = len(suffix)
5396 5399 with repo.lock():
5397 5400 for fn, b, size in repo.store.datafiles():
5398 5401 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5399 5402 res.append(fn[plen:-slen])
5400 5403 for f in res:
5401 5404 fm.startitem()
5402 5405 fm.write("path", '%s\n', f)
5403 5406 fm.end()
5404 5407 return
5405 5408
5406 5409 if rev and node:
5407 5410 raise error.Abort(_("please specify just one revision"))
5408 5411
5409 5412 if not node:
5410 5413 node = rev
5411 5414
5412 5415 char = {'l': '@', 'x': '*', '': ''}
5413 5416 mode = {'l': '644', 'x': '755', '': '644'}
5414 5417 ctx = scmutil.revsingle(repo, node)
5415 5418 mf = ctx.manifest()
5416 5419 for f in ctx:
5417 5420 fm.startitem()
5418 5421 fl = ctx[f].flags()
5419 5422 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5420 5423 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5421 5424 fm.write('path', '%s\n', f)
5422 5425 fm.end()
5423 5426
5424 5427 @command('^merge',
5425 5428 [('f', 'force', None,
5426 5429 _('force a merge including outstanding changes (DEPRECATED)')),
5427 5430 ('r', 'rev', '', _('revision to merge'), _('REV')),
5428 5431 ('P', 'preview', None,
5429 5432 _('review revisions to merge (no merge is performed)'))
5430 5433 ] + mergetoolopts,
5431 5434 _('[-P] [[-r] REV]'))
5432 5435 def merge(ui, repo, node=None, **opts):
5433 5436 """merge another revision into working directory
5434 5437
5435 5438 The current working directory is updated with all changes made in
5436 5439 the requested revision since the last common predecessor revision.
5437 5440
5438 5441 Files that changed between either parent are marked as changed for
5439 5442 the next commit and a commit must be performed before any further
5440 5443 updates to the repository are allowed. The next commit will have
5441 5444 two parents.
5442 5445
5443 5446 ``--tool`` can be used to specify the merge tool used for file
5444 5447 merges. It overrides the HGMERGE environment variable and your
5445 5448 configuration files. See :hg:`help merge-tools` for options.
5446 5449
5447 5450 If no revision is specified, the working directory's parent is a
5448 5451 head revision, and the current branch contains exactly one other
5449 5452 head, the other head is merged with by default. Otherwise, an
5450 5453 explicit revision with which to merge with must be provided.
5451 5454
5452 5455 See :hg:`help resolve` for information on handling file conflicts.
5453 5456
5454 5457 To undo an uncommitted merge, use :hg:`update --clean .` which
5455 5458 will check out a clean copy of the original merge parent, losing
5456 5459 all changes.
5457 5460
5458 5461 Returns 0 on success, 1 if there are unresolved files.
5459 5462 """
5460 5463
5461 5464 if opts.get('rev') and node:
5462 5465 raise error.Abort(_("please specify just one revision"))
5463 5466 if not node:
5464 5467 node = opts.get('rev')
5465 5468
5466 5469 if node:
5467 5470 node = scmutil.revsingle(repo, node).node()
5468 5471
5469 5472 if not node:
5470 5473 node = repo[destutil.destmerge(repo)].node()
5471 5474
5472 5475 if opts.get('preview'):
5473 5476 # find nodes that are ancestors of p2 but not of p1
5474 5477 p1 = repo.lookup('.')
5475 5478 p2 = repo.lookup(node)
5476 5479 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5477 5480
5478 5481 displayer = cmdutil.show_changeset(ui, repo, opts)
5479 5482 for node in nodes:
5480 5483 displayer.show(repo[node])
5481 5484 displayer.close()
5482 5485 return 0
5483 5486
5484 5487 try:
5485 5488 # ui.forcemerge is an internal variable, do not document
5486 5489 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5487 5490 force = opts.get('force')
5488 5491 return hg.merge(repo, node, force=force, mergeforce=force)
5489 5492 finally:
5490 5493 ui.setconfig('ui', 'forcemerge', '', 'merge')
5491 5494
5492 5495 @command('outgoing|out',
5493 5496 [('f', 'force', None, _('run even when the destination is unrelated')),
5494 5497 ('r', 'rev', [],
5495 5498 _('a changeset intended to be included in the destination'), _('REV')),
5496 5499 ('n', 'newest-first', None, _('show newest record first')),
5497 5500 ('B', 'bookmarks', False, _('compare bookmarks')),
5498 5501 ('b', 'branch', [], _('a specific branch you would like to push'),
5499 5502 _('BRANCH')),
5500 5503 ] + logopts + remoteopts + subrepoopts,
5501 5504 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5502 5505 def outgoing(ui, repo, dest=None, **opts):
5503 5506 """show changesets not found in the destination
5504 5507
5505 5508 Show changesets not found in the specified destination repository
5506 5509 or the default push location. These are the changesets that would
5507 5510 be pushed if a push was requested.
5508 5511
5509 5512 See pull for details of valid destination formats.
5510 5513
5511 5514 .. container:: verbose
5512 5515
5513 5516 With -B/--bookmarks, the result of bookmark comparison between
5514 5517 local and remote repositories is displayed. With -v/--verbose,
5515 5518 status is also displayed for each bookmark like below::
5516 5519
5517 5520 BM1 01234567890a added
5518 5521 BM2 deleted
5519 5522 BM3 234567890abc advanced
5520 5523 BM4 34567890abcd diverged
5521 5524 BM5 4567890abcde changed
5522 5525
5523 5526 The action taken when pushing depends on the
5524 5527 status of each bookmark:
5525 5528
5526 5529 :``added``: push with ``-B`` will create it
5527 5530 :``deleted``: push with ``-B`` will delete it
5528 5531 :``advanced``: push will update it
5529 5532 :``diverged``: push with ``-B`` will update it
5530 5533 :``changed``: push with ``-B`` will update it
5531 5534
5532 5535 From the point of view of pushing behavior, bookmarks
5533 5536 existing only in the remote repository are treated as
5534 5537 ``deleted``, even if it is in fact added remotely.
5535 5538
5536 5539 Returns 0 if there are outgoing changes, 1 otherwise.
5537 5540 """
5538 5541 if opts.get('graph'):
5539 5542 cmdutil.checkunsupportedgraphflags([], opts)
5540 5543 o, other = hg._outgoing(ui, repo, dest, opts)
5541 5544 if not o:
5542 5545 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5543 5546 return
5544 5547
5545 5548 revdag = cmdutil.graphrevs(repo, o, opts)
5546 5549 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5547 5550 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5548 5551 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5549 5552 return 0
5550 5553
5551 5554 if opts.get('bookmarks'):
5552 5555 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5553 5556 dest, branches = hg.parseurl(dest, opts.get('branch'))
5554 5557 other = hg.peer(repo, opts, dest)
5555 5558 if 'bookmarks' not in other.listkeys('namespaces'):
5556 5559 ui.warn(_("remote doesn't support bookmarks\n"))
5557 5560 return 0
5558 5561 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5559 5562 return bookmarks.outgoing(ui, repo, other)
5560 5563
5561 5564 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5562 5565 try:
5563 5566 return hg.outgoing(ui, repo, dest, opts)
5564 5567 finally:
5565 5568 del repo._subtoppath
5566 5569
5567 5570 @command('parents',
5568 5571 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5569 5572 ] + templateopts,
5570 5573 _('[-r REV] [FILE]'),
5571 5574 inferrepo=True)
5572 5575 def parents(ui, repo, file_=None, **opts):
5573 5576 """show the parents of the working directory or revision (DEPRECATED)
5574 5577
5575 5578 Print the working directory's parent revisions. If a revision is
5576 5579 given via -r/--rev, the parent of that revision will be printed.
5577 5580 If a file argument is given, the revision in which the file was
5578 5581 last changed (before the working directory revision or the
5579 5582 argument to --rev if given) is printed.
5580 5583
5581 5584 This command is equivalent to::
5582 5585
5583 5586 hg log -r "p1()+p2()" or
5584 5587 hg log -r "p1(REV)+p2(REV)" or
5585 5588 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5586 5589 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5587 5590
5588 5591 See :hg:`summary` and :hg:`help revsets` for related information.
5589 5592
5590 5593 Returns 0 on success.
5591 5594 """
5592 5595
5593 5596 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5594 5597
5595 5598 if file_:
5596 5599 m = scmutil.match(ctx, (file_,), opts)
5597 5600 if m.anypats() or len(m.files()) != 1:
5598 5601 raise error.Abort(_('can only specify an explicit filename'))
5599 5602 file_ = m.files()[0]
5600 5603 filenodes = []
5601 5604 for cp in ctx.parents():
5602 5605 if not cp:
5603 5606 continue
5604 5607 try:
5605 5608 filenodes.append(cp.filenode(file_))
5606 5609 except error.LookupError:
5607 5610 pass
5608 5611 if not filenodes:
5609 5612 raise error.Abort(_("'%s' not found in manifest!") % file_)
5610 5613 p = []
5611 5614 for fn in filenodes:
5612 5615 fctx = repo.filectx(file_, fileid=fn)
5613 5616 p.append(fctx.node())
5614 5617 else:
5615 5618 p = [cp.node() for cp in ctx.parents()]
5616 5619
5617 5620 displayer = cmdutil.show_changeset(ui, repo, opts)
5618 5621 for n in p:
5619 5622 if n != nullid:
5620 5623 displayer.show(repo[n])
5621 5624 displayer.close()
5622 5625
5623 5626 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5624 5627 def paths(ui, repo, search=None, **opts):
5625 5628 """show aliases for remote repositories
5626 5629
5627 5630 Show definition of symbolic path name NAME. If no name is given,
5628 5631 show definition of all available names.
5629 5632
5630 5633 Option -q/--quiet suppresses all output when searching for NAME
5631 5634 and shows only the path names when listing all definitions.
5632 5635
5633 5636 Path names are defined in the [paths] section of your
5634 5637 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5635 5638 repository, ``.hg/hgrc`` is used, too.
5636 5639
5637 5640 The path names ``default`` and ``default-push`` have a special
5638 5641 meaning. When performing a push or pull operation, they are used
5639 5642 as fallbacks if no location is specified on the command-line.
5640 5643 When ``default-push`` is set, it will be used for push and
5641 5644 ``default`` will be used for pull; otherwise ``default`` is used
5642 5645 as the fallback for both. When cloning a repository, the clone
5643 5646 source is written as ``default`` in ``.hg/hgrc``.
5644 5647
5645 5648 .. note::
5646 5649
5647 5650 ``default`` and ``default-push`` apply to all inbound (e.g.
5648 5651 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5649 5652 and :hg:`bundle`) operations.
5650 5653
5651 5654 See :hg:`help urls` for more information.
5652 5655
5653 5656 Returns 0 on success.
5654 5657 """
5655 5658 if search:
5656 5659 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5657 5660 if name == search]
5658 5661 else:
5659 5662 pathitems = sorted(ui.paths.iteritems())
5660 5663
5661 5664 fm = ui.formatter('paths', opts)
5662 5665 if fm:
5663 5666 hidepassword = str
5664 5667 else:
5665 5668 hidepassword = util.hidepassword
5666 5669 if ui.quiet:
5667 5670 namefmt = '%s\n'
5668 5671 else:
5669 5672 namefmt = '%s = '
5670 5673 showsubopts = not search and not ui.quiet
5671 5674
5672 5675 for name, path in pathitems:
5673 5676 fm.startitem()
5674 5677 fm.condwrite(not search, 'name', namefmt, name)
5675 5678 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5676 5679 for subopt, value in sorted(path.suboptions.items()):
5677 5680 assert subopt not in ('name', 'url')
5678 5681 if showsubopts:
5679 5682 fm.plain('%s:%s = ' % (name, subopt))
5680 5683 fm.condwrite(showsubopts, subopt, '%s\n', value)
5681 5684
5682 5685 fm.end()
5683 5686
5684 5687 if search and not pathitems:
5685 5688 if not ui.quiet:
5686 5689 ui.warn(_("not found!\n"))
5687 5690 return 1
5688 5691 else:
5689 5692 return 0
5690 5693
5691 5694 @command('phase',
5692 5695 [('p', 'public', False, _('set changeset phase to public')),
5693 5696 ('d', 'draft', False, _('set changeset phase to draft')),
5694 5697 ('s', 'secret', False, _('set changeset phase to secret')),
5695 5698 ('f', 'force', False, _('allow to move boundary backward')),
5696 5699 ('r', 'rev', [], _('target revision'), _('REV')),
5697 5700 ],
5698 5701 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5699 5702 def phase(ui, repo, *revs, **opts):
5700 5703 """set or show the current phase name
5701 5704
5702 5705 With no argument, show the phase name of the current revision(s).
5703 5706
5704 5707 With one of -p/--public, -d/--draft or -s/--secret, change the
5705 5708 phase value of the specified revisions.
5706 5709
5707 5710 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5708 5711 lower phase to an higher phase. Phases are ordered as follows::
5709 5712
5710 5713 public < draft < secret
5711 5714
5712 5715 Returns 0 on success, 1 if some phases could not be changed.
5713 5716
5714 5717 (For more information about the phases concept, see :hg:`help phases`.)
5715 5718 """
5716 5719 # search for a unique phase argument
5717 5720 targetphase = None
5718 5721 for idx, name in enumerate(phases.phasenames):
5719 5722 if opts[name]:
5720 5723 if targetphase is not None:
5721 5724 raise error.Abort(_('only one phase can be specified'))
5722 5725 targetphase = idx
5723 5726
5724 5727 # look for specified revision
5725 5728 revs = list(revs)
5726 5729 revs.extend(opts['rev'])
5727 5730 if not revs:
5728 5731 # display both parents as the second parent phase can influence
5729 5732 # the phase of a merge commit
5730 5733 revs = [c.rev() for c in repo[None].parents()]
5731 5734
5732 5735 revs = scmutil.revrange(repo, revs)
5733 5736
5734 5737 lock = None
5735 5738 ret = 0
5736 5739 if targetphase is None:
5737 5740 # display
5738 5741 for r in revs:
5739 5742 ctx = repo[r]
5740 5743 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5741 5744 else:
5742 5745 tr = None
5743 5746 lock = repo.lock()
5744 5747 try:
5745 5748 tr = repo.transaction("phase")
5746 5749 # set phase
5747 5750 if not revs:
5748 5751 raise error.Abort(_('empty revision set'))
5749 5752 nodes = [repo[r].node() for r in revs]
5750 5753 # moving revision from public to draft may hide them
5751 5754 # We have to check result on an unfiltered repository
5752 5755 unfi = repo.unfiltered()
5753 5756 getphase = unfi._phasecache.phase
5754 5757 olddata = [getphase(unfi, r) for r in unfi]
5755 5758 phases.advanceboundary(repo, tr, targetphase, nodes)
5756 5759 if opts['force']:
5757 5760 phases.retractboundary(repo, tr, targetphase, nodes)
5758 5761 tr.close()
5759 5762 finally:
5760 5763 if tr is not None:
5761 5764 tr.release()
5762 5765 lock.release()
5763 5766 getphase = unfi._phasecache.phase
5764 5767 newdata = [getphase(unfi, r) for r in unfi]
5765 5768 changes = sum(newdata[r] != olddata[r] for r in unfi)
5766 5769 cl = unfi.changelog
5767 5770 rejected = [n for n in nodes
5768 5771 if newdata[cl.rev(n)] < targetphase]
5769 5772 if rejected:
5770 5773 ui.warn(_('cannot move %i changesets to a higher '
5771 5774 'phase, use --force\n') % len(rejected))
5772 5775 ret = 1
5773 5776 if changes:
5774 5777 msg = _('phase changed for %i changesets\n') % changes
5775 5778 if ret:
5776 5779 ui.status(msg)
5777 5780 else:
5778 5781 ui.note(msg)
5779 5782 else:
5780 5783 ui.warn(_('no phases changed\n'))
5781 5784 return ret
5782 5785
5783 5786 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5784 5787 """Run after a changegroup has been added via pull/unbundle
5785 5788
5786 5789 This takes arguments below:
5787 5790
5788 5791 :modheads: change of heads by pull/unbundle
5789 5792 :optupdate: updating working directory is needed or not
5790 5793 :checkout: update destination revision (or None to default destination)
5791 5794 :brev: a name, which might be a bookmark to be activated after updating
5792 5795 """
5793 5796 if modheads == 0:
5794 5797 return
5795 5798 if optupdate:
5796 5799 try:
5797 5800 return hg.updatetotally(ui, repo, checkout, brev)
5798 5801 except error.UpdateAbort as inst:
5799 5802 msg = _("not updating: %s") % str(inst)
5800 5803 hint = inst.hint
5801 5804 raise error.UpdateAbort(msg, hint=hint)
5802 5805 if modheads > 1:
5803 5806 currentbranchheads = len(repo.branchheads())
5804 5807 if currentbranchheads == modheads:
5805 5808 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5806 5809 elif currentbranchheads > 1:
5807 5810 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5808 5811 "merge)\n"))
5809 5812 else:
5810 5813 ui.status(_("(run 'hg heads' to see heads)\n"))
5811 5814 else:
5812 5815 ui.status(_("(run 'hg update' to get a working copy)\n"))
5813 5816
5814 5817 @command('^pull',
5815 5818 [('u', 'update', None,
5816 5819 _('update to new branch head if changesets were pulled')),
5817 5820 ('f', 'force', None, _('run even when remote repository is unrelated')),
5818 5821 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5819 5822 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5820 5823 ('b', 'branch', [], _('a specific branch you would like to pull'),
5821 5824 _('BRANCH')),
5822 5825 ] + remoteopts,
5823 5826 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5824 5827 def pull(ui, repo, source="default", **opts):
5825 5828 """pull changes from the specified source
5826 5829
5827 5830 Pull changes from a remote repository to a local one.
5828 5831
5829 5832 This finds all changes from the repository at the specified path
5830 5833 or URL and adds them to a local repository (the current one unless
5831 5834 -R is specified). By default, this does not update the copy of the
5832 5835 project in the working directory.
5833 5836
5834 5837 Use :hg:`incoming` if you want to see what would have been added
5835 5838 by a pull at the time you issued this command. If you then decide
5836 5839 to add those changes to the repository, you should use :hg:`pull
5837 5840 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5838 5841
5839 5842 If SOURCE is omitted, the 'default' path will be used.
5840 5843 See :hg:`help urls` for more information.
5841 5844
5842 5845 Specifying bookmark as ``.`` is equivalent to specifying the active
5843 5846 bookmark's name.
5844 5847
5845 5848 Returns 0 on success, 1 if an update had unresolved files.
5846 5849 """
5847 5850 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5848 5851 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5849 5852 other = hg.peer(repo, opts, source)
5850 5853 try:
5851 5854 revs, checkout = hg.addbranchrevs(repo, other, branches,
5852 5855 opts.get('rev'))
5853 5856
5854 5857
5855 5858 pullopargs = {}
5856 5859 if opts.get('bookmark'):
5857 5860 if not revs:
5858 5861 revs = []
5859 5862 # The list of bookmark used here is not the one used to actually
5860 5863 # update the bookmark name. This can result in the revision pulled
5861 5864 # not ending up with the name of the bookmark because of a race
5862 5865 # condition on the server. (See issue 4689 for details)
5863 5866 remotebookmarks = other.listkeys('bookmarks')
5864 5867 pullopargs['remotebookmarks'] = remotebookmarks
5865 5868 for b in opts['bookmark']:
5866 5869 b = repo._bookmarks.expandname(b)
5867 5870 if b not in remotebookmarks:
5868 5871 raise error.Abort(_('remote bookmark %s not found!') % b)
5869 5872 revs.append(remotebookmarks[b])
5870 5873
5871 5874 if revs:
5872 5875 try:
5873 5876 # When 'rev' is a bookmark name, we cannot guarantee that it
5874 5877 # will be updated with that name because of a race condition
5875 5878 # server side. (See issue 4689 for details)
5876 5879 oldrevs = revs
5877 5880 revs = [] # actually, nodes
5878 5881 for r in oldrevs:
5879 5882 node = other.lookup(r)
5880 5883 revs.append(node)
5881 5884 if r == checkout:
5882 5885 checkout = node
5883 5886 except error.CapabilityError:
5884 5887 err = _("other repository doesn't support revision lookup, "
5885 5888 "so a rev cannot be specified.")
5886 5889 raise error.Abort(err)
5887 5890
5888 5891 pullopargs.update(opts.get('opargs', {}))
5889 5892 modheads = exchange.pull(repo, other, heads=revs,
5890 5893 force=opts.get('force'),
5891 5894 bookmarks=opts.get('bookmark', ()),
5892 5895 opargs=pullopargs).cgresult
5893 5896
5894 5897 # brev is a name, which might be a bookmark to be activated at
5895 5898 # the end of the update. In other words, it is an explicit
5896 5899 # destination of the update
5897 5900 brev = None
5898 5901
5899 5902 if checkout:
5900 5903 checkout = str(repo.changelog.rev(checkout))
5901 5904
5902 5905 # order below depends on implementation of
5903 5906 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5904 5907 # because 'checkout' is determined without it.
5905 5908 if opts.get('rev'):
5906 5909 brev = opts['rev'][0]
5907 5910 elif opts.get('branch'):
5908 5911 brev = opts['branch'][0]
5909 5912 else:
5910 5913 brev = branches[0]
5911 5914 repo._subtoppath = source
5912 5915 try:
5913 5916 ret = postincoming(ui, repo, modheads, opts.get('update'),
5914 5917 checkout, brev)
5915 5918
5916 5919 finally:
5917 5920 del repo._subtoppath
5918 5921
5919 5922 finally:
5920 5923 other.close()
5921 5924 return ret
5922 5925
5923 5926 @command('^push',
5924 5927 [('f', 'force', None, _('force push')),
5925 5928 ('r', 'rev', [],
5926 5929 _('a changeset intended to be included in the destination'),
5927 5930 _('REV')),
5928 5931 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5929 5932 ('b', 'branch', [],
5930 5933 _('a specific branch you would like to push'), _('BRANCH')),
5931 5934 ('', 'new-branch', False, _('allow pushing a new branch')),
5932 5935 ] + remoteopts,
5933 5936 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5934 5937 def push(ui, repo, dest=None, **opts):
5935 5938 """push changes to the specified destination
5936 5939
5937 5940 Push changesets from the local repository to the specified
5938 5941 destination.
5939 5942
5940 5943 This operation is symmetrical to pull: it is identical to a pull
5941 5944 in the destination repository from the current one.
5942 5945
5943 5946 By default, push will not allow creation of new heads at the
5944 5947 destination, since multiple heads would make it unclear which head
5945 5948 to use. In this situation, it is recommended to pull and merge
5946 5949 before pushing.
5947 5950
5948 5951 Use --new-branch if you want to allow push to create a new named
5949 5952 branch that is not present at the destination. This allows you to
5950 5953 only create a new branch without forcing other changes.
5951 5954
5952 5955 .. note::
5953 5956
5954 5957 Extra care should be taken with the -f/--force option,
5955 5958 which will push all new heads on all branches, an action which will
5956 5959 almost always cause confusion for collaborators.
5957 5960
5958 5961 If -r/--rev is used, the specified revision and all its ancestors
5959 5962 will be pushed to the remote repository.
5960 5963
5961 5964 If -B/--bookmark is used, the specified bookmarked revision, its
5962 5965 ancestors, and the bookmark will be pushed to the remote
5963 5966 repository. Specifying ``.`` is equivalent to specifying the active
5964 5967 bookmark's name.
5965 5968
5966 5969 Please see :hg:`help urls` for important details about ``ssh://``
5967 5970 URLs. If DESTINATION is omitted, a default path will be used.
5968 5971
5969 5972 Returns 0 if push was successful, 1 if nothing to push.
5970 5973 """
5971 5974
5972 5975 if opts.get('bookmark'):
5973 5976 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5974 5977 for b in opts['bookmark']:
5975 5978 # translate -B options to -r so changesets get pushed
5976 5979 b = repo._bookmarks.expandname(b)
5977 5980 if b in repo._bookmarks:
5978 5981 opts.setdefault('rev', []).append(b)
5979 5982 else:
5980 5983 # if we try to push a deleted bookmark, translate it to null
5981 5984 # this lets simultaneous -r, -b options continue working
5982 5985 opts.setdefault('rev', []).append("null")
5983 5986
5984 5987 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5985 5988 if not path:
5986 5989 raise error.Abort(_('default repository not configured!'),
5987 5990 hint=_('see the "path" section in "hg help config"'))
5988 5991 dest = path.pushloc or path.loc
5989 5992 branches = (path.branch, opts.get('branch') or [])
5990 5993 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5991 5994 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5992 5995 other = hg.peer(repo, opts, dest)
5993 5996
5994 5997 if revs:
5995 5998 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5996 5999 if not revs:
5997 6000 raise error.Abort(_("specified revisions evaluate to an empty set"),
5998 6001 hint=_("use different revision arguments"))
5999 6002 elif path.pushrev:
6000 6003 # It doesn't make any sense to specify ancestor revisions. So limit
6001 6004 # to DAG heads to make discovery simpler.
6002 6005 expr = revset.formatspec('heads(%r)', path.pushrev)
6003 6006 revs = scmutil.revrange(repo, [expr])
6004 6007 revs = [repo[rev].node() for rev in revs]
6005 6008 if not revs:
6006 6009 raise error.Abort(_('default push revset for path evaluates to an '
6007 6010 'empty set'))
6008 6011
6009 6012 repo._subtoppath = dest
6010 6013 try:
6011 6014 # push subrepos depth-first for coherent ordering
6012 6015 c = repo['']
6013 6016 subs = c.substate # only repos that are committed
6014 6017 for s in sorted(subs):
6015 6018 result = c.sub(s).push(opts)
6016 6019 if result == 0:
6017 6020 return not result
6018 6021 finally:
6019 6022 del repo._subtoppath
6020 6023 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
6021 6024 newbranch=opts.get('new_branch'),
6022 6025 bookmarks=opts.get('bookmark', ()),
6023 6026 opargs=opts.get('opargs'))
6024 6027
6025 6028 result = not pushop.cgresult
6026 6029
6027 6030 if pushop.bkresult is not None:
6028 6031 if pushop.bkresult == 2:
6029 6032 result = 2
6030 6033 elif not result and pushop.bkresult:
6031 6034 result = 2
6032 6035
6033 6036 return result
6034 6037
6035 6038 @command('recover', [])
6036 6039 def recover(ui, repo):
6037 6040 """roll back an interrupted transaction
6038 6041
6039 6042 Recover from an interrupted commit or pull.
6040 6043
6041 6044 This command tries to fix the repository status after an
6042 6045 interrupted operation. It should only be necessary when Mercurial
6043 6046 suggests it.
6044 6047
6045 6048 Returns 0 if successful, 1 if nothing to recover or verify fails.
6046 6049 """
6047 6050 if repo.recover():
6048 6051 return hg.verify(repo)
6049 6052 return 1
6050 6053
6051 6054 @command('^remove|rm',
6052 6055 [('A', 'after', None, _('record delete for missing files')),
6053 6056 ('f', 'force', None,
6054 6057 _('forget added files, delete modified files')),
6055 6058 ] + subrepoopts + walkopts,
6056 6059 _('[OPTION]... FILE...'),
6057 6060 inferrepo=True)
6058 6061 def remove(ui, repo, *pats, **opts):
6059 6062 """remove the specified files on the next commit
6060 6063
6061 6064 Schedule the indicated files for removal from the current branch.
6062 6065
6063 6066 This command schedules the files to be removed at the next commit.
6064 6067 To undo a remove before that, see :hg:`revert`. To undo added
6065 6068 files, see :hg:`forget`.
6066 6069
6067 6070 .. container:: verbose
6068 6071
6069 6072 -A/--after can be used to remove only files that have already
6070 6073 been deleted, -f/--force can be used to force deletion, and -Af
6071 6074 can be used to remove files from the next revision without
6072 6075 deleting them from the working directory.
6073 6076
6074 6077 The following table details the behavior of remove for different
6075 6078 file states (columns) and option combinations (rows). The file
6076 6079 states are Added [A], Clean [C], Modified [M] and Missing [!]
6077 6080 (as reported by :hg:`status`). The actions are Warn, Remove
6078 6081 (from branch) and Delete (from disk):
6079 6082
6080 6083 ========= == == == ==
6081 6084 opt/state A C M !
6082 6085 ========= == == == ==
6083 6086 none W RD W R
6084 6087 -f R RD RD R
6085 6088 -A W W W R
6086 6089 -Af R R R R
6087 6090 ========= == == == ==
6088 6091
6089 6092 .. note::
6090 6093
6091 6094 :hg:`remove` never deletes files in Added [A] state from the
6092 6095 working directory, not even if ``--force`` is specified.
6093 6096
6094 6097 Returns 0 on success, 1 if any warnings encountered.
6095 6098 """
6096 6099
6097 6100 after, force = opts.get('after'), opts.get('force')
6098 6101 if not pats and not after:
6099 6102 raise error.Abort(_('no files specified'))
6100 6103
6101 6104 m = scmutil.match(repo[None], pats, opts)
6102 6105 subrepos = opts.get('subrepos')
6103 6106 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
6104 6107
6105 6108 @command('rename|move|mv',
6106 6109 [('A', 'after', None, _('record a rename that has already occurred')),
6107 6110 ('f', 'force', None, _('forcibly copy over an existing managed file')),
6108 6111 ] + walkopts + dryrunopts,
6109 6112 _('[OPTION]... SOURCE... DEST'))
6110 6113 def rename(ui, repo, *pats, **opts):
6111 6114 """rename files; equivalent of copy + remove
6112 6115
6113 6116 Mark dest as copies of sources; mark sources for deletion. If dest
6114 6117 is a directory, copies are put in that directory. If dest is a
6115 6118 file, there can only be one source.
6116 6119
6117 6120 By default, this command copies the contents of files as they
6118 6121 exist in the working directory. If invoked with -A/--after, the
6119 6122 operation is recorded, but no copying is performed.
6120 6123
6121 6124 This command takes effect at the next commit. To undo a rename
6122 6125 before that, see :hg:`revert`.
6123 6126
6124 6127 Returns 0 on success, 1 if errors are encountered.
6125 6128 """
6126 6129 with repo.wlock(False):
6127 6130 return cmdutil.copy(ui, repo, pats, opts, rename=True)
6128 6131
6129 6132 @command('resolve',
6130 6133 [('a', 'all', None, _('select all unresolved files')),
6131 6134 ('l', 'list', None, _('list state of files needing merge')),
6132 6135 ('m', 'mark', None, _('mark files as resolved')),
6133 6136 ('u', 'unmark', None, _('mark files as unresolved')),
6134 6137 ('n', 'no-status', None, _('hide status prefix'))]
6135 6138 + mergetoolopts + walkopts + formatteropts,
6136 6139 _('[OPTION]... [FILE]...'),
6137 6140 inferrepo=True)
6138 6141 def resolve(ui, repo, *pats, **opts):
6139 6142 """redo merges or set/view the merge status of files
6140 6143
6141 6144 Merges with unresolved conflicts are often the result of
6142 6145 non-interactive merging using the ``internal:merge`` configuration
6143 6146 setting, or a command-line merge tool like ``diff3``. The resolve
6144 6147 command is used to manage the files involved in a merge, after
6145 6148 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6146 6149 working directory must have two parents). See :hg:`help
6147 6150 merge-tools` for information on configuring merge tools.
6148 6151
6149 6152 The resolve command can be used in the following ways:
6150 6153
6151 6154 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6152 6155 files, discarding any previous merge attempts. Re-merging is not
6153 6156 performed for files already marked as resolved. Use ``--all/-a``
6154 6157 to select all unresolved files. ``--tool`` can be used to specify
6155 6158 the merge tool used for the given files. It overrides the HGMERGE
6156 6159 environment variable and your configuration files. Previous file
6157 6160 contents are saved with a ``.orig`` suffix.
6158 6161
6159 6162 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6160 6163 (e.g. after having manually fixed-up the files). The default is
6161 6164 to mark all unresolved files.
6162 6165
6163 6166 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6164 6167 default is to mark all resolved files.
6165 6168
6166 6169 - :hg:`resolve -l`: list files which had or still have conflicts.
6167 6170 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6168 6171
6169 6172 .. note::
6170 6173
6171 6174 Mercurial will not let you commit files with unresolved merge
6172 6175 conflicts. You must use :hg:`resolve -m ...` before you can
6173 6176 commit after a conflicting merge.
6174 6177
6175 6178 Returns 0 on success, 1 if any files fail a resolve attempt.
6176 6179 """
6177 6180
6178 6181 flaglist = 'all mark unmark list no_status'.split()
6179 6182 all, mark, unmark, show, nostatus = \
6180 6183 [opts.get(o) for o in flaglist]
6181 6184
6182 6185 if (show and (mark or unmark)) or (mark and unmark):
6183 6186 raise error.Abort(_("too many options specified"))
6184 6187 if pats and all:
6185 6188 raise error.Abort(_("can't specify --all and patterns"))
6186 6189 if not (all or pats or show or mark or unmark):
6187 6190 raise error.Abort(_('no files or directories specified'),
6188 6191 hint=('use --all to re-merge all unresolved files'))
6189 6192
6190 6193 if show:
6191 6194 fm = ui.formatter('resolve', opts)
6192 6195 ms = mergemod.mergestate.read(repo)
6193 6196 m = scmutil.match(repo[None], pats, opts)
6194 6197 for f in ms:
6195 6198 if not m(f):
6196 6199 continue
6197 6200 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6198 6201 'd': 'driverresolved'}[ms[f]]
6199 6202 fm.startitem()
6200 6203 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6201 6204 fm.write('path', '%s\n', f, label=l)
6202 6205 fm.end()
6203 6206 return 0
6204 6207
6205 6208 with repo.wlock():
6206 6209 ms = mergemod.mergestate.read(repo)
6207 6210
6208 6211 if not (ms.active() or repo.dirstate.p2() != nullid):
6209 6212 raise error.Abort(
6210 6213 _('resolve command not applicable when not merging'))
6211 6214
6212 6215 wctx = repo[None]
6213 6216
6214 6217 if ms.mergedriver and ms.mdstate() == 'u':
6215 6218 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6216 6219 ms.commit()
6217 6220 # allow mark and unmark to go through
6218 6221 if not mark and not unmark and not proceed:
6219 6222 return 1
6220 6223
6221 6224 m = scmutil.match(wctx, pats, opts)
6222 6225 ret = 0
6223 6226 didwork = False
6224 6227 runconclude = False
6225 6228
6226 6229 tocomplete = []
6227 6230 for f in ms:
6228 6231 if not m(f):
6229 6232 continue
6230 6233
6231 6234 didwork = True
6232 6235
6233 6236 # don't let driver-resolved files be marked, and run the conclude
6234 6237 # step if asked to resolve
6235 6238 if ms[f] == "d":
6236 6239 exact = m.exact(f)
6237 6240 if mark:
6238 6241 if exact:
6239 6242 ui.warn(_('not marking %s as it is driver-resolved\n')
6240 6243 % f)
6241 6244 elif unmark:
6242 6245 if exact:
6243 6246 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6244 6247 % f)
6245 6248 else:
6246 6249 runconclude = True
6247 6250 continue
6248 6251
6249 6252 if mark:
6250 6253 ms.mark(f, "r")
6251 6254 elif unmark:
6252 6255 ms.mark(f, "u")
6253 6256 else:
6254 6257 # backup pre-resolve (merge uses .orig for its own purposes)
6255 6258 a = repo.wjoin(f)
6256 6259 try:
6257 6260 util.copyfile(a, a + ".resolve")
6258 6261 except (IOError, OSError) as inst:
6259 6262 if inst.errno != errno.ENOENT:
6260 6263 raise
6261 6264
6262 6265 try:
6263 6266 # preresolve file
6264 6267 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6265 6268 'resolve')
6266 6269 complete, r = ms.preresolve(f, wctx)
6267 6270 if not complete:
6268 6271 tocomplete.append(f)
6269 6272 elif r:
6270 6273 ret = 1
6271 6274 finally:
6272 6275 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6273 6276 ms.commit()
6274 6277
6275 6278 # replace filemerge's .orig file with our resolve file, but only
6276 6279 # for merges that are complete
6277 6280 if complete:
6278 6281 try:
6279 6282 util.rename(a + ".resolve",
6280 6283 scmutil.origpath(ui, repo, a))
6281 6284 except OSError as inst:
6282 6285 if inst.errno != errno.ENOENT:
6283 6286 raise
6284 6287
6285 6288 for f in tocomplete:
6286 6289 try:
6287 6290 # resolve file
6288 6291 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6289 6292 'resolve')
6290 6293 r = ms.resolve(f, wctx)
6291 6294 if r:
6292 6295 ret = 1
6293 6296 finally:
6294 6297 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6295 6298 ms.commit()
6296 6299
6297 6300 # replace filemerge's .orig file with our resolve file
6298 6301 a = repo.wjoin(f)
6299 6302 try:
6300 6303 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6301 6304 except OSError as inst:
6302 6305 if inst.errno != errno.ENOENT:
6303 6306 raise
6304 6307
6305 6308 ms.commit()
6306 6309 ms.recordactions()
6307 6310
6308 6311 if not didwork and pats:
6309 6312 hint = None
6310 6313 if not any([p for p in pats if p.find(':') >= 0]):
6311 6314 pats = ['path:%s' % p for p in pats]
6312 6315 m = scmutil.match(wctx, pats, opts)
6313 6316 for f in ms:
6314 6317 if not m(f):
6315 6318 continue
6316 6319 flags = ''.join(['-%s ' % o[0] for o in flaglist
6317 6320 if opts.get(o)])
6318 6321 hint = _("(try: hg resolve %s%s)\n") % (
6319 6322 flags,
6320 6323 ' '.join(pats))
6321 6324 break
6322 6325 ui.warn(_("arguments do not match paths that need resolving\n"))
6323 6326 if hint:
6324 6327 ui.warn(hint)
6325 6328 elif ms.mergedriver and ms.mdstate() != 's':
6326 6329 # run conclude step when either a driver-resolved file is requested
6327 6330 # or there are no driver-resolved files
6328 6331 # we can't use 'ret' to determine whether any files are unresolved
6329 6332 # because we might not have tried to resolve some
6330 6333 if ((runconclude or not list(ms.driverresolved()))
6331 6334 and not list(ms.unresolved())):
6332 6335 proceed = mergemod.driverconclude(repo, ms, wctx)
6333 6336 ms.commit()
6334 6337 if not proceed:
6335 6338 return 1
6336 6339
6337 6340 # Nudge users into finishing an unfinished operation
6338 6341 unresolvedf = list(ms.unresolved())
6339 6342 driverresolvedf = list(ms.driverresolved())
6340 6343 if not unresolvedf and not driverresolvedf:
6341 6344 ui.status(_('(no more unresolved files)\n'))
6342 6345 cmdutil.checkafterresolved(repo)
6343 6346 elif not unresolvedf:
6344 6347 ui.status(_('(no more unresolved files -- '
6345 6348 'run "hg resolve --all" to conclude)\n'))
6346 6349
6347 6350 return ret
6348 6351
6349 6352 @command('revert',
6350 6353 [('a', 'all', None, _('revert all changes when no arguments given')),
6351 6354 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6352 6355 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6353 6356 ('C', 'no-backup', None, _('do not save backup copies of files')),
6354 6357 ('i', 'interactive', None,
6355 6358 _('interactively select the changes (EXPERIMENTAL)')),
6356 6359 ] + walkopts + dryrunopts,
6357 6360 _('[OPTION]... [-r REV] [NAME]...'))
6358 6361 def revert(ui, repo, *pats, **opts):
6359 6362 """restore files to their checkout state
6360 6363
6361 6364 .. note::
6362 6365
6363 6366 To check out earlier revisions, you should use :hg:`update REV`.
6364 6367 To cancel an uncommitted merge (and lose your changes),
6365 6368 use :hg:`update --clean .`.
6366 6369
6367 6370 With no revision specified, revert the specified files or directories
6368 6371 to the contents they had in the parent of the working directory.
6369 6372 This restores the contents of files to an unmodified
6370 6373 state and unschedules adds, removes, copies, and renames. If the
6371 6374 working directory has two parents, you must explicitly specify a
6372 6375 revision.
6373 6376
6374 6377 Using the -r/--rev or -d/--date options, revert the given files or
6375 6378 directories to their states as of a specific revision. Because
6376 6379 revert does not change the working directory parents, this will
6377 6380 cause these files to appear modified. This can be helpful to "back
6378 6381 out" some or all of an earlier change. See :hg:`backout` for a
6379 6382 related method.
6380 6383
6381 6384 Modified files are saved with a .orig suffix before reverting.
6382 6385 To disable these backups, use --no-backup. It is possible to store
6383 6386 the backup files in a custom directory relative to the root of the
6384 6387 repository by setting the ``ui.origbackuppath`` configuration
6385 6388 option.
6386 6389
6387 6390 See :hg:`help dates` for a list of formats valid for -d/--date.
6388 6391
6389 6392 See :hg:`help backout` for a way to reverse the effect of an
6390 6393 earlier changeset.
6391 6394
6392 6395 Returns 0 on success.
6393 6396 """
6394 6397
6395 6398 if opts.get("date"):
6396 6399 if opts.get("rev"):
6397 6400 raise error.Abort(_("you can't specify a revision and a date"))
6398 6401 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6399 6402
6400 6403 parent, p2 = repo.dirstate.parents()
6401 6404 if not opts.get('rev') and p2 != nullid:
6402 6405 # revert after merge is a trap for new users (issue2915)
6403 6406 raise error.Abort(_('uncommitted merge with no revision specified'),
6404 6407 hint=_("use 'hg update' or see 'hg help revert'"))
6405 6408
6406 6409 ctx = scmutil.revsingle(repo, opts.get('rev'))
6407 6410
6408 6411 if (not (pats or opts.get('include') or opts.get('exclude') or
6409 6412 opts.get('all') or opts.get('interactive'))):
6410 6413 msg = _("no files or directories specified")
6411 6414 if p2 != nullid:
6412 6415 hint = _("uncommitted merge, use --all to discard all changes,"
6413 6416 " or 'hg update -C .' to abort the merge")
6414 6417 raise error.Abort(msg, hint=hint)
6415 6418 dirty = any(repo.status())
6416 6419 node = ctx.node()
6417 6420 if node != parent:
6418 6421 if dirty:
6419 6422 hint = _("uncommitted changes, use --all to discard all"
6420 6423 " changes, or 'hg update %s' to update") % ctx.rev()
6421 6424 else:
6422 6425 hint = _("use --all to revert all files,"
6423 6426 " or 'hg update %s' to update") % ctx.rev()
6424 6427 elif dirty:
6425 6428 hint = _("uncommitted changes, use --all to discard all changes")
6426 6429 else:
6427 6430 hint = _("use --all to revert all files")
6428 6431 raise error.Abort(msg, hint=hint)
6429 6432
6430 6433 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6431 6434
6432 6435 @command('rollback', dryrunopts +
6433 6436 [('f', 'force', False, _('ignore safety measures'))])
6434 6437 def rollback(ui, repo, **opts):
6435 6438 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6436 6439
6437 6440 Please use :hg:`commit --amend` instead of rollback to correct
6438 6441 mistakes in the last commit.
6439 6442
6440 6443 This command should be used with care. There is only one level of
6441 6444 rollback, and there is no way to undo a rollback. It will also
6442 6445 restore the dirstate at the time of the last transaction, losing
6443 6446 any dirstate changes since that time. This command does not alter
6444 6447 the working directory.
6445 6448
6446 6449 Transactions are used to encapsulate the effects of all commands
6447 6450 that create new changesets or propagate existing changesets into a
6448 6451 repository.
6449 6452
6450 6453 .. container:: verbose
6451 6454
6452 6455 For example, the following commands are transactional, and their
6453 6456 effects can be rolled back:
6454 6457
6455 6458 - commit
6456 6459 - import
6457 6460 - pull
6458 6461 - push (with this repository as the destination)
6459 6462 - unbundle
6460 6463
6461 6464 To avoid permanent data loss, rollback will refuse to rollback a
6462 6465 commit transaction if it isn't checked out. Use --force to
6463 6466 override this protection.
6464 6467
6465 6468 The rollback command can be entirely disabled by setting the
6466 6469 ``ui.rollback`` configuration setting to false. If you're here
6467 6470 because you want to use rollback and it's disabled, you can
6468 6471 re-enable the command by setting ``ui.rollback`` to true.
6469 6472
6470 6473 This command is not intended for use on public repositories. Once
6471 6474 changes are visible for pull by other users, rolling a transaction
6472 6475 back locally is ineffective (someone else may already have pulled
6473 6476 the changes). Furthermore, a race is possible with readers of the
6474 6477 repository; for example an in-progress pull from the repository
6475 6478 may fail if a rollback is performed.
6476 6479
6477 6480 Returns 0 on success, 1 if no rollback data is available.
6478 6481 """
6479 6482 if not ui.configbool('ui', 'rollback', True):
6480 6483 raise error.Abort(_('rollback is disabled because it is unsafe'),
6481 6484 hint=('see `hg help -v rollback` for information'))
6482 6485 return repo.rollback(dryrun=opts.get('dry_run'),
6483 6486 force=opts.get('force'))
6484 6487
6485 6488 @command('root', [])
6486 6489 def root(ui, repo):
6487 6490 """print the root (top) of the current working directory
6488 6491
6489 6492 Print the root directory of the current repository.
6490 6493
6491 6494 Returns 0 on success.
6492 6495 """
6493 6496 ui.write(repo.root + "\n")
6494 6497
6495 6498 @command('^serve',
6496 6499 [('A', 'accesslog', '', _('name of access log file to write to'),
6497 6500 _('FILE')),
6498 6501 ('d', 'daemon', None, _('run server in background')),
6499 6502 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6500 6503 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6501 6504 # use string type, then we can check if something was passed
6502 6505 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6503 6506 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6504 6507 _('ADDR')),
6505 6508 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6506 6509 _('PREFIX')),
6507 6510 ('n', 'name', '',
6508 6511 _('name to show in web pages (default: working directory)'), _('NAME')),
6509 6512 ('', 'web-conf', '',
6510 6513 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6511 6514 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6512 6515 _('FILE')),
6513 6516 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6514 6517 ('', 'stdio', None, _('for remote clients')),
6515 6518 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6516 6519 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6517 6520 ('', 'style', '', _('template style to use'), _('STYLE')),
6518 6521 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6519 6522 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6520 6523 _('[OPTION]...'),
6521 6524 optionalrepo=True)
6522 6525 def serve(ui, repo, **opts):
6523 6526 """start stand-alone webserver
6524 6527
6525 6528 Start a local HTTP repository browser and pull server. You can use
6526 6529 this for ad-hoc sharing and browsing of repositories. It is
6527 6530 recommended to use a real web server to serve a repository for
6528 6531 longer periods of time.
6529 6532
6530 6533 Please note that the server does not implement access control.
6531 6534 This means that, by default, anybody can read from the server and
6532 6535 nobody can write to it by default. Set the ``web.allow_push``
6533 6536 option to ``*`` to allow everybody to push to the server. You
6534 6537 should use a real web server if you need to authenticate users.
6535 6538
6536 6539 By default, the server logs accesses to stdout and errors to
6537 6540 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6538 6541 files.
6539 6542
6540 6543 To have the server choose a free port number to listen on, specify
6541 6544 a port number of 0; in this case, the server will print the port
6542 6545 number it uses.
6543 6546
6544 6547 Returns 0 on success.
6545 6548 """
6546 6549
6547 6550 if opts["stdio"] and opts["cmdserver"]:
6548 6551 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6549 6552
6550 6553 if opts["stdio"]:
6551 6554 if repo is None:
6552 6555 raise error.RepoError(_("there is no Mercurial repository here"
6553 6556 " (.hg not found)"))
6554 6557 s = sshserver.sshserver(ui, repo)
6555 6558 s.serve_forever()
6556 6559
6557 6560 if opts["cmdserver"]:
6558 6561 service = commandserver.createservice(ui, repo, opts)
6559 6562 else:
6560 6563 service = hgweb.createservice(ui, repo, opts)
6561 6564 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6562 6565
6563 6566 @command('^status|st',
6564 6567 [('A', 'all', None, _('show status of all files')),
6565 6568 ('m', 'modified', None, _('show only modified files')),
6566 6569 ('a', 'added', None, _('show only added files')),
6567 6570 ('r', 'removed', None, _('show only removed files')),
6568 6571 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6569 6572 ('c', 'clean', None, _('show only files without changes')),
6570 6573 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6571 6574 ('i', 'ignored', None, _('show only ignored files')),
6572 6575 ('n', 'no-status', None, _('hide status prefix')),
6573 6576 ('C', 'copies', None, _('show source of copied files')),
6574 6577 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6575 6578 ('', 'rev', [], _('show difference from revision'), _('REV')),
6576 6579 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6577 6580 ] + walkopts + subrepoopts + formatteropts,
6578 6581 _('[OPTION]... [FILE]...'),
6579 6582 inferrepo=True)
6580 6583 def status(ui, repo, *pats, **opts):
6581 6584 """show changed files in the working directory
6582 6585
6583 6586 Show status of files in the repository. If names are given, only
6584 6587 files that match are shown. Files that are clean or ignored or
6585 6588 the source of a copy/move operation, are not listed unless
6586 6589 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6587 6590 Unless options described with "show only ..." are given, the
6588 6591 options -mardu are used.
6589 6592
6590 6593 Option -q/--quiet hides untracked (unknown and ignored) files
6591 6594 unless explicitly requested with -u/--unknown or -i/--ignored.
6592 6595
6593 6596 .. note::
6594 6597
6595 6598 :hg:`status` may appear to disagree with diff if permissions have
6596 6599 changed or a merge has occurred. The standard diff format does
6597 6600 not report permission changes and diff only reports changes
6598 6601 relative to one merge parent.
6599 6602
6600 6603 If one revision is given, it is used as the base revision.
6601 6604 If two revisions are given, the differences between them are
6602 6605 shown. The --change option can also be used as a shortcut to list
6603 6606 the changed files of a revision from its first parent.
6604 6607
6605 6608 The codes used to show the status of files are::
6606 6609
6607 6610 M = modified
6608 6611 A = added
6609 6612 R = removed
6610 6613 C = clean
6611 6614 ! = missing (deleted by non-hg command, but still tracked)
6612 6615 ? = not tracked
6613 6616 I = ignored
6614 6617 = origin of the previous file (with --copies)
6615 6618
6616 6619 .. container:: verbose
6617 6620
6618 6621 Examples:
6619 6622
6620 6623 - show changes in the working directory relative to a
6621 6624 changeset::
6622 6625
6623 6626 hg status --rev 9353
6624 6627
6625 6628 - show changes in the working directory relative to the
6626 6629 current directory (see :hg:`help patterns` for more information)::
6627 6630
6628 6631 hg status re:
6629 6632
6630 6633 - show all changes including copies in an existing changeset::
6631 6634
6632 6635 hg status --copies --change 9353
6633 6636
6634 6637 - get a NUL separated list of added files, suitable for xargs::
6635 6638
6636 6639 hg status -an0
6637 6640
6638 6641 Returns 0 on success.
6639 6642 """
6640 6643
6641 6644 revs = opts.get('rev')
6642 6645 change = opts.get('change')
6643 6646
6644 6647 if revs and change:
6645 6648 msg = _('cannot specify --rev and --change at the same time')
6646 6649 raise error.Abort(msg)
6647 6650 elif change:
6648 6651 node2 = scmutil.revsingle(repo, change, None).node()
6649 6652 node1 = repo[node2].p1().node()
6650 6653 else:
6651 6654 node1, node2 = scmutil.revpair(repo, revs)
6652 6655
6653 6656 if pats:
6654 6657 cwd = repo.getcwd()
6655 6658 else:
6656 6659 cwd = ''
6657 6660
6658 6661 if opts.get('print0'):
6659 6662 end = '\0'
6660 6663 else:
6661 6664 end = '\n'
6662 6665 copy = {}
6663 6666 states = 'modified added removed deleted unknown ignored clean'.split()
6664 6667 show = [k for k in states if opts.get(k)]
6665 6668 if opts.get('all'):
6666 6669 show += ui.quiet and (states[:4] + ['clean']) or states
6667 6670 if not show:
6668 6671 if ui.quiet:
6669 6672 show = states[:4]
6670 6673 else:
6671 6674 show = states[:5]
6672 6675
6673 6676 m = scmutil.match(repo[node2], pats, opts)
6674 6677 stat = repo.status(node1, node2, m,
6675 6678 'ignored' in show, 'clean' in show, 'unknown' in show,
6676 6679 opts.get('subrepos'))
6677 6680 changestates = zip(states, 'MAR!?IC', stat)
6678 6681
6679 6682 if (opts.get('all') or opts.get('copies')
6680 6683 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6681 6684 copy = copies.pathcopies(repo[node1], repo[node2], m)
6682 6685
6683 6686 fm = ui.formatter('status', opts)
6684 6687 fmt = '%s' + end
6685 6688 showchar = not opts.get('no_status')
6686 6689
6687 6690 for state, char, files in changestates:
6688 6691 if state in show:
6689 6692 label = 'status.' + state
6690 6693 for f in files:
6691 6694 fm.startitem()
6692 6695 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6693 6696 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6694 6697 if f in copy:
6695 6698 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6696 6699 label='status.copied')
6697 6700 fm.end()
6698 6701
6699 6702 @command('^summary|sum',
6700 6703 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6701 6704 def summary(ui, repo, **opts):
6702 6705 """summarize working directory state
6703 6706
6704 6707 This generates a brief summary of the working directory state,
6705 6708 including parents, branch, commit status, phase and available updates.
6706 6709
6707 6710 With the --remote option, this will check the default paths for
6708 6711 incoming and outgoing changes. This can be time-consuming.
6709 6712
6710 6713 Returns 0 on success.
6711 6714 """
6712 6715
6713 6716 ctx = repo[None]
6714 6717 parents = ctx.parents()
6715 6718 pnode = parents[0].node()
6716 6719 marks = []
6717 6720
6718 6721 ms = None
6719 6722 try:
6720 6723 ms = mergemod.mergestate.read(repo)
6721 6724 except error.UnsupportedMergeRecords as e:
6722 6725 s = ' '.join(e.recordtypes)
6723 6726 ui.warn(
6724 6727 _('warning: merge state has unsupported record types: %s\n') % s)
6725 6728 unresolved = 0
6726 6729 else:
6727 6730 unresolved = [f for f in ms if ms[f] == 'u']
6728 6731
6729 6732 for p in parents:
6730 6733 # label with log.changeset (instead of log.parent) since this
6731 6734 # shows a working directory parent *changeset*:
6732 6735 # i18n: column positioning for "hg summary"
6733 6736 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6734 6737 label='log.changeset changeset.%s' % p.phasestr())
6735 6738 ui.write(' '.join(p.tags()), label='log.tag')
6736 6739 if p.bookmarks():
6737 6740 marks.extend(p.bookmarks())
6738 6741 if p.rev() == -1:
6739 6742 if not len(repo):
6740 6743 ui.write(_(' (empty repository)'))
6741 6744 else:
6742 6745 ui.write(_(' (no revision checked out)'))
6743 6746 ui.write('\n')
6744 6747 if p.description():
6745 6748 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6746 6749 label='log.summary')
6747 6750
6748 6751 branch = ctx.branch()
6749 6752 bheads = repo.branchheads(branch)
6750 6753 # i18n: column positioning for "hg summary"
6751 6754 m = _('branch: %s\n') % branch
6752 6755 if branch != 'default':
6753 6756 ui.write(m, label='log.branch')
6754 6757 else:
6755 6758 ui.status(m, label='log.branch')
6756 6759
6757 6760 if marks:
6758 6761 active = repo._activebookmark
6759 6762 # i18n: column positioning for "hg summary"
6760 6763 ui.write(_('bookmarks:'), label='log.bookmark')
6761 6764 if active is not None:
6762 6765 if active in marks:
6763 6766 ui.write(' *' + active, label=activebookmarklabel)
6764 6767 marks.remove(active)
6765 6768 else:
6766 6769 ui.write(' [%s]' % active, label=activebookmarklabel)
6767 6770 for m in marks:
6768 6771 ui.write(' ' + m, label='log.bookmark')
6769 6772 ui.write('\n', label='log.bookmark')
6770 6773
6771 6774 status = repo.status(unknown=True)
6772 6775
6773 6776 c = repo.dirstate.copies()
6774 6777 copied, renamed = [], []
6775 6778 for d, s in c.iteritems():
6776 6779 if s in status.removed:
6777 6780 status.removed.remove(s)
6778 6781 renamed.append(d)
6779 6782 else:
6780 6783 copied.append(d)
6781 6784 if d in status.added:
6782 6785 status.added.remove(d)
6783 6786
6784 6787 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6785 6788
6786 6789 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6787 6790 (ui.label(_('%d added'), 'status.added'), status.added),
6788 6791 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6789 6792 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6790 6793 (ui.label(_('%d copied'), 'status.copied'), copied),
6791 6794 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6792 6795 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6793 6796 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6794 6797 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6795 6798 t = []
6796 6799 for l, s in labels:
6797 6800 if s:
6798 6801 t.append(l % len(s))
6799 6802
6800 6803 t = ', '.join(t)
6801 6804 cleanworkdir = False
6802 6805
6803 6806 if repo.vfs.exists('graftstate'):
6804 6807 t += _(' (graft in progress)')
6805 6808 if repo.vfs.exists('updatestate'):
6806 6809 t += _(' (interrupted update)')
6807 6810 elif len(parents) > 1:
6808 6811 t += _(' (merge)')
6809 6812 elif branch != parents[0].branch():
6810 6813 t += _(' (new branch)')
6811 6814 elif (parents[0].closesbranch() and
6812 6815 pnode in repo.branchheads(branch, closed=True)):
6813 6816 t += _(' (head closed)')
6814 6817 elif not (status.modified or status.added or status.removed or renamed or
6815 6818 copied or subs):
6816 6819 t += _(' (clean)')
6817 6820 cleanworkdir = True
6818 6821 elif pnode not in bheads:
6819 6822 t += _(' (new branch head)')
6820 6823
6821 6824 if parents:
6822 6825 pendingphase = max(p.phase() for p in parents)
6823 6826 else:
6824 6827 pendingphase = phases.public
6825 6828
6826 6829 if pendingphase > phases.newcommitphase(ui):
6827 6830 t += ' (%s)' % phases.phasenames[pendingphase]
6828 6831
6829 6832 if cleanworkdir:
6830 6833 # i18n: column positioning for "hg summary"
6831 6834 ui.status(_('commit: %s\n') % t.strip())
6832 6835 else:
6833 6836 # i18n: column positioning for "hg summary"
6834 6837 ui.write(_('commit: %s\n') % t.strip())
6835 6838
6836 6839 # all ancestors of branch heads - all ancestors of parent = new csets
6837 6840 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6838 6841 bheads))
6839 6842
6840 6843 if new == 0:
6841 6844 # i18n: column positioning for "hg summary"
6842 6845 ui.status(_('update: (current)\n'))
6843 6846 elif pnode not in bheads:
6844 6847 # i18n: column positioning for "hg summary"
6845 6848 ui.write(_('update: %d new changesets (update)\n') % new)
6846 6849 else:
6847 6850 # i18n: column positioning for "hg summary"
6848 6851 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6849 6852 (new, len(bheads)))
6850 6853
6851 6854 t = []
6852 6855 draft = len(repo.revs('draft()'))
6853 6856 if draft:
6854 6857 t.append(_('%d draft') % draft)
6855 6858 secret = len(repo.revs('secret()'))
6856 6859 if secret:
6857 6860 t.append(_('%d secret') % secret)
6858 6861
6859 6862 if draft or secret:
6860 6863 ui.status(_('phases: %s\n') % ', '.join(t))
6861 6864
6862 6865 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6863 6866 for trouble in ("unstable", "divergent", "bumped"):
6864 6867 numtrouble = len(repo.revs(trouble + "()"))
6865 6868 # We write all the possibilities to ease translation
6866 6869 troublemsg = {
6867 6870 "unstable": _("unstable: %d changesets"),
6868 6871 "divergent": _("divergent: %d changesets"),
6869 6872 "bumped": _("bumped: %d changesets"),
6870 6873 }
6871 6874 if numtrouble > 0:
6872 6875 ui.status(troublemsg[trouble] % numtrouble + "\n")
6873 6876
6874 6877 cmdutil.summaryhooks(ui, repo)
6875 6878
6876 6879 if opts.get('remote'):
6877 6880 needsincoming, needsoutgoing = True, True
6878 6881 else:
6879 6882 needsincoming, needsoutgoing = False, False
6880 6883 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6881 6884 if i:
6882 6885 needsincoming = True
6883 6886 if o:
6884 6887 needsoutgoing = True
6885 6888 if not needsincoming and not needsoutgoing:
6886 6889 return
6887 6890
6888 6891 def getincoming():
6889 6892 source, branches = hg.parseurl(ui.expandpath('default'))
6890 6893 sbranch = branches[0]
6891 6894 try:
6892 6895 other = hg.peer(repo, {}, source)
6893 6896 except error.RepoError:
6894 6897 if opts.get('remote'):
6895 6898 raise
6896 6899 return source, sbranch, None, None, None
6897 6900 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6898 6901 if revs:
6899 6902 revs = [other.lookup(rev) for rev in revs]
6900 6903 ui.debug('comparing with %s\n' % util.hidepassword(source))
6901 6904 repo.ui.pushbuffer()
6902 6905 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6903 6906 repo.ui.popbuffer()
6904 6907 return source, sbranch, other, commoninc, commoninc[1]
6905 6908
6906 6909 if needsincoming:
6907 6910 source, sbranch, sother, commoninc, incoming = getincoming()
6908 6911 else:
6909 6912 source = sbranch = sother = commoninc = incoming = None
6910 6913
6911 6914 def getoutgoing():
6912 6915 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6913 6916 dbranch = branches[0]
6914 6917 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6915 6918 if source != dest:
6916 6919 try:
6917 6920 dother = hg.peer(repo, {}, dest)
6918 6921 except error.RepoError:
6919 6922 if opts.get('remote'):
6920 6923 raise
6921 6924 return dest, dbranch, None, None
6922 6925 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6923 6926 elif sother is None:
6924 6927 # there is no explicit destination peer, but source one is invalid
6925 6928 return dest, dbranch, None, None
6926 6929 else:
6927 6930 dother = sother
6928 6931 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6929 6932 common = None
6930 6933 else:
6931 6934 common = commoninc
6932 6935 if revs:
6933 6936 revs = [repo.lookup(rev) for rev in revs]
6934 6937 repo.ui.pushbuffer()
6935 6938 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6936 6939 commoninc=common)
6937 6940 repo.ui.popbuffer()
6938 6941 return dest, dbranch, dother, outgoing
6939 6942
6940 6943 if needsoutgoing:
6941 6944 dest, dbranch, dother, outgoing = getoutgoing()
6942 6945 else:
6943 6946 dest = dbranch = dother = outgoing = None
6944 6947
6945 6948 if opts.get('remote'):
6946 6949 t = []
6947 6950 if incoming:
6948 6951 t.append(_('1 or more incoming'))
6949 6952 o = outgoing.missing
6950 6953 if o:
6951 6954 t.append(_('%d outgoing') % len(o))
6952 6955 other = dother or sother
6953 6956 if 'bookmarks' in other.listkeys('namespaces'):
6954 6957 counts = bookmarks.summary(repo, other)
6955 6958 if counts[0] > 0:
6956 6959 t.append(_('%d incoming bookmarks') % counts[0])
6957 6960 if counts[1] > 0:
6958 6961 t.append(_('%d outgoing bookmarks') % counts[1])
6959 6962
6960 6963 if t:
6961 6964 # i18n: column positioning for "hg summary"
6962 6965 ui.write(_('remote: %s\n') % (', '.join(t)))
6963 6966 else:
6964 6967 # i18n: column positioning for "hg summary"
6965 6968 ui.status(_('remote: (synced)\n'))
6966 6969
6967 6970 cmdutil.summaryremotehooks(ui, repo, opts,
6968 6971 ((source, sbranch, sother, commoninc),
6969 6972 (dest, dbranch, dother, outgoing)))
6970 6973
6971 6974 @command('tag',
6972 6975 [('f', 'force', None, _('force tag')),
6973 6976 ('l', 'local', None, _('make the tag local')),
6974 6977 ('r', 'rev', '', _('revision to tag'), _('REV')),
6975 6978 ('', 'remove', None, _('remove a tag')),
6976 6979 # -l/--local is already there, commitopts cannot be used
6977 6980 ('e', 'edit', None, _('invoke editor on commit messages')),
6978 6981 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6979 6982 ] + commitopts2,
6980 6983 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6981 6984 def tag(ui, repo, name1, *names, **opts):
6982 6985 """add one or more tags for the current or given revision
6983 6986
6984 6987 Name a particular revision using <name>.
6985 6988
6986 6989 Tags are used to name particular revisions of the repository and are
6987 6990 very useful to compare different revisions, to go back to significant
6988 6991 earlier versions or to mark branch points as releases, etc. Changing
6989 6992 an existing tag is normally disallowed; use -f/--force to override.
6990 6993
6991 6994 If no revision is given, the parent of the working directory is
6992 6995 used.
6993 6996
6994 6997 To facilitate version control, distribution, and merging of tags,
6995 6998 they are stored as a file named ".hgtags" which is managed similarly
6996 6999 to other project files and can be hand-edited if necessary. This
6997 7000 also means that tagging creates a new commit. The file
6998 7001 ".hg/localtags" is used for local tags (not shared among
6999 7002 repositories).
7000 7003
7001 7004 Tag commits are usually made at the head of a branch. If the parent
7002 7005 of the working directory is not a branch head, :hg:`tag` aborts; use
7003 7006 -f/--force to force the tag commit to be based on a non-head
7004 7007 changeset.
7005 7008
7006 7009 See :hg:`help dates` for a list of formats valid for -d/--date.
7007 7010
7008 7011 Since tag names have priority over branch names during revision
7009 7012 lookup, using an existing branch name as a tag name is discouraged.
7010 7013
7011 7014 Returns 0 on success.
7012 7015 """
7013 7016 wlock = lock = None
7014 7017 try:
7015 7018 wlock = repo.wlock()
7016 7019 lock = repo.lock()
7017 7020 rev_ = "."
7018 7021 names = [t.strip() for t in (name1,) + names]
7019 7022 if len(names) != len(set(names)):
7020 7023 raise error.Abort(_('tag names must be unique'))
7021 7024 for n in names:
7022 7025 scmutil.checknewlabel(repo, n, 'tag')
7023 7026 if not n:
7024 7027 raise error.Abort(_('tag names cannot consist entirely of '
7025 7028 'whitespace'))
7026 7029 if opts.get('rev') and opts.get('remove'):
7027 7030 raise error.Abort(_("--rev and --remove are incompatible"))
7028 7031 if opts.get('rev'):
7029 7032 rev_ = opts['rev']
7030 7033 message = opts.get('message')
7031 7034 if opts.get('remove'):
7032 7035 if opts.get('local'):
7033 7036 expectedtype = 'local'
7034 7037 else:
7035 7038 expectedtype = 'global'
7036 7039
7037 7040 for n in names:
7038 7041 if not repo.tagtype(n):
7039 7042 raise error.Abort(_("tag '%s' does not exist") % n)
7040 7043 if repo.tagtype(n) != expectedtype:
7041 7044 if expectedtype == 'global':
7042 7045 raise error.Abort(_("tag '%s' is not a global tag") % n)
7043 7046 else:
7044 7047 raise error.Abort(_("tag '%s' is not a local tag") % n)
7045 7048 rev_ = 'null'
7046 7049 if not message:
7047 7050 # we don't translate commit messages
7048 7051 message = 'Removed tag %s' % ', '.join(names)
7049 7052 elif not opts.get('force'):
7050 7053 for n in names:
7051 7054 if n in repo.tags():
7052 7055 raise error.Abort(_("tag '%s' already exists "
7053 7056 "(use -f to force)") % n)
7054 7057 if not opts.get('local'):
7055 7058 p1, p2 = repo.dirstate.parents()
7056 7059 if p2 != nullid:
7057 7060 raise error.Abort(_('uncommitted merge'))
7058 7061 bheads = repo.branchheads()
7059 7062 if not opts.get('force') and bheads and p1 not in bheads:
7060 7063 raise error.Abort(_('not at a branch head (use -f to force)'))
7061 7064 r = scmutil.revsingle(repo, rev_).node()
7062 7065
7063 7066 if not message:
7064 7067 # we don't translate commit messages
7065 7068 message = ('Added tag %s for changeset %s' %
7066 7069 (', '.join(names), short(r)))
7067 7070
7068 7071 date = opts.get('date')
7069 7072 if date:
7070 7073 date = util.parsedate(date)
7071 7074
7072 7075 if opts.get('remove'):
7073 7076 editform = 'tag.remove'
7074 7077 else:
7075 7078 editform = 'tag.add'
7076 7079 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7077 7080
7078 7081 # don't allow tagging the null rev
7079 7082 if (not opts.get('remove') and
7080 7083 scmutil.revsingle(repo, rev_).rev() == nullrev):
7081 7084 raise error.Abort(_("cannot tag null revision"))
7082 7085
7083 7086 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
7084 7087 editor=editor)
7085 7088 finally:
7086 7089 release(lock, wlock)
7087 7090
7088 7091 @command('tags', formatteropts, '')
7089 7092 def tags(ui, repo, **opts):
7090 7093 """list repository tags
7091 7094
7092 7095 This lists both regular and local tags. When the -v/--verbose
7093 7096 switch is used, a third column "local" is printed for local tags.
7094 7097 When the -q/--quiet switch is used, only the tag name is printed.
7095 7098
7096 7099 Returns 0 on success.
7097 7100 """
7098 7101
7099 7102 fm = ui.formatter('tags', opts)
7100 7103 hexfunc = fm.hexfunc
7101 7104 tagtype = ""
7102 7105
7103 7106 for t, n in reversed(repo.tagslist()):
7104 7107 hn = hexfunc(n)
7105 7108 label = 'tags.normal'
7106 7109 tagtype = ''
7107 7110 if repo.tagtype(t) == 'local':
7108 7111 label = 'tags.local'
7109 7112 tagtype = 'local'
7110 7113
7111 7114 fm.startitem()
7112 7115 fm.write('tag', '%s', t, label=label)
7113 7116 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
7114 7117 fm.condwrite(not ui.quiet, 'rev node', fmt,
7115 7118 repo.changelog.rev(n), hn, label=label)
7116 7119 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
7117 7120 tagtype, label=label)
7118 7121 fm.plain('\n')
7119 7122 fm.end()
7120 7123
7121 7124 @command('tip',
7122 7125 [('p', 'patch', None, _('show patch')),
7123 7126 ('g', 'git', None, _('use git extended diff format')),
7124 7127 ] + templateopts,
7125 7128 _('[-p] [-g]'))
7126 7129 def tip(ui, repo, **opts):
7127 7130 """show the tip revision (DEPRECATED)
7128 7131
7129 7132 The tip revision (usually just called the tip) is the changeset
7130 7133 most recently added to the repository (and therefore the most
7131 7134 recently changed head).
7132 7135
7133 7136 If you have just made a commit, that commit will be the tip. If
7134 7137 you have just pulled changes from another repository, the tip of
7135 7138 that repository becomes the current tip. The "tip" tag is special
7136 7139 and cannot be renamed or assigned to a different changeset.
7137 7140
7138 7141 This command is deprecated, please use :hg:`heads` instead.
7139 7142
7140 7143 Returns 0 on success.
7141 7144 """
7142 7145 displayer = cmdutil.show_changeset(ui, repo, opts)
7143 7146 displayer.show(repo['tip'])
7144 7147 displayer.close()
7145 7148
7146 7149 @command('unbundle',
7147 7150 [('u', 'update', None,
7148 7151 _('update to new branch head if changesets were unbundled'))],
7149 7152 _('[-u] FILE...'))
7150 7153 def unbundle(ui, repo, fname1, *fnames, **opts):
7151 7154 """apply one or more changegroup files
7152 7155
7153 7156 Apply one or more compressed changegroup files generated by the
7154 7157 bundle command.
7155 7158
7156 7159 Returns 0 on success, 1 if an update has unresolved files.
7157 7160 """
7158 7161 fnames = (fname1,) + fnames
7159 7162
7160 7163 with repo.lock():
7161 7164 for fname in fnames:
7162 7165 f = hg.openpath(ui, fname)
7163 7166 gen = exchange.readbundle(ui, f, fname)
7164 7167 if isinstance(gen, bundle2.unbundle20):
7165 7168 tr = repo.transaction('unbundle')
7166 7169 try:
7167 7170 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7168 7171 url='bundle:' + fname)
7169 7172 tr.close()
7170 7173 except error.BundleUnknownFeatureError as exc:
7171 7174 raise error.Abort(_('%s: unknown bundle feature, %s')
7172 7175 % (fname, exc),
7173 7176 hint=_("see https://mercurial-scm.org/"
7174 7177 "wiki/BundleFeature for more "
7175 7178 "information"))
7176 7179 finally:
7177 7180 if tr:
7178 7181 tr.release()
7179 7182 changes = [r.get('return', 0)
7180 7183 for r in op.records['changegroup']]
7181 7184 modheads = changegroup.combineresults(changes)
7182 7185 elif isinstance(gen, streamclone.streamcloneapplier):
7183 7186 raise error.Abort(
7184 7187 _('packed bundles cannot be applied with '
7185 7188 '"hg unbundle"'),
7186 7189 hint=_('use "hg debugapplystreamclonebundle"'))
7187 7190 else:
7188 7191 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7189 7192
7190 7193 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7191 7194
7192 7195 @command('^update|up|checkout|co',
7193 7196 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7194 7197 ('c', 'check', None, _('require clean working directory')),
7195 7198 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7196 7199 ('r', 'rev', '', _('revision'), _('REV'))
7197 7200 ] + mergetoolopts,
7198 7201 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7199 7202 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7200 7203 tool=None):
7201 7204 """update working directory (or switch revisions)
7202 7205
7203 7206 Update the repository's working directory to the specified
7204 7207 changeset. If no changeset is specified, update to the tip of the
7205 7208 current named branch and move the active bookmark (see :hg:`help
7206 7209 bookmarks`).
7207 7210
7208 7211 Update sets the working directory's parent revision to the specified
7209 7212 changeset (see :hg:`help parents`).
7210 7213
7211 7214 If the changeset is not a descendant or ancestor of the working
7212 7215 directory's parent, the update is aborted. With the -c/--check
7213 7216 option, the working directory is checked for uncommitted changes; if
7214 7217 none are found, the working directory is updated to the specified
7215 7218 changeset.
7216 7219
7217 7220 .. container:: verbose
7218 7221
7219 7222 The following rules apply when the working directory contains
7220 7223 uncommitted changes:
7221 7224
7222 7225 1. If neither -c/--check nor -C/--clean is specified, and if
7223 7226 the requested changeset is an ancestor or descendant of
7224 7227 the working directory's parent, the uncommitted changes
7225 7228 are merged into the requested changeset and the merged
7226 7229 result is left uncommitted. If the requested changeset is
7227 7230 not an ancestor or descendant (that is, it is on another
7228 7231 branch), the update is aborted and the uncommitted changes
7229 7232 are preserved.
7230 7233
7231 7234 2. With the -c/--check option, the update is aborted and the
7232 7235 uncommitted changes are preserved.
7233 7236
7234 7237 3. With the -C/--clean option, uncommitted changes are discarded and
7235 7238 the working directory is updated to the requested changeset.
7236 7239
7237 7240 To cancel an uncommitted merge (and lose your changes), use
7238 7241 :hg:`update --clean .`.
7239 7242
7240 7243 Use null as the changeset to remove the working directory (like
7241 7244 :hg:`clone -U`).
7242 7245
7243 7246 If you want to revert just one file to an older revision, use
7244 7247 :hg:`revert [-r REV] NAME`.
7245 7248
7246 7249 See :hg:`help dates` for a list of formats valid for -d/--date.
7247 7250
7248 7251 Returns 0 on success, 1 if there are unresolved files.
7249 7252 """
7250 7253 if rev and node:
7251 7254 raise error.Abort(_("please specify just one revision"))
7252 7255
7253 7256 if rev is None or rev == '':
7254 7257 rev = node
7255 7258
7256 7259 if date and rev is not None:
7257 7260 raise error.Abort(_("you can't specify a revision and a date"))
7258 7261
7259 7262 if check and clean:
7260 7263 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7261 7264
7262 7265 with repo.wlock():
7263 7266 cmdutil.clearunfinished(repo)
7264 7267
7265 7268 if date:
7266 7269 rev = cmdutil.finddate(ui, repo, date)
7267 7270
7268 7271 # if we defined a bookmark, we have to remember the original name
7269 7272 brev = rev
7270 7273 rev = scmutil.revsingle(repo, rev, rev).rev()
7271 7274
7272 7275 if check:
7273 7276 cmdutil.bailifchanged(repo, merge=False)
7274 7277
7275 7278 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7276 7279
7277 7280 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7278 7281
7279 7282 @command('verify', [])
7280 7283 def verify(ui, repo):
7281 7284 """verify the integrity of the repository
7282 7285
7283 7286 Verify the integrity of the current repository.
7284 7287
7285 7288 This will perform an extensive check of the repository's
7286 7289 integrity, validating the hashes and checksums of each entry in
7287 7290 the changelog, manifest, and tracked files, as well as the
7288 7291 integrity of their crosslinks and indices.
7289 7292
7290 7293 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7291 7294 for more information about recovery from corruption of the
7292 7295 repository.
7293 7296
7294 7297 Returns 0 on success, 1 if errors are encountered.
7295 7298 """
7296 7299 return hg.verify(repo)
7297 7300
7298 7301 @command('version', [] + formatteropts, norepo=True)
7299 7302 def version_(ui, **opts):
7300 7303 """output version and copyright information"""
7301 7304 fm = ui.formatter("version", opts)
7302 7305 fm.startitem()
7303 7306 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
7304 7307 util.version())
7305 7308 license = _(
7306 7309 "(see https://mercurial-scm.org for more information)\n"
7307 7310 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7308 7311 "This is free software; see the source for copying conditions. "
7309 7312 "There is NO\nwarranty; "
7310 7313 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7311 7314 )
7312 7315 if not ui.quiet:
7313 7316 fm.plain(license)
7314 7317
7315 7318 if ui.verbose:
7316 7319 fm.plain(_("\nEnabled extensions:\n\n"))
7317 7320 # format names and versions into columns
7318 7321 names = []
7319 7322 vers = []
7320 7323 isinternals = []
7321 7324 for name, module in extensions.extensions():
7322 7325 names.append(name)
7323 7326 vers.append(extensions.moduleversion(module) or None)
7324 7327 isinternals.append(extensions.ismoduleinternal(module))
7325 7328 fn = fm.nested("extensions")
7326 7329 if names:
7327 7330 namefmt = " %%-%ds " % max(len(n) for n in names)
7328 7331 places = [_("external"), _("internal")]
7329 7332 for n, v, p in zip(names, vers, isinternals):
7330 7333 fn.startitem()
7331 7334 fn.condwrite(ui.verbose, "name", namefmt, n)
7332 7335 if ui.verbose:
7333 7336 fn.plain("%s " % places[p])
7334 7337 fn.data(bundled=p)
7335 7338 fn.condwrite(ui.verbose and v, "ver", "%s", v)
7336 7339 if ui.verbose:
7337 7340 fn.plain("\n")
7338 7341 fn.end()
7339 7342 fm.end()
7340 7343
7341 7344 def loadcmdtable(ui, name, cmdtable):
7342 7345 """Load command functions from specified cmdtable
7343 7346 """
7344 7347 overrides = [cmd for cmd in cmdtable if cmd in table]
7345 7348 if overrides:
7346 7349 ui.warn(_("extension '%s' overrides commands: %s\n")
7347 7350 % (name, " ".join(overrides)))
7348 7351 table.update(cmdtable)
@@ -1,352 +1,352
1 1 Show all commands except debug commands
2 2 $ hg debugcomplete
3 3 add
4 4 addremove
5 5 annotate
6 6 archive
7 7 backout
8 8 bisect
9 9 bookmarks
10 10 branch
11 11 branches
12 12 bundle
13 13 cat
14 14 clone
15 15 commit
16 16 config
17 17 copy
18 18 diff
19 19 export
20 20 files
21 21 forget
22 22 graft
23 23 grep
24 24 heads
25 25 help
26 26 identify
27 27 import
28 28 incoming
29 29 init
30 30 locate
31 31 log
32 32 manifest
33 33 merge
34 34 outgoing
35 35 parents
36 36 paths
37 37 phase
38 38 pull
39 39 push
40 40 recover
41 41 remove
42 42 rename
43 43 resolve
44 44 revert
45 45 rollback
46 46 root
47 47 serve
48 48 status
49 49 summary
50 50 tag
51 51 tags
52 52 tip
53 53 unbundle
54 54 update
55 55 verify
56 56 version
57 57
58 58 Show all commands that start with "a"
59 59 $ hg debugcomplete a
60 60 add
61 61 addremove
62 62 annotate
63 63 archive
64 64
65 65 Do not show debug commands if there are other candidates
66 66 $ hg debugcomplete d
67 67 diff
68 68
69 69 Show debug commands if there are no other candidates
70 70 $ hg debugcomplete debug
71 71 debugancestor
72 72 debugapplystreamclonebundle
73 73 debugbuilddag
74 74 debugbundle
75 75 debugcheckstate
76 76 debugcommands
77 77 debugcomplete
78 78 debugconfig
79 79 debugcreatestreamclonebundle
80 80 debugdag
81 81 debugdata
82 82 debugdate
83 83 debugdeltachain
84 84 debugdirstate
85 85 debugdiscovery
86 86 debugextensions
87 87 debugfileset
88 88 debugfsinfo
89 89 debuggetbundle
90 90 debugignore
91 91 debugindex
92 92 debugindexdot
93 93 debuginstall
94 94 debugknown
95 95 debuglabelcomplete
96 96 debuglocks
97 97 debugmergestate
98 98 debugnamecomplete
99 99 debugobsolete
100 100 debugpathcomplete
101 101 debugpushkey
102 102 debugpvec
103 103 debugrebuilddirstate
104 104 debugrebuildfncache
105 105 debugrename
106 106 debugrevlog
107 107 debugrevspec
108 108 debugsetparents
109 109 debugsub
110 110 debugsuccessorssets
111 111 debugtemplate
112 112 debugwalk
113 113 debugwireargs
114 114
115 115 Do not show the alias of a debug command if there are other candidates
116 116 (this should hide rawcommit)
117 117 $ hg debugcomplete r
118 118 recover
119 119 remove
120 120 rename
121 121 resolve
122 122 revert
123 123 rollback
124 124 root
125 125 Show the alias of a debug command if there are no other candidates
126 126 $ hg debugcomplete rawc
127 127
128 128
129 129 Show the global options
130 130 $ hg debugcomplete --options | sort
131 131 --config
132 132 --cwd
133 133 --debug
134 134 --debugger
135 135 --encoding
136 136 --encodingmode
137 137 --help
138 138 --hidden
139 139 --noninteractive
140 140 --profile
141 141 --quiet
142 142 --repository
143 143 --time
144 144 --traceback
145 145 --verbose
146 146 --version
147 147 -R
148 148 -h
149 149 -q
150 150 -v
151 151 -y
152 152
153 153 Show the options for the "serve" command
154 154 $ hg debugcomplete --options serve | sort
155 155 --accesslog
156 156 --address
157 157 --certificate
158 158 --cmdserver
159 159 --config
160 160 --cwd
161 161 --daemon
162 162 --daemon-postexec
163 163 --debug
164 164 --debugger
165 165 --encoding
166 166 --encodingmode
167 167 --errorlog
168 168 --help
169 169 --hidden
170 170 --ipv6
171 171 --name
172 172 --noninteractive
173 173 --pid-file
174 174 --port
175 175 --prefix
176 176 --profile
177 177 --quiet
178 178 --repository
179 179 --stdio
180 180 --style
181 181 --templates
182 182 --time
183 183 --traceback
184 184 --verbose
185 185 --version
186 186 --web-conf
187 187 -6
188 188 -A
189 189 -E
190 190 -R
191 191 -a
192 192 -d
193 193 -h
194 194 -n
195 195 -p
196 196 -q
197 197 -t
198 198 -v
199 199 -y
200 200
201 201 Show an error if we use --options with an ambiguous abbreviation
202 202 $ hg debugcomplete --options s
203 203 hg: command 's' is ambiguous:
204 204 serve showconfig status summary
205 205 [255]
206 206
207 207 Show all commands + options
208 208 $ hg debugcommands
209 209 add: include, exclude, subrepos, dry-run
210 210 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, ignore-all-space, ignore-space-change, ignore-blank-lines, include, exclude, template
211 211 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd, insecure
212 212 commit: addremove, close-branch, amend, secret, edit, interactive, include, exclude, message, logfile, date, user, subrepos
213 213 diff: rev, change, text, git, nodates, noprefix, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, root, include, exclude, subrepos
214 214 export: output, switch-parent, rev, text, git, nodates
215 215 forget: include, exclude
216 216 init: ssh, remotecmd, insecure
217 217 log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, patch, git, limit, no-merges, stat, graph, style, template, include, exclude
218 218 merge: force, rev, preview, tool
219 219 pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
220 220 push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
221 221 remove: after, force, subrepos, include, exclude
222 222 serve: accesslog, daemon, daemon-postexec, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate
223 223 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos, template
224 224 summary: remote
225 225 update: clean, check, date, rev, tool
226 226 addremove: similarity, subrepos, include, exclude, dry-run
227 227 archive: no-decode, prefix, rev, type, subrepos, include, exclude
228 228 backout: merge, commit, no-commit, parent, rev, edit, tool, include, exclude, message, logfile, date, user
229 229 bisect: reset, good, bad, skip, extend, command, noupdate
230 230 bookmarks: force, rev, delete, rename, inactive, template
231 231 branch: force, clean
232 232 branches: active, closed, template
233 233 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
234 234 cat: output, rev, decode, include, exclude
235 235 config: untrusted, edit, local, global
236 236 copy: after, force, include, exclude, dry-run
237 237 debugancestor:
238 238 debugapplystreamclonebundle:
239 239 debugbuilddag: mergeable-file, overwritten-file, new-file
240 240 debugbundle: all, spec
241 241 debugcheckstate:
242 242 debugcommands:
243 243 debugcomplete: options
244 244 debugcreatestreamclonebundle:
245 245 debugdag: tags, branches, dots, spaces
246 246 debugdata: changelog, manifest, dir
247 247 debugdate: extended
248 248 debugdeltachain: changelog, manifest, dir, template
249 249 debugdirstate: nodates, datesort
250 250 debugdiscovery: old, nonheads, ssh, remotecmd, insecure
251 251 debugextensions: template
252 252 debugfileset: rev
253 253 debugfsinfo:
254 254 debuggetbundle: head, common, type
255 255 debugignore:
256 256 debugindex: changelog, manifest, dir, format
257 257 debugindexdot: changelog, manifest, dir
258 258 debuginstall: template
259 259 debugknown:
260 260 debuglabelcomplete:
261 261 debuglocks: force-lock, force-wlock
262 262 debugmergestate:
263 263 debugnamecomplete:
264 264 debugobsolete: flags, record-parents, rev, index, delete, date, user, template
265 265 debugpathcomplete: full, normal, added, removed
266 266 debugpushkey:
267 267 debugpvec:
268 268 debugrebuilddirstate: rev, minimal
269 269 debugrebuildfncache:
270 270 debugrename: rev
271 271 debugrevlog: changelog, manifest, dir, dump
272 debugrevspec: optimize, show-stage
272 debugrevspec: optimize, show-stage, no-optimized
273 273 debugsetparents:
274 274 debugsub: rev
275 275 debugsuccessorssets:
276 276 debugtemplate: rev, define
277 277 debugwalk: include, exclude
278 278 debugwireargs: three, four, five, ssh, remotecmd, insecure
279 279 files: rev, print0, include, exclude, template, subrepos
280 280 graft: rev, continue, edit, log, force, currentdate, currentuser, date, user, tool, dry-run
281 281 grep: print0, all, text, follow, ignore-case, files-with-matches, line-number, rev, user, date, template, include, exclude
282 282 heads: rev, topo, active, closed, style, template
283 283 help: extension, command, keyword, system
284 284 identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure
285 285 import: strip, base, edit, force, no-commit, bypass, partial, exact, prefix, import-branch, message, logfile, date, user, similarity
286 286 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
287 287 locate: rev, print0, fullpath, include, exclude
288 288 manifest: rev, all, template
289 289 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
290 290 parents: rev, style, template
291 291 paths: template
292 292 phase: public, draft, secret, force, rev
293 293 recover:
294 294 rename: after, force, include, exclude, dry-run
295 295 resolve: all, list, mark, unmark, no-status, tool, include, exclude, template
296 296 revert: all, date, rev, no-backup, interactive, include, exclude, dry-run
297 297 rollback: dry-run, force
298 298 root:
299 299 tag: force, local, rev, remove, edit, message, date, user
300 300 tags: template
301 301 tip: patch, git, style, template
302 302 unbundle: update
303 303 verify:
304 304 version: template
305 305
306 306 $ hg init a
307 307 $ cd a
308 308 $ echo fee > fee
309 309 $ hg ci -q -Amfee
310 310 $ hg tag fee
311 311 $ mkdir fie
312 312 $ echo dead > fie/dead
313 313 $ echo live > fie/live
314 314 $ hg bookmark fo
315 315 $ hg branch -q fie
316 316 $ hg ci -q -Amfie
317 317 $ echo fo > fo
318 318 $ hg branch -qf default
319 319 $ hg ci -q -Amfo
320 320 $ echo Fum > Fum
321 321 $ hg ci -q -AmFum
322 322 $ hg bookmark Fum
323 323
324 324 Test debugpathcomplete
325 325
326 326 $ hg debugpathcomplete f
327 327 fee
328 328 fie
329 329 fo
330 330 $ hg debugpathcomplete -f f
331 331 fee
332 332 fie/dead
333 333 fie/live
334 334 fo
335 335
336 336 $ hg rm Fum
337 337 $ hg debugpathcomplete -r F
338 338 Fum
339 339
340 340 Test debugnamecomplete
341 341
342 342 $ hg debugnamecomplete
343 343 Fum
344 344 default
345 345 fee
346 346 fie
347 347 fo
348 348 tip
349 349 $ hg debugnamecomplete f
350 350 fee
351 351 fie
352 352 fo
@@ -1,3278 +1,3319
1 1 $ HGENCODING=utf-8
2 2 $ export HGENCODING
3 3 $ cat > testrevset.py << EOF
4 4 > import mercurial.revset
5 5 >
6 6 > baseset = mercurial.revset.baseset
7 7 >
8 8 > def r3232(repo, subset, x):
9 9 > """"simple revset that return [3,2,3,2]
10 10 >
11 11 > revisions duplicated on purpose.
12 12 > """
13 13 > if 3 not in subset:
14 14 > if 2 in subset:
15 15 > return baseset([2,2])
16 16 > return baseset()
17 17 > return baseset([3,3,2,2])
18 18 >
19 19 > mercurial.revset.symbols['r3232'] = r3232
20 20 > EOF
21 21 $ cat >> $HGRCPATH << EOF
22 22 > [extensions]
23 23 > testrevset=$TESTTMP/testrevset.py
24 24 > EOF
25 25
26 26 $ try() {
27 27 > hg debugrevspec --debug "$@"
28 28 > }
29 29
30 30 $ log() {
31 31 > hg log --template '{rev}\n' -r "$1"
32 32 > }
33 33
34 34 extension to build '_intlist()' and '_hexlist()', which is necessary because
35 35 these predicates use '\0' as a separator:
36 36
37 37 $ cat <<EOF > debugrevlistspec.py
38 38 > from __future__ import absolute_import
39 39 > from mercurial import (
40 40 > cmdutil,
41 41 > node as nodemod,
42 42 > revset,
43 43 > )
44 44 > cmdtable = {}
45 45 > command = cmdutil.command(cmdtable)
46 46 > @command('debugrevlistspec',
47 47 > [('', 'optimize', None, 'print parsed tree after optimizing'),
48 48 > ('', 'bin', None, 'unhexlify arguments')])
49 49 > def debugrevlistspec(ui, repo, fmt, *args, **opts):
50 50 > if opts['bin']:
51 51 > args = map(nodemod.bin, args)
52 52 > expr = revset.formatspec(fmt, list(args))
53 53 > if ui.verbose:
54 54 > tree = revset.parse(expr, lookup=repo.__contains__)
55 55 > ui.note(revset.prettyformat(tree), "\n")
56 56 > if opts["optimize"]:
57 57 > opttree = revset.optimize(revset.analyze(tree))
58 58 > ui.note("* optimized:\n", revset.prettyformat(opttree), "\n")
59 59 > func = revset.match(ui, expr, repo)
60 60 > revs = func(repo)
61 61 > if ui.verbose:
62 62 > ui.note("* set:\n", revset.prettyformatset(revs), "\n")
63 63 > for c in revs:
64 64 > ui.write("%s\n" % c)
65 65 > EOF
66 66 $ cat <<EOF >> $HGRCPATH
67 67 > [extensions]
68 68 > debugrevlistspec = $TESTTMP/debugrevlistspec.py
69 69 > EOF
70 70 $ trylist() {
71 71 > hg debugrevlistspec --debug "$@"
72 72 > }
73 73
74 74 $ hg init repo
75 75 $ cd repo
76 76
77 77 $ echo a > a
78 78 $ hg branch a
79 79 marked working directory as branch a
80 80 (branches are permanent and global, did you want a bookmark?)
81 81 $ hg ci -Aqm0
82 82
83 83 $ echo b > b
84 84 $ hg branch b
85 85 marked working directory as branch b
86 86 $ hg ci -Aqm1
87 87
88 88 $ rm a
89 89 $ hg branch a-b-c-
90 90 marked working directory as branch a-b-c-
91 91 $ hg ci -Aqm2 -u Bob
92 92
93 93 $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
94 94 2
95 95 $ hg log -r "extra('branch')" --template '{rev}\n'
96 96 0
97 97 1
98 98 2
99 99 $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
100 100 0 a
101 101 2 a-b-c-
102 102
103 103 $ hg co 1
104 104 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
105 105 $ hg branch +a+b+c+
106 106 marked working directory as branch +a+b+c+
107 107 $ hg ci -Aqm3
108 108
109 109 $ hg co 2 # interleave
110 110 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
111 111 $ echo bb > b
112 112 $ hg branch -- -a-b-c-
113 113 marked working directory as branch -a-b-c-
114 114 $ hg ci -Aqm4 -d "May 12 2005"
115 115
116 116 $ hg co 3
117 117 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
118 118 $ hg branch !a/b/c/
119 119 marked working directory as branch !a/b/c/
120 120 $ hg ci -Aqm"5 bug"
121 121
122 122 $ hg merge 4
123 123 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
124 124 (branch merge, don't forget to commit)
125 125 $ hg branch _a_b_c_
126 126 marked working directory as branch _a_b_c_
127 127 $ hg ci -Aqm"6 issue619"
128 128
129 129 $ hg branch .a.b.c.
130 130 marked working directory as branch .a.b.c.
131 131 $ hg ci -Aqm7
132 132
133 133 $ hg branch all
134 134 marked working directory as branch all
135 135
136 136 $ hg co 4
137 137 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
138 138 $ hg branch Γ©
139 139 marked working directory as branch \xc3\xa9 (esc)
140 140 $ hg ci -Aqm9
141 141
142 142 $ hg tag -r6 1.0
143 143 $ hg bookmark -r6 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
144 144
145 145 $ hg clone --quiet -U -r 7 . ../remote1
146 146 $ hg clone --quiet -U -r 8 . ../remote2
147 147 $ echo "[paths]" >> .hg/hgrc
148 148 $ echo "default = ../remote1" >> .hg/hgrc
149 149
150 150 trivial
151 151
152 152 $ try 0:1
153 153 (range
154 154 ('symbol', '0')
155 155 ('symbol', '1'))
156 156 * set:
157 157 <spanset+ 0:1>
158 158 0
159 159 1
160 160 $ try --optimize :
161 161 (rangeall
162 162 None)
163 163 * optimized:
164 164 (range
165 165 ('string', '0')
166 166 ('string', 'tip'))
167 167 * set:
168 168 <spanset+ 0:9>
169 169 0
170 170 1
171 171 2
172 172 3
173 173 4
174 174 5
175 175 6
176 176 7
177 177 8
178 178 9
179 179 $ try 3::6
180 180 (dagrange
181 181 ('symbol', '3')
182 182 ('symbol', '6'))
183 183 * set:
184 184 <baseset+ [3, 5, 6]>
185 185 3
186 186 5
187 187 6
188 188 $ try '0|1|2'
189 189 (or
190 190 ('symbol', '0')
191 191 ('symbol', '1')
192 192 ('symbol', '2'))
193 193 * set:
194 194 <baseset [0, 1, 2]>
195 195 0
196 196 1
197 197 2
198 198
199 199 names that should work without quoting
200 200
201 201 $ try a
202 202 ('symbol', 'a')
203 203 * set:
204 204 <baseset [0]>
205 205 0
206 206 $ try b-a
207 207 (minus
208 208 ('symbol', 'b')
209 209 ('symbol', 'a'))
210 210 * set:
211 211 <filteredset
212 212 <baseset [1]>,
213 213 <not
214 214 <baseset [0]>>>
215 215 1
216 216 $ try _a_b_c_
217 217 ('symbol', '_a_b_c_')
218 218 * set:
219 219 <baseset [6]>
220 220 6
221 221 $ try _a_b_c_-a
222 222 (minus
223 223 ('symbol', '_a_b_c_')
224 224 ('symbol', 'a'))
225 225 * set:
226 226 <filteredset
227 227 <baseset [6]>,
228 228 <not
229 229 <baseset [0]>>>
230 230 6
231 231 $ try .a.b.c.
232 232 ('symbol', '.a.b.c.')
233 233 * set:
234 234 <baseset [7]>
235 235 7
236 236 $ try .a.b.c.-a
237 237 (minus
238 238 ('symbol', '.a.b.c.')
239 239 ('symbol', 'a'))
240 240 * set:
241 241 <filteredset
242 242 <baseset [7]>,
243 243 <not
244 244 <baseset [0]>>>
245 245 7
246 246
247 247 names that should be caught by fallback mechanism
248 248
249 249 $ try -- '-a-b-c-'
250 250 ('symbol', '-a-b-c-')
251 251 * set:
252 252 <baseset [4]>
253 253 4
254 254 $ log -a-b-c-
255 255 4
256 256 $ try '+a+b+c+'
257 257 ('symbol', '+a+b+c+')
258 258 * set:
259 259 <baseset [3]>
260 260 3
261 261 $ try '+a+b+c+:'
262 262 (rangepost
263 263 ('symbol', '+a+b+c+'))
264 264 * set:
265 265 <spanset+ 3:9>
266 266 3
267 267 4
268 268 5
269 269 6
270 270 7
271 271 8
272 272 9
273 273 $ try ':+a+b+c+'
274 274 (rangepre
275 275 ('symbol', '+a+b+c+'))
276 276 * set:
277 277 <spanset+ 0:3>
278 278 0
279 279 1
280 280 2
281 281 3
282 282 $ try -- '-a-b-c-:+a+b+c+'
283 283 (range
284 284 ('symbol', '-a-b-c-')
285 285 ('symbol', '+a+b+c+'))
286 286 * set:
287 287 <spanset- 3:4>
288 288 4
289 289 3
290 290 $ log '-a-b-c-:+a+b+c+'
291 291 4
292 292 3
293 293
294 294 $ try -- -a-b-c--a # complains
295 295 (minus
296 296 (minus
297 297 (minus
298 298 (negate
299 299 ('symbol', 'a'))
300 300 ('symbol', 'b'))
301 301 ('symbol', 'c'))
302 302 (negate
303 303 ('symbol', 'a')))
304 304 abort: unknown revision '-a'!
305 305 [255]
306 306 $ try Γ©
307 307 ('symbol', '\xc3\xa9')
308 308 * set:
309 309 <baseset [9]>
310 310 9
311 311
312 312 no quoting needed
313 313
314 314 $ log ::a-b-c-
315 315 0
316 316 1
317 317 2
318 318
319 319 quoting needed
320 320
321 321 $ try '"-a-b-c-"-a'
322 322 (minus
323 323 ('string', '-a-b-c-')
324 324 ('symbol', 'a'))
325 325 * set:
326 326 <filteredset
327 327 <baseset [4]>,
328 328 <not
329 329 <baseset [0]>>>
330 330 4
331 331
332 332 $ log '1 or 2'
333 333 1
334 334 2
335 335 $ log '1|2'
336 336 1
337 337 2
338 338 $ log '1 and 2'
339 339 $ log '1&2'
340 340 $ try '1&2|3' # precedence - and is higher
341 341 (or
342 342 (and
343 343 ('symbol', '1')
344 344 ('symbol', '2'))
345 345 ('symbol', '3'))
346 346 * set:
347 347 <addset
348 348 <baseset []>,
349 349 <baseset [3]>>
350 350 3
351 351 $ try '1|2&3'
352 352 (or
353 353 ('symbol', '1')
354 354 (and
355 355 ('symbol', '2')
356 356 ('symbol', '3')))
357 357 * set:
358 358 <addset
359 359 <baseset [1]>,
360 360 <baseset []>>
361 361 1
362 362 $ try '1&2&3' # associativity
363 363 (and
364 364 (and
365 365 ('symbol', '1')
366 366 ('symbol', '2'))
367 367 ('symbol', '3'))
368 368 * set:
369 369 <baseset []>
370 370 $ try '1|(2|3)'
371 371 (or
372 372 ('symbol', '1')
373 373 (group
374 374 (or
375 375 ('symbol', '2')
376 376 ('symbol', '3'))))
377 377 * set:
378 378 <addset
379 379 <baseset [1]>,
380 380 <baseset [2, 3]>>
381 381 1
382 382 2
383 383 3
384 384 $ log '1.0' # tag
385 385 6
386 386 $ log 'a' # branch
387 387 0
388 388 $ log '2785f51ee'
389 389 0
390 390 $ log 'date(2005)'
391 391 4
392 392 $ log 'date(this is a test)'
393 393 hg: parse error at 10: unexpected token: symbol
394 394 [255]
395 395 $ log 'date()'
396 396 hg: parse error: date requires a string
397 397 [255]
398 398 $ log 'date'
399 399 abort: unknown revision 'date'!
400 400 [255]
401 401 $ log 'date('
402 402 hg: parse error at 5: not a prefix: end
403 403 [255]
404 404 $ log 'date("\xy")'
405 405 hg: parse error: invalid \x escape
406 406 [255]
407 407 $ log 'date(tip)'
408 408 abort: invalid date: 'tip'
409 409 [255]
410 410 $ log '0:date'
411 411 abort: unknown revision 'date'!
412 412 [255]
413 413 $ log '::"date"'
414 414 abort: unknown revision 'date'!
415 415 [255]
416 416 $ hg book date -r 4
417 417 $ log '0:date'
418 418 0
419 419 1
420 420 2
421 421 3
422 422 4
423 423 $ log '::date'
424 424 0
425 425 1
426 426 2
427 427 4
428 428 $ log '::"date"'
429 429 0
430 430 1
431 431 2
432 432 4
433 433 $ log 'date(2005) and 1::'
434 434 4
435 435 $ hg book -d date
436 436
437 437 function name should be a symbol
438 438
439 439 $ log '"date"(2005)'
440 440 hg: parse error: not a symbol
441 441 [255]
442 442
443 443 keyword arguments
444 444
445 445 $ log 'extra(branch, value=a)'
446 446 0
447 447
448 448 $ log 'extra(branch, a, b)'
449 449 hg: parse error: extra takes at most 2 arguments
450 450 [255]
451 451 $ log 'extra(a, label=b)'
452 452 hg: parse error: extra got multiple values for keyword argument 'label'
453 453 [255]
454 454 $ log 'extra(label=branch, default)'
455 455 hg: parse error: extra got an invalid argument
456 456 [255]
457 457 $ log 'extra(branch, foo+bar=baz)'
458 458 hg: parse error: extra got an invalid argument
459 459 [255]
460 460 $ log 'extra(unknown=branch)'
461 461 hg: parse error: extra got an unexpected keyword argument 'unknown'
462 462 [255]
463 463
464 464 $ try 'foo=bar|baz'
465 465 (keyvalue
466 466 ('symbol', 'foo')
467 467 (or
468 468 ('symbol', 'bar')
469 469 ('symbol', 'baz')))
470 470 hg: parse error: can't use a key-value pair in this context
471 471 [255]
472 472
473 473 right-hand side should be optimized recursively
474 474
475 475 $ try --optimize 'foo=(not public())'
476 476 (keyvalue
477 477 ('symbol', 'foo')
478 478 (group
479 479 (not
480 480 (func
481 481 ('symbol', 'public')
482 482 None))))
483 483 * optimized:
484 484 (keyvalue
485 485 ('symbol', 'foo')
486 486 (func
487 487 ('symbol', '_notpublic')
488 488 None))
489 489 hg: parse error: can't use a key-value pair in this context
490 490 [255]
491 491
492 492 parsed tree at stages:
493 493
494 494 $ hg debugrevspec -p all '()'
495 495 * parsed:
496 496 (group
497 497 None)
498 498 * expanded:
499 499 (group
500 500 None)
501 501 * concatenated:
502 502 (group
503 503 None)
504 504 * analyzed:
505 505 None
506 506 * optimized:
507 507 None
508 508 hg: parse error: missing argument
509 509 [255]
510 510
511 $ hg debugrevspec --no-optimized -p all '()'
512 * parsed:
513 (group
514 None)
515 * expanded:
516 (group
517 None)
518 * concatenated:
519 (group
520 None)
521 * analyzed:
522 None
523 hg: parse error: missing argument
524 [255]
525
511 526 $ hg debugrevspec -p parsed -p analyzed -p optimized '(0|1)-1'
512 527 * parsed:
513 528 (minus
514 529 (group
515 530 (or
516 531 ('symbol', '0')
517 532 ('symbol', '1')))
518 533 ('symbol', '1'))
519 534 * analyzed:
520 535 (and
521 536 (or
522 537 ('symbol', '0')
523 538 ('symbol', '1'))
524 539 (not
525 540 ('symbol', '1')))
526 541 * optimized:
527 542 (difference
528 543 (func
529 544 ('symbol', '_list')
530 545 ('string', '0\x001'))
531 546 ('symbol', '1'))
532 547 0
533 548
534 549 $ hg debugrevspec -p unknown '0'
535 550 abort: invalid stage name: unknown
536 551 [255]
537 552
538 553 $ hg debugrevspec -p all --optimize '0'
539 554 abort: cannot use --optimize with --show-stage
540 555 [255]
541 556
542 557 Test that symbols only get parsed as functions if there's an opening
543 558 parenthesis.
544 559
545 560 $ hg book only -r 9
546 561 $ log 'only(only)' # Outer "only" is a function, inner "only" is the bookmark
547 562 8
548 563 9
549 564
550 565 infix/suffix resolution of ^ operator (issue2884):
551 566
552 567 x^:y means (x^):y
553 568
554 569 $ try '1^:2'
555 570 (range
556 571 (parentpost
557 572 ('symbol', '1'))
558 573 ('symbol', '2'))
559 574 * set:
560 575 <spanset+ 0:2>
561 576 0
562 577 1
563 578 2
564 579
565 580 $ try '1^::2'
566 581 (dagrange
567 582 (parentpost
568 583 ('symbol', '1'))
569 584 ('symbol', '2'))
570 585 * set:
571 586 <baseset+ [0, 1, 2]>
572 587 0
573 588 1
574 589 2
575 590
576 591 $ try '9^:'
577 592 (rangepost
578 593 (parentpost
579 594 ('symbol', '9')))
580 595 * set:
581 596 <spanset+ 8:9>
582 597 8
583 598 9
584 599
585 600 x^:y should be resolved before omitting group operators
586 601
587 602 $ try '1^(:2)'
588 603 (parent
589 604 ('symbol', '1')
590 605 (group
591 606 (rangepre
592 607 ('symbol', '2'))))
593 608 hg: parse error: ^ expects a number 0, 1, or 2
594 609 [255]
595 610
596 611 x^:y should be resolved recursively
597 612
598 613 $ try 'sort(1^:2)'
599 614 (func
600 615 ('symbol', 'sort')
601 616 (range
602 617 (parentpost
603 618 ('symbol', '1'))
604 619 ('symbol', '2')))
605 620 * set:
606 621 <spanset+ 0:2>
607 622 0
608 623 1
609 624 2
610 625
611 626 $ try '(3^:4)^:2'
612 627 (range
613 628 (parentpost
614 629 (group
615 630 (range
616 631 (parentpost
617 632 ('symbol', '3'))
618 633 ('symbol', '4'))))
619 634 ('symbol', '2'))
620 635 * set:
621 636 <spanset+ 0:2>
622 637 0
623 638 1
624 639 2
625 640
626 641 $ try '(3^::4)^::2'
627 642 (dagrange
628 643 (parentpost
629 644 (group
630 645 (dagrange
631 646 (parentpost
632 647 ('symbol', '3'))
633 648 ('symbol', '4'))))
634 649 ('symbol', '2'))
635 650 * set:
636 651 <baseset+ [0, 1, 2]>
637 652 0
638 653 1
639 654 2
640 655
641 656 $ try '(9^:)^:'
642 657 (rangepost
643 658 (parentpost
644 659 (group
645 660 (rangepost
646 661 (parentpost
647 662 ('symbol', '9'))))))
648 663 * set:
649 664 <spanset+ 4:9>
650 665 4
651 666 5
652 667 6
653 668 7
654 669 8
655 670 9
656 671
657 672 x^ in alias should also be resolved
658 673
659 674 $ try 'A' --config 'revsetalias.A=1^:2'
660 675 ('symbol', 'A')
661 676 * expanded:
662 677 (range
663 678 (parentpost
664 679 ('symbol', '1'))
665 680 ('symbol', '2'))
666 681 * set:
667 682 <spanset+ 0:2>
668 683 0
669 684 1
670 685 2
671 686
672 687 $ try 'A:2' --config 'revsetalias.A=1^'
673 688 (range
674 689 ('symbol', 'A')
675 690 ('symbol', '2'))
676 691 * expanded:
677 692 (range
678 693 (parentpost
679 694 ('symbol', '1'))
680 695 ('symbol', '2'))
681 696 * set:
682 697 <spanset+ 0:2>
683 698 0
684 699 1
685 700 2
686 701
687 702 but not beyond the boundary of alias expansion, because the resolution should
688 703 be made at the parsing stage
689 704
690 705 $ try '1^A' --config 'revsetalias.A=:2'
691 706 (parent
692 707 ('symbol', '1')
693 708 ('symbol', 'A'))
694 709 * expanded:
695 710 (parent
696 711 ('symbol', '1')
697 712 (rangepre
698 713 ('symbol', '2')))
699 714 hg: parse error: ^ expects a number 0, 1, or 2
700 715 [255]
701 716
702 717 ancestor can accept 0 or more arguments
703 718
704 719 $ log 'ancestor()'
705 720 $ log 'ancestor(1)'
706 721 1
707 722 $ log 'ancestor(4,5)'
708 723 1
709 724 $ log 'ancestor(4,5) and 4'
710 725 $ log 'ancestor(0,0,1,3)'
711 726 0
712 727 $ log 'ancestor(3,1,5,3,5,1)'
713 728 1
714 729 $ log 'ancestor(0,1,3,5)'
715 730 0
716 731 $ log 'ancestor(1,2,3,4,5)'
717 732 1
718 733
719 734 test ancestors
720 735
721 736 $ log 'ancestors(5)'
722 737 0
723 738 1
724 739 3
725 740 5
726 741 $ log 'ancestor(ancestors(5))'
727 742 0
728 743 $ log '::r3232()'
729 744 0
730 745 1
731 746 2
732 747 3
733 748
734 749 $ log 'author(bob)'
735 750 2
736 751 $ log 'author("re:bob|test")'
737 752 0
738 753 1
739 754 2
740 755 3
741 756 4
742 757 5
743 758 6
744 759 7
745 760 8
746 761 9
747 762 $ log 'branch(Γ©)'
748 763 8
749 764 9
750 765 $ log 'branch(a)'
751 766 0
752 767 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
753 768 0 a
754 769 2 a-b-c-
755 770 3 +a+b+c+
756 771 4 -a-b-c-
757 772 5 !a/b/c/
758 773 6 _a_b_c_
759 774 7 .a.b.c.
760 775 $ log 'children(ancestor(4,5))'
761 776 2
762 777 3
763 778 $ log 'closed()'
764 779 $ log 'contains(a)'
765 780 0
766 781 1
767 782 3
768 783 5
769 784 $ log 'contains("../repo/a")'
770 785 0
771 786 1
772 787 3
773 788 5
774 789 $ log 'desc(B)'
775 790 5
776 791 $ log 'descendants(2 or 3)'
777 792 2
778 793 3
779 794 4
780 795 5
781 796 6
782 797 7
783 798 8
784 799 9
785 800 $ log 'file("b*")'
786 801 1
787 802 4
788 803 $ log 'filelog("b")'
789 804 1
790 805 4
791 806 $ log 'filelog("../repo/b")'
792 807 1
793 808 4
794 809 $ log 'follow()'
795 810 0
796 811 1
797 812 2
798 813 4
799 814 8
800 815 9
801 816 $ log 'grep("issue\d+")'
802 817 6
803 818 $ try 'grep("(")' # invalid regular expression
804 819 (func
805 820 ('symbol', 'grep')
806 821 ('string', '('))
807 822 hg: parse error: invalid match pattern: unbalanced parenthesis
808 823 [255]
809 824 $ try 'grep("\bissue\d+")'
810 825 (func
811 826 ('symbol', 'grep')
812 827 ('string', '\x08issue\\d+'))
813 828 * set:
814 829 <filteredset
815 830 <fullreposet+ 0:9>,
816 831 <grep '\x08issue\\d+'>>
817 832 $ try 'grep(r"\bissue\d+")'
818 833 (func
819 834 ('symbol', 'grep')
820 835 ('string', '\\bissue\\d+'))
821 836 * set:
822 837 <filteredset
823 838 <fullreposet+ 0:9>,
824 839 <grep '\\bissue\\d+'>>
825 840 6
826 841 $ try 'grep(r"\")'
827 842 hg: parse error at 7: unterminated string
828 843 [255]
829 844 $ log 'head()'
830 845 0
831 846 1
832 847 2
833 848 3
834 849 4
835 850 5
836 851 6
837 852 7
838 853 9
839 854 $ log 'heads(6::)'
840 855 7
841 856 $ log 'keyword(issue)'
842 857 6
843 858 $ log 'keyword("test a")'
844 859 $ log 'limit(head(), 1)'
845 860 0
846 861 $ log 'limit(author("re:bob|test"), 3, 5)'
847 862 5
848 863 6
849 864 7
850 865 $ log 'limit(author("re:bob|test"), offset=6)'
851 866 6
852 867 $ log 'limit(author("re:bob|test"), offset=10)'
853 868 $ log 'limit(all(), 1, -1)'
854 869 hg: parse error: negative offset
855 870 [255]
856 871 $ log 'matching(6)'
857 872 6
858 873 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
859 874 6
860 875 7
861 876
862 877 Testing min and max
863 878
864 879 max: simple
865 880
866 881 $ log 'max(contains(a))'
867 882 5
868 883
869 884 max: simple on unordered set)
870 885
871 886 $ log 'max((4+0+2+5+7) and contains(a))'
872 887 5
873 888
874 889 max: no result
875 890
876 891 $ log 'max(contains(stringthatdoesnotappearanywhere))'
877 892
878 893 max: no result on unordered set
879 894
880 895 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
881 896
882 897 min: simple
883 898
884 899 $ log 'min(contains(a))'
885 900 0
886 901
887 902 min: simple on unordered set
888 903
889 904 $ log 'min((4+0+2+5+7) and contains(a))'
890 905 0
891 906
892 907 min: empty
893 908
894 909 $ log 'min(contains(stringthatdoesnotappearanywhere))'
895 910
896 911 min: empty on unordered set
897 912
898 913 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
899 914
900 915
901 916 $ log 'merge()'
902 917 6
903 918 $ log 'branchpoint()'
904 919 1
905 920 4
906 921 $ log 'modifies(b)'
907 922 4
908 923 $ log 'modifies("path:b")'
909 924 4
910 925 $ log 'modifies("*")'
911 926 4
912 927 6
913 928 $ log 'modifies("set:modified()")'
914 929 4
915 930 $ log 'id(5)'
916 931 2
917 932 $ log 'only(9)'
918 933 8
919 934 9
920 935 $ log 'only(8)'
921 936 8
922 937 $ log 'only(9, 5)'
923 938 2
924 939 4
925 940 8
926 941 9
927 942 $ log 'only(7 + 9, 5 + 2)'
928 943 4
929 944 6
930 945 7
931 946 8
932 947 9
933 948
934 949 Test empty set input
935 950 $ log 'only(p2())'
936 951 $ log 'only(p1(), p2())'
937 952 0
938 953 1
939 954 2
940 955 4
941 956 8
942 957 9
943 958
944 959 Test '%' operator
945 960
946 961 $ log '9%'
947 962 8
948 963 9
949 964 $ log '9%5'
950 965 2
951 966 4
952 967 8
953 968 9
954 969 $ log '(7 + 9)%(5 + 2)'
955 970 4
956 971 6
957 972 7
958 973 8
959 974 9
960 975
961 976 Test opreand of '%' is optimized recursively (issue4670)
962 977
963 978 $ try --optimize '8:9-8%'
964 979 (onlypost
965 980 (minus
966 981 (range
967 982 ('symbol', '8')
968 983 ('symbol', '9'))
969 984 ('symbol', '8')))
970 985 * optimized:
971 986 (func
972 987 ('symbol', 'only')
973 988 (difference
974 989 (range
975 990 ('symbol', '8')
976 991 ('symbol', '9'))
977 992 ('symbol', '8')))
978 993 * set:
979 994 <baseset+ [8, 9]>
980 995 8
981 996 9
982 997 $ try --optimize '(9)%(5)'
983 998 (only
984 999 (group
985 1000 ('symbol', '9'))
986 1001 (group
987 1002 ('symbol', '5')))
988 1003 * optimized:
989 1004 (func
990 1005 ('symbol', 'only')
991 1006 (list
992 1007 ('symbol', '9')
993 1008 ('symbol', '5')))
994 1009 * set:
995 1010 <baseset+ [2, 4, 8, 9]>
996 1011 2
997 1012 4
998 1013 8
999 1014 9
1000 1015
1001 1016 Test the order of operations
1002 1017
1003 1018 $ log '7 + 9%5 + 2'
1004 1019 7
1005 1020 2
1006 1021 4
1007 1022 8
1008 1023 9
1009 1024
1010 1025 Test explicit numeric revision
1011 1026 $ log 'rev(-2)'
1012 1027 $ log 'rev(-1)'
1013 1028 -1
1014 1029 $ log 'rev(0)'
1015 1030 0
1016 1031 $ log 'rev(9)'
1017 1032 9
1018 1033 $ log 'rev(10)'
1019 1034 $ log 'rev(tip)'
1020 1035 hg: parse error: rev expects a number
1021 1036 [255]
1022 1037
1023 1038 Test hexadecimal revision
1024 1039 $ log 'id(2)'
1025 1040 abort: 00changelog.i@2: ambiguous identifier!
1026 1041 [255]
1027 1042 $ log 'id(23268)'
1028 1043 4
1029 1044 $ log 'id(2785f51eece)'
1030 1045 0
1031 1046 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532c)'
1032 1047 8
1033 1048 $ log 'id(d5d0dcbdc4a)'
1034 1049 $ log 'id(d5d0dcbdc4w)'
1035 1050 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532d)'
1036 1051 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532q)'
1037 1052 $ log 'id(1.0)'
1038 1053 $ log 'id(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)'
1039 1054
1040 1055 Test null revision
1041 1056 $ log '(null)'
1042 1057 -1
1043 1058 $ log '(null:0)'
1044 1059 -1
1045 1060 0
1046 1061 $ log '(0:null)'
1047 1062 0
1048 1063 -1
1049 1064 $ log 'null::0'
1050 1065 -1
1051 1066 0
1052 1067 $ log 'null:tip - 0:'
1053 1068 -1
1054 1069 $ log 'null: and null::' | head -1
1055 1070 -1
1056 1071 $ log 'null: or 0:' | head -2
1057 1072 -1
1058 1073 0
1059 1074 $ log 'ancestors(null)'
1060 1075 -1
1061 1076 $ log 'reverse(null:)' | tail -2
1062 1077 0
1063 1078 -1
1064 1079 BROKEN: should be '-1'
1065 1080 $ log 'first(null:)'
1066 1081 BROKEN: should be '-1'
1067 1082 $ log 'min(null:)'
1068 1083 $ log 'tip:null and all()' | tail -2
1069 1084 1
1070 1085 0
1071 1086
1072 1087 Test working-directory revision
1073 1088 $ hg debugrevspec 'wdir()'
1074 1089 2147483647
1075 1090 $ hg debugrevspec 'tip or wdir()'
1076 1091 9
1077 1092 2147483647
1078 1093 $ hg debugrevspec '0:tip and wdir()'
1079 1094 $ log '0:wdir()' | tail -3
1080 1095 8
1081 1096 9
1082 1097 2147483647
1083 1098 $ log 'wdir():0' | head -3
1084 1099 2147483647
1085 1100 9
1086 1101 8
1087 1102 $ log 'wdir():wdir()'
1088 1103 2147483647
1089 1104 $ log '(all() + wdir()) & min(. + wdir())'
1090 1105 9
1091 1106 $ log '(all() + wdir()) & max(. + wdir())'
1092 1107 2147483647
1093 1108 $ log '(all() + wdir()) & first(wdir() + .)'
1094 1109 2147483647
1095 1110 $ log '(all() + wdir()) & last(. + wdir())'
1096 1111 2147483647
1097 1112
1098 1113 $ log 'outgoing()'
1099 1114 8
1100 1115 9
1101 1116 $ log 'outgoing("../remote1")'
1102 1117 8
1103 1118 9
1104 1119 $ log 'outgoing("../remote2")'
1105 1120 3
1106 1121 5
1107 1122 6
1108 1123 7
1109 1124 9
1110 1125 $ log 'p1(merge())'
1111 1126 5
1112 1127 $ log 'p2(merge())'
1113 1128 4
1114 1129 $ log 'parents(merge())'
1115 1130 4
1116 1131 5
1117 1132 $ log 'p1(branchpoint())'
1118 1133 0
1119 1134 2
1120 1135 $ log 'p2(branchpoint())'
1121 1136 $ log 'parents(branchpoint())'
1122 1137 0
1123 1138 2
1124 1139 $ log 'removes(a)'
1125 1140 2
1126 1141 6
1127 1142 $ log 'roots(all())'
1128 1143 0
1129 1144 $ log 'reverse(2 or 3 or 4 or 5)'
1130 1145 5
1131 1146 4
1132 1147 3
1133 1148 2
1134 1149 $ log 'reverse(all())'
1135 1150 9
1136 1151 8
1137 1152 7
1138 1153 6
1139 1154 5
1140 1155 4
1141 1156 3
1142 1157 2
1143 1158 1
1144 1159 0
1145 1160 $ log 'reverse(all()) & filelog(b)'
1146 1161 4
1147 1162 1
1148 1163 $ log 'rev(5)'
1149 1164 5
1150 1165 $ log 'sort(limit(reverse(all()), 3))'
1151 1166 7
1152 1167 8
1153 1168 9
1154 1169 $ log 'sort(2 or 3 or 4 or 5, date)'
1155 1170 2
1156 1171 3
1157 1172 5
1158 1173 4
1159 1174 $ log 'tagged()'
1160 1175 6
1161 1176 $ log 'tag()'
1162 1177 6
1163 1178 $ log 'tag(1.0)'
1164 1179 6
1165 1180 $ log 'tag(tip)'
1166 1181 9
1167 1182
1168 1183 Test order of revisions in compound expression
1169 1184 ----------------------------------------------
1170 1185
1171 1186 The general rule is that only the outermost (= leftmost) predicate can
1172 1187 enforce its ordering requirement. The other predicates should take the
1173 1188 ordering defined by it.
1174 1189
1175 1190 'A & B' should follow the order of 'A':
1176 1191
1177 1192 $ log '2:0 & 0::2'
1178 1193 2
1179 1194 1
1180 1195 0
1181 1196
1182 1197 'head()' combines sets in right order:
1183 1198
1184 1199 $ log '2:0 & head()'
1185 1200 2
1186 1201 1
1187 1202 0
1188 1203
1189 1204 'a + b', which is optimized to '_list(a b)', should take the ordering of
1190 1205 the left expression:
1191 1206
1192 1207 $ try --optimize '2:0 & (0 + 1 + 2)'
1193 1208 (and
1194 1209 (range
1195 1210 ('symbol', '2')
1196 1211 ('symbol', '0'))
1197 1212 (group
1198 1213 (or
1199 1214 ('symbol', '0')
1200 1215 ('symbol', '1')
1201 1216 ('symbol', '2'))))
1202 1217 * optimized:
1203 1218 (and
1204 1219 (range
1205 1220 ('symbol', '2')
1206 1221 ('symbol', '0'))
1207 1222 (func
1208 1223 ('symbol', '_list')
1209 1224 ('string', '0\x001\x002')))
1210 1225 * set:
1211 1226 <baseset [0, 1, 2]>
1212 1227 0
1213 1228 1
1214 1229 2
1215 1230 BROKEN: should be '2 1 0'
1216 1231
1217 1232 'A + B' should take the ordering of the left expression:
1218 1233
1219 1234 $ try --optimize '2:0 & (0:1 + 2)'
1220 1235 (and
1221 1236 (range
1222 1237 ('symbol', '2')
1223 1238 ('symbol', '0'))
1224 1239 (group
1225 1240 (or
1226 1241 (range
1227 1242 ('symbol', '0')
1228 1243 ('symbol', '1'))
1229 1244 ('symbol', '2'))))
1230 1245 * optimized:
1231 1246 (and
1232 1247 (range
1233 1248 ('symbol', '2')
1234 1249 ('symbol', '0'))
1235 1250 (or
1236 1251 (range
1237 1252 ('symbol', '0')
1238 1253 ('symbol', '1'))
1239 1254 ('symbol', '2')))
1240 1255 * set:
1241 1256 <addset
1242 1257 <filteredset
1243 1258 <spanset+ 0:1>,
1244 1259 <spanset- 0:2>>,
1245 1260 <baseset [2]>>
1246 1261 0
1247 1262 1
1248 1263 2
1249 1264 BROKEN: should be '2 1 0'
1250 1265
1251 1266 '_intlist(a b)' should behave like 'a + b':
1252 1267
1253 1268 $ trylist --optimize '2:0 & %ld' 0 1 2
1254 1269 (and
1255 1270 (range
1256 1271 ('symbol', '2')
1257 1272 ('symbol', '0'))
1258 1273 (func
1259 1274 ('symbol', '_intlist')
1260 1275 ('string', '0\x001\x002')))
1261 1276 * optimized:
1262 1277 (and
1263 1278 (func
1264 1279 ('symbol', '_intlist')
1265 1280 ('string', '0\x001\x002'))
1266 1281 (range
1267 1282 ('symbol', '2')
1268 1283 ('symbol', '0')))
1269 1284 * set:
1270 1285 <filteredset
1271 1286 <spanset- 0:2>,
1272 1287 <baseset [0, 1, 2]>>
1273 1288 2
1274 1289 1
1275 1290 0
1276 1291
1277 1292 $ trylist --optimize '%ld & 2:0' 0 2 1
1278 1293 (and
1279 1294 (func
1280 1295 ('symbol', '_intlist')
1281 1296 ('string', '0\x002\x001'))
1282 1297 (range
1283 1298 ('symbol', '2')
1284 1299 ('symbol', '0')))
1285 1300 * optimized:
1286 1301 (and
1287 1302 (func
1288 1303 ('symbol', '_intlist')
1289 1304 ('string', '0\x002\x001'))
1290 1305 (range
1291 1306 ('symbol', '2')
1292 1307 ('symbol', '0')))
1293 1308 * set:
1294 1309 <filteredset
1295 1310 <spanset- 0:2>,
1296 1311 <baseset [0, 2, 1]>>
1297 1312 2
1298 1313 1
1299 1314 0
1300 1315 BROKEN: should be '0 2 1'
1301 1316
1302 1317 '_hexlist(a b)' should behave like 'a + b':
1303 1318
1304 1319 $ trylist --optimize --bin '2:0 & %ln' `hg log -T '{node} ' -r0:2`
1305 1320 (and
1306 1321 (range
1307 1322 ('symbol', '2')
1308 1323 ('symbol', '0'))
1309 1324 (func
1310 1325 ('symbol', '_hexlist')
1311 1326 ('string', '*'))) (glob)
1312 1327 * optimized:
1313 1328 (and
1314 1329 (range
1315 1330 ('symbol', '2')
1316 1331 ('symbol', '0'))
1317 1332 (func
1318 1333 ('symbol', '_hexlist')
1319 1334 ('string', '*'))) (glob)
1320 1335 * set:
1321 1336 <baseset [0, 1, 2]>
1322 1337 0
1323 1338 1
1324 1339 2
1325 1340 BROKEN: should be '2 1 0'
1326 1341
1327 1342 $ trylist --optimize --bin '%ln & 2:0' `hg log -T '{node} ' -r0+2+1`
1328 1343 (and
1329 1344 (func
1330 1345 ('symbol', '_hexlist')
1331 1346 ('string', '*')) (glob)
1332 1347 (range
1333 1348 ('symbol', '2')
1334 1349 ('symbol', '0')))
1335 1350 * optimized:
1336 1351 (and
1337 1352 (range
1338 1353 ('symbol', '2')
1339 1354 ('symbol', '0'))
1340 1355 (func
1341 1356 ('symbol', '_hexlist')
1342 1357 ('string', '*'))) (glob)
1343 1358 * set:
1344 1359 <baseset [0, 2, 1]>
1345 1360 0
1346 1361 2
1347 1362 1
1348 1363
1349 1364 'present()' should do nothing other than suppressing an error:
1350 1365
1351 1366 $ try --optimize '2:0 & present(0 + 1 + 2)'
1352 1367 (and
1353 1368 (range
1354 1369 ('symbol', '2')
1355 1370 ('symbol', '0'))
1356 1371 (func
1357 1372 ('symbol', 'present')
1358 1373 (or
1359 1374 ('symbol', '0')
1360 1375 ('symbol', '1')
1361 1376 ('symbol', '2'))))
1362 1377 * optimized:
1363 1378 (and
1364 1379 (range
1365 1380 ('symbol', '2')
1366 1381 ('symbol', '0'))
1367 1382 (func
1368 1383 ('symbol', 'present')
1369 1384 (func
1370 1385 ('symbol', '_list')
1371 1386 ('string', '0\x001\x002'))))
1372 1387 * set:
1373 1388 <baseset [0, 1, 2]>
1374 1389 0
1375 1390 1
1376 1391 2
1377 1392 BROKEN: should be '2 1 0'
1378 1393
1379 1394 'reverse()' should take effect only if it is the outermost expression:
1380 1395
1381 1396 $ try --optimize '0:2 & reverse(all())'
1382 1397 (and
1383 1398 (range
1384 1399 ('symbol', '0')
1385 1400 ('symbol', '2'))
1386 1401 (func
1387 1402 ('symbol', 'reverse')
1388 1403 (func
1389 1404 ('symbol', 'all')
1390 1405 None)))
1391 1406 * optimized:
1392 1407 (and
1393 1408 (range
1394 1409 ('symbol', '0')
1395 1410 ('symbol', '2'))
1396 1411 (func
1397 1412 ('symbol', 'reverse')
1398 1413 (func
1399 1414 ('symbol', 'all')
1400 1415 None)))
1401 1416 * set:
1402 1417 <filteredset
1403 1418 <spanset- 0:2>,
1404 1419 <spanset+ 0:9>>
1405 1420 2
1406 1421 1
1407 1422 0
1408 1423 BROKEN: should be '0 1 2'
1409 1424
1410 1425 'sort()' should take effect only if it is the outermost expression:
1411 1426
1412 1427 $ try --optimize '0:2 & sort(all(), -rev)'
1413 1428 (and
1414 1429 (range
1415 1430 ('symbol', '0')
1416 1431 ('symbol', '2'))
1417 1432 (func
1418 1433 ('symbol', 'sort')
1419 1434 (list
1420 1435 (func
1421 1436 ('symbol', 'all')
1422 1437 None)
1423 1438 (negate
1424 1439 ('symbol', 'rev')))))
1425 1440 * optimized:
1426 1441 (and
1427 1442 (range
1428 1443 ('symbol', '0')
1429 1444 ('symbol', '2'))
1430 1445 (func
1431 1446 ('symbol', 'sort')
1432 1447 (list
1433 1448 (func
1434 1449 ('symbol', 'all')
1435 1450 None)
1436 1451 ('string', '-rev'))))
1437 1452 * set:
1438 1453 <filteredset
1439 1454 <spanset- 0:2>,
1440 1455 <spanset+ 0:9>>
1441 1456 2
1442 1457 1
1443 1458 0
1444 1459 BROKEN: should be '0 1 2'
1445 1460
1446 1461 for 'A & f(B)', 'B' should not be affected by the order of 'A':
1447 1462
1448 1463 $ try --optimize '2:0 & first(1 + 0 + 2)'
1449 1464 (and
1450 1465 (range
1451 1466 ('symbol', '2')
1452 1467 ('symbol', '0'))
1453 1468 (func
1454 1469 ('symbol', 'first')
1455 1470 (or
1456 1471 ('symbol', '1')
1457 1472 ('symbol', '0')
1458 1473 ('symbol', '2'))))
1459 1474 * optimized:
1460 1475 (and
1461 1476 (range
1462 1477 ('symbol', '2')
1463 1478 ('symbol', '0'))
1464 1479 (func
1465 1480 ('symbol', 'first')
1466 1481 (func
1467 1482 ('symbol', '_list')
1468 1483 ('string', '1\x000\x002'))))
1469 1484 * set:
1470 1485 <baseset
1471 1486 <limit n=1, offset=0,
1472 1487 <spanset- 0:2>,
1473 1488 <baseset [1, 0, 2]>>>
1474 1489 1
1475 1490
1476 1491 $ try --optimize '2:0 & not last(0 + 2 + 1)'
1477 1492 (and
1478 1493 (range
1479 1494 ('symbol', '2')
1480 1495 ('symbol', '0'))
1481 1496 (not
1482 1497 (func
1483 1498 ('symbol', 'last')
1484 1499 (or
1485 1500 ('symbol', '0')
1486 1501 ('symbol', '2')
1487 1502 ('symbol', '1')))))
1488 1503 * optimized:
1489 1504 (difference
1490 1505 (range
1491 1506 ('symbol', '2')
1492 1507 ('symbol', '0'))
1493 1508 (func
1494 1509 ('symbol', 'last')
1495 1510 (func
1496 1511 ('symbol', '_list')
1497 1512 ('string', '0\x002\x001'))))
1498 1513 * set:
1499 1514 <filteredset
1500 1515 <spanset- 0:2>,
1501 1516 <not
1502 1517 <baseset
1503 1518 <last n=1,
1504 1519 <fullreposet+ 0:9>,
1505 1520 <baseset [1, 2, 0]>>>>>
1506 1521 2
1507 1522 0
1508 1523
1509 1524 for 'A & (op)(B)', 'B' should not be affected by the order of 'A':
1510 1525
1511 1526 $ try --optimize '2:0 & (1 + 0 + 2):(0 + 2 + 1)'
1512 1527 (and
1513 1528 (range
1514 1529 ('symbol', '2')
1515 1530 ('symbol', '0'))
1516 1531 (range
1517 1532 (group
1518 1533 (or
1519 1534 ('symbol', '1')
1520 1535 ('symbol', '0')
1521 1536 ('symbol', '2')))
1522 1537 (group
1523 1538 (or
1524 1539 ('symbol', '0')
1525 1540 ('symbol', '2')
1526 1541 ('symbol', '1')))))
1527 1542 * optimized:
1528 1543 (and
1529 1544 (range
1530 1545 ('symbol', '2')
1531 1546 ('symbol', '0'))
1532 1547 (range
1533 1548 (func
1534 1549 ('symbol', '_list')
1535 1550 ('string', '1\x000\x002'))
1536 1551 (func
1537 1552 ('symbol', '_list')
1538 1553 ('string', '0\x002\x001'))))
1539 1554 * set:
1540 1555 <filteredset
1541 1556 <baseset [1]>,
1542 1557 <spanset- 0:2>>
1543 1558 1
1544 1559
1545 1560 'A & B' can be rewritten as 'B & A' by weight, but the ordering rule should
1546 1561 be determined before the optimization (i.e. 'B' should take the ordering of
1547 1562 'A'):
1548 1563
1549 1564 $ try --optimize 'contains("glob:*") & (2 + 0 + 1)'
1550 1565 (and
1551 1566 (func
1552 1567 ('symbol', 'contains')
1553 1568 ('string', 'glob:*'))
1554 1569 (group
1555 1570 (or
1556 1571 ('symbol', '2')
1557 1572 ('symbol', '0')
1558 1573 ('symbol', '1'))))
1559 1574 * optimized:
1560 1575 (and
1561 1576 (func
1562 1577 ('symbol', '_list')
1563 1578 ('string', '2\x000\x001'))
1564 1579 (func
1565 1580 ('symbol', 'contains')
1566 1581 ('string', 'glob:*')))
1567 1582 * set:
1568 1583 <filteredset
1569 1584 <baseset [2, 0, 1]>,
1570 1585 <contains 'glob:*'>>
1571 1586 2
1572 1587 0
1573 1588 1
1574 1589 BROKEN: should be '0 1 2'
1575 1590
1576 1591 $ try --optimize 'reverse(contains("glob:*")) & (0 + 2 + 1)'
1577 1592 (and
1578 1593 (func
1579 1594 ('symbol', 'reverse')
1580 1595 (func
1581 1596 ('symbol', 'contains')
1582 1597 ('string', 'glob:*')))
1583 1598 (group
1584 1599 (or
1585 1600 ('symbol', '0')
1586 1601 ('symbol', '2')
1587 1602 ('symbol', '1'))))
1588 1603 * optimized:
1589 1604 (and
1590 1605 (func
1591 1606 ('symbol', '_list')
1592 1607 ('string', '0\x002\x001'))
1593 1608 (func
1594 1609 ('symbol', 'reverse')
1595 1610 (func
1596 1611 ('symbol', 'contains')
1597 1612 ('string', 'glob:*'))))
1598 1613 * set:
1599 1614 <filteredset
1600 1615 <baseset [1, 2, 0]>,
1601 1616 <contains 'glob:*'>>
1602 1617 1
1603 1618 2
1604 1619 0
1605 1620 BROKEN: should be '2 1 0'
1606 1621
1607 1622 test sort revset
1608 1623 --------------------------------------------
1609 1624
1610 1625 test when adding two unordered revsets
1611 1626
1612 1627 $ log 'sort(keyword(issue) or modifies(b))'
1613 1628 4
1614 1629 6
1615 1630
1616 1631 test when sorting a reversed collection in the same way it is
1617 1632
1618 1633 $ log 'sort(reverse(all()), -rev)'
1619 1634 9
1620 1635 8
1621 1636 7
1622 1637 6
1623 1638 5
1624 1639 4
1625 1640 3
1626 1641 2
1627 1642 1
1628 1643 0
1629 1644
1630 1645 test when sorting a reversed collection
1631 1646
1632 1647 $ log 'sort(reverse(all()), rev)'
1633 1648 0
1634 1649 1
1635 1650 2
1636 1651 3
1637 1652 4
1638 1653 5
1639 1654 6
1640 1655 7
1641 1656 8
1642 1657 9
1643 1658
1644 1659
1645 1660 test sorting two sorted collections in different orders
1646 1661
1647 1662 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
1648 1663 2
1649 1664 6
1650 1665 8
1651 1666 9
1652 1667
1653 1668 test sorting two sorted collections in different orders backwards
1654 1669
1655 1670 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
1656 1671 9
1657 1672 8
1658 1673 6
1659 1674 2
1660 1675
1661 1676 test empty sort key which is noop
1662 1677
1663 1678 $ log 'sort(0 + 2 + 1, "")'
1664 1679 0
1665 1680 2
1666 1681 1
1667 1682
1668 1683 test invalid sort keys
1669 1684
1670 1685 $ log 'sort(all(), -invalid)'
1671 1686 hg: parse error: unknown sort key '-invalid'
1672 1687 [255]
1673 1688
1674 1689 $ cd ..
1675 1690
1676 1691 test sorting by multiple keys including variable-length strings
1677 1692
1678 1693 $ hg init sorting
1679 1694 $ cd sorting
1680 1695 $ cat <<EOF >> .hg/hgrc
1681 1696 > [ui]
1682 1697 > logtemplate = '{rev} {branch|p5}{desc|p5}{author|p5}{date|hgdate}\n'
1683 1698 > [templatealias]
1684 1699 > p5(s) = pad(s, 5)
1685 1700 > EOF
1686 1701 $ hg branch -qf b12
1687 1702 $ hg ci -m m111 -u u112 -d '111 10800'
1688 1703 $ hg branch -qf b11
1689 1704 $ hg ci -m m12 -u u111 -d '112 7200'
1690 1705 $ hg branch -qf b111
1691 1706 $ hg ci -m m11 -u u12 -d '111 3600'
1692 1707 $ hg branch -qf b112
1693 1708 $ hg ci -m m111 -u u11 -d '120 0'
1694 1709 $ hg branch -qf b111
1695 1710 $ hg ci -m m112 -u u111 -d '110 14400'
1696 1711 created new head
1697 1712
1698 1713 compare revisions (has fast path):
1699 1714
1700 1715 $ hg log -r 'sort(all(), rev)'
1701 1716 0 b12 m111 u112 111 10800
1702 1717 1 b11 m12 u111 112 7200
1703 1718 2 b111 m11 u12 111 3600
1704 1719 3 b112 m111 u11 120 0
1705 1720 4 b111 m112 u111 110 14400
1706 1721
1707 1722 $ hg log -r 'sort(all(), -rev)'
1708 1723 4 b111 m112 u111 110 14400
1709 1724 3 b112 m111 u11 120 0
1710 1725 2 b111 m11 u12 111 3600
1711 1726 1 b11 m12 u111 112 7200
1712 1727 0 b12 m111 u112 111 10800
1713 1728
1714 1729 compare variable-length strings (issue5218):
1715 1730
1716 1731 $ hg log -r 'sort(all(), branch)'
1717 1732 1 b11 m12 u111 112 7200
1718 1733 2 b111 m11 u12 111 3600
1719 1734 4 b111 m112 u111 110 14400
1720 1735 3 b112 m111 u11 120 0
1721 1736 0 b12 m111 u112 111 10800
1722 1737
1723 1738 $ hg log -r 'sort(all(), -branch)'
1724 1739 0 b12 m111 u112 111 10800
1725 1740 3 b112 m111 u11 120 0
1726 1741 2 b111 m11 u12 111 3600
1727 1742 4 b111 m112 u111 110 14400
1728 1743 1 b11 m12 u111 112 7200
1729 1744
1730 1745 $ hg log -r 'sort(all(), desc)'
1731 1746 2 b111 m11 u12 111 3600
1732 1747 0 b12 m111 u112 111 10800
1733 1748 3 b112 m111 u11 120 0
1734 1749 4 b111 m112 u111 110 14400
1735 1750 1 b11 m12 u111 112 7200
1736 1751
1737 1752 $ hg log -r 'sort(all(), -desc)'
1738 1753 1 b11 m12 u111 112 7200
1739 1754 4 b111 m112 u111 110 14400
1740 1755 0 b12 m111 u112 111 10800
1741 1756 3 b112 m111 u11 120 0
1742 1757 2 b111 m11 u12 111 3600
1743 1758
1744 1759 $ hg log -r 'sort(all(), user)'
1745 1760 3 b112 m111 u11 120 0
1746 1761 1 b11 m12 u111 112 7200
1747 1762 4 b111 m112 u111 110 14400
1748 1763 0 b12 m111 u112 111 10800
1749 1764 2 b111 m11 u12 111 3600
1750 1765
1751 1766 $ hg log -r 'sort(all(), -user)'
1752 1767 2 b111 m11 u12 111 3600
1753 1768 0 b12 m111 u112 111 10800
1754 1769 1 b11 m12 u111 112 7200
1755 1770 4 b111 m112 u111 110 14400
1756 1771 3 b112 m111 u11 120 0
1757 1772
1758 1773 compare dates (tz offset should have no effect):
1759 1774
1760 1775 $ hg log -r 'sort(all(), date)'
1761 1776 4 b111 m112 u111 110 14400
1762 1777 0 b12 m111 u112 111 10800
1763 1778 2 b111 m11 u12 111 3600
1764 1779 1 b11 m12 u111 112 7200
1765 1780 3 b112 m111 u11 120 0
1766 1781
1767 1782 $ hg log -r 'sort(all(), -date)'
1768 1783 3 b112 m111 u11 120 0
1769 1784 1 b11 m12 u111 112 7200
1770 1785 0 b12 m111 u112 111 10800
1771 1786 2 b111 m11 u12 111 3600
1772 1787 4 b111 m112 u111 110 14400
1773 1788
1774 1789 be aware that 'sort(x, -k)' is not exactly the same as 'reverse(sort(x, k))'
1775 1790 because '-k' reverses the comparison, not the list itself:
1776 1791
1777 1792 $ hg log -r 'sort(0 + 2, date)'
1778 1793 0 b12 m111 u112 111 10800
1779 1794 2 b111 m11 u12 111 3600
1780 1795
1781 1796 $ hg log -r 'sort(0 + 2, -date)'
1782 1797 0 b12 m111 u112 111 10800
1783 1798 2 b111 m11 u12 111 3600
1784 1799
1785 1800 $ hg log -r 'reverse(sort(0 + 2, date))'
1786 1801 2 b111 m11 u12 111 3600
1787 1802 0 b12 m111 u112 111 10800
1788 1803
1789 1804 sort by multiple keys:
1790 1805
1791 1806 $ hg log -r 'sort(all(), "branch -rev")'
1792 1807 1 b11 m12 u111 112 7200
1793 1808 4 b111 m112 u111 110 14400
1794 1809 2 b111 m11 u12 111 3600
1795 1810 3 b112 m111 u11 120 0
1796 1811 0 b12 m111 u112 111 10800
1797 1812
1798 1813 $ hg log -r 'sort(all(), "-desc -date")'
1799 1814 1 b11 m12 u111 112 7200
1800 1815 4 b111 m112 u111 110 14400
1801 1816 3 b112 m111 u11 120 0
1802 1817 0 b12 m111 u112 111 10800
1803 1818 2 b111 m11 u12 111 3600
1804 1819
1805 1820 $ hg log -r 'sort(all(), "user -branch date rev")'
1806 1821 3 b112 m111 u11 120 0
1807 1822 4 b111 m112 u111 110 14400
1808 1823 1 b11 m12 u111 112 7200
1809 1824 0 b12 m111 u112 111 10800
1810 1825 2 b111 m11 u12 111 3600
1811 1826
1812 1827 toposort prioritises graph branches
1813 1828
1814 1829 $ hg up 2
1815 1830 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1816 1831 $ touch a
1817 1832 $ hg addremove
1818 1833 adding a
1819 1834 $ hg ci -m 't1' -u 'tu' -d '130 0'
1820 1835 created new head
1821 1836 $ echo 'a' >> a
1822 1837 $ hg ci -m 't2' -u 'tu' -d '130 0'
1823 1838 $ hg book book1
1824 1839 $ hg up 4
1825 1840 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1826 1841 (leaving bookmark book1)
1827 1842 $ touch a
1828 1843 $ hg addremove
1829 1844 adding a
1830 1845 $ hg ci -m 't3' -u 'tu' -d '130 0'
1831 1846
1832 1847 $ hg log -r 'sort(all(), topo)'
1833 1848 7 b111 t3 tu 130 0
1834 1849 4 b111 m112 u111 110 14400
1835 1850 3 b112 m111 u11 120 0
1836 1851 6 b111 t2 tu 130 0
1837 1852 5 b111 t1 tu 130 0
1838 1853 2 b111 m11 u12 111 3600
1839 1854 1 b11 m12 u111 112 7200
1840 1855 0 b12 m111 u112 111 10800
1841 1856
1842 1857 $ hg log -r 'sort(all(), -topo)'
1843 1858 0 b12 m111 u112 111 10800
1844 1859 1 b11 m12 u111 112 7200
1845 1860 2 b111 m11 u12 111 3600
1846 1861 5 b111 t1 tu 130 0
1847 1862 6 b111 t2 tu 130 0
1848 1863 3 b112 m111 u11 120 0
1849 1864 4 b111 m112 u111 110 14400
1850 1865 7 b111 t3 tu 130 0
1851 1866
1852 1867 $ hg log -r 'sort(all(), topo, topo.firstbranch=book1)'
1853 1868 6 b111 t2 tu 130 0
1854 1869 5 b111 t1 tu 130 0
1855 1870 7 b111 t3 tu 130 0
1856 1871 4 b111 m112 u111 110 14400
1857 1872 3 b112 m111 u11 120 0
1858 1873 2 b111 m11 u12 111 3600
1859 1874 1 b11 m12 u111 112 7200
1860 1875 0 b12 m111 u112 111 10800
1861 1876
1862 1877 topographical sorting can't be combined with other sort keys, and you can't
1863 1878 use the topo.firstbranch option when topo sort is not active:
1864 1879
1865 1880 $ hg log -r 'sort(all(), "topo user")'
1866 1881 hg: parse error: topo sort order cannot be combined with other sort keys
1867 1882 [255]
1868 1883
1869 1884 $ hg log -r 'sort(all(), user, topo.firstbranch=book1)'
1870 1885 hg: parse error: topo.firstbranch can only be used when using the topo sort key
1871 1886 [255]
1872 1887
1873 1888 topo.firstbranch should accept any kind of expressions:
1874 1889
1875 1890 $ hg log -r 'sort(0, topo, topo.firstbranch=(book1))'
1876 1891 0 b12 m111 u112 111 10800
1877 1892
1878 1893 $ cd ..
1879 1894 $ cd repo
1880 1895
1881 1896 test subtracting something from an addset
1882 1897
1883 1898 $ log '(outgoing() or removes(a)) - removes(a)'
1884 1899 8
1885 1900 9
1886 1901
1887 1902 test intersecting something with an addset
1888 1903
1889 1904 $ log 'parents(outgoing() or removes(a))'
1890 1905 1
1891 1906 4
1892 1907 5
1893 1908 8
1894 1909
1895 1910 test that `or` operation combines elements in the right order:
1896 1911
1897 1912 $ log '3:4 or 2:5'
1898 1913 3
1899 1914 4
1900 1915 2
1901 1916 5
1902 1917 $ log '3:4 or 5:2'
1903 1918 3
1904 1919 4
1905 1920 5
1906 1921 2
1907 1922 $ log 'sort(3:4 or 2:5)'
1908 1923 2
1909 1924 3
1910 1925 4
1911 1926 5
1912 1927 $ log 'sort(3:4 or 5:2)'
1913 1928 2
1914 1929 3
1915 1930 4
1916 1931 5
1917 1932
1918 1933 test that more than one `-r`s are combined in the right order and deduplicated:
1919 1934
1920 1935 $ hg log -T '{rev}\n' -r 3 -r 3 -r 4 -r 5:2 -r 'ancestors(4)'
1921 1936 3
1922 1937 4
1923 1938 5
1924 1939 2
1925 1940 0
1926 1941 1
1927 1942
1928 1943 test that `or` operation skips duplicated revisions from right-hand side
1929 1944
1930 1945 $ try 'reverse(1::5) or ancestors(4)'
1931 1946 (or
1932 1947 (func
1933 1948 ('symbol', 'reverse')
1934 1949 (dagrange
1935 1950 ('symbol', '1')
1936 1951 ('symbol', '5')))
1937 1952 (func
1938 1953 ('symbol', 'ancestors')
1939 1954 ('symbol', '4')))
1940 1955 * set:
1941 1956 <addset
1942 1957 <baseset- [1, 3, 5]>,
1943 1958 <generatorset+>>
1944 1959 5
1945 1960 3
1946 1961 1
1947 1962 0
1948 1963 2
1949 1964 4
1950 1965 $ try 'sort(ancestors(4) or reverse(1::5))'
1951 1966 (func
1952 1967 ('symbol', 'sort')
1953 1968 (or
1954 1969 (func
1955 1970 ('symbol', 'ancestors')
1956 1971 ('symbol', '4'))
1957 1972 (func
1958 1973 ('symbol', 'reverse')
1959 1974 (dagrange
1960 1975 ('symbol', '1')
1961 1976 ('symbol', '5')))))
1962 1977 * set:
1963 1978 <addset+
1964 1979 <generatorset+>,
1965 1980 <baseset- [1, 3, 5]>>
1966 1981 0
1967 1982 1
1968 1983 2
1969 1984 3
1970 1985 4
1971 1986 5
1972 1987
1973 1988 test optimization of trivial `or` operation
1974 1989
1975 1990 $ try --optimize '0|(1)|"2"|-2|tip|null'
1976 1991 (or
1977 1992 ('symbol', '0')
1978 1993 (group
1979 1994 ('symbol', '1'))
1980 1995 ('string', '2')
1981 1996 (negate
1982 1997 ('symbol', '2'))
1983 1998 ('symbol', 'tip')
1984 1999 ('symbol', 'null'))
1985 2000 * optimized:
1986 2001 (func
1987 2002 ('symbol', '_list')
1988 2003 ('string', '0\x001\x002\x00-2\x00tip\x00null'))
1989 2004 * set:
1990 2005 <baseset [0, 1, 2, 8, 9, -1]>
1991 2006 0
1992 2007 1
1993 2008 2
1994 2009 8
1995 2010 9
1996 2011 -1
1997 2012
1998 2013 $ try --optimize '0|1|2:3'
1999 2014 (or
2000 2015 ('symbol', '0')
2001 2016 ('symbol', '1')
2002 2017 (range
2003 2018 ('symbol', '2')
2004 2019 ('symbol', '3')))
2005 2020 * optimized:
2006 2021 (or
2007 2022 (func
2008 2023 ('symbol', '_list')
2009 2024 ('string', '0\x001'))
2010 2025 (range
2011 2026 ('symbol', '2')
2012 2027 ('symbol', '3')))
2013 2028 * set:
2014 2029 <addset
2015 2030 <baseset [0, 1]>,
2016 2031 <spanset+ 2:3>>
2017 2032 0
2018 2033 1
2019 2034 2
2020 2035 3
2021 2036
2022 2037 $ try --optimize '0:1|2|3:4|5|6'
2023 2038 (or
2024 2039 (range
2025 2040 ('symbol', '0')
2026 2041 ('symbol', '1'))
2027 2042 ('symbol', '2')
2028 2043 (range
2029 2044 ('symbol', '3')
2030 2045 ('symbol', '4'))
2031 2046 ('symbol', '5')
2032 2047 ('symbol', '6'))
2033 2048 * optimized:
2034 2049 (or
2035 2050 (range
2036 2051 ('symbol', '0')
2037 2052 ('symbol', '1'))
2038 2053 ('symbol', '2')
2039 2054 (range
2040 2055 ('symbol', '3')
2041 2056 ('symbol', '4'))
2042 2057 (func
2043 2058 ('symbol', '_list')
2044 2059 ('string', '5\x006')))
2045 2060 * set:
2046 2061 <addset
2047 2062 <addset
2048 2063 <spanset+ 0:1>,
2049 2064 <baseset [2]>>,
2050 2065 <addset
2051 2066 <spanset+ 3:4>,
2052 2067 <baseset [5, 6]>>>
2053 2068 0
2054 2069 1
2055 2070 2
2056 2071 3
2057 2072 4
2058 2073 5
2059 2074 6
2060 2075
2076 unoptimized `or` looks like this
2077
2078 $ try --no-optimized -p analyzed '0|1|2|3|4'
2079 * analyzed:
2080 (or
2081 ('symbol', '0')
2082 ('symbol', '1')
2083 ('symbol', '2')
2084 ('symbol', '3')
2085 ('symbol', '4'))
2086 * set:
2087 <addset
2088 <addset
2089 <baseset [0]>,
2090 <baseset [1]>>,
2091 <addset
2092 <baseset [2]>,
2093 <addset
2094 <baseset [3]>,
2095 <baseset [4]>>>>
2096 0
2097 1
2098 2
2099 3
2100 4
2101
2061 2102 test that `_list` should be narrowed by provided `subset`
2062 2103
2063 2104 $ log '0:2 and (null|1|2|3)'
2064 2105 1
2065 2106 2
2066 2107
2067 2108 test that `_list` should remove duplicates
2068 2109
2069 2110 $ log '0|1|2|1|2|-1|tip'
2070 2111 0
2071 2112 1
2072 2113 2
2073 2114 9
2074 2115
2075 2116 test unknown revision in `_list`
2076 2117
2077 2118 $ log '0|unknown'
2078 2119 abort: unknown revision 'unknown'!
2079 2120 [255]
2080 2121
2081 2122 test integer range in `_list`
2082 2123
2083 2124 $ log '-1|-10'
2084 2125 9
2085 2126 0
2086 2127
2087 2128 $ log '-10|-11'
2088 2129 abort: unknown revision '-11'!
2089 2130 [255]
2090 2131
2091 2132 $ log '9|10'
2092 2133 abort: unknown revision '10'!
2093 2134 [255]
2094 2135
2095 2136 test '0000' != '0' in `_list`
2096 2137
2097 2138 $ log '0|0000'
2098 2139 0
2099 2140 -1
2100 2141
2101 2142 test ',' in `_list`
2102 2143 $ log '0,1'
2103 2144 hg: parse error: can't use a list in this context
2104 2145 (see hg help "revsets.x or y")
2105 2146 [255]
2106 2147 $ try '0,1,2'
2107 2148 (list
2108 2149 ('symbol', '0')
2109 2150 ('symbol', '1')
2110 2151 ('symbol', '2'))
2111 2152 hg: parse error: can't use a list in this context
2112 2153 (see hg help "revsets.x or y")
2113 2154 [255]
2114 2155
2115 2156 test that chained `or` operations make balanced addsets
2116 2157
2117 2158 $ try '0:1|1:2|2:3|3:4|4:5'
2118 2159 (or
2119 2160 (range
2120 2161 ('symbol', '0')
2121 2162 ('symbol', '1'))
2122 2163 (range
2123 2164 ('symbol', '1')
2124 2165 ('symbol', '2'))
2125 2166 (range
2126 2167 ('symbol', '2')
2127 2168 ('symbol', '3'))
2128 2169 (range
2129 2170 ('symbol', '3')
2130 2171 ('symbol', '4'))
2131 2172 (range
2132 2173 ('symbol', '4')
2133 2174 ('symbol', '5')))
2134 2175 * set:
2135 2176 <addset
2136 2177 <addset
2137 2178 <spanset+ 0:1>,
2138 2179 <spanset+ 1:2>>,
2139 2180 <addset
2140 2181 <spanset+ 2:3>,
2141 2182 <addset
2142 2183 <spanset+ 3:4>,
2143 2184 <spanset+ 4:5>>>>
2144 2185 0
2145 2186 1
2146 2187 2
2147 2188 3
2148 2189 4
2149 2190 5
2150 2191
2151 2192 no crash by empty group "()" while optimizing `or` operations
2152 2193
2153 2194 $ try --optimize '0|()'
2154 2195 (or
2155 2196 ('symbol', '0')
2156 2197 (group
2157 2198 None))
2158 2199 * optimized:
2159 2200 (or
2160 2201 ('symbol', '0')
2161 2202 None)
2162 2203 hg: parse error: missing argument
2163 2204 [255]
2164 2205
2165 2206 test that chained `or` operations never eat up stack (issue4624)
2166 2207 (uses `0:1` instead of `0` to avoid future optimization of trivial revisions)
2167 2208
2168 2209 $ hg log -T '{rev}\n' -r `python -c "print '+'.join(['0:1'] * 500)"`
2169 2210 0
2170 2211 1
2171 2212
2172 2213 test that repeated `-r` options never eat up stack (issue4565)
2173 2214 (uses `-r 0::1` to avoid possible optimization at old-style parser)
2174 2215
2175 2216 $ hg log -T '{rev}\n' `python -c "for i in xrange(500): print '-r 0::1 ',"`
2176 2217 0
2177 2218 1
2178 2219
2179 2220 check that conversion to only works
2180 2221 $ try --optimize '::3 - ::1'
2181 2222 (minus
2182 2223 (dagrangepre
2183 2224 ('symbol', '3'))
2184 2225 (dagrangepre
2185 2226 ('symbol', '1')))
2186 2227 * optimized:
2187 2228 (func
2188 2229 ('symbol', 'only')
2189 2230 (list
2190 2231 ('symbol', '3')
2191 2232 ('symbol', '1')))
2192 2233 * set:
2193 2234 <baseset+ [3]>
2194 2235 3
2195 2236 $ try --optimize 'ancestors(1) - ancestors(3)'
2196 2237 (minus
2197 2238 (func
2198 2239 ('symbol', 'ancestors')
2199 2240 ('symbol', '1'))
2200 2241 (func
2201 2242 ('symbol', 'ancestors')
2202 2243 ('symbol', '3')))
2203 2244 * optimized:
2204 2245 (func
2205 2246 ('symbol', 'only')
2206 2247 (list
2207 2248 ('symbol', '1')
2208 2249 ('symbol', '3')))
2209 2250 * set:
2210 2251 <baseset+ []>
2211 2252 $ try --optimize 'not ::2 and ::6'
2212 2253 (and
2213 2254 (not
2214 2255 (dagrangepre
2215 2256 ('symbol', '2')))
2216 2257 (dagrangepre
2217 2258 ('symbol', '6')))
2218 2259 * optimized:
2219 2260 (func
2220 2261 ('symbol', 'only')
2221 2262 (list
2222 2263 ('symbol', '6')
2223 2264 ('symbol', '2')))
2224 2265 * set:
2225 2266 <baseset+ [3, 4, 5, 6]>
2226 2267 3
2227 2268 4
2228 2269 5
2229 2270 6
2230 2271 $ try --optimize 'ancestors(6) and not ancestors(4)'
2231 2272 (and
2232 2273 (func
2233 2274 ('symbol', 'ancestors')
2234 2275 ('symbol', '6'))
2235 2276 (not
2236 2277 (func
2237 2278 ('symbol', 'ancestors')
2238 2279 ('symbol', '4'))))
2239 2280 * optimized:
2240 2281 (func
2241 2282 ('symbol', 'only')
2242 2283 (list
2243 2284 ('symbol', '6')
2244 2285 ('symbol', '4')))
2245 2286 * set:
2246 2287 <baseset+ [3, 5, 6]>
2247 2288 3
2248 2289 5
2249 2290 6
2250 2291
2251 2292 no crash by empty group "()" while optimizing to "only()"
2252 2293
2253 2294 $ try --optimize '::1 and ()'
2254 2295 (and
2255 2296 (dagrangepre
2256 2297 ('symbol', '1'))
2257 2298 (group
2258 2299 None))
2259 2300 * optimized:
2260 2301 (and
2261 2302 None
2262 2303 (func
2263 2304 ('symbol', 'ancestors')
2264 2305 ('symbol', '1')))
2265 2306 hg: parse error: missing argument
2266 2307 [255]
2267 2308
2268 2309 invalid function call should not be optimized to only()
2269 2310
2270 2311 $ log '"ancestors"(6) and not ancestors(4)'
2271 2312 hg: parse error: not a symbol
2272 2313 [255]
2273 2314
2274 2315 $ log 'ancestors(6) and not "ancestors"(4)'
2275 2316 hg: parse error: not a symbol
2276 2317 [255]
2277 2318
2278 2319 we can use patterns when searching for tags
2279 2320
2280 2321 $ log 'tag("1..*")'
2281 2322 abort: tag '1..*' does not exist!
2282 2323 [255]
2283 2324 $ log 'tag("re:1..*")'
2284 2325 6
2285 2326 $ log 'tag("re:[0-9].[0-9]")'
2286 2327 6
2287 2328 $ log 'tag("literal:1.0")'
2288 2329 6
2289 2330 $ log 'tag("re:0..*")'
2290 2331
2291 2332 $ log 'tag(unknown)'
2292 2333 abort: tag 'unknown' does not exist!
2293 2334 [255]
2294 2335 $ log 'tag("re:unknown")'
2295 2336 $ log 'present(tag("unknown"))'
2296 2337 $ log 'present(tag("re:unknown"))'
2297 2338 $ log 'branch(unknown)'
2298 2339 abort: unknown revision 'unknown'!
2299 2340 [255]
2300 2341 $ log 'branch("literal:unknown")'
2301 2342 abort: branch 'unknown' does not exist!
2302 2343 [255]
2303 2344 $ log 'branch("re:unknown")'
2304 2345 $ log 'present(branch("unknown"))'
2305 2346 $ log 'present(branch("re:unknown"))'
2306 2347 $ log 'user(bob)'
2307 2348 2
2308 2349
2309 2350 $ log '4::8'
2310 2351 4
2311 2352 8
2312 2353 $ log '4:8'
2313 2354 4
2314 2355 5
2315 2356 6
2316 2357 7
2317 2358 8
2318 2359
2319 2360 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
2320 2361 4
2321 2362 2
2322 2363 5
2323 2364
2324 2365 $ log 'not 0 and 0:2'
2325 2366 1
2326 2367 2
2327 2368 $ log 'not 1 and 0:2'
2328 2369 0
2329 2370 2
2330 2371 $ log 'not 2 and 0:2'
2331 2372 0
2332 2373 1
2333 2374 $ log '(1 and 2)::'
2334 2375 $ log '(1 and 2):'
2335 2376 $ log '(1 and 2):3'
2336 2377 $ log 'sort(head(), -rev)'
2337 2378 9
2338 2379 7
2339 2380 6
2340 2381 5
2341 2382 4
2342 2383 3
2343 2384 2
2344 2385 1
2345 2386 0
2346 2387 $ log '4::8 - 8'
2347 2388 4
2348 2389
2349 2390 matching() should preserve the order of the input set:
2350 2391
2351 2392 $ log '(2 or 3 or 1) and matching(1 or 2 or 3)'
2352 2393 2
2353 2394 3
2354 2395 1
2355 2396
2356 2397 $ log 'named("unknown")'
2357 2398 abort: namespace 'unknown' does not exist!
2358 2399 [255]
2359 2400 $ log 'named("re:unknown")'
2360 2401 abort: no namespace exists that match 'unknown'!
2361 2402 [255]
2362 2403 $ log 'present(named("unknown"))'
2363 2404 $ log 'present(named("re:unknown"))'
2364 2405
2365 2406 $ log 'tag()'
2366 2407 6
2367 2408 $ log 'named("tags")'
2368 2409 6
2369 2410
2370 2411 issue2437
2371 2412
2372 2413 $ log '3 and p1(5)'
2373 2414 3
2374 2415 $ log '4 and p2(6)'
2375 2416 4
2376 2417 $ log '1 and parents(:2)'
2377 2418 1
2378 2419 $ log '2 and children(1:)'
2379 2420 2
2380 2421 $ log 'roots(all()) or roots(all())'
2381 2422 0
2382 2423 $ hg debugrevspec 'roots(all()) or roots(all())'
2383 2424 0
2384 2425 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
2385 2426 9
2386 2427 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
2387 2428 4
2388 2429
2389 2430 issue2654: report a parse error if the revset was not completely parsed
2390 2431
2391 2432 $ log '1 OR 2'
2392 2433 hg: parse error at 2: invalid token
2393 2434 [255]
2394 2435
2395 2436 or operator should preserve ordering:
2396 2437 $ log 'reverse(2::4) or tip'
2397 2438 4
2398 2439 2
2399 2440 9
2400 2441
2401 2442 parentrevspec
2402 2443
2403 2444 $ log 'merge()^0'
2404 2445 6
2405 2446 $ log 'merge()^'
2406 2447 5
2407 2448 $ log 'merge()^1'
2408 2449 5
2409 2450 $ log 'merge()^2'
2410 2451 4
2411 2452 $ log 'merge()^^'
2412 2453 3
2413 2454 $ log 'merge()^1^'
2414 2455 3
2415 2456 $ log 'merge()^^^'
2416 2457 1
2417 2458
2418 2459 $ log 'merge()~0'
2419 2460 6
2420 2461 $ log 'merge()~1'
2421 2462 5
2422 2463 $ log 'merge()~2'
2423 2464 3
2424 2465 $ log 'merge()~2^1'
2425 2466 1
2426 2467 $ log 'merge()~3'
2427 2468 1
2428 2469
2429 2470 $ log '(-3:tip)^'
2430 2471 4
2431 2472 6
2432 2473 8
2433 2474
2434 2475 $ log 'tip^foo'
2435 2476 hg: parse error: ^ expects a number 0, 1, or 2
2436 2477 [255]
2437 2478
2438 2479 Bogus function gets suggestions
2439 2480 $ log 'add()'
2440 2481 hg: parse error: unknown identifier: add
2441 2482 (did you mean adds?)
2442 2483 [255]
2443 2484 $ log 'added()'
2444 2485 hg: parse error: unknown identifier: added
2445 2486 (did you mean adds?)
2446 2487 [255]
2447 2488 $ log 'remo()'
2448 2489 hg: parse error: unknown identifier: remo
2449 2490 (did you mean one of remote, removes?)
2450 2491 [255]
2451 2492 $ log 'babar()'
2452 2493 hg: parse error: unknown identifier: babar
2453 2494 [255]
2454 2495
2455 2496 Bogus function with a similar internal name doesn't suggest the internal name
2456 2497 $ log 'matches()'
2457 2498 hg: parse error: unknown identifier: matches
2458 2499 (did you mean matching?)
2459 2500 [255]
2460 2501
2461 2502 Undocumented functions aren't suggested as similar either
2462 2503 $ log 'wdir2()'
2463 2504 hg: parse error: unknown identifier: wdir2
2464 2505 [255]
2465 2506
2466 2507 multiple revspecs
2467 2508
2468 2509 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
2469 2510 8
2470 2511 9
2471 2512 4
2472 2513 5
2473 2514 6
2474 2515 7
2475 2516
2476 2517 test usage in revpair (with "+")
2477 2518
2478 2519 (real pair)
2479 2520
2480 2521 $ hg diff -r 'tip^^' -r 'tip'
2481 2522 diff -r 2326846efdab -r 24286f4ae135 .hgtags
2482 2523 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2483 2524 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
2484 2525 @@ -0,0 +1,1 @@
2485 2526 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
2486 2527 $ hg diff -r 'tip^^::tip'
2487 2528 diff -r 2326846efdab -r 24286f4ae135 .hgtags
2488 2529 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2489 2530 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
2490 2531 @@ -0,0 +1,1 @@
2491 2532 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
2492 2533
2493 2534 (single rev)
2494 2535
2495 2536 $ hg diff -r 'tip^' -r 'tip^'
2496 2537 $ hg diff -r 'tip^:tip^'
2497 2538
2498 2539 (single rev that does not looks like a range)
2499 2540
2500 2541 $ hg diff -r 'tip^::tip^ or tip^'
2501 2542 diff -r d5d0dcbdc4d9 .hgtags
2502 2543 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2503 2544 +++ b/.hgtags * (glob)
2504 2545 @@ -0,0 +1,1 @@
2505 2546 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
2506 2547 $ hg diff -r 'tip^ or tip^'
2507 2548 diff -r d5d0dcbdc4d9 .hgtags
2508 2549 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2509 2550 +++ b/.hgtags * (glob)
2510 2551 @@ -0,0 +1,1 @@
2511 2552 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
2512 2553
2513 2554 (no rev)
2514 2555
2515 2556 $ hg diff -r 'author("babar") or author("celeste")'
2516 2557 abort: empty revision range
2517 2558 [255]
2518 2559
2519 2560 aliases:
2520 2561
2521 2562 $ echo '[revsetalias]' >> .hg/hgrc
2522 2563 $ echo 'm = merge()' >> .hg/hgrc
2523 2564 (revset aliases can override builtin revsets)
2524 2565 $ echo 'p2($1) = p1($1)' >> .hg/hgrc
2525 2566 $ echo 'sincem = descendants(m)' >> .hg/hgrc
2526 2567 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
2527 2568 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
2528 2569 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
2529 2570
2530 2571 $ try m
2531 2572 ('symbol', 'm')
2532 2573 * expanded:
2533 2574 (func
2534 2575 ('symbol', 'merge')
2535 2576 None)
2536 2577 * set:
2537 2578 <filteredset
2538 2579 <fullreposet+ 0:9>,
2539 2580 <merge>>
2540 2581 6
2541 2582
2542 2583 $ HGPLAIN=1
2543 2584 $ export HGPLAIN
2544 2585 $ try m
2545 2586 ('symbol', 'm')
2546 2587 abort: unknown revision 'm'!
2547 2588 [255]
2548 2589
2549 2590 $ HGPLAINEXCEPT=revsetalias
2550 2591 $ export HGPLAINEXCEPT
2551 2592 $ try m
2552 2593 ('symbol', 'm')
2553 2594 * expanded:
2554 2595 (func
2555 2596 ('symbol', 'merge')
2556 2597 None)
2557 2598 * set:
2558 2599 <filteredset
2559 2600 <fullreposet+ 0:9>,
2560 2601 <merge>>
2561 2602 6
2562 2603
2563 2604 $ unset HGPLAIN
2564 2605 $ unset HGPLAINEXCEPT
2565 2606
2566 2607 $ try 'p2(.)'
2567 2608 (func
2568 2609 ('symbol', 'p2')
2569 2610 ('symbol', '.'))
2570 2611 * expanded:
2571 2612 (func
2572 2613 ('symbol', 'p1')
2573 2614 ('symbol', '.'))
2574 2615 * set:
2575 2616 <baseset+ [8]>
2576 2617 8
2577 2618
2578 2619 $ HGPLAIN=1
2579 2620 $ export HGPLAIN
2580 2621 $ try 'p2(.)'
2581 2622 (func
2582 2623 ('symbol', 'p2')
2583 2624 ('symbol', '.'))
2584 2625 * set:
2585 2626 <baseset+ []>
2586 2627
2587 2628 $ HGPLAINEXCEPT=revsetalias
2588 2629 $ export HGPLAINEXCEPT
2589 2630 $ try 'p2(.)'
2590 2631 (func
2591 2632 ('symbol', 'p2')
2592 2633 ('symbol', '.'))
2593 2634 * expanded:
2594 2635 (func
2595 2636 ('symbol', 'p1')
2596 2637 ('symbol', '.'))
2597 2638 * set:
2598 2639 <baseset+ [8]>
2599 2640 8
2600 2641
2601 2642 $ unset HGPLAIN
2602 2643 $ unset HGPLAINEXCEPT
2603 2644
2604 2645 test alias recursion
2605 2646
2606 2647 $ try sincem
2607 2648 ('symbol', 'sincem')
2608 2649 * expanded:
2609 2650 (func
2610 2651 ('symbol', 'descendants')
2611 2652 (func
2612 2653 ('symbol', 'merge')
2613 2654 None))
2614 2655 * set:
2615 2656 <addset+
2616 2657 <filteredset
2617 2658 <fullreposet+ 0:9>,
2618 2659 <merge>>,
2619 2660 <generatorset+>>
2620 2661 6
2621 2662 7
2622 2663
2623 2664 test infinite recursion
2624 2665
2625 2666 $ echo 'recurse1 = recurse2' >> .hg/hgrc
2626 2667 $ echo 'recurse2 = recurse1' >> .hg/hgrc
2627 2668 $ try recurse1
2628 2669 ('symbol', 'recurse1')
2629 2670 hg: parse error: infinite expansion of revset alias "recurse1" detected
2630 2671 [255]
2631 2672
2632 2673 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
2633 2674 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
2634 2675 $ try "level2(level1(1, 2), 3)"
2635 2676 (func
2636 2677 ('symbol', 'level2')
2637 2678 (list
2638 2679 (func
2639 2680 ('symbol', 'level1')
2640 2681 (list
2641 2682 ('symbol', '1')
2642 2683 ('symbol', '2')))
2643 2684 ('symbol', '3')))
2644 2685 * expanded:
2645 2686 (or
2646 2687 ('symbol', '3')
2647 2688 (or
2648 2689 ('symbol', '1')
2649 2690 ('symbol', '2')))
2650 2691 * set:
2651 2692 <addset
2652 2693 <baseset [3]>,
2653 2694 <baseset [1, 2]>>
2654 2695 3
2655 2696 1
2656 2697 2
2657 2698
2658 2699 test nesting and variable passing
2659 2700
2660 2701 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
2661 2702 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
2662 2703 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
2663 2704 $ try 'nested(2:5)'
2664 2705 (func
2665 2706 ('symbol', 'nested')
2666 2707 (range
2667 2708 ('symbol', '2')
2668 2709 ('symbol', '5')))
2669 2710 * expanded:
2670 2711 (func
2671 2712 ('symbol', 'max')
2672 2713 (range
2673 2714 ('symbol', '2')
2674 2715 ('symbol', '5')))
2675 2716 * set:
2676 2717 <baseset
2677 2718 <max
2678 2719 <fullreposet+ 0:9>,
2679 2720 <spanset+ 2:5>>>
2680 2721 5
2681 2722
2682 2723 test chained `or` operations are flattened at parsing phase
2683 2724
2684 2725 $ echo 'chainedorops($1, $2, $3) = $1|$2|$3' >> .hg/hgrc
2685 2726 $ try 'chainedorops(0:1, 1:2, 2:3)'
2686 2727 (func
2687 2728 ('symbol', 'chainedorops')
2688 2729 (list
2689 2730 (range
2690 2731 ('symbol', '0')
2691 2732 ('symbol', '1'))
2692 2733 (range
2693 2734 ('symbol', '1')
2694 2735 ('symbol', '2'))
2695 2736 (range
2696 2737 ('symbol', '2')
2697 2738 ('symbol', '3'))))
2698 2739 * expanded:
2699 2740 (or
2700 2741 (range
2701 2742 ('symbol', '0')
2702 2743 ('symbol', '1'))
2703 2744 (range
2704 2745 ('symbol', '1')
2705 2746 ('symbol', '2'))
2706 2747 (range
2707 2748 ('symbol', '2')
2708 2749 ('symbol', '3')))
2709 2750 * set:
2710 2751 <addset
2711 2752 <spanset+ 0:1>,
2712 2753 <addset
2713 2754 <spanset+ 1:2>,
2714 2755 <spanset+ 2:3>>>
2715 2756 0
2716 2757 1
2717 2758 2
2718 2759 3
2719 2760
2720 2761 test variable isolation, variable placeholders are rewritten as string
2721 2762 then parsed and matched again as string. Check they do not leak too
2722 2763 far away.
2723 2764
2724 2765 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
2725 2766 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
2726 2767 $ try 'callinjection(2:5)'
2727 2768 (func
2728 2769 ('symbol', 'callinjection')
2729 2770 (range
2730 2771 ('symbol', '2')
2731 2772 ('symbol', '5')))
2732 2773 * expanded:
2733 2774 (func
2734 2775 ('symbol', 'descendants')
2735 2776 (func
2736 2777 ('symbol', 'max')
2737 2778 ('string', '$1')))
2738 2779 abort: unknown revision '$1'!
2739 2780 [255]
2740 2781
2741 2782 test scope of alias expansion: 'universe' is expanded prior to 'shadowall(0)',
2742 2783 but 'all()' should never be substituded to '0()'.
2743 2784
2744 2785 $ echo 'universe = all()' >> .hg/hgrc
2745 2786 $ echo 'shadowall(all) = all and universe' >> .hg/hgrc
2746 2787 $ try 'shadowall(0)'
2747 2788 (func
2748 2789 ('symbol', 'shadowall')
2749 2790 ('symbol', '0'))
2750 2791 * expanded:
2751 2792 (and
2752 2793 ('symbol', '0')
2753 2794 (func
2754 2795 ('symbol', 'all')
2755 2796 None))
2756 2797 * set:
2757 2798 <filteredset
2758 2799 <baseset [0]>,
2759 2800 <spanset+ 0:9>>
2760 2801 0
2761 2802
2762 2803 test unknown reference:
2763 2804
2764 2805 $ try "unknownref(0)" --config 'revsetalias.unknownref($1)=$1:$2'
2765 2806 (func
2766 2807 ('symbol', 'unknownref')
2767 2808 ('symbol', '0'))
2768 2809 abort: bad definition of revset alias "unknownref": invalid symbol '$2'
2769 2810 [255]
2770 2811
2771 2812 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
2772 2813 ('symbol', 'tip')
2773 2814 warning: bad definition of revset alias "anotherbadone": at 7: not a prefix: end
2774 2815 * set:
2775 2816 <baseset [9]>
2776 2817 9
2777 2818
2778 2819 $ try 'tip'
2779 2820 ('symbol', 'tip')
2780 2821 * set:
2781 2822 <baseset [9]>
2782 2823 9
2783 2824
2784 2825 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
2785 2826 ('symbol', 'tip')
2786 2827 warning: bad declaration of revset alias "bad name": at 4: invalid token
2787 2828 * set:
2788 2829 <baseset [9]>
2789 2830 9
2790 2831 $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc
2791 2832 $ try 'strictreplacing("foo", tip)'
2792 2833 (func
2793 2834 ('symbol', 'strictreplacing')
2794 2835 (list
2795 2836 ('string', 'foo')
2796 2837 ('symbol', 'tip')))
2797 2838 * expanded:
2798 2839 (or
2799 2840 ('symbol', 'tip')
2800 2841 (func
2801 2842 ('symbol', 'desc')
2802 2843 ('string', '$1')))
2803 2844 * set:
2804 2845 <addset
2805 2846 <baseset [9]>,
2806 2847 <filteredset
2807 2848 <fullreposet+ 0:9>,
2808 2849 <desc '$1'>>>
2809 2850 9
2810 2851
2811 2852 $ try 'd(2:5)'
2812 2853 (func
2813 2854 ('symbol', 'd')
2814 2855 (range
2815 2856 ('symbol', '2')
2816 2857 ('symbol', '5')))
2817 2858 * expanded:
2818 2859 (func
2819 2860 ('symbol', 'reverse')
2820 2861 (func
2821 2862 ('symbol', 'sort')
2822 2863 (list
2823 2864 (range
2824 2865 ('symbol', '2')
2825 2866 ('symbol', '5'))
2826 2867 ('symbol', 'date'))))
2827 2868 * set:
2828 2869 <baseset [4, 5, 3, 2]>
2829 2870 4
2830 2871 5
2831 2872 3
2832 2873 2
2833 2874 $ try 'rs(2 or 3, date)'
2834 2875 (func
2835 2876 ('symbol', 'rs')
2836 2877 (list
2837 2878 (or
2838 2879 ('symbol', '2')
2839 2880 ('symbol', '3'))
2840 2881 ('symbol', 'date')))
2841 2882 * expanded:
2842 2883 (func
2843 2884 ('symbol', 'reverse')
2844 2885 (func
2845 2886 ('symbol', 'sort')
2846 2887 (list
2847 2888 (or
2848 2889 ('symbol', '2')
2849 2890 ('symbol', '3'))
2850 2891 ('symbol', 'date'))))
2851 2892 * set:
2852 2893 <baseset [3, 2]>
2853 2894 3
2854 2895 2
2855 2896 $ try 'rs()'
2856 2897 (func
2857 2898 ('symbol', 'rs')
2858 2899 None)
2859 2900 hg: parse error: invalid number of arguments: 0
2860 2901 [255]
2861 2902 $ try 'rs(2)'
2862 2903 (func
2863 2904 ('symbol', 'rs')
2864 2905 ('symbol', '2'))
2865 2906 hg: parse error: invalid number of arguments: 1
2866 2907 [255]
2867 2908 $ try 'rs(2, data, 7)'
2868 2909 (func
2869 2910 ('symbol', 'rs')
2870 2911 (list
2871 2912 ('symbol', '2')
2872 2913 ('symbol', 'data')
2873 2914 ('symbol', '7')))
2874 2915 hg: parse error: invalid number of arguments: 3
2875 2916 [255]
2876 2917 $ try 'rs4(2 or 3, x, x, date)'
2877 2918 (func
2878 2919 ('symbol', 'rs4')
2879 2920 (list
2880 2921 (or
2881 2922 ('symbol', '2')
2882 2923 ('symbol', '3'))
2883 2924 ('symbol', 'x')
2884 2925 ('symbol', 'x')
2885 2926 ('symbol', 'date')))
2886 2927 * expanded:
2887 2928 (func
2888 2929 ('symbol', 'reverse')
2889 2930 (func
2890 2931 ('symbol', 'sort')
2891 2932 (list
2892 2933 (or
2893 2934 ('symbol', '2')
2894 2935 ('symbol', '3'))
2895 2936 ('symbol', 'date'))))
2896 2937 * set:
2897 2938 <baseset [3, 2]>
2898 2939 3
2899 2940 2
2900 2941
2901 2942 issue4553: check that revset aliases override existing hash prefix
2902 2943
2903 2944 $ hg log -qr e
2904 2945 6:e0cc66ef77e8
2905 2946
2906 2947 $ hg log -qr e --config revsetalias.e="all()"
2907 2948 0:2785f51eece5
2908 2949 1:d75937da8da0
2909 2950 2:5ed5505e9f1c
2910 2951 3:8528aa5637f2
2911 2952 4:2326846efdab
2912 2953 5:904fa392b941
2913 2954 6:e0cc66ef77e8
2914 2955 7:013af1973af4
2915 2956 8:d5d0dcbdc4d9
2916 2957 9:24286f4ae135
2917 2958
2918 2959 $ hg log -qr e: --config revsetalias.e="0"
2919 2960 0:2785f51eece5
2920 2961 1:d75937da8da0
2921 2962 2:5ed5505e9f1c
2922 2963 3:8528aa5637f2
2923 2964 4:2326846efdab
2924 2965 5:904fa392b941
2925 2966 6:e0cc66ef77e8
2926 2967 7:013af1973af4
2927 2968 8:d5d0dcbdc4d9
2928 2969 9:24286f4ae135
2929 2970
2930 2971 $ hg log -qr :e --config revsetalias.e="9"
2931 2972 0:2785f51eece5
2932 2973 1:d75937da8da0
2933 2974 2:5ed5505e9f1c
2934 2975 3:8528aa5637f2
2935 2976 4:2326846efdab
2936 2977 5:904fa392b941
2937 2978 6:e0cc66ef77e8
2938 2979 7:013af1973af4
2939 2980 8:d5d0dcbdc4d9
2940 2981 9:24286f4ae135
2941 2982
2942 2983 $ hg log -qr e:
2943 2984 6:e0cc66ef77e8
2944 2985 7:013af1973af4
2945 2986 8:d5d0dcbdc4d9
2946 2987 9:24286f4ae135
2947 2988
2948 2989 $ hg log -qr :e
2949 2990 0:2785f51eece5
2950 2991 1:d75937da8da0
2951 2992 2:5ed5505e9f1c
2952 2993 3:8528aa5637f2
2953 2994 4:2326846efdab
2954 2995 5:904fa392b941
2955 2996 6:e0cc66ef77e8
2956 2997
2957 2998 issue2549 - correct optimizations
2958 2999
2959 3000 $ try 'limit(1 or 2 or 3, 2) and not 2'
2960 3001 (and
2961 3002 (func
2962 3003 ('symbol', 'limit')
2963 3004 (list
2964 3005 (or
2965 3006 ('symbol', '1')
2966 3007 ('symbol', '2')
2967 3008 ('symbol', '3'))
2968 3009 ('symbol', '2')))
2969 3010 (not
2970 3011 ('symbol', '2')))
2971 3012 * set:
2972 3013 <filteredset
2973 3014 <baseset
2974 3015 <limit n=2, offset=0,
2975 3016 <fullreposet+ 0:9>,
2976 3017 <baseset [1, 2, 3]>>>,
2977 3018 <not
2978 3019 <baseset [2]>>>
2979 3020 1
2980 3021 $ try 'max(1 or 2) and not 2'
2981 3022 (and
2982 3023 (func
2983 3024 ('symbol', 'max')
2984 3025 (or
2985 3026 ('symbol', '1')
2986 3027 ('symbol', '2')))
2987 3028 (not
2988 3029 ('symbol', '2')))
2989 3030 * set:
2990 3031 <filteredset
2991 3032 <baseset
2992 3033 <max
2993 3034 <fullreposet+ 0:9>,
2994 3035 <baseset [1, 2]>>>,
2995 3036 <not
2996 3037 <baseset [2]>>>
2997 3038 $ try 'min(1 or 2) and not 1'
2998 3039 (and
2999 3040 (func
3000 3041 ('symbol', 'min')
3001 3042 (or
3002 3043 ('symbol', '1')
3003 3044 ('symbol', '2')))
3004 3045 (not
3005 3046 ('symbol', '1')))
3006 3047 * set:
3007 3048 <filteredset
3008 3049 <baseset
3009 3050 <min
3010 3051 <fullreposet+ 0:9>,
3011 3052 <baseset [1, 2]>>>,
3012 3053 <not
3013 3054 <baseset [1]>>>
3014 3055 $ try 'last(1 or 2, 1) and not 2'
3015 3056 (and
3016 3057 (func
3017 3058 ('symbol', 'last')
3018 3059 (list
3019 3060 (or
3020 3061 ('symbol', '1')
3021 3062 ('symbol', '2'))
3022 3063 ('symbol', '1')))
3023 3064 (not
3024 3065 ('symbol', '2')))
3025 3066 * set:
3026 3067 <filteredset
3027 3068 <baseset
3028 3069 <last n=1,
3029 3070 <fullreposet+ 0:9>,
3030 3071 <baseset [2, 1]>>>,
3031 3072 <not
3032 3073 <baseset [2]>>>
3033 3074
3034 3075 issue4289 - ordering of built-ins
3035 3076 $ hg log -M -q -r 3:2
3036 3077 3:8528aa5637f2
3037 3078 2:5ed5505e9f1c
3038 3079
3039 3080 test revsets started with 40-chars hash (issue3669)
3040 3081
3041 3082 $ ISSUE3669_TIP=`hg tip --template '{node}'`
3042 3083 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
3043 3084 9
3044 3085 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
3045 3086 8
3046 3087
3047 3088 test or-ed indirect predicates (issue3775)
3048 3089
3049 3090 $ log '6 or 6^1' | sort
3050 3091 5
3051 3092 6
3052 3093 $ log '6^1 or 6' | sort
3053 3094 5
3054 3095 6
3055 3096 $ log '4 or 4~1' | sort
3056 3097 2
3057 3098 4
3058 3099 $ log '4~1 or 4' | sort
3059 3100 2
3060 3101 4
3061 3102 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
3062 3103 0
3063 3104 1
3064 3105 2
3065 3106 3
3066 3107 4
3067 3108 5
3068 3109 6
3069 3110 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
3070 3111 0
3071 3112 1
3072 3113 2
3073 3114 3
3074 3115 4
3075 3116 5
3076 3117 6
3077 3118
3078 3119 tests for 'remote()' predicate:
3079 3120 #. (csets in remote) (id) (remote)
3080 3121 1. less than local current branch "default"
3081 3122 2. same with local specified "default"
3082 3123 3. more than local specified specified
3083 3124
3084 3125 $ hg clone --quiet -U . ../remote3
3085 3126 $ cd ../remote3
3086 3127 $ hg update -q 7
3087 3128 $ echo r > r
3088 3129 $ hg ci -Aqm 10
3089 3130 $ log 'remote()'
3090 3131 7
3091 3132 $ log 'remote("a-b-c-")'
3092 3133 2
3093 3134 $ cd ../repo
3094 3135 $ log 'remote(".a.b.c.", "../remote3")'
3095 3136
3096 3137 tests for concatenation of strings/symbols by "##"
3097 3138
3098 3139 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
3099 3140 (_concat
3100 3141 (_concat
3101 3142 (_concat
3102 3143 ('symbol', '278')
3103 3144 ('string', '5f5'))
3104 3145 ('symbol', '1ee'))
3105 3146 ('string', 'ce5'))
3106 3147 * concatenated:
3107 3148 ('string', '2785f51eece5')
3108 3149 * set:
3109 3150 <baseset [0]>
3110 3151 0
3111 3152
3112 3153 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
3113 3154 $ try "cat4(278, '5f5', 1ee, 'ce5')"
3114 3155 (func
3115 3156 ('symbol', 'cat4')
3116 3157 (list
3117 3158 ('symbol', '278')
3118 3159 ('string', '5f5')
3119 3160 ('symbol', '1ee')
3120 3161 ('string', 'ce5')))
3121 3162 * expanded:
3122 3163 (_concat
3123 3164 (_concat
3124 3165 (_concat
3125 3166 ('symbol', '278')
3126 3167 ('string', '5f5'))
3127 3168 ('symbol', '1ee'))
3128 3169 ('string', 'ce5'))
3129 3170 * concatenated:
3130 3171 ('string', '2785f51eece5')
3131 3172 * set:
3132 3173 <baseset [0]>
3133 3174 0
3134 3175
3135 3176 (check concatenation in alias nesting)
3136 3177
3137 3178 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
3138 3179 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
3139 3180 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
3140 3181 0
3141 3182
3142 3183 (check operator priority)
3143 3184
3144 3185 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
3145 3186 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
3146 3187 0
3147 3188 4
3148 3189
3149 3190 $ cd ..
3150 3191
3151 3192 prepare repository that has "default" branches of multiple roots
3152 3193
3153 3194 $ hg init namedbranch
3154 3195 $ cd namedbranch
3155 3196
3156 3197 $ echo default0 >> a
3157 3198 $ hg ci -Aqm0
3158 3199 $ echo default1 >> a
3159 3200 $ hg ci -m1
3160 3201
3161 3202 $ hg branch -q stable
3162 3203 $ echo stable2 >> a
3163 3204 $ hg ci -m2
3164 3205 $ echo stable3 >> a
3165 3206 $ hg ci -m3
3166 3207
3167 3208 $ hg update -q null
3168 3209 $ echo default4 >> a
3169 3210 $ hg ci -Aqm4
3170 3211 $ echo default5 >> a
3171 3212 $ hg ci -m5
3172 3213
3173 3214 "null" revision belongs to "default" branch (issue4683)
3174 3215
3175 3216 $ log 'branch(null)'
3176 3217 0
3177 3218 1
3178 3219 4
3179 3220 5
3180 3221
3181 3222 "null" revision belongs to "default" branch, but it shouldn't appear in set
3182 3223 unless explicitly specified (issue4682)
3183 3224
3184 3225 $ log 'children(branch(default))'
3185 3226 1
3186 3227 2
3187 3228 5
3188 3229
3189 3230 $ cd ..
3190 3231
3191 3232 test author/desc/keyword in problematic encoding
3192 3233 # unicode: cp932:
3193 3234 # u30A2 0x83 0x41(= 'A')
3194 3235 # u30C2 0x83 0x61(= 'a')
3195 3236
3196 3237 $ hg init problematicencoding
3197 3238 $ cd problematicencoding
3198 3239
3199 3240 $ python > setup.sh <<EOF
3200 3241 > print u'''
3201 3242 > echo a > text
3202 3243 > hg add text
3203 3244 > hg --encoding utf-8 commit -u '\u30A2' -m none
3204 3245 > echo b > text
3205 3246 > hg --encoding utf-8 commit -u '\u30C2' -m none
3206 3247 > echo c > text
3207 3248 > hg --encoding utf-8 commit -u none -m '\u30A2'
3208 3249 > echo d > text
3209 3250 > hg --encoding utf-8 commit -u none -m '\u30C2'
3210 3251 > '''.encode('utf-8')
3211 3252 > EOF
3212 3253 $ sh < setup.sh
3213 3254
3214 3255 test in problematic encoding
3215 3256 $ python > test.sh <<EOF
3216 3257 > print u'''
3217 3258 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
3218 3259 > echo ====
3219 3260 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
3220 3261 > echo ====
3221 3262 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
3222 3263 > echo ====
3223 3264 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
3224 3265 > echo ====
3225 3266 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
3226 3267 > echo ====
3227 3268 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
3228 3269 > '''.encode('cp932')
3229 3270 > EOF
3230 3271 $ sh < test.sh
3231 3272 0
3232 3273 ====
3233 3274 1
3234 3275 ====
3235 3276 2
3236 3277 ====
3237 3278 3
3238 3279 ====
3239 3280 0
3240 3281 2
3241 3282 ====
3242 3283 1
3243 3284 3
3244 3285
3245 3286 test error message of bad revset
3246 3287 $ hg log -r 'foo\\'
3247 3288 hg: parse error at 3: syntax error in revset 'foo\\'
3248 3289 [255]
3249 3290
3250 3291 $ cd ..
3251 3292
3252 3293 Test that revset predicate of extension isn't loaded at failure of
3253 3294 loading it
3254 3295
3255 3296 $ cd repo
3256 3297
3257 3298 $ cat <<EOF > $TESTTMP/custompredicate.py
3258 3299 > from mercurial import error, registrar, revset
3259 3300 >
3260 3301 > revsetpredicate = registrar.revsetpredicate()
3261 3302 >
3262 3303 > @revsetpredicate('custom1()')
3263 3304 > def custom1(repo, subset, x):
3264 3305 > return revset.baseset([1])
3265 3306 >
3266 3307 > raise error.Abort('intentional failure of loading extension')
3267 3308 > EOF
3268 3309 $ cat <<EOF > .hg/hgrc
3269 3310 > [extensions]
3270 3311 > custompredicate = $TESTTMP/custompredicate.py
3271 3312 > EOF
3272 3313
3273 3314 $ hg debugrevspec "custom1()"
3274 3315 *** failed to import extension custompredicate from $TESTTMP/custompredicate.py: intentional failure of loading extension
3275 3316 hg: parse error: unknown identifier: custom1
3276 3317 [255]
3277 3318
3278 3319 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now