##// END OF EJS Templates
bisect: move 'printresult' in the 'hbisect' module...
Pierre-Yves David -
r30067:6e88cd06 default
parent child Browse files
Show More
@@ -1,7381 +1,7356 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.isplain():
445 445 def makefunc(get, fmt):
446 446 return lambda x: fmt(get(x))
447 447 else:
448 448 def makefunc(get, fmt):
449 449 return get
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.isplain():
480 480 sizes = [encoding.colwidth(x) for x in l]
481 481 ml = max(sizes)
482 482 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
483 483 else:
484 484 formats.append(['%s' for x in l])
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 def print_result(nodes, good):
839 displayer = cmdutil.show_changeset(ui, repo, {})
840 if len(nodes) == 1:
841 # narrowed it down to a single revision
842 if good:
843 ui.write(_("The first good revision is:\n"))
844 else:
845 ui.write(_("The first bad revision is:\n"))
846 displayer.show(repo[nodes[0]])
847 extendnode = hbisect.extendrange(repo, state, nodes, good)
848 if extendnode is not None:
849 ui.write(_('Not all ancestors of this changeset have been'
850 ' checked.\nUse bisect --extend to continue the '
851 'bisection from\nthe common ancestor, %s.\n')
852 % extendnode)
853 else:
854 # multiple possible revisions
855 if good:
856 ui.write(_("Due to skipped revisions, the first "
857 "good revision could be any of:\n"))
858 else:
859 ui.write(_("Due to skipped revisions, the first "
860 "bad revision could be any of:\n"))
861 for n in nodes:
862 displayer.show(repo[n])
863 displayer.close()
864
865 838 def check_state(state, interactive=True):
866 839 if not state['good'] or not state['bad']:
867 840 if (good or bad or skip or reset) and interactive:
868 841 return
869 842 if not state['good']:
870 843 raise error.Abort(_('cannot bisect (no known good revisions)'))
871 844 else:
872 845 raise error.Abort(_('cannot bisect (no known bad revisions)'))
873 846 return True
874 847
875 848 # backward compatibility
876 849 if rev in "good bad reset init".split():
877 850 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
878 851 cmd, rev, extra = rev, extra, None
879 852 if cmd == "good":
880 853 good = True
881 854 elif cmd == "bad":
882 855 bad = True
883 856 else:
884 857 reset = True
885 858 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
886 859 raise error.Abort(_('incompatible arguments'))
887 860
888 861 cmdutil.checkunfinished(repo)
889 862
890 863 if reset:
891 864 hbisect.resetstate(repo)
892 865 return
893 866
894 867 state = hbisect.load_state(repo)
895 868
896 869 if command:
897 870 changesets = 1
898 871 if noupdate:
899 872 try:
900 873 node = state['current'][0]
901 874 except LookupError:
902 875 raise error.Abort(_('current bisect revision is unknown - '
903 876 'start a new bisect to fix'))
904 877 else:
905 878 node, p2 = repo.dirstate.parents()
906 879 if p2 != nullid:
907 880 raise error.Abort(_('current bisect revision is a merge'))
908 881 try:
909 882 while changesets:
910 883 # update state
911 884 state['current'] = [node]
912 885 hbisect.save_state(repo, state)
913 886 status = ui.system(command, environ={'HG_NODE': hex(node)})
914 887 if status == 125:
915 888 transition = "skip"
916 889 elif status == 0:
917 890 transition = "good"
918 891 # status < 0 means process was killed
919 892 elif status == 127:
920 893 raise error.Abort(_("failed to execute %s") % command)
921 894 elif status < 0:
922 895 raise error.Abort(_("%s killed") % command)
923 896 else:
924 897 transition = "bad"
925 898 ctx = scmutil.revsingle(repo, rev, node)
926 899 rev = None # clear for future iterations
927 900 state[transition].append(ctx.node())
928 901 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
929 902 check_state(state, interactive=False)
930 903 # bisect
931 904 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
932 905 # update to next check
933 906 node = nodes[0]
934 907 if not noupdate:
935 908 cmdutil.bailifchanged(repo)
936 909 hg.clean(repo, node, show_stats=False)
937 910 finally:
938 911 state['current'] = [node]
939 912 hbisect.save_state(repo, state)
940 print_result(nodes, bgood)
913 displayer = cmdutil.show_changeset(ui, repo, {})
914 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
941 915 return
942 916
943 917 # update state
944 918
945 919 if rev:
946 920 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
947 921 else:
948 922 nodes = [repo.lookup('.')]
949 923
950 924 if good or bad or skip:
951 925 if good:
952 926 state['good'] += nodes
953 927 elif bad:
954 928 state['bad'] += nodes
955 929 elif skip:
956 930 state['skip'] += nodes
957 931 hbisect.save_state(repo, state)
958 932
959 933 if not check_state(state):
960 934 return
961 935
962 936 # actually bisect
963 937 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
964 938 if extend:
965 939 if not changesets:
966 940 extendnode = hbisect.extendrange(repo, state, nodes, good)
967 941 if extendnode is not None:
968 942 ui.write(_("Extending search to changeset %d:%s\n")
969 943 % (extendnode.rev(), extendnode))
970 944 state['current'] = [extendnode.node()]
971 945 hbisect.save_state(repo, state)
972 946 if noupdate:
973 947 return
974 948 cmdutil.bailifchanged(repo)
975 949 return hg.clean(repo, extendnode.node())
976 950 raise error.Abort(_("nothing to extend"))
977 951
978 952 if changesets == 0:
979 print_result(nodes, good)
953 displayer = cmdutil.show_changeset(ui, repo, {})
954 hbisect.printresult(ui, repo, state, displayer, nodes, good)
980 955 else:
981 956 assert len(nodes) == 1 # only a single node can be tested next
982 957 node = nodes[0]
983 958 # compute the approximate number of remaining tests
984 959 tests, size = 0, 2
985 960 while size <= changesets:
986 961 tests, size = tests + 1, size * 2
987 962 rev = repo.changelog.rev(node)
988 963 ui.write(_("Testing changeset %d:%s "
989 964 "(%d changesets remaining, ~%d tests)\n")
990 965 % (rev, short(node), changesets, tests))
991 966 state['current'] = [node]
992 967 hbisect.save_state(repo, state)
993 968 if not noupdate:
994 969 cmdutil.bailifchanged(repo)
995 970 return hg.clean(repo, node)
996 971
997 972 @command('bookmarks|bookmark',
998 973 [('f', 'force', False, _('force')),
999 974 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
1000 975 ('d', 'delete', False, _('delete a given bookmark')),
1001 976 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
1002 977 ('i', 'inactive', False, _('mark a bookmark inactive')),
1003 978 ] + formatteropts,
1004 979 _('hg bookmarks [OPTIONS]... [NAME]...'))
1005 980 def bookmark(ui, repo, *names, **opts):
1006 981 '''create a new bookmark or list existing bookmarks
1007 982
1008 983 Bookmarks are labels on changesets to help track lines of development.
1009 984 Bookmarks are unversioned and can be moved, renamed and deleted.
1010 985 Deleting or moving a bookmark has no effect on the associated changesets.
1011 986
1012 987 Creating or updating to a bookmark causes it to be marked as 'active'.
1013 988 The active bookmark is indicated with a '*'.
1014 989 When a commit is made, the active bookmark will advance to the new commit.
1015 990 A plain :hg:`update` will also advance an active bookmark, if possible.
1016 991 Updating away from a bookmark will cause it to be deactivated.
1017 992
1018 993 Bookmarks can be pushed and pulled between repositories (see
1019 994 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1020 995 diverged, a new 'divergent bookmark' of the form 'name@path' will
1021 996 be created. Using :hg:`merge` will resolve the divergence.
1022 997
1023 998 A bookmark named '@' has the special property that :hg:`clone` will
1024 999 check it out by default if it exists.
1025 1000
1026 1001 .. container:: verbose
1027 1002
1028 1003 Examples:
1029 1004
1030 1005 - create an active bookmark for a new line of development::
1031 1006
1032 1007 hg book new-feature
1033 1008
1034 1009 - create an inactive bookmark as a place marker::
1035 1010
1036 1011 hg book -i reviewed
1037 1012
1038 1013 - create an inactive bookmark on another changeset::
1039 1014
1040 1015 hg book -r .^ tested
1041 1016
1042 1017 - rename bookmark turkey to dinner::
1043 1018
1044 1019 hg book -m turkey dinner
1045 1020
1046 1021 - move the '@' bookmark from another branch::
1047 1022
1048 1023 hg book -f @
1049 1024 '''
1050 1025 force = opts.get('force')
1051 1026 rev = opts.get('rev')
1052 1027 delete = opts.get('delete')
1053 1028 rename = opts.get('rename')
1054 1029 inactive = opts.get('inactive')
1055 1030
1056 1031 def checkformat(mark):
1057 1032 mark = mark.strip()
1058 1033 if not mark:
1059 1034 raise error.Abort(_("bookmark names cannot consist entirely of "
1060 1035 "whitespace"))
1061 1036 scmutil.checknewlabel(repo, mark, 'bookmark')
1062 1037 return mark
1063 1038
1064 1039 def checkconflict(repo, mark, cur, force=False, target=None):
1065 1040 if mark in marks and not force:
1066 1041 if target:
1067 1042 if marks[mark] == target and target == cur:
1068 1043 # re-activating a bookmark
1069 1044 return
1070 1045 anc = repo.changelog.ancestors([repo[target].rev()])
1071 1046 bmctx = repo[marks[mark]]
1072 1047 divs = [repo[b].node() for b in marks
1073 1048 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1074 1049
1075 1050 # allow resolving a single divergent bookmark even if moving
1076 1051 # the bookmark across branches when a revision is specified
1077 1052 # that contains a divergent bookmark
1078 1053 if bmctx.rev() not in anc and target in divs:
1079 1054 bookmarks.deletedivergent(repo, [target], mark)
1080 1055 return
1081 1056
1082 1057 deletefrom = [b for b in divs
1083 1058 if repo[b].rev() in anc or b == target]
1084 1059 bookmarks.deletedivergent(repo, deletefrom, mark)
1085 1060 if bookmarks.validdest(repo, bmctx, repo[target]):
1086 1061 ui.status(_("moving bookmark '%s' forward from %s\n") %
1087 1062 (mark, short(bmctx.node())))
1088 1063 return
1089 1064 raise error.Abort(_("bookmark '%s' already exists "
1090 1065 "(use -f to force)") % mark)
1091 1066 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1092 1067 and not force):
1093 1068 raise error.Abort(
1094 1069 _("a bookmark cannot have the name of an existing branch"))
1095 1070
1096 1071 if delete and rename:
1097 1072 raise error.Abort(_("--delete and --rename are incompatible"))
1098 1073 if delete and rev:
1099 1074 raise error.Abort(_("--rev is incompatible with --delete"))
1100 1075 if rename and rev:
1101 1076 raise error.Abort(_("--rev is incompatible with --rename"))
1102 1077 if not names and (delete or rev):
1103 1078 raise error.Abort(_("bookmark name required"))
1104 1079
1105 1080 if delete or rename or names or inactive:
1106 1081 wlock = lock = tr = None
1107 1082 try:
1108 1083 wlock = repo.wlock()
1109 1084 lock = repo.lock()
1110 1085 cur = repo.changectx('.').node()
1111 1086 marks = repo._bookmarks
1112 1087 if delete:
1113 1088 tr = repo.transaction('bookmark')
1114 1089 for mark in names:
1115 1090 if mark not in marks:
1116 1091 raise error.Abort(_("bookmark '%s' does not exist") %
1117 1092 mark)
1118 1093 if mark == repo._activebookmark:
1119 1094 bookmarks.deactivate(repo)
1120 1095 del marks[mark]
1121 1096
1122 1097 elif rename:
1123 1098 tr = repo.transaction('bookmark')
1124 1099 if not names:
1125 1100 raise error.Abort(_("new bookmark name required"))
1126 1101 elif len(names) > 1:
1127 1102 raise error.Abort(_("only one new bookmark name allowed"))
1128 1103 mark = checkformat(names[0])
1129 1104 if rename not in marks:
1130 1105 raise error.Abort(_("bookmark '%s' does not exist")
1131 1106 % rename)
1132 1107 checkconflict(repo, mark, cur, force)
1133 1108 marks[mark] = marks[rename]
1134 1109 if repo._activebookmark == rename and not inactive:
1135 1110 bookmarks.activate(repo, mark)
1136 1111 del marks[rename]
1137 1112 elif names:
1138 1113 tr = repo.transaction('bookmark')
1139 1114 newact = None
1140 1115 for mark in names:
1141 1116 mark = checkformat(mark)
1142 1117 if newact is None:
1143 1118 newact = mark
1144 1119 if inactive and mark == repo._activebookmark:
1145 1120 bookmarks.deactivate(repo)
1146 1121 return
1147 1122 tgt = cur
1148 1123 if rev:
1149 1124 tgt = scmutil.revsingle(repo, rev).node()
1150 1125 checkconflict(repo, mark, cur, force, tgt)
1151 1126 marks[mark] = tgt
1152 1127 if not inactive and cur == marks[newact] and not rev:
1153 1128 bookmarks.activate(repo, newact)
1154 1129 elif cur != tgt and newact == repo._activebookmark:
1155 1130 bookmarks.deactivate(repo)
1156 1131 elif inactive:
1157 1132 if len(marks) == 0:
1158 1133 ui.status(_("no bookmarks set\n"))
1159 1134 elif not repo._activebookmark:
1160 1135 ui.status(_("no active bookmark\n"))
1161 1136 else:
1162 1137 bookmarks.deactivate(repo)
1163 1138 if tr is not None:
1164 1139 marks.recordchange(tr)
1165 1140 tr.close()
1166 1141 finally:
1167 1142 lockmod.release(tr, lock, wlock)
1168 1143 else: # show bookmarks
1169 1144 fm = ui.formatter('bookmarks', opts)
1170 1145 hexfn = fm.hexfunc
1171 1146 marks = repo._bookmarks
1172 1147 if len(marks) == 0 and fm.isplain():
1173 1148 ui.status(_("no bookmarks set\n"))
1174 1149 for bmark, n in sorted(marks.iteritems()):
1175 1150 active = repo._activebookmark
1176 1151 if bmark == active:
1177 1152 prefix, label = '*', activebookmarklabel
1178 1153 else:
1179 1154 prefix, label = ' ', ''
1180 1155
1181 1156 fm.startitem()
1182 1157 if not ui.quiet:
1183 1158 fm.plain(' %s ' % prefix, label=label)
1184 1159 fm.write('bookmark', '%s', bmark, label=label)
1185 1160 pad = " " * (25 - encoding.colwidth(bmark))
1186 1161 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1187 1162 repo.changelog.rev(n), hexfn(n), label=label)
1188 1163 fm.data(active=(bmark == active))
1189 1164 fm.plain('\n')
1190 1165 fm.end()
1191 1166
1192 1167 @command('branch',
1193 1168 [('f', 'force', None,
1194 1169 _('set branch name even if it shadows an existing branch')),
1195 1170 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1196 1171 _('[-fC] [NAME]'))
1197 1172 def branch(ui, repo, label=None, **opts):
1198 1173 """set or show the current branch name
1199 1174
1200 1175 .. note::
1201 1176
1202 1177 Branch names are permanent and global. Use :hg:`bookmark` to create a
1203 1178 light-weight bookmark instead. See :hg:`help glossary` for more
1204 1179 information about named branches and bookmarks.
1205 1180
1206 1181 With no argument, show the current branch name. With one argument,
1207 1182 set the working directory branch name (the branch will not exist
1208 1183 in the repository until the next commit). Standard practice
1209 1184 recommends that primary development take place on the 'default'
1210 1185 branch.
1211 1186
1212 1187 Unless -f/--force is specified, branch will not let you set a
1213 1188 branch name that already exists.
1214 1189
1215 1190 Use -C/--clean to reset the working directory branch to that of
1216 1191 the parent of the working directory, negating a previous branch
1217 1192 change.
1218 1193
1219 1194 Use the command :hg:`update` to switch to an existing branch. Use
1220 1195 :hg:`commit --close-branch` to mark this branch head as closed.
1221 1196 When all heads of a branch are closed, the branch will be
1222 1197 considered closed.
1223 1198
1224 1199 Returns 0 on success.
1225 1200 """
1226 1201 if label:
1227 1202 label = label.strip()
1228 1203
1229 1204 if not opts.get('clean') and not label:
1230 1205 ui.write("%s\n" % repo.dirstate.branch())
1231 1206 return
1232 1207
1233 1208 with repo.wlock():
1234 1209 if opts.get('clean'):
1235 1210 label = repo[None].p1().branch()
1236 1211 repo.dirstate.setbranch(label)
1237 1212 ui.status(_('reset working directory to branch %s\n') % label)
1238 1213 elif label:
1239 1214 if not opts.get('force') and label in repo.branchmap():
1240 1215 if label not in [p.branch() for p in repo[None].parents()]:
1241 1216 raise error.Abort(_('a branch of the same name already'
1242 1217 ' exists'),
1243 1218 # i18n: "it" refers to an existing branch
1244 1219 hint=_("use 'hg update' to switch to it"))
1245 1220 scmutil.checknewlabel(repo, label, 'branch')
1246 1221 repo.dirstate.setbranch(label)
1247 1222 ui.status(_('marked working directory as branch %s\n') % label)
1248 1223
1249 1224 # find any open named branches aside from default
1250 1225 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1251 1226 if n != "default" and not c]
1252 1227 if not others:
1253 1228 ui.status(_('(branches are permanent and global, '
1254 1229 'did you want a bookmark?)\n'))
1255 1230
1256 1231 @command('branches',
1257 1232 [('a', 'active', False,
1258 1233 _('show only branches that have unmerged heads (DEPRECATED)')),
1259 1234 ('c', 'closed', False, _('show normal and closed branches')),
1260 1235 ] + formatteropts,
1261 1236 _('[-c]'))
1262 1237 def branches(ui, repo, active=False, closed=False, **opts):
1263 1238 """list repository named branches
1264 1239
1265 1240 List the repository's named branches, indicating which ones are
1266 1241 inactive. If -c/--closed is specified, also list branches which have
1267 1242 been marked closed (see :hg:`commit --close-branch`).
1268 1243
1269 1244 Use the command :hg:`update` to switch to an existing branch.
1270 1245
1271 1246 Returns 0.
1272 1247 """
1273 1248
1274 1249 fm = ui.formatter('branches', opts)
1275 1250 hexfunc = fm.hexfunc
1276 1251
1277 1252 allheads = set(repo.heads())
1278 1253 branches = []
1279 1254 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1280 1255 isactive = not isclosed and bool(set(heads) & allheads)
1281 1256 branches.append((tag, repo[tip], isactive, not isclosed))
1282 1257 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1283 1258 reverse=True)
1284 1259
1285 1260 for tag, ctx, isactive, isopen in branches:
1286 1261 if active and not isactive:
1287 1262 continue
1288 1263 if isactive:
1289 1264 label = 'branches.active'
1290 1265 notice = ''
1291 1266 elif not isopen:
1292 1267 if not closed:
1293 1268 continue
1294 1269 label = 'branches.closed'
1295 1270 notice = _(' (closed)')
1296 1271 else:
1297 1272 label = 'branches.inactive'
1298 1273 notice = _(' (inactive)')
1299 1274 current = (tag == repo.dirstate.branch())
1300 1275 if current:
1301 1276 label = 'branches.current'
1302 1277
1303 1278 fm.startitem()
1304 1279 fm.write('branch', '%s', tag, label=label)
1305 1280 rev = ctx.rev()
1306 1281 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1307 1282 fmt = ' ' * padsize + ' %d:%s'
1308 1283 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1309 1284 label='log.changeset changeset.%s' % ctx.phasestr())
1310 1285 fm.data(active=isactive, closed=not isopen, current=current)
1311 1286 if not ui.quiet:
1312 1287 fm.plain(notice)
1313 1288 fm.plain('\n')
1314 1289 fm.end()
1315 1290
1316 1291 @command('bundle',
1317 1292 [('f', 'force', None, _('run even when the destination is unrelated')),
1318 1293 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1319 1294 _('REV')),
1320 1295 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1321 1296 _('BRANCH')),
1322 1297 ('', 'base', [],
1323 1298 _('a base changeset assumed to be available at the destination'),
1324 1299 _('REV')),
1325 1300 ('a', 'all', None, _('bundle all changesets in the repository')),
1326 1301 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1327 1302 ] + remoteopts,
1328 1303 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1329 1304 def bundle(ui, repo, fname, dest=None, **opts):
1330 1305 """create a changegroup file
1331 1306
1332 1307 Generate a changegroup file collecting changesets to be added
1333 1308 to a repository.
1334 1309
1335 1310 To create a bundle containing all changesets, use -a/--all
1336 1311 (or --base null). Otherwise, hg assumes the destination will have
1337 1312 all the nodes you specify with --base parameters. Otherwise, hg
1338 1313 will assume the repository has all the nodes in destination, or
1339 1314 default-push/default if no destination is specified.
1340 1315
1341 1316 You can change bundle format with the -t/--type option. You can
1342 1317 specify a compression, a bundle version or both using a dash
1343 1318 (comp-version). The available compression methods are: none, bzip2,
1344 1319 and gzip (by default, bundles are compressed using bzip2). The
1345 1320 available formats are: v1, v2 (default to most suitable).
1346 1321
1347 1322 The bundle file can then be transferred using conventional means
1348 1323 and applied to another repository with the unbundle or pull
1349 1324 command. This is useful when direct push and pull are not
1350 1325 available or when exporting an entire repository is undesirable.
1351 1326
1352 1327 Applying bundles preserves all changeset contents including
1353 1328 permissions, copy/rename information, and revision history.
1354 1329
1355 1330 Returns 0 on success, 1 if no changes found.
1356 1331 """
1357 1332 revs = None
1358 1333 if 'rev' in opts:
1359 1334 revstrings = opts['rev']
1360 1335 revs = scmutil.revrange(repo, revstrings)
1361 1336 if revstrings and not revs:
1362 1337 raise error.Abort(_('no commits to bundle'))
1363 1338
1364 1339 bundletype = opts.get('type', 'bzip2').lower()
1365 1340 try:
1366 1341 bcompression, cgversion, params = exchange.parsebundlespec(
1367 1342 repo, bundletype, strict=False)
1368 1343 except error.UnsupportedBundleSpecification as e:
1369 1344 raise error.Abort(str(e),
1370 1345 hint=_("see 'hg help bundle' for supported "
1371 1346 "values for --type"))
1372 1347
1373 1348 # Packed bundles are a pseudo bundle format for now.
1374 1349 if cgversion == 's1':
1375 1350 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1376 1351 hint=_("use 'hg debugcreatestreamclonebundle'"))
1377 1352
1378 1353 if opts.get('all'):
1379 1354 if dest:
1380 1355 raise error.Abort(_("--all is incompatible with specifying "
1381 1356 "a destination"))
1382 1357 if opts.get('base'):
1383 1358 ui.warn(_("ignoring --base because --all was specified\n"))
1384 1359 base = ['null']
1385 1360 else:
1386 1361 base = scmutil.revrange(repo, opts.get('base'))
1387 1362 # TODO: get desired bundlecaps from command line.
1388 1363 bundlecaps = None
1389 1364 if cgversion not in changegroup.supportedoutgoingversions(repo):
1390 1365 raise error.Abort(_("repository does not support bundle version %s") %
1391 1366 cgversion)
1392 1367
1393 1368 if base:
1394 1369 if dest:
1395 1370 raise error.Abort(_("--base is incompatible with specifying "
1396 1371 "a destination"))
1397 1372 common = [repo.lookup(rev) for rev in base]
1398 1373 heads = revs and map(repo.lookup, revs) or None
1399 1374 outgoing = discovery.outgoing(repo, common, heads)
1400 1375 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1401 1376 bundlecaps=bundlecaps,
1402 1377 version=cgversion)
1403 1378 outgoing = None
1404 1379 else:
1405 1380 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1406 1381 dest, branches = hg.parseurl(dest, opts.get('branch'))
1407 1382 other = hg.peer(repo, opts, dest)
1408 1383 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1409 1384 heads = revs and map(repo.lookup, revs) or revs
1410 1385 outgoing = discovery.findcommonoutgoing(repo, other,
1411 1386 onlyheads=heads,
1412 1387 force=opts.get('force'),
1413 1388 portable=True)
1414 1389 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1415 1390 bundlecaps, version=cgversion)
1416 1391 if not cg:
1417 1392 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1418 1393 return 1
1419 1394
1420 1395 if cgversion == '01': #bundle1
1421 1396 if bcompression is None:
1422 1397 bcompression = 'UN'
1423 1398 bversion = 'HG10' + bcompression
1424 1399 bcompression = None
1425 1400 else:
1426 1401 assert cgversion == '02'
1427 1402 bversion = 'HG20'
1428 1403
1429 1404 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression)
1430 1405
1431 1406 @command('cat',
1432 1407 [('o', 'output', '',
1433 1408 _('print output to file with formatted name'), _('FORMAT')),
1434 1409 ('r', 'rev', '', _('print the given revision'), _('REV')),
1435 1410 ('', 'decode', None, _('apply any matching decode filter')),
1436 1411 ] + walkopts,
1437 1412 _('[OPTION]... FILE...'),
1438 1413 inferrepo=True)
1439 1414 def cat(ui, repo, file1, *pats, **opts):
1440 1415 """output the current or given revision of files
1441 1416
1442 1417 Print the specified files as they were at the given revision. If
1443 1418 no revision is given, the parent of the working directory is used.
1444 1419
1445 1420 Output may be to a file, in which case the name of the file is
1446 1421 given using a format string. The formatting rules as follows:
1447 1422
1448 1423 :``%%``: literal "%" character
1449 1424 :``%s``: basename of file being printed
1450 1425 :``%d``: dirname of file being printed, or '.' if in repository root
1451 1426 :``%p``: root-relative path name of file being printed
1452 1427 :``%H``: changeset hash (40 hexadecimal digits)
1453 1428 :``%R``: changeset revision number
1454 1429 :``%h``: short-form changeset hash (12 hexadecimal digits)
1455 1430 :``%r``: zero-padded changeset revision number
1456 1431 :``%b``: basename of the exporting repository
1457 1432
1458 1433 Returns 0 on success.
1459 1434 """
1460 1435 ctx = scmutil.revsingle(repo, opts.get('rev'))
1461 1436 m = scmutil.match(ctx, (file1,) + pats, opts)
1462 1437
1463 1438 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1464 1439
1465 1440 @command('^clone',
1466 1441 [('U', 'noupdate', None, _('the clone will include an empty working '
1467 1442 'directory (only a repository)')),
1468 1443 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1469 1444 _('REV')),
1470 1445 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1471 1446 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1472 1447 ('', 'pull', None, _('use pull protocol to copy metadata')),
1473 1448 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1474 1449 ] + remoteopts,
1475 1450 _('[OPTION]... SOURCE [DEST]'),
1476 1451 norepo=True)
1477 1452 def clone(ui, source, dest=None, **opts):
1478 1453 """make a copy of an existing repository
1479 1454
1480 1455 Create a copy of an existing repository in a new directory.
1481 1456
1482 1457 If no destination directory name is specified, it defaults to the
1483 1458 basename of the source.
1484 1459
1485 1460 The location of the source is added to the new repository's
1486 1461 ``.hg/hgrc`` file, as the default to be used for future pulls.
1487 1462
1488 1463 Only local paths and ``ssh://`` URLs are supported as
1489 1464 destinations. For ``ssh://`` destinations, no working directory or
1490 1465 ``.hg/hgrc`` will be created on the remote side.
1491 1466
1492 1467 If the source repository has a bookmark called '@' set, that
1493 1468 revision will be checked out in the new repository by default.
1494 1469
1495 1470 To check out a particular version, use -u/--update, or
1496 1471 -U/--noupdate to create a clone with no working directory.
1497 1472
1498 1473 To pull only a subset of changesets, specify one or more revisions
1499 1474 identifiers with -r/--rev or branches with -b/--branch. The
1500 1475 resulting clone will contain only the specified changesets and
1501 1476 their ancestors. These options (or 'clone src#rev dest') imply
1502 1477 --pull, even for local source repositories.
1503 1478
1504 1479 .. note::
1505 1480
1506 1481 Specifying a tag will include the tagged changeset but not the
1507 1482 changeset containing the tag.
1508 1483
1509 1484 .. container:: verbose
1510 1485
1511 1486 For efficiency, hardlinks are used for cloning whenever the
1512 1487 source and destination are on the same filesystem (note this
1513 1488 applies only to the repository data, not to the working
1514 1489 directory). Some filesystems, such as AFS, implement hardlinking
1515 1490 incorrectly, but do not report errors. In these cases, use the
1516 1491 --pull option to avoid hardlinking.
1517 1492
1518 1493 In some cases, you can clone repositories and the working
1519 1494 directory using full hardlinks with ::
1520 1495
1521 1496 $ cp -al REPO REPOCLONE
1522 1497
1523 1498 This is the fastest way to clone, but it is not always safe. The
1524 1499 operation is not atomic (making sure REPO is not modified during
1525 1500 the operation is up to you) and you have to make sure your
1526 1501 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1527 1502 so). Also, this is not compatible with certain extensions that
1528 1503 place their metadata under the .hg directory, such as mq.
1529 1504
1530 1505 Mercurial will update the working directory to the first applicable
1531 1506 revision from this list:
1532 1507
1533 1508 a) null if -U or the source repository has no changesets
1534 1509 b) if -u . and the source repository is local, the first parent of
1535 1510 the source repository's working directory
1536 1511 c) the changeset specified with -u (if a branch name, this means the
1537 1512 latest head of that branch)
1538 1513 d) the changeset specified with -r
1539 1514 e) the tipmost head specified with -b
1540 1515 f) the tipmost head specified with the url#branch source syntax
1541 1516 g) the revision marked with the '@' bookmark, if present
1542 1517 h) the tipmost head of the default branch
1543 1518 i) tip
1544 1519
1545 1520 When cloning from servers that support it, Mercurial may fetch
1546 1521 pre-generated data from a server-advertised URL. When this is done,
1547 1522 hooks operating on incoming changesets and changegroups may fire twice,
1548 1523 once for the bundle fetched from the URL and another for any additional
1549 1524 data not fetched from this URL. In addition, if an error occurs, the
1550 1525 repository may be rolled back to a partial clone. This behavior may
1551 1526 change in future releases. See :hg:`help -e clonebundles` for more.
1552 1527
1553 1528 Examples:
1554 1529
1555 1530 - clone a remote repository to a new directory named hg/::
1556 1531
1557 1532 hg clone http://selenic.com/hg
1558 1533
1559 1534 - create a lightweight local clone::
1560 1535
1561 1536 hg clone project/ project-feature/
1562 1537
1563 1538 - clone from an absolute path on an ssh server (note double-slash)::
1564 1539
1565 1540 hg clone ssh://user@server//home/projects/alpha/
1566 1541
1567 1542 - do a high-speed clone over a LAN while checking out a
1568 1543 specified version::
1569 1544
1570 1545 hg clone --uncompressed http://server/repo -u 1.5
1571 1546
1572 1547 - create a repository without changesets after a particular revision::
1573 1548
1574 1549 hg clone -r 04e544 experimental/ good/
1575 1550
1576 1551 - clone (and track) a particular named branch::
1577 1552
1578 1553 hg clone http://selenic.com/hg#stable
1579 1554
1580 1555 See :hg:`help urls` for details on specifying URLs.
1581 1556
1582 1557 Returns 0 on success.
1583 1558 """
1584 1559 if opts.get('noupdate') and opts.get('updaterev'):
1585 1560 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1586 1561
1587 1562 r = hg.clone(ui, opts, source, dest,
1588 1563 pull=opts.get('pull'),
1589 1564 stream=opts.get('uncompressed'),
1590 1565 rev=opts.get('rev'),
1591 1566 update=opts.get('updaterev') or not opts.get('noupdate'),
1592 1567 branch=opts.get('branch'),
1593 1568 shareopts=opts.get('shareopts'))
1594 1569
1595 1570 return r is None
1596 1571
1597 1572 @command('^commit|ci',
1598 1573 [('A', 'addremove', None,
1599 1574 _('mark new/missing files as added/removed before committing')),
1600 1575 ('', 'close-branch', None,
1601 1576 _('mark a branch head as closed')),
1602 1577 ('', 'amend', None, _('amend the parent of the working directory')),
1603 1578 ('s', 'secret', None, _('use the secret phase for committing')),
1604 1579 ('e', 'edit', None, _('invoke editor on commit messages')),
1605 1580 ('i', 'interactive', None, _('use interactive mode')),
1606 1581 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1607 1582 _('[OPTION]... [FILE]...'),
1608 1583 inferrepo=True)
1609 1584 def commit(ui, repo, *pats, **opts):
1610 1585 """commit the specified files or all outstanding changes
1611 1586
1612 1587 Commit changes to the given files into the repository. Unlike a
1613 1588 centralized SCM, this operation is a local operation. See
1614 1589 :hg:`push` for a way to actively distribute your changes.
1615 1590
1616 1591 If a list of files is omitted, all changes reported by :hg:`status`
1617 1592 will be committed.
1618 1593
1619 1594 If you are committing the result of a merge, do not provide any
1620 1595 filenames or -I/-X filters.
1621 1596
1622 1597 If no commit message is specified, Mercurial starts your
1623 1598 configured editor where you can enter a message. In case your
1624 1599 commit fails, you will find a backup of your message in
1625 1600 ``.hg/last-message.txt``.
1626 1601
1627 1602 The --close-branch flag can be used to mark the current branch
1628 1603 head closed. When all heads of a branch are closed, the branch
1629 1604 will be considered closed and no longer listed.
1630 1605
1631 1606 The --amend flag can be used to amend the parent of the
1632 1607 working directory with a new commit that contains the changes
1633 1608 in the parent in addition to those currently reported by :hg:`status`,
1634 1609 if there are any. The old commit is stored in a backup bundle in
1635 1610 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1636 1611 on how to restore it).
1637 1612
1638 1613 Message, user and date are taken from the amended commit unless
1639 1614 specified. When a message isn't specified on the command line,
1640 1615 the editor will open with the message of the amended commit.
1641 1616
1642 1617 It is not possible to amend public changesets (see :hg:`help phases`)
1643 1618 or changesets that have children.
1644 1619
1645 1620 See :hg:`help dates` for a list of formats valid for -d/--date.
1646 1621
1647 1622 Returns 0 on success, 1 if nothing changed.
1648 1623
1649 1624 .. container:: verbose
1650 1625
1651 1626 Examples:
1652 1627
1653 1628 - commit all files ending in .py::
1654 1629
1655 1630 hg commit --include "set:**.py"
1656 1631
1657 1632 - commit all non-binary files::
1658 1633
1659 1634 hg commit --exclude "set:binary()"
1660 1635
1661 1636 - amend the current commit and set the date to now::
1662 1637
1663 1638 hg commit --amend --date now
1664 1639 """
1665 1640 wlock = lock = None
1666 1641 try:
1667 1642 wlock = repo.wlock()
1668 1643 lock = repo.lock()
1669 1644 return _docommit(ui, repo, *pats, **opts)
1670 1645 finally:
1671 1646 release(lock, wlock)
1672 1647
1673 1648 def _docommit(ui, repo, *pats, **opts):
1674 1649 if opts.get('interactive'):
1675 1650 opts.pop('interactive')
1676 1651 cmdutil.dorecord(ui, repo, commit, None, False,
1677 1652 cmdutil.recordfilter, *pats, **opts)
1678 1653 return
1679 1654
1680 1655 if opts.get('subrepos'):
1681 1656 if opts.get('amend'):
1682 1657 raise error.Abort(_('cannot amend with --subrepos'))
1683 1658 # Let --subrepos on the command line override config setting.
1684 1659 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1685 1660
1686 1661 cmdutil.checkunfinished(repo, commit=True)
1687 1662
1688 1663 branch = repo[None].branch()
1689 1664 bheads = repo.branchheads(branch)
1690 1665
1691 1666 extra = {}
1692 1667 if opts.get('close_branch'):
1693 1668 extra['close'] = 1
1694 1669
1695 1670 if not bheads:
1696 1671 raise error.Abort(_('can only close branch heads'))
1697 1672 elif opts.get('amend'):
1698 1673 if repo[None].parents()[0].p1().branch() != branch and \
1699 1674 repo[None].parents()[0].p2().branch() != branch:
1700 1675 raise error.Abort(_('can only close branch heads'))
1701 1676
1702 1677 if opts.get('amend'):
1703 1678 if ui.configbool('ui', 'commitsubrepos'):
1704 1679 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1705 1680
1706 1681 old = repo['.']
1707 1682 if not old.mutable():
1708 1683 raise error.Abort(_('cannot amend public changesets'))
1709 1684 if len(repo[None].parents()) > 1:
1710 1685 raise error.Abort(_('cannot amend while merging'))
1711 1686 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1712 1687 if not allowunstable and old.children():
1713 1688 raise error.Abort(_('cannot amend changeset with children'))
1714 1689
1715 1690 # Currently histedit gets confused if an amend happens while histedit
1716 1691 # is in progress. Since we have a checkunfinished command, we are
1717 1692 # temporarily honoring it.
1718 1693 #
1719 1694 # Note: eventually this guard will be removed. Please do not expect
1720 1695 # this behavior to remain.
1721 1696 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1722 1697 cmdutil.checkunfinished(repo)
1723 1698
1724 1699 # commitfunc is used only for temporary amend commit by cmdutil.amend
1725 1700 def commitfunc(ui, repo, message, match, opts):
1726 1701 return repo.commit(message,
1727 1702 opts.get('user') or old.user(),
1728 1703 opts.get('date') or old.date(),
1729 1704 match,
1730 1705 extra=extra)
1731 1706
1732 1707 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1733 1708 if node == old.node():
1734 1709 ui.status(_("nothing changed\n"))
1735 1710 return 1
1736 1711 else:
1737 1712 def commitfunc(ui, repo, message, match, opts):
1738 1713 backup = ui.backupconfig('phases', 'new-commit')
1739 1714 baseui = repo.baseui
1740 1715 basebackup = baseui.backupconfig('phases', 'new-commit')
1741 1716 try:
1742 1717 if opts.get('secret'):
1743 1718 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1744 1719 # Propagate to subrepos
1745 1720 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1746 1721
1747 1722 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1748 1723 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1749 1724 return repo.commit(message, opts.get('user'), opts.get('date'),
1750 1725 match,
1751 1726 editor=editor,
1752 1727 extra=extra)
1753 1728 finally:
1754 1729 ui.restoreconfig(backup)
1755 1730 repo.baseui.restoreconfig(basebackup)
1756 1731
1757 1732
1758 1733 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1759 1734
1760 1735 if not node:
1761 1736 stat = cmdutil.postcommitstatus(repo, pats, opts)
1762 1737 if stat[3]:
1763 1738 ui.status(_("nothing changed (%d missing files, see "
1764 1739 "'hg status')\n") % len(stat[3]))
1765 1740 else:
1766 1741 ui.status(_("nothing changed\n"))
1767 1742 return 1
1768 1743
1769 1744 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1770 1745
1771 1746 @command('config|showconfig|debugconfig',
1772 1747 [('u', 'untrusted', None, _('show untrusted configuration options')),
1773 1748 ('e', 'edit', None, _('edit user config')),
1774 1749 ('l', 'local', None, _('edit repository config')),
1775 1750 ('g', 'global', None, _('edit global config'))] + formatteropts,
1776 1751 _('[-u] [NAME]...'),
1777 1752 optionalrepo=True)
1778 1753 def config(ui, repo, *values, **opts):
1779 1754 """show combined config settings from all hgrc files
1780 1755
1781 1756 With no arguments, print names and values of all config items.
1782 1757
1783 1758 With one argument of the form section.name, print just the value
1784 1759 of that config item.
1785 1760
1786 1761 With multiple arguments, print names and values of all config
1787 1762 items with matching section names.
1788 1763
1789 1764 With --edit, start an editor on the user-level config file. With
1790 1765 --global, edit the system-wide config file. With --local, edit the
1791 1766 repository-level config file.
1792 1767
1793 1768 With --debug, the source (filename and line number) is printed
1794 1769 for each config item.
1795 1770
1796 1771 See :hg:`help config` for more information about config files.
1797 1772
1798 1773 Returns 0 on success, 1 if NAME does not exist.
1799 1774
1800 1775 """
1801 1776
1802 1777 if opts.get('edit') or opts.get('local') or opts.get('global'):
1803 1778 if opts.get('local') and opts.get('global'):
1804 1779 raise error.Abort(_("can't use --local and --global together"))
1805 1780
1806 1781 if opts.get('local'):
1807 1782 if not repo:
1808 1783 raise error.Abort(_("can't use --local outside a repository"))
1809 1784 paths = [repo.join('hgrc')]
1810 1785 elif opts.get('global'):
1811 1786 paths = scmutil.systemrcpath()
1812 1787 else:
1813 1788 paths = scmutil.userrcpath()
1814 1789
1815 1790 for f in paths:
1816 1791 if os.path.exists(f):
1817 1792 break
1818 1793 else:
1819 1794 if opts.get('global'):
1820 1795 samplehgrc = uimod.samplehgrcs['global']
1821 1796 elif opts.get('local'):
1822 1797 samplehgrc = uimod.samplehgrcs['local']
1823 1798 else:
1824 1799 samplehgrc = uimod.samplehgrcs['user']
1825 1800
1826 1801 f = paths[0]
1827 1802 fp = open(f, "w")
1828 1803 fp.write(samplehgrc)
1829 1804 fp.close()
1830 1805
1831 1806 editor = ui.geteditor()
1832 1807 ui.system("%s \"%s\"" % (editor, f),
1833 1808 onerr=error.Abort, errprefix=_("edit failed"))
1834 1809 return
1835 1810
1836 1811 fm = ui.formatter('config', opts)
1837 1812 for f in scmutil.rcpath():
1838 1813 ui.debug('read config from: %s\n' % f)
1839 1814 untrusted = bool(opts.get('untrusted'))
1840 1815 if values:
1841 1816 sections = [v for v in values if '.' not in v]
1842 1817 items = [v for v in values if '.' in v]
1843 1818 if len(items) > 1 or items and sections:
1844 1819 raise error.Abort(_('only one config item permitted'))
1845 1820 matched = False
1846 1821 for section, name, value in ui.walkconfig(untrusted=untrusted):
1847 1822 value = str(value)
1848 1823 if fm.isplain():
1849 1824 value = value.replace('\n', '\\n')
1850 1825 entryname = section + '.' + name
1851 1826 if values:
1852 1827 for v in values:
1853 1828 if v == section:
1854 1829 fm.startitem()
1855 1830 fm.condwrite(ui.debugflag, 'source', '%s: ',
1856 1831 ui.configsource(section, name, untrusted))
1857 1832 fm.write('name value', '%s=%s\n', entryname, value)
1858 1833 matched = True
1859 1834 elif v == entryname:
1860 1835 fm.startitem()
1861 1836 fm.condwrite(ui.debugflag, 'source', '%s: ',
1862 1837 ui.configsource(section, name, untrusted))
1863 1838 fm.write('value', '%s\n', value)
1864 1839 fm.data(name=entryname)
1865 1840 matched = True
1866 1841 else:
1867 1842 fm.startitem()
1868 1843 fm.condwrite(ui.debugflag, 'source', '%s: ',
1869 1844 ui.configsource(section, name, untrusted))
1870 1845 fm.write('name value', '%s=%s\n', entryname, value)
1871 1846 matched = True
1872 1847 fm.end()
1873 1848 if matched:
1874 1849 return 0
1875 1850 return 1
1876 1851
1877 1852 @command('copy|cp',
1878 1853 [('A', 'after', None, _('record a copy that has already occurred')),
1879 1854 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1880 1855 ] + walkopts + dryrunopts,
1881 1856 _('[OPTION]... [SOURCE]... DEST'))
1882 1857 def copy(ui, repo, *pats, **opts):
1883 1858 """mark files as copied for the next commit
1884 1859
1885 1860 Mark dest as having copies of source files. If dest is a
1886 1861 directory, copies are put in that directory. If dest is a file,
1887 1862 the source must be a single file.
1888 1863
1889 1864 By default, this command copies the contents of files as they
1890 1865 exist in the working directory. If invoked with -A/--after, the
1891 1866 operation is recorded, but no copying is performed.
1892 1867
1893 1868 This command takes effect with the next commit. To undo a copy
1894 1869 before that, see :hg:`revert`.
1895 1870
1896 1871 Returns 0 on success, 1 if errors are encountered.
1897 1872 """
1898 1873 with repo.wlock(False):
1899 1874 return cmdutil.copy(ui, repo, pats, opts)
1900 1875
1901 1876 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1902 1877 def debugancestor(ui, repo, *args):
1903 1878 """find the ancestor revision of two revisions in a given index"""
1904 1879 if len(args) == 3:
1905 1880 index, rev1, rev2 = args
1906 1881 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1907 1882 lookup = r.lookup
1908 1883 elif len(args) == 2:
1909 1884 if not repo:
1910 1885 raise error.Abort(_("there is no Mercurial repository here "
1911 1886 "(.hg not found)"))
1912 1887 rev1, rev2 = args
1913 1888 r = repo.changelog
1914 1889 lookup = repo.lookup
1915 1890 else:
1916 1891 raise error.Abort(_('either two or three arguments required'))
1917 1892 a = r.ancestor(lookup(rev1), lookup(rev2))
1918 1893 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1919 1894
1920 1895 @command('debugbuilddag',
1921 1896 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1922 1897 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1923 1898 ('n', 'new-file', None, _('add new file at each rev'))],
1924 1899 _('[OPTION]... [TEXT]'))
1925 1900 def debugbuilddag(ui, repo, text=None,
1926 1901 mergeable_file=False,
1927 1902 overwritten_file=False,
1928 1903 new_file=False):
1929 1904 """builds a repo with a given DAG from scratch in the current empty repo
1930 1905
1931 1906 The description of the DAG is read from stdin if not given on the
1932 1907 command line.
1933 1908
1934 1909 Elements:
1935 1910
1936 1911 - "+n" is a linear run of n nodes based on the current default parent
1937 1912 - "." is a single node based on the current default parent
1938 1913 - "$" resets the default parent to null (implied at the start);
1939 1914 otherwise the default parent is always the last node created
1940 1915 - "<p" sets the default parent to the backref p
1941 1916 - "*p" is a fork at parent p, which is a backref
1942 1917 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1943 1918 - "/p2" is a merge of the preceding node and p2
1944 1919 - ":tag" defines a local tag for the preceding node
1945 1920 - "@branch" sets the named branch for subsequent nodes
1946 1921 - "#...\\n" is a comment up to the end of the line
1947 1922
1948 1923 Whitespace between the above elements is ignored.
1949 1924
1950 1925 A backref is either
1951 1926
1952 1927 - a number n, which references the node curr-n, where curr is the current
1953 1928 node, or
1954 1929 - the name of a local tag you placed earlier using ":tag", or
1955 1930 - empty to denote the default parent.
1956 1931
1957 1932 All string valued-elements are either strictly alphanumeric, or must
1958 1933 be enclosed in double quotes ("..."), with "\\" as escape character.
1959 1934 """
1960 1935
1961 1936 if text is None:
1962 1937 ui.status(_("reading DAG from stdin\n"))
1963 1938 text = ui.fin.read()
1964 1939
1965 1940 cl = repo.changelog
1966 1941 if len(cl) > 0:
1967 1942 raise error.Abort(_('repository is not empty'))
1968 1943
1969 1944 # determine number of revs in DAG
1970 1945 total = 0
1971 1946 for type, data in dagparser.parsedag(text):
1972 1947 if type == 'n':
1973 1948 total += 1
1974 1949
1975 1950 if mergeable_file:
1976 1951 linesperrev = 2
1977 1952 # make a file with k lines per rev
1978 1953 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1979 1954 initialmergedlines.append("")
1980 1955
1981 1956 tags = []
1982 1957
1983 1958 wlock = lock = tr = None
1984 1959 try:
1985 1960 wlock = repo.wlock()
1986 1961 lock = repo.lock()
1987 1962 tr = repo.transaction("builddag")
1988 1963
1989 1964 at = -1
1990 1965 atbranch = 'default'
1991 1966 nodeids = []
1992 1967 id = 0
1993 1968 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1994 1969 for type, data in dagparser.parsedag(text):
1995 1970 if type == 'n':
1996 1971 ui.note(('node %s\n' % str(data)))
1997 1972 id, ps = data
1998 1973
1999 1974 files = []
2000 1975 fctxs = {}
2001 1976
2002 1977 p2 = None
2003 1978 if mergeable_file:
2004 1979 fn = "mf"
2005 1980 p1 = repo[ps[0]]
2006 1981 if len(ps) > 1:
2007 1982 p2 = repo[ps[1]]
2008 1983 pa = p1.ancestor(p2)
2009 1984 base, local, other = [x[fn].data() for x in (pa, p1,
2010 1985 p2)]
2011 1986 m3 = simplemerge.Merge3Text(base, local, other)
2012 1987 ml = [l.strip() for l in m3.merge_lines()]
2013 1988 ml.append("")
2014 1989 elif at > 0:
2015 1990 ml = p1[fn].data().split("\n")
2016 1991 else:
2017 1992 ml = initialmergedlines
2018 1993 ml[id * linesperrev] += " r%i" % id
2019 1994 mergedtext = "\n".join(ml)
2020 1995 files.append(fn)
2021 1996 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
2022 1997
2023 1998 if overwritten_file:
2024 1999 fn = "of"
2025 2000 files.append(fn)
2026 2001 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2027 2002
2028 2003 if new_file:
2029 2004 fn = "nf%i" % id
2030 2005 files.append(fn)
2031 2006 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2032 2007 if len(ps) > 1:
2033 2008 if not p2:
2034 2009 p2 = repo[ps[1]]
2035 2010 for fn in p2:
2036 2011 if fn.startswith("nf"):
2037 2012 files.append(fn)
2038 2013 fctxs[fn] = p2[fn]
2039 2014
2040 2015 def fctxfn(repo, cx, path):
2041 2016 return fctxs.get(path)
2042 2017
2043 2018 if len(ps) == 0 or ps[0] < 0:
2044 2019 pars = [None, None]
2045 2020 elif len(ps) == 1:
2046 2021 pars = [nodeids[ps[0]], None]
2047 2022 else:
2048 2023 pars = [nodeids[p] for p in ps]
2049 2024 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2050 2025 date=(id, 0),
2051 2026 user="debugbuilddag",
2052 2027 extra={'branch': atbranch})
2053 2028 nodeid = repo.commitctx(cx)
2054 2029 nodeids.append(nodeid)
2055 2030 at = id
2056 2031 elif type == 'l':
2057 2032 id, name = data
2058 2033 ui.note(('tag %s\n' % name))
2059 2034 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2060 2035 elif type == 'a':
2061 2036 ui.note(('branch %s\n' % data))
2062 2037 atbranch = data
2063 2038 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2064 2039 tr.close()
2065 2040
2066 2041 if tags:
2067 2042 repo.vfs.write("localtags", "".join(tags))
2068 2043 finally:
2069 2044 ui.progress(_('building'), None)
2070 2045 release(tr, lock, wlock)
2071 2046
2072 2047 @command('debugbundle',
2073 2048 [('a', 'all', None, _('show all details')),
2074 2049 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2075 2050 _('FILE'),
2076 2051 norepo=True)
2077 2052 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2078 2053 """lists the contents of a bundle"""
2079 2054 with hg.openpath(ui, bundlepath) as f:
2080 2055 if spec:
2081 2056 spec = exchange.getbundlespec(ui, f)
2082 2057 ui.write('%s\n' % spec)
2083 2058 return
2084 2059
2085 2060 gen = exchange.readbundle(ui, f, bundlepath)
2086 2061 if isinstance(gen, bundle2.unbundle20):
2087 2062 return _debugbundle2(ui, gen, all=all, **opts)
2088 2063 _debugchangegroup(ui, gen, all=all, **opts)
2089 2064
2090 2065 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
2091 2066 indent_string = ' ' * indent
2092 2067 if all:
2093 2068 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
2094 2069 % indent_string)
2095 2070
2096 2071 def showchunks(named):
2097 2072 ui.write("\n%s%s\n" % (indent_string, named))
2098 2073 chain = None
2099 2074 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
2100 2075 node = chunkdata['node']
2101 2076 p1 = chunkdata['p1']
2102 2077 p2 = chunkdata['p2']
2103 2078 cs = chunkdata['cs']
2104 2079 deltabase = chunkdata['deltabase']
2105 2080 delta = chunkdata['delta']
2106 2081 ui.write("%s%s %s %s %s %s %s\n" %
2107 2082 (indent_string, hex(node), hex(p1), hex(p2),
2108 2083 hex(cs), hex(deltabase), len(delta)))
2109 2084 chain = node
2110 2085
2111 2086 chunkdata = gen.changelogheader()
2112 2087 showchunks("changelog")
2113 2088 chunkdata = gen.manifestheader()
2114 2089 showchunks("manifest")
2115 2090 for chunkdata in iter(gen.filelogheader, {}):
2116 2091 fname = chunkdata['filename']
2117 2092 showchunks(fname)
2118 2093 else:
2119 2094 if isinstance(gen, bundle2.unbundle20):
2120 2095 raise error.Abort(_('use debugbundle2 for this file'))
2121 2096 chunkdata = gen.changelogheader()
2122 2097 chain = None
2123 2098 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
2124 2099 node = chunkdata['node']
2125 2100 ui.write("%s%s\n" % (indent_string, hex(node)))
2126 2101 chain = node
2127 2102
2128 2103 def _debugbundle2(ui, gen, all=None, **opts):
2129 2104 """lists the contents of a bundle2"""
2130 2105 if not isinstance(gen, bundle2.unbundle20):
2131 2106 raise error.Abort(_('not a bundle2 file'))
2132 2107 ui.write(('Stream params: %s\n' % repr(gen.params)))
2133 2108 for part in gen.iterparts():
2134 2109 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2135 2110 if part.type == 'changegroup':
2136 2111 version = part.params.get('version', '01')
2137 2112 cg = changegroup.getunbundler(version, part, 'UN')
2138 2113 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
2139 2114
2140 2115 @command('debugcreatestreamclonebundle', [], 'FILE')
2141 2116 def debugcreatestreamclonebundle(ui, repo, fname):
2142 2117 """create a stream clone bundle file
2143 2118
2144 2119 Stream bundles are special bundles that are essentially archives of
2145 2120 revlog files. They are commonly used for cloning very quickly.
2146 2121 """
2147 2122 requirements, gen = streamclone.generatebundlev1(repo)
2148 2123 changegroup.writechunks(ui, gen, fname)
2149 2124
2150 2125 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2151 2126
2152 2127 @command('debugapplystreamclonebundle', [], 'FILE')
2153 2128 def debugapplystreamclonebundle(ui, repo, fname):
2154 2129 """apply a stream clone bundle file"""
2155 2130 f = hg.openpath(ui, fname)
2156 2131 gen = exchange.readbundle(ui, f, fname)
2157 2132 gen.apply(repo)
2158 2133
2159 2134 @command('debugcheckstate', [], '')
2160 2135 def debugcheckstate(ui, repo):
2161 2136 """validate the correctness of the current dirstate"""
2162 2137 parent1, parent2 = repo.dirstate.parents()
2163 2138 m1 = repo[parent1].manifest()
2164 2139 m2 = repo[parent2].manifest()
2165 2140 errors = 0
2166 2141 for f in repo.dirstate:
2167 2142 state = repo.dirstate[f]
2168 2143 if state in "nr" and f not in m1:
2169 2144 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2170 2145 errors += 1
2171 2146 if state in "a" and f in m1:
2172 2147 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2173 2148 errors += 1
2174 2149 if state in "m" and f not in m1 and f not in m2:
2175 2150 ui.warn(_("%s in state %s, but not in either manifest\n") %
2176 2151 (f, state))
2177 2152 errors += 1
2178 2153 for f in m1:
2179 2154 state = repo.dirstate[f]
2180 2155 if state not in "nrm":
2181 2156 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2182 2157 errors += 1
2183 2158 if errors:
2184 2159 error = _(".hg/dirstate inconsistent with current parent's manifest")
2185 2160 raise error.Abort(error)
2186 2161
2187 2162 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2188 2163 def debugcommands(ui, cmd='', *args):
2189 2164 """list all available commands and options"""
2190 2165 for cmd, vals in sorted(table.iteritems()):
2191 2166 cmd = cmd.split('|')[0].strip('^')
2192 2167 opts = ', '.join([i[1] for i in vals[1]])
2193 2168 ui.write('%s: %s\n' % (cmd, opts))
2194 2169
2195 2170 @command('debugcomplete',
2196 2171 [('o', 'options', None, _('show the command options'))],
2197 2172 _('[-o] CMD'),
2198 2173 norepo=True)
2199 2174 def debugcomplete(ui, cmd='', **opts):
2200 2175 """returns the completion list associated with the given command"""
2201 2176
2202 2177 if opts.get('options'):
2203 2178 options = []
2204 2179 otables = [globalopts]
2205 2180 if cmd:
2206 2181 aliases, entry = cmdutil.findcmd(cmd, table, False)
2207 2182 otables.append(entry[1])
2208 2183 for t in otables:
2209 2184 for o in t:
2210 2185 if "(DEPRECATED)" in o[3]:
2211 2186 continue
2212 2187 if o[0]:
2213 2188 options.append('-%s' % o[0])
2214 2189 options.append('--%s' % o[1])
2215 2190 ui.write("%s\n" % "\n".join(options))
2216 2191 return
2217 2192
2218 2193 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2219 2194 if ui.verbose:
2220 2195 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2221 2196 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2222 2197
2223 2198 @command('debugdag',
2224 2199 [('t', 'tags', None, _('use tags as labels')),
2225 2200 ('b', 'branches', None, _('annotate with branch names')),
2226 2201 ('', 'dots', None, _('use dots for runs')),
2227 2202 ('s', 'spaces', None, _('separate elements by spaces'))],
2228 2203 _('[OPTION]... [FILE [REV]...]'),
2229 2204 optionalrepo=True)
2230 2205 def debugdag(ui, repo, file_=None, *revs, **opts):
2231 2206 """format the changelog or an index DAG as a concise textual description
2232 2207
2233 2208 If you pass a revlog index, the revlog's DAG is emitted. If you list
2234 2209 revision numbers, they get labeled in the output as rN.
2235 2210
2236 2211 Otherwise, the changelog DAG of the current repo is emitted.
2237 2212 """
2238 2213 spaces = opts.get('spaces')
2239 2214 dots = opts.get('dots')
2240 2215 if file_:
2241 2216 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2242 2217 revs = set((int(r) for r in revs))
2243 2218 def events():
2244 2219 for r in rlog:
2245 2220 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2246 2221 if p != -1))
2247 2222 if r in revs:
2248 2223 yield 'l', (r, "r%i" % r)
2249 2224 elif repo:
2250 2225 cl = repo.changelog
2251 2226 tags = opts.get('tags')
2252 2227 branches = opts.get('branches')
2253 2228 if tags:
2254 2229 labels = {}
2255 2230 for l, n in repo.tags().items():
2256 2231 labels.setdefault(cl.rev(n), []).append(l)
2257 2232 def events():
2258 2233 b = "default"
2259 2234 for r in cl:
2260 2235 if branches:
2261 2236 newb = cl.read(cl.node(r))[5]['branch']
2262 2237 if newb != b:
2263 2238 yield 'a', newb
2264 2239 b = newb
2265 2240 yield 'n', (r, list(p for p in cl.parentrevs(r)
2266 2241 if p != -1))
2267 2242 if tags:
2268 2243 ls = labels.get(r)
2269 2244 if ls:
2270 2245 for l in ls:
2271 2246 yield 'l', (r, l)
2272 2247 else:
2273 2248 raise error.Abort(_('need repo for changelog dag'))
2274 2249
2275 2250 for line in dagparser.dagtextlines(events(),
2276 2251 addspaces=spaces,
2277 2252 wraplabels=True,
2278 2253 wrapannotations=True,
2279 2254 wrapnonlinear=dots,
2280 2255 usedots=dots,
2281 2256 maxlinewidth=70):
2282 2257 ui.write(line)
2283 2258 ui.write("\n")
2284 2259
2285 2260 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2286 2261 def debugdata(ui, repo, file_, rev=None, **opts):
2287 2262 """dump the contents of a data file revision"""
2288 2263 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
2289 2264 if rev is not None:
2290 2265 raise error.CommandError('debugdata', _('invalid arguments'))
2291 2266 file_, rev = None, file_
2292 2267 elif rev is None:
2293 2268 raise error.CommandError('debugdata', _('invalid arguments'))
2294 2269 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2295 2270 try:
2296 2271 ui.write(r.revision(r.lookup(rev)))
2297 2272 except KeyError:
2298 2273 raise error.Abort(_('invalid revision identifier %s') % rev)
2299 2274
2300 2275 @command('debugdate',
2301 2276 [('e', 'extended', None, _('try extended date formats'))],
2302 2277 _('[-e] DATE [RANGE]'),
2303 2278 norepo=True, optionalrepo=True)
2304 2279 def debugdate(ui, date, range=None, **opts):
2305 2280 """parse and display a date"""
2306 2281 if opts["extended"]:
2307 2282 d = util.parsedate(date, util.extendeddateformats)
2308 2283 else:
2309 2284 d = util.parsedate(date)
2310 2285 ui.write(("internal: %s %s\n") % d)
2311 2286 ui.write(("standard: %s\n") % util.datestr(d))
2312 2287 if range:
2313 2288 m = util.matchdate(range)
2314 2289 ui.write(("match: %s\n") % m(d[0]))
2315 2290
2316 2291 @command('debugdiscovery',
2317 2292 [('', 'old', None, _('use old-style discovery')),
2318 2293 ('', 'nonheads', None,
2319 2294 _('use old-style discovery with non-heads included')),
2320 2295 ] + remoteopts,
2321 2296 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2322 2297 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2323 2298 """runs the changeset discovery protocol in isolation"""
2324 2299 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2325 2300 opts.get('branch'))
2326 2301 remote = hg.peer(repo, opts, remoteurl)
2327 2302 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2328 2303
2329 2304 # make sure tests are repeatable
2330 2305 random.seed(12323)
2331 2306
2332 2307 def doit(localheads, remoteheads, remote=remote):
2333 2308 if opts.get('old'):
2334 2309 if localheads:
2335 2310 raise error.Abort('cannot use localheads with old style '
2336 2311 'discovery')
2337 2312 if not util.safehasattr(remote, 'branches'):
2338 2313 # enable in-client legacy support
2339 2314 remote = localrepo.locallegacypeer(remote.local())
2340 2315 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2341 2316 force=True)
2342 2317 common = set(common)
2343 2318 if not opts.get('nonheads'):
2344 2319 ui.write(("unpruned common: %s\n") %
2345 2320 " ".join(sorted(short(n) for n in common)))
2346 2321 dag = dagutil.revlogdag(repo.changelog)
2347 2322 all = dag.ancestorset(dag.internalizeall(common))
2348 2323 common = dag.externalizeall(dag.headsetofconnecteds(all))
2349 2324 else:
2350 2325 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2351 2326 common = set(common)
2352 2327 rheads = set(hds)
2353 2328 lheads = set(repo.heads())
2354 2329 ui.write(("common heads: %s\n") %
2355 2330 " ".join(sorted(short(n) for n in common)))
2356 2331 if lheads <= common:
2357 2332 ui.write(("local is subset\n"))
2358 2333 elif rheads <= common:
2359 2334 ui.write(("remote is subset\n"))
2360 2335
2361 2336 serverlogs = opts.get('serverlog')
2362 2337 if serverlogs:
2363 2338 for filename in serverlogs:
2364 2339 with open(filename, 'r') as logfile:
2365 2340 line = logfile.readline()
2366 2341 while line:
2367 2342 parts = line.strip().split(';')
2368 2343 op = parts[1]
2369 2344 if op == 'cg':
2370 2345 pass
2371 2346 elif op == 'cgss':
2372 2347 doit(parts[2].split(' '), parts[3].split(' '))
2373 2348 elif op == 'unb':
2374 2349 doit(parts[3].split(' '), parts[2].split(' '))
2375 2350 line = logfile.readline()
2376 2351 else:
2377 2352 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2378 2353 opts.get('remote_head'))
2379 2354 localrevs = opts.get('local_head')
2380 2355 doit(localrevs, remoterevs)
2381 2356
2382 2357 @command('debugextensions', formatteropts, [], norepo=True)
2383 2358 def debugextensions(ui, **opts):
2384 2359 '''show information about active extensions'''
2385 2360 exts = extensions.extensions(ui)
2386 2361 hgver = util.version()
2387 2362 fm = ui.formatter('debugextensions', opts)
2388 2363 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2389 2364 isinternal = extensions.ismoduleinternal(extmod)
2390 2365 extsource = extmod.__file__
2391 2366 if isinternal:
2392 2367 exttestedwith = [] # never expose magic string to users
2393 2368 else:
2394 2369 exttestedwith = getattr(extmod, 'testedwith', '').split()
2395 2370 extbuglink = getattr(extmod, 'buglink', None)
2396 2371
2397 2372 fm.startitem()
2398 2373
2399 2374 if ui.quiet or ui.verbose:
2400 2375 fm.write('name', '%s\n', extname)
2401 2376 else:
2402 2377 fm.write('name', '%s', extname)
2403 2378 if isinternal or hgver in exttestedwith:
2404 2379 fm.plain('\n')
2405 2380 elif not exttestedwith:
2406 2381 fm.plain(_(' (untested!)\n'))
2407 2382 else:
2408 2383 lasttestedversion = exttestedwith[-1]
2409 2384 fm.plain(' (%s!)\n' % lasttestedversion)
2410 2385
2411 2386 fm.condwrite(ui.verbose and extsource, 'source',
2412 2387 _(' location: %s\n'), extsource or "")
2413 2388
2414 2389 if ui.verbose:
2415 2390 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
2416 2391 fm.data(bundled=isinternal)
2417 2392
2418 2393 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2419 2394 _(' tested with: %s\n'),
2420 2395 fm.formatlist(exttestedwith, name='ver'))
2421 2396
2422 2397 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2423 2398 _(' bug reporting: %s\n'), extbuglink or "")
2424 2399
2425 2400 fm.end()
2426 2401
2427 2402 @command('debugfileset',
2428 2403 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2429 2404 _('[-r REV] FILESPEC'))
2430 2405 def debugfileset(ui, repo, expr, **opts):
2431 2406 '''parse and apply a fileset specification'''
2432 2407 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2433 2408 if ui.verbose:
2434 2409 tree = fileset.parse(expr)
2435 2410 ui.note(fileset.prettyformat(tree), "\n")
2436 2411
2437 2412 for f in ctx.getfileset(expr):
2438 2413 ui.write("%s\n" % f)
2439 2414
2440 2415 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2441 2416 def debugfsinfo(ui, path="."):
2442 2417 """show information detected about current filesystem"""
2443 2418 util.writefile('.debugfsinfo', '')
2444 2419 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2445 2420 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2446 2421 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2447 2422 ui.write(('case-sensitive: %s\n') % (util.fscasesensitive('.debugfsinfo')
2448 2423 and 'yes' or 'no'))
2449 2424 os.unlink('.debugfsinfo')
2450 2425
2451 2426 @command('debuggetbundle',
2452 2427 [('H', 'head', [], _('id of head node'), _('ID')),
2453 2428 ('C', 'common', [], _('id of common node'), _('ID')),
2454 2429 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2455 2430 _('REPO FILE [-H|-C ID]...'),
2456 2431 norepo=True)
2457 2432 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2458 2433 """retrieves a bundle from a repo
2459 2434
2460 2435 Every ID must be a full-length hex node id string. Saves the bundle to the
2461 2436 given file.
2462 2437 """
2463 2438 repo = hg.peer(ui, opts, repopath)
2464 2439 if not repo.capable('getbundle'):
2465 2440 raise error.Abort("getbundle() not supported by target repository")
2466 2441 args = {}
2467 2442 if common:
2468 2443 args['common'] = [bin(s) for s in common]
2469 2444 if head:
2470 2445 args['heads'] = [bin(s) for s in head]
2471 2446 # TODO: get desired bundlecaps from command line.
2472 2447 args['bundlecaps'] = None
2473 2448 bundle = repo.getbundle('debug', **args)
2474 2449
2475 2450 bundletype = opts.get('type', 'bzip2').lower()
2476 2451 btypes = {'none': 'HG10UN',
2477 2452 'bzip2': 'HG10BZ',
2478 2453 'gzip': 'HG10GZ',
2479 2454 'bundle2': 'HG20'}
2480 2455 bundletype = btypes.get(bundletype)
2481 2456 if bundletype not in bundle2.bundletypes:
2482 2457 raise error.Abort(_('unknown bundle type specified with --type'))
2483 2458 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2484 2459
2485 2460 @command('debugignore', [], '[FILE]')
2486 2461 def debugignore(ui, repo, *files, **opts):
2487 2462 """display the combined ignore pattern and information about ignored files
2488 2463
2489 2464 With no argument display the combined ignore pattern.
2490 2465
2491 2466 Given space separated file names, shows if the given file is ignored and
2492 2467 if so, show the ignore rule (file and line number) that matched it.
2493 2468 """
2494 2469 ignore = repo.dirstate._ignore
2495 2470 if not files:
2496 2471 # Show all the patterns
2497 2472 includepat = getattr(ignore, 'includepat', None)
2498 2473 if includepat is not None:
2499 2474 ui.write("%s\n" % includepat)
2500 2475 else:
2501 2476 raise error.Abort(_("no ignore patterns found"))
2502 2477 else:
2503 2478 for f in files:
2504 2479 nf = util.normpath(f)
2505 2480 ignored = None
2506 2481 ignoredata = None
2507 2482 if nf != '.':
2508 2483 if ignore(nf):
2509 2484 ignored = nf
2510 2485 ignoredata = repo.dirstate._ignorefileandline(nf)
2511 2486 else:
2512 2487 for p in util.finddirs(nf):
2513 2488 if ignore(p):
2514 2489 ignored = p
2515 2490 ignoredata = repo.dirstate._ignorefileandline(p)
2516 2491 break
2517 2492 if ignored:
2518 2493 if ignored == nf:
2519 2494 ui.write(_("%s is ignored\n") % f)
2520 2495 else:
2521 2496 ui.write(_("%s is ignored because of "
2522 2497 "containing folder %s\n")
2523 2498 % (f, ignored))
2524 2499 ignorefile, lineno, line = ignoredata
2525 2500 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
2526 2501 % (ignorefile, lineno, line))
2527 2502 else:
2528 2503 ui.write(_("%s is not ignored\n") % f)
2529 2504
2530 2505 @command('debugindex', debugrevlogopts +
2531 2506 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2532 2507 _('[-f FORMAT] -c|-m|FILE'),
2533 2508 optionalrepo=True)
2534 2509 def debugindex(ui, repo, file_=None, **opts):
2535 2510 """dump the contents of an index file"""
2536 2511 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2537 2512 format = opts.get('format', 0)
2538 2513 if format not in (0, 1):
2539 2514 raise error.Abort(_("unknown format %d") % format)
2540 2515
2541 2516 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2542 2517 if generaldelta:
2543 2518 basehdr = ' delta'
2544 2519 else:
2545 2520 basehdr = ' base'
2546 2521
2547 2522 if ui.debugflag:
2548 2523 shortfn = hex
2549 2524 else:
2550 2525 shortfn = short
2551 2526
2552 2527 # There might not be anything in r, so have a sane default
2553 2528 idlen = 12
2554 2529 for i in r:
2555 2530 idlen = len(shortfn(r.node(i)))
2556 2531 break
2557 2532
2558 2533 if format == 0:
2559 2534 ui.write((" rev offset length " + basehdr + " linkrev"
2560 2535 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2561 2536 elif format == 1:
2562 2537 ui.write((" rev flag offset length"
2563 2538 " size " + basehdr + " link p1 p2"
2564 2539 " %s\n") % "nodeid".rjust(idlen))
2565 2540
2566 2541 for i in r:
2567 2542 node = r.node(i)
2568 2543 if generaldelta:
2569 2544 base = r.deltaparent(i)
2570 2545 else:
2571 2546 base = r.chainbase(i)
2572 2547 if format == 0:
2573 2548 try:
2574 2549 pp = r.parents(node)
2575 2550 except Exception:
2576 2551 pp = [nullid, nullid]
2577 2552 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2578 2553 i, r.start(i), r.length(i), base, r.linkrev(i),
2579 2554 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2580 2555 elif format == 1:
2581 2556 pr = r.parentrevs(i)
2582 2557 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2583 2558 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2584 2559 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2585 2560
2586 2561 @command('debugindexdot', debugrevlogopts,
2587 2562 _('-c|-m|FILE'), optionalrepo=True)
2588 2563 def debugindexdot(ui, repo, file_=None, **opts):
2589 2564 """dump an index DAG as a graphviz dot file"""
2590 2565 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2591 2566 ui.write(("digraph G {\n"))
2592 2567 for i in r:
2593 2568 node = r.node(i)
2594 2569 pp = r.parents(node)
2595 2570 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2596 2571 if pp[1] != nullid:
2597 2572 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2598 2573 ui.write("}\n")
2599 2574
2600 2575 @command('debugdeltachain',
2601 2576 debugrevlogopts + formatteropts,
2602 2577 _('-c|-m|FILE'),
2603 2578 optionalrepo=True)
2604 2579 def debugdeltachain(ui, repo, file_=None, **opts):
2605 2580 """dump information about delta chains in a revlog
2606 2581
2607 2582 Output can be templatized. Available template keywords are:
2608 2583
2609 2584 :``rev``: revision number
2610 2585 :``chainid``: delta chain identifier (numbered by unique base)
2611 2586 :``chainlen``: delta chain length to this revision
2612 2587 :``prevrev``: previous revision in delta chain
2613 2588 :``deltatype``: role of delta / how it was computed
2614 2589 :``compsize``: compressed size of revision
2615 2590 :``uncompsize``: uncompressed size of revision
2616 2591 :``chainsize``: total size of compressed revisions in chain
2617 2592 :``chainratio``: total chain size divided by uncompressed revision size
2618 2593 (new delta chains typically start at ratio 2.00)
2619 2594 :``lindist``: linear distance from base revision in delta chain to end
2620 2595 of this revision
2621 2596 :``extradist``: total size of revisions not part of this delta chain from
2622 2597 base of delta chain to end of this revision; a measurement
2623 2598 of how much extra data we need to read/seek across to read
2624 2599 the delta chain for this revision
2625 2600 :``extraratio``: extradist divided by chainsize; another representation of
2626 2601 how much unrelated data is needed to load this delta chain
2627 2602 """
2628 2603 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2629 2604 index = r.index
2630 2605 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2631 2606
2632 2607 def revinfo(rev):
2633 2608 e = index[rev]
2634 2609 compsize = e[1]
2635 2610 uncompsize = e[2]
2636 2611 chainsize = 0
2637 2612
2638 2613 if generaldelta:
2639 2614 if e[3] == e[5]:
2640 2615 deltatype = 'p1'
2641 2616 elif e[3] == e[6]:
2642 2617 deltatype = 'p2'
2643 2618 elif e[3] == rev - 1:
2644 2619 deltatype = 'prev'
2645 2620 elif e[3] == rev:
2646 2621 deltatype = 'base'
2647 2622 else:
2648 2623 deltatype = 'other'
2649 2624 else:
2650 2625 if e[3] == rev:
2651 2626 deltatype = 'base'
2652 2627 else:
2653 2628 deltatype = 'prev'
2654 2629
2655 2630 chain = r._deltachain(rev)[0]
2656 2631 for iterrev in chain:
2657 2632 e = index[iterrev]
2658 2633 chainsize += e[1]
2659 2634
2660 2635 return compsize, uncompsize, deltatype, chain, chainsize
2661 2636
2662 2637 fm = ui.formatter('debugdeltachain', opts)
2663 2638
2664 2639 fm.plain(' rev chain# chainlen prev delta '
2665 2640 'size rawsize chainsize ratio lindist extradist '
2666 2641 'extraratio\n')
2667 2642
2668 2643 chainbases = {}
2669 2644 for rev in r:
2670 2645 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2671 2646 chainbase = chain[0]
2672 2647 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2673 2648 basestart = r.start(chainbase)
2674 2649 revstart = r.start(rev)
2675 2650 lineardist = revstart + comp - basestart
2676 2651 extradist = lineardist - chainsize
2677 2652 try:
2678 2653 prevrev = chain[-2]
2679 2654 except IndexError:
2680 2655 prevrev = -1
2681 2656
2682 2657 chainratio = float(chainsize) / float(uncomp)
2683 2658 extraratio = float(extradist) / float(chainsize)
2684 2659
2685 2660 fm.startitem()
2686 2661 fm.write('rev chainid chainlen prevrev deltatype compsize '
2687 2662 'uncompsize chainsize chainratio lindist extradist '
2688 2663 'extraratio',
2689 2664 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2690 2665 rev, chainid, len(chain), prevrev, deltatype, comp,
2691 2666 uncomp, chainsize, chainratio, lineardist, extradist,
2692 2667 extraratio,
2693 2668 rev=rev, chainid=chainid, chainlen=len(chain),
2694 2669 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2695 2670 uncompsize=uncomp, chainsize=chainsize,
2696 2671 chainratio=chainratio, lindist=lineardist,
2697 2672 extradist=extradist, extraratio=extraratio)
2698 2673
2699 2674 fm.end()
2700 2675
2701 2676 @command('debuginstall', [] + formatteropts, '', norepo=True)
2702 2677 def debuginstall(ui, **opts):
2703 2678 '''test Mercurial installation
2704 2679
2705 2680 Returns 0 on success.
2706 2681 '''
2707 2682
2708 2683 def writetemp(contents):
2709 2684 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2710 2685 f = os.fdopen(fd, "wb")
2711 2686 f.write(contents)
2712 2687 f.close()
2713 2688 return name
2714 2689
2715 2690 problems = 0
2716 2691
2717 2692 fm = ui.formatter('debuginstall', opts)
2718 2693 fm.startitem()
2719 2694
2720 2695 # encoding
2721 2696 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2722 2697 err = None
2723 2698 try:
2724 2699 encoding.fromlocal("test")
2725 2700 except error.Abort as inst:
2726 2701 err = inst
2727 2702 problems += 1
2728 2703 fm.condwrite(err, 'encodingerror', _(" %s\n"
2729 2704 " (check that your locale is properly set)\n"), err)
2730 2705
2731 2706 # Python
2732 2707 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2733 2708 sys.executable)
2734 2709 fm.write('pythonver', _("checking Python version (%s)\n"),
2735 2710 ("%s.%s.%s" % sys.version_info[:3]))
2736 2711 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2737 2712 os.path.dirname(os.__file__))
2738 2713
2739 2714 # hg version
2740 2715 hgver = util.version()
2741 2716 fm.write('hgver', _("checking Mercurial version (%s)\n"),
2742 2717 hgver.split('+')[0])
2743 2718 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
2744 2719 '+'.join(hgver.split('+')[1:]))
2745 2720
2746 2721 # compiled modules
2747 2722 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
2748 2723 policy.policy)
2749 2724 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2750 2725 os.path.dirname(__file__))
2751 2726
2752 2727 err = None
2753 2728 try:
2754 2729 from . import (
2755 2730 base85,
2756 2731 bdiff,
2757 2732 mpatch,
2758 2733 osutil,
2759 2734 )
2760 2735 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2761 2736 except Exception as inst:
2762 2737 err = inst
2763 2738 problems += 1
2764 2739 fm.condwrite(err, 'extensionserror', " %s\n", err)
2765 2740
2766 2741 # templates
2767 2742 p = templater.templatepaths()
2768 2743 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2769 2744 fm.condwrite(not p, '', _(" no template directories found\n"))
2770 2745 if p:
2771 2746 m = templater.templatepath("map-cmdline.default")
2772 2747 if m:
2773 2748 # template found, check if it is working
2774 2749 err = None
2775 2750 try:
2776 2751 templater.templater.frommapfile(m)
2777 2752 except Exception as inst:
2778 2753 err = inst
2779 2754 p = None
2780 2755 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2781 2756 else:
2782 2757 p = None
2783 2758 fm.condwrite(p, 'defaulttemplate',
2784 2759 _("checking default template (%s)\n"), m)
2785 2760 fm.condwrite(not m, 'defaulttemplatenotfound',
2786 2761 _(" template '%s' not found\n"), "default")
2787 2762 if not p:
2788 2763 problems += 1
2789 2764 fm.condwrite(not p, '',
2790 2765 _(" (templates seem to have been installed incorrectly)\n"))
2791 2766
2792 2767 # editor
2793 2768 editor = ui.geteditor()
2794 2769 editor = util.expandpath(editor)
2795 2770 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2796 2771 cmdpath = util.findexe(shlex.split(editor)[0])
2797 2772 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2798 2773 _(" No commit editor set and can't find %s in PATH\n"
2799 2774 " (specify a commit editor in your configuration"
2800 2775 " file)\n"), not cmdpath and editor == 'vi' and editor)
2801 2776 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2802 2777 _(" Can't find editor '%s' in PATH\n"
2803 2778 " (specify a commit editor in your configuration"
2804 2779 " file)\n"), not cmdpath and editor)
2805 2780 if not cmdpath and editor != 'vi':
2806 2781 problems += 1
2807 2782
2808 2783 # check username
2809 2784 username = None
2810 2785 err = None
2811 2786 try:
2812 2787 username = ui.username()
2813 2788 except error.Abort as e:
2814 2789 err = e
2815 2790 problems += 1
2816 2791
2817 2792 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2818 2793 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2819 2794 " (specify a username in your configuration file)\n"), err)
2820 2795
2821 2796 fm.condwrite(not problems, '',
2822 2797 _("no problems detected\n"))
2823 2798 if not problems:
2824 2799 fm.data(problems=problems)
2825 2800 fm.condwrite(problems, 'problems',
2826 2801 _("%s problems detected,"
2827 2802 " please check your install!\n"), problems)
2828 2803 fm.end()
2829 2804
2830 2805 return problems
2831 2806
2832 2807 @command('debugknown', [], _('REPO ID...'), norepo=True)
2833 2808 def debugknown(ui, repopath, *ids, **opts):
2834 2809 """test whether node ids are known to a repo
2835 2810
2836 2811 Every ID must be a full-length hex node id string. Returns a list of 0s
2837 2812 and 1s indicating unknown/known.
2838 2813 """
2839 2814 repo = hg.peer(ui, opts, repopath)
2840 2815 if not repo.capable('known'):
2841 2816 raise error.Abort("known() not supported by target repository")
2842 2817 flags = repo.known([bin(s) for s in ids])
2843 2818 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2844 2819
2845 2820 @command('debuglabelcomplete', [], _('LABEL...'))
2846 2821 def debuglabelcomplete(ui, repo, *args):
2847 2822 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2848 2823 debugnamecomplete(ui, repo, *args)
2849 2824
2850 2825 @command('debugmergestate', [], '')
2851 2826 def debugmergestate(ui, repo, *args):
2852 2827 """print merge state
2853 2828
2854 2829 Use --verbose to print out information about whether v1 or v2 merge state
2855 2830 was chosen."""
2856 2831 def _hashornull(h):
2857 2832 if h == nullhex:
2858 2833 return 'null'
2859 2834 else:
2860 2835 return h
2861 2836
2862 2837 def printrecords(version):
2863 2838 ui.write(('* version %s records\n') % version)
2864 2839 if version == 1:
2865 2840 records = v1records
2866 2841 else:
2867 2842 records = v2records
2868 2843
2869 2844 for rtype, record in records:
2870 2845 # pretty print some record types
2871 2846 if rtype == 'L':
2872 2847 ui.write(('local: %s\n') % record)
2873 2848 elif rtype == 'O':
2874 2849 ui.write(('other: %s\n') % record)
2875 2850 elif rtype == 'm':
2876 2851 driver, mdstate = record.split('\0', 1)
2877 2852 ui.write(('merge driver: %s (state "%s")\n')
2878 2853 % (driver, mdstate))
2879 2854 elif rtype in 'FDC':
2880 2855 r = record.split('\0')
2881 2856 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2882 2857 if version == 1:
2883 2858 onode = 'not stored in v1 format'
2884 2859 flags = r[7]
2885 2860 else:
2886 2861 onode, flags = r[7:9]
2887 2862 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2888 2863 % (f, rtype, state, _hashornull(hash)))
2889 2864 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2890 2865 ui.write((' ancestor path: %s (node %s)\n')
2891 2866 % (afile, _hashornull(anode)))
2892 2867 ui.write((' other path: %s (node %s)\n')
2893 2868 % (ofile, _hashornull(onode)))
2894 2869 elif rtype == 'f':
2895 2870 filename, rawextras = record.split('\0', 1)
2896 2871 extras = rawextras.split('\0')
2897 2872 i = 0
2898 2873 extrastrings = []
2899 2874 while i < len(extras):
2900 2875 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2901 2876 i += 2
2902 2877
2903 2878 ui.write(('file extras: %s (%s)\n')
2904 2879 % (filename, ', '.join(extrastrings)))
2905 2880 elif rtype == 'l':
2906 2881 labels = record.split('\0', 2)
2907 2882 labels = [l for l in labels if len(l) > 0]
2908 2883 ui.write(('labels:\n'))
2909 2884 ui.write((' local: %s\n' % labels[0]))
2910 2885 ui.write((' other: %s\n' % labels[1]))
2911 2886 if len(labels) > 2:
2912 2887 ui.write((' base: %s\n' % labels[2]))
2913 2888 else:
2914 2889 ui.write(('unrecognized entry: %s\t%s\n')
2915 2890 % (rtype, record.replace('\0', '\t')))
2916 2891
2917 2892 # Avoid mergestate.read() since it may raise an exception for unsupported
2918 2893 # merge state records. We shouldn't be doing this, but this is OK since this
2919 2894 # command is pretty low-level.
2920 2895 ms = mergemod.mergestate(repo)
2921 2896
2922 2897 # sort so that reasonable information is on top
2923 2898 v1records = ms._readrecordsv1()
2924 2899 v2records = ms._readrecordsv2()
2925 2900 order = 'LOml'
2926 2901 def key(r):
2927 2902 idx = order.find(r[0])
2928 2903 if idx == -1:
2929 2904 return (1, r[1])
2930 2905 else:
2931 2906 return (0, idx)
2932 2907 v1records.sort(key=key)
2933 2908 v2records.sort(key=key)
2934 2909
2935 2910 if not v1records and not v2records:
2936 2911 ui.write(('no merge state found\n'))
2937 2912 elif not v2records:
2938 2913 ui.note(('no version 2 merge state\n'))
2939 2914 printrecords(1)
2940 2915 elif ms._v1v2match(v1records, v2records):
2941 2916 ui.note(('v1 and v2 states match: using v2\n'))
2942 2917 printrecords(2)
2943 2918 else:
2944 2919 ui.note(('v1 and v2 states mismatch: using v1\n'))
2945 2920 printrecords(1)
2946 2921 if ui.verbose:
2947 2922 printrecords(2)
2948 2923
2949 2924 @command('debugnamecomplete', [], _('NAME...'))
2950 2925 def debugnamecomplete(ui, repo, *args):
2951 2926 '''complete "names" - tags, open branch names, bookmark names'''
2952 2927
2953 2928 names = set()
2954 2929 # since we previously only listed open branches, we will handle that
2955 2930 # specially (after this for loop)
2956 2931 for name, ns in repo.names.iteritems():
2957 2932 if name != 'branches':
2958 2933 names.update(ns.listnames(repo))
2959 2934 names.update(tag for (tag, heads, tip, closed)
2960 2935 in repo.branchmap().iterbranches() if not closed)
2961 2936 completions = set()
2962 2937 if not args:
2963 2938 args = ['']
2964 2939 for a in args:
2965 2940 completions.update(n for n in names if n.startswith(a))
2966 2941 ui.write('\n'.join(sorted(completions)))
2967 2942 ui.write('\n')
2968 2943
2969 2944 @command('debuglocks',
2970 2945 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2971 2946 ('W', 'force-wlock', None,
2972 2947 _('free the working state lock (DANGEROUS)'))],
2973 2948 _('[OPTION]...'))
2974 2949 def debuglocks(ui, repo, **opts):
2975 2950 """show or modify state of locks
2976 2951
2977 2952 By default, this command will show which locks are held. This
2978 2953 includes the user and process holding the lock, the amount of time
2979 2954 the lock has been held, and the machine name where the process is
2980 2955 running if it's not local.
2981 2956
2982 2957 Locks protect the integrity of Mercurial's data, so should be
2983 2958 treated with care. System crashes or other interruptions may cause
2984 2959 locks to not be properly released, though Mercurial will usually
2985 2960 detect and remove such stale locks automatically.
2986 2961
2987 2962 However, detecting stale locks may not always be possible (for
2988 2963 instance, on a shared filesystem). Removing locks may also be
2989 2964 blocked by filesystem permissions.
2990 2965
2991 2966 Returns 0 if no locks are held.
2992 2967
2993 2968 """
2994 2969
2995 2970 if opts.get('force_lock'):
2996 2971 repo.svfs.unlink('lock')
2997 2972 if opts.get('force_wlock'):
2998 2973 repo.vfs.unlink('wlock')
2999 2974 if opts.get('force_lock') or opts.get('force_lock'):
3000 2975 return 0
3001 2976
3002 2977 now = time.time()
3003 2978 held = 0
3004 2979
3005 2980 def report(vfs, name, method):
3006 2981 # this causes stale locks to get reaped for more accurate reporting
3007 2982 try:
3008 2983 l = method(False)
3009 2984 except error.LockHeld:
3010 2985 l = None
3011 2986
3012 2987 if l:
3013 2988 l.release()
3014 2989 else:
3015 2990 try:
3016 2991 stat = vfs.lstat(name)
3017 2992 age = now - stat.st_mtime
3018 2993 user = util.username(stat.st_uid)
3019 2994 locker = vfs.readlock(name)
3020 2995 if ":" in locker:
3021 2996 host, pid = locker.split(':')
3022 2997 if host == socket.gethostname():
3023 2998 locker = 'user %s, process %s' % (user, pid)
3024 2999 else:
3025 3000 locker = 'user %s, process %s, host %s' \
3026 3001 % (user, pid, host)
3027 3002 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
3028 3003 return 1
3029 3004 except OSError as e:
3030 3005 if e.errno != errno.ENOENT:
3031 3006 raise
3032 3007
3033 3008 ui.write(("%-6s free\n") % (name + ":"))
3034 3009 return 0
3035 3010
3036 3011 held += report(repo.svfs, "lock", repo.lock)
3037 3012 held += report(repo.vfs, "wlock", repo.wlock)
3038 3013
3039 3014 return held
3040 3015
3041 3016 @command('debugobsolete',
3042 3017 [('', 'flags', 0, _('markers flag')),
3043 3018 ('', 'record-parents', False,
3044 3019 _('record parent information for the precursor')),
3045 3020 ('r', 'rev', [], _('display markers relevant to REV')),
3046 3021 ('', 'index', False, _('display index of the marker')),
3047 3022 ('', 'delete', [], _('delete markers specified by indices')),
3048 3023 ] + commitopts2 + formatteropts,
3049 3024 _('[OBSOLETED [REPLACEMENT ...]]'))
3050 3025 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3051 3026 """create arbitrary obsolete marker
3052 3027
3053 3028 With no arguments, displays the list of obsolescence markers."""
3054 3029
3055 3030 def parsenodeid(s):
3056 3031 try:
3057 3032 # We do not use revsingle/revrange functions here to accept
3058 3033 # arbitrary node identifiers, possibly not present in the
3059 3034 # local repository.
3060 3035 n = bin(s)
3061 3036 if len(n) != len(nullid):
3062 3037 raise TypeError()
3063 3038 return n
3064 3039 except TypeError:
3065 3040 raise error.Abort('changeset references must be full hexadecimal '
3066 3041 'node identifiers')
3067 3042
3068 3043 if opts.get('delete'):
3069 3044 indices = []
3070 3045 for v in opts.get('delete'):
3071 3046 try:
3072 3047 indices.append(int(v))
3073 3048 except ValueError:
3074 3049 raise error.Abort(_('invalid index value: %r') % v,
3075 3050 hint=_('use integers for indices'))
3076 3051
3077 3052 if repo.currenttransaction():
3078 3053 raise error.Abort(_('cannot delete obsmarkers in the middle '
3079 3054 'of transaction.'))
3080 3055
3081 3056 with repo.lock():
3082 3057 n = repair.deleteobsmarkers(repo.obsstore, indices)
3083 3058 ui.write(_('deleted %i obsolescense markers\n') % n)
3084 3059
3085 3060 return
3086 3061
3087 3062 if precursor is not None:
3088 3063 if opts['rev']:
3089 3064 raise error.Abort('cannot select revision when creating marker')
3090 3065 metadata = {}
3091 3066 metadata['user'] = opts['user'] or ui.username()
3092 3067 succs = tuple(parsenodeid(succ) for succ in successors)
3093 3068 l = repo.lock()
3094 3069 try:
3095 3070 tr = repo.transaction('debugobsolete')
3096 3071 try:
3097 3072 date = opts.get('date')
3098 3073 if date:
3099 3074 date = util.parsedate(date)
3100 3075 else:
3101 3076 date = None
3102 3077 prec = parsenodeid(precursor)
3103 3078 parents = None
3104 3079 if opts['record_parents']:
3105 3080 if prec not in repo.unfiltered():
3106 3081 raise error.Abort('cannot used --record-parents on '
3107 3082 'unknown changesets')
3108 3083 parents = repo.unfiltered()[prec].parents()
3109 3084 parents = tuple(p.node() for p in parents)
3110 3085 repo.obsstore.create(tr, prec, succs, opts['flags'],
3111 3086 parents=parents, date=date,
3112 3087 metadata=metadata)
3113 3088 tr.close()
3114 3089 except ValueError as exc:
3115 3090 raise error.Abort(_('bad obsmarker input: %s') % exc)
3116 3091 finally:
3117 3092 tr.release()
3118 3093 finally:
3119 3094 l.release()
3120 3095 else:
3121 3096 if opts['rev']:
3122 3097 revs = scmutil.revrange(repo, opts['rev'])
3123 3098 nodes = [repo[r].node() for r in revs]
3124 3099 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3125 3100 markers.sort(key=lambda x: x._data)
3126 3101 else:
3127 3102 markers = obsolete.getmarkers(repo)
3128 3103
3129 3104 markerstoiter = markers
3130 3105 isrelevant = lambda m: True
3131 3106 if opts.get('rev') and opts.get('index'):
3132 3107 markerstoiter = obsolete.getmarkers(repo)
3133 3108 markerset = set(markers)
3134 3109 isrelevant = lambda m: m in markerset
3135 3110
3136 3111 fm = ui.formatter('debugobsolete', opts)
3137 3112 for i, m in enumerate(markerstoiter):
3138 3113 if not isrelevant(m):
3139 3114 # marker can be irrelevant when we're iterating over a set
3140 3115 # of markers (markerstoiter) which is bigger than the set
3141 3116 # of markers we want to display (markers)
3142 3117 # this can happen if both --index and --rev options are
3143 3118 # provided and thus we need to iterate over all of the markers
3144 3119 # to get the correct indices, but only display the ones that
3145 3120 # are relevant to --rev value
3146 3121 continue
3147 3122 fm.startitem()
3148 3123 ind = i if opts.get('index') else None
3149 3124 cmdutil.showmarker(fm, m, index=ind)
3150 3125 fm.end()
3151 3126
3152 3127 @command('debugpathcomplete',
3153 3128 [('f', 'full', None, _('complete an entire path')),
3154 3129 ('n', 'normal', None, _('show only normal files')),
3155 3130 ('a', 'added', None, _('show only added files')),
3156 3131 ('r', 'removed', None, _('show only removed files'))],
3157 3132 _('FILESPEC...'))
3158 3133 def debugpathcomplete(ui, repo, *specs, **opts):
3159 3134 '''complete part or all of a tracked path
3160 3135
3161 3136 This command supports shells that offer path name completion. It
3162 3137 currently completes only files already known to the dirstate.
3163 3138
3164 3139 Completion extends only to the next path segment unless
3165 3140 --full is specified, in which case entire paths are used.'''
3166 3141
3167 3142 def complete(path, acceptable):
3168 3143 dirstate = repo.dirstate
3169 3144 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3170 3145 rootdir = repo.root + os.sep
3171 3146 if spec != repo.root and not spec.startswith(rootdir):
3172 3147 return [], []
3173 3148 if os.path.isdir(spec):
3174 3149 spec += '/'
3175 3150 spec = spec[len(rootdir):]
3176 3151 fixpaths = os.sep != '/'
3177 3152 if fixpaths:
3178 3153 spec = spec.replace(os.sep, '/')
3179 3154 speclen = len(spec)
3180 3155 fullpaths = opts['full']
3181 3156 files, dirs = set(), set()
3182 3157 adddir, addfile = dirs.add, files.add
3183 3158 for f, st in dirstate.iteritems():
3184 3159 if f.startswith(spec) and st[0] in acceptable:
3185 3160 if fixpaths:
3186 3161 f = f.replace('/', os.sep)
3187 3162 if fullpaths:
3188 3163 addfile(f)
3189 3164 continue
3190 3165 s = f.find(os.sep, speclen)
3191 3166 if s >= 0:
3192 3167 adddir(f[:s])
3193 3168 else:
3194 3169 addfile(f)
3195 3170 return files, dirs
3196 3171
3197 3172 acceptable = ''
3198 3173 if opts['normal']:
3199 3174 acceptable += 'nm'
3200 3175 if opts['added']:
3201 3176 acceptable += 'a'
3202 3177 if opts['removed']:
3203 3178 acceptable += 'r'
3204 3179 cwd = repo.getcwd()
3205 3180 if not specs:
3206 3181 specs = ['.']
3207 3182
3208 3183 files, dirs = set(), set()
3209 3184 for spec in specs:
3210 3185 f, d = complete(spec, acceptable or 'nmar')
3211 3186 files.update(f)
3212 3187 dirs.update(d)
3213 3188 files.update(dirs)
3214 3189 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3215 3190 ui.write('\n')
3216 3191
3217 3192 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3218 3193 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3219 3194 '''access the pushkey key/value protocol
3220 3195
3221 3196 With two args, list the keys in the given namespace.
3222 3197
3223 3198 With five args, set a key to new if it currently is set to old.
3224 3199 Reports success or failure.
3225 3200 '''
3226 3201
3227 3202 target = hg.peer(ui, {}, repopath)
3228 3203 if keyinfo:
3229 3204 key, old, new = keyinfo
3230 3205 r = target.pushkey(namespace, key, old, new)
3231 3206 ui.status(str(r) + '\n')
3232 3207 return not r
3233 3208 else:
3234 3209 for k, v in sorted(target.listkeys(namespace).iteritems()):
3235 3210 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3236 3211 v.encode('string-escape')))
3237 3212
3238 3213 @command('debugpvec', [], _('A B'))
3239 3214 def debugpvec(ui, repo, a, b=None):
3240 3215 ca = scmutil.revsingle(repo, a)
3241 3216 cb = scmutil.revsingle(repo, b)
3242 3217 pa = pvec.ctxpvec(ca)
3243 3218 pb = pvec.ctxpvec(cb)
3244 3219 if pa == pb:
3245 3220 rel = "="
3246 3221 elif pa > pb:
3247 3222 rel = ">"
3248 3223 elif pa < pb:
3249 3224 rel = "<"
3250 3225 elif pa | pb:
3251 3226 rel = "|"
3252 3227 ui.write(_("a: %s\n") % pa)
3253 3228 ui.write(_("b: %s\n") % pb)
3254 3229 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3255 3230 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3256 3231 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3257 3232 pa.distance(pb), rel))
3258 3233
3259 3234 @command('debugrebuilddirstate|debugrebuildstate',
3260 3235 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3261 3236 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3262 3237 'the working copy parent')),
3263 3238 ],
3264 3239 _('[-r REV]'))
3265 3240 def debugrebuilddirstate(ui, repo, rev, **opts):
3266 3241 """rebuild the dirstate as it would look like for the given revision
3267 3242
3268 3243 If no revision is specified the first current parent will be used.
3269 3244
3270 3245 The dirstate will be set to the files of the given revision.
3271 3246 The actual working directory content or existing dirstate
3272 3247 information such as adds or removes is not considered.
3273 3248
3274 3249 ``minimal`` will only rebuild the dirstate status for files that claim to be
3275 3250 tracked but are not in the parent manifest, or that exist in the parent
3276 3251 manifest but are not in the dirstate. It will not change adds, removes, or
3277 3252 modified files that are in the working copy parent.
3278 3253
3279 3254 One use of this command is to make the next :hg:`status` invocation
3280 3255 check the actual file content.
3281 3256 """
3282 3257 ctx = scmutil.revsingle(repo, rev)
3283 3258 with repo.wlock():
3284 3259 dirstate = repo.dirstate
3285 3260 changedfiles = None
3286 3261 # See command doc for what minimal does.
3287 3262 if opts.get('minimal'):
3288 3263 manifestfiles = set(ctx.manifest().keys())
3289 3264 dirstatefiles = set(dirstate)
3290 3265 manifestonly = manifestfiles - dirstatefiles
3291 3266 dsonly = dirstatefiles - manifestfiles
3292 3267 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3293 3268 changedfiles = manifestonly | dsnotadded
3294 3269
3295 3270 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3296 3271
3297 3272 @command('debugrebuildfncache', [], '')
3298 3273 def debugrebuildfncache(ui, repo):
3299 3274 """rebuild the fncache file"""
3300 3275 repair.rebuildfncache(ui, repo)
3301 3276
3302 3277 @command('debugrename',
3303 3278 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3304 3279 _('[-r REV] FILE'))
3305 3280 def debugrename(ui, repo, file1, *pats, **opts):
3306 3281 """dump rename information"""
3307 3282
3308 3283 ctx = scmutil.revsingle(repo, opts.get('rev'))
3309 3284 m = scmutil.match(ctx, (file1,) + pats, opts)
3310 3285 for abs in ctx.walk(m):
3311 3286 fctx = ctx[abs]
3312 3287 o = fctx.filelog().renamed(fctx.filenode())
3313 3288 rel = m.rel(abs)
3314 3289 if o:
3315 3290 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3316 3291 else:
3317 3292 ui.write(_("%s not renamed\n") % rel)
3318 3293
3319 3294 @command('debugrevlog', debugrevlogopts +
3320 3295 [('d', 'dump', False, _('dump index data'))],
3321 3296 _('-c|-m|FILE'),
3322 3297 optionalrepo=True)
3323 3298 def debugrevlog(ui, repo, file_=None, **opts):
3324 3299 """show data and statistics about a revlog"""
3325 3300 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3326 3301
3327 3302 if opts.get("dump"):
3328 3303 numrevs = len(r)
3329 3304 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
3330 3305 " rawsize totalsize compression heads chainlen\n"))
3331 3306 ts = 0
3332 3307 heads = set()
3333 3308
3334 3309 for rev in xrange(numrevs):
3335 3310 dbase = r.deltaparent(rev)
3336 3311 if dbase == -1:
3337 3312 dbase = rev
3338 3313 cbase = r.chainbase(rev)
3339 3314 clen = r.chainlen(rev)
3340 3315 p1, p2 = r.parentrevs(rev)
3341 3316 rs = r.rawsize(rev)
3342 3317 ts = ts + rs
3343 3318 heads -= set(r.parentrevs(rev))
3344 3319 heads.add(rev)
3345 3320 try:
3346 3321 compression = ts / r.end(rev)
3347 3322 except ZeroDivisionError:
3348 3323 compression = 0
3349 3324 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3350 3325 "%11d %5d %8d\n" %
3351 3326 (rev, p1, p2, r.start(rev), r.end(rev),
3352 3327 r.start(dbase), r.start(cbase),
3353 3328 r.start(p1), r.start(p2),
3354 3329 rs, ts, compression, len(heads), clen))
3355 3330 return 0
3356 3331
3357 3332 v = r.version
3358 3333 format = v & 0xFFFF
3359 3334 flags = []
3360 3335 gdelta = False
3361 3336 if v & revlog.REVLOGNGINLINEDATA:
3362 3337 flags.append('inline')
3363 3338 if v & revlog.REVLOGGENERALDELTA:
3364 3339 gdelta = True
3365 3340 flags.append('generaldelta')
3366 3341 if not flags:
3367 3342 flags = ['(none)']
3368 3343
3369 3344 nummerges = 0
3370 3345 numfull = 0
3371 3346 numprev = 0
3372 3347 nump1 = 0
3373 3348 nump2 = 0
3374 3349 numother = 0
3375 3350 nump1prev = 0
3376 3351 nump2prev = 0
3377 3352 chainlengths = []
3378 3353
3379 3354 datasize = [None, 0, 0]
3380 3355 fullsize = [None, 0, 0]
3381 3356 deltasize = [None, 0, 0]
3382 3357
3383 3358 def addsize(size, l):
3384 3359 if l[0] is None or size < l[0]:
3385 3360 l[0] = size
3386 3361 if size > l[1]:
3387 3362 l[1] = size
3388 3363 l[2] += size
3389 3364
3390 3365 numrevs = len(r)
3391 3366 for rev in xrange(numrevs):
3392 3367 p1, p2 = r.parentrevs(rev)
3393 3368 delta = r.deltaparent(rev)
3394 3369 if format > 0:
3395 3370 addsize(r.rawsize(rev), datasize)
3396 3371 if p2 != nullrev:
3397 3372 nummerges += 1
3398 3373 size = r.length(rev)
3399 3374 if delta == nullrev:
3400 3375 chainlengths.append(0)
3401 3376 numfull += 1
3402 3377 addsize(size, fullsize)
3403 3378 else:
3404 3379 chainlengths.append(chainlengths[delta] + 1)
3405 3380 addsize(size, deltasize)
3406 3381 if delta == rev - 1:
3407 3382 numprev += 1
3408 3383 if delta == p1:
3409 3384 nump1prev += 1
3410 3385 elif delta == p2:
3411 3386 nump2prev += 1
3412 3387 elif delta == p1:
3413 3388 nump1 += 1
3414 3389 elif delta == p2:
3415 3390 nump2 += 1
3416 3391 elif delta != nullrev:
3417 3392 numother += 1
3418 3393
3419 3394 # Adjust size min value for empty cases
3420 3395 for size in (datasize, fullsize, deltasize):
3421 3396 if size[0] is None:
3422 3397 size[0] = 0
3423 3398
3424 3399 numdeltas = numrevs - numfull
3425 3400 numoprev = numprev - nump1prev - nump2prev
3426 3401 totalrawsize = datasize[2]
3427 3402 datasize[2] /= numrevs
3428 3403 fulltotal = fullsize[2]
3429 3404 fullsize[2] /= numfull
3430 3405 deltatotal = deltasize[2]
3431 3406 if numrevs - numfull > 0:
3432 3407 deltasize[2] /= numrevs - numfull
3433 3408 totalsize = fulltotal + deltatotal
3434 3409 avgchainlen = sum(chainlengths) / numrevs
3435 3410 maxchainlen = max(chainlengths)
3436 3411 compratio = 1
3437 3412 if totalsize:
3438 3413 compratio = totalrawsize / totalsize
3439 3414
3440 3415 basedfmtstr = '%%%dd\n'
3441 3416 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3442 3417
3443 3418 def dfmtstr(max):
3444 3419 return basedfmtstr % len(str(max))
3445 3420 def pcfmtstr(max, padding=0):
3446 3421 return basepcfmtstr % (len(str(max)), ' ' * padding)
3447 3422
3448 3423 def pcfmt(value, total):
3449 3424 if total:
3450 3425 return (value, 100 * float(value) / total)
3451 3426 else:
3452 3427 return value, 100.0
3453 3428
3454 3429 ui.write(('format : %d\n') % format)
3455 3430 ui.write(('flags : %s\n') % ', '.join(flags))
3456 3431
3457 3432 ui.write('\n')
3458 3433 fmt = pcfmtstr(totalsize)
3459 3434 fmt2 = dfmtstr(totalsize)
3460 3435 ui.write(('revisions : ') + fmt2 % numrevs)
3461 3436 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3462 3437 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3463 3438 ui.write(('revisions : ') + fmt2 % numrevs)
3464 3439 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3465 3440 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3466 3441 ui.write(('revision size : ') + fmt2 % totalsize)
3467 3442 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3468 3443 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3469 3444
3470 3445 ui.write('\n')
3471 3446 fmt = dfmtstr(max(avgchainlen, compratio))
3472 3447 ui.write(('avg chain length : ') + fmt % avgchainlen)
3473 3448 ui.write(('max chain length : ') + fmt % maxchainlen)
3474 3449 ui.write(('compression ratio : ') + fmt % compratio)
3475 3450
3476 3451 if format > 0:
3477 3452 ui.write('\n')
3478 3453 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3479 3454 % tuple(datasize))
3480 3455 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3481 3456 % tuple(fullsize))
3482 3457 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3483 3458 % tuple(deltasize))
3484 3459
3485 3460 if numdeltas > 0:
3486 3461 ui.write('\n')
3487 3462 fmt = pcfmtstr(numdeltas)
3488 3463 fmt2 = pcfmtstr(numdeltas, 4)
3489 3464 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3490 3465 if numprev > 0:
3491 3466 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3492 3467 numprev))
3493 3468 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3494 3469 numprev))
3495 3470 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3496 3471 numprev))
3497 3472 if gdelta:
3498 3473 ui.write(('deltas against p1 : ')
3499 3474 + fmt % pcfmt(nump1, numdeltas))
3500 3475 ui.write(('deltas against p2 : ')
3501 3476 + fmt % pcfmt(nump2, numdeltas))
3502 3477 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3503 3478 numdeltas))
3504 3479
3505 3480 @command('debugrevspec',
3506 3481 [('', 'optimize', None,
3507 3482 _('print parsed tree after optimizing (DEPRECATED)')),
3508 3483 ('p', 'show-stage', [],
3509 3484 _('print parsed tree at the given stage'), _('NAME')),
3510 3485 ('', 'no-optimized', False, _('evaluate tree without optimization')),
3511 3486 ('', 'verify-optimized', False, _('verify optimized result')),
3512 3487 ],
3513 3488 ('REVSPEC'))
3514 3489 def debugrevspec(ui, repo, expr, **opts):
3515 3490 """parse and apply a revision specification
3516 3491
3517 3492 Use -p/--show-stage option to print the parsed tree at the given stages.
3518 3493 Use -p all to print tree at every stage.
3519 3494
3520 3495 Use --verify-optimized to compare the optimized result with the unoptimized
3521 3496 one. Returns 1 if the optimized result differs.
3522 3497 """
3523 3498 stages = [
3524 3499 ('parsed', lambda tree: tree),
3525 3500 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
3526 3501 ('concatenated', revset.foldconcat),
3527 3502 ('analyzed', revset.analyze),
3528 3503 ('optimized', revset.optimize),
3529 3504 ]
3530 3505 if opts['no_optimized']:
3531 3506 stages = stages[:-1]
3532 3507 if opts['verify_optimized'] and opts['no_optimized']:
3533 3508 raise error.Abort(_('cannot use --verify-optimized with '
3534 3509 '--no-optimized'))
3535 3510 stagenames = set(n for n, f in stages)
3536 3511
3537 3512 showalways = set()
3538 3513 showchanged = set()
3539 3514 if ui.verbose and not opts['show_stage']:
3540 3515 # show parsed tree by --verbose (deprecated)
3541 3516 showalways.add('parsed')
3542 3517 showchanged.update(['expanded', 'concatenated'])
3543 3518 if opts['optimize']:
3544 3519 showalways.add('optimized')
3545 3520 if opts['show_stage'] and opts['optimize']:
3546 3521 raise error.Abort(_('cannot use --optimize with --show-stage'))
3547 3522 if opts['show_stage'] == ['all']:
3548 3523 showalways.update(stagenames)
3549 3524 else:
3550 3525 for n in opts['show_stage']:
3551 3526 if n not in stagenames:
3552 3527 raise error.Abort(_('invalid stage name: %s') % n)
3553 3528 showalways.update(opts['show_stage'])
3554 3529
3555 3530 treebystage = {}
3556 3531 printedtree = None
3557 3532 tree = revset.parse(expr, lookup=repo.__contains__)
3558 3533 for n, f in stages:
3559 3534 treebystage[n] = tree = f(tree)
3560 3535 if n in showalways or (n in showchanged and tree != printedtree):
3561 3536 if opts['show_stage'] or n != 'parsed':
3562 3537 ui.write(("* %s:\n") % n)
3563 3538 ui.write(revset.prettyformat(tree), "\n")
3564 3539 printedtree = tree
3565 3540
3566 3541 if opts['verify_optimized']:
3567 3542 arevs = revset.makematcher(treebystage['analyzed'])(repo)
3568 3543 brevs = revset.makematcher(treebystage['optimized'])(repo)
3569 3544 if ui.verbose:
3570 3545 ui.note(("* analyzed set:\n"), revset.prettyformatset(arevs), "\n")
3571 3546 ui.note(("* optimized set:\n"), revset.prettyformatset(brevs), "\n")
3572 3547 arevs = list(arevs)
3573 3548 brevs = list(brevs)
3574 3549 if arevs == brevs:
3575 3550 return 0
3576 3551 ui.write(('--- analyzed\n'), label='diff.file_a')
3577 3552 ui.write(('+++ optimized\n'), label='diff.file_b')
3578 3553 sm = difflib.SequenceMatcher(None, arevs, brevs)
3579 3554 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3580 3555 if tag in ('delete', 'replace'):
3581 3556 for c in arevs[alo:ahi]:
3582 3557 ui.write('-%s\n' % c, label='diff.deleted')
3583 3558 if tag in ('insert', 'replace'):
3584 3559 for c in brevs[blo:bhi]:
3585 3560 ui.write('+%s\n' % c, label='diff.inserted')
3586 3561 if tag == 'equal':
3587 3562 for c in arevs[alo:ahi]:
3588 3563 ui.write(' %s\n' % c)
3589 3564 return 1
3590 3565
3591 3566 func = revset.makematcher(tree)
3592 3567 revs = func(repo)
3593 3568 if ui.verbose:
3594 3569 ui.note(("* set:\n"), revset.prettyformatset(revs), "\n")
3595 3570 for c in revs:
3596 3571 ui.write("%s\n" % c)
3597 3572
3598 3573 @command('debugsetparents', [], _('REV1 [REV2]'))
3599 3574 def debugsetparents(ui, repo, rev1, rev2=None):
3600 3575 """manually set the parents of the current working directory
3601 3576
3602 3577 This is useful for writing repository conversion tools, but should
3603 3578 be used with care. For example, neither the working directory nor the
3604 3579 dirstate is updated, so file status may be incorrect after running this
3605 3580 command.
3606 3581
3607 3582 Returns 0 on success.
3608 3583 """
3609 3584
3610 3585 r1 = scmutil.revsingle(repo, rev1).node()
3611 3586 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3612 3587
3613 3588 with repo.wlock():
3614 3589 repo.setparents(r1, r2)
3615 3590
3616 3591 @command('debugdirstate|debugstate',
3617 3592 [('', 'nodates', None, _('do not display the saved mtime')),
3618 3593 ('', 'datesort', None, _('sort by saved mtime'))],
3619 3594 _('[OPTION]...'))
3620 3595 def debugstate(ui, repo, **opts):
3621 3596 """show the contents of the current dirstate"""
3622 3597
3623 3598 nodates = opts.get('nodates')
3624 3599 datesort = opts.get('datesort')
3625 3600
3626 3601 timestr = ""
3627 3602 if datesort:
3628 3603 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3629 3604 else:
3630 3605 keyfunc = None # sort by filename
3631 3606 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3632 3607 if ent[3] == -1:
3633 3608 timestr = 'unset '
3634 3609 elif nodates:
3635 3610 timestr = 'set '
3636 3611 else:
3637 3612 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3638 3613 time.localtime(ent[3]))
3639 3614 if ent[1] & 0o20000:
3640 3615 mode = 'lnk'
3641 3616 else:
3642 3617 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3643 3618 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3644 3619 for f in repo.dirstate.copies():
3645 3620 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3646 3621
3647 3622 @command('debugsub',
3648 3623 [('r', 'rev', '',
3649 3624 _('revision to check'), _('REV'))],
3650 3625 _('[-r REV] [REV]'))
3651 3626 def debugsub(ui, repo, rev=None):
3652 3627 ctx = scmutil.revsingle(repo, rev, None)
3653 3628 for k, v in sorted(ctx.substate.items()):
3654 3629 ui.write(('path %s\n') % k)
3655 3630 ui.write((' source %s\n') % v[0])
3656 3631 ui.write((' revision %s\n') % v[1])
3657 3632
3658 3633 @command('debugsuccessorssets',
3659 3634 [],
3660 3635 _('[REV]'))
3661 3636 def debugsuccessorssets(ui, repo, *revs):
3662 3637 """show set of successors for revision
3663 3638
3664 3639 A successors set of changeset A is a consistent group of revisions that
3665 3640 succeed A. It contains non-obsolete changesets only.
3666 3641
3667 3642 In most cases a changeset A has a single successors set containing a single
3668 3643 successor (changeset A replaced by A').
3669 3644
3670 3645 A changeset that is made obsolete with no successors are called "pruned".
3671 3646 Such changesets have no successors sets at all.
3672 3647
3673 3648 A changeset that has been "split" will have a successors set containing
3674 3649 more than one successor.
3675 3650
3676 3651 A changeset that has been rewritten in multiple different ways is called
3677 3652 "divergent". Such changesets have multiple successor sets (each of which
3678 3653 may also be split, i.e. have multiple successors).
3679 3654
3680 3655 Results are displayed as follows::
3681 3656
3682 3657 <rev1>
3683 3658 <successors-1A>
3684 3659 <rev2>
3685 3660 <successors-2A>
3686 3661 <successors-2B1> <successors-2B2> <successors-2B3>
3687 3662
3688 3663 Here rev2 has two possible (i.e. divergent) successors sets. The first
3689 3664 holds one element, whereas the second holds three (i.e. the changeset has
3690 3665 been split).
3691 3666 """
3692 3667 # passed to successorssets caching computation from one call to another
3693 3668 cache = {}
3694 3669 ctx2str = str
3695 3670 node2str = short
3696 3671 if ui.debug():
3697 3672 def ctx2str(ctx):
3698 3673 return ctx.hex()
3699 3674 node2str = hex
3700 3675 for rev in scmutil.revrange(repo, revs):
3701 3676 ctx = repo[rev]
3702 3677 ui.write('%s\n'% ctx2str(ctx))
3703 3678 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3704 3679 if succsset:
3705 3680 ui.write(' ')
3706 3681 ui.write(node2str(succsset[0]))
3707 3682 for node in succsset[1:]:
3708 3683 ui.write(' ')
3709 3684 ui.write(node2str(node))
3710 3685 ui.write('\n')
3711 3686
3712 3687 @command('debugtemplate',
3713 3688 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3714 3689 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3715 3690 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3716 3691 optionalrepo=True)
3717 3692 def debugtemplate(ui, repo, tmpl, **opts):
3718 3693 """parse and apply a template
3719 3694
3720 3695 If -r/--rev is given, the template is processed as a log template and
3721 3696 applied to the given changesets. Otherwise, it is processed as a generic
3722 3697 template.
3723 3698
3724 3699 Use --verbose to print the parsed tree.
3725 3700 """
3726 3701 revs = None
3727 3702 if opts['rev']:
3728 3703 if repo is None:
3729 3704 raise error.RepoError(_('there is no Mercurial repository here '
3730 3705 '(.hg not found)'))
3731 3706 revs = scmutil.revrange(repo, opts['rev'])
3732 3707
3733 3708 props = {}
3734 3709 for d in opts['define']:
3735 3710 try:
3736 3711 k, v = (e.strip() for e in d.split('=', 1))
3737 3712 if not k:
3738 3713 raise ValueError
3739 3714 props[k] = v
3740 3715 except ValueError:
3741 3716 raise error.Abort(_('malformed keyword definition: %s') % d)
3742 3717
3743 3718 if ui.verbose:
3744 3719 aliases = ui.configitems('templatealias')
3745 3720 tree = templater.parse(tmpl)
3746 3721 ui.note(templater.prettyformat(tree), '\n')
3747 3722 newtree = templater.expandaliases(tree, aliases)
3748 3723 if newtree != tree:
3749 3724 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
3750 3725
3751 3726 mapfile = None
3752 3727 if revs is None:
3753 3728 k = 'debugtemplate'
3754 3729 t = formatter.maketemplater(ui, k, tmpl)
3755 3730 ui.write(templater.stringify(t(k, **props)))
3756 3731 else:
3757 3732 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3758 3733 mapfile, buffered=False)
3759 3734 for r in revs:
3760 3735 displayer.show(repo[r], **props)
3761 3736 displayer.close()
3762 3737
3763 3738 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3764 3739 def debugwalk(ui, repo, *pats, **opts):
3765 3740 """show how files match on given patterns"""
3766 3741 m = scmutil.match(repo[None], pats, opts)
3767 3742 items = list(repo.walk(m))
3768 3743 if not items:
3769 3744 return
3770 3745 f = lambda fn: fn
3771 3746 if ui.configbool('ui', 'slash') and os.sep != '/':
3772 3747 f = lambda fn: util.normpath(fn)
3773 3748 fmt = 'f %%-%ds %%-%ds %%s' % (
3774 3749 max([len(abs) for abs in items]),
3775 3750 max([len(m.rel(abs)) for abs in items]))
3776 3751 for abs in items:
3777 3752 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3778 3753 ui.write("%s\n" % line.rstrip())
3779 3754
3780 3755 @command('debugwireargs',
3781 3756 [('', 'three', '', 'three'),
3782 3757 ('', 'four', '', 'four'),
3783 3758 ('', 'five', '', 'five'),
3784 3759 ] + remoteopts,
3785 3760 _('REPO [OPTIONS]... [ONE [TWO]]'),
3786 3761 norepo=True)
3787 3762 def debugwireargs(ui, repopath, *vals, **opts):
3788 3763 repo = hg.peer(ui, opts, repopath)
3789 3764 for opt in remoteopts:
3790 3765 del opts[opt[1]]
3791 3766 args = {}
3792 3767 for k, v in opts.iteritems():
3793 3768 if v:
3794 3769 args[k] = v
3795 3770 # run twice to check that we don't mess up the stream for the next command
3796 3771 res1 = repo.debugwireargs(*vals, **args)
3797 3772 res2 = repo.debugwireargs(*vals, **args)
3798 3773 ui.write("%s\n" % res1)
3799 3774 if res1 != res2:
3800 3775 ui.warn("%s\n" % res2)
3801 3776
3802 3777 @command('^diff',
3803 3778 [('r', 'rev', [], _('revision'), _('REV')),
3804 3779 ('c', 'change', '', _('change made by revision'), _('REV'))
3805 3780 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3806 3781 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3807 3782 inferrepo=True)
3808 3783 def diff(ui, repo, *pats, **opts):
3809 3784 """diff repository (or selected files)
3810 3785
3811 3786 Show differences between revisions for the specified files.
3812 3787
3813 3788 Differences between files are shown using the unified diff format.
3814 3789
3815 3790 .. note::
3816 3791
3817 3792 :hg:`diff` may generate unexpected results for merges, as it will
3818 3793 default to comparing against the working directory's first
3819 3794 parent changeset if no revisions are specified.
3820 3795
3821 3796 When two revision arguments are given, then changes are shown
3822 3797 between those revisions. If only one revision is specified then
3823 3798 that revision is compared to the working directory, and, when no
3824 3799 revisions are specified, the working directory files are compared
3825 3800 to its first parent.
3826 3801
3827 3802 Alternatively you can specify -c/--change with a revision to see
3828 3803 the changes in that changeset relative to its first parent.
3829 3804
3830 3805 Without the -a/--text option, diff will avoid generating diffs of
3831 3806 files it detects as binary. With -a, diff will generate a diff
3832 3807 anyway, probably with undesirable results.
3833 3808
3834 3809 Use the -g/--git option to generate diffs in the git extended diff
3835 3810 format. For more information, read :hg:`help diffs`.
3836 3811
3837 3812 .. container:: verbose
3838 3813
3839 3814 Examples:
3840 3815
3841 3816 - compare a file in the current working directory to its parent::
3842 3817
3843 3818 hg diff foo.c
3844 3819
3845 3820 - compare two historical versions of a directory, with rename info::
3846 3821
3847 3822 hg diff --git -r 1.0:1.2 lib/
3848 3823
3849 3824 - get change stats relative to the last change on some date::
3850 3825
3851 3826 hg diff --stat -r "date('may 2')"
3852 3827
3853 3828 - diff all newly-added files that contain a keyword::
3854 3829
3855 3830 hg diff "set:added() and grep(GNU)"
3856 3831
3857 3832 - compare a revision and its parents::
3858 3833
3859 3834 hg diff -c 9353 # compare against first parent
3860 3835 hg diff -r 9353^:9353 # same using revset syntax
3861 3836 hg diff -r 9353^2:9353 # compare against the second parent
3862 3837
3863 3838 Returns 0 on success.
3864 3839 """
3865 3840
3866 3841 revs = opts.get('rev')
3867 3842 change = opts.get('change')
3868 3843 stat = opts.get('stat')
3869 3844 reverse = opts.get('reverse')
3870 3845
3871 3846 if revs and change:
3872 3847 msg = _('cannot specify --rev and --change at the same time')
3873 3848 raise error.Abort(msg)
3874 3849 elif change:
3875 3850 node2 = scmutil.revsingle(repo, change, None).node()
3876 3851 node1 = repo[node2].p1().node()
3877 3852 else:
3878 3853 node1, node2 = scmutil.revpair(repo, revs)
3879 3854
3880 3855 if reverse:
3881 3856 node1, node2 = node2, node1
3882 3857
3883 3858 diffopts = patch.diffallopts(ui, opts)
3884 3859 m = scmutil.match(repo[node2], pats, opts)
3885 3860 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3886 3861 listsubrepos=opts.get('subrepos'),
3887 3862 root=opts.get('root'))
3888 3863
3889 3864 @command('^export',
3890 3865 [('o', 'output', '',
3891 3866 _('print output to file with formatted name'), _('FORMAT')),
3892 3867 ('', 'switch-parent', None, _('diff against the second parent')),
3893 3868 ('r', 'rev', [], _('revisions to export'), _('REV')),
3894 3869 ] + diffopts,
3895 3870 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3896 3871 def export(ui, repo, *changesets, **opts):
3897 3872 """dump the header and diffs for one or more changesets
3898 3873
3899 3874 Print the changeset header and diffs for one or more revisions.
3900 3875 If no revision is given, the parent of the working directory is used.
3901 3876
3902 3877 The information shown in the changeset header is: author, date,
3903 3878 branch name (if non-default), changeset hash, parent(s) and commit
3904 3879 comment.
3905 3880
3906 3881 .. note::
3907 3882
3908 3883 :hg:`export` may generate unexpected diff output for merge
3909 3884 changesets, as it will compare the merge changeset against its
3910 3885 first parent only.
3911 3886
3912 3887 Output may be to a file, in which case the name of the file is
3913 3888 given using a format string. The formatting rules are as follows:
3914 3889
3915 3890 :``%%``: literal "%" character
3916 3891 :``%H``: changeset hash (40 hexadecimal digits)
3917 3892 :``%N``: number of patches being generated
3918 3893 :``%R``: changeset revision number
3919 3894 :``%b``: basename of the exporting repository
3920 3895 :``%h``: short-form changeset hash (12 hexadecimal digits)
3921 3896 :``%m``: first line of the commit message (only alphanumeric characters)
3922 3897 :``%n``: zero-padded sequence number, starting at 1
3923 3898 :``%r``: zero-padded changeset revision number
3924 3899
3925 3900 Without the -a/--text option, export will avoid generating diffs
3926 3901 of files it detects as binary. With -a, export will generate a
3927 3902 diff anyway, probably with undesirable results.
3928 3903
3929 3904 Use the -g/--git option to generate diffs in the git extended diff
3930 3905 format. See :hg:`help diffs` for more information.
3931 3906
3932 3907 With the --switch-parent option, the diff will be against the
3933 3908 second parent. It can be useful to review a merge.
3934 3909
3935 3910 .. container:: verbose
3936 3911
3937 3912 Examples:
3938 3913
3939 3914 - use export and import to transplant a bugfix to the current
3940 3915 branch::
3941 3916
3942 3917 hg export -r 9353 | hg import -
3943 3918
3944 3919 - export all the changesets between two revisions to a file with
3945 3920 rename information::
3946 3921
3947 3922 hg export --git -r 123:150 > changes.txt
3948 3923
3949 3924 - split outgoing changes into a series of patches with
3950 3925 descriptive names::
3951 3926
3952 3927 hg export -r "outgoing()" -o "%n-%m.patch"
3953 3928
3954 3929 Returns 0 on success.
3955 3930 """
3956 3931 changesets += tuple(opts.get('rev', []))
3957 3932 if not changesets:
3958 3933 changesets = ['.']
3959 3934 revs = scmutil.revrange(repo, changesets)
3960 3935 if not revs:
3961 3936 raise error.Abort(_("export requires at least one changeset"))
3962 3937 if len(revs) > 1:
3963 3938 ui.note(_('exporting patches:\n'))
3964 3939 else:
3965 3940 ui.note(_('exporting patch:\n'))
3966 3941 cmdutil.export(repo, revs, template=opts.get('output'),
3967 3942 switch_parent=opts.get('switch_parent'),
3968 3943 opts=patch.diffallopts(ui, opts))
3969 3944
3970 3945 @command('files',
3971 3946 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3972 3947 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3973 3948 ] + walkopts + formatteropts + subrepoopts,
3974 3949 _('[OPTION]... [FILE]...'))
3975 3950 def files(ui, repo, *pats, **opts):
3976 3951 """list tracked files
3977 3952
3978 3953 Print files under Mercurial control in the working directory or
3979 3954 specified revision for given files (excluding removed files).
3980 3955 Files can be specified as filenames or filesets.
3981 3956
3982 3957 If no files are given to match, this command prints the names
3983 3958 of all files under Mercurial control.
3984 3959
3985 3960 .. container:: verbose
3986 3961
3987 3962 Examples:
3988 3963
3989 3964 - list all files under the current directory::
3990 3965
3991 3966 hg files .
3992 3967
3993 3968 - shows sizes and flags for current revision::
3994 3969
3995 3970 hg files -vr .
3996 3971
3997 3972 - list all files named README::
3998 3973
3999 3974 hg files -I "**/README"
4000 3975
4001 3976 - list all binary files::
4002 3977
4003 3978 hg files "set:binary()"
4004 3979
4005 3980 - find files containing a regular expression::
4006 3981
4007 3982 hg files "set:grep('bob')"
4008 3983
4009 3984 - search tracked file contents with xargs and grep::
4010 3985
4011 3986 hg files -0 | xargs -0 grep foo
4012 3987
4013 3988 See :hg:`help patterns` and :hg:`help filesets` for more information
4014 3989 on specifying file patterns.
4015 3990
4016 3991 Returns 0 if a match is found, 1 otherwise.
4017 3992
4018 3993 """
4019 3994 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4020 3995
4021 3996 end = '\n'
4022 3997 if opts.get('print0'):
4023 3998 end = '\0'
4024 3999 fmt = '%s' + end
4025 4000
4026 4001 m = scmutil.match(ctx, pats, opts)
4027 4002 with ui.formatter('files', opts) as fm:
4028 4003 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
4029 4004
4030 4005 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
4031 4006 def forget(ui, repo, *pats, **opts):
4032 4007 """forget the specified files on the next commit
4033 4008
4034 4009 Mark the specified files so they will no longer be tracked
4035 4010 after the next commit.
4036 4011
4037 4012 This only removes files from the current branch, not from the
4038 4013 entire project history, and it does not delete them from the
4039 4014 working directory.
4040 4015
4041 4016 To delete the file from the working directory, see :hg:`remove`.
4042 4017
4043 4018 To undo a forget before the next commit, see :hg:`add`.
4044 4019
4045 4020 .. container:: verbose
4046 4021
4047 4022 Examples:
4048 4023
4049 4024 - forget newly-added binary files::
4050 4025
4051 4026 hg forget "set:added() and binary()"
4052 4027
4053 4028 - forget files that would be excluded by .hgignore::
4054 4029
4055 4030 hg forget "set:hgignore()"
4056 4031
4057 4032 Returns 0 on success.
4058 4033 """
4059 4034
4060 4035 if not pats:
4061 4036 raise error.Abort(_('no files specified'))
4062 4037
4063 4038 m = scmutil.match(repo[None], pats, opts)
4064 4039 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
4065 4040 return rejected and 1 or 0
4066 4041
4067 4042 @command(
4068 4043 'graft',
4069 4044 [('r', 'rev', [], _('revisions to graft'), _('REV')),
4070 4045 ('c', 'continue', False, _('resume interrupted graft')),
4071 4046 ('e', 'edit', False, _('invoke editor on commit messages')),
4072 4047 ('', 'log', None, _('append graft info to log message')),
4073 4048 ('f', 'force', False, _('force graft')),
4074 4049 ('D', 'currentdate', False,
4075 4050 _('record the current date as commit date')),
4076 4051 ('U', 'currentuser', False,
4077 4052 _('record the current user as committer'), _('DATE'))]
4078 4053 + commitopts2 + mergetoolopts + dryrunopts,
4079 4054 _('[OPTION]... [-r REV]... REV...'))
4080 4055 def graft(ui, repo, *revs, **opts):
4081 4056 '''copy changes from other branches onto the current branch
4082 4057
4083 4058 This command uses Mercurial's merge logic to copy individual
4084 4059 changes from other branches without merging branches in the
4085 4060 history graph. This is sometimes known as 'backporting' or
4086 4061 'cherry-picking'. By default, graft will copy user, date, and
4087 4062 description from the source changesets.
4088 4063
4089 4064 Changesets that are ancestors of the current revision, that have
4090 4065 already been grafted, or that are merges will be skipped.
4091 4066
4092 4067 If --log is specified, log messages will have a comment appended
4093 4068 of the form::
4094 4069
4095 4070 (grafted from CHANGESETHASH)
4096 4071
4097 4072 If --force is specified, revisions will be grafted even if they
4098 4073 are already ancestors of or have been grafted to the destination.
4099 4074 This is useful when the revisions have since been backed out.
4100 4075
4101 4076 If a graft merge results in conflicts, the graft process is
4102 4077 interrupted so that the current merge can be manually resolved.
4103 4078 Once all conflicts are addressed, the graft process can be
4104 4079 continued with the -c/--continue option.
4105 4080
4106 4081 .. note::
4107 4082
4108 4083 The -c/--continue option does not reapply earlier options, except
4109 4084 for --force.
4110 4085
4111 4086 .. container:: verbose
4112 4087
4113 4088 Examples:
4114 4089
4115 4090 - copy a single change to the stable branch and edit its description::
4116 4091
4117 4092 hg update stable
4118 4093 hg graft --edit 9393
4119 4094
4120 4095 - graft a range of changesets with one exception, updating dates::
4121 4096
4122 4097 hg graft -D "2085::2093 and not 2091"
4123 4098
4124 4099 - continue a graft after resolving conflicts::
4125 4100
4126 4101 hg graft -c
4127 4102
4128 4103 - show the source of a grafted changeset::
4129 4104
4130 4105 hg log --debug -r .
4131 4106
4132 4107 - show revisions sorted by date::
4133 4108
4134 4109 hg log -r "sort(all(), date)"
4135 4110
4136 4111 See :hg:`help revisions` and :hg:`help revsets` for more about
4137 4112 specifying revisions.
4138 4113
4139 4114 Returns 0 on successful completion.
4140 4115 '''
4141 4116 with repo.wlock():
4142 4117 return _dograft(ui, repo, *revs, **opts)
4143 4118
4144 4119 def _dograft(ui, repo, *revs, **opts):
4145 4120 if revs and opts.get('rev'):
4146 4121 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4147 4122 'revision ordering!\n'))
4148 4123
4149 4124 revs = list(revs)
4150 4125 revs.extend(opts.get('rev'))
4151 4126
4152 4127 if not opts.get('user') and opts.get('currentuser'):
4153 4128 opts['user'] = ui.username()
4154 4129 if not opts.get('date') and opts.get('currentdate'):
4155 4130 opts['date'] = "%d %d" % util.makedate()
4156 4131
4157 4132 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4158 4133
4159 4134 cont = False
4160 4135 if opts.get('continue'):
4161 4136 cont = True
4162 4137 if revs:
4163 4138 raise error.Abort(_("can't specify --continue and revisions"))
4164 4139 # read in unfinished revisions
4165 4140 try:
4166 4141 nodes = repo.vfs.read('graftstate').splitlines()
4167 4142 revs = [repo[node].rev() for node in nodes]
4168 4143 except IOError as inst:
4169 4144 if inst.errno != errno.ENOENT:
4170 4145 raise
4171 4146 cmdutil.wrongtooltocontinue(repo, _('graft'))
4172 4147 else:
4173 4148 cmdutil.checkunfinished(repo)
4174 4149 cmdutil.bailifchanged(repo)
4175 4150 if not revs:
4176 4151 raise error.Abort(_('no revisions specified'))
4177 4152 revs = scmutil.revrange(repo, revs)
4178 4153
4179 4154 skipped = set()
4180 4155 # check for merges
4181 4156 for rev in repo.revs('%ld and merge()', revs):
4182 4157 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4183 4158 skipped.add(rev)
4184 4159 revs = [r for r in revs if r not in skipped]
4185 4160 if not revs:
4186 4161 return -1
4187 4162
4188 4163 # Don't check in the --continue case, in effect retaining --force across
4189 4164 # --continues. That's because without --force, any revisions we decided to
4190 4165 # skip would have been filtered out here, so they wouldn't have made their
4191 4166 # way to the graftstate. With --force, any revisions we would have otherwise
4192 4167 # skipped would not have been filtered out, and if they hadn't been applied
4193 4168 # already, they'd have been in the graftstate.
4194 4169 if not (cont or opts.get('force')):
4195 4170 # check for ancestors of dest branch
4196 4171 crev = repo['.'].rev()
4197 4172 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4198 4173 # XXX make this lazy in the future
4199 4174 # don't mutate while iterating, create a copy
4200 4175 for rev in list(revs):
4201 4176 if rev in ancestors:
4202 4177 ui.warn(_('skipping ancestor revision %d:%s\n') %
4203 4178 (rev, repo[rev]))
4204 4179 # XXX remove on list is slow
4205 4180 revs.remove(rev)
4206 4181 if not revs:
4207 4182 return -1
4208 4183
4209 4184 # analyze revs for earlier grafts
4210 4185 ids = {}
4211 4186 for ctx in repo.set("%ld", revs):
4212 4187 ids[ctx.hex()] = ctx.rev()
4213 4188 n = ctx.extra().get('source')
4214 4189 if n:
4215 4190 ids[n] = ctx.rev()
4216 4191
4217 4192 # check ancestors for earlier grafts
4218 4193 ui.debug('scanning for duplicate grafts\n')
4219 4194
4220 4195 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4221 4196 ctx = repo[rev]
4222 4197 n = ctx.extra().get('source')
4223 4198 if n in ids:
4224 4199 try:
4225 4200 r = repo[n].rev()
4226 4201 except error.RepoLookupError:
4227 4202 r = None
4228 4203 if r in revs:
4229 4204 ui.warn(_('skipping revision %d:%s '
4230 4205 '(already grafted to %d:%s)\n')
4231 4206 % (r, repo[r], rev, ctx))
4232 4207 revs.remove(r)
4233 4208 elif ids[n] in revs:
4234 4209 if r is None:
4235 4210 ui.warn(_('skipping already grafted revision %d:%s '
4236 4211 '(%d:%s also has unknown origin %s)\n')
4237 4212 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4238 4213 else:
4239 4214 ui.warn(_('skipping already grafted revision %d:%s '
4240 4215 '(%d:%s also has origin %d:%s)\n')
4241 4216 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4242 4217 revs.remove(ids[n])
4243 4218 elif ctx.hex() in ids:
4244 4219 r = ids[ctx.hex()]
4245 4220 ui.warn(_('skipping already grafted revision %d:%s '
4246 4221 '(was grafted from %d:%s)\n') %
4247 4222 (r, repo[r], rev, ctx))
4248 4223 revs.remove(r)
4249 4224 if not revs:
4250 4225 return -1
4251 4226
4252 4227 for pos, ctx in enumerate(repo.set("%ld", revs)):
4253 4228 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4254 4229 ctx.description().split('\n', 1)[0])
4255 4230 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4256 4231 if names:
4257 4232 desc += ' (%s)' % ' '.join(names)
4258 4233 ui.status(_('grafting %s\n') % desc)
4259 4234 if opts.get('dry_run'):
4260 4235 continue
4261 4236
4262 4237 source = ctx.extra().get('source')
4263 4238 extra = {}
4264 4239 if source:
4265 4240 extra['source'] = source
4266 4241 extra['intermediate-source'] = ctx.hex()
4267 4242 else:
4268 4243 extra['source'] = ctx.hex()
4269 4244 user = ctx.user()
4270 4245 if opts.get('user'):
4271 4246 user = opts['user']
4272 4247 date = ctx.date()
4273 4248 if opts.get('date'):
4274 4249 date = opts['date']
4275 4250 message = ctx.description()
4276 4251 if opts.get('log'):
4277 4252 message += '\n(grafted from %s)' % ctx.hex()
4278 4253
4279 4254 # we don't merge the first commit when continuing
4280 4255 if not cont:
4281 4256 # perform the graft merge with p1(rev) as 'ancestor'
4282 4257 try:
4283 4258 # ui.forcemerge is an internal variable, do not document
4284 4259 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4285 4260 'graft')
4286 4261 stats = mergemod.graft(repo, ctx, ctx.p1(),
4287 4262 ['local', 'graft'])
4288 4263 finally:
4289 4264 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4290 4265 # report any conflicts
4291 4266 if stats and stats[3] > 0:
4292 4267 # write out state for --continue
4293 4268 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4294 4269 repo.vfs.write('graftstate', ''.join(nodelines))
4295 4270 extra = ''
4296 4271 if opts.get('user'):
4297 4272 extra += ' --user %s' % util.shellquote(opts['user'])
4298 4273 if opts.get('date'):
4299 4274 extra += ' --date %s' % util.shellquote(opts['date'])
4300 4275 if opts.get('log'):
4301 4276 extra += ' --log'
4302 4277 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
4303 4278 raise error.Abort(
4304 4279 _("unresolved conflicts, can't continue"),
4305 4280 hint=hint)
4306 4281 else:
4307 4282 cont = False
4308 4283
4309 4284 # commit
4310 4285 node = repo.commit(text=message, user=user,
4311 4286 date=date, extra=extra, editor=editor)
4312 4287 if node is None:
4313 4288 ui.warn(
4314 4289 _('note: graft of %d:%s created no changes to commit\n') %
4315 4290 (ctx.rev(), ctx))
4316 4291
4317 4292 # remove state when we complete successfully
4318 4293 if not opts.get('dry_run'):
4319 4294 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4320 4295
4321 4296 return 0
4322 4297
4323 4298 @command('grep',
4324 4299 [('0', 'print0', None, _('end fields with NUL')),
4325 4300 ('', 'all', None, _('print all revisions that match')),
4326 4301 ('a', 'text', None, _('treat all files as text')),
4327 4302 ('f', 'follow', None,
4328 4303 _('follow changeset history,'
4329 4304 ' or file history across copies and renames')),
4330 4305 ('i', 'ignore-case', None, _('ignore case when matching')),
4331 4306 ('l', 'files-with-matches', None,
4332 4307 _('print only filenames and revisions that match')),
4333 4308 ('n', 'line-number', None, _('print matching line numbers')),
4334 4309 ('r', 'rev', [],
4335 4310 _('only search files changed within revision range'), _('REV')),
4336 4311 ('u', 'user', None, _('list the author (long with -v)')),
4337 4312 ('d', 'date', None, _('list the date (short with -q)')),
4338 4313 ] + formatteropts + walkopts,
4339 4314 _('[OPTION]... PATTERN [FILE]...'),
4340 4315 inferrepo=True)
4341 4316 def grep(ui, repo, pattern, *pats, **opts):
4342 4317 """search revision history for a pattern in specified files
4343 4318
4344 4319 Search revision history for a regular expression in the specified
4345 4320 files or the entire project.
4346 4321
4347 4322 By default, grep prints the most recent revision number for each
4348 4323 file in which it finds a match. To get it to print every revision
4349 4324 that contains a change in match status ("-" for a match that becomes
4350 4325 a non-match, or "+" for a non-match that becomes a match), use the
4351 4326 --all flag.
4352 4327
4353 4328 PATTERN can be any Python (roughly Perl-compatible) regular
4354 4329 expression.
4355 4330
4356 4331 If no FILEs are specified (and -f/--follow isn't set), all files in
4357 4332 the repository are searched, including those that don't exist in the
4358 4333 current branch or have been deleted in a prior changeset.
4359 4334
4360 4335 Returns 0 if a match is found, 1 otherwise.
4361 4336 """
4362 4337 reflags = re.M
4363 4338 if opts.get('ignore_case'):
4364 4339 reflags |= re.I
4365 4340 try:
4366 4341 regexp = util.re.compile(pattern, reflags)
4367 4342 except re.error as inst:
4368 4343 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4369 4344 return 1
4370 4345 sep, eol = ':', '\n'
4371 4346 if opts.get('print0'):
4372 4347 sep = eol = '\0'
4373 4348
4374 4349 getfile = util.lrucachefunc(repo.file)
4375 4350
4376 4351 def matchlines(body):
4377 4352 begin = 0
4378 4353 linenum = 0
4379 4354 while begin < len(body):
4380 4355 match = regexp.search(body, begin)
4381 4356 if not match:
4382 4357 break
4383 4358 mstart, mend = match.span()
4384 4359 linenum += body.count('\n', begin, mstart) + 1
4385 4360 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4386 4361 begin = body.find('\n', mend) + 1 or len(body) + 1
4387 4362 lend = begin - 1
4388 4363 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4389 4364
4390 4365 class linestate(object):
4391 4366 def __init__(self, line, linenum, colstart, colend):
4392 4367 self.line = line
4393 4368 self.linenum = linenum
4394 4369 self.colstart = colstart
4395 4370 self.colend = colend
4396 4371
4397 4372 def __hash__(self):
4398 4373 return hash((self.linenum, self.line))
4399 4374
4400 4375 def __eq__(self, other):
4401 4376 return self.line == other.line
4402 4377
4403 4378 def findpos(self):
4404 4379 """Iterate all (start, end) indices of matches"""
4405 4380 yield self.colstart, self.colend
4406 4381 p = self.colend
4407 4382 while p < len(self.line):
4408 4383 m = regexp.search(self.line, p)
4409 4384 if not m:
4410 4385 break
4411 4386 yield m.span()
4412 4387 p = m.end()
4413 4388
4414 4389 matches = {}
4415 4390 copies = {}
4416 4391 def grepbody(fn, rev, body):
4417 4392 matches[rev].setdefault(fn, [])
4418 4393 m = matches[rev][fn]
4419 4394 for lnum, cstart, cend, line in matchlines(body):
4420 4395 s = linestate(line, lnum, cstart, cend)
4421 4396 m.append(s)
4422 4397
4423 4398 def difflinestates(a, b):
4424 4399 sm = difflib.SequenceMatcher(None, a, b)
4425 4400 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4426 4401 if tag == 'insert':
4427 4402 for i in xrange(blo, bhi):
4428 4403 yield ('+', b[i])
4429 4404 elif tag == 'delete':
4430 4405 for i in xrange(alo, ahi):
4431 4406 yield ('-', a[i])
4432 4407 elif tag == 'replace':
4433 4408 for i in xrange(alo, ahi):
4434 4409 yield ('-', a[i])
4435 4410 for i in xrange(blo, bhi):
4436 4411 yield ('+', b[i])
4437 4412
4438 4413 def display(fm, fn, ctx, pstates, states):
4439 4414 rev = ctx.rev()
4440 4415 if fm.isplain():
4441 4416 formatuser = ui.shortuser
4442 4417 else:
4443 4418 formatuser = str
4444 4419 if ui.quiet:
4445 4420 datefmt = '%Y-%m-%d'
4446 4421 else:
4447 4422 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
4448 4423 found = False
4449 4424 @util.cachefunc
4450 4425 def binary():
4451 4426 flog = getfile(fn)
4452 4427 return util.binary(flog.read(ctx.filenode(fn)))
4453 4428
4454 4429 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
4455 4430 if opts.get('all'):
4456 4431 iter = difflinestates(pstates, states)
4457 4432 else:
4458 4433 iter = [('', l) for l in states]
4459 4434 for change, l in iter:
4460 4435 fm.startitem()
4461 4436 fm.data(node=fm.hexfunc(ctx.node()))
4462 4437 cols = [
4463 4438 ('filename', fn, True),
4464 4439 ('rev', rev, True),
4465 4440 ('linenumber', l.linenum, opts.get('line_number')),
4466 4441 ]
4467 4442 if opts.get('all'):
4468 4443 cols.append(('change', change, True))
4469 4444 cols.extend([
4470 4445 ('user', formatuser(ctx.user()), opts.get('user')),
4471 4446 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
4472 4447 ])
4473 4448 lastcol = next(name for name, data, cond in reversed(cols) if cond)
4474 4449 for name, data, cond in cols:
4475 4450 field = fieldnamemap.get(name, name)
4476 4451 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
4477 4452 if cond and name != lastcol:
4478 4453 fm.plain(sep, label='grep.sep')
4479 4454 if not opts.get('files_with_matches'):
4480 4455 fm.plain(sep, label='grep.sep')
4481 4456 if not opts.get('text') and binary():
4482 4457 fm.plain(_(" Binary file matches"))
4483 4458 else:
4484 4459 displaymatches(fm.nested('texts'), l)
4485 4460 fm.plain(eol)
4486 4461 found = True
4487 4462 if opts.get('files_with_matches'):
4488 4463 break
4489 4464 return found
4490 4465
4491 4466 def displaymatches(fm, l):
4492 4467 p = 0
4493 4468 for s, e in l.findpos():
4494 4469 if p < s:
4495 4470 fm.startitem()
4496 4471 fm.write('text', '%s', l.line[p:s])
4497 4472 fm.data(matched=False)
4498 4473 fm.startitem()
4499 4474 fm.write('text', '%s', l.line[s:e], label='grep.match')
4500 4475 fm.data(matched=True)
4501 4476 p = e
4502 4477 if p < len(l.line):
4503 4478 fm.startitem()
4504 4479 fm.write('text', '%s', l.line[p:])
4505 4480 fm.data(matched=False)
4506 4481 fm.end()
4507 4482
4508 4483 skip = {}
4509 4484 revfiles = {}
4510 4485 matchfn = scmutil.match(repo[None], pats, opts)
4511 4486 found = False
4512 4487 follow = opts.get('follow')
4513 4488
4514 4489 def prep(ctx, fns):
4515 4490 rev = ctx.rev()
4516 4491 pctx = ctx.p1()
4517 4492 parent = pctx.rev()
4518 4493 matches.setdefault(rev, {})
4519 4494 matches.setdefault(parent, {})
4520 4495 files = revfiles.setdefault(rev, [])
4521 4496 for fn in fns:
4522 4497 flog = getfile(fn)
4523 4498 try:
4524 4499 fnode = ctx.filenode(fn)
4525 4500 except error.LookupError:
4526 4501 continue
4527 4502
4528 4503 copied = flog.renamed(fnode)
4529 4504 copy = follow and copied and copied[0]
4530 4505 if copy:
4531 4506 copies.setdefault(rev, {})[fn] = copy
4532 4507 if fn in skip:
4533 4508 if copy:
4534 4509 skip[copy] = True
4535 4510 continue
4536 4511 files.append(fn)
4537 4512
4538 4513 if fn not in matches[rev]:
4539 4514 grepbody(fn, rev, flog.read(fnode))
4540 4515
4541 4516 pfn = copy or fn
4542 4517 if pfn not in matches[parent]:
4543 4518 try:
4544 4519 fnode = pctx.filenode(pfn)
4545 4520 grepbody(pfn, parent, flog.read(fnode))
4546 4521 except error.LookupError:
4547 4522 pass
4548 4523
4549 4524 fm = ui.formatter('grep', opts)
4550 4525 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4551 4526 rev = ctx.rev()
4552 4527 parent = ctx.p1().rev()
4553 4528 for fn in sorted(revfiles.get(rev, [])):
4554 4529 states = matches[rev][fn]
4555 4530 copy = copies.get(rev, {}).get(fn)
4556 4531 if fn in skip:
4557 4532 if copy:
4558 4533 skip[copy] = True
4559 4534 continue
4560 4535 pstates = matches.get(parent, {}).get(copy or fn, [])
4561 4536 if pstates or states:
4562 4537 r = display(fm, fn, ctx, pstates, states)
4563 4538 found = found or r
4564 4539 if r and not opts.get('all'):
4565 4540 skip[fn] = True
4566 4541 if copy:
4567 4542 skip[copy] = True
4568 4543 del matches[rev]
4569 4544 del revfiles[rev]
4570 4545 fm.end()
4571 4546
4572 4547 return not found
4573 4548
4574 4549 @command('heads',
4575 4550 [('r', 'rev', '',
4576 4551 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4577 4552 ('t', 'topo', False, _('show topological heads only')),
4578 4553 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4579 4554 ('c', 'closed', False, _('show normal and closed branch heads')),
4580 4555 ] + templateopts,
4581 4556 _('[-ct] [-r STARTREV] [REV]...'))
4582 4557 def heads(ui, repo, *branchrevs, **opts):
4583 4558 """show branch heads
4584 4559
4585 4560 With no arguments, show all open branch heads in the repository.
4586 4561 Branch heads are changesets that have no descendants on the
4587 4562 same branch. They are where development generally takes place and
4588 4563 are the usual targets for update and merge operations.
4589 4564
4590 4565 If one or more REVs are given, only open branch heads on the
4591 4566 branches associated with the specified changesets are shown. This
4592 4567 means that you can use :hg:`heads .` to see the heads on the
4593 4568 currently checked-out branch.
4594 4569
4595 4570 If -c/--closed is specified, also show branch heads marked closed
4596 4571 (see :hg:`commit --close-branch`).
4597 4572
4598 4573 If STARTREV is specified, only those heads that are descendants of
4599 4574 STARTREV will be displayed.
4600 4575
4601 4576 If -t/--topo is specified, named branch mechanics will be ignored and only
4602 4577 topological heads (changesets with no children) will be shown.
4603 4578
4604 4579 Returns 0 if matching heads are found, 1 if not.
4605 4580 """
4606 4581
4607 4582 start = None
4608 4583 if 'rev' in opts:
4609 4584 start = scmutil.revsingle(repo, opts['rev'], None).node()
4610 4585
4611 4586 if opts.get('topo'):
4612 4587 heads = [repo[h] for h in repo.heads(start)]
4613 4588 else:
4614 4589 heads = []
4615 4590 for branch in repo.branchmap():
4616 4591 heads += repo.branchheads(branch, start, opts.get('closed'))
4617 4592 heads = [repo[h] for h in heads]
4618 4593
4619 4594 if branchrevs:
4620 4595 branches = set(repo[br].branch() for br in branchrevs)
4621 4596 heads = [h for h in heads if h.branch() in branches]
4622 4597
4623 4598 if opts.get('active') and branchrevs:
4624 4599 dagheads = repo.heads(start)
4625 4600 heads = [h for h in heads if h.node() in dagheads]
4626 4601
4627 4602 if branchrevs:
4628 4603 haveheads = set(h.branch() for h in heads)
4629 4604 if branches - haveheads:
4630 4605 headless = ', '.join(b for b in branches - haveheads)
4631 4606 msg = _('no open branch heads found on branches %s')
4632 4607 if opts.get('rev'):
4633 4608 msg += _(' (started at %s)') % opts['rev']
4634 4609 ui.warn((msg + '\n') % headless)
4635 4610
4636 4611 if not heads:
4637 4612 return 1
4638 4613
4639 4614 heads = sorted(heads, key=lambda x: -x.rev())
4640 4615 displayer = cmdutil.show_changeset(ui, repo, opts)
4641 4616 for ctx in heads:
4642 4617 displayer.show(ctx)
4643 4618 displayer.close()
4644 4619
4645 4620 @command('help',
4646 4621 [('e', 'extension', None, _('show only help for extensions')),
4647 4622 ('c', 'command', None, _('show only help for commands')),
4648 4623 ('k', 'keyword', None, _('show topics matching keyword')),
4649 4624 ('s', 'system', [], _('show help for specific platform(s)')),
4650 4625 ],
4651 4626 _('[-ecks] [TOPIC]'),
4652 4627 norepo=True)
4653 4628 def help_(ui, name=None, **opts):
4654 4629 """show help for a given topic or a help overview
4655 4630
4656 4631 With no arguments, print a list of commands with short help messages.
4657 4632
4658 4633 Given a topic, extension, or command name, print help for that
4659 4634 topic.
4660 4635
4661 4636 Returns 0 if successful.
4662 4637 """
4663 4638
4664 4639 textwidth = ui.configint('ui', 'textwidth', 78)
4665 4640 termwidth = ui.termwidth() - 2
4666 4641 if textwidth <= 0 or termwidth < textwidth:
4667 4642 textwidth = termwidth
4668 4643
4669 4644 keep = opts.get('system') or []
4670 4645 if len(keep) == 0:
4671 4646 if sys.platform.startswith('win'):
4672 4647 keep.append('windows')
4673 4648 elif sys.platform == 'OpenVMS':
4674 4649 keep.append('vms')
4675 4650 elif sys.platform == 'plan9':
4676 4651 keep.append('plan9')
4677 4652 else:
4678 4653 keep.append('unix')
4679 4654 keep.append(sys.platform.lower())
4680 4655 if ui.verbose:
4681 4656 keep.append('verbose')
4682 4657
4683 4658 section = None
4684 4659 subtopic = None
4685 4660 if name and '.' in name:
4686 4661 name, remaining = name.split('.', 1)
4687 4662 remaining = encoding.lower(remaining)
4688 4663 if '.' in remaining:
4689 4664 subtopic, section = remaining.split('.', 1)
4690 4665 else:
4691 4666 if name in help.subtopics:
4692 4667 subtopic = remaining
4693 4668 else:
4694 4669 section = remaining
4695 4670
4696 4671 text = help.help_(ui, name, subtopic=subtopic, **opts)
4697 4672
4698 4673 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4699 4674 section=section)
4700 4675
4701 4676 # We could have been given a weird ".foo" section without a name
4702 4677 # to look for, or we could have simply failed to found "foo.bar"
4703 4678 # because bar isn't a section of foo
4704 4679 if section and not (formatted and name):
4705 4680 raise error.Abort(_("help section not found"))
4706 4681
4707 4682 if 'verbose' in pruned:
4708 4683 keep.append('omitted')
4709 4684 else:
4710 4685 keep.append('notomitted')
4711 4686 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4712 4687 section=section)
4713 4688 ui.write(formatted)
4714 4689
4715 4690
4716 4691 @command('identify|id',
4717 4692 [('r', 'rev', '',
4718 4693 _('identify the specified revision'), _('REV')),
4719 4694 ('n', 'num', None, _('show local revision number')),
4720 4695 ('i', 'id', None, _('show global revision id')),
4721 4696 ('b', 'branch', None, _('show branch')),
4722 4697 ('t', 'tags', None, _('show tags')),
4723 4698 ('B', 'bookmarks', None, _('show bookmarks')),
4724 4699 ] + remoteopts,
4725 4700 _('[-nibtB] [-r REV] [SOURCE]'),
4726 4701 optionalrepo=True)
4727 4702 def identify(ui, repo, source=None, rev=None,
4728 4703 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4729 4704 """identify the working directory or specified revision
4730 4705
4731 4706 Print a summary identifying the repository state at REV using one or
4732 4707 two parent hash identifiers, followed by a "+" if the working
4733 4708 directory has uncommitted changes, the branch name (if not default),
4734 4709 a list of tags, and a list of bookmarks.
4735 4710
4736 4711 When REV is not given, print a summary of the current state of the
4737 4712 repository.
4738 4713
4739 4714 Specifying a path to a repository root or Mercurial bundle will
4740 4715 cause lookup to operate on that repository/bundle.
4741 4716
4742 4717 .. container:: verbose
4743 4718
4744 4719 Examples:
4745 4720
4746 4721 - generate a build identifier for the working directory::
4747 4722
4748 4723 hg id --id > build-id.dat
4749 4724
4750 4725 - find the revision corresponding to a tag::
4751 4726
4752 4727 hg id -n -r 1.3
4753 4728
4754 4729 - check the most recent revision of a remote repository::
4755 4730
4756 4731 hg id -r tip http://selenic.com/hg/
4757 4732
4758 4733 See :hg:`log` for generating more information about specific revisions,
4759 4734 including full hash identifiers.
4760 4735
4761 4736 Returns 0 if successful.
4762 4737 """
4763 4738
4764 4739 if not repo and not source:
4765 4740 raise error.Abort(_("there is no Mercurial repository here "
4766 4741 "(.hg not found)"))
4767 4742
4768 4743 if ui.debugflag:
4769 4744 hexfunc = hex
4770 4745 else:
4771 4746 hexfunc = short
4772 4747 default = not (num or id or branch or tags or bookmarks)
4773 4748 output = []
4774 4749 revs = []
4775 4750
4776 4751 if source:
4777 4752 source, branches = hg.parseurl(ui.expandpath(source))
4778 4753 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4779 4754 repo = peer.local()
4780 4755 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4781 4756
4782 4757 if not repo:
4783 4758 if num or branch or tags:
4784 4759 raise error.Abort(
4785 4760 _("can't query remote revision number, branch, or tags"))
4786 4761 if not rev and revs:
4787 4762 rev = revs[0]
4788 4763 if not rev:
4789 4764 rev = "tip"
4790 4765
4791 4766 remoterev = peer.lookup(rev)
4792 4767 if default or id:
4793 4768 output = [hexfunc(remoterev)]
4794 4769
4795 4770 def getbms():
4796 4771 bms = []
4797 4772
4798 4773 if 'bookmarks' in peer.listkeys('namespaces'):
4799 4774 hexremoterev = hex(remoterev)
4800 4775 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4801 4776 if bmr == hexremoterev]
4802 4777
4803 4778 return sorted(bms)
4804 4779
4805 4780 if bookmarks:
4806 4781 output.extend(getbms())
4807 4782 elif default and not ui.quiet:
4808 4783 # multiple bookmarks for a single parent separated by '/'
4809 4784 bm = '/'.join(getbms())
4810 4785 if bm:
4811 4786 output.append(bm)
4812 4787 else:
4813 4788 ctx = scmutil.revsingle(repo, rev, None)
4814 4789
4815 4790 if ctx.rev() is None:
4816 4791 ctx = repo[None]
4817 4792 parents = ctx.parents()
4818 4793 taglist = []
4819 4794 for p in parents:
4820 4795 taglist.extend(p.tags())
4821 4796
4822 4797 changed = ""
4823 4798 if default or id or num:
4824 4799 if (any(repo.status())
4825 4800 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4826 4801 changed = '+'
4827 4802 if default or id:
4828 4803 output = ["%s%s" %
4829 4804 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4830 4805 if num:
4831 4806 output.append("%s%s" %
4832 4807 ('+'.join([str(p.rev()) for p in parents]), changed))
4833 4808 else:
4834 4809 if default or id:
4835 4810 output = [hexfunc(ctx.node())]
4836 4811 if num:
4837 4812 output.append(str(ctx.rev()))
4838 4813 taglist = ctx.tags()
4839 4814
4840 4815 if default and not ui.quiet:
4841 4816 b = ctx.branch()
4842 4817 if b != 'default':
4843 4818 output.append("(%s)" % b)
4844 4819
4845 4820 # multiple tags for a single parent separated by '/'
4846 4821 t = '/'.join(taglist)
4847 4822 if t:
4848 4823 output.append(t)
4849 4824
4850 4825 # multiple bookmarks for a single parent separated by '/'
4851 4826 bm = '/'.join(ctx.bookmarks())
4852 4827 if bm:
4853 4828 output.append(bm)
4854 4829 else:
4855 4830 if branch:
4856 4831 output.append(ctx.branch())
4857 4832
4858 4833 if tags:
4859 4834 output.extend(taglist)
4860 4835
4861 4836 if bookmarks:
4862 4837 output.extend(ctx.bookmarks())
4863 4838
4864 4839 ui.write("%s\n" % ' '.join(output))
4865 4840
4866 4841 @command('import|patch',
4867 4842 [('p', 'strip', 1,
4868 4843 _('directory strip option for patch. This has the same '
4869 4844 'meaning as the corresponding patch option'), _('NUM')),
4870 4845 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4871 4846 ('e', 'edit', False, _('invoke editor on commit messages')),
4872 4847 ('f', 'force', None,
4873 4848 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4874 4849 ('', 'no-commit', None,
4875 4850 _("don't commit, just update the working directory")),
4876 4851 ('', 'bypass', None,
4877 4852 _("apply patch without touching the working directory")),
4878 4853 ('', 'partial', None,
4879 4854 _('commit even if some hunks fail')),
4880 4855 ('', 'exact', None,
4881 4856 _('abort if patch would apply lossily')),
4882 4857 ('', 'prefix', '',
4883 4858 _('apply patch to subdirectory'), _('DIR')),
4884 4859 ('', 'import-branch', None,
4885 4860 _('use any branch information in patch (implied by --exact)'))] +
4886 4861 commitopts + commitopts2 + similarityopts,
4887 4862 _('[OPTION]... PATCH...'))
4888 4863 def import_(ui, repo, patch1=None, *patches, **opts):
4889 4864 """import an ordered set of patches
4890 4865
4891 4866 Import a list of patches and commit them individually (unless
4892 4867 --no-commit is specified).
4893 4868
4894 4869 To read a patch from standard input, use "-" as the patch name. If
4895 4870 a URL is specified, the patch will be downloaded from there.
4896 4871
4897 4872 Import first applies changes to the working directory (unless
4898 4873 --bypass is specified), import will abort if there are outstanding
4899 4874 changes.
4900 4875
4901 4876 Use --bypass to apply and commit patches directly to the
4902 4877 repository, without affecting the working directory. Without
4903 4878 --exact, patches will be applied on top of the working directory
4904 4879 parent revision.
4905 4880
4906 4881 You can import a patch straight from a mail message. Even patches
4907 4882 as attachments work (to use the body part, it must have type
4908 4883 text/plain or text/x-patch). From and Subject headers of email
4909 4884 message are used as default committer and commit message. All
4910 4885 text/plain body parts before first diff are added to the commit
4911 4886 message.
4912 4887
4913 4888 If the imported patch was generated by :hg:`export`, user and
4914 4889 description from patch override values from message headers and
4915 4890 body. Values given on command line with -m/--message and -u/--user
4916 4891 override these.
4917 4892
4918 4893 If --exact is specified, import will set the working directory to
4919 4894 the parent of each patch before applying it, and will abort if the
4920 4895 resulting changeset has a different ID than the one recorded in
4921 4896 the patch. This will guard against various ways that portable
4922 4897 patch formats and mail systems might fail to transfer Mercurial
4923 4898 data or metadata. See :hg:`bundle` for lossless transmission.
4924 4899
4925 4900 Use --partial to ensure a changeset will be created from the patch
4926 4901 even if some hunks fail to apply. Hunks that fail to apply will be
4927 4902 written to a <target-file>.rej file. Conflicts can then be resolved
4928 4903 by hand before :hg:`commit --amend` is run to update the created
4929 4904 changeset. This flag exists to let people import patches that
4930 4905 partially apply without losing the associated metadata (author,
4931 4906 date, description, ...).
4932 4907
4933 4908 .. note::
4934 4909
4935 4910 When no hunks apply cleanly, :hg:`import --partial` will create
4936 4911 an empty changeset, importing only the patch metadata.
4937 4912
4938 4913 With -s/--similarity, hg will attempt to discover renames and
4939 4914 copies in the patch in the same way as :hg:`addremove`.
4940 4915
4941 4916 It is possible to use external patch programs to perform the patch
4942 4917 by setting the ``ui.patch`` configuration option. For the default
4943 4918 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4944 4919 See :hg:`help config` for more information about configuration
4945 4920 files and how to use these options.
4946 4921
4947 4922 See :hg:`help dates` for a list of formats valid for -d/--date.
4948 4923
4949 4924 .. container:: verbose
4950 4925
4951 4926 Examples:
4952 4927
4953 4928 - import a traditional patch from a website and detect renames::
4954 4929
4955 4930 hg import -s 80 http://example.com/bugfix.patch
4956 4931
4957 4932 - import a changeset from an hgweb server::
4958 4933
4959 4934 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4960 4935
4961 4936 - import all the patches in an Unix-style mbox::
4962 4937
4963 4938 hg import incoming-patches.mbox
4964 4939
4965 4940 - attempt to exactly restore an exported changeset (not always
4966 4941 possible)::
4967 4942
4968 4943 hg import --exact proposed-fix.patch
4969 4944
4970 4945 - use an external tool to apply a patch which is too fuzzy for
4971 4946 the default internal tool.
4972 4947
4973 4948 hg import --config ui.patch="patch --merge" fuzzy.patch
4974 4949
4975 4950 - change the default fuzzing from 2 to a less strict 7
4976 4951
4977 4952 hg import --config ui.fuzz=7 fuzz.patch
4978 4953
4979 4954 Returns 0 on success, 1 on partial success (see --partial).
4980 4955 """
4981 4956
4982 4957 if not patch1:
4983 4958 raise error.Abort(_('need at least one patch to import'))
4984 4959
4985 4960 patches = (patch1,) + patches
4986 4961
4987 4962 date = opts.get('date')
4988 4963 if date:
4989 4964 opts['date'] = util.parsedate(date)
4990 4965
4991 4966 exact = opts.get('exact')
4992 4967 update = not opts.get('bypass')
4993 4968 if not update and opts.get('no_commit'):
4994 4969 raise error.Abort(_('cannot use --no-commit with --bypass'))
4995 4970 try:
4996 4971 sim = float(opts.get('similarity') or 0)
4997 4972 except ValueError:
4998 4973 raise error.Abort(_('similarity must be a number'))
4999 4974 if sim < 0 or sim > 100:
5000 4975 raise error.Abort(_('similarity must be between 0 and 100'))
5001 4976 if sim and not update:
5002 4977 raise error.Abort(_('cannot use --similarity with --bypass'))
5003 4978 if exact:
5004 4979 if opts.get('edit'):
5005 4980 raise error.Abort(_('cannot use --exact with --edit'))
5006 4981 if opts.get('prefix'):
5007 4982 raise error.Abort(_('cannot use --exact with --prefix'))
5008 4983
5009 4984 base = opts["base"]
5010 4985 wlock = dsguard = lock = tr = None
5011 4986 msgs = []
5012 4987 ret = 0
5013 4988
5014 4989
5015 4990 try:
5016 4991 wlock = repo.wlock()
5017 4992
5018 4993 if update:
5019 4994 cmdutil.checkunfinished(repo)
5020 4995 if (exact or not opts.get('force')):
5021 4996 cmdutil.bailifchanged(repo)
5022 4997
5023 4998 if not opts.get('no_commit'):
5024 4999 lock = repo.lock()
5025 5000 tr = repo.transaction('import')
5026 5001 else:
5027 5002 dsguard = cmdutil.dirstateguard(repo, 'import')
5028 5003 parents = repo[None].parents()
5029 5004 for patchurl in patches:
5030 5005 if patchurl == '-':
5031 5006 ui.status(_('applying patch from stdin\n'))
5032 5007 patchfile = ui.fin
5033 5008 patchurl = 'stdin' # for error message
5034 5009 else:
5035 5010 patchurl = os.path.join(base, patchurl)
5036 5011 ui.status(_('applying %s\n') % patchurl)
5037 5012 patchfile = hg.openpath(ui, patchurl)
5038 5013
5039 5014 haspatch = False
5040 5015 for hunk in patch.split(patchfile):
5041 5016 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
5042 5017 parents, opts,
5043 5018 msgs, hg.clean)
5044 5019 if msg:
5045 5020 haspatch = True
5046 5021 ui.note(msg + '\n')
5047 5022 if update or exact:
5048 5023 parents = repo[None].parents()
5049 5024 else:
5050 5025 parents = [repo[node]]
5051 5026 if rej:
5052 5027 ui.write_err(_("patch applied partially\n"))
5053 5028 ui.write_err(_("(fix the .rej files and run "
5054 5029 "`hg commit --amend`)\n"))
5055 5030 ret = 1
5056 5031 break
5057 5032
5058 5033 if not haspatch:
5059 5034 raise error.Abort(_('%s: no diffs found') % patchurl)
5060 5035
5061 5036 if tr:
5062 5037 tr.close()
5063 5038 if msgs:
5064 5039 repo.savecommitmessage('\n* * *\n'.join(msgs))
5065 5040 if dsguard:
5066 5041 dsguard.close()
5067 5042 return ret
5068 5043 finally:
5069 5044 if tr:
5070 5045 tr.release()
5071 5046 release(lock, dsguard, wlock)
5072 5047
5073 5048 @command('incoming|in',
5074 5049 [('f', 'force', None,
5075 5050 _('run even if remote repository is unrelated')),
5076 5051 ('n', 'newest-first', None, _('show newest record first')),
5077 5052 ('', 'bundle', '',
5078 5053 _('file to store the bundles into'), _('FILE')),
5079 5054 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5080 5055 ('B', 'bookmarks', False, _("compare bookmarks")),
5081 5056 ('b', 'branch', [],
5082 5057 _('a specific branch you would like to pull'), _('BRANCH')),
5083 5058 ] + logopts + remoteopts + subrepoopts,
5084 5059 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
5085 5060 def incoming(ui, repo, source="default", **opts):
5086 5061 """show new changesets found in source
5087 5062
5088 5063 Show new changesets found in the specified path/URL or the default
5089 5064 pull location. These are the changesets that would have been pulled
5090 5065 if a pull at the time you issued this command.
5091 5066
5092 5067 See pull for valid source format details.
5093 5068
5094 5069 .. container:: verbose
5095 5070
5096 5071 With -B/--bookmarks, the result of bookmark comparison between
5097 5072 local and remote repositories is displayed. With -v/--verbose,
5098 5073 status is also displayed for each bookmark like below::
5099 5074
5100 5075 BM1 01234567890a added
5101 5076 BM2 1234567890ab advanced
5102 5077 BM3 234567890abc diverged
5103 5078 BM4 34567890abcd changed
5104 5079
5105 5080 The action taken locally when pulling depends on the
5106 5081 status of each bookmark:
5107 5082
5108 5083 :``added``: pull will create it
5109 5084 :``advanced``: pull will update it
5110 5085 :``diverged``: pull will create a divergent bookmark
5111 5086 :``changed``: result depends on remote changesets
5112 5087
5113 5088 From the point of view of pulling behavior, bookmark
5114 5089 existing only in the remote repository are treated as ``added``,
5115 5090 even if it is in fact locally deleted.
5116 5091
5117 5092 .. container:: verbose
5118 5093
5119 5094 For remote repository, using --bundle avoids downloading the
5120 5095 changesets twice if the incoming is followed by a pull.
5121 5096
5122 5097 Examples:
5123 5098
5124 5099 - show incoming changes with patches and full description::
5125 5100
5126 5101 hg incoming -vp
5127 5102
5128 5103 - show incoming changes excluding merges, store a bundle::
5129 5104
5130 5105 hg in -vpM --bundle incoming.hg
5131 5106 hg pull incoming.hg
5132 5107
5133 5108 - briefly list changes inside a bundle::
5134 5109
5135 5110 hg in changes.hg -T "{desc|firstline}\\n"
5136 5111
5137 5112 Returns 0 if there are incoming changes, 1 otherwise.
5138 5113 """
5139 5114 if opts.get('graph'):
5140 5115 cmdutil.checkunsupportedgraphflags([], opts)
5141 5116 def display(other, chlist, displayer):
5142 5117 revdag = cmdutil.graphrevs(other, chlist, opts)
5143 5118 cmdutil.displaygraph(ui, repo, revdag, displayer,
5144 5119 graphmod.asciiedges)
5145 5120
5146 5121 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5147 5122 return 0
5148 5123
5149 5124 if opts.get('bundle') and opts.get('subrepos'):
5150 5125 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5151 5126
5152 5127 if opts.get('bookmarks'):
5153 5128 source, branches = hg.parseurl(ui.expandpath(source),
5154 5129 opts.get('branch'))
5155 5130 other = hg.peer(repo, opts, source)
5156 5131 if 'bookmarks' not in other.listkeys('namespaces'):
5157 5132 ui.warn(_("remote doesn't support bookmarks\n"))
5158 5133 return 0
5159 5134 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5160 5135 return bookmarks.incoming(ui, repo, other)
5161 5136
5162 5137 repo._subtoppath = ui.expandpath(source)
5163 5138 try:
5164 5139 return hg.incoming(ui, repo, source, opts)
5165 5140 finally:
5166 5141 del repo._subtoppath
5167 5142
5168 5143
5169 5144 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5170 5145 norepo=True)
5171 5146 def init(ui, dest=".", **opts):
5172 5147 """create a new repository in the given directory
5173 5148
5174 5149 Initialize a new repository in the given directory. If the given
5175 5150 directory does not exist, it will be created.
5176 5151
5177 5152 If no directory is given, the current directory is used.
5178 5153
5179 5154 It is possible to specify an ``ssh://`` URL as the destination.
5180 5155 See :hg:`help urls` for more information.
5181 5156
5182 5157 Returns 0 on success.
5183 5158 """
5184 5159 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5185 5160
5186 5161 @command('locate',
5187 5162 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5188 5163 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5189 5164 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5190 5165 ] + walkopts,
5191 5166 _('[OPTION]... [PATTERN]...'))
5192 5167 def locate(ui, repo, *pats, **opts):
5193 5168 """locate files matching specific patterns (DEPRECATED)
5194 5169
5195 5170 Print files under Mercurial control in the working directory whose
5196 5171 names match the given patterns.
5197 5172
5198 5173 By default, this command searches all directories in the working
5199 5174 directory. To search just the current directory and its
5200 5175 subdirectories, use "--include .".
5201 5176
5202 5177 If no patterns are given to match, this command prints the names
5203 5178 of all files under Mercurial control in the working directory.
5204 5179
5205 5180 If you want to feed the output of this command into the "xargs"
5206 5181 command, use the -0 option to both this command and "xargs". This
5207 5182 will avoid the problem of "xargs" treating single filenames that
5208 5183 contain whitespace as multiple filenames.
5209 5184
5210 5185 See :hg:`help files` for a more versatile command.
5211 5186
5212 5187 Returns 0 if a match is found, 1 otherwise.
5213 5188 """
5214 5189 if opts.get('print0'):
5215 5190 end = '\0'
5216 5191 else:
5217 5192 end = '\n'
5218 5193 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5219 5194
5220 5195 ret = 1
5221 5196 ctx = repo[rev]
5222 5197 m = scmutil.match(ctx, pats, opts, default='relglob',
5223 5198 badfn=lambda x, y: False)
5224 5199
5225 5200 for abs in ctx.matches(m):
5226 5201 if opts.get('fullpath'):
5227 5202 ui.write(repo.wjoin(abs), end)
5228 5203 else:
5229 5204 ui.write(((pats and m.rel(abs)) or abs), end)
5230 5205 ret = 0
5231 5206
5232 5207 return ret
5233 5208
5234 5209 @command('^log|history',
5235 5210 [('f', 'follow', None,
5236 5211 _('follow changeset history, or file history across copies and renames')),
5237 5212 ('', 'follow-first', None,
5238 5213 _('only follow the first parent of merge changesets (DEPRECATED)')),
5239 5214 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5240 5215 ('C', 'copies', None, _('show copied files')),
5241 5216 ('k', 'keyword', [],
5242 5217 _('do case-insensitive search for a given text'), _('TEXT')),
5243 5218 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5244 5219 ('', 'removed', None, _('include revisions where files were removed')),
5245 5220 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5246 5221 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5247 5222 ('', 'only-branch', [],
5248 5223 _('show only changesets within the given named branch (DEPRECATED)'),
5249 5224 _('BRANCH')),
5250 5225 ('b', 'branch', [],
5251 5226 _('show changesets within the given named branch'), _('BRANCH')),
5252 5227 ('P', 'prune', [],
5253 5228 _('do not display revision or any of its ancestors'), _('REV')),
5254 5229 ] + logopts + walkopts,
5255 5230 _('[OPTION]... [FILE]'),
5256 5231 inferrepo=True)
5257 5232 def log(ui, repo, *pats, **opts):
5258 5233 """show revision history of entire repository or files
5259 5234
5260 5235 Print the revision history of the specified files or the entire
5261 5236 project.
5262 5237
5263 5238 If no revision range is specified, the default is ``tip:0`` unless
5264 5239 --follow is set, in which case the working directory parent is
5265 5240 used as the starting revision.
5266 5241
5267 5242 File history is shown without following rename or copy history of
5268 5243 files. Use -f/--follow with a filename to follow history across
5269 5244 renames and copies. --follow without a filename will only show
5270 5245 ancestors or descendants of the starting revision.
5271 5246
5272 5247 By default this command prints revision number and changeset id,
5273 5248 tags, non-trivial parents, user, date and time, and a summary for
5274 5249 each commit. When the -v/--verbose switch is used, the list of
5275 5250 changed files and full commit message are shown.
5276 5251
5277 5252 With --graph the revisions are shown as an ASCII art DAG with the most
5278 5253 recent changeset at the top.
5279 5254 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5280 5255 and '+' represents a fork where the changeset from the lines below is a
5281 5256 parent of the 'o' merge on the same line.
5282 5257
5283 5258 .. note::
5284 5259
5285 5260 :hg:`log --patch` may generate unexpected diff output for merge
5286 5261 changesets, as it will only compare the merge changeset against
5287 5262 its first parent. Also, only files different from BOTH parents
5288 5263 will appear in files:.
5289 5264
5290 5265 .. note::
5291 5266
5292 5267 For performance reasons, :hg:`log FILE` may omit duplicate changes
5293 5268 made on branches and will not show removals or mode changes. To
5294 5269 see all such changes, use the --removed switch.
5295 5270
5296 5271 .. container:: verbose
5297 5272
5298 5273 Some examples:
5299 5274
5300 5275 - changesets with full descriptions and file lists::
5301 5276
5302 5277 hg log -v
5303 5278
5304 5279 - changesets ancestral to the working directory::
5305 5280
5306 5281 hg log -f
5307 5282
5308 5283 - last 10 commits on the current branch::
5309 5284
5310 5285 hg log -l 10 -b .
5311 5286
5312 5287 - changesets showing all modifications of a file, including removals::
5313 5288
5314 5289 hg log --removed file.c
5315 5290
5316 5291 - all changesets that touch a directory, with diffs, excluding merges::
5317 5292
5318 5293 hg log -Mp lib/
5319 5294
5320 5295 - all revision numbers that match a keyword::
5321 5296
5322 5297 hg log -k bug --template "{rev}\\n"
5323 5298
5324 5299 - the full hash identifier of the working directory parent::
5325 5300
5326 5301 hg log -r . --template "{node}\\n"
5327 5302
5328 5303 - list available log templates::
5329 5304
5330 5305 hg log -T list
5331 5306
5332 5307 - check if a given changeset is included in a tagged release::
5333 5308
5334 5309 hg log -r "a21ccf and ancestor(1.9)"
5335 5310
5336 5311 - find all changesets by some user in a date range::
5337 5312
5338 5313 hg log -k alice -d "may 2008 to jul 2008"
5339 5314
5340 5315 - summary of all changesets after the last tag::
5341 5316
5342 5317 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5343 5318
5344 5319 See :hg:`help dates` for a list of formats valid for -d/--date.
5345 5320
5346 5321 See :hg:`help revisions` and :hg:`help revsets` for more about
5347 5322 specifying and ordering revisions.
5348 5323
5349 5324 See :hg:`help templates` for more about pre-packaged styles and
5350 5325 specifying custom templates.
5351 5326
5352 5327 Returns 0 on success.
5353 5328
5354 5329 """
5355 5330 if opts.get('follow') and opts.get('rev'):
5356 5331 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5357 5332 del opts['follow']
5358 5333
5359 5334 if opts.get('graph'):
5360 5335 return cmdutil.graphlog(ui, repo, *pats, **opts)
5361 5336
5362 5337 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5363 5338 limit = cmdutil.loglimit(opts)
5364 5339 count = 0
5365 5340
5366 5341 getrenamed = None
5367 5342 if opts.get('copies'):
5368 5343 endrev = None
5369 5344 if opts.get('rev'):
5370 5345 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5371 5346 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5372 5347
5373 5348 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5374 5349 for rev in revs:
5375 5350 if count == limit:
5376 5351 break
5377 5352 ctx = repo[rev]
5378 5353 copies = None
5379 5354 if getrenamed is not None and rev:
5380 5355 copies = []
5381 5356 for fn in ctx.files():
5382 5357 rename = getrenamed(fn, rev)
5383 5358 if rename:
5384 5359 copies.append((fn, rename[0]))
5385 5360 if filematcher:
5386 5361 revmatchfn = filematcher(ctx.rev())
5387 5362 else:
5388 5363 revmatchfn = None
5389 5364 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5390 5365 if displayer.flush(ctx):
5391 5366 count += 1
5392 5367
5393 5368 displayer.close()
5394 5369
5395 5370 @command('manifest',
5396 5371 [('r', 'rev', '', _('revision to display'), _('REV')),
5397 5372 ('', 'all', False, _("list files from all revisions"))]
5398 5373 + formatteropts,
5399 5374 _('[-r REV]'))
5400 5375 def manifest(ui, repo, node=None, rev=None, **opts):
5401 5376 """output the current or given revision of the project manifest
5402 5377
5403 5378 Print a list of version controlled files for the given revision.
5404 5379 If no revision is given, the first parent of the working directory
5405 5380 is used, or the null revision if no revision is checked out.
5406 5381
5407 5382 With -v, print file permissions, symlink and executable bits.
5408 5383 With --debug, print file revision hashes.
5409 5384
5410 5385 If option --all is specified, the list of all files from all revisions
5411 5386 is printed. This includes deleted and renamed files.
5412 5387
5413 5388 Returns 0 on success.
5414 5389 """
5415 5390
5416 5391 fm = ui.formatter('manifest', opts)
5417 5392
5418 5393 if opts.get('all'):
5419 5394 if rev or node:
5420 5395 raise error.Abort(_("can't specify a revision with --all"))
5421 5396
5422 5397 res = []
5423 5398 prefix = "data/"
5424 5399 suffix = ".i"
5425 5400 plen = len(prefix)
5426 5401 slen = len(suffix)
5427 5402 with repo.lock():
5428 5403 for fn, b, size in repo.store.datafiles():
5429 5404 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5430 5405 res.append(fn[plen:-slen])
5431 5406 for f in res:
5432 5407 fm.startitem()
5433 5408 fm.write("path", '%s\n', f)
5434 5409 fm.end()
5435 5410 return
5436 5411
5437 5412 if rev and node:
5438 5413 raise error.Abort(_("please specify just one revision"))
5439 5414
5440 5415 if not node:
5441 5416 node = rev
5442 5417
5443 5418 char = {'l': '@', 'x': '*', '': ''}
5444 5419 mode = {'l': '644', 'x': '755', '': '644'}
5445 5420 ctx = scmutil.revsingle(repo, node)
5446 5421 mf = ctx.manifest()
5447 5422 for f in ctx:
5448 5423 fm.startitem()
5449 5424 fl = ctx[f].flags()
5450 5425 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5451 5426 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5452 5427 fm.write('path', '%s\n', f)
5453 5428 fm.end()
5454 5429
5455 5430 @command('^merge',
5456 5431 [('f', 'force', None,
5457 5432 _('force a merge including outstanding changes (DEPRECATED)')),
5458 5433 ('r', 'rev', '', _('revision to merge'), _('REV')),
5459 5434 ('P', 'preview', None,
5460 5435 _('review revisions to merge (no merge is performed)'))
5461 5436 ] + mergetoolopts,
5462 5437 _('[-P] [[-r] REV]'))
5463 5438 def merge(ui, repo, node=None, **opts):
5464 5439 """merge another revision into working directory
5465 5440
5466 5441 The current working directory is updated with all changes made in
5467 5442 the requested revision since the last common predecessor revision.
5468 5443
5469 5444 Files that changed between either parent are marked as changed for
5470 5445 the next commit and a commit must be performed before any further
5471 5446 updates to the repository are allowed. The next commit will have
5472 5447 two parents.
5473 5448
5474 5449 ``--tool`` can be used to specify the merge tool used for file
5475 5450 merges. It overrides the HGMERGE environment variable and your
5476 5451 configuration files. See :hg:`help merge-tools` for options.
5477 5452
5478 5453 If no revision is specified, the working directory's parent is a
5479 5454 head revision, and the current branch contains exactly one other
5480 5455 head, the other head is merged with by default. Otherwise, an
5481 5456 explicit revision with which to merge with must be provided.
5482 5457
5483 5458 See :hg:`help resolve` for information on handling file conflicts.
5484 5459
5485 5460 To undo an uncommitted merge, use :hg:`update --clean .` which
5486 5461 will check out a clean copy of the original merge parent, losing
5487 5462 all changes.
5488 5463
5489 5464 Returns 0 on success, 1 if there are unresolved files.
5490 5465 """
5491 5466
5492 5467 if opts.get('rev') and node:
5493 5468 raise error.Abort(_("please specify just one revision"))
5494 5469 if not node:
5495 5470 node = opts.get('rev')
5496 5471
5497 5472 if node:
5498 5473 node = scmutil.revsingle(repo, node).node()
5499 5474
5500 5475 if not node:
5501 5476 node = repo[destutil.destmerge(repo)].node()
5502 5477
5503 5478 if opts.get('preview'):
5504 5479 # find nodes that are ancestors of p2 but not of p1
5505 5480 p1 = repo.lookup('.')
5506 5481 p2 = repo.lookup(node)
5507 5482 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5508 5483
5509 5484 displayer = cmdutil.show_changeset(ui, repo, opts)
5510 5485 for node in nodes:
5511 5486 displayer.show(repo[node])
5512 5487 displayer.close()
5513 5488 return 0
5514 5489
5515 5490 try:
5516 5491 # ui.forcemerge is an internal variable, do not document
5517 5492 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5518 5493 force = opts.get('force')
5519 5494 labels = ['working copy', 'merge rev']
5520 5495 return hg.merge(repo, node, force=force, mergeforce=force,
5521 5496 labels=labels)
5522 5497 finally:
5523 5498 ui.setconfig('ui', 'forcemerge', '', 'merge')
5524 5499
5525 5500 @command('outgoing|out',
5526 5501 [('f', 'force', None, _('run even when the destination is unrelated')),
5527 5502 ('r', 'rev', [],
5528 5503 _('a changeset intended to be included in the destination'), _('REV')),
5529 5504 ('n', 'newest-first', None, _('show newest record first')),
5530 5505 ('B', 'bookmarks', False, _('compare bookmarks')),
5531 5506 ('b', 'branch', [], _('a specific branch you would like to push'),
5532 5507 _('BRANCH')),
5533 5508 ] + logopts + remoteopts + subrepoopts,
5534 5509 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5535 5510 def outgoing(ui, repo, dest=None, **opts):
5536 5511 """show changesets not found in the destination
5537 5512
5538 5513 Show changesets not found in the specified destination repository
5539 5514 or the default push location. These are the changesets that would
5540 5515 be pushed if a push was requested.
5541 5516
5542 5517 See pull for details of valid destination formats.
5543 5518
5544 5519 .. container:: verbose
5545 5520
5546 5521 With -B/--bookmarks, the result of bookmark comparison between
5547 5522 local and remote repositories is displayed. With -v/--verbose,
5548 5523 status is also displayed for each bookmark like below::
5549 5524
5550 5525 BM1 01234567890a added
5551 5526 BM2 deleted
5552 5527 BM3 234567890abc advanced
5553 5528 BM4 34567890abcd diverged
5554 5529 BM5 4567890abcde changed
5555 5530
5556 5531 The action taken when pushing depends on the
5557 5532 status of each bookmark:
5558 5533
5559 5534 :``added``: push with ``-B`` will create it
5560 5535 :``deleted``: push with ``-B`` will delete it
5561 5536 :``advanced``: push will update it
5562 5537 :``diverged``: push with ``-B`` will update it
5563 5538 :``changed``: push with ``-B`` will update it
5564 5539
5565 5540 From the point of view of pushing behavior, bookmarks
5566 5541 existing only in the remote repository are treated as
5567 5542 ``deleted``, even if it is in fact added remotely.
5568 5543
5569 5544 Returns 0 if there are outgoing changes, 1 otherwise.
5570 5545 """
5571 5546 if opts.get('graph'):
5572 5547 cmdutil.checkunsupportedgraphflags([], opts)
5573 5548 o, other = hg._outgoing(ui, repo, dest, opts)
5574 5549 if not o:
5575 5550 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5576 5551 return
5577 5552
5578 5553 revdag = cmdutil.graphrevs(repo, o, opts)
5579 5554 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5580 5555 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5581 5556 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5582 5557 return 0
5583 5558
5584 5559 if opts.get('bookmarks'):
5585 5560 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5586 5561 dest, branches = hg.parseurl(dest, opts.get('branch'))
5587 5562 other = hg.peer(repo, opts, dest)
5588 5563 if 'bookmarks' not in other.listkeys('namespaces'):
5589 5564 ui.warn(_("remote doesn't support bookmarks\n"))
5590 5565 return 0
5591 5566 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5592 5567 return bookmarks.outgoing(ui, repo, other)
5593 5568
5594 5569 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5595 5570 try:
5596 5571 return hg.outgoing(ui, repo, dest, opts)
5597 5572 finally:
5598 5573 del repo._subtoppath
5599 5574
5600 5575 @command('parents',
5601 5576 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5602 5577 ] + templateopts,
5603 5578 _('[-r REV] [FILE]'),
5604 5579 inferrepo=True)
5605 5580 def parents(ui, repo, file_=None, **opts):
5606 5581 """show the parents of the working directory or revision (DEPRECATED)
5607 5582
5608 5583 Print the working directory's parent revisions. If a revision is
5609 5584 given via -r/--rev, the parent of that revision will be printed.
5610 5585 If a file argument is given, the revision in which the file was
5611 5586 last changed (before the working directory revision or the
5612 5587 argument to --rev if given) is printed.
5613 5588
5614 5589 This command is equivalent to::
5615 5590
5616 5591 hg log -r "p1()+p2()" or
5617 5592 hg log -r "p1(REV)+p2(REV)" or
5618 5593 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5619 5594 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5620 5595
5621 5596 See :hg:`summary` and :hg:`help revsets` for related information.
5622 5597
5623 5598 Returns 0 on success.
5624 5599 """
5625 5600
5626 5601 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5627 5602
5628 5603 if file_:
5629 5604 m = scmutil.match(ctx, (file_,), opts)
5630 5605 if m.anypats() or len(m.files()) != 1:
5631 5606 raise error.Abort(_('can only specify an explicit filename'))
5632 5607 file_ = m.files()[0]
5633 5608 filenodes = []
5634 5609 for cp in ctx.parents():
5635 5610 if not cp:
5636 5611 continue
5637 5612 try:
5638 5613 filenodes.append(cp.filenode(file_))
5639 5614 except error.LookupError:
5640 5615 pass
5641 5616 if not filenodes:
5642 5617 raise error.Abort(_("'%s' not found in manifest!") % file_)
5643 5618 p = []
5644 5619 for fn in filenodes:
5645 5620 fctx = repo.filectx(file_, fileid=fn)
5646 5621 p.append(fctx.node())
5647 5622 else:
5648 5623 p = [cp.node() for cp in ctx.parents()]
5649 5624
5650 5625 displayer = cmdutil.show_changeset(ui, repo, opts)
5651 5626 for n in p:
5652 5627 if n != nullid:
5653 5628 displayer.show(repo[n])
5654 5629 displayer.close()
5655 5630
5656 5631 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5657 5632 def paths(ui, repo, search=None, **opts):
5658 5633 """show aliases for remote repositories
5659 5634
5660 5635 Show definition of symbolic path name NAME. If no name is given,
5661 5636 show definition of all available names.
5662 5637
5663 5638 Option -q/--quiet suppresses all output when searching for NAME
5664 5639 and shows only the path names when listing all definitions.
5665 5640
5666 5641 Path names are defined in the [paths] section of your
5667 5642 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5668 5643 repository, ``.hg/hgrc`` is used, too.
5669 5644
5670 5645 The path names ``default`` and ``default-push`` have a special
5671 5646 meaning. When performing a push or pull operation, they are used
5672 5647 as fallbacks if no location is specified on the command-line.
5673 5648 When ``default-push`` is set, it will be used for push and
5674 5649 ``default`` will be used for pull; otherwise ``default`` is used
5675 5650 as the fallback for both. When cloning a repository, the clone
5676 5651 source is written as ``default`` in ``.hg/hgrc``.
5677 5652
5678 5653 .. note::
5679 5654
5680 5655 ``default`` and ``default-push`` apply to all inbound (e.g.
5681 5656 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5682 5657 and :hg:`bundle`) operations.
5683 5658
5684 5659 See :hg:`help urls` for more information.
5685 5660
5686 5661 Returns 0 on success.
5687 5662 """
5688 5663 if search:
5689 5664 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5690 5665 if name == search]
5691 5666 else:
5692 5667 pathitems = sorted(ui.paths.iteritems())
5693 5668
5694 5669 fm = ui.formatter('paths', opts)
5695 5670 if fm.isplain():
5696 5671 hidepassword = util.hidepassword
5697 5672 else:
5698 5673 hidepassword = str
5699 5674 if ui.quiet:
5700 5675 namefmt = '%s\n'
5701 5676 else:
5702 5677 namefmt = '%s = '
5703 5678 showsubopts = not search and not ui.quiet
5704 5679
5705 5680 for name, path in pathitems:
5706 5681 fm.startitem()
5707 5682 fm.condwrite(not search, 'name', namefmt, name)
5708 5683 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5709 5684 for subopt, value in sorted(path.suboptions.items()):
5710 5685 assert subopt not in ('name', 'url')
5711 5686 if showsubopts:
5712 5687 fm.plain('%s:%s = ' % (name, subopt))
5713 5688 fm.condwrite(showsubopts, subopt, '%s\n', value)
5714 5689
5715 5690 fm.end()
5716 5691
5717 5692 if search and not pathitems:
5718 5693 if not ui.quiet:
5719 5694 ui.warn(_("not found!\n"))
5720 5695 return 1
5721 5696 else:
5722 5697 return 0
5723 5698
5724 5699 @command('phase',
5725 5700 [('p', 'public', False, _('set changeset phase to public')),
5726 5701 ('d', 'draft', False, _('set changeset phase to draft')),
5727 5702 ('s', 'secret', False, _('set changeset phase to secret')),
5728 5703 ('f', 'force', False, _('allow to move boundary backward')),
5729 5704 ('r', 'rev', [], _('target revision'), _('REV')),
5730 5705 ],
5731 5706 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5732 5707 def phase(ui, repo, *revs, **opts):
5733 5708 """set or show the current phase name
5734 5709
5735 5710 With no argument, show the phase name of the current revision(s).
5736 5711
5737 5712 With one of -p/--public, -d/--draft or -s/--secret, change the
5738 5713 phase value of the specified revisions.
5739 5714
5740 5715 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5741 5716 lower phase to an higher phase. Phases are ordered as follows::
5742 5717
5743 5718 public < draft < secret
5744 5719
5745 5720 Returns 0 on success, 1 if some phases could not be changed.
5746 5721
5747 5722 (For more information about the phases concept, see :hg:`help phases`.)
5748 5723 """
5749 5724 # search for a unique phase argument
5750 5725 targetphase = None
5751 5726 for idx, name in enumerate(phases.phasenames):
5752 5727 if opts[name]:
5753 5728 if targetphase is not None:
5754 5729 raise error.Abort(_('only one phase can be specified'))
5755 5730 targetphase = idx
5756 5731
5757 5732 # look for specified revision
5758 5733 revs = list(revs)
5759 5734 revs.extend(opts['rev'])
5760 5735 if not revs:
5761 5736 # display both parents as the second parent phase can influence
5762 5737 # the phase of a merge commit
5763 5738 revs = [c.rev() for c in repo[None].parents()]
5764 5739
5765 5740 revs = scmutil.revrange(repo, revs)
5766 5741
5767 5742 lock = None
5768 5743 ret = 0
5769 5744 if targetphase is None:
5770 5745 # display
5771 5746 for r in revs:
5772 5747 ctx = repo[r]
5773 5748 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5774 5749 else:
5775 5750 tr = None
5776 5751 lock = repo.lock()
5777 5752 try:
5778 5753 tr = repo.transaction("phase")
5779 5754 # set phase
5780 5755 if not revs:
5781 5756 raise error.Abort(_('empty revision set'))
5782 5757 nodes = [repo[r].node() for r in revs]
5783 5758 # moving revision from public to draft may hide them
5784 5759 # We have to check result on an unfiltered repository
5785 5760 unfi = repo.unfiltered()
5786 5761 getphase = unfi._phasecache.phase
5787 5762 olddata = [getphase(unfi, r) for r in unfi]
5788 5763 phases.advanceboundary(repo, tr, targetphase, nodes)
5789 5764 if opts['force']:
5790 5765 phases.retractboundary(repo, tr, targetphase, nodes)
5791 5766 tr.close()
5792 5767 finally:
5793 5768 if tr is not None:
5794 5769 tr.release()
5795 5770 lock.release()
5796 5771 getphase = unfi._phasecache.phase
5797 5772 newdata = [getphase(unfi, r) for r in unfi]
5798 5773 changes = sum(newdata[r] != olddata[r] for r in unfi)
5799 5774 cl = unfi.changelog
5800 5775 rejected = [n for n in nodes
5801 5776 if newdata[cl.rev(n)] < targetphase]
5802 5777 if rejected:
5803 5778 ui.warn(_('cannot move %i changesets to a higher '
5804 5779 'phase, use --force\n') % len(rejected))
5805 5780 ret = 1
5806 5781 if changes:
5807 5782 msg = _('phase changed for %i changesets\n') % changes
5808 5783 if ret:
5809 5784 ui.status(msg)
5810 5785 else:
5811 5786 ui.note(msg)
5812 5787 else:
5813 5788 ui.warn(_('no phases changed\n'))
5814 5789 return ret
5815 5790
5816 5791 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5817 5792 """Run after a changegroup has been added via pull/unbundle
5818 5793
5819 5794 This takes arguments below:
5820 5795
5821 5796 :modheads: change of heads by pull/unbundle
5822 5797 :optupdate: updating working directory is needed or not
5823 5798 :checkout: update destination revision (or None to default destination)
5824 5799 :brev: a name, which might be a bookmark to be activated after updating
5825 5800 """
5826 5801 if modheads == 0:
5827 5802 return
5828 5803 if optupdate:
5829 5804 try:
5830 5805 return hg.updatetotally(ui, repo, checkout, brev)
5831 5806 except error.UpdateAbort as inst:
5832 5807 msg = _("not updating: %s") % str(inst)
5833 5808 hint = inst.hint
5834 5809 raise error.UpdateAbort(msg, hint=hint)
5835 5810 if modheads > 1:
5836 5811 currentbranchheads = len(repo.branchheads())
5837 5812 if currentbranchheads == modheads:
5838 5813 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5839 5814 elif currentbranchheads > 1:
5840 5815 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5841 5816 "merge)\n"))
5842 5817 else:
5843 5818 ui.status(_("(run 'hg heads' to see heads)\n"))
5844 5819 else:
5845 5820 ui.status(_("(run 'hg update' to get a working copy)\n"))
5846 5821
5847 5822 @command('^pull',
5848 5823 [('u', 'update', None,
5849 5824 _('update to new branch head if changesets were pulled')),
5850 5825 ('f', 'force', None, _('run even when remote repository is unrelated')),
5851 5826 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5852 5827 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5853 5828 ('b', 'branch', [], _('a specific branch you would like to pull'),
5854 5829 _('BRANCH')),
5855 5830 ] + remoteopts,
5856 5831 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5857 5832 def pull(ui, repo, source="default", **opts):
5858 5833 """pull changes from the specified source
5859 5834
5860 5835 Pull changes from a remote repository to a local one.
5861 5836
5862 5837 This finds all changes from the repository at the specified path
5863 5838 or URL and adds them to a local repository (the current one unless
5864 5839 -R is specified). By default, this does not update the copy of the
5865 5840 project in the working directory.
5866 5841
5867 5842 Use :hg:`incoming` if you want to see what would have been added
5868 5843 by a pull at the time you issued this command. If you then decide
5869 5844 to add those changes to the repository, you should use :hg:`pull
5870 5845 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5871 5846
5872 5847 If SOURCE is omitted, the 'default' path will be used.
5873 5848 See :hg:`help urls` for more information.
5874 5849
5875 5850 Specifying bookmark as ``.`` is equivalent to specifying the active
5876 5851 bookmark's name.
5877 5852
5878 5853 Returns 0 on success, 1 if an update had unresolved files.
5879 5854 """
5880 5855 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5881 5856 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5882 5857 other = hg.peer(repo, opts, source)
5883 5858 try:
5884 5859 revs, checkout = hg.addbranchrevs(repo, other, branches,
5885 5860 opts.get('rev'))
5886 5861
5887 5862
5888 5863 pullopargs = {}
5889 5864 if opts.get('bookmark'):
5890 5865 if not revs:
5891 5866 revs = []
5892 5867 # The list of bookmark used here is not the one used to actually
5893 5868 # update the bookmark name. This can result in the revision pulled
5894 5869 # not ending up with the name of the bookmark because of a race
5895 5870 # condition on the server. (See issue 4689 for details)
5896 5871 remotebookmarks = other.listkeys('bookmarks')
5897 5872 pullopargs['remotebookmarks'] = remotebookmarks
5898 5873 for b in opts['bookmark']:
5899 5874 b = repo._bookmarks.expandname(b)
5900 5875 if b not in remotebookmarks:
5901 5876 raise error.Abort(_('remote bookmark %s not found!') % b)
5902 5877 revs.append(remotebookmarks[b])
5903 5878
5904 5879 if revs:
5905 5880 try:
5906 5881 # When 'rev' is a bookmark name, we cannot guarantee that it
5907 5882 # will be updated with that name because of a race condition
5908 5883 # server side. (See issue 4689 for details)
5909 5884 oldrevs = revs
5910 5885 revs = [] # actually, nodes
5911 5886 for r in oldrevs:
5912 5887 node = other.lookup(r)
5913 5888 revs.append(node)
5914 5889 if r == checkout:
5915 5890 checkout = node
5916 5891 except error.CapabilityError:
5917 5892 err = _("other repository doesn't support revision lookup, "
5918 5893 "so a rev cannot be specified.")
5919 5894 raise error.Abort(err)
5920 5895
5921 5896 pullopargs.update(opts.get('opargs', {}))
5922 5897 modheads = exchange.pull(repo, other, heads=revs,
5923 5898 force=opts.get('force'),
5924 5899 bookmarks=opts.get('bookmark', ()),
5925 5900 opargs=pullopargs).cgresult
5926 5901
5927 5902 # brev is a name, which might be a bookmark to be activated at
5928 5903 # the end of the update. In other words, it is an explicit
5929 5904 # destination of the update
5930 5905 brev = None
5931 5906
5932 5907 if checkout:
5933 5908 checkout = str(repo.changelog.rev(checkout))
5934 5909
5935 5910 # order below depends on implementation of
5936 5911 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5937 5912 # because 'checkout' is determined without it.
5938 5913 if opts.get('rev'):
5939 5914 brev = opts['rev'][0]
5940 5915 elif opts.get('branch'):
5941 5916 brev = opts['branch'][0]
5942 5917 else:
5943 5918 brev = branches[0]
5944 5919 repo._subtoppath = source
5945 5920 try:
5946 5921 ret = postincoming(ui, repo, modheads, opts.get('update'),
5947 5922 checkout, brev)
5948 5923
5949 5924 finally:
5950 5925 del repo._subtoppath
5951 5926
5952 5927 finally:
5953 5928 other.close()
5954 5929 return ret
5955 5930
5956 5931 @command('^push',
5957 5932 [('f', 'force', None, _('force push')),
5958 5933 ('r', 'rev', [],
5959 5934 _('a changeset intended to be included in the destination'),
5960 5935 _('REV')),
5961 5936 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5962 5937 ('b', 'branch', [],
5963 5938 _('a specific branch you would like to push'), _('BRANCH')),
5964 5939 ('', 'new-branch', False, _('allow pushing a new branch')),
5965 5940 ] + remoteopts,
5966 5941 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5967 5942 def push(ui, repo, dest=None, **opts):
5968 5943 """push changes to the specified destination
5969 5944
5970 5945 Push changesets from the local repository to the specified
5971 5946 destination.
5972 5947
5973 5948 This operation is symmetrical to pull: it is identical to a pull
5974 5949 in the destination repository from the current one.
5975 5950
5976 5951 By default, push will not allow creation of new heads at the
5977 5952 destination, since multiple heads would make it unclear which head
5978 5953 to use. In this situation, it is recommended to pull and merge
5979 5954 before pushing.
5980 5955
5981 5956 Use --new-branch if you want to allow push to create a new named
5982 5957 branch that is not present at the destination. This allows you to
5983 5958 only create a new branch without forcing other changes.
5984 5959
5985 5960 .. note::
5986 5961
5987 5962 Extra care should be taken with the -f/--force option,
5988 5963 which will push all new heads on all branches, an action which will
5989 5964 almost always cause confusion for collaborators.
5990 5965
5991 5966 If -r/--rev is used, the specified revision and all its ancestors
5992 5967 will be pushed to the remote repository.
5993 5968
5994 5969 If -B/--bookmark is used, the specified bookmarked revision, its
5995 5970 ancestors, and the bookmark will be pushed to the remote
5996 5971 repository. Specifying ``.`` is equivalent to specifying the active
5997 5972 bookmark's name.
5998 5973
5999 5974 Please see :hg:`help urls` for important details about ``ssh://``
6000 5975 URLs. If DESTINATION is omitted, a default path will be used.
6001 5976
6002 5977 Returns 0 if push was successful, 1 if nothing to push.
6003 5978 """
6004 5979
6005 5980 if opts.get('bookmark'):
6006 5981 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
6007 5982 for b in opts['bookmark']:
6008 5983 # translate -B options to -r so changesets get pushed
6009 5984 b = repo._bookmarks.expandname(b)
6010 5985 if b in repo._bookmarks:
6011 5986 opts.setdefault('rev', []).append(b)
6012 5987 else:
6013 5988 # if we try to push a deleted bookmark, translate it to null
6014 5989 # this lets simultaneous -r, -b options continue working
6015 5990 opts.setdefault('rev', []).append("null")
6016 5991
6017 5992 path = ui.paths.getpath(dest, default=('default-push', 'default'))
6018 5993 if not path:
6019 5994 raise error.Abort(_('default repository not configured!'),
6020 5995 hint=_("see 'hg help config.paths'"))
6021 5996 dest = path.pushloc or path.loc
6022 5997 branches = (path.branch, opts.get('branch') or [])
6023 5998 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
6024 5999 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
6025 6000 other = hg.peer(repo, opts, dest)
6026 6001
6027 6002 if revs:
6028 6003 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
6029 6004 if not revs:
6030 6005 raise error.Abort(_("specified revisions evaluate to an empty set"),
6031 6006 hint=_("use different revision arguments"))
6032 6007 elif path.pushrev:
6033 6008 # It doesn't make any sense to specify ancestor revisions. So limit
6034 6009 # to DAG heads to make discovery simpler.
6035 6010 expr = revset.formatspec('heads(%r)', path.pushrev)
6036 6011 revs = scmutil.revrange(repo, [expr])
6037 6012 revs = [repo[rev].node() for rev in revs]
6038 6013 if not revs:
6039 6014 raise error.Abort(_('default push revset for path evaluates to an '
6040 6015 'empty set'))
6041 6016
6042 6017 repo._subtoppath = dest
6043 6018 try:
6044 6019 # push subrepos depth-first for coherent ordering
6045 6020 c = repo['']
6046 6021 subs = c.substate # only repos that are committed
6047 6022 for s in sorted(subs):
6048 6023 result = c.sub(s).push(opts)
6049 6024 if result == 0:
6050 6025 return not result
6051 6026 finally:
6052 6027 del repo._subtoppath
6053 6028 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
6054 6029 newbranch=opts.get('new_branch'),
6055 6030 bookmarks=opts.get('bookmark', ()),
6056 6031 opargs=opts.get('opargs'))
6057 6032
6058 6033 result = not pushop.cgresult
6059 6034
6060 6035 if pushop.bkresult is not None:
6061 6036 if pushop.bkresult == 2:
6062 6037 result = 2
6063 6038 elif not result and pushop.bkresult:
6064 6039 result = 2
6065 6040
6066 6041 return result
6067 6042
6068 6043 @command('recover', [])
6069 6044 def recover(ui, repo):
6070 6045 """roll back an interrupted transaction
6071 6046
6072 6047 Recover from an interrupted commit or pull.
6073 6048
6074 6049 This command tries to fix the repository status after an
6075 6050 interrupted operation. It should only be necessary when Mercurial
6076 6051 suggests it.
6077 6052
6078 6053 Returns 0 if successful, 1 if nothing to recover or verify fails.
6079 6054 """
6080 6055 if repo.recover():
6081 6056 return hg.verify(repo)
6082 6057 return 1
6083 6058
6084 6059 @command('^remove|rm',
6085 6060 [('A', 'after', None, _('record delete for missing files')),
6086 6061 ('f', 'force', None,
6087 6062 _('forget added files, delete modified files')),
6088 6063 ] + subrepoopts + walkopts,
6089 6064 _('[OPTION]... FILE...'),
6090 6065 inferrepo=True)
6091 6066 def remove(ui, repo, *pats, **opts):
6092 6067 """remove the specified files on the next commit
6093 6068
6094 6069 Schedule the indicated files for removal from the current branch.
6095 6070
6096 6071 This command schedules the files to be removed at the next commit.
6097 6072 To undo a remove before that, see :hg:`revert`. To undo added
6098 6073 files, see :hg:`forget`.
6099 6074
6100 6075 .. container:: verbose
6101 6076
6102 6077 -A/--after can be used to remove only files that have already
6103 6078 been deleted, -f/--force can be used to force deletion, and -Af
6104 6079 can be used to remove files from the next revision without
6105 6080 deleting them from the working directory.
6106 6081
6107 6082 The following table details the behavior of remove for different
6108 6083 file states (columns) and option combinations (rows). The file
6109 6084 states are Added [A], Clean [C], Modified [M] and Missing [!]
6110 6085 (as reported by :hg:`status`). The actions are Warn, Remove
6111 6086 (from branch) and Delete (from disk):
6112 6087
6113 6088 ========= == == == ==
6114 6089 opt/state A C M !
6115 6090 ========= == == == ==
6116 6091 none W RD W R
6117 6092 -f R RD RD R
6118 6093 -A W W W R
6119 6094 -Af R R R R
6120 6095 ========= == == == ==
6121 6096
6122 6097 .. note::
6123 6098
6124 6099 :hg:`remove` never deletes files in Added [A] state from the
6125 6100 working directory, not even if ``--force`` is specified.
6126 6101
6127 6102 Returns 0 on success, 1 if any warnings encountered.
6128 6103 """
6129 6104
6130 6105 after, force = opts.get('after'), opts.get('force')
6131 6106 if not pats and not after:
6132 6107 raise error.Abort(_('no files specified'))
6133 6108
6134 6109 m = scmutil.match(repo[None], pats, opts)
6135 6110 subrepos = opts.get('subrepos')
6136 6111 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
6137 6112
6138 6113 @command('rename|move|mv',
6139 6114 [('A', 'after', None, _('record a rename that has already occurred')),
6140 6115 ('f', 'force', None, _('forcibly copy over an existing managed file')),
6141 6116 ] + walkopts + dryrunopts,
6142 6117 _('[OPTION]... SOURCE... DEST'))
6143 6118 def rename(ui, repo, *pats, **opts):
6144 6119 """rename files; equivalent of copy + remove
6145 6120
6146 6121 Mark dest as copies of sources; mark sources for deletion. If dest
6147 6122 is a directory, copies are put in that directory. If dest is a
6148 6123 file, there can only be one source.
6149 6124
6150 6125 By default, this command copies the contents of files as they
6151 6126 exist in the working directory. If invoked with -A/--after, the
6152 6127 operation is recorded, but no copying is performed.
6153 6128
6154 6129 This command takes effect at the next commit. To undo a rename
6155 6130 before that, see :hg:`revert`.
6156 6131
6157 6132 Returns 0 on success, 1 if errors are encountered.
6158 6133 """
6159 6134 with repo.wlock(False):
6160 6135 return cmdutil.copy(ui, repo, pats, opts, rename=True)
6161 6136
6162 6137 @command('resolve',
6163 6138 [('a', 'all', None, _('select all unresolved files')),
6164 6139 ('l', 'list', None, _('list state of files needing merge')),
6165 6140 ('m', 'mark', None, _('mark files as resolved')),
6166 6141 ('u', 'unmark', None, _('mark files as unresolved')),
6167 6142 ('n', 'no-status', None, _('hide status prefix'))]
6168 6143 + mergetoolopts + walkopts + formatteropts,
6169 6144 _('[OPTION]... [FILE]...'),
6170 6145 inferrepo=True)
6171 6146 def resolve(ui, repo, *pats, **opts):
6172 6147 """redo merges or set/view the merge status of files
6173 6148
6174 6149 Merges with unresolved conflicts are often the result of
6175 6150 non-interactive merging using the ``internal:merge`` configuration
6176 6151 setting, or a command-line merge tool like ``diff3``. The resolve
6177 6152 command is used to manage the files involved in a merge, after
6178 6153 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6179 6154 working directory must have two parents). See :hg:`help
6180 6155 merge-tools` for information on configuring merge tools.
6181 6156
6182 6157 The resolve command can be used in the following ways:
6183 6158
6184 6159 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6185 6160 files, discarding any previous merge attempts. Re-merging is not
6186 6161 performed for files already marked as resolved. Use ``--all/-a``
6187 6162 to select all unresolved files. ``--tool`` can be used to specify
6188 6163 the merge tool used for the given files. It overrides the HGMERGE
6189 6164 environment variable and your configuration files. Previous file
6190 6165 contents are saved with a ``.orig`` suffix.
6191 6166
6192 6167 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6193 6168 (e.g. after having manually fixed-up the files). The default is
6194 6169 to mark all unresolved files.
6195 6170
6196 6171 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6197 6172 default is to mark all resolved files.
6198 6173
6199 6174 - :hg:`resolve -l`: list files which had or still have conflicts.
6200 6175 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6201 6176
6202 6177 .. note::
6203 6178
6204 6179 Mercurial will not let you commit files with unresolved merge
6205 6180 conflicts. You must use :hg:`resolve -m ...` before you can
6206 6181 commit after a conflicting merge.
6207 6182
6208 6183 Returns 0 on success, 1 if any files fail a resolve attempt.
6209 6184 """
6210 6185
6211 6186 flaglist = 'all mark unmark list no_status'.split()
6212 6187 all, mark, unmark, show, nostatus = \
6213 6188 [opts.get(o) for o in flaglist]
6214 6189
6215 6190 if (show and (mark or unmark)) or (mark and unmark):
6216 6191 raise error.Abort(_("too many options specified"))
6217 6192 if pats and all:
6218 6193 raise error.Abort(_("can't specify --all and patterns"))
6219 6194 if not (all or pats or show or mark or unmark):
6220 6195 raise error.Abort(_('no files or directories specified'),
6221 6196 hint=('use --all to re-merge all unresolved files'))
6222 6197
6223 6198 if show:
6224 6199 fm = ui.formatter('resolve', opts)
6225 6200 ms = mergemod.mergestate.read(repo)
6226 6201 m = scmutil.match(repo[None], pats, opts)
6227 6202 for f in ms:
6228 6203 if not m(f):
6229 6204 continue
6230 6205 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6231 6206 'd': 'driverresolved'}[ms[f]]
6232 6207 fm.startitem()
6233 6208 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6234 6209 fm.write('path', '%s\n', f, label=l)
6235 6210 fm.end()
6236 6211 return 0
6237 6212
6238 6213 with repo.wlock():
6239 6214 ms = mergemod.mergestate.read(repo)
6240 6215
6241 6216 if not (ms.active() or repo.dirstate.p2() != nullid):
6242 6217 raise error.Abort(
6243 6218 _('resolve command not applicable when not merging'))
6244 6219
6245 6220 wctx = repo[None]
6246 6221
6247 6222 if ms.mergedriver and ms.mdstate() == 'u':
6248 6223 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6249 6224 ms.commit()
6250 6225 # allow mark and unmark to go through
6251 6226 if not mark and not unmark and not proceed:
6252 6227 return 1
6253 6228
6254 6229 m = scmutil.match(wctx, pats, opts)
6255 6230 ret = 0
6256 6231 didwork = False
6257 6232 runconclude = False
6258 6233
6259 6234 tocomplete = []
6260 6235 for f in ms:
6261 6236 if not m(f):
6262 6237 continue
6263 6238
6264 6239 didwork = True
6265 6240
6266 6241 # don't let driver-resolved files be marked, and run the conclude
6267 6242 # step if asked to resolve
6268 6243 if ms[f] == "d":
6269 6244 exact = m.exact(f)
6270 6245 if mark:
6271 6246 if exact:
6272 6247 ui.warn(_('not marking %s as it is driver-resolved\n')
6273 6248 % f)
6274 6249 elif unmark:
6275 6250 if exact:
6276 6251 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6277 6252 % f)
6278 6253 else:
6279 6254 runconclude = True
6280 6255 continue
6281 6256
6282 6257 if mark:
6283 6258 ms.mark(f, "r")
6284 6259 elif unmark:
6285 6260 ms.mark(f, "u")
6286 6261 else:
6287 6262 # backup pre-resolve (merge uses .orig for its own purposes)
6288 6263 a = repo.wjoin(f)
6289 6264 try:
6290 6265 util.copyfile(a, a + ".resolve")
6291 6266 except (IOError, OSError) as inst:
6292 6267 if inst.errno != errno.ENOENT:
6293 6268 raise
6294 6269
6295 6270 try:
6296 6271 # preresolve file
6297 6272 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6298 6273 'resolve')
6299 6274 complete, r = ms.preresolve(f, wctx)
6300 6275 if not complete:
6301 6276 tocomplete.append(f)
6302 6277 elif r:
6303 6278 ret = 1
6304 6279 finally:
6305 6280 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6306 6281 ms.commit()
6307 6282
6308 6283 # replace filemerge's .orig file with our resolve file, but only
6309 6284 # for merges that are complete
6310 6285 if complete:
6311 6286 try:
6312 6287 util.rename(a + ".resolve",
6313 6288 scmutil.origpath(ui, repo, a))
6314 6289 except OSError as inst:
6315 6290 if inst.errno != errno.ENOENT:
6316 6291 raise
6317 6292
6318 6293 for f in tocomplete:
6319 6294 try:
6320 6295 # resolve file
6321 6296 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6322 6297 'resolve')
6323 6298 r = ms.resolve(f, wctx)
6324 6299 if r:
6325 6300 ret = 1
6326 6301 finally:
6327 6302 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6328 6303 ms.commit()
6329 6304
6330 6305 # replace filemerge's .orig file with our resolve file
6331 6306 a = repo.wjoin(f)
6332 6307 try:
6333 6308 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6334 6309 except OSError as inst:
6335 6310 if inst.errno != errno.ENOENT:
6336 6311 raise
6337 6312
6338 6313 ms.commit()
6339 6314 ms.recordactions()
6340 6315
6341 6316 if not didwork and pats:
6342 6317 hint = None
6343 6318 if not any([p for p in pats if p.find(':') >= 0]):
6344 6319 pats = ['path:%s' % p for p in pats]
6345 6320 m = scmutil.match(wctx, pats, opts)
6346 6321 for f in ms:
6347 6322 if not m(f):
6348 6323 continue
6349 6324 flags = ''.join(['-%s ' % o[0] for o in flaglist
6350 6325 if opts.get(o)])
6351 6326 hint = _("(try: hg resolve %s%s)\n") % (
6352 6327 flags,
6353 6328 ' '.join(pats))
6354 6329 break
6355 6330 ui.warn(_("arguments do not match paths that need resolving\n"))
6356 6331 if hint:
6357 6332 ui.warn(hint)
6358 6333 elif ms.mergedriver and ms.mdstate() != 's':
6359 6334 # run conclude step when either a driver-resolved file is requested
6360 6335 # or there are no driver-resolved files
6361 6336 # we can't use 'ret' to determine whether any files are unresolved
6362 6337 # because we might not have tried to resolve some
6363 6338 if ((runconclude or not list(ms.driverresolved()))
6364 6339 and not list(ms.unresolved())):
6365 6340 proceed = mergemod.driverconclude(repo, ms, wctx)
6366 6341 ms.commit()
6367 6342 if not proceed:
6368 6343 return 1
6369 6344
6370 6345 # Nudge users into finishing an unfinished operation
6371 6346 unresolvedf = list(ms.unresolved())
6372 6347 driverresolvedf = list(ms.driverresolved())
6373 6348 if not unresolvedf and not driverresolvedf:
6374 6349 ui.status(_('(no more unresolved files)\n'))
6375 6350 cmdutil.checkafterresolved(repo)
6376 6351 elif not unresolvedf:
6377 6352 ui.status(_('(no more unresolved files -- '
6378 6353 'run "hg resolve --all" to conclude)\n'))
6379 6354
6380 6355 return ret
6381 6356
6382 6357 @command('revert',
6383 6358 [('a', 'all', None, _('revert all changes when no arguments given')),
6384 6359 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6385 6360 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6386 6361 ('C', 'no-backup', None, _('do not save backup copies of files')),
6387 6362 ('i', 'interactive', None,
6388 6363 _('interactively select the changes (EXPERIMENTAL)')),
6389 6364 ] + walkopts + dryrunopts,
6390 6365 _('[OPTION]... [-r REV] [NAME]...'))
6391 6366 def revert(ui, repo, *pats, **opts):
6392 6367 """restore files to their checkout state
6393 6368
6394 6369 .. note::
6395 6370
6396 6371 To check out earlier revisions, you should use :hg:`update REV`.
6397 6372 To cancel an uncommitted merge (and lose your changes),
6398 6373 use :hg:`update --clean .`.
6399 6374
6400 6375 With no revision specified, revert the specified files or directories
6401 6376 to the contents they had in the parent of the working directory.
6402 6377 This restores the contents of files to an unmodified
6403 6378 state and unschedules adds, removes, copies, and renames. If the
6404 6379 working directory has two parents, you must explicitly specify a
6405 6380 revision.
6406 6381
6407 6382 Using the -r/--rev or -d/--date options, revert the given files or
6408 6383 directories to their states as of a specific revision. Because
6409 6384 revert does not change the working directory parents, this will
6410 6385 cause these files to appear modified. This can be helpful to "back
6411 6386 out" some or all of an earlier change. See :hg:`backout` for a
6412 6387 related method.
6413 6388
6414 6389 Modified files are saved with a .orig suffix before reverting.
6415 6390 To disable these backups, use --no-backup. It is possible to store
6416 6391 the backup files in a custom directory relative to the root of the
6417 6392 repository by setting the ``ui.origbackuppath`` configuration
6418 6393 option.
6419 6394
6420 6395 See :hg:`help dates` for a list of formats valid for -d/--date.
6421 6396
6422 6397 See :hg:`help backout` for a way to reverse the effect of an
6423 6398 earlier changeset.
6424 6399
6425 6400 Returns 0 on success.
6426 6401 """
6427 6402
6428 6403 if opts.get("date"):
6429 6404 if opts.get("rev"):
6430 6405 raise error.Abort(_("you can't specify a revision and a date"))
6431 6406 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6432 6407
6433 6408 parent, p2 = repo.dirstate.parents()
6434 6409 if not opts.get('rev') and p2 != nullid:
6435 6410 # revert after merge is a trap for new users (issue2915)
6436 6411 raise error.Abort(_('uncommitted merge with no revision specified'),
6437 6412 hint=_("use 'hg update' or see 'hg help revert'"))
6438 6413
6439 6414 ctx = scmutil.revsingle(repo, opts.get('rev'))
6440 6415
6441 6416 if (not (pats or opts.get('include') or opts.get('exclude') or
6442 6417 opts.get('all') or opts.get('interactive'))):
6443 6418 msg = _("no files or directories specified")
6444 6419 if p2 != nullid:
6445 6420 hint = _("uncommitted merge, use --all to discard all changes,"
6446 6421 " or 'hg update -C .' to abort the merge")
6447 6422 raise error.Abort(msg, hint=hint)
6448 6423 dirty = any(repo.status())
6449 6424 node = ctx.node()
6450 6425 if node != parent:
6451 6426 if dirty:
6452 6427 hint = _("uncommitted changes, use --all to discard all"
6453 6428 " changes, or 'hg update %s' to update") % ctx.rev()
6454 6429 else:
6455 6430 hint = _("use --all to revert all files,"
6456 6431 " or 'hg update %s' to update") % ctx.rev()
6457 6432 elif dirty:
6458 6433 hint = _("uncommitted changes, use --all to discard all changes")
6459 6434 else:
6460 6435 hint = _("use --all to revert all files")
6461 6436 raise error.Abort(msg, hint=hint)
6462 6437
6463 6438 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6464 6439
6465 6440 @command('rollback', dryrunopts +
6466 6441 [('f', 'force', False, _('ignore safety measures'))])
6467 6442 def rollback(ui, repo, **opts):
6468 6443 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6469 6444
6470 6445 Please use :hg:`commit --amend` instead of rollback to correct
6471 6446 mistakes in the last commit.
6472 6447
6473 6448 This command should be used with care. There is only one level of
6474 6449 rollback, and there is no way to undo a rollback. It will also
6475 6450 restore the dirstate at the time of the last transaction, losing
6476 6451 any dirstate changes since that time. This command does not alter
6477 6452 the working directory.
6478 6453
6479 6454 Transactions are used to encapsulate the effects of all commands
6480 6455 that create new changesets or propagate existing changesets into a
6481 6456 repository.
6482 6457
6483 6458 .. container:: verbose
6484 6459
6485 6460 For example, the following commands are transactional, and their
6486 6461 effects can be rolled back:
6487 6462
6488 6463 - commit
6489 6464 - import
6490 6465 - pull
6491 6466 - push (with this repository as the destination)
6492 6467 - unbundle
6493 6468
6494 6469 To avoid permanent data loss, rollback will refuse to rollback a
6495 6470 commit transaction if it isn't checked out. Use --force to
6496 6471 override this protection.
6497 6472
6498 6473 The rollback command can be entirely disabled by setting the
6499 6474 ``ui.rollback`` configuration setting to false. If you're here
6500 6475 because you want to use rollback and it's disabled, you can
6501 6476 re-enable the command by setting ``ui.rollback`` to true.
6502 6477
6503 6478 This command is not intended for use on public repositories. Once
6504 6479 changes are visible for pull by other users, rolling a transaction
6505 6480 back locally is ineffective (someone else may already have pulled
6506 6481 the changes). Furthermore, a race is possible with readers of the
6507 6482 repository; for example an in-progress pull from the repository
6508 6483 may fail if a rollback is performed.
6509 6484
6510 6485 Returns 0 on success, 1 if no rollback data is available.
6511 6486 """
6512 6487 if not ui.configbool('ui', 'rollback', True):
6513 6488 raise error.Abort(_('rollback is disabled because it is unsafe'),
6514 6489 hint=('see `hg help -v rollback` for information'))
6515 6490 return repo.rollback(dryrun=opts.get('dry_run'),
6516 6491 force=opts.get('force'))
6517 6492
6518 6493 @command('root', [])
6519 6494 def root(ui, repo):
6520 6495 """print the root (top) of the current working directory
6521 6496
6522 6497 Print the root directory of the current repository.
6523 6498
6524 6499 Returns 0 on success.
6525 6500 """
6526 6501 ui.write(repo.root + "\n")
6527 6502
6528 6503 @command('^serve',
6529 6504 [('A', 'accesslog', '', _('name of access log file to write to'),
6530 6505 _('FILE')),
6531 6506 ('d', 'daemon', None, _('run server in background')),
6532 6507 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6533 6508 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6534 6509 # use string type, then we can check if something was passed
6535 6510 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6536 6511 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6537 6512 _('ADDR')),
6538 6513 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6539 6514 _('PREFIX')),
6540 6515 ('n', 'name', '',
6541 6516 _('name to show in web pages (default: working directory)'), _('NAME')),
6542 6517 ('', 'web-conf', '',
6543 6518 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
6544 6519 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6545 6520 _('FILE')),
6546 6521 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6547 6522 ('', 'stdio', None, _('for remote clients')),
6548 6523 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6549 6524 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6550 6525 ('', 'style', '', _('template style to use'), _('STYLE')),
6551 6526 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6552 6527 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6553 6528 _('[OPTION]...'),
6554 6529 optionalrepo=True)
6555 6530 def serve(ui, repo, **opts):
6556 6531 """start stand-alone webserver
6557 6532
6558 6533 Start a local HTTP repository browser and pull server. You can use
6559 6534 this for ad-hoc sharing and browsing of repositories. It is
6560 6535 recommended to use a real web server to serve a repository for
6561 6536 longer periods of time.
6562 6537
6563 6538 Please note that the server does not implement access control.
6564 6539 This means that, by default, anybody can read from the server and
6565 6540 nobody can write to it by default. Set the ``web.allow_push``
6566 6541 option to ``*`` to allow everybody to push to the server. You
6567 6542 should use a real web server if you need to authenticate users.
6568 6543
6569 6544 By default, the server logs accesses to stdout and errors to
6570 6545 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6571 6546 files.
6572 6547
6573 6548 To have the server choose a free port number to listen on, specify
6574 6549 a port number of 0; in this case, the server will print the port
6575 6550 number it uses.
6576 6551
6577 6552 Returns 0 on success.
6578 6553 """
6579 6554
6580 6555 if opts["stdio"] and opts["cmdserver"]:
6581 6556 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6582 6557
6583 6558 if opts["stdio"]:
6584 6559 if repo is None:
6585 6560 raise error.RepoError(_("there is no Mercurial repository here"
6586 6561 " (.hg not found)"))
6587 6562 s = sshserver.sshserver(ui, repo)
6588 6563 s.serve_forever()
6589 6564
6590 6565 if opts["cmdserver"]:
6591 6566 service = commandserver.createservice(ui, repo, opts)
6592 6567 else:
6593 6568 service = hgweb.createservice(ui, repo, opts)
6594 6569 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6595 6570
6596 6571 @command('^status|st',
6597 6572 [('A', 'all', None, _('show status of all files')),
6598 6573 ('m', 'modified', None, _('show only modified files')),
6599 6574 ('a', 'added', None, _('show only added files')),
6600 6575 ('r', 'removed', None, _('show only removed files')),
6601 6576 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6602 6577 ('c', 'clean', None, _('show only files without changes')),
6603 6578 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6604 6579 ('i', 'ignored', None, _('show only ignored files')),
6605 6580 ('n', 'no-status', None, _('hide status prefix')),
6606 6581 ('C', 'copies', None, _('show source of copied files')),
6607 6582 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6608 6583 ('', 'rev', [], _('show difference from revision'), _('REV')),
6609 6584 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6610 6585 ] + walkopts + subrepoopts + formatteropts,
6611 6586 _('[OPTION]... [FILE]...'),
6612 6587 inferrepo=True)
6613 6588 def status(ui, repo, *pats, **opts):
6614 6589 """show changed files in the working directory
6615 6590
6616 6591 Show status of files in the repository. If names are given, only
6617 6592 files that match are shown. Files that are clean or ignored or
6618 6593 the source of a copy/move operation, are not listed unless
6619 6594 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6620 6595 Unless options described with "show only ..." are given, the
6621 6596 options -mardu are used.
6622 6597
6623 6598 Option -q/--quiet hides untracked (unknown and ignored) files
6624 6599 unless explicitly requested with -u/--unknown or -i/--ignored.
6625 6600
6626 6601 .. note::
6627 6602
6628 6603 :hg:`status` may appear to disagree with diff if permissions have
6629 6604 changed or a merge has occurred. The standard diff format does
6630 6605 not report permission changes and diff only reports changes
6631 6606 relative to one merge parent.
6632 6607
6633 6608 If one revision is given, it is used as the base revision.
6634 6609 If two revisions are given, the differences between them are
6635 6610 shown. The --change option can also be used as a shortcut to list
6636 6611 the changed files of a revision from its first parent.
6637 6612
6638 6613 The codes used to show the status of files are::
6639 6614
6640 6615 M = modified
6641 6616 A = added
6642 6617 R = removed
6643 6618 C = clean
6644 6619 ! = missing (deleted by non-hg command, but still tracked)
6645 6620 ? = not tracked
6646 6621 I = ignored
6647 6622 = origin of the previous file (with --copies)
6648 6623
6649 6624 .. container:: verbose
6650 6625
6651 6626 Examples:
6652 6627
6653 6628 - show changes in the working directory relative to a
6654 6629 changeset::
6655 6630
6656 6631 hg status --rev 9353
6657 6632
6658 6633 - show changes in the working directory relative to the
6659 6634 current directory (see :hg:`help patterns` for more information)::
6660 6635
6661 6636 hg status re:
6662 6637
6663 6638 - show all changes including copies in an existing changeset::
6664 6639
6665 6640 hg status --copies --change 9353
6666 6641
6667 6642 - get a NUL separated list of added files, suitable for xargs::
6668 6643
6669 6644 hg status -an0
6670 6645
6671 6646 Returns 0 on success.
6672 6647 """
6673 6648
6674 6649 revs = opts.get('rev')
6675 6650 change = opts.get('change')
6676 6651
6677 6652 if revs and change:
6678 6653 msg = _('cannot specify --rev and --change at the same time')
6679 6654 raise error.Abort(msg)
6680 6655 elif change:
6681 6656 node2 = scmutil.revsingle(repo, change, None).node()
6682 6657 node1 = repo[node2].p1().node()
6683 6658 else:
6684 6659 node1, node2 = scmutil.revpair(repo, revs)
6685 6660
6686 6661 if pats:
6687 6662 cwd = repo.getcwd()
6688 6663 else:
6689 6664 cwd = ''
6690 6665
6691 6666 if opts.get('print0'):
6692 6667 end = '\0'
6693 6668 else:
6694 6669 end = '\n'
6695 6670 copy = {}
6696 6671 states = 'modified added removed deleted unknown ignored clean'.split()
6697 6672 show = [k for k in states if opts.get(k)]
6698 6673 if opts.get('all'):
6699 6674 show += ui.quiet and (states[:4] + ['clean']) or states
6700 6675 if not show:
6701 6676 if ui.quiet:
6702 6677 show = states[:4]
6703 6678 else:
6704 6679 show = states[:5]
6705 6680
6706 6681 m = scmutil.match(repo[node2], pats, opts)
6707 6682 stat = repo.status(node1, node2, m,
6708 6683 'ignored' in show, 'clean' in show, 'unknown' in show,
6709 6684 opts.get('subrepos'))
6710 6685 changestates = zip(states, 'MAR!?IC', stat)
6711 6686
6712 6687 if (opts.get('all') or opts.get('copies')
6713 6688 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6714 6689 copy = copies.pathcopies(repo[node1], repo[node2], m)
6715 6690
6716 6691 fm = ui.formatter('status', opts)
6717 6692 fmt = '%s' + end
6718 6693 showchar = not opts.get('no_status')
6719 6694
6720 6695 for state, char, files in changestates:
6721 6696 if state in show:
6722 6697 label = 'status.' + state
6723 6698 for f in files:
6724 6699 fm.startitem()
6725 6700 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6726 6701 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6727 6702 if f in copy:
6728 6703 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6729 6704 label='status.copied')
6730 6705 fm.end()
6731 6706
6732 6707 @command('^summary|sum',
6733 6708 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6734 6709 def summary(ui, repo, **opts):
6735 6710 """summarize working directory state
6736 6711
6737 6712 This generates a brief summary of the working directory state,
6738 6713 including parents, branch, commit status, phase and available updates.
6739 6714
6740 6715 With the --remote option, this will check the default paths for
6741 6716 incoming and outgoing changes. This can be time-consuming.
6742 6717
6743 6718 Returns 0 on success.
6744 6719 """
6745 6720
6746 6721 ctx = repo[None]
6747 6722 parents = ctx.parents()
6748 6723 pnode = parents[0].node()
6749 6724 marks = []
6750 6725
6751 6726 ms = None
6752 6727 try:
6753 6728 ms = mergemod.mergestate.read(repo)
6754 6729 except error.UnsupportedMergeRecords as e:
6755 6730 s = ' '.join(e.recordtypes)
6756 6731 ui.warn(
6757 6732 _('warning: merge state has unsupported record types: %s\n') % s)
6758 6733 unresolved = 0
6759 6734 else:
6760 6735 unresolved = [f for f in ms if ms[f] == 'u']
6761 6736
6762 6737 for p in parents:
6763 6738 # label with log.changeset (instead of log.parent) since this
6764 6739 # shows a working directory parent *changeset*:
6765 6740 # i18n: column positioning for "hg summary"
6766 6741 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6767 6742 label='log.changeset changeset.%s' % p.phasestr())
6768 6743 ui.write(' '.join(p.tags()), label='log.tag')
6769 6744 if p.bookmarks():
6770 6745 marks.extend(p.bookmarks())
6771 6746 if p.rev() == -1:
6772 6747 if not len(repo):
6773 6748 ui.write(_(' (empty repository)'))
6774 6749 else:
6775 6750 ui.write(_(' (no revision checked out)'))
6776 6751 ui.write('\n')
6777 6752 if p.description():
6778 6753 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6779 6754 label='log.summary')
6780 6755
6781 6756 branch = ctx.branch()
6782 6757 bheads = repo.branchheads(branch)
6783 6758 # i18n: column positioning for "hg summary"
6784 6759 m = _('branch: %s\n') % branch
6785 6760 if branch != 'default':
6786 6761 ui.write(m, label='log.branch')
6787 6762 else:
6788 6763 ui.status(m, label='log.branch')
6789 6764
6790 6765 if marks:
6791 6766 active = repo._activebookmark
6792 6767 # i18n: column positioning for "hg summary"
6793 6768 ui.write(_('bookmarks:'), label='log.bookmark')
6794 6769 if active is not None:
6795 6770 if active in marks:
6796 6771 ui.write(' *' + active, label=activebookmarklabel)
6797 6772 marks.remove(active)
6798 6773 else:
6799 6774 ui.write(' [%s]' % active, label=activebookmarklabel)
6800 6775 for m in marks:
6801 6776 ui.write(' ' + m, label='log.bookmark')
6802 6777 ui.write('\n', label='log.bookmark')
6803 6778
6804 6779 status = repo.status(unknown=True)
6805 6780
6806 6781 c = repo.dirstate.copies()
6807 6782 copied, renamed = [], []
6808 6783 for d, s in c.iteritems():
6809 6784 if s in status.removed:
6810 6785 status.removed.remove(s)
6811 6786 renamed.append(d)
6812 6787 else:
6813 6788 copied.append(d)
6814 6789 if d in status.added:
6815 6790 status.added.remove(d)
6816 6791
6817 6792 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6818 6793
6819 6794 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6820 6795 (ui.label(_('%d added'), 'status.added'), status.added),
6821 6796 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6822 6797 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6823 6798 (ui.label(_('%d copied'), 'status.copied'), copied),
6824 6799 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6825 6800 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6826 6801 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6827 6802 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6828 6803 t = []
6829 6804 for l, s in labels:
6830 6805 if s:
6831 6806 t.append(l % len(s))
6832 6807
6833 6808 t = ', '.join(t)
6834 6809 cleanworkdir = False
6835 6810
6836 6811 if repo.vfs.exists('graftstate'):
6837 6812 t += _(' (graft in progress)')
6838 6813 if repo.vfs.exists('updatestate'):
6839 6814 t += _(' (interrupted update)')
6840 6815 elif len(parents) > 1:
6841 6816 t += _(' (merge)')
6842 6817 elif branch != parents[0].branch():
6843 6818 t += _(' (new branch)')
6844 6819 elif (parents[0].closesbranch() and
6845 6820 pnode in repo.branchheads(branch, closed=True)):
6846 6821 t += _(' (head closed)')
6847 6822 elif not (status.modified or status.added or status.removed or renamed or
6848 6823 copied or subs):
6849 6824 t += _(' (clean)')
6850 6825 cleanworkdir = True
6851 6826 elif pnode not in bheads:
6852 6827 t += _(' (new branch head)')
6853 6828
6854 6829 if parents:
6855 6830 pendingphase = max(p.phase() for p in parents)
6856 6831 else:
6857 6832 pendingphase = phases.public
6858 6833
6859 6834 if pendingphase > phases.newcommitphase(ui):
6860 6835 t += ' (%s)' % phases.phasenames[pendingphase]
6861 6836
6862 6837 if cleanworkdir:
6863 6838 # i18n: column positioning for "hg summary"
6864 6839 ui.status(_('commit: %s\n') % t.strip())
6865 6840 else:
6866 6841 # i18n: column positioning for "hg summary"
6867 6842 ui.write(_('commit: %s\n') % t.strip())
6868 6843
6869 6844 # all ancestors of branch heads - all ancestors of parent = new csets
6870 6845 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6871 6846 bheads))
6872 6847
6873 6848 if new == 0:
6874 6849 # i18n: column positioning for "hg summary"
6875 6850 ui.status(_('update: (current)\n'))
6876 6851 elif pnode not in bheads:
6877 6852 # i18n: column positioning for "hg summary"
6878 6853 ui.write(_('update: %d new changesets (update)\n') % new)
6879 6854 else:
6880 6855 # i18n: column positioning for "hg summary"
6881 6856 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6882 6857 (new, len(bheads)))
6883 6858
6884 6859 t = []
6885 6860 draft = len(repo.revs('draft()'))
6886 6861 if draft:
6887 6862 t.append(_('%d draft') % draft)
6888 6863 secret = len(repo.revs('secret()'))
6889 6864 if secret:
6890 6865 t.append(_('%d secret') % secret)
6891 6866
6892 6867 if draft or secret:
6893 6868 ui.status(_('phases: %s\n') % ', '.join(t))
6894 6869
6895 6870 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6896 6871 for trouble in ("unstable", "divergent", "bumped"):
6897 6872 numtrouble = len(repo.revs(trouble + "()"))
6898 6873 # We write all the possibilities to ease translation
6899 6874 troublemsg = {
6900 6875 "unstable": _("unstable: %d changesets"),
6901 6876 "divergent": _("divergent: %d changesets"),
6902 6877 "bumped": _("bumped: %d changesets"),
6903 6878 }
6904 6879 if numtrouble > 0:
6905 6880 ui.status(troublemsg[trouble] % numtrouble + "\n")
6906 6881
6907 6882 cmdutil.summaryhooks(ui, repo)
6908 6883
6909 6884 if opts.get('remote'):
6910 6885 needsincoming, needsoutgoing = True, True
6911 6886 else:
6912 6887 needsincoming, needsoutgoing = False, False
6913 6888 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6914 6889 if i:
6915 6890 needsincoming = True
6916 6891 if o:
6917 6892 needsoutgoing = True
6918 6893 if not needsincoming and not needsoutgoing:
6919 6894 return
6920 6895
6921 6896 def getincoming():
6922 6897 source, branches = hg.parseurl(ui.expandpath('default'))
6923 6898 sbranch = branches[0]
6924 6899 try:
6925 6900 other = hg.peer(repo, {}, source)
6926 6901 except error.RepoError:
6927 6902 if opts.get('remote'):
6928 6903 raise
6929 6904 return source, sbranch, None, None, None
6930 6905 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6931 6906 if revs:
6932 6907 revs = [other.lookup(rev) for rev in revs]
6933 6908 ui.debug('comparing with %s\n' % util.hidepassword(source))
6934 6909 repo.ui.pushbuffer()
6935 6910 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6936 6911 repo.ui.popbuffer()
6937 6912 return source, sbranch, other, commoninc, commoninc[1]
6938 6913
6939 6914 if needsincoming:
6940 6915 source, sbranch, sother, commoninc, incoming = getincoming()
6941 6916 else:
6942 6917 source = sbranch = sother = commoninc = incoming = None
6943 6918
6944 6919 def getoutgoing():
6945 6920 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6946 6921 dbranch = branches[0]
6947 6922 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6948 6923 if source != dest:
6949 6924 try:
6950 6925 dother = hg.peer(repo, {}, dest)
6951 6926 except error.RepoError:
6952 6927 if opts.get('remote'):
6953 6928 raise
6954 6929 return dest, dbranch, None, None
6955 6930 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6956 6931 elif sother is None:
6957 6932 # there is no explicit destination peer, but source one is invalid
6958 6933 return dest, dbranch, None, None
6959 6934 else:
6960 6935 dother = sother
6961 6936 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6962 6937 common = None
6963 6938 else:
6964 6939 common = commoninc
6965 6940 if revs:
6966 6941 revs = [repo.lookup(rev) for rev in revs]
6967 6942 repo.ui.pushbuffer()
6968 6943 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6969 6944 commoninc=common)
6970 6945 repo.ui.popbuffer()
6971 6946 return dest, dbranch, dother, outgoing
6972 6947
6973 6948 if needsoutgoing:
6974 6949 dest, dbranch, dother, outgoing = getoutgoing()
6975 6950 else:
6976 6951 dest = dbranch = dother = outgoing = None
6977 6952
6978 6953 if opts.get('remote'):
6979 6954 t = []
6980 6955 if incoming:
6981 6956 t.append(_('1 or more incoming'))
6982 6957 o = outgoing.missing
6983 6958 if o:
6984 6959 t.append(_('%d outgoing') % len(o))
6985 6960 other = dother or sother
6986 6961 if 'bookmarks' in other.listkeys('namespaces'):
6987 6962 counts = bookmarks.summary(repo, other)
6988 6963 if counts[0] > 0:
6989 6964 t.append(_('%d incoming bookmarks') % counts[0])
6990 6965 if counts[1] > 0:
6991 6966 t.append(_('%d outgoing bookmarks') % counts[1])
6992 6967
6993 6968 if t:
6994 6969 # i18n: column positioning for "hg summary"
6995 6970 ui.write(_('remote: %s\n') % (', '.join(t)))
6996 6971 else:
6997 6972 # i18n: column positioning for "hg summary"
6998 6973 ui.status(_('remote: (synced)\n'))
6999 6974
7000 6975 cmdutil.summaryremotehooks(ui, repo, opts,
7001 6976 ((source, sbranch, sother, commoninc),
7002 6977 (dest, dbranch, dother, outgoing)))
7003 6978
7004 6979 @command('tag',
7005 6980 [('f', 'force', None, _('force tag')),
7006 6981 ('l', 'local', None, _('make the tag local')),
7007 6982 ('r', 'rev', '', _('revision to tag'), _('REV')),
7008 6983 ('', 'remove', None, _('remove a tag')),
7009 6984 # -l/--local is already there, commitopts cannot be used
7010 6985 ('e', 'edit', None, _('invoke editor on commit messages')),
7011 6986 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
7012 6987 ] + commitopts2,
7013 6988 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
7014 6989 def tag(ui, repo, name1, *names, **opts):
7015 6990 """add one or more tags for the current or given revision
7016 6991
7017 6992 Name a particular revision using <name>.
7018 6993
7019 6994 Tags are used to name particular revisions of the repository and are
7020 6995 very useful to compare different revisions, to go back to significant
7021 6996 earlier versions or to mark branch points as releases, etc. Changing
7022 6997 an existing tag is normally disallowed; use -f/--force to override.
7023 6998
7024 6999 If no revision is given, the parent of the working directory is
7025 7000 used.
7026 7001
7027 7002 To facilitate version control, distribution, and merging of tags,
7028 7003 they are stored as a file named ".hgtags" which is managed similarly
7029 7004 to other project files and can be hand-edited if necessary. This
7030 7005 also means that tagging creates a new commit. The file
7031 7006 ".hg/localtags" is used for local tags (not shared among
7032 7007 repositories).
7033 7008
7034 7009 Tag commits are usually made at the head of a branch. If the parent
7035 7010 of the working directory is not a branch head, :hg:`tag` aborts; use
7036 7011 -f/--force to force the tag commit to be based on a non-head
7037 7012 changeset.
7038 7013
7039 7014 See :hg:`help dates` for a list of formats valid for -d/--date.
7040 7015
7041 7016 Since tag names have priority over branch names during revision
7042 7017 lookup, using an existing branch name as a tag name is discouraged.
7043 7018
7044 7019 Returns 0 on success.
7045 7020 """
7046 7021 wlock = lock = None
7047 7022 try:
7048 7023 wlock = repo.wlock()
7049 7024 lock = repo.lock()
7050 7025 rev_ = "."
7051 7026 names = [t.strip() for t in (name1,) + names]
7052 7027 if len(names) != len(set(names)):
7053 7028 raise error.Abort(_('tag names must be unique'))
7054 7029 for n in names:
7055 7030 scmutil.checknewlabel(repo, n, 'tag')
7056 7031 if not n:
7057 7032 raise error.Abort(_('tag names cannot consist entirely of '
7058 7033 'whitespace'))
7059 7034 if opts.get('rev') and opts.get('remove'):
7060 7035 raise error.Abort(_("--rev and --remove are incompatible"))
7061 7036 if opts.get('rev'):
7062 7037 rev_ = opts['rev']
7063 7038 message = opts.get('message')
7064 7039 if opts.get('remove'):
7065 7040 if opts.get('local'):
7066 7041 expectedtype = 'local'
7067 7042 else:
7068 7043 expectedtype = 'global'
7069 7044
7070 7045 for n in names:
7071 7046 if not repo.tagtype(n):
7072 7047 raise error.Abort(_("tag '%s' does not exist") % n)
7073 7048 if repo.tagtype(n) != expectedtype:
7074 7049 if expectedtype == 'global':
7075 7050 raise error.Abort(_("tag '%s' is not a global tag") % n)
7076 7051 else:
7077 7052 raise error.Abort(_("tag '%s' is not a local tag") % n)
7078 7053 rev_ = 'null'
7079 7054 if not message:
7080 7055 # we don't translate commit messages
7081 7056 message = 'Removed tag %s' % ', '.join(names)
7082 7057 elif not opts.get('force'):
7083 7058 for n in names:
7084 7059 if n in repo.tags():
7085 7060 raise error.Abort(_("tag '%s' already exists "
7086 7061 "(use -f to force)") % n)
7087 7062 if not opts.get('local'):
7088 7063 p1, p2 = repo.dirstate.parents()
7089 7064 if p2 != nullid:
7090 7065 raise error.Abort(_('uncommitted merge'))
7091 7066 bheads = repo.branchheads()
7092 7067 if not opts.get('force') and bheads and p1 not in bheads:
7093 7068 raise error.Abort(_('not at a branch head (use -f to force)'))
7094 7069 r = scmutil.revsingle(repo, rev_).node()
7095 7070
7096 7071 if not message:
7097 7072 # we don't translate commit messages
7098 7073 message = ('Added tag %s for changeset %s' %
7099 7074 (', '.join(names), short(r)))
7100 7075
7101 7076 date = opts.get('date')
7102 7077 if date:
7103 7078 date = util.parsedate(date)
7104 7079
7105 7080 if opts.get('remove'):
7106 7081 editform = 'tag.remove'
7107 7082 else:
7108 7083 editform = 'tag.add'
7109 7084 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7110 7085
7111 7086 # don't allow tagging the null rev
7112 7087 if (not opts.get('remove') and
7113 7088 scmutil.revsingle(repo, rev_).rev() == nullrev):
7114 7089 raise error.Abort(_("cannot tag null revision"))
7115 7090
7116 7091 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
7117 7092 editor=editor)
7118 7093 finally:
7119 7094 release(lock, wlock)
7120 7095
7121 7096 @command('tags', formatteropts, '')
7122 7097 def tags(ui, repo, **opts):
7123 7098 """list repository tags
7124 7099
7125 7100 This lists both regular and local tags. When the -v/--verbose
7126 7101 switch is used, a third column "local" is printed for local tags.
7127 7102 When the -q/--quiet switch is used, only the tag name is printed.
7128 7103
7129 7104 Returns 0 on success.
7130 7105 """
7131 7106
7132 7107 fm = ui.formatter('tags', opts)
7133 7108 hexfunc = fm.hexfunc
7134 7109 tagtype = ""
7135 7110
7136 7111 for t, n in reversed(repo.tagslist()):
7137 7112 hn = hexfunc(n)
7138 7113 label = 'tags.normal'
7139 7114 tagtype = ''
7140 7115 if repo.tagtype(t) == 'local':
7141 7116 label = 'tags.local'
7142 7117 tagtype = 'local'
7143 7118
7144 7119 fm.startitem()
7145 7120 fm.write('tag', '%s', t, label=label)
7146 7121 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
7147 7122 fm.condwrite(not ui.quiet, 'rev node', fmt,
7148 7123 repo.changelog.rev(n), hn, label=label)
7149 7124 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
7150 7125 tagtype, label=label)
7151 7126 fm.plain('\n')
7152 7127 fm.end()
7153 7128
7154 7129 @command('tip',
7155 7130 [('p', 'patch', None, _('show patch')),
7156 7131 ('g', 'git', None, _('use git extended diff format')),
7157 7132 ] + templateopts,
7158 7133 _('[-p] [-g]'))
7159 7134 def tip(ui, repo, **opts):
7160 7135 """show the tip revision (DEPRECATED)
7161 7136
7162 7137 The tip revision (usually just called the tip) is the changeset
7163 7138 most recently added to the repository (and therefore the most
7164 7139 recently changed head).
7165 7140
7166 7141 If you have just made a commit, that commit will be the tip. If
7167 7142 you have just pulled changes from another repository, the tip of
7168 7143 that repository becomes the current tip. The "tip" tag is special
7169 7144 and cannot be renamed or assigned to a different changeset.
7170 7145
7171 7146 This command is deprecated, please use :hg:`heads` instead.
7172 7147
7173 7148 Returns 0 on success.
7174 7149 """
7175 7150 displayer = cmdutil.show_changeset(ui, repo, opts)
7176 7151 displayer.show(repo['tip'])
7177 7152 displayer.close()
7178 7153
7179 7154 @command('unbundle',
7180 7155 [('u', 'update', None,
7181 7156 _('update to new branch head if changesets were unbundled'))],
7182 7157 _('[-u] FILE...'))
7183 7158 def unbundle(ui, repo, fname1, *fnames, **opts):
7184 7159 """apply one or more changegroup files
7185 7160
7186 7161 Apply one or more compressed changegroup files generated by the
7187 7162 bundle command.
7188 7163
7189 7164 Returns 0 on success, 1 if an update has unresolved files.
7190 7165 """
7191 7166 fnames = (fname1,) + fnames
7192 7167
7193 7168 with repo.lock():
7194 7169 for fname in fnames:
7195 7170 f = hg.openpath(ui, fname)
7196 7171 gen = exchange.readbundle(ui, f, fname)
7197 7172 if isinstance(gen, bundle2.unbundle20):
7198 7173 tr = repo.transaction('unbundle')
7199 7174 try:
7200 7175 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7201 7176 url='bundle:' + fname)
7202 7177 tr.close()
7203 7178 except error.BundleUnknownFeatureError as exc:
7204 7179 raise error.Abort(_('%s: unknown bundle feature, %s')
7205 7180 % (fname, exc),
7206 7181 hint=_("see https://mercurial-scm.org/"
7207 7182 "wiki/BundleFeature for more "
7208 7183 "information"))
7209 7184 finally:
7210 7185 if tr:
7211 7186 tr.release()
7212 7187 changes = [r.get('return', 0)
7213 7188 for r in op.records['changegroup']]
7214 7189 modheads = changegroup.combineresults(changes)
7215 7190 elif isinstance(gen, streamclone.streamcloneapplier):
7216 7191 raise error.Abort(
7217 7192 _('packed bundles cannot be applied with '
7218 7193 '"hg unbundle"'),
7219 7194 hint=_('use "hg debugapplystreamclonebundle"'))
7220 7195 else:
7221 7196 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7222 7197
7223 7198 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7224 7199
7225 7200 @command('^update|up|checkout|co',
7226 7201 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7227 7202 ('c', 'check', None, _('require clean working directory')),
7228 7203 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7229 7204 ('r', 'rev', '', _('revision'), _('REV'))
7230 7205 ] + mergetoolopts,
7231 7206 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7232 7207 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7233 7208 tool=None):
7234 7209 """update working directory (or switch revisions)
7235 7210
7236 7211 Update the repository's working directory to the specified
7237 7212 changeset. If no changeset is specified, update to the tip of the
7238 7213 current named branch and move the active bookmark (see :hg:`help
7239 7214 bookmarks`).
7240 7215
7241 7216 Update sets the working directory's parent revision to the specified
7242 7217 changeset (see :hg:`help parents`).
7243 7218
7244 7219 If the changeset is not a descendant or ancestor of the working
7245 7220 directory's parent, the update is aborted. With the -c/--check
7246 7221 option, the working directory is checked for uncommitted changes; if
7247 7222 none are found, the working directory is updated to the specified
7248 7223 changeset.
7249 7224
7250 7225 .. container:: verbose
7251 7226
7252 7227 The following rules apply when the working directory contains
7253 7228 uncommitted changes:
7254 7229
7255 7230 1. If neither -c/--check nor -C/--clean is specified, and if
7256 7231 the requested changeset is an ancestor or descendant of
7257 7232 the working directory's parent, the uncommitted changes
7258 7233 are merged into the requested changeset and the merged
7259 7234 result is left uncommitted. If the requested changeset is
7260 7235 not an ancestor or descendant (that is, it is on another
7261 7236 branch), the update is aborted and the uncommitted changes
7262 7237 are preserved.
7263 7238
7264 7239 2. With the -c/--check option, the update is aborted and the
7265 7240 uncommitted changes are preserved.
7266 7241
7267 7242 3. With the -C/--clean option, uncommitted changes are discarded and
7268 7243 the working directory is updated to the requested changeset.
7269 7244
7270 7245 To cancel an uncommitted merge (and lose your changes), use
7271 7246 :hg:`update --clean .`.
7272 7247
7273 7248 Use null as the changeset to remove the working directory (like
7274 7249 :hg:`clone -U`).
7275 7250
7276 7251 If you want to revert just one file to an older revision, use
7277 7252 :hg:`revert [-r REV] NAME`.
7278 7253
7279 7254 See :hg:`help dates` for a list of formats valid for -d/--date.
7280 7255
7281 7256 Returns 0 on success, 1 if there are unresolved files.
7282 7257 """
7283 7258 if rev and node:
7284 7259 raise error.Abort(_("please specify just one revision"))
7285 7260
7286 7261 if rev is None or rev == '':
7287 7262 rev = node
7288 7263
7289 7264 if date and rev is not None:
7290 7265 raise error.Abort(_("you can't specify a revision and a date"))
7291 7266
7292 7267 if check and clean:
7293 7268 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7294 7269
7295 7270 with repo.wlock():
7296 7271 cmdutil.clearunfinished(repo)
7297 7272
7298 7273 if date:
7299 7274 rev = cmdutil.finddate(ui, repo, date)
7300 7275
7301 7276 # if we defined a bookmark, we have to remember the original name
7302 7277 brev = rev
7303 7278 rev = scmutil.revsingle(repo, rev, rev).rev()
7304 7279
7305 7280 if check:
7306 7281 cmdutil.bailifchanged(repo, merge=False)
7307 7282
7308 7283 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7309 7284
7310 7285 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7311 7286
7312 7287 @command('verify', [])
7313 7288 def verify(ui, repo):
7314 7289 """verify the integrity of the repository
7315 7290
7316 7291 Verify the integrity of the current repository.
7317 7292
7318 7293 This will perform an extensive check of the repository's
7319 7294 integrity, validating the hashes and checksums of each entry in
7320 7295 the changelog, manifest, and tracked files, as well as the
7321 7296 integrity of their crosslinks and indices.
7322 7297
7323 7298 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7324 7299 for more information about recovery from corruption of the
7325 7300 repository.
7326 7301
7327 7302 Returns 0 on success, 1 if errors are encountered.
7328 7303 """
7329 7304 return hg.verify(repo)
7330 7305
7331 7306 @command('version', [] + formatteropts, norepo=True)
7332 7307 def version_(ui, **opts):
7333 7308 """output version and copyright information"""
7334 7309 fm = ui.formatter("version", opts)
7335 7310 fm.startitem()
7336 7311 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
7337 7312 util.version())
7338 7313 license = _(
7339 7314 "(see https://mercurial-scm.org for more information)\n"
7340 7315 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7341 7316 "This is free software; see the source for copying conditions. "
7342 7317 "There is NO\nwarranty; "
7343 7318 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7344 7319 )
7345 7320 if not ui.quiet:
7346 7321 fm.plain(license)
7347 7322
7348 7323 if ui.verbose:
7349 7324 fm.plain(_("\nEnabled extensions:\n\n"))
7350 7325 # format names and versions into columns
7351 7326 names = []
7352 7327 vers = []
7353 7328 isinternals = []
7354 7329 for name, module in extensions.extensions():
7355 7330 names.append(name)
7356 7331 vers.append(extensions.moduleversion(module) or None)
7357 7332 isinternals.append(extensions.ismoduleinternal(module))
7358 7333 fn = fm.nested("extensions")
7359 7334 if names:
7360 7335 namefmt = " %%-%ds " % max(len(n) for n in names)
7361 7336 places = [_("external"), _("internal")]
7362 7337 for n, v, p in zip(names, vers, isinternals):
7363 7338 fn.startitem()
7364 7339 fn.condwrite(ui.verbose, "name", namefmt, n)
7365 7340 if ui.verbose:
7366 7341 fn.plain("%s " % places[p])
7367 7342 fn.data(bundled=p)
7368 7343 fn.condwrite(ui.verbose and v, "ver", "%s", v)
7369 7344 if ui.verbose:
7370 7345 fn.plain("\n")
7371 7346 fn.end()
7372 7347 fm.end()
7373 7348
7374 7349 def loadcmdtable(ui, name, cmdtable):
7375 7350 """Load command functions from specified cmdtable
7376 7351 """
7377 7352 overrides = [cmd for cmd in cmdtable if cmd in table]
7378 7353 if overrides:
7379 7354 ui.warn(_("extension '%s' overrides commands: %s\n")
7380 7355 % (name, " ".join(overrides)))
7381 7356 table.update(cmdtable)
@@ -1,281 +1,307 b''
1 1 # changelog bisection for mercurial
2 2 #
3 3 # Copyright 2007 Matt Mackall
4 4 # Copyright 2005, 2006 Benoit Boissinot <benoit.boissinot@ens-lyon.org>
5 5 #
6 6 # Inspired by git bisect, extension skeleton taken from mq.py.
7 7 #
8 8 # This software may be used and distributed according to the terms of the
9 9 # GNU General Public License version 2 or any later version.
10 10
11 11 from __future__ import absolute_import
12 12
13 13 import collections
14 14
15 15 from .i18n import _
16 16 from .node import (
17 17 hex,
18 18 short,
19 19 )
20 20 from . import (
21 21 error,
22 22 )
23 23
24 24 def bisect(changelog, state):
25 25 """find the next node (if any) for testing during a bisect search.
26 26 returns a (nodes, number, good) tuple.
27 27
28 28 'nodes' is the final result of the bisect if 'number' is 0.
29 29 Otherwise 'number' indicates the remaining possible candidates for
30 30 the search and 'nodes' contains the next bisect target.
31 31 'good' is True if bisect is searching for a first good changeset, False
32 32 if searching for a first bad one.
33 33 """
34 34
35 35 clparents = changelog.parentrevs
36 36 skip = set([changelog.rev(n) for n in state['skip']])
37 37
38 38 def buildancestors(bad, good):
39 39 # only the earliest bad revision matters
40 40 badrev = min([changelog.rev(n) for n in bad])
41 41 goodrevs = [changelog.rev(n) for n in good]
42 42 goodrev = min(goodrevs)
43 43 # build visit array
44 44 ancestors = [None] * (len(changelog) + 1) # an extra for [-1]
45 45
46 46 # set nodes descended from goodrevs
47 47 for rev in goodrevs:
48 48 ancestors[rev] = []
49 49 for rev in changelog.revs(goodrev + 1):
50 50 for prev in clparents(rev):
51 51 if ancestors[prev] == []:
52 52 ancestors[rev] = []
53 53
54 54 # clear good revs from array
55 55 for rev in goodrevs:
56 56 ancestors[rev] = None
57 57 for rev in changelog.revs(len(changelog), goodrev):
58 58 if ancestors[rev] is None:
59 59 for prev in clparents(rev):
60 60 ancestors[prev] = None
61 61
62 62 if ancestors[badrev] is None:
63 63 return badrev, None
64 64 return badrev, ancestors
65 65
66 66 good = False
67 67 badrev, ancestors = buildancestors(state['bad'], state['good'])
68 68 if not ancestors: # looking for bad to good transition?
69 69 good = True
70 70 badrev, ancestors = buildancestors(state['good'], state['bad'])
71 71 bad = changelog.node(badrev)
72 72 if not ancestors: # now we're confused
73 73 if (len(state['bad']) == 1 and len(state['good']) == 1 and
74 74 state['bad'] != state['good']):
75 75 raise error.Abort(_("starting revisions are not directly related"))
76 76 raise error.Abort(_("inconsistent state, %s:%s is good and bad")
77 77 % (badrev, short(bad)))
78 78
79 79 # build children dict
80 80 children = {}
81 81 visit = collections.deque([badrev])
82 82 candidates = []
83 83 while visit:
84 84 rev = visit.popleft()
85 85 if ancestors[rev] == []:
86 86 candidates.append(rev)
87 87 for prev in clparents(rev):
88 88 if prev != -1:
89 89 if prev in children:
90 90 children[prev].append(rev)
91 91 else:
92 92 children[prev] = [rev]
93 93 visit.append(prev)
94 94
95 95 candidates.sort()
96 96 # have we narrowed it down to one entry?
97 97 # or have all other possible candidates besides 'bad' have been skipped?
98 98 tot = len(candidates)
99 99 unskipped = [c for c in candidates if (c not in skip) and (c != badrev)]
100 100 if tot == 1 or not unskipped:
101 101 return ([changelog.node(rev) for rev in candidates], 0, good)
102 102 perfect = tot // 2
103 103
104 104 # find the best node to test
105 105 best_rev = None
106 106 best_len = -1
107 107 poison = set()
108 108 for rev in candidates:
109 109 if rev in poison:
110 110 # poison children
111 111 poison.update(children.get(rev, []))
112 112 continue
113 113
114 114 a = ancestors[rev] or [rev]
115 115 ancestors[rev] = None
116 116
117 117 x = len(a) # number of ancestors
118 118 y = tot - x # number of non-ancestors
119 119 value = min(x, y) # how good is this test?
120 120 if value > best_len and rev not in skip:
121 121 best_len = value
122 122 best_rev = rev
123 123 if value == perfect: # found a perfect candidate? quit early
124 124 break
125 125
126 126 if y < perfect and rev not in skip: # all downhill from here?
127 127 # poison children
128 128 poison.update(children.get(rev, []))
129 129 continue
130 130
131 131 for c in children.get(rev, []):
132 132 if ancestors[c]:
133 133 ancestors[c] = list(set(ancestors[c] + a))
134 134 else:
135 135 ancestors[c] = a + [c]
136 136
137 137 assert best_rev is not None
138 138 best_node = changelog.node(best_rev)
139 139
140 140 return ([best_node], tot, good)
141 141
142 142 def extendrange(repo, state, nodes, good):
143 143 # bisect is incomplete when it ends on a merge node and
144 144 # one of the parent was not checked.
145 145 parents = repo[nodes[0]].parents()
146 146 if len(parents) > 1:
147 147 if good:
148 148 side = state['bad']
149 149 else:
150 150 side = state['good']
151 151 num = len(set(i.node() for i in parents) & set(side))
152 152 if num == 1:
153 153 return parents[0].ancestor(parents[1])
154 154 return None
155 155
156 156 def load_state(repo):
157 157 state = {'current': [], 'good': [], 'bad': [], 'skip': []}
158 158 for l in repo.vfs.tryreadlines("bisect.state"):
159 159 kind, node = l[:-1].split()
160 160 node = repo.lookup(node)
161 161 if kind not in state:
162 162 raise error.Abort(_("unknown bisect kind %s") % kind)
163 163 state[kind].append(node)
164 164 return state
165 165
166 166
167 167 def save_state(repo, state):
168 168 f = repo.vfs("bisect.state", "w", atomictemp=True)
169 169 with repo.wlock():
170 170 for kind in sorted(state):
171 171 for node in state[kind]:
172 172 f.write("%s %s\n" % (kind, hex(node)))
173 173 f.close()
174 174
175 175 def resetstate(repo):
176 176 """remove any bisect state from the repository"""
177 177 if repo.vfs.exists("bisect.state"):
178 178 repo.vfs.unlink("bisect.state")
179 179
180 180 def get(repo, status):
181 181 """
182 182 Return a list of revision(s) that match the given status:
183 183
184 184 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
185 185 - ``goods``, ``bads`` : csets topologically good/bad
186 186 - ``range`` : csets taking part in the bisection
187 187 - ``pruned`` : csets that are goods, bads or skipped
188 188 - ``untested`` : csets whose fate is yet unknown
189 189 - ``ignored`` : csets ignored due to DAG topology
190 190 - ``current`` : the cset currently being bisected
191 191 """
192 192 state = load_state(repo)
193 193 if status in ('good', 'bad', 'skip', 'current'):
194 194 return map(repo.changelog.rev, state[status])
195 195 else:
196 196 # In the following sets, we do *not* call 'bisect()' with more
197 197 # than one level of recursion, because that can be very, very
198 198 # time consuming. Instead, we always develop the expression as
199 199 # much as possible.
200 200
201 201 # 'range' is all csets that make the bisection:
202 202 # - have a good ancestor and a bad descendant, or conversely
203 203 # that's because the bisection can go either way
204 204 range = '( bisect(bad)::bisect(good) | bisect(good)::bisect(bad) )'
205 205
206 206 _t = repo.revs('bisect(good)::bisect(bad)')
207 207 # The sets of topologically good or bad csets
208 208 if len(_t) == 0:
209 209 # Goods are topologically after bads
210 210 goods = 'bisect(good)::' # Pruned good csets
211 211 bads = '::bisect(bad)' # Pruned bad csets
212 212 else:
213 213 # Goods are topologically before bads
214 214 goods = '::bisect(good)' # Pruned good csets
215 215 bads = 'bisect(bad)::' # Pruned bad csets
216 216
217 217 # 'pruned' is all csets whose fate is already known: good, bad, skip
218 218 skips = 'bisect(skip)' # Pruned skipped csets
219 219 pruned = '( (%s) | (%s) | (%s) )' % (goods, bads, skips)
220 220
221 221 # 'untested' is all cset that are- in 'range', but not in 'pruned'
222 222 untested = '( (%s) - (%s) )' % (range, pruned)
223 223
224 224 # 'ignored' is all csets that were not used during the bisection
225 225 # due to DAG topology, but may however have had an impact.
226 226 # E.g., a branch merged between bads and goods, but whose branch-
227 227 # point is out-side of the range.
228 228 iba = '::bisect(bad) - ::bisect(good)' # Ignored bads' ancestors
229 229 iga = '::bisect(good) - ::bisect(bad)' # Ignored goods' ancestors
230 230 ignored = '( ( (%s) | (%s) ) - (%s) )' % (iba, iga, range)
231 231
232 232 if status == 'range':
233 233 return repo.revs(range)
234 234 elif status == 'pruned':
235 235 return repo.revs(pruned)
236 236 elif status == 'untested':
237 237 return repo.revs(untested)
238 238 elif status == 'ignored':
239 239 return repo.revs(ignored)
240 240 elif status == "goods":
241 241 return repo.revs(goods)
242 242 elif status == "bads":
243 243 return repo.revs(bads)
244 244 else:
245 245 raise error.ParseError(_('invalid bisect state'))
246 246
247 247 def label(repo, node):
248 248 rev = repo.changelog.rev(node)
249 249
250 250 # Try explicit sets
251 251 if rev in get(repo, 'good'):
252 252 # i18n: bisect changeset status
253 253 return _('good')
254 254 if rev in get(repo, 'bad'):
255 255 # i18n: bisect changeset status
256 256 return _('bad')
257 257 if rev in get(repo, 'skip'):
258 258 # i18n: bisect changeset status
259 259 return _('skipped')
260 260 if rev in get(repo, 'untested') or rev in get(repo, 'current'):
261 261 # i18n: bisect changeset status
262 262 return _('untested')
263 263 if rev in get(repo, 'ignored'):
264 264 # i18n: bisect changeset status
265 265 return _('ignored')
266 266
267 267 # Try implicit sets
268 268 if rev in get(repo, 'goods'):
269 269 # i18n: bisect changeset status
270 270 return _('good (implicit)')
271 271 if rev in get(repo, 'bads'):
272 272 # i18n: bisect changeset status
273 273 return _('bad (implicit)')
274 274
275 275 return None
276 276
277 277 def shortlabel(label):
278 278 if label:
279 279 return label[0].upper()
280 280
281 281 return None
282
283 def printresult(ui, repo, state, displayer, nodes, good):
284 if len(nodes) == 1:
285 # narrowed it down to a single revision
286 if good:
287 ui.write(_("The first good revision is:\n"))
288 else:
289 ui.write(_("The first bad revision is:\n"))
290 displayer.show(repo[nodes[0]])
291 extendnode = extendrange(repo, state, nodes, good)
292 if extendnode is not None:
293 ui.write(_('Not all ancestors of this changeset have been'
294 ' checked.\nUse bisect --extend to continue the '
295 'bisection from\nthe common ancestor, %s.\n')
296 % extendnode)
297 else:
298 # multiple possible revisions
299 if good:
300 ui.write(_("Due to skipped revisions, the first "
301 "good revision could be any of:\n"))
302 else:
303 ui.write(_("Due to skipped revisions, the first "
304 "bad revision could be any of:\n"))
305 for n in nodes:
306 displayer.show(repo[n])
307 displayer.close()
General Comments 0
You need to be logged in to leave comments. Login now