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