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