##// END OF EJS Templates
debugrevspec: add option to print parsed tree at given stages...
Yuya Nishihara -
r29913:9cb95027 default
parent child Browse files
Show More
@@ -1,7330 +1,7347 b''
1 1 # commands.py - command processing for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __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 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3514 [('', 'optimize', None, _('print parsed tree after optimizing')),
3515 ('p', 'show-stage', [],
3516 _('print parsed tree at the given stage'), _('NAME')),
3517 ],
3515 3518 ('REVSPEC'))
3516 3519 def debugrevspec(ui, repo, expr, **opts):
3517 3520 """parse and apply a revision specification
3518 3521
3519 Use --verbose to print the parsed tree before and after aliases
3520 expansion.
3522 Use -p/--show-stage option to print the parsed tree at the given stages.
3523 Use -p all to print tree at every stage.
3521 3524 """
3522 3525 stages = [
3523 3526 ('parsed', lambda tree: tree),
3524 3527 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
3525 3528 ('concatenated', revset.foldconcat),
3526 3529 ('analyzed', revset.analyze),
3527 3530 ('optimized', revset.optimize),
3528 3531 ]
3529
3530 showalways = set(['parsed'])
3531 showchanged = set(['expanded', 'concatenated'])
3532 if opts['optimize']:
3533 showalways.add('optimized')
3532 stagenames = set(n for n, f in stages)
3533
3534 showalways = set()
3535 showchanged = set()
3536 if ui.verbose and not opts['show_stage']:
3537 # show parsed tree by --verbose (deprecated)
3538 showalways.add('parsed')
3539 showchanged.update(['expanded', 'concatenated'])
3540 if opts['optimize']:
3541 showalways.add('optimized')
3542 if opts['show_stage'] and opts['optimize']:
3543 raise error.Abort(_('cannot use --optimize with --show-stage'))
3544 if opts['show_stage'] == ['all']:
3545 showalways.update(stagenames)
3546 else:
3547 for n in opts['show_stage']:
3548 if n not in stagenames:
3549 raise error.Abort(_('invalid stage name: %s') % n)
3550 showalways.update(opts['show_stage'])
3534 3551
3535 3552 printedtree = None
3536 3553 tree = revset.parse(expr, lookup=repo.__contains__)
3537 3554 for n, f in stages:
3538 3555 tree = f(tree)
3539 3556 if n in showalways or (n in showchanged and tree != printedtree):
3540 if n != 'parsed':
3541 ui.note(("* %s:\n") % n)
3542 ui.note(revset.prettyformat(tree), "\n")
3557 if opts['show_stage'] or n != 'parsed':
3558 ui.write(("* %s:\n") % n)
3559 ui.write(revset.prettyformat(tree), "\n")
3543 3560 printedtree = tree
3544 3561
3545 3562 func = revset.match(ui, expr, repo)
3546 3563 revs = func(repo)
3547 3564 if ui.verbose:
3548 3565 ui.note(("* set:\n"), revset.prettyformatset(revs), "\n")
3549 3566 for c in revs:
3550 3567 ui.write("%s\n" % c)
3551 3568
3552 3569 @command('debugsetparents', [], _('REV1 [REV2]'))
3553 3570 def debugsetparents(ui, repo, rev1, rev2=None):
3554 3571 """manually set the parents of the current working directory
3555 3572
3556 3573 This is useful for writing repository conversion tools, but should
3557 3574 be used with care. For example, neither the working directory nor the
3558 3575 dirstate is updated, so file status may be incorrect after running this
3559 3576 command.
3560 3577
3561 3578 Returns 0 on success.
3562 3579 """
3563 3580
3564 3581 r1 = scmutil.revsingle(repo, rev1).node()
3565 3582 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3566 3583
3567 3584 with repo.wlock():
3568 3585 repo.setparents(r1, r2)
3569 3586
3570 3587 @command('debugdirstate|debugstate',
3571 3588 [('', 'nodates', None, _('do not display the saved mtime')),
3572 3589 ('', 'datesort', None, _('sort by saved mtime'))],
3573 3590 _('[OPTION]...'))
3574 3591 def debugstate(ui, repo, **opts):
3575 3592 """show the contents of the current dirstate"""
3576 3593
3577 3594 nodates = opts.get('nodates')
3578 3595 datesort = opts.get('datesort')
3579 3596
3580 3597 timestr = ""
3581 3598 if datesort:
3582 3599 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3583 3600 else:
3584 3601 keyfunc = None # sort by filename
3585 3602 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3586 3603 if ent[3] == -1:
3587 3604 timestr = 'unset '
3588 3605 elif nodates:
3589 3606 timestr = 'set '
3590 3607 else:
3591 3608 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3592 3609 time.localtime(ent[3]))
3593 3610 if ent[1] & 0o20000:
3594 3611 mode = 'lnk'
3595 3612 else:
3596 3613 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3597 3614 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3598 3615 for f in repo.dirstate.copies():
3599 3616 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3600 3617
3601 3618 @command('debugsub',
3602 3619 [('r', 'rev', '',
3603 3620 _('revision to check'), _('REV'))],
3604 3621 _('[-r REV] [REV]'))
3605 3622 def debugsub(ui, repo, rev=None):
3606 3623 ctx = scmutil.revsingle(repo, rev, None)
3607 3624 for k, v in sorted(ctx.substate.items()):
3608 3625 ui.write(('path %s\n') % k)
3609 3626 ui.write((' source %s\n') % v[0])
3610 3627 ui.write((' revision %s\n') % v[1])
3611 3628
3612 3629 @command('debugsuccessorssets',
3613 3630 [],
3614 3631 _('[REV]'))
3615 3632 def debugsuccessorssets(ui, repo, *revs):
3616 3633 """show set of successors for revision
3617 3634
3618 3635 A successors set of changeset A is a consistent group of revisions that
3619 3636 succeed A. It contains non-obsolete changesets only.
3620 3637
3621 3638 In most cases a changeset A has a single successors set containing a single
3622 3639 successor (changeset A replaced by A').
3623 3640
3624 3641 A changeset that is made obsolete with no successors are called "pruned".
3625 3642 Such changesets have no successors sets at all.
3626 3643
3627 3644 A changeset that has been "split" will have a successors set containing
3628 3645 more than one successor.
3629 3646
3630 3647 A changeset that has been rewritten in multiple different ways is called
3631 3648 "divergent". Such changesets have multiple successor sets (each of which
3632 3649 may also be split, i.e. have multiple successors).
3633 3650
3634 3651 Results are displayed as follows::
3635 3652
3636 3653 <rev1>
3637 3654 <successors-1A>
3638 3655 <rev2>
3639 3656 <successors-2A>
3640 3657 <successors-2B1> <successors-2B2> <successors-2B3>
3641 3658
3642 3659 Here rev2 has two possible (i.e. divergent) successors sets. The first
3643 3660 holds one element, whereas the second holds three (i.e. the changeset has
3644 3661 been split).
3645 3662 """
3646 3663 # passed to successorssets caching computation from one call to another
3647 3664 cache = {}
3648 3665 ctx2str = str
3649 3666 node2str = short
3650 3667 if ui.debug():
3651 3668 def ctx2str(ctx):
3652 3669 return ctx.hex()
3653 3670 node2str = hex
3654 3671 for rev in scmutil.revrange(repo, revs):
3655 3672 ctx = repo[rev]
3656 3673 ui.write('%s\n'% ctx2str(ctx))
3657 3674 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3658 3675 if succsset:
3659 3676 ui.write(' ')
3660 3677 ui.write(node2str(succsset[0]))
3661 3678 for node in succsset[1:]:
3662 3679 ui.write(' ')
3663 3680 ui.write(node2str(node))
3664 3681 ui.write('\n')
3665 3682
3666 3683 @command('debugtemplate',
3667 3684 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3668 3685 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3669 3686 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3670 3687 optionalrepo=True)
3671 3688 def debugtemplate(ui, repo, tmpl, **opts):
3672 3689 """parse and apply a template
3673 3690
3674 3691 If -r/--rev is given, the template is processed as a log template and
3675 3692 applied to the given changesets. Otherwise, it is processed as a generic
3676 3693 template.
3677 3694
3678 3695 Use --verbose to print the parsed tree.
3679 3696 """
3680 3697 revs = None
3681 3698 if opts['rev']:
3682 3699 if repo is None:
3683 3700 raise error.RepoError(_('there is no Mercurial repository here '
3684 3701 '(.hg not found)'))
3685 3702 revs = scmutil.revrange(repo, opts['rev'])
3686 3703
3687 3704 props = {}
3688 3705 for d in opts['define']:
3689 3706 try:
3690 3707 k, v = (e.strip() for e in d.split('=', 1))
3691 3708 if not k:
3692 3709 raise ValueError
3693 3710 props[k] = v
3694 3711 except ValueError:
3695 3712 raise error.Abort(_('malformed keyword definition: %s') % d)
3696 3713
3697 3714 if ui.verbose:
3698 3715 aliases = ui.configitems('templatealias')
3699 3716 tree = templater.parse(tmpl)
3700 3717 ui.note(templater.prettyformat(tree), '\n')
3701 3718 newtree = templater.expandaliases(tree, aliases)
3702 3719 if newtree != tree:
3703 3720 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
3704 3721
3705 3722 mapfile = None
3706 3723 if revs is None:
3707 3724 k = 'debugtemplate'
3708 3725 t = formatter.maketemplater(ui, k, tmpl)
3709 3726 ui.write(templater.stringify(t(k, **props)))
3710 3727 else:
3711 3728 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3712 3729 mapfile, buffered=False)
3713 3730 for r in revs:
3714 3731 displayer.show(repo[r], **props)
3715 3732 displayer.close()
3716 3733
3717 3734 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3718 3735 def debugwalk(ui, repo, *pats, **opts):
3719 3736 """show how files match on given patterns"""
3720 3737 m = scmutil.match(repo[None], pats, opts)
3721 3738 items = list(repo.walk(m))
3722 3739 if not items:
3723 3740 return
3724 3741 f = lambda fn: fn
3725 3742 if ui.configbool('ui', 'slash') and os.sep != '/':
3726 3743 f = lambda fn: util.normpath(fn)
3727 3744 fmt = 'f %%-%ds %%-%ds %%s' % (
3728 3745 max([len(abs) for abs in items]),
3729 3746 max([len(m.rel(abs)) for abs in items]))
3730 3747 for abs in items:
3731 3748 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3732 3749 ui.write("%s\n" % line.rstrip())
3733 3750
3734 3751 @command('debugwireargs',
3735 3752 [('', 'three', '', 'three'),
3736 3753 ('', 'four', '', 'four'),
3737 3754 ('', 'five', '', 'five'),
3738 3755 ] + remoteopts,
3739 3756 _('REPO [OPTIONS]... [ONE [TWO]]'),
3740 3757 norepo=True)
3741 3758 def debugwireargs(ui, repopath, *vals, **opts):
3742 3759 repo = hg.peer(ui, opts, repopath)
3743 3760 for opt in remoteopts:
3744 3761 del opts[opt[1]]
3745 3762 args = {}
3746 3763 for k, v in opts.iteritems():
3747 3764 if v:
3748 3765 args[k] = v
3749 3766 # run twice to check that we don't mess up the stream for the next command
3750 3767 res1 = repo.debugwireargs(*vals, **args)
3751 3768 res2 = repo.debugwireargs(*vals, **args)
3752 3769 ui.write("%s\n" % res1)
3753 3770 if res1 != res2:
3754 3771 ui.warn("%s\n" % res2)
3755 3772
3756 3773 @command('^diff',
3757 3774 [('r', 'rev', [], _('revision'), _('REV')),
3758 3775 ('c', 'change', '', _('change made by revision'), _('REV'))
3759 3776 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3760 3777 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3761 3778 inferrepo=True)
3762 3779 def diff(ui, repo, *pats, **opts):
3763 3780 """diff repository (or selected files)
3764 3781
3765 3782 Show differences between revisions for the specified files.
3766 3783
3767 3784 Differences between files are shown using the unified diff format.
3768 3785
3769 3786 .. note::
3770 3787
3771 3788 :hg:`diff` may generate unexpected results for merges, as it will
3772 3789 default to comparing against the working directory's first
3773 3790 parent changeset if no revisions are specified.
3774 3791
3775 3792 When two revision arguments are given, then changes are shown
3776 3793 between those revisions. If only one revision is specified then
3777 3794 that revision is compared to the working directory, and, when no
3778 3795 revisions are specified, the working directory files are compared
3779 3796 to its first parent.
3780 3797
3781 3798 Alternatively you can specify -c/--change with a revision to see
3782 3799 the changes in that changeset relative to its first parent.
3783 3800
3784 3801 Without the -a/--text option, diff will avoid generating diffs of
3785 3802 files it detects as binary. With -a, diff will generate a diff
3786 3803 anyway, probably with undesirable results.
3787 3804
3788 3805 Use the -g/--git option to generate diffs in the git extended diff
3789 3806 format. For more information, read :hg:`help diffs`.
3790 3807
3791 3808 .. container:: verbose
3792 3809
3793 3810 Examples:
3794 3811
3795 3812 - compare a file in the current working directory to its parent::
3796 3813
3797 3814 hg diff foo.c
3798 3815
3799 3816 - compare two historical versions of a directory, with rename info::
3800 3817
3801 3818 hg diff --git -r 1.0:1.2 lib/
3802 3819
3803 3820 - get change stats relative to the last change on some date::
3804 3821
3805 3822 hg diff --stat -r "date('may 2')"
3806 3823
3807 3824 - diff all newly-added files that contain a keyword::
3808 3825
3809 3826 hg diff "set:added() and grep(GNU)"
3810 3827
3811 3828 - compare a revision and its parents::
3812 3829
3813 3830 hg diff -c 9353 # compare against first parent
3814 3831 hg diff -r 9353^:9353 # same using revset syntax
3815 3832 hg diff -r 9353^2:9353 # compare against the second parent
3816 3833
3817 3834 Returns 0 on success.
3818 3835 """
3819 3836
3820 3837 revs = opts.get('rev')
3821 3838 change = opts.get('change')
3822 3839 stat = opts.get('stat')
3823 3840 reverse = opts.get('reverse')
3824 3841
3825 3842 if revs and change:
3826 3843 msg = _('cannot specify --rev and --change at the same time')
3827 3844 raise error.Abort(msg)
3828 3845 elif change:
3829 3846 node2 = scmutil.revsingle(repo, change, None).node()
3830 3847 node1 = repo[node2].p1().node()
3831 3848 else:
3832 3849 node1, node2 = scmutil.revpair(repo, revs)
3833 3850
3834 3851 if reverse:
3835 3852 node1, node2 = node2, node1
3836 3853
3837 3854 diffopts = patch.diffallopts(ui, opts)
3838 3855 m = scmutil.match(repo[node2], pats, opts)
3839 3856 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3840 3857 listsubrepos=opts.get('subrepos'),
3841 3858 root=opts.get('root'))
3842 3859
3843 3860 @command('^export',
3844 3861 [('o', 'output', '',
3845 3862 _('print output to file with formatted name'), _('FORMAT')),
3846 3863 ('', 'switch-parent', None, _('diff against the second parent')),
3847 3864 ('r', 'rev', [], _('revisions to export'), _('REV')),
3848 3865 ] + diffopts,
3849 3866 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3850 3867 def export(ui, repo, *changesets, **opts):
3851 3868 """dump the header and diffs for one or more changesets
3852 3869
3853 3870 Print the changeset header and diffs for one or more revisions.
3854 3871 If no revision is given, the parent of the working directory is used.
3855 3872
3856 3873 The information shown in the changeset header is: author, date,
3857 3874 branch name (if non-default), changeset hash, parent(s) and commit
3858 3875 comment.
3859 3876
3860 3877 .. note::
3861 3878
3862 3879 :hg:`export` may generate unexpected diff output for merge
3863 3880 changesets, as it will compare the merge changeset against its
3864 3881 first parent only.
3865 3882
3866 3883 Output may be to a file, in which case the name of the file is
3867 3884 given using a format string. The formatting rules are as follows:
3868 3885
3869 3886 :``%%``: literal "%" character
3870 3887 :``%H``: changeset hash (40 hexadecimal digits)
3871 3888 :``%N``: number of patches being generated
3872 3889 :``%R``: changeset revision number
3873 3890 :``%b``: basename of the exporting repository
3874 3891 :``%h``: short-form changeset hash (12 hexadecimal digits)
3875 3892 :``%m``: first line of the commit message (only alphanumeric characters)
3876 3893 :``%n``: zero-padded sequence number, starting at 1
3877 3894 :``%r``: zero-padded changeset revision number
3878 3895
3879 3896 Without the -a/--text option, export will avoid generating diffs
3880 3897 of files it detects as binary. With -a, export will generate a
3881 3898 diff anyway, probably with undesirable results.
3882 3899
3883 3900 Use the -g/--git option to generate diffs in the git extended diff
3884 3901 format. See :hg:`help diffs` for more information.
3885 3902
3886 3903 With the --switch-parent option, the diff will be against the
3887 3904 second parent. It can be useful to review a merge.
3888 3905
3889 3906 .. container:: verbose
3890 3907
3891 3908 Examples:
3892 3909
3893 3910 - use export and import to transplant a bugfix to the current
3894 3911 branch::
3895 3912
3896 3913 hg export -r 9353 | hg import -
3897 3914
3898 3915 - export all the changesets between two revisions to a file with
3899 3916 rename information::
3900 3917
3901 3918 hg export --git -r 123:150 > changes.txt
3902 3919
3903 3920 - split outgoing changes into a series of patches with
3904 3921 descriptive names::
3905 3922
3906 3923 hg export -r "outgoing()" -o "%n-%m.patch"
3907 3924
3908 3925 Returns 0 on success.
3909 3926 """
3910 3927 changesets += tuple(opts.get('rev', []))
3911 3928 if not changesets:
3912 3929 changesets = ['.']
3913 3930 revs = scmutil.revrange(repo, changesets)
3914 3931 if not revs:
3915 3932 raise error.Abort(_("export requires at least one changeset"))
3916 3933 if len(revs) > 1:
3917 3934 ui.note(_('exporting patches:\n'))
3918 3935 else:
3919 3936 ui.note(_('exporting patch:\n'))
3920 3937 cmdutil.export(repo, revs, template=opts.get('output'),
3921 3938 switch_parent=opts.get('switch_parent'),
3922 3939 opts=patch.diffallopts(ui, opts))
3923 3940
3924 3941 @command('files',
3925 3942 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3926 3943 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3927 3944 ] + walkopts + formatteropts + subrepoopts,
3928 3945 _('[OPTION]... [FILE]...'))
3929 3946 def files(ui, repo, *pats, **opts):
3930 3947 """list tracked files
3931 3948
3932 3949 Print files under Mercurial control in the working directory or
3933 3950 specified revision for given files (excluding removed files).
3934 3951 Files can be specified as filenames or filesets.
3935 3952
3936 3953 If no files are given to match, this command prints the names
3937 3954 of all files under Mercurial control.
3938 3955
3939 3956 .. container:: verbose
3940 3957
3941 3958 Examples:
3942 3959
3943 3960 - list all files under the current directory::
3944 3961
3945 3962 hg files .
3946 3963
3947 3964 - shows sizes and flags for current revision::
3948 3965
3949 3966 hg files -vr .
3950 3967
3951 3968 - list all files named README::
3952 3969
3953 3970 hg files -I "**/README"
3954 3971
3955 3972 - list all binary files::
3956 3973
3957 3974 hg files "set:binary()"
3958 3975
3959 3976 - find files containing a regular expression::
3960 3977
3961 3978 hg files "set:grep('bob')"
3962 3979
3963 3980 - search tracked file contents with xargs and grep::
3964 3981
3965 3982 hg files -0 | xargs -0 grep foo
3966 3983
3967 3984 See :hg:`help patterns` and :hg:`help filesets` for more information
3968 3985 on specifying file patterns.
3969 3986
3970 3987 Returns 0 if a match is found, 1 otherwise.
3971 3988
3972 3989 """
3973 3990 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3974 3991
3975 3992 end = '\n'
3976 3993 if opts.get('print0'):
3977 3994 end = '\0'
3978 3995 fmt = '%s' + end
3979 3996
3980 3997 m = scmutil.match(ctx, pats, opts)
3981 3998 with ui.formatter('files', opts) as fm:
3982 3999 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3983 4000
3984 4001 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3985 4002 def forget(ui, repo, *pats, **opts):
3986 4003 """forget the specified files on the next commit
3987 4004
3988 4005 Mark the specified files so they will no longer be tracked
3989 4006 after the next commit.
3990 4007
3991 4008 This only removes files from the current branch, not from the
3992 4009 entire project history, and it does not delete them from the
3993 4010 working directory.
3994 4011
3995 4012 To delete the file from the working directory, see :hg:`remove`.
3996 4013
3997 4014 To undo a forget before the next commit, see :hg:`add`.
3998 4015
3999 4016 .. container:: verbose
4000 4017
4001 4018 Examples:
4002 4019
4003 4020 - forget newly-added binary files::
4004 4021
4005 4022 hg forget "set:added() and binary()"
4006 4023
4007 4024 - forget files that would be excluded by .hgignore::
4008 4025
4009 4026 hg forget "set:hgignore()"
4010 4027
4011 4028 Returns 0 on success.
4012 4029 """
4013 4030
4014 4031 if not pats:
4015 4032 raise error.Abort(_('no files specified'))
4016 4033
4017 4034 m = scmutil.match(repo[None], pats, opts)
4018 4035 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
4019 4036 return rejected and 1 or 0
4020 4037
4021 4038 @command(
4022 4039 'graft',
4023 4040 [('r', 'rev', [], _('revisions to graft'), _('REV')),
4024 4041 ('c', 'continue', False, _('resume interrupted graft')),
4025 4042 ('e', 'edit', False, _('invoke editor on commit messages')),
4026 4043 ('', 'log', None, _('append graft info to log message')),
4027 4044 ('f', 'force', False, _('force graft')),
4028 4045 ('D', 'currentdate', False,
4029 4046 _('record the current date as commit date')),
4030 4047 ('U', 'currentuser', False,
4031 4048 _('record the current user as committer'), _('DATE'))]
4032 4049 + commitopts2 + mergetoolopts + dryrunopts,
4033 4050 _('[OPTION]... [-r REV]... REV...'))
4034 4051 def graft(ui, repo, *revs, **opts):
4035 4052 '''copy changes from other branches onto the current branch
4036 4053
4037 4054 This command uses Mercurial's merge logic to copy individual
4038 4055 changes from other branches without merging branches in the
4039 4056 history graph. This is sometimes known as 'backporting' or
4040 4057 'cherry-picking'. By default, graft will copy user, date, and
4041 4058 description from the source changesets.
4042 4059
4043 4060 Changesets that are ancestors of the current revision, that have
4044 4061 already been grafted, or that are merges will be skipped.
4045 4062
4046 4063 If --log is specified, log messages will have a comment appended
4047 4064 of the form::
4048 4065
4049 4066 (grafted from CHANGESETHASH)
4050 4067
4051 4068 If --force is specified, revisions will be grafted even if they
4052 4069 are already ancestors of or have been grafted to the destination.
4053 4070 This is useful when the revisions have since been backed out.
4054 4071
4055 4072 If a graft merge results in conflicts, the graft process is
4056 4073 interrupted so that the current merge can be manually resolved.
4057 4074 Once all conflicts are addressed, the graft process can be
4058 4075 continued with the -c/--continue option.
4059 4076
4060 4077 .. note::
4061 4078
4062 4079 The -c/--continue option does not reapply earlier options, except
4063 4080 for --force.
4064 4081
4065 4082 .. container:: verbose
4066 4083
4067 4084 Examples:
4068 4085
4069 4086 - copy a single change to the stable branch and edit its description::
4070 4087
4071 4088 hg update stable
4072 4089 hg graft --edit 9393
4073 4090
4074 4091 - graft a range of changesets with one exception, updating dates::
4075 4092
4076 4093 hg graft -D "2085::2093 and not 2091"
4077 4094
4078 4095 - continue a graft after resolving conflicts::
4079 4096
4080 4097 hg graft -c
4081 4098
4082 4099 - show the source of a grafted changeset::
4083 4100
4084 4101 hg log --debug -r .
4085 4102
4086 4103 - show revisions sorted by date::
4087 4104
4088 4105 hg log -r "sort(all(), date)"
4089 4106
4090 4107 See :hg:`help revisions` and :hg:`help revsets` for more about
4091 4108 specifying revisions.
4092 4109
4093 4110 Returns 0 on successful completion.
4094 4111 '''
4095 4112 with repo.wlock():
4096 4113 return _dograft(ui, repo, *revs, **opts)
4097 4114
4098 4115 def _dograft(ui, repo, *revs, **opts):
4099 4116 if revs and opts.get('rev'):
4100 4117 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4101 4118 'revision ordering!\n'))
4102 4119
4103 4120 revs = list(revs)
4104 4121 revs.extend(opts.get('rev'))
4105 4122
4106 4123 if not opts.get('user') and opts.get('currentuser'):
4107 4124 opts['user'] = ui.username()
4108 4125 if not opts.get('date') and opts.get('currentdate'):
4109 4126 opts['date'] = "%d %d" % util.makedate()
4110 4127
4111 4128 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4112 4129
4113 4130 cont = False
4114 4131 if opts.get('continue'):
4115 4132 cont = True
4116 4133 if revs:
4117 4134 raise error.Abort(_("can't specify --continue and revisions"))
4118 4135 # read in unfinished revisions
4119 4136 try:
4120 4137 nodes = repo.vfs.read('graftstate').splitlines()
4121 4138 revs = [repo[node].rev() for node in nodes]
4122 4139 except IOError as inst:
4123 4140 if inst.errno != errno.ENOENT:
4124 4141 raise
4125 4142 cmdutil.wrongtooltocontinue(repo, _('graft'))
4126 4143 else:
4127 4144 cmdutil.checkunfinished(repo)
4128 4145 cmdutil.bailifchanged(repo)
4129 4146 if not revs:
4130 4147 raise error.Abort(_('no revisions specified'))
4131 4148 revs = scmutil.revrange(repo, revs)
4132 4149
4133 4150 skipped = set()
4134 4151 # check for merges
4135 4152 for rev in repo.revs('%ld and merge()', revs):
4136 4153 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4137 4154 skipped.add(rev)
4138 4155 revs = [r for r in revs if r not in skipped]
4139 4156 if not revs:
4140 4157 return -1
4141 4158
4142 4159 # Don't check in the --continue case, in effect retaining --force across
4143 4160 # --continues. That's because without --force, any revisions we decided to
4144 4161 # skip would have been filtered out here, so they wouldn't have made their
4145 4162 # way to the graftstate. With --force, any revisions we would have otherwise
4146 4163 # skipped would not have been filtered out, and if they hadn't been applied
4147 4164 # already, they'd have been in the graftstate.
4148 4165 if not (cont or opts.get('force')):
4149 4166 # check for ancestors of dest branch
4150 4167 crev = repo['.'].rev()
4151 4168 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4152 4169 # XXX make this lazy in the future
4153 4170 # don't mutate while iterating, create a copy
4154 4171 for rev in list(revs):
4155 4172 if rev in ancestors:
4156 4173 ui.warn(_('skipping ancestor revision %d:%s\n') %
4157 4174 (rev, repo[rev]))
4158 4175 # XXX remove on list is slow
4159 4176 revs.remove(rev)
4160 4177 if not revs:
4161 4178 return -1
4162 4179
4163 4180 # analyze revs for earlier grafts
4164 4181 ids = {}
4165 4182 for ctx in repo.set("%ld", revs):
4166 4183 ids[ctx.hex()] = ctx.rev()
4167 4184 n = ctx.extra().get('source')
4168 4185 if n:
4169 4186 ids[n] = ctx.rev()
4170 4187
4171 4188 # check ancestors for earlier grafts
4172 4189 ui.debug('scanning for duplicate grafts\n')
4173 4190
4174 4191 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4175 4192 ctx = repo[rev]
4176 4193 n = ctx.extra().get('source')
4177 4194 if n in ids:
4178 4195 try:
4179 4196 r = repo[n].rev()
4180 4197 except error.RepoLookupError:
4181 4198 r = None
4182 4199 if r in revs:
4183 4200 ui.warn(_('skipping revision %d:%s '
4184 4201 '(already grafted to %d:%s)\n')
4185 4202 % (r, repo[r], rev, ctx))
4186 4203 revs.remove(r)
4187 4204 elif ids[n] in revs:
4188 4205 if r is None:
4189 4206 ui.warn(_('skipping already grafted revision %d:%s '
4190 4207 '(%d:%s also has unknown origin %s)\n')
4191 4208 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4192 4209 else:
4193 4210 ui.warn(_('skipping already grafted revision %d:%s '
4194 4211 '(%d:%s also has origin %d:%s)\n')
4195 4212 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4196 4213 revs.remove(ids[n])
4197 4214 elif ctx.hex() in ids:
4198 4215 r = ids[ctx.hex()]
4199 4216 ui.warn(_('skipping already grafted revision %d:%s '
4200 4217 '(was grafted from %d:%s)\n') %
4201 4218 (r, repo[r], rev, ctx))
4202 4219 revs.remove(r)
4203 4220 if not revs:
4204 4221 return -1
4205 4222
4206 4223 for pos, ctx in enumerate(repo.set("%ld", revs)):
4207 4224 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4208 4225 ctx.description().split('\n', 1)[0])
4209 4226 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4210 4227 if names:
4211 4228 desc += ' (%s)' % ' '.join(names)
4212 4229 ui.status(_('grafting %s\n') % desc)
4213 4230 if opts.get('dry_run'):
4214 4231 continue
4215 4232
4216 4233 source = ctx.extra().get('source')
4217 4234 extra = {}
4218 4235 if source:
4219 4236 extra['source'] = source
4220 4237 extra['intermediate-source'] = ctx.hex()
4221 4238 else:
4222 4239 extra['source'] = ctx.hex()
4223 4240 user = ctx.user()
4224 4241 if opts.get('user'):
4225 4242 user = opts['user']
4226 4243 date = ctx.date()
4227 4244 if opts.get('date'):
4228 4245 date = opts['date']
4229 4246 message = ctx.description()
4230 4247 if opts.get('log'):
4231 4248 message += '\n(grafted from %s)' % ctx.hex()
4232 4249
4233 4250 # we don't merge the first commit when continuing
4234 4251 if not cont:
4235 4252 # perform the graft merge with p1(rev) as 'ancestor'
4236 4253 try:
4237 4254 # ui.forcemerge is an internal variable, do not document
4238 4255 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4239 4256 'graft')
4240 4257 stats = mergemod.graft(repo, ctx, ctx.p1(),
4241 4258 ['local', 'graft'])
4242 4259 finally:
4243 4260 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4244 4261 # report any conflicts
4245 4262 if stats and stats[3] > 0:
4246 4263 # write out state for --continue
4247 4264 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4248 4265 repo.vfs.write('graftstate', ''.join(nodelines))
4249 4266 extra = ''
4250 4267 if opts.get('user'):
4251 4268 extra += ' --user %s' % util.shellquote(opts['user'])
4252 4269 if opts.get('date'):
4253 4270 extra += ' --date %s' % util.shellquote(opts['date'])
4254 4271 if opts.get('log'):
4255 4272 extra += ' --log'
4256 4273 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
4257 4274 raise error.Abort(
4258 4275 _("unresolved conflicts, can't continue"),
4259 4276 hint=hint)
4260 4277 else:
4261 4278 cont = False
4262 4279
4263 4280 # commit
4264 4281 node = repo.commit(text=message, user=user,
4265 4282 date=date, extra=extra, editor=editor)
4266 4283 if node is None:
4267 4284 ui.warn(
4268 4285 _('note: graft of %d:%s created no changes to commit\n') %
4269 4286 (ctx.rev(), ctx))
4270 4287
4271 4288 # remove state when we complete successfully
4272 4289 if not opts.get('dry_run'):
4273 4290 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4274 4291
4275 4292 return 0
4276 4293
4277 4294 @command('grep',
4278 4295 [('0', 'print0', None, _('end fields with NUL')),
4279 4296 ('', 'all', None, _('print all revisions that match')),
4280 4297 ('a', 'text', None, _('treat all files as text')),
4281 4298 ('f', 'follow', None,
4282 4299 _('follow changeset history,'
4283 4300 ' or file history across copies and renames')),
4284 4301 ('i', 'ignore-case', None, _('ignore case when matching')),
4285 4302 ('l', 'files-with-matches', None,
4286 4303 _('print only filenames and revisions that match')),
4287 4304 ('n', 'line-number', None, _('print matching line numbers')),
4288 4305 ('r', 'rev', [],
4289 4306 _('only search files changed within revision range'), _('REV')),
4290 4307 ('u', 'user', None, _('list the author (long with -v)')),
4291 4308 ('d', 'date', None, _('list the date (short with -q)')),
4292 4309 ] + formatteropts + walkopts,
4293 4310 _('[OPTION]... PATTERN [FILE]...'),
4294 4311 inferrepo=True)
4295 4312 def grep(ui, repo, pattern, *pats, **opts):
4296 4313 """search for a pattern in specified files and revisions
4297 4314
4298 4315 Search revisions of files for a regular expression.
4299 4316
4300 4317 This command behaves differently than Unix grep. It only accepts
4301 4318 Python/Perl regexps. It searches repository history, not the
4302 4319 working directory. It always prints the revision number in which a
4303 4320 match appears.
4304 4321
4305 4322 By default, grep only prints output for the first revision of a
4306 4323 file in which it finds a match. To get it to print every revision
4307 4324 that contains a change in match status ("-" for a match that
4308 4325 becomes a non-match, or "+" for a non-match that becomes a match),
4309 4326 use the --all flag.
4310 4327
4311 4328 Returns 0 if a match is found, 1 otherwise.
4312 4329 """
4313 4330 reflags = re.M
4314 4331 if opts.get('ignore_case'):
4315 4332 reflags |= re.I
4316 4333 try:
4317 4334 regexp = util.re.compile(pattern, reflags)
4318 4335 except re.error as inst:
4319 4336 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4320 4337 return 1
4321 4338 sep, eol = ':', '\n'
4322 4339 if opts.get('print0'):
4323 4340 sep = eol = '\0'
4324 4341
4325 4342 getfile = util.lrucachefunc(repo.file)
4326 4343
4327 4344 def matchlines(body):
4328 4345 begin = 0
4329 4346 linenum = 0
4330 4347 while begin < len(body):
4331 4348 match = regexp.search(body, begin)
4332 4349 if not match:
4333 4350 break
4334 4351 mstart, mend = match.span()
4335 4352 linenum += body.count('\n', begin, mstart) + 1
4336 4353 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4337 4354 begin = body.find('\n', mend) + 1 or len(body) + 1
4338 4355 lend = begin - 1
4339 4356 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4340 4357
4341 4358 class linestate(object):
4342 4359 def __init__(self, line, linenum, colstart, colend):
4343 4360 self.line = line
4344 4361 self.linenum = linenum
4345 4362 self.colstart = colstart
4346 4363 self.colend = colend
4347 4364
4348 4365 def __hash__(self):
4349 4366 return hash((self.linenum, self.line))
4350 4367
4351 4368 def __eq__(self, other):
4352 4369 return self.line == other.line
4353 4370
4354 4371 def findpos(self):
4355 4372 """Iterate all (start, end) indices of matches"""
4356 4373 yield self.colstart, self.colend
4357 4374 p = self.colend
4358 4375 while p < len(self.line):
4359 4376 m = regexp.search(self.line, p)
4360 4377 if not m:
4361 4378 break
4362 4379 yield m.span()
4363 4380 p = m.end()
4364 4381
4365 4382 matches = {}
4366 4383 copies = {}
4367 4384 def grepbody(fn, rev, body):
4368 4385 matches[rev].setdefault(fn, [])
4369 4386 m = matches[rev][fn]
4370 4387 for lnum, cstart, cend, line in matchlines(body):
4371 4388 s = linestate(line, lnum, cstart, cend)
4372 4389 m.append(s)
4373 4390
4374 4391 def difflinestates(a, b):
4375 4392 sm = difflib.SequenceMatcher(None, a, b)
4376 4393 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4377 4394 if tag == 'insert':
4378 4395 for i in xrange(blo, bhi):
4379 4396 yield ('+', b[i])
4380 4397 elif tag == 'delete':
4381 4398 for i in xrange(alo, ahi):
4382 4399 yield ('-', a[i])
4383 4400 elif tag == 'replace':
4384 4401 for i in xrange(alo, ahi):
4385 4402 yield ('-', a[i])
4386 4403 for i in xrange(blo, bhi):
4387 4404 yield ('+', b[i])
4388 4405
4389 4406 def display(fm, fn, ctx, pstates, states):
4390 4407 rev = ctx.rev()
4391 4408 if fm:
4392 4409 formatuser = str
4393 4410 else:
4394 4411 formatuser = ui.shortuser
4395 4412 if ui.quiet:
4396 4413 datefmt = '%Y-%m-%d'
4397 4414 else:
4398 4415 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
4399 4416 found = False
4400 4417 @util.cachefunc
4401 4418 def binary():
4402 4419 flog = getfile(fn)
4403 4420 return util.binary(flog.read(ctx.filenode(fn)))
4404 4421
4405 4422 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
4406 4423 if opts.get('all'):
4407 4424 iter = difflinestates(pstates, states)
4408 4425 else:
4409 4426 iter = [('', l) for l in states]
4410 4427 for change, l in iter:
4411 4428 fm.startitem()
4412 4429 fm.data(node=fm.hexfunc(ctx.node()))
4413 4430 cols = [
4414 4431 ('filename', fn, True),
4415 4432 ('rev', rev, True),
4416 4433 ('linenumber', l.linenum, opts.get('line_number')),
4417 4434 ]
4418 4435 if opts.get('all'):
4419 4436 cols.append(('change', change, True))
4420 4437 cols.extend([
4421 4438 ('user', formatuser(ctx.user()), opts.get('user')),
4422 4439 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
4423 4440 ])
4424 4441 lastcol = next(name for name, data, cond in reversed(cols) if cond)
4425 4442 for name, data, cond in cols:
4426 4443 field = fieldnamemap.get(name, name)
4427 4444 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
4428 4445 if cond and name != lastcol:
4429 4446 fm.plain(sep, label='grep.sep')
4430 4447 if not opts.get('files_with_matches'):
4431 4448 fm.plain(sep, label='grep.sep')
4432 4449 if not opts.get('text') and binary():
4433 4450 fm.plain(_(" Binary file matches"))
4434 4451 else:
4435 4452 displaymatches(fm.nested('texts'), l)
4436 4453 fm.plain(eol)
4437 4454 found = True
4438 4455 if opts.get('files_with_matches'):
4439 4456 break
4440 4457 return found
4441 4458
4442 4459 def displaymatches(fm, l):
4443 4460 p = 0
4444 4461 for s, e in l.findpos():
4445 4462 if p < s:
4446 4463 fm.startitem()
4447 4464 fm.write('text', '%s', l.line[p:s])
4448 4465 fm.data(matched=False)
4449 4466 fm.startitem()
4450 4467 fm.write('text', '%s', l.line[s:e], label='grep.match')
4451 4468 fm.data(matched=True)
4452 4469 p = e
4453 4470 if p < len(l.line):
4454 4471 fm.startitem()
4455 4472 fm.write('text', '%s', l.line[p:])
4456 4473 fm.data(matched=False)
4457 4474 fm.end()
4458 4475
4459 4476 skip = {}
4460 4477 revfiles = {}
4461 4478 matchfn = scmutil.match(repo[None], pats, opts)
4462 4479 found = False
4463 4480 follow = opts.get('follow')
4464 4481
4465 4482 def prep(ctx, fns):
4466 4483 rev = ctx.rev()
4467 4484 pctx = ctx.p1()
4468 4485 parent = pctx.rev()
4469 4486 matches.setdefault(rev, {})
4470 4487 matches.setdefault(parent, {})
4471 4488 files = revfiles.setdefault(rev, [])
4472 4489 for fn in fns:
4473 4490 flog = getfile(fn)
4474 4491 try:
4475 4492 fnode = ctx.filenode(fn)
4476 4493 except error.LookupError:
4477 4494 continue
4478 4495
4479 4496 copied = flog.renamed(fnode)
4480 4497 copy = follow and copied and copied[0]
4481 4498 if copy:
4482 4499 copies.setdefault(rev, {})[fn] = copy
4483 4500 if fn in skip:
4484 4501 if copy:
4485 4502 skip[copy] = True
4486 4503 continue
4487 4504 files.append(fn)
4488 4505
4489 4506 if fn not in matches[rev]:
4490 4507 grepbody(fn, rev, flog.read(fnode))
4491 4508
4492 4509 pfn = copy or fn
4493 4510 if pfn not in matches[parent]:
4494 4511 try:
4495 4512 fnode = pctx.filenode(pfn)
4496 4513 grepbody(pfn, parent, flog.read(fnode))
4497 4514 except error.LookupError:
4498 4515 pass
4499 4516
4500 4517 fm = ui.formatter('grep', opts)
4501 4518 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4502 4519 rev = ctx.rev()
4503 4520 parent = ctx.p1().rev()
4504 4521 for fn in sorted(revfiles.get(rev, [])):
4505 4522 states = matches[rev][fn]
4506 4523 copy = copies.get(rev, {}).get(fn)
4507 4524 if fn in skip:
4508 4525 if copy:
4509 4526 skip[copy] = True
4510 4527 continue
4511 4528 pstates = matches.get(parent, {}).get(copy or fn, [])
4512 4529 if pstates or states:
4513 4530 r = display(fm, fn, ctx, pstates, states)
4514 4531 found = found or r
4515 4532 if r and not opts.get('all'):
4516 4533 skip[fn] = True
4517 4534 if copy:
4518 4535 skip[copy] = True
4519 4536 del matches[rev]
4520 4537 del revfiles[rev]
4521 4538 fm.end()
4522 4539
4523 4540 return not found
4524 4541
4525 4542 @command('heads',
4526 4543 [('r', 'rev', '',
4527 4544 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4528 4545 ('t', 'topo', False, _('show topological heads only')),
4529 4546 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4530 4547 ('c', 'closed', False, _('show normal and closed branch heads')),
4531 4548 ] + templateopts,
4532 4549 _('[-ct] [-r STARTREV] [REV]...'))
4533 4550 def heads(ui, repo, *branchrevs, **opts):
4534 4551 """show branch heads
4535 4552
4536 4553 With no arguments, show all open branch heads in the repository.
4537 4554 Branch heads are changesets that have no descendants on the
4538 4555 same branch. They are where development generally takes place and
4539 4556 are the usual targets for update and merge operations.
4540 4557
4541 4558 If one or more REVs are given, only open branch heads on the
4542 4559 branches associated with the specified changesets are shown. This
4543 4560 means that you can use :hg:`heads .` to see the heads on the
4544 4561 currently checked-out branch.
4545 4562
4546 4563 If -c/--closed is specified, also show branch heads marked closed
4547 4564 (see :hg:`commit --close-branch`).
4548 4565
4549 4566 If STARTREV is specified, only those heads that are descendants of
4550 4567 STARTREV will be displayed.
4551 4568
4552 4569 If -t/--topo is specified, named branch mechanics will be ignored and only
4553 4570 topological heads (changesets with no children) will be shown.
4554 4571
4555 4572 Returns 0 if matching heads are found, 1 if not.
4556 4573 """
4557 4574
4558 4575 start = None
4559 4576 if 'rev' in opts:
4560 4577 start = scmutil.revsingle(repo, opts['rev'], None).node()
4561 4578
4562 4579 if opts.get('topo'):
4563 4580 heads = [repo[h] for h in repo.heads(start)]
4564 4581 else:
4565 4582 heads = []
4566 4583 for branch in repo.branchmap():
4567 4584 heads += repo.branchheads(branch, start, opts.get('closed'))
4568 4585 heads = [repo[h] for h in heads]
4569 4586
4570 4587 if branchrevs:
4571 4588 branches = set(repo[br].branch() for br in branchrevs)
4572 4589 heads = [h for h in heads if h.branch() in branches]
4573 4590
4574 4591 if opts.get('active') and branchrevs:
4575 4592 dagheads = repo.heads(start)
4576 4593 heads = [h for h in heads if h.node() in dagheads]
4577 4594
4578 4595 if branchrevs:
4579 4596 haveheads = set(h.branch() for h in heads)
4580 4597 if branches - haveheads:
4581 4598 headless = ', '.join(b for b in branches - haveheads)
4582 4599 msg = _('no open branch heads found on branches %s')
4583 4600 if opts.get('rev'):
4584 4601 msg += _(' (started at %s)') % opts['rev']
4585 4602 ui.warn((msg + '\n') % headless)
4586 4603
4587 4604 if not heads:
4588 4605 return 1
4589 4606
4590 4607 heads = sorted(heads, key=lambda x: -x.rev())
4591 4608 displayer = cmdutil.show_changeset(ui, repo, opts)
4592 4609 for ctx in heads:
4593 4610 displayer.show(ctx)
4594 4611 displayer.close()
4595 4612
4596 4613 @command('help',
4597 4614 [('e', 'extension', None, _('show only help for extensions')),
4598 4615 ('c', 'command', None, _('show only help for commands')),
4599 4616 ('k', 'keyword', None, _('show topics matching keyword')),
4600 4617 ('s', 'system', [], _('show help for specific platform(s)')),
4601 4618 ],
4602 4619 _('[-ecks] [TOPIC]'),
4603 4620 norepo=True)
4604 4621 def help_(ui, name=None, **opts):
4605 4622 """show help for a given topic or a help overview
4606 4623
4607 4624 With no arguments, print a list of commands with short help messages.
4608 4625
4609 4626 Given a topic, extension, or command name, print help for that
4610 4627 topic.
4611 4628
4612 4629 Returns 0 if successful.
4613 4630 """
4614 4631
4615 4632 textwidth = ui.configint('ui', 'textwidth', 78)
4616 4633 termwidth = ui.termwidth() - 2
4617 4634 if textwidth <= 0 or termwidth < textwidth:
4618 4635 textwidth = termwidth
4619 4636
4620 4637 keep = opts.get('system') or []
4621 4638 if len(keep) == 0:
4622 4639 if sys.platform.startswith('win'):
4623 4640 keep.append('windows')
4624 4641 elif sys.platform == 'OpenVMS':
4625 4642 keep.append('vms')
4626 4643 elif sys.platform == 'plan9':
4627 4644 keep.append('plan9')
4628 4645 else:
4629 4646 keep.append('unix')
4630 4647 keep.append(sys.platform.lower())
4631 4648 if ui.verbose:
4632 4649 keep.append('verbose')
4633 4650
4634 4651 section = None
4635 4652 subtopic = None
4636 4653 if name and '.' in name:
4637 4654 name, remaining = name.split('.', 1)
4638 4655 remaining = encoding.lower(remaining)
4639 4656 if '.' in remaining:
4640 4657 subtopic, section = remaining.split('.', 1)
4641 4658 else:
4642 4659 if name in help.subtopics:
4643 4660 subtopic = remaining
4644 4661 else:
4645 4662 section = remaining
4646 4663
4647 4664 text = help.help_(ui, name, subtopic=subtopic, **opts)
4648 4665
4649 4666 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4650 4667 section=section)
4651 4668
4652 4669 # We could have been given a weird ".foo" section without a name
4653 4670 # to look for, or we could have simply failed to found "foo.bar"
4654 4671 # because bar isn't a section of foo
4655 4672 if section and not (formatted and name):
4656 4673 raise error.Abort(_("help section not found"))
4657 4674
4658 4675 if 'verbose' in pruned:
4659 4676 keep.append('omitted')
4660 4677 else:
4661 4678 keep.append('notomitted')
4662 4679 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4663 4680 section=section)
4664 4681 ui.write(formatted)
4665 4682
4666 4683
4667 4684 @command('identify|id',
4668 4685 [('r', 'rev', '',
4669 4686 _('identify the specified revision'), _('REV')),
4670 4687 ('n', 'num', None, _('show local revision number')),
4671 4688 ('i', 'id', None, _('show global revision id')),
4672 4689 ('b', 'branch', None, _('show branch')),
4673 4690 ('t', 'tags', None, _('show tags')),
4674 4691 ('B', 'bookmarks', None, _('show bookmarks')),
4675 4692 ] + remoteopts,
4676 4693 _('[-nibtB] [-r REV] [SOURCE]'),
4677 4694 optionalrepo=True)
4678 4695 def identify(ui, repo, source=None, rev=None,
4679 4696 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4680 4697 """identify the working directory or specified revision
4681 4698
4682 4699 Print a summary identifying the repository state at REV using one or
4683 4700 two parent hash identifiers, followed by a "+" if the working
4684 4701 directory has uncommitted changes, the branch name (if not default),
4685 4702 a list of tags, and a list of bookmarks.
4686 4703
4687 4704 When REV is not given, print a summary of the current state of the
4688 4705 repository.
4689 4706
4690 4707 Specifying a path to a repository root or Mercurial bundle will
4691 4708 cause lookup to operate on that repository/bundle.
4692 4709
4693 4710 .. container:: verbose
4694 4711
4695 4712 Examples:
4696 4713
4697 4714 - generate a build identifier for the working directory::
4698 4715
4699 4716 hg id --id > build-id.dat
4700 4717
4701 4718 - find the revision corresponding to a tag::
4702 4719
4703 4720 hg id -n -r 1.3
4704 4721
4705 4722 - check the most recent revision of a remote repository::
4706 4723
4707 4724 hg id -r tip http://selenic.com/hg/
4708 4725
4709 4726 See :hg:`log` for generating more information about specific revisions,
4710 4727 including full hash identifiers.
4711 4728
4712 4729 Returns 0 if successful.
4713 4730 """
4714 4731
4715 4732 if not repo and not source:
4716 4733 raise error.Abort(_("there is no Mercurial repository here "
4717 4734 "(.hg not found)"))
4718 4735
4719 4736 if ui.debugflag:
4720 4737 hexfunc = hex
4721 4738 else:
4722 4739 hexfunc = short
4723 4740 default = not (num or id or branch or tags or bookmarks)
4724 4741 output = []
4725 4742 revs = []
4726 4743
4727 4744 if source:
4728 4745 source, branches = hg.parseurl(ui.expandpath(source))
4729 4746 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4730 4747 repo = peer.local()
4731 4748 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4732 4749
4733 4750 if not repo:
4734 4751 if num or branch or tags:
4735 4752 raise error.Abort(
4736 4753 _("can't query remote revision number, branch, or tags"))
4737 4754 if not rev and revs:
4738 4755 rev = revs[0]
4739 4756 if not rev:
4740 4757 rev = "tip"
4741 4758
4742 4759 remoterev = peer.lookup(rev)
4743 4760 if default or id:
4744 4761 output = [hexfunc(remoterev)]
4745 4762
4746 4763 def getbms():
4747 4764 bms = []
4748 4765
4749 4766 if 'bookmarks' in peer.listkeys('namespaces'):
4750 4767 hexremoterev = hex(remoterev)
4751 4768 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4752 4769 if bmr == hexremoterev]
4753 4770
4754 4771 return sorted(bms)
4755 4772
4756 4773 if bookmarks:
4757 4774 output.extend(getbms())
4758 4775 elif default and not ui.quiet:
4759 4776 # multiple bookmarks for a single parent separated by '/'
4760 4777 bm = '/'.join(getbms())
4761 4778 if bm:
4762 4779 output.append(bm)
4763 4780 else:
4764 4781 ctx = scmutil.revsingle(repo, rev, None)
4765 4782
4766 4783 if ctx.rev() is None:
4767 4784 ctx = repo[None]
4768 4785 parents = ctx.parents()
4769 4786 taglist = []
4770 4787 for p in parents:
4771 4788 taglist.extend(p.tags())
4772 4789
4773 4790 changed = ""
4774 4791 if default or id or num:
4775 4792 if (any(repo.status())
4776 4793 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4777 4794 changed = '+'
4778 4795 if default or id:
4779 4796 output = ["%s%s" %
4780 4797 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4781 4798 if num:
4782 4799 output.append("%s%s" %
4783 4800 ('+'.join([str(p.rev()) for p in parents]), changed))
4784 4801 else:
4785 4802 if default or id:
4786 4803 output = [hexfunc(ctx.node())]
4787 4804 if num:
4788 4805 output.append(str(ctx.rev()))
4789 4806 taglist = ctx.tags()
4790 4807
4791 4808 if default and not ui.quiet:
4792 4809 b = ctx.branch()
4793 4810 if b != 'default':
4794 4811 output.append("(%s)" % b)
4795 4812
4796 4813 # multiple tags for a single parent separated by '/'
4797 4814 t = '/'.join(taglist)
4798 4815 if t:
4799 4816 output.append(t)
4800 4817
4801 4818 # multiple bookmarks for a single parent separated by '/'
4802 4819 bm = '/'.join(ctx.bookmarks())
4803 4820 if bm:
4804 4821 output.append(bm)
4805 4822 else:
4806 4823 if branch:
4807 4824 output.append(ctx.branch())
4808 4825
4809 4826 if tags:
4810 4827 output.extend(taglist)
4811 4828
4812 4829 if bookmarks:
4813 4830 output.extend(ctx.bookmarks())
4814 4831
4815 4832 ui.write("%s\n" % ' '.join(output))
4816 4833
4817 4834 @command('import|patch',
4818 4835 [('p', 'strip', 1,
4819 4836 _('directory strip option for patch. This has the same '
4820 4837 'meaning as the corresponding patch option'), _('NUM')),
4821 4838 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4822 4839 ('e', 'edit', False, _('invoke editor on commit messages')),
4823 4840 ('f', 'force', None,
4824 4841 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4825 4842 ('', 'no-commit', None,
4826 4843 _("don't commit, just update the working directory")),
4827 4844 ('', 'bypass', None,
4828 4845 _("apply patch without touching the working directory")),
4829 4846 ('', 'partial', None,
4830 4847 _('commit even if some hunks fail')),
4831 4848 ('', 'exact', None,
4832 4849 _('abort if patch would apply lossily')),
4833 4850 ('', 'prefix', '',
4834 4851 _('apply patch to subdirectory'), _('DIR')),
4835 4852 ('', 'import-branch', None,
4836 4853 _('use any branch information in patch (implied by --exact)'))] +
4837 4854 commitopts + commitopts2 + similarityopts,
4838 4855 _('[OPTION]... PATCH...'))
4839 4856 def import_(ui, repo, patch1=None, *patches, **opts):
4840 4857 """import an ordered set of patches
4841 4858
4842 4859 Import a list of patches and commit them individually (unless
4843 4860 --no-commit is specified).
4844 4861
4845 4862 To read a patch from standard input, use "-" as the patch name. If
4846 4863 a URL is specified, the patch will be downloaded from there.
4847 4864
4848 4865 Import first applies changes to the working directory (unless
4849 4866 --bypass is specified), import will abort if there are outstanding
4850 4867 changes.
4851 4868
4852 4869 Use --bypass to apply and commit patches directly to the
4853 4870 repository, without affecting the working directory. Without
4854 4871 --exact, patches will be applied on top of the working directory
4855 4872 parent revision.
4856 4873
4857 4874 You can import a patch straight from a mail message. Even patches
4858 4875 as attachments work (to use the body part, it must have type
4859 4876 text/plain or text/x-patch). From and Subject headers of email
4860 4877 message are used as default committer and commit message. All
4861 4878 text/plain body parts before first diff are added to the commit
4862 4879 message.
4863 4880
4864 4881 If the imported patch was generated by :hg:`export`, user and
4865 4882 description from patch override values from message headers and
4866 4883 body. Values given on command line with -m/--message and -u/--user
4867 4884 override these.
4868 4885
4869 4886 If --exact is specified, import will set the working directory to
4870 4887 the parent of each patch before applying it, and will abort if the
4871 4888 resulting changeset has a different ID than the one recorded in
4872 4889 the patch. This will guard against various ways that portable
4873 4890 patch formats and mail systems might fail to transfer Mercurial
4874 4891 data or metadata. See :hg:`bundle` for lossless transmission.
4875 4892
4876 4893 Use --partial to ensure a changeset will be created from the patch
4877 4894 even if some hunks fail to apply. Hunks that fail to apply will be
4878 4895 written to a <target-file>.rej file. Conflicts can then be resolved
4879 4896 by hand before :hg:`commit --amend` is run to update the created
4880 4897 changeset. This flag exists to let people import patches that
4881 4898 partially apply without losing the associated metadata (author,
4882 4899 date, description, ...).
4883 4900
4884 4901 .. note::
4885 4902
4886 4903 When no hunks apply cleanly, :hg:`import --partial` will create
4887 4904 an empty changeset, importing only the patch metadata.
4888 4905
4889 4906 With -s/--similarity, hg will attempt to discover renames and
4890 4907 copies in the patch in the same way as :hg:`addremove`.
4891 4908
4892 4909 It is possible to use external patch programs to perform the patch
4893 4910 by setting the ``ui.patch`` configuration option. For the default
4894 4911 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4895 4912 See :hg:`help config` for more information about configuration
4896 4913 files and how to use these options.
4897 4914
4898 4915 See :hg:`help dates` for a list of formats valid for -d/--date.
4899 4916
4900 4917 .. container:: verbose
4901 4918
4902 4919 Examples:
4903 4920
4904 4921 - import a traditional patch from a website and detect renames::
4905 4922
4906 4923 hg import -s 80 http://example.com/bugfix.patch
4907 4924
4908 4925 - import a changeset from an hgweb server::
4909 4926
4910 4927 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4911 4928
4912 4929 - import all the patches in an Unix-style mbox::
4913 4930
4914 4931 hg import incoming-patches.mbox
4915 4932
4916 4933 - attempt to exactly restore an exported changeset (not always
4917 4934 possible)::
4918 4935
4919 4936 hg import --exact proposed-fix.patch
4920 4937
4921 4938 - use an external tool to apply a patch which is too fuzzy for
4922 4939 the default internal tool.
4923 4940
4924 4941 hg import --config ui.patch="patch --merge" fuzzy.patch
4925 4942
4926 4943 - change the default fuzzing from 2 to a less strict 7
4927 4944
4928 4945 hg import --config ui.fuzz=7 fuzz.patch
4929 4946
4930 4947 Returns 0 on success, 1 on partial success (see --partial).
4931 4948 """
4932 4949
4933 4950 if not patch1:
4934 4951 raise error.Abort(_('need at least one patch to import'))
4935 4952
4936 4953 patches = (patch1,) + patches
4937 4954
4938 4955 date = opts.get('date')
4939 4956 if date:
4940 4957 opts['date'] = util.parsedate(date)
4941 4958
4942 4959 exact = opts.get('exact')
4943 4960 update = not opts.get('bypass')
4944 4961 if not update and opts.get('no_commit'):
4945 4962 raise error.Abort(_('cannot use --no-commit with --bypass'))
4946 4963 try:
4947 4964 sim = float(opts.get('similarity') or 0)
4948 4965 except ValueError:
4949 4966 raise error.Abort(_('similarity must be a number'))
4950 4967 if sim < 0 or sim > 100:
4951 4968 raise error.Abort(_('similarity must be between 0 and 100'))
4952 4969 if sim and not update:
4953 4970 raise error.Abort(_('cannot use --similarity with --bypass'))
4954 4971 if exact:
4955 4972 if opts.get('edit'):
4956 4973 raise error.Abort(_('cannot use --exact with --edit'))
4957 4974 if opts.get('prefix'):
4958 4975 raise error.Abort(_('cannot use --exact with --prefix'))
4959 4976
4960 4977 base = opts["base"]
4961 4978 wlock = dsguard = lock = tr = None
4962 4979 msgs = []
4963 4980 ret = 0
4964 4981
4965 4982
4966 4983 try:
4967 4984 wlock = repo.wlock()
4968 4985
4969 4986 if update:
4970 4987 cmdutil.checkunfinished(repo)
4971 4988 if (exact or not opts.get('force')):
4972 4989 cmdutil.bailifchanged(repo)
4973 4990
4974 4991 if not opts.get('no_commit'):
4975 4992 lock = repo.lock()
4976 4993 tr = repo.transaction('import')
4977 4994 else:
4978 4995 dsguard = cmdutil.dirstateguard(repo, 'import')
4979 4996 parents = repo[None].parents()
4980 4997 for patchurl in patches:
4981 4998 if patchurl == '-':
4982 4999 ui.status(_('applying patch from stdin\n'))
4983 5000 patchfile = ui.fin
4984 5001 patchurl = 'stdin' # for error message
4985 5002 else:
4986 5003 patchurl = os.path.join(base, patchurl)
4987 5004 ui.status(_('applying %s\n') % patchurl)
4988 5005 patchfile = hg.openpath(ui, patchurl)
4989 5006
4990 5007 haspatch = False
4991 5008 for hunk in patch.split(patchfile):
4992 5009 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4993 5010 parents, opts,
4994 5011 msgs, hg.clean)
4995 5012 if msg:
4996 5013 haspatch = True
4997 5014 ui.note(msg + '\n')
4998 5015 if update or exact:
4999 5016 parents = repo[None].parents()
5000 5017 else:
5001 5018 parents = [repo[node]]
5002 5019 if rej:
5003 5020 ui.write_err(_("patch applied partially\n"))
5004 5021 ui.write_err(_("(fix the .rej files and run "
5005 5022 "`hg commit --amend`)\n"))
5006 5023 ret = 1
5007 5024 break
5008 5025
5009 5026 if not haspatch:
5010 5027 raise error.Abort(_('%s: no diffs found') % patchurl)
5011 5028
5012 5029 if tr:
5013 5030 tr.close()
5014 5031 if msgs:
5015 5032 repo.savecommitmessage('\n* * *\n'.join(msgs))
5016 5033 if dsguard:
5017 5034 dsguard.close()
5018 5035 return ret
5019 5036 finally:
5020 5037 if tr:
5021 5038 tr.release()
5022 5039 release(lock, dsguard, wlock)
5023 5040
5024 5041 @command('incoming|in',
5025 5042 [('f', 'force', None,
5026 5043 _('run even if remote repository is unrelated')),
5027 5044 ('n', 'newest-first', None, _('show newest record first')),
5028 5045 ('', 'bundle', '',
5029 5046 _('file to store the bundles into'), _('FILE')),
5030 5047 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5031 5048 ('B', 'bookmarks', False, _("compare bookmarks")),
5032 5049 ('b', 'branch', [],
5033 5050 _('a specific branch you would like to pull'), _('BRANCH')),
5034 5051 ] + logopts + remoteopts + subrepoopts,
5035 5052 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
5036 5053 def incoming(ui, repo, source="default", **opts):
5037 5054 """show new changesets found in source
5038 5055
5039 5056 Show new changesets found in the specified path/URL or the default
5040 5057 pull location. These are the changesets that would have been pulled
5041 5058 if a pull at the time you issued this command.
5042 5059
5043 5060 See pull for valid source format details.
5044 5061
5045 5062 .. container:: verbose
5046 5063
5047 5064 With -B/--bookmarks, the result of bookmark comparison between
5048 5065 local and remote repositories is displayed. With -v/--verbose,
5049 5066 status is also displayed for each bookmark like below::
5050 5067
5051 5068 BM1 01234567890a added
5052 5069 BM2 1234567890ab advanced
5053 5070 BM3 234567890abc diverged
5054 5071 BM4 34567890abcd changed
5055 5072
5056 5073 The action taken locally when pulling depends on the
5057 5074 status of each bookmark:
5058 5075
5059 5076 :``added``: pull will create it
5060 5077 :``advanced``: pull will update it
5061 5078 :``diverged``: pull will create a divergent bookmark
5062 5079 :``changed``: result depends on remote changesets
5063 5080
5064 5081 From the point of view of pulling behavior, bookmark
5065 5082 existing only in the remote repository are treated as ``added``,
5066 5083 even if it is in fact locally deleted.
5067 5084
5068 5085 .. container:: verbose
5069 5086
5070 5087 For remote repository, using --bundle avoids downloading the
5071 5088 changesets twice if the incoming is followed by a pull.
5072 5089
5073 5090 Examples:
5074 5091
5075 5092 - show incoming changes with patches and full description::
5076 5093
5077 5094 hg incoming -vp
5078 5095
5079 5096 - show incoming changes excluding merges, store a bundle::
5080 5097
5081 5098 hg in -vpM --bundle incoming.hg
5082 5099 hg pull incoming.hg
5083 5100
5084 5101 - briefly list changes inside a bundle::
5085 5102
5086 5103 hg in changes.hg -T "{desc|firstline}\\n"
5087 5104
5088 5105 Returns 0 if there are incoming changes, 1 otherwise.
5089 5106 """
5090 5107 if opts.get('graph'):
5091 5108 cmdutil.checkunsupportedgraphflags([], opts)
5092 5109 def display(other, chlist, displayer):
5093 5110 revdag = cmdutil.graphrevs(other, chlist, opts)
5094 5111 cmdutil.displaygraph(ui, repo, revdag, displayer,
5095 5112 graphmod.asciiedges)
5096 5113
5097 5114 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5098 5115 return 0
5099 5116
5100 5117 if opts.get('bundle') and opts.get('subrepos'):
5101 5118 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5102 5119
5103 5120 if opts.get('bookmarks'):
5104 5121 source, branches = hg.parseurl(ui.expandpath(source),
5105 5122 opts.get('branch'))
5106 5123 other = hg.peer(repo, opts, source)
5107 5124 if 'bookmarks' not in other.listkeys('namespaces'):
5108 5125 ui.warn(_("remote doesn't support bookmarks\n"))
5109 5126 return 0
5110 5127 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5111 5128 return bookmarks.incoming(ui, repo, other)
5112 5129
5113 5130 repo._subtoppath = ui.expandpath(source)
5114 5131 try:
5115 5132 return hg.incoming(ui, repo, source, opts)
5116 5133 finally:
5117 5134 del repo._subtoppath
5118 5135
5119 5136
5120 5137 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5121 5138 norepo=True)
5122 5139 def init(ui, dest=".", **opts):
5123 5140 """create a new repository in the given directory
5124 5141
5125 5142 Initialize a new repository in the given directory. If the given
5126 5143 directory does not exist, it will be created.
5127 5144
5128 5145 If no directory is given, the current directory is used.
5129 5146
5130 5147 It is possible to specify an ``ssh://`` URL as the destination.
5131 5148 See :hg:`help urls` for more information.
5132 5149
5133 5150 Returns 0 on success.
5134 5151 """
5135 5152 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5136 5153
5137 5154 @command('locate',
5138 5155 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5139 5156 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5140 5157 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5141 5158 ] + walkopts,
5142 5159 _('[OPTION]... [PATTERN]...'))
5143 5160 def locate(ui, repo, *pats, **opts):
5144 5161 """locate files matching specific patterns (DEPRECATED)
5145 5162
5146 5163 Print files under Mercurial control in the working directory whose
5147 5164 names match the given patterns.
5148 5165
5149 5166 By default, this command searches all directories in the working
5150 5167 directory. To search just the current directory and its
5151 5168 subdirectories, use "--include .".
5152 5169
5153 5170 If no patterns are given to match, this command prints the names
5154 5171 of all files under Mercurial control in the working directory.
5155 5172
5156 5173 If you want to feed the output of this command into the "xargs"
5157 5174 command, use the -0 option to both this command and "xargs". This
5158 5175 will avoid the problem of "xargs" treating single filenames that
5159 5176 contain whitespace as multiple filenames.
5160 5177
5161 5178 See :hg:`help files` for a more versatile command.
5162 5179
5163 5180 Returns 0 if a match is found, 1 otherwise.
5164 5181 """
5165 5182 if opts.get('print0'):
5166 5183 end = '\0'
5167 5184 else:
5168 5185 end = '\n'
5169 5186 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5170 5187
5171 5188 ret = 1
5172 5189 ctx = repo[rev]
5173 5190 m = scmutil.match(ctx, pats, opts, default='relglob',
5174 5191 badfn=lambda x, y: False)
5175 5192
5176 5193 for abs in ctx.matches(m):
5177 5194 if opts.get('fullpath'):
5178 5195 ui.write(repo.wjoin(abs), end)
5179 5196 else:
5180 5197 ui.write(((pats and m.rel(abs)) or abs), end)
5181 5198 ret = 0
5182 5199
5183 5200 return ret
5184 5201
5185 5202 @command('^log|history',
5186 5203 [('f', 'follow', None,
5187 5204 _('follow changeset history, or file history across copies and renames')),
5188 5205 ('', 'follow-first', None,
5189 5206 _('only follow the first parent of merge changesets (DEPRECATED)')),
5190 5207 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5191 5208 ('C', 'copies', None, _('show copied files')),
5192 5209 ('k', 'keyword', [],
5193 5210 _('do case-insensitive search for a given text'), _('TEXT')),
5194 5211 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5195 5212 ('', 'removed', None, _('include revisions where files were removed')),
5196 5213 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5197 5214 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5198 5215 ('', 'only-branch', [],
5199 5216 _('show only changesets within the given named branch (DEPRECATED)'),
5200 5217 _('BRANCH')),
5201 5218 ('b', 'branch', [],
5202 5219 _('show changesets within the given named branch'), _('BRANCH')),
5203 5220 ('P', 'prune', [],
5204 5221 _('do not display revision or any of its ancestors'), _('REV')),
5205 5222 ] + logopts + walkopts,
5206 5223 _('[OPTION]... [FILE]'),
5207 5224 inferrepo=True)
5208 5225 def log(ui, repo, *pats, **opts):
5209 5226 """show revision history of entire repository or files
5210 5227
5211 5228 Print the revision history of the specified files or the entire
5212 5229 project.
5213 5230
5214 5231 If no revision range is specified, the default is ``tip:0`` unless
5215 5232 --follow is set, in which case the working directory parent is
5216 5233 used as the starting revision.
5217 5234
5218 5235 File history is shown without following rename or copy history of
5219 5236 files. Use -f/--follow with a filename to follow history across
5220 5237 renames and copies. --follow without a filename will only show
5221 5238 ancestors or descendants of the starting revision.
5222 5239
5223 5240 By default this command prints revision number and changeset id,
5224 5241 tags, non-trivial parents, user, date and time, and a summary for
5225 5242 each commit. When the -v/--verbose switch is used, the list of
5226 5243 changed files and full commit message are shown.
5227 5244
5228 5245 With --graph the revisions are shown as an ASCII art DAG with the most
5229 5246 recent changeset at the top.
5230 5247 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5231 5248 and '+' represents a fork where the changeset from the lines below is a
5232 5249 parent of the 'o' merge on the same line.
5233 5250
5234 5251 .. note::
5235 5252
5236 5253 :hg:`log --patch` may generate unexpected diff output for merge
5237 5254 changesets, as it will only compare the merge changeset against
5238 5255 its first parent. Also, only files different from BOTH parents
5239 5256 will appear in files:.
5240 5257
5241 5258 .. note::
5242 5259
5243 5260 For performance reasons, :hg:`log FILE` may omit duplicate changes
5244 5261 made on branches and will not show removals or mode changes. To
5245 5262 see all such changes, use the --removed switch.
5246 5263
5247 5264 .. container:: verbose
5248 5265
5249 5266 Some examples:
5250 5267
5251 5268 - changesets with full descriptions and file lists::
5252 5269
5253 5270 hg log -v
5254 5271
5255 5272 - changesets ancestral to the working directory::
5256 5273
5257 5274 hg log -f
5258 5275
5259 5276 - last 10 commits on the current branch::
5260 5277
5261 5278 hg log -l 10 -b .
5262 5279
5263 5280 - changesets showing all modifications of a file, including removals::
5264 5281
5265 5282 hg log --removed file.c
5266 5283
5267 5284 - all changesets that touch a directory, with diffs, excluding merges::
5268 5285
5269 5286 hg log -Mp lib/
5270 5287
5271 5288 - all revision numbers that match a keyword::
5272 5289
5273 5290 hg log -k bug --template "{rev}\\n"
5274 5291
5275 5292 - the full hash identifier of the working directory parent::
5276 5293
5277 5294 hg log -r . --template "{node}\\n"
5278 5295
5279 5296 - list available log templates::
5280 5297
5281 5298 hg log -T list
5282 5299
5283 5300 - check if a given changeset is included in a tagged release::
5284 5301
5285 5302 hg log -r "a21ccf and ancestor(1.9)"
5286 5303
5287 5304 - find all changesets by some user in a date range::
5288 5305
5289 5306 hg log -k alice -d "may 2008 to jul 2008"
5290 5307
5291 5308 - summary of all changesets after the last tag::
5292 5309
5293 5310 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5294 5311
5295 5312 See :hg:`help dates` for a list of formats valid for -d/--date.
5296 5313
5297 5314 See :hg:`help revisions` and :hg:`help revsets` for more about
5298 5315 specifying and ordering revisions.
5299 5316
5300 5317 See :hg:`help templates` for more about pre-packaged styles and
5301 5318 specifying custom templates.
5302 5319
5303 5320 Returns 0 on success.
5304 5321
5305 5322 """
5306 5323 if opts.get('follow') and opts.get('rev'):
5307 5324 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5308 5325 del opts['follow']
5309 5326
5310 5327 if opts.get('graph'):
5311 5328 return cmdutil.graphlog(ui, repo, *pats, **opts)
5312 5329
5313 5330 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5314 5331 limit = cmdutil.loglimit(opts)
5315 5332 count = 0
5316 5333
5317 5334 getrenamed = None
5318 5335 if opts.get('copies'):
5319 5336 endrev = None
5320 5337 if opts.get('rev'):
5321 5338 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5322 5339 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5323 5340
5324 5341 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5325 5342 for rev in revs:
5326 5343 if count == limit:
5327 5344 break
5328 5345 ctx = repo[rev]
5329 5346 copies = None
5330 5347 if getrenamed is not None and rev:
5331 5348 copies = []
5332 5349 for fn in ctx.files():
5333 5350 rename = getrenamed(fn, rev)
5334 5351 if rename:
5335 5352 copies.append((fn, rename[0]))
5336 5353 if filematcher:
5337 5354 revmatchfn = filematcher(ctx.rev())
5338 5355 else:
5339 5356 revmatchfn = None
5340 5357 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5341 5358 if displayer.flush(ctx):
5342 5359 count += 1
5343 5360
5344 5361 displayer.close()
5345 5362
5346 5363 @command('manifest',
5347 5364 [('r', 'rev', '', _('revision to display'), _('REV')),
5348 5365 ('', 'all', False, _("list files from all revisions"))]
5349 5366 + formatteropts,
5350 5367 _('[-r REV]'))
5351 5368 def manifest(ui, repo, node=None, rev=None, **opts):
5352 5369 """output the current or given revision of the project manifest
5353 5370
5354 5371 Print a list of version controlled files for the given revision.
5355 5372 If no revision is given, the first parent of the working directory
5356 5373 is used, or the null revision if no revision is checked out.
5357 5374
5358 5375 With -v, print file permissions, symlink and executable bits.
5359 5376 With --debug, print file revision hashes.
5360 5377
5361 5378 If option --all is specified, the list of all files from all revisions
5362 5379 is printed. This includes deleted and renamed files.
5363 5380
5364 5381 Returns 0 on success.
5365 5382 """
5366 5383
5367 5384 fm = ui.formatter('manifest', opts)
5368 5385
5369 5386 if opts.get('all'):
5370 5387 if rev or node:
5371 5388 raise error.Abort(_("can't specify a revision with --all"))
5372 5389
5373 5390 res = []
5374 5391 prefix = "data/"
5375 5392 suffix = ".i"
5376 5393 plen = len(prefix)
5377 5394 slen = len(suffix)
5378 5395 with repo.lock():
5379 5396 for fn, b, size in repo.store.datafiles():
5380 5397 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5381 5398 res.append(fn[plen:-slen])
5382 5399 for f in res:
5383 5400 fm.startitem()
5384 5401 fm.write("path", '%s\n', f)
5385 5402 fm.end()
5386 5403 return
5387 5404
5388 5405 if rev and node:
5389 5406 raise error.Abort(_("please specify just one revision"))
5390 5407
5391 5408 if not node:
5392 5409 node = rev
5393 5410
5394 5411 char = {'l': '@', 'x': '*', '': ''}
5395 5412 mode = {'l': '644', 'x': '755', '': '644'}
5396 5413 ctx = scmutil.revsingle(repo, node)
5397 5414 mf = ctx.manifest()
5398 5415 for f in ctx:
5399 5416 fm.startitem()
5400 5417 fl = ctx[f].flags()
5401 5418 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5402 5419 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5403 5420 fm.write('path', '%s\n', f)
5404 5421 fm.end()
5405 5422
5406 5423 @command('^merge',
5407 5424 [('f', 'force', None,
5408 5425 _('force a merge including outstanding changes (DEPRECATED)')),
5409 5426 ('r', 'rev', '', _('revision to merge'), _('REV')),
5410 5427 ('P', 'preview', None,
5411 5428 _('review revisions to merge (no merge is performed)'))
5412 5429 ] + mergetoolopts,
5413 5430 _('[-P] [[-r] REV]'))
5414 5431 def merge(ui, repo, node=None, **opts):
5415 5432 """merge another revision into working directory
5416 5433
5417 5434 The current working directory is updated with all changes made in
5418 5435 the requested revision since the last common predecessor revision.
5419 5436
5420 5437 Files that changed between either parent are marked as changed for
5421 5438 the next commit and a commit must be performed before any further
5422 5439 updates to the repository are allowed. The next commit will have
5423 5440 two parents.
5424 5441
5425 5442 ``--tool`` can be used to specify the merge tool used for file
5426 5443 merges. It overrides the HGMERGE environment variable and your
5427 5444 configuration files. See :hg:`help merge-tools` for options.
5428 5445
5429 5446 If no revision is specified, the working directory's parent is a
5430 5447 head revision, and the current branch contains exactly one other
5431 5448 head, the other head is merged with by default. Otherwise, an
5432 5449 explicit revision with which to merge with must be provided.
5433 5450
5434 5451 See :hg:`help resolve` for information on handling file conflicts.
5435 5452
5436 5453 To undo an uncommitted merge, use :hg:`update --clean .` which
5437 5454 will check out a clean copy of the original merge parent, losing
5438 5455 all changes.
5439 5456
5440 5457 Returns 0 on success, 1 if there are unresolved files.
5441 5458 """
5442 5459
5443 5460 if opts.get('rev') and node:
5444 5461 raise error.Abort(_("please specify just one revision"))
5445 5462 if not node:
5446 5463 node = opts.get('rev')
5447 5464
5448 5465 if node:
5449 5466 node = scmutil.revsingle(repo, node).node()
5450 5467
5451 5468 if not node:
5452 5469 node = repo[destutil.destmerge(repo)].node()
5453 5470
5454 5471 if opts.get('preview'):
5455 5472 # find nodes that are ancestors of p2 but not of p1
5456 5473 p1 = repo.lookup('.')
5457 5474 p2 = repo.lookup(node)
5458 5475 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5459 5476
5460 5477 displayer = cmdutil.show_changeset(ui, repo, opts)
5461 5478 for node in nodes:
5462 5479 displayer.show(repo[node])
5463 5480 displayer.close()
5464 5481 return 0
5465 5482
5466 5483 try:
5467 5484 # ui.forcemerge is an internal variable, do not document
5468 5485 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5469 5486 force = opts.get('force')
5470 5487 return hg.merge(repo, node, force=force, mergeforce=force)
5471 5488 finally:
5472 5489 ui.setconfig('ui', 'forcemerge', '', 'merge')
5473 5490
5474 5491 @command('outgoing|out',
5475 5492 [('f', 'force', None, _('run even when the destination is unrelated')),
5476 5493 ('r', 'rev', [],
5477 5494 _('a changeset intended to be included in the destination'), _('REV')),
5478 5495 ('n', 'newest-first', None, _('show newest record first')),
5479 5496 ('B', 'bookmarks', False, _('compare bookmarks')),
5480 5497 ('b', 'branch', [], _('a specific branch you would like to push'),
5481 5498 _('BRANCH')),
5482 5499 ] + logopts + remoteopts + subrepoopts,
5483 5500 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5484 5501 def outgoing(ui, repo, dest=None, **opts):
5485 5502 """show changesets not found in the destination
5486 5503
5487 5504 Show changesets not found in the specified destination repository
5488 5505 or the default push location. These are the changesets that would
5489 5506 be pushed if a push was requested.
5490 5507
5491 5508 See pull for details of valid destination formats.
5492 5509
5493 5510 .. container:: verbose
5494 5511
5495 5512 With -B/--bookmarks, the result of bookmark comparison between
5496 5513 local and remote repositories is displayed. With -v/--verbose,
5497 5514 status is also displayed for each bookmark like below::
5498 5515
5499 5516 BM1 01234567890a added
5500 5517 BM2 deleted
5501 5518 BM3 234567890abc advanced
5502 5519 BM4 34567890abcd diverged
5503 5520 BM5 4567890abcde changed
5504 5521
5505 5522 The action taken when pushing depends on the
5506 5523 status of each bookmark:
5507 5524
5508 5525 :``added``: push with ``-B`` will create it
5509 5526 :``deleted``: push with ``-B`` will delete it
5510 5527 :``advanced``: push will update it
5511 5528 :``diverged``: push with ``-B`` will update it
5512 5529 :``changed``: push with ``-B`` will update it
5513 5530
5514 5531 From the point of view of pushing behavior, bookmarks
5515 5532 existing only in the remote repository are treated as
5516 5533 ``deleted``, even if it is in fact added remotely.
5517 5534
5518 5535 Returns 0 if there are outgoing changes, 1 otherwise.
5519 5536 """
5520 5537 if opts.get('graph'):
5521 5538 cmdutil.checkunsupportedgraphflags([], opts)
5522 5539 o, other = hg._outgoing(ui, repo, dest, opts)
5523 5540 if not o:
5524 5541 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5525 5542 return
5526 5543
5527 5544 revdag = cmdutil.graphrevs(repo, o, opts)
5528 5545 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5529 5546 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5530 5547 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5531 5548 return 0
5532 5549
5533 5550 if opts.get('bookmarks'):
5534 5551 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5535 5552 dest, branches = hg.parseurl(dest, opts.get('branch'))
5536 5553 other = hg.peer(repo, opts, dest)
5537 5554 if 'bookmarks' not in other.listkeys('namespaces'):
5538 5555 ui.warn(_("remote doesn't support bookmarks\n"))
5539 5556 return 0
5540 5557 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5541 5558 return bookmarks.outgoing(ui, repo, other)
5542 5559
5543 5560 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5544 5561 try:
5545 5562 return hg.outgoing(ui, repo, dest, opts)
5546 5563 finally:
5547 5564 del repo._subtoppath
5548 5565
5549 5566 @command('parents',
5550 5567 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5551 5568 ] + templateopts,
5552 5569 _('[-r REV] [FILE]'),
5553 5570 inferrepo=True)
5554 5571 def parents(ui, repo, file_=None, **opts):
5555 5572 """show the parents of the working directory or revision (DEPRECATED)
5556 5573
5557 5574 Print the working directory's parent revisions. If a revision is
5558 5575 given via -r/--rev, the parent of that revision will be printed.
5559 5576 If a file argument is given, the revision in which the file was
5560 5577 last changed (before the working directory revision or the
5561 5578 argument to --rev if given) is printed.
5562 5579
5563 5580 This command is equivalent to::
5564 5581
5565 5582 hg log -r "p1()+p2()" or
5566 5583 hg log -r "p1(REV)+p2(REV)" or
5567 5584 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5568 5585 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5569 5586
5570 5587 See :hg:`summary` and :hg:`help revsets` for related information.
5571 5588
5572 5589 Returns 0 on success.
5573 5590 """
5574 5591
5575 5592 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5576 5593
5577 5594 if file_:
5578 5595 m = scmutil.match(ctx, (file_,), opts)
5579 5596 if m.anypats() or len(m.files()) != 1:
5580 5597 raise error.Abort(_('can only specify an explicit filename'))
5581 5598 file_ = m.files()[0]
5582 5599 filenodes = []
5583 5600 for cp in ctx.parents():
5584 5601 if not cp:
5585 5602 continue
5586 5603 try:
5587 5604 filenodes.append(cp.filenode(file_))
5588 5605 except error.LookupError:
5589 5606 pass
5590 5607 if not filenodes:
5591 5608 raise error.Abort(_("'%s' not found in manifest!") % file_)
5592 5609 p = []
5593 5610 for fn in filenodes:
5594 5611 fctx = repo.filectx(file_, fileid=fn)
5595 5612 p.append(fctx.node())
5596 5613 else:
5597 5614 p = [cp.node() for cp in ctx.parents()]
5598 5615
5599 5616 displayer = cmdutil.show_changeset(ui, repo, opts)
5600 5617 for n in p:
5601 5618 if n != nullid:
5602 5619 displayer.show(repo[n])
5603 5620 displayer.close()
5604 5621
5605 5622 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5606 5623 def paths(ui, repo, search=None, **opts):
5607 5624 """show aliases for remote repositories
5608 5625
5609 5626 Show definition of symbolic path name NAME. If no name is given,
5610 5627 show definition of all available names.
5611 5628
5612 5629 Option -q/--quiet suppresses all output when searching for NAME
5613 5630 and shows only the path names when listing all definitions.
5614 5631
5615 5632 Path names are defined in the [paths] section of your
5616 5633 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5617 5634 repository, ``.hg/hgrc`` is used, too.
5618 5635
5619 5636 The path names ``default`` and ``default-push`` have a special
5620 5637 meaning. When performing a push or pull operation, they are used
5621 5638 as fallbacks if no location is specified on the command-line.
5622 5639 When ``default-push`` is set, it will be used for push and
5623 5640 ``default`` will be used for pull; otherwise ``default`` is used
5624 5641 as the fallback for both. When cloning a repository, the clone
5625 5642 source is written as ``default`` in ``.hg/hgrc``.
5626 5643
5627 5644 .. note::
5628 5645
5629 5646 ``default`` and ``default-push`` apply to all inbound (e.g.
5630 5647 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5631 5648 and :hg:`bundle`) operations.
5632 5649
5633 5650 See :hg:`help urls` for more information.
5634 5651
5635 5652 Returns 0 on success.
5636 5653 """
5637 5654 if search:
5638 5655 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5639 5656 if name == search]
5640 5657 else:
5641 5658 pathitems = sorted(ui.paths.iteritems())
5642 5659
5643 5660 fm = ui.formatter('paths', opts)
5644 5661 if fm:
5645 5662 hidepassword = str
5646 5663 else:
5647 5664 hidepassword = util.hidepassword
5648 5665 if ui.quiet:
5649 5666 namefmt = '%s\n'
5650 5667 else:
5651 5668 namefmt = '%s = '
5652 5669 showsubopts = not search and not ui.quiet
5653 5670
5654 5671 for name, path in pathitems:
5655 5672 fm.startitem()
5656 5673 fm.condwrite(not search, 'name', namefmt, name)
5657 5674 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5658 5675 for subopt, value in sorted(path.suboptions.items()):
5659 5676 assert subopt not in ('name', 'url')
5660 5677 if showsubopts:
5661 5678 fm.plain('%s:%s = ' % (name, subopt))
5662 5679 fm.condwrite(showsubopts, subopt, '%s\n', value)
5663 5680
5664 5681 fm.end()
5665 5682
5666 5683 if search and not pathitems:
5667 5684 if not ui.quiet:
5668 5685 ui.warn(_("not found!\n"))
5669 5686 return 1
5670 5687 else:
5671 5688 return 0
5672 5689
5673 5690 @command('phase',
5674 5691 [('p', 'public', False, _('set changeset phase to public')),
5675 5692 ('d', 'draft', False, _('set changeset phase to draft')),
5676 5693 ('s', 'secret', False, _('set changeset phase to secret')),
5677 5694 ('f', 'force', False, _('allow to move boundary backward')),
5678 5695 ('r', 'rev', [], _('target revision'), _('REV')),
5679 5696 ],
5680 5697 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5681 5698 def phase(ui, repo, *revs, **opts):
5682 5699 """set or show the current phase name
5683 5700
5684 5701 With no argument, show the phase name of the current revision(s).
5685 5702
5686 5703 With one of -p/--public, -d/--draft or -s/--secret, change the
5687 5704 phase value of the specified revisions.
5688 5705
5689 5706 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5690 5707 lower phase to an higher phase. Phases are ordered as follows::
5691 5708
5692 5709 public < draft < secret
5693 5710
5694 5711 Returns 0 on success, 1 if some phases could not be changed.
5695 5712
5696 5713 (For more information about the phases concept, see :hg:`help phases`.)
5697 5714 """
5698 5715 # search for a unique phase argument
5699 5716 targetphase = None
5700 5717 for idx, name in enumerate(phases.phasenames):
5701 5718 if opts[name]:
5702 5719 if targetphase is not None:
5703 5720 raise error.Abort(_('only one phase can be specified'))
5704 5721 targetphase = idx
5705 5722
5706 5723 # look for specified revision
5707 5724 revs = list(revs)
5708 5725 revs.extend(opts['rev'])
5709 5726 if not revs:
5710 5727 # display both parents as the second parent phase can influence
5711 5728 # the phase of a merge commit
5712 5729 revs = [c.rev() for c in repo[None].parents()]
5713 5730
5714 5731 revs = scmutil.revrange(repo, revs)
5715 5732
5716 5733 lock = None
5717 5734 ret = 0
5718 5735 if targetphase is None:
5719 5736 # display
5720 5737 for r in revs:
5721 5738 ctx = repo[r]
5722 5739 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5723 5740 else:
5724 5741 tr = None
5725 5742 lock = repo.lock()
5726 5743 try:
5727 5744 tr = repo.transaction("phase")
5728 5745 # set phase
5729 5746 if not revs:
5730 5747 raise error.Abort(_('empty revision set'))
5731 5748 nodes = [repo[r].node() for r in revs]
5732 5749 # moving revision from public to draft may hide them
5733 5750 # We have to check result on an unfiltered repository
5734 5751 unfi = repo.unfiltered()
5735 5752 getphase = unfi._phasecache.phase
5736 5753 olddata = [getphase(unfi, r) for r in unfi]
5737 5754 phases.advanceboundary(repo, tr, targetphase, nodes)
5738 5755 if opts['force']:
5739 5756 phases.retractboundary(repo, tr, targetphase, nodes)
5740 5757 tr.close()
5741 5758 finally:
5742 5759 if tr is not None:
5743 5760 tr.release()
5744 5761 lock.release()
5745 5762 getphase = unfi._phasecache.phase
5746 5763 newdata = [getphase(unfi, r) for r in unfi]
5747 5764 changes = sum(newdata[r] != olddata[r] for r in unfi)
5748 5765 cl = unfi.changelog
5749 5766 rejected = [n for n in nodes
5750 5767 if newdata[cl.rev(n)] < targetphase]
5751 5768 if rejected:
5752 5769 ui.warn(_('cannot move %i changesets to a higher '
5753 5770 'phase, use --force\n') % len(rejected))
5754 5771 ret = 1
5755 5772 if changes:
5756 5773 msg = _('phase changed for %i changesets\n') % changes
5757 5774 if ret:
5758 5775 ui.status(msg)
5759 5776 else:
5760 5777 ui.note(msg)
5761 5778 else:
5762 5779 ui.warn(_('no phases changed\n'))
5763 5780 return ret
5764 5781
5765 5782 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5766 5783 """Run after a changegroup has been added via pull/unbundle
5767 5784
5768 5785 This takes arguments below:
5769 5786
5770 5787 :modheads: change of heads by pull/unbundle
5771 5788 :optupdate: updating working directory is needed or not
5772 5789 :checkout: update destination revision (or None to default destination)
5773 5790 :brev: a name, which might be a bookmark to be activated after updating
5774 5791 """
5775 5792 if modheads == 0:
5776 5793 return
5777 5794 if optupdate:
5778 5795 try:
5779 5796 return hg.updatetotally(ui, repo, checkout, brev)
5780 5797 except error.UpdateAbort as inst:
5781 5798 msg = _("not updating: %s") % str(inst)
5782 5799 hint = inst.hint
5783 5800 raise error.UpdateAbort(msg, hint=hint)
5784 5801 if modheads > 1:
5785 5802 currentbranchheads = len(repo.branchheads())
5786 5803 if currentbranchheads == modheads:
5787 5804 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5788 5805 elif currentbranchheads > 1:
5789 5806 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5790 5807 "merge)\n"))
5791 5808 else:
5792 5809 ui.status(_("(run 'hg heads' to see heads)\n"))
5793 5810 else:
5794 5811 ui.status(_("(run 'hg update' to get a working copy)\n"))
5795 5812
5796 5813 @command('^pull',
5797 5814 [('u', 'update', None,
5798 5815 _('update to new branch head if changesets were pulled')),
5799 5816 ('f', 'force', None, _('run even when remote repository is unrelated')),
5800 5817 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5801 5818 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5802 5819 ('b', 'branch', [], _('a specific branch you would like to pull'),
5803 5820 _('BRANCH')),
5804 5821 ] + remoteopts,
5805 5822 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5806 5823 def pull(ui, repo, source="default", **opts):
5807 5824 """pull changes from the specified source
5808 5825
5809 5826 Pull changes from a remote repository to a local one.
5810 5827
5811 5828 This finds all changes from the repository at the specified path
5812 5829 or URL and adds them to a local repository (the current one unless
5813 5830 -R is specified). By default, this does not update the copy of the
5814 5831 project in the working directory.
5815 5832
5816 5833 Use :hg:`incoming` if you want to see what would have been added
5817 5834 by a pull at the time you issued this command. If you then decide
5818 5835 to add those changes to the repository, you should use :hg:`pull
5819 5836 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5820 5837
5821 5838 If SOURCE is omitted, the 'default' path will be used.
5822 5839 See :hg:`help urls` for more information.
5823 5840
5824 5841 Specifying bookmark as ``.`` is equivalent to specifying the active
5825 5842 bookmark's name.
5826 5843
5827 5844 Returns 0 on success, 1 if an update had unresolved files.
5828 5845 """
5829 5846 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5830 5847 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5831 5848 other = hg.peer(repo, opts, source)
5832 5849 try:
5833 5850 revs, checkout = hg.addbranchrevs(repo, other, branches,
5834 5851 opts.get('rev'))
5835 5852
5836 5853
5837 5854 pullopargs = {}
5838 5855 if opts.get('bookmark'):
5839 5856 if not revs:
5840 5857 revs = []
5841 5858 # The list of bookmark used here is not the one used to actually
5842 5859 # update the bookmark name. This can result in the revision pulled
5843 5860 # not ending up with the name of the bookmark because of a race
5844 5861 # condition on the server. (See issue 4689 for details)
5845 5862 remotebookmarks = other.listkeys('bookmarks')
5846 5863 pullopargs['remotebookmarks'] = remotebookmarks
5847 5864 for b in opts['bookmark']:
5848 5865 b = repo._bookmarks.expandname(b)
5849 5866 if b not in remotebookmarks:
5850 5867 raise error.Abort(_('remote bookmark %s not found!') % b)
5851 5868 revs.append(remotebookmarks[b])
5852 5869
5853 5870 if revs:
5854 5871 try:
5855 5872 # When 'rev' is a bookmark name, we cannot guarantee that it
5856 5873 # will be updated with that name because of a race condition
5857 5874 # server side. (See issue 4689 for details)
5858 5875 oldrevs = revs
5859 5876 revs = [] # actually, nodes
5860 5877 for r in oldrevs:
5861 5878 node = other.lookup(r)
5862 5879 revs.append(node)
5863 5880 if r == checkout:
5864 5881 checkout = node
5865 5882 except error.CapabilityError:
5866 5883 err = _("other repository doesn't support revision lookup, "
5867 5884 "so a rev cannot be specified.")
5868 5885 raise error.Abort(err)
5869 5886
5870 5887 pullopargs.update(opts.get('opargs', {}))
5871 5888 modheads = exchange.pull(repo, other, heads=revs,
5872 5889 force=opts.get('force'),
5873 5890 bookmarks=opts.get('bookmark', ()),
5874 5891 opargs=pullopargs).cgresult
5875 5892
5876 5893 # brev is a name, which might be a bookmark to be activated at
5877 5894 # the end of the update. In other words, it is an explicit
5878 5895 # destination of the update
5879 5896 brev = None
5880 5897
5881 5898 if checkout:
5882 5899 checkout = str(repo.changelog.rev(checkout))
5883 5900
5884 5901 # order below depends on implementation of
5885 5902 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5886 5903 # because 'checkout' is determined without it.
5887 5904 if opts.get('rev'):
5888 5905 brev = opts['rev'][0]
5889 5906 elif opts.get('branch'):
5890 5907 brev = opts['branch'][0]
5891 5908 else:
5892 5909 brev = branches[0]
5893 5910 repo._subtoppath = source
5894 5911 try:
5895 5912 ret = postincoming(ui, repo, modheads, opts.get('update'),
5896 5913 checkout, brev)
5897 5914
5898 5915 finally:
5899 5916 del repo._subtoppath
5900 5917
5901 5918 finally:
5902 5919 other.close()
5903 5920 return ret
5904 5921
5905 5922 @command('^push',
5906 5923 [('f', 'force', None, _('force push')),
5907 5924 ('r', 'rev', [],
5908 5925 _('a changeset intended to be included in the destination'),
5909 5926 _('REV')),
5910 5927 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5911 5928 ('b', 'branch', [],
5912 5929 _('a specific branch you would like to push'), _('BRANCH')),
5913 5930 ('', 'new-branch', False, _('allow pushing a new branch')),
5914 5931 ] + remoteopts,
5915 5932 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5916 5933 def push(ui, repo, dest=None, **opts):
5917 5934 """push changes to the specified destination
5918 5935
5919 5936 Push changesets from the local repository to the specified
5920 5937 destination.
5921 5938
5922 5939 This operation is symmetrical to pull: it is identical to a pull
5923 5940 in the destination repository from the current one.
5924 5941
5925 5942 By default, push will not allow creation of new heads at the
5926 5943 destination, since multiple heads would make it unclear which head
5927 5944 to use. In this situation, it is recommended to pull and merge
5928 5945 before pushing.
5929 5946
5930 5947 Use --new-branch if you want to allow push to create a new named
5931 5948 branch that is not present at the destination. This allows you to
5932 5949 only create a new branch without forcing other changes.
5933 5950
5934 5951 .. note::
5935 5952
5936 5953 Extra care should be taken with the -f/--force option,
5937 5954 which will push all new heads on all branches, an action which will
5938 5955 almost always cause confusion for collaborators.
5939 5956
5940 5957 If -r/--rev is used, the specified revision and all its ancestors
5941 5958 will be pushed to the remote repository.
5942 5959
5943 5960 If -B/--bookmark is used, the specified bookmarked revision, its
5944 5961 ancestors, and the bookmark will be pushed to the remote
5945 5962 repository. Specifying ``.`` is equivalent to specifying the active
5946 5963 bookmark's name.
5947 5964
5948 5965 Please see :hg:`help urls` for important details about ``ssh://``
5949 5966 URLs. If DESTINATION is omitted, a default path will be used.
5950 5967
5951 5968 Returns 0 if push was successful, 1 if nothing to push.
5952 5969 """
5953 5970
5954 5971 if opts.get('bookmark'):
5955 5972 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5956 5973 for b in opts['bookmark']:
5957 5974 # translate -B options to -r so changesets get pushed
5958 5975 b = repo._bookmarks.expandname(b)
5959 5976 if b in repo._bookmarks:
5960 5977 opts.setdefault('rev', []).append(b)
5961 5978 else:
5962 5979 # if we try to push a deleted bookmark, translate it to null
5963 5980 # this lets simultaneous -r, -b options continue working
5964 5981 opts.setdefault('rev', []).append("null")
5965 5982
5966 5983 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5967 5984 if not path:
5968 5985 raise error.Abort(_('default repository not configured!'),
5969 5986 hint=_('see the "path" section in "hg help config"'))
5970 5987 dest = path.pushloc or path.loc
5971 5988 branches = (path.branch, opts.get('branch') or [])
5972 5989 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5973 5990 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5974 5991 other = hg.peer(repo, opts, dest)
5975 5992
5976 5993 if revs:
5977 5994 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5978 5995 if not revs:
5979 5996 raise error.Abort(_("specified revisions evaluate to an empty set"),
5980 5997 hint=_("use different revision arguments"))
5981 5998 elif path.pushrev:
5982 5999 # It doesn't make any sense to specify ancestor revisions. So limit
5983 6000 # to DAG heads to make discovery simpler.
5984 6001 expr = revset.formatspec('heads(%r)', path.pushrev)
5985 6002 revs = scmutil.revrange(repo, [expr])
5986 6003 revs = [repo[rev].node() for rev in revs]
5987 6004 if not revs:
5988 6005 raise error.Abort(_('default push revset for path evaluates to an '
5989 6006 'empty set'))
5990 6007
5991 6008 repo._subtoppath = dest
5992 6009 try:
5993 6010 # push subrepos depth-first for coherent ordering
5994 6011 c = repo['']
5995 6012 subs = c.substate # only repos that are committed
5996 6013 for s in sorted(subs):
5997 6014 result = c.sub(s).push(opts)
5998 6015 if result == 0:
5999 6016 return not result
6000 6017 finally:
6001 6018 del repo._subtoppath
6002 6019 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
6003 6020 newbranch=opts.get('new_branch'),
6004 6021 bookmarks=opts.get('bookmark', ()),
6005 6022 opargs=opts.get('opargs'))
6006 6023
6007 6024 result = not pushop.cgresult
6008 6025
6009 6026 if pushop.bkresult is not None:
6010 6027 if pushop.bkresult == 2:
6011 6028 result = 2
6012 6029 elif not result and pushop.bkresult:
6013 6030 result = 2
6014 6031
6015 6032 return result
6016 6033
6017 6034 @command('recover', [])
6018 6035 def recover(ui, repo):
6019 6036 """roll back an interrupted transaction
6020 6037
6021 6038 Recover from an interrupted commit or pull.
6022 6039
6023 6040 This command tries to fix the repository status after an
6024 6041 interrupted operation. It should only be necessary when Mercurial
6025 6042 suggests it.
6026 6043
6027 6044 Returns 0 if successful, 1 if nothing to recover or verify fails.
6028 6045 """
6029 6046 if repo.recover():
6030 6047 return hg.verify(repo)
6031 6048 return 1
6032 6049
6033 6050 @command('^remove|rm',
6034 6051 [('A', 'after', None, _('record delete for missing files')),
6035 6052 ('f', 'force', None,
6036 6053 _('forget added files, delete modified files')),
6037 6054 ] + subrepoopts + walkopts,
6038 6055 _('[OPTION]... FILE...'),
6039 6056 inferrepo=True)
6040 6057 def remove(ui, repo, *pats, **opts):
6041 6058 """remove the specified files on the next commit
6042 6059
6043 6060 Schedule the indicated files for removal from the current branch.
6044 6061
6045 6062 This command schedules the files to be removed at the next commit.
6046 6063 To undo a remove before that, see :hg:`revert`. To undo added
6047 6064 files, see :hg:`forget`.
6048 6065
6049 6066 .. container:: verbose
6050 6067
6051 6068 -A/--after can be used to remove only files that have already
6052 6069 been deleted, -f/--force can be used to force deletion, and -Af
6053 6070 can be used to remove files from the next revision without
6054 6071 deleting them from the working directory.
6055 6072
6056 6073 The following table details the behavior of remove for different
6057 6074 file states (columns) and option combinations (rows). The file
6058 6075 states are Added [A], Clean [C], Modified [M] and Missing [!]
6059 6076 (as reported by :hg:`status`). The actions are Warn, Remove
6060 6077 (from branch) and Delete (from disk):
6061 6078
6062 6079 ========= == == == ==
6063 6080 opt/state A C M !
6064 6081 ========= == == == ==
6065 6082 none W RD W R
6066 6083 -f R RD RD R
6067 6084 -A W W W R
6068 6085 -Af R R R R
6069 6086 ========= == == == ==
6070 6087
6071 6088 .. note::
6072 6089
6073 6090 :hg:`remove` never deletes files in Added [A] state from the
6074 6091 working directory, not even if ``--force`` is specified.
6075 6092
6076 6093 Returns 0 on success, 1 if any warnings encountered.
6077 6094 """
6078 6095
6079 6096 after, force = opts.get('after'), opts.get('force')
6080 6097 if not pats and not after:
6081 6098 raise error.Abort(_('no files specified'))
6082 6099
6083 6100 m = scmutil.match(repo[None], pats, opts)
6084 6101 subrepos = opts.get('subrepos')
6085 6102 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
6086 6103
6087 6104 @command('rename|move|mv',
6088 6105 [('A', 'after', None, _('record a rename that has already occurred')),
6089 6106 ('f', 'force', None, _('forcibly copy over an existing managed file')),
6090 6107 ] + walkopts + dryrunopts,
6091 6108 _('[OPTION]... SOURCE... DEST'))
6092 6109 def rename(ui, repo, *pats, **opts):
6093 6110 """rename files; equivalent of copy + remove
6094 6111
6095 6112 Mark dest as copies of sources; mark sources for deletion. If dest
6096 6113 is a directory, copies are put in that directory. If dest is a
6097 6114 file, there can only be one source.
6098 6115
6099 6116 By default, this command copies the contents of files as they
6100 6117 exist in the working directory. If invoked with -A/--after, the
6101 6118 operation is recorded, but no copying is performed.
6102 6119
6103 6120 This command takes effect at the next commit. To undo a rename
6104 6121 before that, see :hg:`revert`.
6105 6122
6106 6123 Returns 0 on success, 1 if errors are encountered.
6107 6124 """
6108 6125 with repo.wlock(False):
6109 6126 return cmdutil.copy(ui, repo, pats, opts, rename=True)
6110 6127
6111 6128 @command('resolve',
6112 6129 [('a', 'all', None, _('select all unresolved files')),
6113 6130 ('l', 'list', None, _('list state of files needing merge')),
6114 6131 ('m', 'mark', None, _('mark files as resolved')),
6115 6132 ('u', 'unmark', None, _('mark files as unresolved')),
6116 6133 ('n', 'no-status', None, _('hide status prefix'))]
6117 6134 + mergetoolopts + walkopts + formatteropts,
6118 6135 _('[OPTION]... [FILE]...'),
6119 6136 inferrepo=True)
6120 6137 def resolve(ui, repo, *pats, **opts):
6121 6138 """redo merges or set/view the merge status of files
6122 6139
6123 6140 Merges with unresolved conflicts are often the result of
6124 6141 non-interactive merging using the ``internal:merge`` configuration
6125 6142 setting, or a command-line merge tool like ``diff3``. The resolve
6126 6143 command is used to manage the files involved in a merge, after
6127 6144 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6128 6145 working directory must have two parents). See :hg:`help
6129 6146 merge-tools` for information on configuring merge tools.
6130 6147
6131 6148 The resolve command can be used in the following ways:
6132 6149
6133 6150 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6134 6151 files, discarding any previous merge attempts. Re-merging is not
6135 6152 performed for files already marked as resolved. Use ``--all/-a``
6136 6153 to select all unresolved files. ``--tool`` can be used to specify
6137 6154 the merge tool used for the given files. It overrides the HGMERGE
6138 6155 environment variable and your configuration files. Previous file
6139 6156 contents are saved with a ``.orig`` suffix.
6140 6157
6141 6158 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6142 6159 (e.g. after having manually fixed-up the files). The default is
6143 6160 to mark all unresolved files.
6144 6161
6145 6162 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6146 6163 default is to mark all resolved files.
6147 6164
6148 6165 - :hg:`resolve -l`: list files which had or still have conflicts.
6149 6166 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6150 6167
6151 6168 .. note::
6152 6169
6153 6170 Mercurial will not let you commit files with unresolved merge
6154 6171 conflicts. You must use :hg:`resolve -m ...` before you can
6155 6172 commit after a conflicting merge.
6156 6173
6157 6174 Returns 0 on success, 1 if any files fail a resolve attempt.
6158 6175 """
6159 6176
6160 6177 flaglist = 'all mark unmark list no_status'.split()
6161 6178 all, mark, unmark, show, nostatus = \
6162 6179 [opts.get(o) for o in flaglist]
6163 6180
6164 6181 if (show and (mark or unmark)) or (mark and unmark):
6165 6182 raise error.Abort(_("too many options specified"))
6166 6183 if pats and all:
6167 6184 raise error.Abort(_("can't specify --all and patterns"))
6168 6185 if not (all or pats or show or mark or unmark):
6169 6186 raise error.Abort(_('no files or directories specified'),
6170 6187 hint=('use --all to re-merge all unresolved files'))
6171 6188
6172 6189 if show:
6173 6190 fm = ui.formatter('resolve', opts)
6174 6191 ms = mergemod.mergestate.read(repo)
6175 6192 m = scmutil.match(repo[None], pats, opts)
6176 6193 for f in ms:
6177 6194 if not m(f):
6178 6195 continue
6179 6196 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6180 6197 'd': 'driverresolved'}[ms[f]]
6181 6198 fm.startitem()
6182 6199 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6183 6200 fm.write('path', '%s\n', f, label=l)
6184 6201 fm.end()
6185 6202 return 0
6186 6203
6187 6204 with repo.wlock():
6188 6205 ms = mergemod.mergestate.read(repo)
6189 6206
6190 6207 if not (ms.active() or repo.dirstate.p2() != nullid):
6191 6208 raise error.Abort(
6192 6209 _('resolve command not applicable when not merging'))
6193 6210
6194 6211 wctx = repo[None]
6195 6212
6196 6213 if ms.mergedriver and ms.mdstate() == 'u':
6197 6214 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6198 6215 ms.commit()
6199 6216 # allow mark and unmark to go through
6200 6217 if not mark and not unmark and not proceed:
6201 6218 return 1
6202 6219
6203 6220 m = scmutil.match(wctx, pats, opts)
6204 6221 ret = 0
6205 6222 didwork = False
6206 6223 runconclude = False
6207 6224
6208 6225 tocomplete = []
6209 6226 for f in ms:
6210 6227 if not m(f):
6211 6228 continue
6212 6229
6213 6230 didwork = True
6214 6231
6215 6232 # don't let driver-resolved files be marked, and run the conclude
6216 6233 # step if asked to resolve
6217 6234 if ms[f] == "d":
6218 6235 exact = m.exact(f)
6219 6236 if mark:
6220 6237 if exact:
6221 6238 ui.warn(_('not marking %s as it is driver-resolved\n')
6222 6239 % f)
6223 6240 elif unmark:
6224 6241 if exact:
6225 6242 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6226 6243 % f)
6227 6244 else:
6228 6245 runconclude = True
6229 6246 continue
6230 6247
6231 6248 if mark:
6232 6249 ms.mark(f, "r")
6233 6250 elif unmark:
6234 6251 ms.mark(f, "u")
6235 6252 else:
6236 6253 # backup pre-resolve (merge uses .orig for its own purposes)
6237 6254 a = repo.wjoin(f)
6238 6255 try:
6239 6256 util.copyfile(a, a + ".resolve")
6240 6257 except (IOError, OSError) as inst:
6241 6258 if inst.errno != errno.ENOENT:
6242 6259 raise
6243 6260
6244 6261 try:
6245 6262 # preresolve file
6246 6263 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6247 6264 'resolve')
6248 6265 complete, r = ms.preresolve(f, wctx)
6249 6266 if not complete:
6250 6267 tocomplete.append(f)
6251 6268 elif r:
6252 6269 ret = 1
6253 6270 finally:
6254 6271 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6255 6272 ms.commit()
6256 6273
6257 6274 # replace filemerge's .orig file with our resolve file, but only
6258 6275 # for merges that are complete
6259 6276 if complete:
6260 6277 try:
6261 6278 util.rename(a + ".resolve",
6262 6279 scmutil.origpath(ui, repo, a))
6263 6280 except OSError as inst:
6264 6281 if inst.errno != errno.ENOENT:
6265 6282 raise
6266 6283
6267 6284 for f in tocomplete:
6268 6285 try:
6269 6286 # resolve file
6270 6287 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6271 6288 'resolve')
6272 6289 r = ms.resolve(f, wctx)
6273 6290 if r:
6274 6291 ret = 1
6275 6292 finally:
6276 6293 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6277 6294 ms.commit()
6278 6295
6279 6296 # replace filemerge's .orig file with our resolve file
6280 6297 a = repo.wjoin(f)
6281 6298 try:
6282 6299 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6283 6300 except OSError as inst:
6284 6301 if inst.errno != errno.ENOENT:
6285 6302 raise
6286 6303
6287 6304 ms.commit()
6288 6305 ms.recordactions()
6289 6306
6290 6307 if not didwork and pats:
6291 6308 hint = None
6292 6309 if not any([p for p in pats if p.find(':') >= 0]):
6293 6310 pats = ['path:%s' % p for p in pats]
6294 6311 m = scmutil.match(wctx, pats, opts)
6295 6312 for f in ms:
6296 6313 if not m(f):
6297 6314 continue
6298 6315 flags = ''.join(['-%s ' % o[0] for o in flaglist
6299 6316 if opts.get(o)])
6300 6317 hint = _("(try: hg resolve %s%s)\n") % (
6301 6318 flags,
6302 6319 ' '.join(pats))
6303 6320 break
6304 6321 ui.warn(_("arguments do not match paths that need resolving\n"))
6305 6322 if hint:
6306 6323 ui.warn(hint)
6307 6324 elif ms.mergedriver and ms.mdstate() != 's':
6308 6325 # run conclude step when either a driver-resolved file is requested
6309 6326 # or there are no driver-resolved files
6310 6327 # we can't use 'ret' to determine whether any files are unresolved
6311 6328 # because we might not have tried to resolve some
6312 6329 if ((runconclude or not list(ms.driverresolved()))
6313 6330 and not list(ms.unresolved())):
6314 6331 proceed = mergemod.driverconclude(repo, ms, wctx)
6315 6332 ms.commit()
6316 6333 if not proceed:
6317 6334 return 1
6318 6335
6319 6336 # Nudge users into finishing an unfinished operation
6320 6337 unresolvedf = list(ms.unresolved())
6321 6338 driverresolvedf = list(ms.driverresolved())
6322 6339 if not unresolvedf and not driverresolvedf:
6323 6340 ui.status(_('(no more unresolved files)\n'))
6324 6341 cmdutil.checkafterresolved(repo)
6325 6342 elif not unresolvedf:
6326 6343 ui.status(_('(no more unresolved files -- '
6327 6344 'run "hg resolve --all" to conclude)\n'))
6328 6345
6329 6346 return ret
6330 6347
6331 6348 @command('revert',
6332 6349 [('a', 'all', None, _('revert all changes when no arguments given')),
6333 6350 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6334 6351 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6335 6352 ('C', 'no-backup', None, _('do not save backup copies of files')),
6336 6353 ('i', 'interactive', None,
6337 6354 _('interactively select the changes (EXPERIMENTAL)')),
6338 6355 ] + walkopts + dryrunopts,
6339 6356 _('[OPTION]... [-r REV] [NAME]...'))
6340 6357 def revert(ui, repo, *pats, **opts):
6341 6358 """restore files to their checkout state
6342 6359
6343 6360 .. note::
6344 6361
6345 6362 To check out earlier revisions, you should use :hg:`update REV`.
6346 6363 To cancel an uncommitted merge (and lose your changes),
6347 6364 use :hg:`update --clean .`.
6348 6365
6349 6366 With no revision specified, revert the specified files or directories
6350 6367 to the contents they had in the parent of the working directory.
6351 6368 This restores the contents of files to an unmodified
6352 6369 state and unschedules adds, removes, copies, and renames. If the
6353 6370 working directory has two parents, you must explicitly specify a
6354 6371 revision.
6355 6372
6356 6373 Using the -r/--rev or -d/--date options, revert the given files or
6357 6374 directories to their states as of a specific revision. Because
6358 6375 revert does not change the working directory parents, this will
6359 6376 cause these files to appear modified. This can be helpful to "back
6360 6377 out" some or all of an earlier change. See :hg:`backout` for a
6361 6378 related method.
6362 6379
6363 6380 Modified files are saved with a .orig suffix before reverting.
6364 6381 To disable these backups, use --no-backup. It is possible to store
6365 6382 the backup files in a custom directory relative to the root of the
6366 6383 repository by setting the ``ui.origbackuppath`` configuration
6367 6384 option.
6368 6385
6369 6386 See :hg:`help dates` for a list of formats valid for -d/--date.
6370 6387
6371 6388 See :hg:`help backout` for a way to reverse the effect of an
6372 6389 earlier changeset.
6373 6390
6374 6391 Returns 0 on success.
6375 6392 """
6376 6393
6377 6394 if opts.get("date"):
6378 6395 if opts.get("rev"):
6379 6396 raise error.Abort(_("you can't specify a revision and a date"))
6380 6397 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6381 6398
6382 6399 parent, p2 = repo.dirstate.parents()
6383 6400 if not opts.get('rev') and p2 != nullid:
6384 6401 # revert after merge is a trap for new users (issue2915)
6385 6402 raise error.Abort(_('uncommitted merge with no revision specified'),
6386 6403 hint=_("use 'hg update' or see 'hg help revert'"))
6387 6404
6388 6405 ctx = scmutil.revsingle(repo, opts.get('rev'))
6389 6406
6390 6407 if (not (pats or opts.get('include') or opts.get('exclude') or
6391 6408 opts.get('all') or opts.get('interactive'))):
6392 6409 msg = _("no files or directories specified")
6393 6410 if p2 != nullid:
6394 6411 hint = _("uncommitted merge, use --all to discard all changes,"
6395 6412 " or 'hg update -C .' to abort the merge")
6396 6413 raise error.Abort(msg, hint=hint)
6397 6414 dirty = any(repo.status())
6398 6415 node = ctx.node()
6399 6416 if node != parent:
6400 6417 if dirty:
6401 6418 hint = _("uncommitted changes, use --all to discard all"
6402 6419 " changes, or 'hg update %s' to update") % ctx.rev()
6403 6420 else:
6404 6421 hint = _("use --all to revert all files,"
6405 6422 " or 'hg update %s' to update") % ctx.rev()
6406 6423 elif dirty:
6407 6424 hint = _("uncommitted changes, use --all to discard all changes")
6408 6425 else:
6409 6426 hint = _("use --all to revert all files")
6410 6427 raise error.Abort(msg, hint=hint)
6411 6428
6412 6429 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6413 6430
6414 6431 @command('rollback', dryrunopts +
6415 6432 [('f', 'force', False, _('ignore safety measures'))])
6416 6433 def rollback(ui, repo, **opts):
6417 6434 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6418 6435
6419 6436 Please use :hg:`commit --amend` instead of rollback to correct
6420 6437 mistakes in the last commit.
6421 6438
6422 6439 This command should be used with care. There is only one level of
6423 6440 rollback, and there is no way to undo a rollback. It will also
6424 6441 restore the dirstate at the time of the last transaction, losing
6425 6442 any dirstate changes since that time. This command does not alter
6426 6443 the working directory.
6427 6444
6428 6445 Transactions are used to encapsulate the effects of all commands
6429 6446 that create new changesets or propagate existing changesets into a
6430 6447 repository.
6431 6448
6432 6449 .. container:: verbose
6433 6450
6434 6451 For example, the following commands are transactional, and their
6435 6452 effects can be rolled back:
6436 6453
6437 6454 - commit
6438 6455 - import
6439 6456 - pull
6440 6457 - push (with this repository as the destination)
6441 6458 - unbundle
6442 6459
6443 6460 To avoid permanent data loss, rollback will refuse to rollback a
6444 6461 commit transaction if it isn't checked out. Use --force to
6445 6462 override this protection.
6446 6463
6447 6464 The rollback command can be entirely disabled by setting the
6448 6465 ``ui.rollback`` configuration setting to false. If you're here
6449 6466 because you want to use rollback and it's disabled, you can
6450 6467 re-enable the command by setting ``ui.rollback`` to true.
6451 6468
6452 6469 This command is not intended for use on public repositories. Once
6453 6470 changes are visible for pull by other users, rolling a transaction
6454 6471 back locally is ineffective (someone else may already have pulled
6455 6472 the changes). Furthermore, a race is possible with readers of the
6456 6473 repository; for example an in-progress pull from the repository
6457 6474 may fail if a rollback is performed.
6458 6475
6459 6476 Returns 0 on success, 1 if no rollback data is available.
6460 6477 """
6461 6478 if not ui.configbool('ui', 'rollback', True):
6462 6479 raise error.Abort(_('rollback is disabled because it is unsafe'),
6463 6480 hint=('see `hg help -v rollback` for information'))
6464 6481 return repo.rollback(dryrun=opts.get('dry_run'),
6465 6482 force=opts.get('force'))
6466 6483
6467 6484 @command('root', [])
6468 6485 def root(ui, repo):
6469 6486 """print the root (top) of the current working directory
6470 6487
6471 6488 Print the root directory of the current repository.
6472 6489
6473 6490 Returns 0 on success.
6474 6491 """
6475 6492 ui.write(repo.root + "\n")
6476 6493
6477 6494 @command('^serve',
6478 6495 [('A', 'accesslog', '', _('name of access log file to write to'),
6479 6496 _('FILE')),
6480 6497 ('d', 'daemon', None, _('run server in background')),
6481 6498 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6482 6499 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6483 6500 # use string type, then we can check if something was passed
6484 6501 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6485 6502 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6486 6503 _('ADDR')),
6487 6504 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6488 6505 _('PREFIX')),
6489 6506 ('n', 'name', '',
6490 6507 _('name to show in web pages (default: working directory)'), _('NAME')),
6491 6508 ('', 'web-conf', '',
6492 6509 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6493 6510 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6494 6511 _('FILE')),
6495 6512 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6496 6513 ('', 'stdio', None, _('for remote clients')),
6497 6514 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6498 6515 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6499 6516 ('', 'style', '', _('template style to use'), _('STYLE')),
6500 6517 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6501 6518 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6502 6519 _('[OPTION]...'),
6503 6520 optionalrepo=True)
6504 6521 def serve(ui, repo, **opts):
6505 6522 """start stand-alone webserver
6506 6523
6507 6524 Start a local HTTP repository browser and pull server. You can use
6508 6525 this for ad-hoc sharing and browsing of repositories. It is
6509 6526 recommended to use a real web server to serve a repository for
6510 6527 longer periods of time.
6511 6528
6512 6529 Please note that the server does not implement access control.
6513 6530 This means that, by default, anybody can read from the server and
6514 6531 nobody can write to it by default. Set the ``web.allow_push``
6515 6532 option to ``*`` to allow everybody to push to the server. You
6516 6533 should use a real web server if you need to authenticate users.
6517 6534
6518 6535 By default, the server logs accesses to stdout and errors to
6519 6536 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6520 6537 files.
6521 6538
6522 6539 To have the server choose a free port number to listen on, specify
6523 6540 a port number of 0; in this case, the server will print the port
6524 6541 number it uses.
6525 6542
6526 6543 Returns 0 on success.
6527 6544 """
6528 6545
6529 6546 if opts["stdio"] and opts["cmdserver"]:
6530 6547 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6531 6548
6532 6549 if opts["stdio"]:
6533 6550 if repo is None:
6534 6551 raise error.RepoError(_("there is no Mercurial repository here"
6535 6552 " (.hg not found)"))
6536 6553 s = sshserver.sshserver(ui, repo)
6537 6554 s.serve_forever()
6538 6555
6539 6556 if opts["cmdserver"]:
6540 6557 service = commandserver.createservice(ui, repo, opts)
6541 6558 else:
6542 6559 service = hgweb.createservice(ui, repo, opts)
6543 6560 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6544 6561
6545 6562 @command('^status|st',
6546 6563 [('A', 'all', None, _('show status of all files')),
6547 6564 ('m', 'modified', None, _('show only modified files')),
6548 6565 ('a', 'added', None, _('show only added files')),
6549 6566 ('r', 'removed', None, _('show only removed files')),
6550 6567 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6551 6568 ('c', 'clean', None, _('show only files without changes')),
6552 6569 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6553 6570 ('i', 'ignored', None, _('show only ignored files')),
6554 6571 ('n', 'no-status', None, _('hide status prefix')),
6555 6572 ('C', 'copies', None, _('show source of copied files')),
6556 6573 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6557 6574 ('', 'rev', [], _('show difference from revision'), _('REV')),
6558 6575 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6559 6576 ] + walkopts + subrepoopts + formatteropts,
6560 6577 _('[OPTION]... [FILE]...'),
6561 6578 inferrepo=True)
6562 6579 def status(ui, repo, *pats, **opts):
6563 6580 """show changed files in the working directory
6564 6581
6565 6582 Show status of files in the repository. If names are given, only
6566 6583 files that match are shown. Files that are clean or ignored or
6567 6584 the source of a copy/move operation, are not listed unless
6568 6585 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6569 6586 Unless options described with "show only ..." are given, the
6570 6587 options -mardu are used.
6571 6588
6572 6589 Option -q/--quiet hides untracked (unknown and ignored) files
6573 6590 unless explicitly requested with -u/--unknown or -i/--ignored.
6574 6591
6575 6592 .. note::
6576 6593
6577 6594 :hg:`status` may appear to disagree with diff if permissions have
6578 6595 changed or a merge has occurred. The standard diff format does
6579 6596 not report permission changes and diff only reports changes
6580 6597 relative to one merge parent.
6581 6598
6582 6599 If one revision is given, it is used as the base revision.
6583 6600 If two revisions are given, the differences between them are
6584 6601 shown. The --change option can also be used as a shortcut to list
6585 6602 the changed files of a revision from its first parent.
6586 6603
6587 6604 The codes used to show the status of files are::
6588 6605
6589 6606 M = modified
6590 6607 A = added
6591 6608 R = removed
6592 6609 C = clean
6593 6610 ! = missing (deleted by non-hg command, but still tracked)
6594 6611 ? = not tracked
6595 6612 I = ignored
6596 6613 = origin of the previous file (with --copies)
6597 6614
6598 6615 .. container:: verbose
6599 6616
6600 6617 Examples:
6601 6618
6602 6619 - show changes in the working directory relative to a
6603 6620 changeset::
6604 6621
6605 6622 hg status --rev 9353
6606 6623
6607 6624 - show changes in the working directory relative to the
6608 6625 current directory (see :hg:`help patterns` for more information)::
6609 6626
6610 6627 hg status re:
6611 6628
6612 6629 - show all changes including copies in an existing changeset::
6613 6630
6614 6631 hg status --copies --change 9353
6615 6632
6616 6633 - get a NUL separated list of added files, suitable for xargs::
6617 6634
6618 6635 hg status -an0
6619 6636
6620 6637 Returns 0 on success.
6621 6638 """
6622 6639
6623 6640 revs = opts.get('rev')
6624 6641 change = opts.get('change')
6625 6642
6626 6643 if revs and change:
6627 6644 msg = _('cannot specify --rev and --change at the same time')
6628 6645 raise error.Abort(msg)
6629 6646 elif change:
6630 6647 node2 = scmutil.revsingle(repo, change, None).node()
6631 6648 node1 = repo[node2].p1().node()
6632 6649 else:
6633 6650 node1, node2 = scmutil.revpair(repo, revs)
6634 6651
6635 6652 if pats:
6636 6653 cwd = repo.getcwd()
6637 6654 else:
6638 6655 cwd = ''
6639 6656
6640 6657 if opts.get('print0'):
6641 6658 end = '\0'
6642 6659 else:
6643 6660 end = '\n'
6644 6661 copy = {}
6645 6662 states = 'modified added removed deleted unknown ignored clean'.split()
6646 6663 show = [k for k in states if opts.get(k)]
6647 6664 if opts.get('all'):
6648 6665 show += ui.quiet and (states[:4] + ['clean']) or states
6649 6666 if not show:
6650 6667 if ui.quiet:
6651 6668 show = states[:4]
6652 6669 else:
6653 6670 show = states[:5]
6654 6671
6655 6672 m = scmutil.match(repo[node2], pats, opts)
6656 6673 stat = repo.status(node1, node2, m,
6657 6674 'ignored' in show, 'clean' in show, 'unknown' in show,
6658 6675 opts.get('subrepos'))
6659 6676 changestates = zip(states, 'MAR!?IC', stat)
6660 6677
6661 6678 if (opts.get('all') or opts.get('copies')
6662 6679 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6663 6680 copy = copies.pathcopies(repo[node1], repo[node2], m)
6664 6681
6665 6682 fm = ui.formatter('status', opts)
6666 6683 fmt = '%s' + end
6667 6684 showchar = not opts.get('no_status')
6668 6685
6669 6686 for state, char, files in changestates:
6670 6687 if state in show:
6671 6688 label = 'status.' + state
6672 6689 for f in files:
6673 6690 fm.startitem()
6674 6691 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6675 6692 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6676 6693 if f in copy:
6677 6694 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6678 6695 label='status.copied')
6679 6696 fm.end()
6680 6697
6681 6698 @command('^summary|sum',
6682 6699 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6683 6700 def summary(ui, repo, **opts):
6684 6701 """summarize working directory state
6685 6702
6686 6703 This generates a brief summary of the working directory state,
6687 6704 including parents, branch, commit status, phase and available updates.
6688 6705
6689 6706 With the --remote option, this will check the default paths for
6690 6707 incoming and outgoing changes. This can be time-consuming.
6691 6708
6692 6709 Returns 0 on success.
6693 6710 """
6694 6711
6695 6712 ctx = repo[None]
6696 6713 parents = ctx.parents()
6697 6714 pnode = parents[0].node()
6698 6715 marks = []
6699 6716
6700 6717 ms = None
6701 6718 try:
6702 6719 ms = mergemod.mergestate.read(repo)
6703 6720 except error.UnsupportedMergeRecords as e:
6704 6721 s = ' '.join(e.recordtypes)
6705 6722 ui.warn(
6706 6723 _('warning: merge state has unsupported record types: %s\n') % s)
6707 6724 unresolved = 0
6708 6725 else:
6709 6726 unresolved = [f for f in ms if ms[f] == 'u']
6710 6727
6711 6728 for p in parents:
6712 6729 # label with log.changeset (instead of log.parent) since this
6713 6730 # shows a working directory parent *changeset*:
6714 6731 # i18n: column positioning for "hg summary"
6715 6732 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6716 6733 label='log.changeset changeset.%s' % p.phasestr())
6717 6734 ui.write(' '.join(p.tags()), label='log.tag')
6718 6735 if p.bookmarks():
6719 6736 marks.extend(p.bookmarks())
6720 6737 if p.rev() == -1:
6721 6738 if not len(repo):
6722 6739 ui.write(_(' (empty repository)'))
6723 6740 else:
6724 6741 ui.write(_(' (no revision checked out)'))
6725 6742 ui.write('\n')
6726 6743 if p.description():
6727 6744 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6728 6745 label='log.summary')
6729 6746
6730 6747 branch = ctx.branch()
6731 6748 bheads = repo.branchheads(branch)
6732 6749 # i18n: column positioning for "hg summary"
6733 6750 m = _('branch: %s\n') % branch
6734 6751 if branch != 'default':
6735 6752 ui.write(m, label='log.branch')
6736 6753 else:
6737 6754 ui.status(m, label='log.branch')
6738 6755
6739 6756 if marks:
6740 6757 active = repo._activebookmark
6741 6758 # i18n: column positioning for "hg summary"
6742 6759 ui.write(_('bookmarks:'), label='log.bookmark')
6743 6760 if active is not None:
6744 6761 if active in marks:
6745 6762 ui.write(' *' + active, label=activebookmarklabel)
6746 6763 marks.remove(active)
6747 6764 else:
6748 6765 ui.write(' [%s]' % active, label=activebookmarklabel)
6749 6766 for m in marks:
6750 6767 ui.write(' ' + m, label='log.bookmark')
6751 6768 ui.write('\n', label='log.bookmark')
6752 6769
6753 6770 status = repo.status(unknown=True)
6754 6771
6755 6772 c = repo.dirstate.copies()
6756 6773 copied, renamed = [], []
6757 6774 for d, s in c.iteritems():
6758 6775 if s in status.removed:
6759 6776 status.removed.remove(s)
6760 6777 renamed.append(d)
6761 6778 else:
6762 6779 copied.append(d)
6763 6780 if d in status.added:
6764 6781 status.added.remove(d)
6765 6782
6766 6783 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6767 6784
6768 6785 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6769 6786 (ui.label(_('%d added'), 'status.added'), status.added),
6770 6787 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6771 6788 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6772 6789 (ui.label(_('%d copied'), 'status.copied'), copied),
6773 6790 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6774 6791 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6775 6792 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6776 6793 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6777 6794 t = []
6778 6795 for l, s in labels:
6779 6796 if s:
6780 6797 t.append(l % len(s))
6781 6798
6782 6799 t = ', '.join(t)
6783 6800 cleanworkdir = False
6784 6801
6785 6802 if repo.vfs.exists('graftstate'):
6786 6803 t += _(' (graft in progress)')
6787 6804 if repo.vfs.exists('updatestate'):
6788 6805 t += _(' (interrupted update)')
6789 6806 elif len(parents) > 1:
6790 6807 t += _(' (merge)')
6791 6808 elif branch != parents[0].branch():
6792 6809 t += _(' (new branch)')
6793 6810 elif (parents[0].closesbranch() and
6794 6811 pnode in repo.branchheads(branch, closed=True)):
6795 6812 t += _(' (head closed)')
6796 6813 elif not (status.modified or status.added or status.removed or renamed or
6797 6814 copied or subs):
6798 6815 t += _(' (clean)')
6799 6816 cleanworkdir = True
6800 6817 elif pnode not in bheads:
6801 6818 t += _(' (new branch head)')
6802 6819
6803 6820 if parents:
6804 6821 pendingphase = max(p.phase() for p in parents)
6805 6822 else:
6806 6823 pendingphase = phases.public
6807 6824
6808 6825 if pendingphase > phases.newcommitphase(ui):
6809 6826 t += ' (%s)' % phases.phasenames[pendingphase]
6810 6827
6811 6828 if cleanworkdir:
6812 6829 # i18n: column positioning for "hg summary"
6813 6830 ui.status(_('commit: %s\n') % t.strip())
6814 6831 else:
6815 6832 # i18n: column positioning for "hg summary"
6816 6833 ui.write(_('commit: %s\n') % t.strip())
6817 6834
6818 6835 # all ancestors of branch heads - all ancestors of parent = new csets
6819 6836 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6820 6837 bheads))
6821 6838
6822 6839 if new == 0:
6823 6840 # i18n: column positioning for "hg summary"
6824 6841 ui.status(_('update: (current)\n'))
6825 6842 elif pnode not in bheads:
6826 6843 # i18n: column positioning for "hg summary"
6827 6844 ui.write(_('update: %d new changesets (update)\n') % new)
6828 6845 else:
6829 6846 # i18n: column positioning for "hg summary"
6830 6847 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6831 6848 (new, len(bheads)))
6832 6849
6833 6850 t = []
6834 6851 draft = len(repo.revs('draft()'))
6835 6852 if draft:
6836 6853 t.append(_('%d draft') % draft)
6837 6854 secret = len(repo.revs('secret()'))
6838 6855 if secret:
6839 6856 t.append(_('%d secret') % secret)
6840 6857
6841 6858 if draft or secret:
6842 6859 ui.status(_('phases: %s\n') % ', '.join(t))
6843 6860
6844 6861 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6845 6862 for trouble in ("unstable", "divergent", "bumped"):
6846 6863 numtrouble = len(repo.revs(trouble + "()"))
6847 6864 # We write all the possibilities to ease translation
6848 6865 troublemsg = {
6849 6866 "unstable": _("unstable: %d changesets"),
6850 6867 "divergent": _("divergent: %d changesets"),
6851 6868 "bumped": _("bumped: %d changesets"),
6852 6869 }
6853 6870 if numtrouble > 0:
6854 6871 ui.status(troublemsg[trouble] % numtrouble + "\n")
6855 6872
6856 6873 cmdutil.summaryhooks(ui, repo)
6857 6874
6858 6875 if opts.get('remote'):
6859 6876 needsincoming, needsoutgoing = True, True
6860 6877 else:
6861 6878 needsincoming, needsoutgoing = False, False
6862 6879 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6863 6880 if i:
6864 6881 needsincoming = True
6865 6882 if o:
6866 6883 needsoutgoing = True
6867 6884 if not needsincoming and not needsoutgoing:
6868 6885 return
6869 6886
6870 6887 def getincoming():
6871 6888 source, branches = hg.parseurl(ui.expandpath('default'))
6872 6889 sbranch = branches[0]
6873 6890 try:
6874 6891 other = hg.peer(repo, {}, source)
6875 6892 except error.RepoError:
6876 6893 if opts.get('remote'):
6877 6894 raise
6878 6895 return source, sbranch, None, None, None
6879 6896 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6880 6897 if revs:
6881 6898 revs = [other.lookup(rev) for rev in revs]
6882 6899 ui.debug('comparing with %s\n' % util.hidepassword(source))
6883 6900 repo.ui.pushbuffer()
6884 6901 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6885 6902 repo.ui.popbuffer()
6886 6903 return source, sbranch, other, commoninc, commoninc[1]
6887 6904
6888 6905 if needsincoming:
6889 6906 source, sbranch, sother, commoninc, incoming = getincoming()
6890 6907 else:
6891 6908 source = sbranch = sother = commoninc = incoming = None
6892 6909
6893 6910 def getoutgoing():
6894 6911 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6895 6912 dbranch = branches[0]
6896 6913 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6897 6914 if source != dest:
6898 6915 try:
6899 6916 dother = hg.peer(repo, {}, dest)
6900 6917 except error.RepoError:
6901 6918 if opts.get('remote'):
6902 6919 raise
6903 6920 return dest, dbranch, None, None
6904 6921 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6905 6922 elif sother is None:
6906 6923 # there is no explicit destination peer, but source one is invalid
6907 6924 return dest, dbranch, None, None
6908 6925 else:
6909 6926 dother = sother
6910 6927 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6911 6928 common = None
6912 6929 else:
6913 6930 common = commoninc
6914 6931 if revs:
6915 6932 revs = [repo.lookup(rev) for rev in revs]
6916 6933 repo.ui.pushbuffer()
6917 6934 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6918 6935 commoninc=common)
6919 6936 repo.ui.popbuffer()
6920 6937 return dest, dbranch, dother, outgoing
6921 6938
6922 6939 if needsoutgoing:
6923 6940 dest, dbranch, dother, outgoing = getoutgoing()
6924 6941 else:
6925 6942 dest = dbranch = dother = outgoing = None
6926 6943
6927 6944 if opts.get('remote'):
6928 6945 t = []
6929 6946 if incoming:
6930 6947 t.append(_('1 or more incoming'))
6931 6948 o = outgoing.missing
6932 6949 if o:
6933 6950 t.append(_('%d outgoing') % len(o))
6934 6951 other = dother or sother
6935 6952 if 'bookmarks' in other.listkeys('namespaces'):
6936 6953 counts = bookmarks.summary(repo, other)
6937 6954 if counts[0] > 0:
6938 6955 t.append(_('%d incoming bookmarks') % counts[0])
6939 6956 if counts[1] > 0:
6940 6957 t.append(_('%d outgoing bookmarks') % counts[1])
6941 6958
6942 6959 if t:
6943 6960 # i18n: column positioning for "hg summary"
6944 6961 ui.write(_('remote: %s\n') % (', '.join(t)))
6945 6962 else:
6946 6963 # i18n: column positioning for "hg summary"
6947 6964 ui.status(_('remote: (synced)\n'))
6948 6965
6949 6966 cmdutil.summaryremotehooks(ui, repo, opts,
6950 6967 ((source, sbranch, sother, commoninc),
6951 6968 (dest, dbranch, dother, outgoing)))
6952 6969
6953 6970 @command('tag',
6954 6971 [('f', 'force', None, _('force tag')),
6955 6972 ('l', 'local', None, _('make the tag local')),
6956 6973 ('r', 'rev', '', _('revision to tag'), _('REV')),
6957 6974 ('', 'remove', None, _('remove a tag')),
6958 6975 # -l/--local is already there, commitopts cannot be used
6959 6976 ('e', 'edit', None, _('invoke editor on commit messages')),
6960 6977 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6961 6978 ] + commitopts2,
6962 6979 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6963 6980 def tag(ui, repo, name1, *names, **opts):
6964 6981 """add one or more tags for the current or given revision
6965 6982
6966 6983 Name a particular revision using <name>.
6967 6984
6968 6985 Tags are used to name particular revisions of the repository and are
6969 6986 very useful to compare different revisions, to go back to significant
6970 6987 earlier versions or to mark branch points as releases, etc. Changing
6971 6988 an existing tag is normally disallowed; use -f/--force to override.
6972 6989
6973 6990 If no revision is given, the parent of the working directory is
6974 6991 used.
6975 6992
6976 6993 To facilitate version control, distribution, and merging of tags,
6977 6994 they are stored as a file named ".hgtags" which is managed similarly
6978 6995 to other project files and can be hand-edited if necessary. This
6979 6996 also means that tagging creates a new commit. The file
6980 6997 ".hg/localtags" is used for local tags (not shared among
6981 6998 repositories).
6982 6999
6983 7000 Tag commits are usually made at the head of a branch. If the parent
6984 7001 of the working directory is not a branch head, :hg:`tag` aborts; use
6985 7002 -f/--force to force the tag commit to be based on a non-head
6986 7003 changeset.
6987 7004
6988 7005 See :hg:`help dates` for a list of formats valid for -d/--date.
6989 7006
6990 7007 Since tag names have priority over branch names during revision
6991 7008 lookup, using an existing branch name as a tag name is discouraged.
6992 7009
6993 7010 Returns 0 on success.
6994 7011 """
6995 7012 wlock = lock = None
6996 7013 try:
6997 7014 wlock = repo.wlock()
6998 7015 lock = repo.lock()
6999 7016 rev_ = "."
7000 7017 names = [t.strip() for t in (name1,) + names]
7001 7018 if len(names) != len(set(names)):
7002 7019 raise error.Abort(_('tag names must be unique'))
7003 7020 for n in names:
7004 7021 scmutil.checknewlabel(repo, n, 'tag')
7005 7022 if not n:
7006 7023 raise error.Abort(_('tag names cannot consist entirely of '
7007 7024 'whitespace'))
7008 7025 if opts.get('rev') and opts.get('remove'):
7009 7026 raise error.Abort(_("--rev and --remove are incompatible"))
7010 7027 if opts.get('rev'):
7011 7028 rev_ = opts['rev']
7012 7029 message = opts.get('message')
7013 7030 if opts.get('remove'):
7014 7031 if opts.get('local'):
7015 7032 expectedtype = 'local'
7016 7033 else:
7017 7034 expectedtype = 'global'
7018 7035
7019 7036 for n in names:
7020 7037 if not repo.tagtype(n):
7021 7038 raise error.Abort(_("tag '%s' does not exist") % n)
7022 7039 if repo.tagtype(n) != expectedtype:
7023 7040 if expectedtype == 'global':
7024 7041 raise error.Abort(_("tag '%s' is not a global tag") % n)
7025 7042 else:
7026 7043 raise error.Abort(_("tag '%s' is not a local tag") % n)
7027 7044 rev_ = 'null'
7028 7045 if not message:
7029 7046 # we don't translate commit messages
7030 7047 message = 'Removed tag %s' % ', '.join(names)
7031 7048 elif not opts.get('force'):
7032 7049 for n in names:
7033 7050 if n in repo.tags():
7034 7051 raise error.Abort(_("tag '%s' already exists "
7035 7052 "(use -f to force)") % n)
7036 7053 if not opts.get('local'):
7037 7054 p1, p2 = repo.dirstate.parents()
7038 7055 if p2 != nullid:
7039 7056 raise error.Abort(_('uncommitted merge'))
7040 7057 bheads = repo.branchheads()
7041 7058 if not opts.get('force') and bheads and p1 not in bheads:
7042 7059 raise error.Abort(_('not at a branch head (use -f to force)'))
7043 7060 r = scmutil.revsingle(repo, rev_).node()
7044 7061
7045 7062 if not message:
7046 7063 # we don't translate commit messages
7047 7064 message = ('Added tag %s for changeset %s' %
7048 7065 (', '.join(names), short(r)))
7049 7066
7050 7067 date = opts.get('date')
7051 7068 if date:
7052 7069 date = util.parsedate(date)
7053 7070
7054 7071 if opts.get('remove'):
7055 7072 editform = 'tag.remove'
7056 7073 else:
7057 7074 editform = 'tag.add'
7058 7075 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7059 7076
7060 7077 # don't allow tagging the null rev
7061 7078 if (not opts.get('remove') and
7062 7079 scmutil.revsingle(repo, rev_).rev() == nullrev):
7063 7080 raise error.Abort(_("cannot tag null revision"))
7064 7081
7065 7082 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
7066 7083 editor=editor)
7067 7084 finally:
7068 7085 release(lock, wlock)
7069 7086
7070 7087 @command('tags', formatteropts, '')
7071 7088 def tags(ui, repo, **opts):
7072 7089 """list repository tags
7073 7090
7074 7091 This lists both regular and local tags. When the -v/--verbose
7075 7092 switch is used, a third column "local" is printed for local tags.
7076 7093 When the -q/--quiet switch is used, only the tag name is printed.
7077 7094
7078 7095 Returns 0 on success.
7079 7096 """
7080 7097
7081 7098 fm = ui.formatter('tags', opts)
7082 7099 hexfunc = fm.hexfunc
7083 7100 tagtype = ""
7084 7101
7085 7102 for t, n in reversed(repo.tagslist()):
7086 7103 hn = hexfunc(n)
7087 7104 label = 'tags.normal'
7088 7105 tagtype = ''
7089 7106 if repo.tagtype(t) == 'local':
7090 7107 label = 'tags.local'
7091 7108 tagtype = 'local'
7092 7109
7093 7110 fm.startitem()
7094 7111 fm.write('tag', '%s', t, label=label)
7095 7112 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
7096 7113 fm.condwrite(not ui.quiet, 'rev node', fmt,
7097 7114 repo.changelog.rev(n), hn, label=label)
7098 7115 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
7099 7116 tagtype, label=label)
7100 7117 fm.plain('\n')
7101 7118 fm.end()
7102 7119
7103 7120 @command('tip',
7104 7121 [('p', 'patch', None, _('show patch')),
7105 7122 ('g', 'git', None, _('use git extended diff format')),
7106 7123 ] + templateopts,
7107 7124 _('[-p] [-g]'))
7108 7125 def tip(ui, repo, **opts):
7109 7126 """show the tip revision (DEPRECATED)
7110 7127
7111 7128 The tip revision (usually just called the tip) is the changeset
7112 7129 most recently added to the repository (and therefore the most
7113 7130 recently changed head).
7114 7131
7115 7132 If you have just made a commit, that commit will be the tip. If
7116 7133 you have just pulled changes from another repository, the tip of
7117 7134 that repository becomes the current tip. The "tip" tag is special
7118 7135 and cannot be renamed or assigned to a different changeset.
7119 7136
7120 7137 This command is deprecated, please use :hg:`heads` instead.
7121 7138
7122 7139 Returns 0 on success.
7123 7140 """
7124 7141 displayer = cmdutil.show_changeset(ui, repo, opts)
7125 7142 displayer.show(repo['tip'])
7126 7143 displayer.close()
7127 7144
7128 7145 @command('unbundle',
7129 7146 [('u', 'update', None,
7130 7147 _('update to new branch head if changesets were unbundled'))],
7131 7148 _('[-u] FILE...'))
7132 7149 def unbundle(ui, repo, fname1, *fnames, **opts):
7133 7150 """apply one or more changegroup files
7134 7151
7135 7152 Apply one or more compressed changegroup files generated by the
7136 7153 bundle command.
7137 7154
7138 7155 Returns 0 on success, 1 if an update has unresolved files.
7139 7156 """
7140 7157 fnames = (fname1,) + fnames
7141 7158
7142 7159 with repo.lock():
7143 7160 for fname in fnames:
7144 7161 f = hg.openpath(ui, fname)
7145 7162 gen = exchange.readbundle(ui, f, fname)
7146 7163 if isinstance(gen, bundle2.unbundle20):
7147 7164 tr = repo.transaction('unbundle')
7148 7165 try:
7149 7166 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7150 7167 url='bundle:' + fname)
7151 7168 tr.close()
7152 7169 except error.BundleUnknownFeatureError as exc:
7153 7170 raise error.Abort(_('%s: unknown bundle feature, %s')
7154 7171 % (fname, exc),
7155 7172 hint=_("see https://mercurial-scm.org/"
7156 7173 "wiki/BundleFeature for more "
7157 7174 "information"))
7158 7175 finally:
7159 7176 if tr:
7160 7177 tr.release()
7161 7178 changes = [r.get('return', 0)
7162 7179 for r in op.records['changegroup']]
7163 7180 modheads = changegroup.combineresults(changes)
7164 7181 elif isinstance(gen, streamclone.streamcloneapplier):
7165 7182 raise error.Abort(
7166 7183 _('packed bundles cannot be applied with '
7167 7184 '"hg unbundle"'),
7168 7185 hint=_('use "hg debugapplystreamclonebundle"'))
7169 7186 else:
7170 7187 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7171 7188
7172 7189 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7173 7190
7174 7191 @command('^update|up|checkout|co',
7175 7192 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7176 7193 ('c', 'check', None, _('require clean working directory')),
7177 7194 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7178 7195 ('r', 'rev', '', _('revision'), _('REV'))
7179 7196 ] + mergetoolopts,
7180 7197 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7181 7198 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7182 7199 tool=None):
7183 7200 """update working directory (or switch revisions)
7184 7201
7185 7202 Update the repository's working directory to the specified
7186 7203 changeset. If no changeset is specified, update to the tip of the
7187 7204 current named branch and move the active bookmark (see :hg:`help
7188 7205 bookmarks`).
7189 7206
7190 7207 Update sets the working directory's parent revision to the specified
7191 7208 changeset (see :hg:`help parents`).
7192 7209
7193 7210 If the changeset is not a descendant or ancestor of the working
7194 7211 directory's parent, the update is aborted. With the -c/--check
7195 7212 option, the working directory is checked for uncommitted changes; if
7196 7213 none are found, the working directory is updated to the specified
7197 7214 changeset.
7198 7215
7199 7216 .. container:: verbose
7200 7217
7201 7218 The following rules apply when the working directory contains
7202 7219 uncommitted changes:
7203 7220
7204 7221 1. If neither -c/--check nor -C/--clean is specified, and if
7205 7222 the requested changeset is an ancestor or descendant of
7206 7223 the working directory's parent, the uncommitted changes
7207 7224 are merged into the requested changeset and the merged
7208 7225 result is left uncommitted. If the requested changeset is
7209 7226 not an ancestor or descendant (that is, it is on another
7210 7227 branch), the update is aborted and the uncommitted changes
7211 7228 are preserved.
7212 7229
7213 7230 2. With the -c/--check option, the update is aborted and the
7214 7231 uncommitted changes are preserved.
7215 7232
7216 7233 3. With the -C/--clean option, uncommitted changes are discarded and
7217 7234 the working directory is updated to the requested changeset.
7218 7235
7219 7236 To cancel an uncommitted merge (and lose your changes), use
7220 7237 :hg:`update --clean .`.
7221 7238
7222 7239 Use null as the changeset to remove the working directory (like
7223 7240 :hg:`clone -U`).
7224 7241
7225 7242 If you want to revert just one file to an older revision, use
7226 7243 :hg:`revert [-r REV] NAME`.
7227 7244
7228 7245 See :hg:`help dates` for a list of formats valid for -d/--date.
7229 7246
7230 7247 Returns 0 on success, 1 if there are unresolved files.
7231 7248 """
7232 7249 if rev and node:
7233 7250 raise error.Abort(_("please specify just one revision"))
7234 7251
7235 7252 if rev is None or rev == '':
7236 7253 rev = node
7237 7254
7238 7255 if date and rev is not None:
7239 7256 raise error.Abort(_("you can't specify a revision and a date"))
7240 7257
7241 7258 if check and clean:
7242 7259 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7243 7260
7244 7261 with repo.wlock():
7245 7262 cmdutil.clearunfinished(repo)
7246 7263
7247 7264 if date:
7248 7265 rev = cmdutil.finddate(ui, repo, date)
7249 7266
7250 7267 # if we defined a bookmark, we have to remember the original name
7251 7268 brev = rev
7252 7269 rev = scmutil.revsingle(repo, rev, rev).rev()
7253 7270
7254 7271 if check:
7255 7272 cmdutil.bailifchanged(repo, merge=False)
7256 7273
7257 7274 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7258 7275
7259 7276 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7260 7277
7261 7278 @command('verify', [])
7262 7279 def verify(ui, repo):
7263 7280 """verify the integrity of the repository
7264 7281
7265 7282 Verify the integrity of the current repository.
7266 7283
7267 7284 This will perform an extensive check of the repository's
7268 7285 integrity, validating the hashes and checksums of each entry in
7269 7286 the changelog, manifest, and tracked files, as well as the
7270 7287 integrity of their crosslinks and indices.
7271 7288
7272 7289 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7273 7290 for more information about recovery from corruption of the
7274 7291 repository.
7275 7292
7276 7293 Returns 0 on success, 1 if errors are encountered.
7277 7294 """
7278 7295 return hg.verify(repo)
7279 7296
7280 7297 @command('version', [] + formatteropts, norepo=True)
7281 7298 def version_(ui, **opts):
7282 7299 """output version and copyright information"""
7283 7300 fm = ui.formatter("version", opts)
7284 7301 fm.startitem()
7285 7302 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
7286 7303 util.version())
7287 7304 license = _(
7288 7305 "(see https://mercurial-scm.org for more information)\n"
7289 7306 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7290 7307 "This is free software; see the source for copying conditions. "
7291 7308 "There is NO\nwarranty; "
7292 7309 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7293 7310 )
7294 7311 if not ui.quiet:
7295 7312 fm.plain(license)
7296 7313
7297 7314 if ui.verbose:
7298 7315 fm.plain(_("\nEnabled extensions:\n\n"))
7299 7316 # format names and versions into columns
7300 7317 names = []
7301 7318 vers = []
7302 7319 isinternals = []
7303 7320 for name, module in extensions.extensions():
7304 7321 names.append(name)
7305 7322 vers.append(extensions.moduleversion(module) or None)
7306 7323 isinternals.append(extensions.ismoduleinternal(module))
7307 7324 fn = fm.nested("extensions")
7308 7325 if names:
7309 7326 namefmt = " %%-%ds " % max(len(n) for n in names)
7310 7327 places = [_("external"), _("internal")]
7311 7328 for n, v, p in zip(names, vers, isinternals):
7312 7329 fn.startitem()
7313 7330 fn.condwrite(ui.verbose, "name", namefmt, n)
7314 7331 if ui.verbose:
7315 7332 fn.plain("%s " % places[p])
7316 7333 fn.data(bundled=p)
7317 7334 fn.condwrite(ui.verbose and v, "ver", "%s", v)
7318 7335 if ui.verbose:
7319 7336 fn.plain("\n")
7320 7337 fn.end()
7321 7338 fm.end()
7322 7339
7323 7340 def loadcmdtable(ui, name, cmdtable):
7324 7341 """Load command functions from specified cmdtable
7325 7342 """
7326 7343 overrides = [cmd for cmd in cmdtable if cmd in table]
7327 7344 if overrides:
7328 7345 ui.warn(_("extension '%s' overrides commands: %s\n")
7329 7346 % (name, " ".join(overrides)))
7330 7347 table.update(cmdtable)
@@ -1,352 +1,352 b''
1 1 Show all commands except debug commands
2 2 $ hg debugcomplete
3 3 add
4 4 addremove
5 5 annotate
6 6 archive
7 7 backout
8 8 bisect
9 9 bookmarks
10 10 branch
11 11 branches
12 12 bundle
13 13 cat
14 14 clone
15 15 commit
16 16 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
272 debugrevspec: optimize, show-stage
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,3228 +1,3278 b''
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 parsed tree at stages:
493
494 $ hg debugrevspec -p all '()'
495 * parsed:
496 (group
497 None)
498 * expanded:
499 (group
500 None)
501 * concatenated:
502 (group
503 None)
504 * analyzed:
505 None
506 * optimized:
507 None
508 hg: parse error: missing argument
509 [255]
510
511 $ hg debugrevspec -p parsed -p analyzed -p optimized '(0|1)-1'
512 * parsed:
513 (minus
514 (group
515 (or
516 ('symbol', '0')
517 ('symbol', '1')))
518 ('symbol', '1'))
519 * analyzed:
520 (and
521 (or
522 ('symbol', '0')
523 ('symbol', '1'))
524 (not
525 ('symbol', '1')))
526 * optimized:
527 (difference
528 (func
529 ('symbol', '_list')
530 ('string', '0\x001'))
531 ('symbol', '1'))
532 0
533
534 $ hg debugrevspec -p unknown '0'
535 abort: invalid stage name: unknown
536 [255]
537
538 $ hg debugrevspec -p all --optimize '0'
539 abort: cannot use --optimize with --show-stage
540 [255]
541
492 542 Test that symbols only get parsed as functions if there's an opening
493 543 parenthesis.
494 544
495 545 $ hg book only -r 9
496 546 $ log 'only(only)' # Outer "only" is a function, inner "only" is the bookmark
497 547 8
498 548 9
499 549
500 550 infix/suffix resolution of ^ operator (issue2884):
501 551
502 552 x^:y means (x^):y
503 553
504 554 $ try '1^:2'
505 555 (range
506 556 (parentpost
507 557 ('symbol', '1'))
508 558 ('symbol', '2'))
509 559 * set:
510 560 <spanset+ 0:2>
511 561 0
512 562 1
513 563 2
514 564
515 565 $ try '1^::2'
516 566 (dagrange
517 567 (parentpost
518 568 ('symbol', '1'))
519 569 ('symbol', '2'))
520 570 * set:
521 571 <baseset+ [0, 1, 2]>
522 572 0
523 573 1
524 574 2
525 575
526 576 $ try '9^:'
527 577 (rangepost
528 578 (parentpost
529 579 ('symbol', '9')))
530 580 * set:
531 581 <spanset+ 8:9>
532 582 8
533 583 9
534 584
535 585 x^:y should be resolved before omitting group operators
536 586
537 587 $ try '1^(:2)'
538 588 (parent
539 589 ('symbol', '1')
540 590 (group
541 591 (rangepre
542 592 ('symbol', '2'))))
543 593 hg: parse error: ^ expects a number 0, 1, or 2
544 594 [255]
545 595
546 596 x^:y should be resolved recursively
547 597
548 598 $ try 'sort(1^:2)'
549 599 (func
550 600 ('symbol', 'sort')
551 601 (range
552 602 (parentpost
553 603 ('symbol', '1'))
554 604 ('symbol', '2')))
555 605 * set:
556 606 <spanset+ 0:2>
557 607 0
558 608 1
559 609 2
560 610
561 611 $ try '(3^:4)^:2'
562 612 (range
563 613 (parentpost
564 614 (group
565 615 (range
566 616 (parentpost
567 617 ('symbol', '3'))
568 618 ('symbol', '4'))))
569 619 ('symbol', '2'))
570 620 * set:
571 621 <spanset+ 0:2>
572 622 0
573 623 1
574 624 2
575 625
576 626 $ try '(3^::4)^::2'
577 627 (dagrange
578 628 (parentpost
579 629 (group
580 630 (dagrange
581 631 (parentpost
582 632 ('symbol', '3'))
583 633 ('symbol', '4'))))
584 634 ('symbol', '2'))
585 635 * set:
586 636 <baseset+ [0, 1, 2]>
587 637 0
588 638 1
589 639 2
590 640
591 641 $ try '(9^:)^:'
592 642 (rangepost
593 643 (parentpost
594 644 (group
595 645 (rangepost
596 646 (parentpost
597 647 ('symbol', '9'))))))
598 648 * set:
599 649 <spanset+ 4:9>
600 650 4
601 651 5
602 652 6
603 653 7
604 654 8
605 655 9
606 656
607 657 x^ in alias should also be resolved
608 658
609 659 $ try 'A' --config 'revsetalias.A=1^:2'
610 660 ('symbol', 'A')
611 661 * expanded:
612 662 (range
613 663 (parentpost
614 664 ('symbol', '1'))
615 665 ('symbol', '2'))
616 666 * set:
617 667 <spanset+ 0:2>
618 668 0
619 669 1
620 670 2
621 671
622 672 $ try 'A:2' --config 'revsetalias.A=1^'
623 673 (range
624 674 ('symbol', 'A')
625 675 ('symbol', '2'))
626 676 * expanded:
627 677 (range
628 678 (parentpost
629 679 ('symbol', '1'))
630 680 ('symbol', '2'))
631 681 * set:
632 682 <spanset+ 0:2>
633 683 0
634 684 1
635 685 2
636 686
637 687 but not beyond the boundary of alias expansion, because the resolution should
638 688 be made at the parsing stage
639 689
640 690 $ try '1^A' --config 'revsetalias.A=:2'
641 691 (parent
642 692 ('symbol', '1')
643 693 ('symbol', 'A'))
644 694 * expanded:
645 695 (parent
646 696 ('symbol', '1')
647 697 (rangepre
648 698 ('symbol', '2')))
649 699 hg: parse error: ^ expects a number 0, 1, or 2
650 700 [255]
651 701
652 702 ancestor can accept 0 or more arguments
653 703
654 704 $ log 'ancestor()'
655 705 $ log 'ancestor(1)'
656 706 1
657 707 $ log 'ancestor(4,5)'
658 708 1
659 709 $ log 'ancestor(4,5) and 4'
660 710 $ log 'ancestor(0,0,1,3)'
661 711 0
662 712 $ log 'ancestor(3,1,5,3,5,1)'
663 713 1
664 714 $ log 'ancestor(0,1,3,5)'
665 715 0
666 716 $ log 'ancestor(1,2,3,4,5)'
667 717 1
668 718
669 719 test ancestors
670 720
671 721 $ log 'ancestors(5)'
672 722 0
673 723 1
674 724 3
675 725 5
676 726 $ log 'ancestor(ancestors(5))'
677 727 0
678 728 $ log '::r3232()'
679 729 0
680 730 1
681 731 2
682 732 3
683 733
684 734 $ log 'author(bob)'
685 735 2
686 736 $ log 'author("re:bob|test")'
687 737 0
688 738 1
689 739 2
690 740 3
691 741 4
692 742 5
693 743 6
694 744 7
695 745 8
696 746 9
697 747 $ log 'branch(Γ©)'
698 748 8
699 749 9
700 750 $ log 'branch(a)'
701 751 0
702 752 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
703 753 0 a
704 754 2 a-b-c-
705 755 3 +a+b+c+
706 756 4 -a-b-c-
707 757 5 !a/b/c/
708 758 6 _a_b_c_
709 759 7 .a.b.c.
710 760 $ log 'children(ancestor(4,5))'
711 761 2
712 762 3
713 763 $ log 'closed()'
714 764 $ log 'contains(a)'
715 765 0
716 766 1
717 767 3
718 768 5
719 769 $ log 'contains("../repo/a")'
720 770 0
721 771 1
722 772 3
723 773 5
724 774 $ log 'desc(B)'
725 775 5
726 776 $ log 'descendants(2 or 3)'
727 777 2
728 778 3
729 779 4
730 780 5
731 781 6
732 782 7
733 783 8
734 784 9
735 785 $ log 'file("b*")'
736 786 1
737 787 4
738 788 $ log 'filelog("b")'
739 789 1
740 790 4
741 791 $ log 'filelog("../repo/b")'
742 792 1
743 793 4
744 794 $ log 'follow()'
745 795 0
746 796 1
747 797 2
748 798 4
749 799 8
750 800 9
751 801 $ log 'grep("issue\d+")'
752 802 6
753 803 $ try 'grep("(")' # invalid regular expression
754 804 (func
755 805 ('symbol', 'grep')
756 806 ('string', '('))
757 807 hg: parse error: invalid match pattern: unbalanced parenthesis
758 808 [255]
759 809 $ try 'grep("\bissue\d+")'
760 810 (func
761 811 ('symbol', 'grep')
762 812 ('string', '\x08issue\\d+'))
763 813 * set:
764 814 <filteredset
765 815 <fullreposet+ 0:9>,
766 816 <grep '\x08issue\\d+'>>
767 817 $ try 'grep(r"\bissue\d+")'
768 818 (func
769 819 ('symbol', 'grep')
770 820 ('string', '\\bissue\\d+'))
771 821 * set:
772 822 <filteredset
773 823 <fullreposet+ 0:9>,
774 824 <grep '\\bissue\\d+'>>
775 825 6
776 826 $ try 'grep(r"\")'
777 827 hg: parse error at 7: unterminated string
778 828 [255]
779 829 $ log 'head()'
780 830 0
781 831 1
782 832 2
783 833 3
784 834 4
785 835 5
786 836 6
787 837 7
788 838 9
789 839 $ log 'heads(6::)'
790 840 7
791 841 $ log 'keyword(issue)'
792 842 6
793 843 $ log 'keyword("test a")'
794 844 $ log 'limit(head(), 1)'
795 845 0
796 846 $ log 'limit(author("re:bob|test"), 3, 5)'
797 847 5
798 848 6
799 849 7
800 850 $ log 'limit(author("re:bob|test"), offset=6)'
801 851 6
802 852 $ log 'limit(author("re:bob|test"), offset=10)'
803 853 $ log 'limit(all(), 1, -1)'
804 854 hg: parse error: negative offset
805 855 [255]
806 856 $ log 'matching(6)'
807 857 6
808 858 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
809 859 6
810 860 7
811 861
812 862 Testing min and max
813 863
814 864 max: simple
815 865
816 866 $ log 'max(contains(a))'
817 867 5
818 868
819 869 max: simple on unordered set)
820 870
821 871 $ log 'max((4+0+2+5+7) and contains(a))'
822 872 5
823 873
824 874 max: no result
825 875
826 876 $ log 'max(contains(stringthatdoesnotappearanywhere))'
827 877
828 878 max: no result on unordered set
829 879
830 880 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
831 881
832 882 min: simple
833 883
834 884 $ log 'min(contains(a))'
835 885 0
836 886
837 887 min: simple on unordered set
838 888
839 889 $ log 'min((4+0+2+5+7) and contains(a))'
840 890 0
841 891
842 892 min: empty
843 893
844 894 $ log 'min(contains(stringthatdoesnotappearanywhere))'
845 895
846 896 min: empty on unordered set
847 897
848 898 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
849 899
850 900
851 901 $ log 'merge()'
852 902 6
853 903 $ log 'branchpoint()'
854 904 1
855 905 4
856 906 $ log 'modifies(b)'
857 907 4
858 908 $ log 'modifies("path:b")'
859 909 4
860 910 $ log 'modifies("*")'
861 911 4
862 912 6
863 913 $ log 'modifies("set:modified()")'
864 914 4
865 915 $ log 'id(5)'
866 916 2
867 917 $ log 'only(9)'
868 918 8
869 919 9
870 920 $ log 'only(8)'
871 921 8
872 922 $ log 'only(9, 5)'
873 923 2
874 924 4
875 925 8
876 926 9
877 927 $ log 'only(7 + 9, 5 + 2)'
878 928 4
879 929 6
880 930 7
881 931 8
882 932 9
883 933
884 934 Test empty set input
885 935 $ log 'only(p2())'
886 936 $ log 'only(p1(), p2())'
887 937 0
888 938 1
889 939 2
890 940 4
891 941 8
892 942 9
893 943
894 944 Test '%' operator
895 945
896 946 $ log '9%'
897 947 8
898 948 9
899 949 $ log '9%5'
900 950 2
901 951 4
902 952 8
903 953 9
904 954 $ log '(7 + 9)%(5 + 2)'
905 955 4
906 956 6
907 957 7
908 958 8
909 959 9
910 960
911 961 Test opreand of '%' is optimized recursively (issue4670)
912 962
913 963 $ try --optimize '8:9-8%'
914 964 (onlypost
915 965 (minus
916 966 (range
917 967 ('symbol', '8')
918 968 ('symbol', '9'))
919 969 ('symbol', '8')))
920 970 * optimized:
921 971 (func
922 972 ('symbol', 'only')
923 973 (difference
924 974 (range
925 975 ('symbol', '8')
926 976 ('symbol', '9'))
927 977 ('symbol', '8')))
928 978 * set:
929 979 <baseset+ [8, 9]>
930 980 8
931 981 9
932 982 $ try --optimize '(9)%(5)'
933 983 (only
934 984 (group
935 985 ('symbol', '9'))
936 986 (group
937 987 ('symbol', '5')))
938 988 * optimized:
939 989 (func
940 990 ('symbol', 'only')
941 991 (list
942 992 ('symbol', '9')
943 993 ('symbol', '5')))
944 994 * set:
945 995 <baseset+ [2, 4, 8, 9]>
946 996 2
947 997 4
948 998 8
949 999 9
950 1000
951 1001 Test the order of operations
952 1002
953 1003 $ log '7 + 9%5 + 2'
954 1004 7
955 1005 2
956 1006 4
957 1007 8
958 1008 9
959 1009
960 1010 Test explicit numeric revision
961 1011 $ log 'rev(-2)'
962 1012 $ log 'rev(-1)'
963 1013 -1
964 1014 $ log 'rev(0)'
965 1015 0
966 1016 $ log 'rev(9)'
967 1017 9
968 1018 $ log 'rev(10)'
969 1019 $ log 'rev(tip)'
970 1020 hg: parse error: rev expects a number
971 1021 [255]
972 1022
973 1023 Test hexadecimal revision
974 1024 $ log 'id(2)'
975 1025 abort: 00changelog.i@2: ambiguous identifier!
976 1026 [255]
977 1027 $ log 'id(23268)'
978 1028 4
979 1029 $ log 'id(2785f51eece)'
980 1030 0
981 1031 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532c)'
982 1032 8
983 1033 $ log 'id(d5d0dcbdc4a)'
984 1034 $ log 'id(d5d0dcbdc4w)'
985 1035 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532d)'
986 1036 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532q)'
987 1037 $ log 'id(1.0)'
988 1038 $ log 'id(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)'
989 1039
990 1040 Test null revision
991 1041 $ log '(null)'
992 1042 -1
993 1043 $ log '(null:0)'
994 1044 -1
995 1045 0
996 1046 $ log '(0:null)'
997 1047 0
998 1048 -1
999 1049 $ log 'null::0'
1000 1050 -1
1001 1051 0
1002 1052 $ log 'null:tip - 0:'
1003 1053 -1
1004 1054 $ log 'null: and null::' | head -1
1005 1055 -1
1006 1056 $ log 'null: or 0:' | head -2
1007 1057 -1
1008 1058 0
1009 1059 $ log 'ancestors(null)'
1010 1060 -1
1011 1061 $ log 'reverse(null:)' | tail -2
1012 1062 0
1013 1063 -1
1014 1064 BROKEN: should be '-1'
1015 1065 $ log 'first(null:)'
1016 1066 BROKEN: should be '-1'
1017 1067 $ log 'min(null:)'
1018 1068 $ log 'tip:null and all()' | tail -2
1019 1069 1
1020 1070 0
1021 1071
1022 1072 Test working-directory revision
1023 1073 $ hg debugrevspec 'wdir()'
1024 1074 2147483647
1025 1075 $ hg debugrevspec 'tip or wdir()'
1026 1076 9
1027 1077 2147483647
1028 1078 $ hg debugrevspec '0:tip and wdir()'
1029 1079 $ log '0:wdir()' | tail -3
1030 1080 8
1031 1081 9
1032 1082 2147483647
1033 1083 $ log 'wdir():0' | head -3
1034 1084 2147483647
1035 1085 9
1036 1086 8
1037 1087 $ log 'wdir():wdir()'
1038 1088 2147483647
1039 1089 $ log '(all() + wdir()) & min(. + wdir())'
1040 1090 9
1041 1091 $ log '(all() + wdir()) & max(. + wdir())'
1042 1092 2147483647
1043 1093 $ log '(all() + wdir()) & first(wdir() + .)'
1044 1094 2147483647
1045 1095 $ log '(all() + wdir()) & last(. + wdir())'
1046 1096 2147483647
1047 1097
1048 1098 $ log 'outgoing()'
1049 1099 8
1050 1100 9
1051 1101 $ log 'outgoing("../remote1")'
1052 1102 8
1053 1103 9
1054 1104 $ log 'outgoing("../remote2")'
1055 1105 3
1056 1106 5
1057 1107 6
1058 1108 7
1059 1109 9
1060 1110 $ log 'p1(merge())'
1061 1111 5
1062 1112 $ log 'p2(merge())'
1063 1113 4
1064 1114 $ log 'parents(merge())'
1065 1115 4
1066 1116 5
1067 1117 $ log 'p1(branchpoint())'
1068 1118 0
1069 1119 2
1070 1120 $ log 'p2(branchpoint())'
1071 1121 $ log 'parents(branchpoint())'
1072 1122 0
1073 1123 2
1074 1124 $ log 'removes(a)'
1075 1125 2
1076 1126 6
1077 1127 $ log 'roots(all())'
1078 1128 0
1079 1129 $ log 'reverse(2 or 3 or 4 or 5)'
1080 1130 5
1081 1131 4
1082 1132 3
1083 1133 2
1084 1134 $ log 'reverse(all())'
1085 1135 9
1086 1136 8
1087 1137 7
1088 1138 6
1089 1139 5
1090 1140 4
1091 1141 3
1092 1142 2
1093 1143 1
1094 1144 0
1095 1145 $ log 'reverse(all()) & filelog(b)'
1096 1146 4
1097 1147 1
1098 1148 $ log 'rev(5)'
1099 1149 5
1100 1150 $ log 'sort(limit(reverse(all()), 3))'
1101 1151 7
1102 1152 8
1103 1153 9
1104 1154 $ log 'sort(2 or 3 or 4 or 5, date)'
1105 1155 2
1106 1156 3
1107 1157 5
1108 1158 4
1109 1159 $ log 'tagged()'
1110 1160 6
1111 1161 $ log 'tag()'
1112 1162 6
1113 1163 $ log 'tag(1.0)'
1114 1164 6
1115 1165 $ log 'tag(tip)'
1116 1166 9
1117 1167
1118 1168 Test order of revisions in compound expression
1119 1169 ----------------------------------------------
1120 1170
1121 1171 The general rule is that only the outermost (= leftmost) predicate can
1122 1172 enforce its ordering requirement. The other predicates should take the
1123 1173 ordering defined by it.
1124 1174
1125 1175 'A & B' should follow the order of 'A':
1126 1176
1127 1177 $ log '2:0 & 0::2'
1128 1178 2
1129 1179 1
1130 1180 0
1131 1181
1132 1182 'head()' combines sets in right order:
1133 1183
1134 1184 $ log '2:0 & head()'
1135 1185 2
1136 1186 1
1137 1187 0
1138 1188
1139 1189 'a + b', which is optimized to '_list(a b)', should take the ordering of
1140 1190 the left expression:
1141 1191
1142 1192 $ try --optimize '2:0 & (0 + 1 + 2)'
1143 1193 (and
1144 1194 (range
1145 1195 ('symbol', '2')
1146 1196 ('symbol', '0'))
1147 1197 (group
1148 1198 (or
1149 1199 ('symbol', '0')
1150 1200 ('symbol', '1')
1151 1201 ('symbol', '2'))))
1152 1202 * optimized:
1153 1203 (and
1154 1204 (range
1155 1205 ('symbol', '2')
1156 1206 ('symbol', '0'))
1157 1207 (func
1158 1208 ('symbol', '_list')
1159 1209 ('string', '0\x001\x002')))
1160 1210 * set:
1161 1211 <baseset [0, 1, 2]>
1162 1212 0
1163 1213 1
1164 1214 2
1165 1215 BROKEN: should be '2 1 0'
1166 1216
1167 1217 'A + B' should take the ordering of the left expression:
1168 1218
1169 1219 $ try --optimize '2:0 & (0:1 + 2)'
1170 1220 (and
1171 1221 (range
1172 1222 ('symbol', '2')
1173 1223 ('symbol', '0'))
1174 1224 (group
1175 1225 (or
1176 1226 (range
1177 1227 ('symbol', '0')
1178 1228 ('symbol', '1'))
1179 1229 ('symbol', '2'))))
1180 1230 * optimized:
1181 1231 (and
1182 1232 (range
1183 1233 ('symbol', '2')
1184 1234 ('symbol', '0'))
1185 1235 (or
1186 1236 (range
1187 1237 ('symbol', '0')
1188 1238 ('symbol', '1'))
1189 1239 ('symbol', '2')))
1190 1240 * set:
1191 1241 <addset
1192 1242 <filteredset
1193 1243 <spanset+ 0:1>,
1194 1244 <spanset- 0:2>>,
1195 1245 <baseset [2]>>
1196 1246 0
1197 1247 1
1198 1248 2
1199 1249 BROKEN: should be '2 1 0'
1200 1250
1201 1251 '_intlist(a b)' should behave like 'a + b':
1202 1252
1203 1253 $ trylist --optimize '2:0 & %ld' 0 1 2
1204 1254 (and
1205 1255 (range
1206 1256 ('symbol', '2')
1207 1257 ('symbol', '0'))
1208 1258 (func
1209 1259 ('symbol', '_intlist')
1210 1260 ('string', '0\x001\x002')))
1211 1261 * optimized:
1212 1262 (and
1213 1263 (func
1214 1264 ('symbol', '_intlist')
1215 1265 ('string', '0\x001\x002'))
1216 1266 (range
1217 1267 ('symbol', '2')
1218 1268 ('symbol', '0')))
1219 1269 * set:
1220 1270 <filteredset
1221 1271 <spanset- 0:2>,
1222 1272 <baseset [0, 1, 2]>>
1223 1273 2
1224 1274 1
1225 1275 0
1226 1276
1227 1277 $ trylist --optimize '%ld & 2:0' 0 2 1
1228 1278 (and
1229 1279 (func
1230 1280 ('symbol', '_intlist')
1231 1281 ('string', '0\x002\x001'))
1232 1282 (range
1233 1283 ('symbol', '2')
1234 1284 ('symbol', '0')))
1235 1285 * optimized:
1236 1286 (and
1237 1287 (func
1238 1288 ('symbol', '_intlist')
1239 1289 ('string', '0\x002\x001'))
1240 1290 (range
1241 1291 ('symbol', '2')
1242 1292 ('symbol', '0')))
1243 1293 * set:
1244 1294 <filteredset
1245 1295 <spanset- 0:2>,
1246 1296 <baseset [0, 2, 1]>>
1247 1297 2
1248 1298 1
1249 1299 0
1250 1300 BROKEN: should be '0 2 1'
1251 1301
1252 1302 '_hexlist(a b)' should behave like 'a + b':
1253 1303
1254 1304 $ trylist --optimize --bin '2:0 & %ln' `hg log -T '{node} ' -r0:2`
1255 1305 (and
1256 1306 (range
1257 1307 ('symbol', '2')
1258 1308 ('symbol', '0'))
1259 1309 (func
1260 1310 ('symbol', '_hexlist')
1261 1311 ('string', '*'))) (glob)
1262 1312 * optimized:
1263 1313 (and
1264 1314 (range
1265 1315 ('symbol', '2')
1266 1316 ('symbol', '0'))
1267 1317 (func
1268 1318 ('symbol', '_hexlist')
1269 1319 ('string', '*'))) (glob)
1270 1320 * set:
1271 1321 <baseset [0, 1, 2]>
1272 1322 0
1273 1323 1
1274 1324 2
1275 1325 BROKEN: should be '2 1 0'
1276 1326
1277 1327 $ trylist --optimize --bin '%ln & 2:0' `hg log -T '{node} ' -r0+2+1`
1278 1328 (and
1279 1329 (func
1280 1330 ('symbol', '_hexlist')
1281 1331 ('string', '*')) (glob)
1282 1332 (range
1283 1333 ('symbol', '2')
1284 1334 ('symbol', '0')))
1285 1335 * optimized:
1286 1336 (and
1287 1337 (range
1288 1338 ('symbol', '2')
1289 1339 ('symbol', '0'))
1290 1340 (func
1291 1341 ('symbol', '_hexlist')
1292 1342 ('string', '*'))) (glob)
1293 1343 * set:
1294 1344 <baseset [0, 2, 1]>
1295 1345 0
1296 1346 2
1297 1347 1
1298 1348
1299 1349 'present()' should do nothing other than suppressing an error:
1300 1350
1301 1351 $ try --optimize '2:0 & present(0 + 1 + 2)'
1302 1352 (and
1303 1353 (range
1304 1354 ('symbol', '2')
1305 1355 ('symbol', '0'))
1306 1356 (func
1307 1357 ('symbol', 'present')
1308 1358 (or
1309 1359 ('symbol', '0')
1310 1360 ('symbol', '1')
1311 1361 ('symbol', '2'))))
1312 1362 * optimized:
1313 1363 (and
1314 1364 (range
1315 1365 ('symbol', '2')
1316 1366 ('symbol', '0'))
1317 1367 (func
1318 1368 ('symbol', 'present')
1319 1369 (func
1320 1370 ('symbol', '_list')
1321 1371 ('string', '0\x001\x002'))))
1322 1372 * set:
1323 1373 <baseset [0, 1, 2]>
1324 1374 0
1325 1375 1
1326 1376 2
1327 1377 BROKEN: should be '2 1 0'
1328 1378
1329 1379 'reverse()' should take effect only if it is the outermost expression:
1330 1380
1331 1381 $ try --optimize '0:2 & reverse(all())'
1332 1382 (and
1333 1383 (range
1334 1384 ('symbol', '0')
1335 1385 ('symbol', '2'))
1336 1386 (func
1337 1387 ('symbol', 'reverse')
1338 1388 (func
1339 1389 ('symbol', 'all')
1340 1390 None)))
1341 1391 * optimized:
1342 1392 (and
1343 1393 (range
1344 1394 ('symbol', '0')
1345 1395 ('symbol', '2'))
1346 1396 (func
1347 1397 ('symbol', 'reverse')
1348 1398 (func
1349 1399 ('symbol', 'all')
1350 1400 None)))
1351 1401 * set:
1352 1402 <filteredset
1353 1403 <spanset- 0:2>,
1354 1404 <spanset+ 0:9>>
1355 1405 2
1356 1406 1
1357 1407 0
1358 1408 BROKEN: should be '0 1 2'
1359 1409
1360 1410 'sort()' should take effect only if it is the outermost expression:
1361 1411
1362 1412 $ try --optimize '0:2 & sort(all(), -rev)'
1363 1413 (and
1364 1414 (range
1365 1415 ('symbol', '0')
1366 1416 ('symbol', '2'))
1367 1417 (func
1368 1418 ('symbol', 'sort')
1369 1419 (list
1370 1420 (func
1371 1421 ('symbol', 'all')
1372 1422 None)
1373 1423 (negate
1374 1424 ('symbol', 'rev')))))
1375 1425 * optimized:
1376 1426 (and
1377 1427 (range
1378 1428 ('symbol', '0')
1379 1429 ('symbol', '2'))
1380 1430 (func
1381 1431 ('symbol', 'sort')
1382 1432 (list
1383 1433 (func
1384 1434 ('symbol', 'all')
1385 1435 None)
1386 1436 ('string', '-rev'))))
1387 1437 * set:
1388 1438 <filteredset
1389 1439 <spanset- 0:2>,
1390 1440 <spanset+ 0:9>>
1391 1441 2
1392 1442 1
1393 1443 0
1394 1444 BROKEN: should be '0 1 2'
1395 1445
1396 1446 for 'A & f(B)', 'B' should not be affected by the order of 'A':
1397 1447
1398 1448 $ try --optimize '2:0 & first(1 + 0 + 2)'
1399 1449 (and
1400 1450 (range
1401 1451 ('symbol', '2')
1402 1452 ('symbol', '0'))
1403 1453 (func
1404 1454 ('symbol', 'first')
1405 1455 (or
1406 1456 ('symbol', '1')
1407 1457 ('symbol', '0')
1408 1458 ('symbol', '2'))))
1409 1459 * optimized:
1410 1460 (and
1411 1461 (range
1412 1462 ('symbol', '2')
1413 1463 ('symbol', '0'))
1414 1464 (func
1415 1465 ('symbol', 'first')
1416 1466 (func
1417 1467 ('symbol', '_list')
1418 1468 ('string', '1\x000\x002'))))
1419 1469 * set:
1420 1470 <baseset
1421 1471 <limit n=1, offset=0,
1422 1472 <spanset- 0:2>,
1423 1473 <baseset [1, 0, 2]>>>
1424 1474 1
1425 1475
1426 1476 $ try --optimize '2:0 & not last(0 + 2 + 1)'
1427 1477 (and
1428 1478 (range
1429 1479 ('symbol', '2')
1430 1480 ('symbol', '0'))
1431 1481 (not
1432 1482 (func
1433 1483 ('symbol', 'last')
1434 1484 (or
1435 1485 ('symbol', '0')
1436 1486 ('symbol', '2')
1437 1487 ('symbol', '1')))))
1438 1488 * optimized:
1439 1489 (difference
1440 1490 (range
1441 1491 ('symbol', '2')
1442 1492 ('symbol', '0'))
1443 1493 (func
1444 1494 ('symbol', 'last')
1445 1495 (func
1446 1496 ('symbol', '_list')
1447 1497 ('string', '0\x002\x001'))))
1448 1498 * set:
1449 1499 <filteredset
1450 1500 <spanset- 0:2>,
1451 1501 <not
1452 1502 <baseset
1453 1503 <last n=1,
1454 1504 <fullreposet+ 0:9>,
1455 1505 <baseset [1, 2, 0]>>>>>
1456 1506 2
1457 1507 0
1458 1508
1459 1509 for 'A & (op)(B)', 'B' should not be affected by the order of 'A':
1460 1510
1461 1511 $ try --optimize '2:0 & (1 + 0 + 2):(0 + 2 + 1)'
1462 1512 (and
1463 1513 (range
1464 1514 ('symbol', '2')
1465 1515 ('symbol', '0'))
1466 1516 (range
1467 1517 (group
1468 1518 (or
1469 1519 ('symbol', '1')
1470 1520 ('symbol', '0')
1471 1521 ('symbol', '2')))
1472 1522 (group
1473 1523 (or
1474 1524 ('symbol', '0')
1475 1525 ('symbol', '2')
1476 1526 ('symbol', '1')))))
1477 1527 * optimized:
1478 1528 (and
1479 1529 (range
1480 1530 ('symbol', '2')
1481 1531 ('symbol', '0'))
1482 1532 (range
1483 1533 (func
1484 1534 ('symbol', '_list')
1485 1535 ('string', '1\x000\x002'))
1486 1536 (func
1487 1537 ('symbol', '_list')
1488 1538 ('string', '0\x002\x001'))))
1489 1539 * set:
1490 1540 <filteredset
1491 1541 <baseset [1]>,
1492 1542 <spanset- 0:2>>
1493 1543 1
1494 1544
1495 1545 'A & B' can be rewritten as 'B & A' by weight, but the ordering rule should
1496 1546 be determined before the optimization (i.e. 'B' should take the ordering of
1497 1547 'A'):
1498 1548
1499 1549 $ try --optimize 'contains("glob:*") & (2 + 0 + 1)'
1500 1550 (and
1501 1551 (func
1502 1552 ('symbol', 'contains')
1503 1553 ('string', 'glob:*'))
1504 1554 (group
1505 1555 (or
1506 1556 ('symbol', '2')
1507 1557 ('symbol', '0')
1508 1558 ('symbol', '1'))))
1509 1559 * optimized:
1510 1560 (and
1511 1561 (func
1512 1562 ('symbol', '_list')
1513 1563 ('string', '2\x000\x001'))
1514 1564 (func
1515 1565 ('symbol', 'contains')
1516 1566 ('string', 'glob:*')))
1517 1567 * set:
1518 1568 <filteredset
1519 1569 <baseset [2, 0, 1]>,
1520 1570 <contains 'glob:*'>>
1521 1571 2
1522 1572 0
1523 1573 1
1524 1574 BROKEN: should be '0 1 2'
1525 1575
1526 1576 $ try --optimize 'reverse(contains("glob:*")) & (0 + 2 + 1)'
1527 1577 (and
1528 1578 (func
1529 1579 ('symbol', 'reverse')
1530 1580 (func
1531 1581 ('symbol', 'contains')
1532 1582 ('string', 'glob:*')))
1533 1583 (group
1534 1584 (or
1535 1585 ('symbol', '0')
1536 1586 ('symbol', '2')
1537 1587 ('symbol', '1'))))
1538 1588 * optimized:
1539 1589 (and
1540 1590 (func
1541 1591 ('symbol', '_list')
1542 1592 ('string', '0\x002\x001'))
1543 1593 (func
1544 1594 ('symbol', 'reverse')
1545 1595 (func
1546 1596 ('symbol', 'contains')
1547 1597 ('string', 'glob:*'))))
1548 1598 * set:
1549 1599 <filteredset
1550 1600 <baseset [1, 2, 0]>,
1551 1601 <contains 'glob:*'>>
1552 1602 1
1553 1603 2
1554 1604 0
1555 1605 BROKEN: should be '2 1 0'
1556 1606
1557 1607 test sort revset
1558 1608 --------------------------------------------
1559 1609
1560 1610 test when adding two unordered revsets
1561 1611
1562 1612 $ log 'sort(keyword(issue) or modifies(b))'
1563 1613 4
1564 1614 6
1565 1615
1566 1616 test when sorting a reversed collection in the same way it is
1567 1617
1568 1618 $ log 'sort(reverse(all()), -rev)'
1569 1619 9
1570 1620 8
1571 1621 7
1572 1622 6
1573 1623 5
1574 1624 4
1575 1625 3
1576 1626 2
1577 1627 1
1578 1628 0
1579 1629
1580 1630 test when sorting a reversed collection
1581 1631
1582 1632 $ log 'sort(reverse(all()), rev)'
1583 1633 0
1584 1634 1
1585 1635 2
1586 1636 3
1587 1637 4
1588 1638 5
1589 1639 6
1590 1640 7
1591 1641 8
1592 1642 9
1593 1643
1594 1644
1595 1645 test sorting two sorted collections in different orders
1596 1646
1597 1647 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
1598 1648 2
1599 1649 6
1600 1650 8
1601 1651 9
1602 1652
1603 1653 test sorting two sorted collections in different orders backwards
1604 1654
1605 1655 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
1606 1656 9
1607 1657 8
1608 1658 6
1609 1659 2
1610 1660
1611 1661 test empty sort key which is noop
1612 1662
1613 1663 $ log 'sort(0 + 2 + 1, "")'
1614 1664 0
1615 1665 2
1616 1666 1
1617 1667
1618 1668 test invalid sort keys
1619 1669
1620 1670 $ log 'sort(all(), -invalid)'
1621 1671 hg: parse error: unknown sort key '-invalid'
1622 1672 [255]
1623 1673
1624 1674 $ cd ..
1625 1675
1626 1676 test sorting by multiple keys including variable-length strings
1627 1677
1628 1678 $ hg init sorting
1629 1679 $ cd sorting
1630 1680 $ cat <<EOF >> .hg/hgrc
1631 1681 > [ui]
1632 1682 > logtemplate = '{rev} {branch|p5}{desc|p5}{author|p5}{date|hgdate}\n'
1633 1683 > [templatealias]
1634 1684 > p5(s) = pad(s, 5)
1635 1685 > EOF
1636 1686 $ hg branch -qf b12
1637 1687 $ hg ci -m m111 -u u112 -d '111 10800'
1638 1688 $ hg branch -qf b11
1639 1689 $ hg ci -m m12 -u u111 -d '112 7200'
1640 1690 $ hg branch -qf b111
1641 1691 $ hg ci -m m11 -u u12 -d '111 3600'
1642 1692 $ hg branch -qf b112
1643 1693 $ hg ci -m m111 -u u11 -d '120 0'
1644 1694 $ hg branch -qf b111
1645 1695 $ hg ci -m m112 -u u111 -d '110 14400'
1646 1696 created new head
1647 1697
1648 1698 compare revisions (has fast path):
1649 1699
1650 1700 $ hg log -r 'sort(all(), rev)'
1651 1701 0 b12 m111 u112 111 10800
1652 1702 1 b11 m12 u111 112 7200
1653 1703 2 b111 m11 u12 111 3600
1654 1704 3 b112 m111 u11 120 0
1655 1705 4 b111 m112 u111 110 14400
1656 1706
1657 1707 $ hg log -r 'sort(all(), -rev)'
1658 1708 4 b111 m112 u111 110 14400
1659 1709 3 b112 m111 u11 120 0
1660 1710 2 b111 m11 u12 111 3600
1661 1711 1 b11 m12 u111 112 7200
1662 1712 0 b12 m111 u112 111 10800
1663 1713
1664 1714 compare variable-length strings (issue5218):
1665 1715
1666 1716 $ hg log -r 'sort(all(), branch)'
1667 1717 1 b11 m12 u111 112 7200
1668 1718 2 b111 m11 u12 111 3600
1669 1719 4 b111 m112 u111 110 14400
1670 1720 3 b112 m111 u11 120 0
1671 1721 0 b12 m111 u112 111 10800
1672 1722
1673 1723 $ hg log -r 'sort(all(), -branch)'
1674 1724 0 b12 m111 u112 111 10800
1675 1725 3 b112 m111 u11 120 0
1676 1726 2 b111 m11 u12 111 3600
1677 1727 4 b111 m112 u111 110 14400
1678 1728 1 b11 m12 u111 112 7200
1679 1729
1680 1730 $ hg log -r 'sort(all(), desc)'
1681 1731 2 b111 m11 u12 111 3600
1682 1732 0 b12 m111 u112 111 10800
1683 1733 3 b112 m111 u11 120 0
1684 1734 4 b111 m112 u111 110 14400
1685 1735 1 b11 m12 u111 112 7200
1686 1736
1687 1737 $ hg log -r 'sort(all(), -desc)'
1688 1738 1 b11 m12 u111 112 7200
1689 1739 4 b111 m112 u111 110 14400
1690 1740 0 b12 m111 u112 111 10800
1691 1741 3 b112 m111 u11 120 0
1692 1742 2 b111 m11 u12 111 3600
1693 1743
1694 1744 $ hg log -r 'sort(all(), user)'
1695 1745 3 b112 m111 u11 120 0
1696 1746 1 b11 m12 u111 112 7200
1697 1747 4 b111 m112 u111 110 14400
1698 1748 0 b12 m111 u112 111 10800
1699 1749 2 b111 m11 u12 111 3600
1700 1750
1701 1751 $ hg log -r 'sort(all(), -user)'
1702 1752 2 b111 m11 u12 111 3600
1703 1753 0 b12 m111 u112 111 10800
1704 1754 1 b11 m12 u111 112 7200
1705 1755 4 b111 m112 u111 110 14400
1706 1756 3 b112 m111 u11 120 0
1707 1757
1708 1758 compare dates (tz offset should have no effect):
1709 1759
1710 1760 $ hg log -r 'sort(all(), date)'
1711 1761 4 b111 m112 u111 110 14400
1712 1762 0 b12 m111 u112 111 10800
1713 1763 2 b111 m11 u12 111 3600
1714 1764 1 b11 m12 u111 112 7200
1715 1765 3 b112 m111 u11 120 0
1716 1766
1717 1767 $ hg log -r 'sort(all(), -date)'
1718 1768 3 b112 m111 u11 120 0
1719 1769 1 b11 m12 u111 112 7200
1720 1770 0 b12 m111 u112 111 10800
1721 1771 2 b111 m11 u12 111 3600
1722 1772 4 b111 m112 u111 110 14400
1723 1773
1724 1774 be aware that 'sort(x, -k)' is not exactly the same as 'reverse(sort(x, k))'
1725 1775 because '-k' reverses the comparison, not the list itself:
1726 1776
1727 1777 $ hg log -r 'sort(0 + 2, date)'
1728 1778 0 b12 m111 u112 111 10800
1729 1779 2 b111 m11 u12 111 3600
1730 1780
1731 1781 $ hg log -r 'sort(0 + 2, -date)'
1732 1782 0 b12 m111 u112 111 10800
1733 1783 2 b111 m11 u12 111 3600
1734 1784
1735 1785 $ hg log -r 'reverse(sort(0 + 2, date))'
1736 1786 2 b111 m11 u12 111 3600
1737 1787 0 b12 m111 u112 111 10800
1738 1788
1739 1789 sort by multiple keys:
1740 1790
1741 1791 $ hg log -r 'sort(all(), "branch -rev")'
1742 1792 1 b11 m12 u111 112 7200
1743 1793 4 b111 m112 u111 110 14400
1744 1794 2 b111 m11 u12 111 3600
1745 1795 3 b112 m111 u11 120 0
1746 1796 0 b12 m111 u112 111 10800
1747 1797
1748 1798 $ hg log -r 'sort(all(), "-desc -date")'
1749 1799 1 b11 m12 u111 112 7200
1750 1800 4 b111 m112 u111 110 14400
1751 1801 3 b112 m111 u11 120 0
1752 1802 0 b12 m111 u112 111 10800
1753 1803 2 b111 m11 u12 111 3600
1754 1804
1755 1805 $ hg log -r 'sort(all(), "user -branch date rev")'
1756 1806 3 b112 m111 u11 120 0
1757 1807 4 b111 m112 u111 110 14400
1758 1808 1 b11 m12 u111 112 7200
1759 1809 0 b12 m111 u112 111 10800
1760 1810 2 b111 m11 u12 111 3600
1761 1811
1762 1812 toposort prioritises graph branches
1763 1813
1764 1814 $ hg up 2
1765 1815 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1766 1816 $ touch a
1767 1817 $ hg addremove
1768 1818 adding a
1769 1819 $ hg ci -m 't1' -u 'tu' -d '130 0'
1770 1820 created new head
1771 1821 $ echo 'a' >> a
1772 1822 $ hg ci -m 't2' -u 'tu' -d '130 0'
1773 1823 $ hg book book1
1774 1824 $ hg up 4
1775 1825 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1776 1826 (leaving bookmark book1)
1777 1827 $ touch a
1778 1828 $ hg addremove
1779 1829 adding a
1780 1830 $ hg ci -m 't3' -u 'tu' -d '130 0'
1781 1831
1782 1832 $ hg log -r 'sort(all(), topo)'
1783 1833 7 b111 t3 tu 130 0
1784 1834 4 b111 m112 u111 110 14400
1785 1835 3 b112 m111 u11 120 0
1786 1836 6 b111 t2 tu 130 0
1787 1837 5 b111 t1 tu 130 0
1788 1838 2 b111 m11 u12 111 3600
1789 1839 1 b11 m12 u111 112 7200
1790 1840 0 b12 m111 u112 111 10800
1791 1841
1792 1842 $ hg log -r 'sort(all(), -topo)'
1793 1843 0 b12 m111 u112 111 10800
1794 1844 1 b11 m12 u111 112 7200
1795 1845 2 b111 m11 u12 111 3600
1796 1846 5 b111 t1 tu 130 0
1797 1847 6 b111 t2 tu 130 0
1798 1848 3 b112 m111 u11 120 0
1799 1849 4 b111 m112 u111 110 14400
1800 1850 7 b111 t3 tu 130 0
1801 1851
1802 1852 $ hg log -r 'sort(all(), topo, topo.firstbranch=book1)'
1803 1853 6 b111 t2 tu 130 0
1804 1854 5 b111 t1 tu 130 0
1805 1855 7 b111 t3 tu 130 0
1806 1856 4 b111 m112 u111 110 14400
1807 1857 3 b112 m111 u11 120 0
1808 1858 2 b111 m11 u12 111 3600
1809 1859 1 b11 m12 u111 112 7200
1810 1860 0 b12 m111 u112 111 10800
1811 1861
1812 1862 topographical sorting can't be combined with other sort keys, and you can't
1813 1863 use the topo.firstbranch option when topo sort is not active:
1814 1864
1815 1865 $ hg log -r 'sort(all(), "topo user")'
1816 1866 hg: parse error: topo sort order cannot be combined with other sort keys
1817 1867 [255]
1818 1868
1819 1869 $ hg log -r 'sort(all(), user, topo.firstbranch=book1)'
1820 1870 hg: parse error: topo.firstbranch can only be used when using the topo sort key
1821 1871 [255]
1822 1872
1823 1873 topo.firstbranch should accept any kind of expressions:
1824 1874
1825 1875 $ hg log -r 'sort(0, topo, topo.firstbranch=(book1))'
1826 1876 0 b12 m111 u112 111 10800
1827 1877
1828 1878 $ cd ..
1829 1879 $ cd repo
1830 1880
1831 1881 test subtracting something from an addset
1832 1882
1833 1883 $ log '(outgoing() or removes(a)) - removes(a)'
1834 1884 8
1835 1885 9
1836 1886
1837 1887 test intersecting something with an addset
1838 1888
1839 1889 $ log 'parents(outgoing() or removes(a))'
1840 1890 1
1841 1891 4
1842 1892 5
1843 1893 8
1844 1894
1845 1895 test that `or` operation combines elements in the right order:
1846 1896
1847 1897 $ log '3:4 or 2:5'
1848 1898 3
1849 1899 4
1850 1900 2
1851 1901 5
1852 1902 $ log '3:4 or 5:2'
1853 1903 3
1854 1904 4
1855 1905 5
1856 1906 2
1857 1907 $ log 'sort(3:4 or 2:5)'
1858 1908 2
1859 1909 3
1860 1910 4
1861 1911 5
1862 1912 $ log 'sort(3:4 or 5:2)'
1863 1913 2
1864 1914 3
1865 1915 4
1866 1916 5
1867 1917
1868 1918 test that more than one `-r`s are combined in the right order and deduplicated:
1869 1919
1870 1920 $ hg log -T '{rev}\n' -r 3 -r 3 -r 4 -r 5:2 -r 'ancestors(4)'
1871 1921 3
1872 1922 4
1873 1923 5
1874 1924 2
1875 1925 0
1876 1926 1
1877 1927
1878 1928 test that `or` operation skips duplicated revisions from right-hand side
1879 1929
1880 1930 $ try 'reverse(1::5) or ancestors(4)'
1881 1931 (or
1882 1932 (func
1883 1933 ('symbol', 'reverse')
1884 1934 (dagrange
1885 1935 ('symbol', '1')
1886 1936 ('symbol', '5')))
1887 1937 (func
1888 1938 ('symbol', 'ancestors')
1889 1939 ('symbol', '4')))
1890 1940 * set:
1891 1941 <addset
1892 1942 <baseset- [1, 3, 5]>,
1893 1943 <generatorset+>>
1894 1944 5
1895 1945 3
1896 1946 1
1897 1947 0
1898 1948 2
1899 1949 4
1900 1950 $ try 'sort(ancestors(4) or reverse(1::5))'
1901 1951 (func
1902 1952 ('symbol', 'sort')
1903 1953 (or
1904 1954 (func
1905 1955 ('symbol', 'ancestors')
1906 1956 ('symbol', '4'))
1907 1957 (func
1908 1958 ('symbol', 'reverse')
1909 1959 (dagrange
1910 1960 ('symbol', '1')
1911 1961 ('symbol', '5')))))
1912 1962 * set:
1913 1963 <addset+
1914 1964 <generatorset+>,
1915 1965 <baseset- [1, 3, 5]>>
1916 1966 0
1917 1967 1
1918 1968 2
1919 1969 3
1920 1970 4
1921 1971 5
1922 1972
1923 1973 test optimization of trivial `or` operation
1924 1974
1925 1975 $ try --optimize '0|(1)|"2"|-2|tip|null'
1926 1976 (or
1927 1977 ('symbol', '0')
1928 1978 (group
1929 1979 ('symbol', '1'))
1930 1980 ('string', '2')
1931 1981 (negate
1932 1982 ('symbol', '2'))
1933 1983 ('symbol', 'tip')
1934 1984 ('symbol', 'null'))
1935 1985 * optimized:
1936 1986 (func
1937 1987 ('symbol', '_list')
1938 1988 ('string', '0\x001\x002\x00-2\x00tip\x00null'))
1939 1989 * set:
1940 1990 <baseset [0, 1, 2, 8, 9, -1]>
1941 1991 0
1942 1992 1
1943 1993 2
1944 1994 8
1945 1995 9
1946 1996 -1
1947 1997
1948 1998 $ try --optimize '0|1|2:3'
1949 1999 (or
1950 2000 ('symbol', '0')
1951 2001 ('symbol', '1')
1952 2002 (range
1953 2003 ('symbol', '2')
1954 2004 ('symbol', '3')))
1955 2005 * optimized:
1956 2006 (or
1957 2007 (func
1958 2008 ('symbol', '_list')
1959 2009 ('string', '0\x001'))
1960 2010 (range
1961 2011 ('symbol', '2')
1962 2012 ('symbol', '3')))
1963 2013 * set:
1964 2014 <addset
1965 2015 <baseset [0, 1]>,
1966 2016 <spanset+ 2:3>>
1967 2017 0
1968 2018 1
1969 2019 2
1970 2020 3
1971 2021
1972 2022 $ try --optimize '0:1|2|3:4|5|6'
1973 2023 (or
1974 2024 (range
1975 2025 ('symbol', '0')
1976 2026 ('symbol', '1'))
1977 2027 ('symbol', '2')
1978 2028 (range
1979 2029 ('symbol', '3')
1980 2030 ('symbol', '4'))
1981 2031 ('symbol', '5')
1982 2032 ('symbol', '6'))
1983 2033 * optimized:
1984 2034 (or
1985 2035 (range
1986 2036 ('symbol', '0')
1987 2037 ('symbol', '1'))
1988 2038 ('symbol', '2')
1989 2039 (range
1990 2040 ('symbol', '3')
1991 2041 ('symbol', '4'))
1992 2042 (func
1993 2043 ('symbol', '_list')
1994 2044 ('string', '5\x006')))
1995 2045 * set:
1996 2046 <addset
1997 2047 <addset
1998 2048 <spanset+ 0:1>,
1999 2049 <baseset [2]>>,
2000 2050 <addset
2001 2051 <spanset+ 3:4>,
2002 2052 <baseset [5, 6]>>>
2003 2053 0
2004 2054 1
2005 2055 2
2006 2056 3
2007 2057 4
2008 2058 5
2009 2059 6
2010 2060
2011 2061 test that `_list` should be narrowed by provided `subset`
2012 2062
2013 2063 $ log '0:2 and (null|1|2|3)'
2014 2064 1
2015 2065 2
2016 2066
2017 2067 test that `_list` should remove duplicates
2018 2068
2019 2069 $ log '0|1|2|1|2|-1|tip'
2020 2070 0
2021 2071 1
2022 2072 2
2023 2073 9
2024 2074
2025 2075 test unknown revision in `_list`
2026 2076
2027 2077 $ log '0|unknown'
2028 2078 abort: unknown revision 'unknown'!
2029 2079 [255]
2030 2080
2031 2081 test integer range in `_list`
2032 2082
2033 2083 $ log '-1|-10'
2034 2084 9
2035 2085 0
2036 2086
2037 2087 $ log '-10|-11'
2038 2088 abort: unknown revision '-11'!
2039 2089 [255]
2040 2090
2041 2091 $ log '9|10'
2042 2092 abort: unknown revision '10'!
2043 2093 [255]
2044 2094
2045 2095 test '0000' != '0' in `_list`
2046 2096
2047 2097 $ log '0|0000'
2048 2098 0
2049 2099 -1
2050 2100
2051 2101 test ',' in `_list`
2052 2102 $ log '0,1'
2053 2103 hg: parse error: can't use a list in this context
2054 2104 (see hg help "revsets.x or y")
2055 2105 [255]
2056 2106 $ try '0,1,2'
2057 2107 (list
2058 2108 ('symbol', '0')
2059 2109 ('symbol', '1')
2060 2110 ('symbol', '2'))
2061 2111 hg: parse error: can't use a list in this context
2062 2112 (see hg help "revsets.x or y")
2063 2113 [255]
2064 2114
2065 2115 test that chained `or` operations make balanced addsets
2066 2116
2067 2117 $ try '0:1|1:2|2:3|3:4|4:5'
2068 2118 (or
2069 2119 (range
2070 2120 ('symbol', '0')
2071 2121 ('symbol', '1'))
2072 2122 (range
2073 2123 ('symbol', '1')
2074 2124 ('symbol', '2'))
2075 2125 (range
2076 2126 ('symbol', '2')
2077 2127 ('symbol', '3'))
2078 2128 (range
2079 2129 ('symbol', '3')
2080 2130 ('symbol', '4'))
2081 2131 (range
2082 2132 ('symbol', '4')
2083 2133 ('symbol', '5')))
2084 2134 * set:
2085 2135 <addset
2086 2136 <addset
2087 2137 <spanset+ 0:1>,
2088 2138 <spanset+ 1:2>>,
2089 2139 <addset
2090 2140 <spanset+ 2:3>,
2091 2141 <addset
2092 2142 <spanset+ 3:4>,
2093 2143 <spanset+ 4:5>>>>
2094 2144 0
2095 2145 1
2096 2146 2
2097 2147 3
2098 2148 4
2099 2149 5
2100 2150
2101 2151 no crash by empty group "()" while optimizing `or` operations
2102 2152
2103 2153 $ try --optimize '0|()'
2104 2154 (or
2105 2155 ('symbol', '0')
2106 2156 (group
2107 2157 None))
2108 2158 * optimized:
2109 2159 (or
2110 2160 ('symbol', '0')
2111 2161 None)
2112 2162 hg: parse error: missing argument
2113 2163 [255]
2114 2164
2115 2165 test that chained `or` operations never eat up stack (issue4624)
2116 2166 (uses `0:1` instead of `0` to avoid future optimization of trivial revisions)
2117 2167
2118 2168 $ hg log -T '{rev}\n' -r `python -c "print '+'.join(['0:1'] * 500)"`
2119 2169 0
2120 2170 1
2121 2171
2122 2172 test that repeated `-r` options never eat up stack (issue4565)
2123 2173 (uses `-r 0::1` to avoid possible optimization at old-style parser)
2124 2174
2125 2175 $ hg log -T '{rev}\n' `python -c "for i in xrange(500): print '-r 0::1 ',"`
2126 2176 0
2127 2177 1
2128 2178
2129 2179 check that conversion to only works
2130 2180 $ try --optimize '::3 - ::1'
2131 2181 (minus
2132 2182 (dagrangepre
2133 2183 ('symbol', '3'))
2134 2184 (dagrangepre
2135 2185 ('symbol', '1')))
2136 2186 * optimized:
2137 2187 (func
2138 2188 ('symbol', 'only')
2139 2189 (list
2140 2190 ('symbol', '3')
2141 2191 ('symbol', '1')))
2142 2192 * set:
2143 2193 <baseset+ [3]>
2144 2194 3
2145 2195 $ try --optimize 'ancestors(1) - ancestors(3)'
2146 2196 (minus
2147 2197 (func
2148 2198 ('symbol', 'ancestors')
2149 2199 ('symbol', '1'))
2150 2200 (func
2151 2201 ('symbol', 'ancestors')
2152 2202 ('symbol', '3')))
2153 2203 * optimized:
2154 2204 (func
2155 2205 ('symbol', 'only')
2156 2206 (list
2157 2207 ('symbol', '1')
2158 2208 ('symbol', '3')))
2159 2209 * set:
2160 2210 <baseset+ []>
2161 2211 $ try --optimize 'not ::2 and ::6'
2162 2212 (and
2163 2213 (not
2164 2214 (dagrangepre
2165 2215 ('symbol', '2')))
2166 2216 (dagrangepre
2167 2217 ('symbol', '6')))
2168 2218 * optimized:
2169 2219 (func
2170 2220 ('symbol', 'only')
2171 2221 (list
2172 2222 ('symbol', '6')
2173 2223 ('symbol', '2')))
2174 2224 * set:
2175 2225 <baseset+ [3, 4, 5, 6]>
2176 2226 3
2177 2227 4
2178 2228 5
2179 2229 6
2180 2230 $ try --optimize 'ancestors(6) and not ancestors(4)'
2181 2231 (and
2182 2232 (func
2183 2233 ('symbol', 'ancestors')
2184 2234 ('symbol', '6'))
2185 2235 (not
2186 2236 (func
2187 2237 ('symbol', 'ancestors')
2188 2238 ('symbol', '4'))))
2189 2239 * optimized:
2190 2240 (func
2191 2241 ('symbol', 'only')
2192 2242 (list
2193 2243 ('symbol', '6')
2194 2244 ('symbol', '4')))
2195 2245 * set:
2196 2246 <baseset+ [3, 5, 6]>
2197 2247 3
2198 2248 5
2199 2249 6
2200 2250
2201 2251 no crash by empty group "()" while optimizing to "only()"
2202 2252
2203 2253 $ try --optimize '::1 and ()'
2204 2254 (and
2205 2255 (dagrangepre
2206 2256 ('symbol', '1'))
2207 2257 (group
2208 2258 None))
2209 2259 * optimized:
2210 2260 (and
2211 2261 None
2212 2262 (func
2213 2263 ('symbol', 'ancestors')
2214 2264 ('symbol', '1')))
2215 2265 hg: parse error: missing argument
2216 2266 [255]
2217 2267
2218 2268 invalid function call should not be optimized to only()
2219 2269
2220 2270 $ log '"ancestors"(6) and not ancestors(4)'
2221 2271 hg: parse error: not a symbol
2222 2272 [255]
2223 2273
2224 2274 $ log 'ancestors(6) and not "ancestors"(4)'
2225 2275 hg: parse error: not a symbol
2226 2276 [255]
2227 2277
2228 2278 we can use patterns when searching for tags
2229 2279
2230 2280 $ log 'tag("1..*")'
2231 2281 abort: tag '1..*' does not exist!
2232 2282 [255]
2233 2283 $ log 'tag("re:1..*")'
2234 2284 6
2235 2285 $ log 'tag("re:[0-9].[0-9]")'
2236 2286 6
2237 2287 $ log 'tag("literal:1.0")'
2238 2288 6
2239 2289 $ log 'tag("re:0..*")'
2240 2290
2241 2291 $ log 'tag(unknown)'
2242 2292 abort: tag 'unknown' does not exist!
2243 2293 [255]
2244 2294 $ log 'tag("re:unknown")'
2245 2295 $ log 'present(tag("unknown"))'
2246 2296 $ log 'present(tag("re:unknown"))'
2247 2297 $ log 'branch(unknown)'
2248 2298 abort: unknown revision 'unknown'!
2249 2299 [255]
2250 2300 $ log 'branch("literal:unknown")'
2251 2301 abort: branch 'unknown' does not exist!
2252 2302 [255]
2253 2303 $ log 'branch("re:unknown")'
2254 2304 $ log 'present(branch("unknown"))'
2255 2305 $ log 'present(branch("re:unknown"))'
2256 2306 $ log 'user(bob)'
2257 2307 2
2258 2308
2259 2309 $ log '4::8'
2260 2310 4
2261 2311 8
2262 2312 $ log '4:8'
2263 2313 4
2264 2314 5
2265 2315 6
2266 2316 7
2267 2317 8
2268 2318
2269 2319 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
2270 2320 4
2271 2321 2
2272 2322 5
2273 2323
2274 2324 $ log 'not 0 and 0:2'
2275 2325 1
2276 2326 2
2277 2327 $ log 'not 1 and 0:2'
2278 2328 0
2279 2329 2
2280 2330 $ log 'not 2 and 0:2'
2281 2331 0
2282 2332 1
2283 2333 $ log '(1 and 2)::'
2284 2334 $ log '(1 and 2):'
2285 2335 $ log '(1 and 2):3'
2286 2336 $ log 'sort(head(), -rev)'
2287 2337 9
2288 2338 7
2289 2339 6
2290 2340 5
2291 2341 4
2292 2342 3
2293 2343 2
2294 2344 1
2295 2345 0
2296 2346 $ log '4::8 - 8'
2297 2347 4
2298 2348
2299 2349 matching() should preserve the order of the input set:
2300 2350
2301 2351 $ log '(2 or 3 or 1) and matching(1 or 2 or 3)'
2302 2352 2
2303 2353 3
2304 2354 1
2305 2355
2306 2356 $ log 'named("unknown")'
2307 2357 abort: namespace 'unknown' does not exist!
2308 2358 [255]
2309 2359 $ log 'named("re:unknown")'
2310 2360 abort: no namespace exists that match 'unknown'!
2311 2361 [255]
2312 2362 $ log 'present(named("unknown"))'
2313 2363 $ log 'present(named("re:unknown"))'
2314 2364
2315 2365 $ log 'tag()'
2316 2366 6
2317 2367 $ log 'named("tags")'
2318 2368 6
2319 2369
2320 2370 issue2437
2321 2371
2322 2372 $ log '3 and p1(5)'
2323 2373 3
2324 2374 $ log '4 and p2(6)'
2325 2375 4
2326 2376 $ log '1 and parents(:2)'
2327 2377 1
2328 2378 $ log '2 and children(1:)'
2329 2379 2
2330 2380 $ log 'roots(all()) or roots(all())'
2331 2381 0
2332 2382 $ hg debugrevspec 'roots(all()) or roots(all())'
2333 2383 0
2334 2384 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
2335 2385 9
2336 2386 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
2337 2387 4
2338 2388
2339 2389 issue2654: report a parse error if the revset was not completely parsed
2340 2390
2341 2391 $ log '1 OR 2'
2342 2392 hg: parse error at 2: invalid token
2343 2393 [255]
2344 2394
2345 2395 or operator should preserve ordering:
2346 2396 $ log 'reverse(2::4) or tip'
2347 2397 4
2348 2398 2
2349 2399 9
2350 2400
2351 2401 parentrevspec
2352 2402
2353 2403 $ log 'merge()^0'
2354 2404 6
2355 2405 $ log 'merge()^'
2356 2406 5
2357 2407 $ log 'merge()^1'
2358 2408 5
2359 2409 $ log 'merge()^2'
2360 2410 4
2361 2411 $ log 'merge()^^'
2362 2412 3
2363 2413 $ log 'merge()^1^'
2364 2414 3
2365 2415 $ log 'merge()^^^'
2366 2416 1
2367 2417
2368 2418 $ log 'merge()~0'
2369 2419 6
2370 2420 $ log 'merge()~1'
2371 2421 5
2372 2422 $ log 'merge()~2'
2373 2423 3
2374 2424 $ log 'merge()~2^1'
2375 2425 1
2376 2426 $ log 'merge()~3'
2377 2427 1
2378 2428
2379 2429 $ log '(-3:tip)^'
2380 2430 4
2381 2431 6
2382 2432 8
2383 2433
2384 2434 $ log 'tip^foo'
2385 2435 hg: parse error: ^ expects a number 0, 1, or 2
2386 2436 [255]
2387 2437
2388 2438 Bogus function gets suggestions
2389 2439 $ log 'add()'
2390 2440 hg: parse error: unknown identifier: add
2391 2441 (did you mean adds?)
2392 2442 [255]
2393 2443 $ log 'added()'
2394 2444 hg: parse error: unknown identifier: added
2395 2445 (did you mean adds?)
2396 2446 [255]
2397 2447 $ log 'remo()'
2398 2448 hg: parse error: unknown identifier: remo
2399 2449 (did you mean one of remote, removes?)
2400 2450 [255]
2401 2451 $ log 'babar()'
2402 2452 hg: parse error: unknown identifier: babar
2403 2453 [255]
2404 2454
2405 2455 Bogus function with a similar internal name doesn't suggest the internal name
2406 2456 $ log 'matches()'
2407 2457 hg: parse error: unknown identifier: matches
2408 2458 (did you mean matching?)
2409 2459 [255]
2410 2460
2411 2461 Undocumented functions aren't suggested as similar either
2412 2462 $ log 'wdir2()'
2413 2463 hg: parse error: unknown identifier: wdir2
2414 2464 [255]
2415 2465
2416 2466 multiple revspecs
2417 2467
2418 2468 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
2419 2469 8
2420 2470 9
2421 2471 4
2422 2472 5
2423 2473 6
2424 2474 7
2425 2475
2426 2476 test usage in revpair (with "+")
2427 2477
2428 2478 (real pair)
2429 2479
2430 2480 $ hg diff -r 'tip^^' -r 'tip'
2431 2481 diff -r 2326846efdab -r 24286f4ae135 .hgtags
2432 2482 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2433 2483 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
2434 2484 @@ -0,0 +1,1 @@
2435 2485 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
2436 2486 $ hg diff -r 'tip^^::tip'
2437 2487 diff -r 2326846efdab -r 24286f4ae135 .hgtags
2438 2488 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2439 2489 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
2440 2490 @@ -0,0 +1,1 @@
2441 2491 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
2442 2492
2443 2493 (single rev)
2444 2494
2445 2495 $ hg diff -r 'tip^' -r 'tip^'
2446 2496 $ hg diff -r 'tip^:tip^'
2447 2497
2448 2498 (single rev that does not looks like a range)
2449 2499
2450 2500 $ hg diff -r 'tip^::tip^ or tip^'
2451 2501 diff -r d5d0dcbdc4d9 .hgtags
2452 2502 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2453 2503 +++ b/.hgtags * (glob)
2454 2504 @@ -0,0 +1,1 @@
2455 2505 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
2456 2506 $ hg diff -r 'tip^ or tip^'
2457 2507 diff -r d5d0dcbdc4d9 .hgtags
2458 2508 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2459 2509 +++ b/.hgtags * (glob)
2460 2510 @@ -0,0 +1,1 @@
2461 2511 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
2462 2512
2463 2513 (no rev)
2464 2514
2465 2515 $ hg diff -r 'author("babar") or author("celeste")'
2466 2516 abort: empty revision range
2467 2517 [255]
2468 2518
2469 2519 aliases:
2470 2520
2471 2521 $ echo '[revsetalias]' >> .hg/hgrc
2472 2522 $ echo 'm = merge()' >> .hg/hgrc
2473 2523 (revset aliases can override builtin revsets)
2474 2524 $ echo 'p2($1) = p1($1)' >> .hg/hgrc
2475 2525 $ echo 'sincem = descendants(m)' >> .hg/hgrc
2476 2526 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
2477 2527 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
2478 2528 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
2479 2529
2480 2530 $ try m
2481 2531 ('symbol', 'm')
2482 2532 * expanded:
2483 2533 (func
2484 2534 ('symbol', 'merge')
2485 2535 None)
2486 2536 * set:
2487 2537 <filteredset
2488 2538 <fullreposet+ 0:9>,
2489 2539 <merge>>
2490 2540 6
2491 2541
2492 2542 $ HGPLAIN=1
2493 2543 $ export HGPLAIN
2494 2544 $ try m
2495 2545 ('symbol', 'm')
2496 2546 abort: unknown revision 'm'!
2497 2547 [255]
2498 2548
2499 2549 $ HGPLAINEXCEPT=revsetalias
2500 2550 $ export HGPLAINEXCEPT
2501 2551 $ try m
2502 2552 ('symbol', 'm')
2503 2553 * expanded:
2504 2554 (func
2505 2555 ('symbol', 'merge')
2506 2556 None)
2507 2557 * set:
2508 2558 <filteredset
2509 2559 <fullreposet+ 0:9>,
2510 2560 <merge>>
2511 2561 6
2512 2562
2513 2563 $ unset HGPLAIN
2514 2564 $ unset HGPLAINEXCEPT
2515 2565
2516 2566 $ try 'p2(.)'
2517 2567 (func
2518 2568 ('symbol', 'p2')
2519 2569 ('symbol', '.'))
2520 2570 * expanded:
2521 2571 (func
2522 2572 ('symbol', 'p1')
2523 2573 ('symbol', '.'))
2524 2574 * set:
2525 2575 <baseset+ [8]>
2526 2576 8
2527 2577
2528 2578 $ HGPLAIN=1
2529 2579 $ export HGPLAIN
2530 2580 $ try 'p2(.)'
2531 2581 (func
2532 2582 ('symbol', 'p2')
2533 2583 ('symbol', '.'))
2534 2584 * set:
2535 2585 <baseset+ []>
2536 2586
2537 2587 $ HGPLAINEXCEPT=revsetalias
2538 2588 $ export HGPLAINEXCEPT
2539 2589 $ try 'p2(.)'
2540 2590 (func
2541 2591 ('symbol', 'p2')
2542 2592 ('symbol', '.'))
2543 2593 * expanded:
2544 2594 (func
2545 2595 ('symbol', 'p1')
2546 2596 ('symbol', '.'))
2547 2597 * set:
2548 2598 <baseset+ [8]>
2549 2599 8
2550 2600
2551 2601 $ unset HGPLAIN
2552 2602 $ unset HGPLAINEXCEPT
2553 2603
2554 2604 test alias recursion
2555 2605
2556 2606 $ try sincem
2557 2607 ('symbol', 'sincem')
2558 2608 * expanded:
2559 2609 (func
2560 2610 ('symbol', 'descendants')
2561 2611 (func
2562 2612 ('symbol', 'merge')
2563 2613 None))
2564 2614 * set:
2565 2615 <addset+
2566 2616 <filteredset
2567 2617 <fullreposet+ 0:9>,
2568 2618 <merge>>,
2569 2619 <generatorset+>>
2570 2620 6
2571 2621 7
2572 2622
2573 2623 test infinite recursion
2574 2624
2575 2625 $ echo 'recurse1 = recurse2' >> .hg/hgrc
2576 2626 $ echo 'recurse2 = recurse1' >> .hg/hgrc
2577 2627 $ try recurse1
2578 2628 ('symbol', 'recurse1')
2579 2629 hg: parse error: infinite expansion of revset alias "recurse1" detected
2580 2630 [255]
2581 2631
2582 2632 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
2583 2633 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
2584 2634 $ try "level2(level1(1, 2), 3)"
2585 2635 (func
2586 2636 ('symbol', 'level2')
2587 2637 (list
2588 2638 (func
2589 2639 ('symbol', 'level1')
2590 2640 (list
2591 2641 ('symbol', '1')
2592 2642 ('symbol', '2')))
2593 2643 ('symbol', '3')))
2594 2644 * expanded:
2595 2645 (or
2596 2646 ('symbol', '3')
2597 2647 (or
2598 2648 ('symbol', '1')
2599 2649 ('symbol', '2')))
2600 2650 * set:
2601 2651 <addset
2602 2652 <baseset [3]>,
2603 2653 <baseset [1, 2]>>
2604 2654 3
2605 2655 1
2606 2656 2
2607 2657
2608 2658 test nesting and variable passing
2609 2659
2610 2660 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
2611 2661 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
2612 2662 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
2613 2663 $ try 'nested(2:5)'
2614 2664 (func
2615 2665 ('symbol', 'nested')
2616 2666 (range
2617 2667 ('symbol', '2')
2618 2668 ('symbol', '5')))
2619 2669 * expanded:
2620 2670 (func
2621 2671 ('symbol', 'max')
2622 2672 (range
2623 2673 ('symbol', '2')
2624 2674 ('symbol', '5')))
2625 2675 * set:
2626 2676 <baseset
2627 2677 <max
2628 2678 <fullreposet+ 0:9>,
2629 2679 <spanset+ 2:5>>>
2630 2680 5
2631 2681
2632 2682 test chained `or` operations are flattened at parsing phase
2633 2683
2634 2684 $ echo 'chainedorops($1, $2, $3) = $1|$2|$3' >> .hg/hgrc
2635 2685 $ try 'chainedorops(0:1, 1:2, 2:3)'
2636 2686 (func
2637 2687 ('symbol', 'chainedorops')
2638 2688 (list
2639 2689 (range
2640 2690 ('symbol', '0')
2641 2691 ('symbol', '1'))
2642 2692 (range
2643 2693 ('symbol', '1')
2644 2694 ('symbol', '2'))
2645 2695 (range
2646 2696 ('symbol', '2')
2647 2697 ('symbol', '3'))))
2648 2698 * expanded:
2649 2699 (or
2650 2700 (range
2651 2701 ('symbol', '0')
2652 2702 ('symbol', '1'))
2653 2703 (range
2654 2704 ('symbol', '1')
2655 2705 ('symbol', '2'))
2656 2706 (range
2657 2707 ('symbol', '2')
2658 2708 ('symbol', '3')))
2659 2709 * set:
2660 2710 <addset
2661 2711 <spanset+ 0:1>,
2662 2712 <addset
2663 2713 <spanset+ 1:2>,
2664 2714 <spanset+ 2:3>>>
2665 2715 0
2666 2716 1
2667 2717 2
2668 2718 3
2669 2719
2670 2720 test variable isolation, variable placeholders are rewritten as string
2671 2721 then parsed and matched again as string. Check they do not leak too
2672 2722 far away.
2673 2723
2674 2724 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
2675 2725 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
2676 2726 $ try 'callinjection(2:5)'
2677 2727 (func
2678 2728 ('symbol', 'callinjection')
2679 2729 (range
2680 2730 ('symbol', '2')
2681 2731 ('symbol', '5')))
2682 2732 * expanded:
2683 2733 (func
2684 2734 ('symbol', 'descendants')
2685 2735 (func
2686 2736 ('symbol', 'max')
2687 2737 ('string', '$1')))
2688 2738 abort: unknown revision '$1'!
2689 2739 [255]
2690 2740
2691 2741 test scope of alias expansion: 'universe' is expanded prior to 'shadowall(0)',
2692 2742 but 'all()' should never be substituded to '0()'.
2693 2743
2694 2744 $ echo 'universe = all()' >> .hg/hgrc
2695 2745 $ echo 'shadowall(all) = all and universe' >> .hg/hgrc
2696 2746 $ try 'shadowall(0)'
2697 2747 (func
2698 2748 ('symbol', 'shadowall')
2699 2749 ('symbol', '0'))
2700 2750 * expanded:
2701 2751 (and
2702 2752 ('symbol', '0')
2703 2753 (func
2704 2754 ('symbol', 'all')
2705 2755 None))
2706 2756 * set:
2707 2757 <filteredset
2708 2758 <baseset [0]>,
2709 2759 <spanset+ 0:9>>
2710 2760 0
2711 2761
2712 2762 test unknown reference:
2713 2763
2714 2764 $ try "unknownref(0)" --config 'revsetalias.unknownref($1)=$1:$2'
2715 2765 (func
2716 2766 ('symbol', 'unknownref')
2717 2767 ('symbol', '0'))
2718 2768 abort: bad definition of revset alias "unknownref": invalid symbol '$2'
2719 2769 [255]
2720 2770
2721 2771 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
2722 2772 ('symbol', 'tip')
2723 2773 warning: bad definition of revset alias "anotherbadone": at 7: not a prefix: end
2724 2774 * set:
2725 2775 <baseset [9]>
2726 2776 9
2727 2777
2728 2778 $ try 'tip'
2729 2779 ('symbol', 'tip')
2730 2780 * set:
2731 2781 <baseset [9]>
2732 2782 9
2733 2783
2734 2784 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
2735 2785 ('symbol', 'tip')
2736 2786 warning: bad declaration of revset alias "bad name": at 4: invalid token
2737 2787 * set:
2738 2788 <baseset [9]>
2739 2789 9
2740 2790 $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc
2741 2791 $ try 'strictreplacing("foo", tip)'
2742 2792 (func
2743 2793 ('symbol', 'strictreplacing')
2744 2794 (list
2745 2795 ('string', 'foo')
2746 2796 ('symbol', 'tip')))
2747 2797 * expanded:
2748 2798 (or
2749 2799 ('symbol', 'tip')
2750 2800 (func
2751 2801 ('symbol', 'desc')
2752 2802 ('string', '$1')))
2753 2803 * set:
2754 2804 <addset
2755 2805 <baseset [9]>,
2756 2806 <filteredset
2757 2807 <fullreposet+ 0:9>,
2758 2808 <desc '$1'>>>
2759 2809 9
2760 2810
2761 2811 $ try 'd(2:5)'
2762 2812 (func
2763 2813 ('symbol', 'd')
2764 2814 (range
2765 2815 ('symbol', '2')
2766 2816 ('symbol', '5')))
2767 2817 * expanded:
2768 2818 (func
2769 2819 ('symbol', 'reverse')
2770 2820 (func
2771 2821 ('symbol', 'sort')
2772 2822 (list
2773 2823 (range
2774 2824 ('symbol', '2')
2775 2825 ('symbol', '5'))
2776 2826 ('symbol', 'date'))))
2777 2827 * set:
2778 2828 <baseset [4, 5, 3, 2]>
2779 2829 4
2780 2830 5
2781 2831 3
2782 2832 2
2783 2833 $ try 'rs(2 or 3, date)'
2784 2834 (func
2785 2835 ('symbol', 'rs')
2786 2836 (list
2787 2837 (or
2788 2838 ('symbol', '2')
2789 2839 ('symbol', '3'))
2790 2840 ('symbol', 'date')))
2791 2841 * expanded:
2792 2842 (func
2793 2843 ('symbol', 'reverse')
2794 2844 (func
2795 2845 ('symbol', 'sort')
2796 2846 (list
2797 2847 (or
2798 2848 ('symbol', '2')
2799 2849 ('symbol', '3'))
2800 2850 ('symbol', 'date'))))
2801 2851 * set:
2802 2852 <baseset [3, 2]>
2803 2853 3
2804 2854 2
2805 2855 $ try 'rs()'
2806 2856 (func
2807 2857 ('symbol', 'rs')
2808 2858 None)
2809 2859 hg: parse error: invalid number of arguments: 0
2810 2860 [255]
2811 2861 $ try 'rs(2)'
2812 2862 (func
2813 2863 ('symbol', 'rs')
2814 2864 ('symbol', '2'))
2815 2865 hg: parse error: invalid number of arguments: 1
2816 2866 [255]
2817 2867 $ try 'rs(2, data, 7)'
2818 2868 (func
2819 2869 ('symbol', 'rs')
2820 2870 (list
2821 2871 ('symbol', '2')
2822 2872 ('symbol', 'data')
2823 2873 ('symbol', '7')))
2824 2874 hg: parse error: invalid number of arguments: 3
2825 2875 [255]
2826 2876 $ try 'rs4(2 or 3, x, x, date)'
2827 2877 (func
2828 2878 ('symbol', 'rs4')
2829 2879 (list
2830 2880 (or
2831 2881 ('symbol', '2')
2832 2882 ('symbol', '3'))
2833 2883 ('symbol', 'x')
2834 2884 ('symbol', 'x')
2835 2885 ('symbol', 'date')))
2836 2886 * expanded:
2837 2887 (func
2838 2888 ('symbol', 'reverse')
2839 2889 (func
2840 2890 ('symbol', 'sort')
2841 2891 (list
2842 2892 (or
2843 2893 ('symbol', '2')
2844 2894 ('symbol', '3'))
2845 2895 ('symbol', 'date'))))
2846 2896 * set:
2847 2897 <baseset [3, 2]>
2848 2898 3
2849 2899 2
2850 2900
2851 2901 issue4553: check that revset aliases override existing hash prefix
2852 2902
2853 2903 $ hg log -qr e
2854 2904 6:e0cc66ef77e8
2855 2905
2856 2906 $ hg log -qr e --config revsetalias.e="all()"
2857 2907 0:2785f51eece5
2858 2908 1:d75937da8da0
2859 2909 2:5ed5505e9f1c
2860 2910 3:8528aa5637f2
2861 2911 4:2326846efdab
2862 2912 5:904fa392b941
2863 2913 6:e0cc66ef77e8
2864 2914 7:013af1973af4
2865 2915 8:d5d0dcbdc4d9
2866 2916 9:24286f4ae135
2867 2917
2868 2918 $ hg log -qr e: --config revsetalias.e="0"
2869 2919 0:2785f51eece5
2870 2920 1:d75937da8da0
2871 2921 2:5ed5505e9f1c
2872 2922 3:8528aa5637f2
2873 2923 4:2326846efdab
2874 2924 5:904fa392b941
2875 2925 6:e0cc66ef77e8
2876 2926 7:013af1973af4
2877 2927 8:d5d0dcbdc4d9
2878 2928 9:24286f4ae135
2879 2929
2880 2930 $ hg log -qr :e --config revsetalias.e="9"
2881 2931 0:2785f51eece5
2882 2932 1:d75937da8da0
2883 2933 2:5ed5505e9f1c
2884 2934 3:8528aa5637f2
2885 2935 4:2326846efdab
2886 2936 5:904fa392b941
2887 2937 6:e0cc66ef77e8
2888 2938 7:013af1973af4
2889 2939 8:d5d0dcbdc4d9
2890 2940 9:24286f4ae135
2891 2941
2892 2942 $ hg log -qr e:
2893 2943 6:e0cc66ef77e8
2894 2944 7:013af1973af4
2895 2945 8:d5d0dcbdc4d9
2896 2946 9:24286f4ae135
2897 2947
2898 2948 $ hg log -qr :e
2899 2949 0:2785f51eece5
2900 2950 1:d75937da8da0
2901 2951 2:5ed5505e9f1c
2902 2952 3:8528aa5637f2
2903 2953 4:2326846efdab
2904 2954 5:904fa392b941
2905 2955 6:e0cc66ef77e8
2906 2956
2907 2957 issue2549 - correct optimizations
2908 2958
2909 2959 $ try 'limit(1 or 2 or 3, 2) and not 2'
2910 2960 (and
2911 2961 (func
2912 2962 ('symbol', 'limit')
2913 2963 (list
2914 2964 (or
2915 2965 ('symbol', '1')
2916 2966 ('symbol', '2')
2917 2967 ('symbol', '3'))
2918 2968 ('symbol', '2')))
2919 2969 (not
2920 2970 ('symbol', '2')))
2921 2971 * set:
2922 2972 <filteredset
2923 2973 <baseset
2924 2974 <limit n=2, offset=0,
2925 2975 <fullreposet+ 0:9>,
2926 2976 <baseset [1, 2, 3]>>>,
2927 2977 <not
2928 2978 <baseset [2]>>>
2929 2979 1
2930 2980 $ try 'max(1 or 2) and not 2'
2931 2981 (and
2932 2982 (func
2933 2983 ('symbol', 'max')
2934 2984 (or
2935 2985 ('symbol', '1')
2936 2986 ('symbol', '2')))
2937 2987 (not
2938 2988 ('symbol', '2')))
2939 2989 * set:
2940 2990 <filteredset
2941 2991 <baseset
2942 2992 <max
2943 2993 <fullreposet+ 0:9>,
2944 2994 <baseset [1, 2]>>>,
2945 2995 <not
2946 2996 <baseset [2]>>>
2947 2997 $ try 'min(1 or 2) and not 1'
2948 2998 (and
2949 2999 (func
2950 3000 ('symbol', 'min')
2951 3001 (or
2952 3002 ('symbol', '1')
2953 3003 ('symbol', '2')))
2954 3004 (not
2955 3005 ('symbol', '1')))
2956 3006 * set:
2957 3007 <filteredset
2958 3008 <baseset
2959 3009 <min
2960 3010 <fullreposet+ 0:9>,
2961 3011 <baseset [1, 2]>>>,
2962 3012 <not
2963 3013 <baseset [1]>>>
2964 3014 $ try 'last(1 or 2, 1) and not 2'
2965 3015 (and
2966 3016 (func
2967 3017 ('symbol', 'last')
2968 3018 (list
2969 3019 (or
2970 3020 ('symbol', '1')
2971 3021 ('symbol', '2'))
2972 3022 ('symbol', '1')))
2973 3023 (not
2974 3024 ('symbol', '2')))
2975 3025 * set:
2976 3026 <filteredset
2977 3027 <baseset
2978 3028 <last n=1,
2979 3029 <fullreposet+ 0:9>,
2980 3030 <baseset [2, 1]>>>,
2981 3031 <not
2982 3032 <baseset [2]>>>
2983 3033
2984 3034 issue4289 - ordering of built-ins
2985 3035 $ hg log -M -q -r 3:2
2986 3036 3:8528aa5637f2
2987 3037 2:5ed5505e9f1c
2988 3038
2989 3039 test revsets started with 40-chars hash (issue3669)
2990 3040
2991 3041 $ ISSUE3669_TIP=`hg tip --template '{node}'`
2992 3042 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
2993 3043 9
2994 3044 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
2995 3045 8
2996 3046
2997 3047 test or-ed indirect predicates (issue3775)
2998 3048
2999 3049 $ log '6 or 6^1' | sort
3000 3050 5
3001 3051 6
3002 3052 $ log '6^1 or 6' | sort
3003 3053 5
3004 3054 6
3005 3055 $ log '4 or 4~1' | sort
3006 3056 2
3007 3057 4
3008 3058 $ log '4~1 or 4' | sort
3009 3059 2
3010 3060 4
3011 3061 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
3012 3062 0
3013 3063 1
3014 3064 2
3015 3065 3
3016 3066 4
3017 3067 5
3018 3068 6
3019 3069 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
3020 3070 0
3021 3071 1
3022 3072 2
3023 3073 3
3024 3074 4
3025 3075 5
3026 3076 6
3027 3077
3028 3078 tests for 'remote()' predicate:
3029 3079 #. (csets in remote) (id) (remote)
3030 3080 1. less than local current branch "default"
3031 3081 2. same with local specified "default"
3032 3082 3. more than local specified specified
3033 3083
3034 3084 $ hg clone --quiet -U . ../remote3
3035 3085 $ cd ../remote3
3036 3086 $ hg update -q 7
3037 3087 $ echo r > r
3038 3088 $ hg ci -Aqm 10
3039 3089 $ log 'remote()'
3040 3090 7
3041 3091 $ log 'remote("a-b-c-")'
3042 3092 2
3043 3093 $ cd ../repo
3044 3094 $ log 'remote(".a.b.c.", "../remote3")'
3045 3095
3046 3096 tests for concatenation of strings/symbols by "##"
3047 3097
3048 3098 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
3049 3099 (_concat
3050 3100 (_concat
3051 3101 (_concat
3052 3102 ('symbol', '278')
3053 3103 ('string', '5f5'))
3054 3104 ('symbol', '1ee'))
3055 3105 ('string', 'ce5'))
3056 3106 * concatenated:
3057 3107 ('string', '2785f51eece5')
3058 3108 * set:
3059 3109 <baseset [0]>
3060 3110 0
3061 3111
3062 3112 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
3063 3113 $ try "cat4(278, '5f5', 1ee, 'ce5')"
3064 3114 (func
3065 3115 ('symbol', 'cat4')
3066 3116 (list
3067 3117 ('symbol', '278')
3068 3118 ('string', '5f5')
3069 3119 ('symbol', '1ee')
3070 3120 ('string', 'ce5')))
3071 3121 * expanded:
3072 3122 (_concat
3073 3123 (_concat
3074 3124 (_concat
3075 3125 ('symbol', '278')
3076 3126 ('string', '5f5'))
3077 3127 ('symbol', '1ee'))
3078 3128 ('string', 'ce5'))
3079 3129 * concatenated:
3080 3130 ('string', '2785f51eece5')
3081 3131 * set:
3082 3132 <baseset [0]>
3083 3133 0
3084 3134
3085 3135 (check concatenation in alias nesting)
3086 3136
3087 3137 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
3088 3138 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
3089 3139 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
3090 3140 0
3091 3141
3092 3142 (check operator priority)
3093 3143
3094 3144 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
3095 3145 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
3096 3146 0
3097 3147 4
3098 3148
3099 3149 $ cd ..
3100 3150
3101 3151 prepare repository that has "default" branches of multiple roots
3102 3152
3103 3153 $ hg init namedbranch
3104 3154 $ cd namedbranch
3105 3155
3106 3156 $ echo default0 >> a
3107 3157 $ hg ci -Aqm0
3108 3158 $ echo default1 >> a
3109 3159 $ hg ci -m1
3110 3160
3111 3161 $ hg branch -q stable
3112 3162 $ echo stable2 >> a
3113 3163 $ hg ci -m2
3114 3164 $ echo stable3 >> a
3115 3165 $ hg ci -m3
3116 3166
3117 3167 $ hg update -q null
3118 3168 $ echo default4 >> a
3119 3169 $ hg ci -Aqm4
3120 3170 $ echo default5 >> a
3121 3171 $ hg ci -m5
3122 3172
3123 3173 "null" revision belongs to "default" branch (issue4683)
3124 3174
3125 3175 $ log 'branch(null)'
3126 3176 0
3127 3177 1
3128 3178 4
3129 3179 5
3130 3180
3131 3181 "null" revision belongs to "default" branch, but it shouldn't appear in set
3132 3182 unless explicitly specified (issue4682)
3133 3183
3134 3184 $ log 'children(branch(default))'
3135 3185 1
3136 3186 2
3137 3187 5
3138 3188
3139 3189 $ cd ..
3140 3190
3141 3191 test author/desc/keyword in problematic encoding
3142 3192 # unicode: cp932:
3143 3193 # u30A2 0x83 0x41(= 'A')
3144 3194 # u30C2 0x83 0x61(= 'a')
3145 3195
3146 3196 $ hg init problematicencoding
3147 3197 $ cd problematicencoding
3148 3198
3149 3199 $ python > setup.sh <<EOF
3150 3200 > print u'''
3151 3201 > echo a > text
3152 3202 > hg add text
3153 3203 > hg --encoding utf-8 commit -u '\u30A2' -m none
3154 3204 > echo b > text
3155 3205 > hg --encoding utf-8 commit -u '\u30C2' -m none
3156 3206 > echo c > text
3157 3207 > hg --encoding utf-8 commit -u none -m '\u30A2'
3158 3208 > echo d > text
3159 3209 > hg --encoding utf-8 commit -u none -m '\u30C2'
3160 3210 > '''.encode('utf-8')
3161 3211 > EOF
3162 3212 $ sh < setup.sh
3163 3213
3164 3214 test in problematic encoding
3165 3215 $ python > test.sh <<EOF
3166 3216 > print u'''
3167 3217 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
3168 3218 > echo ====
3169 3219 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
3170 3220 > echo ====
3171 3221 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
3172 3222 > echo ====
3173 3223 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
3174 3224 > echo ====
3175 3225 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
3176 3226 > echo ====
3177 3227 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
3178 3228 > '''.encode('cp932')
3179 3229 > EOF
3180 3230 $ sh < test.sh
3181 3231 0
3182 3232 ====
3183 3233 1
3184 3234 ====
3185 3235 2
3186 3236 ====
3187 3237 3
3188 3238 ====
3189 3239 0
3190 3240 2
3191 3241 ====
3192 3242 1
3193 3243 3
3194 3244
3195 3245 test error message of bad revset
3196 3246 $ hg log -r 'foo\\'
3197 3247 hg: parse error at 3: syntax error in revset 'foo\\'
3198 3248 [255]
3199 3249
3200 3250 $ cd ..
3201 3251
3202 3252 Test that revset predicate of extension isn't loaded at failure of
3203 3253 loading it
3204 3254
3205 3255 $ cd repo
3206 3256
3207 3257 $ cat <<EOF > $TESTTMP/custompredicate.py
3208 3258 > from mercurial import error, registrar, revset
3209 3259 >
3210 3260 > revsetpredicate = registrar.revsetpredicate()
3211 3261 >
3212 3262 > @revsetpredicate('custom1()')
3213 3263 > def custom1(repo, subset, x):
3214 3264 > return revset.baseset([1])
3215 3265 >
3216 3266 > raise error.Abort('intentional failure of loading extension')
3217 3267 > EOF
3218 3268 $ cat <<EOF > .hg/hgrc
3219 3269 > [extensions]
3220 3270 > custompredicate = $TESTTMP/custompredicate.py
3221 3271 > EOF
3222 3272
3223 3273 $ hg debugrevspec "custom1()"
3224 3274 *** failed to import extension custompredicate from $TESTTMP/custompredicate.py: intentional failure of loading extension
3225 3275 hg: parse error: unknown identifier: custom1
3226 3276 [255]
3227 3277
3228 3278 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now