##// END OF EJS Templates
debug: add a debug::unbundle command that simulate the unbundle from a push...
marmoute -
r52293:e2dfa403 default
parent child Browse files
Show More
@@ -1,8100 +1,8104 b''
1 1 # commands.py - command processing for mercurial
2 2 #
3 3 # Copyright 2005-2007 Olivia Mackall <olivia@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
9 9 import os
10 10 import re
11 11 import sys
12 12
13 13 from .i18n import _
14 14 from .node import (
15 15 hex,
16 16 nullid,
17 17 nullrev,
18 18 short,
19 19 wdirrev,
20 20 )
21 21 from . import (
22 22 admin_commands as admin_commands_mod,
23 23 archival,
24 24 bookmarks,
25 25 bundle2,
26 26 bundlecaches,
27 27 changegroup,
28 28 cmdutil,
29 29 copies,
30 30 debugcommands as debugcommandsmod,
31 31 destutil,
32 32 diffutil,
33 33 discovery,
34 34 encoding,
35 35 error,
36 36 exchange,
37 37 extensions,
38 38 filemerge,
39 39 formatter,
40 40 graphmod,
41 41 grep as grepmod,
42 42 hbisect,
43 43 help,
44 44 hg,
45 45 logcmdutil,
46 46 merge as mergemod,
47 47 mergestate as mergestatemod,
48 48 narrowspec,
49 49 obsolete,
50 50 obsutil,
51 51 patch,
52 52 phases,
53 53 pycompat,
54 54 rcutil,
55 55 registrar,
56 56 requirements,
57 57 revsetlang,
58 58 rewriteutil,
59 59 scmutil,
60 60 server,
61 61 shelve as shelvemod,
62 62 state as statemod,
63 63 streamclone,
64 64 tags as tagsmod,
65 65 ui as uimod,
66 66 util,
67 67 verify as verifymod,
68 68 vfs as vfsmod,
69 69 wireprotoserver,
70 70 )
71 71 from .utils import (
72 72 dateutil,
73 73 procutil,
74 74 stringutil,
75 75 urlutil,
76 76 )
77 77
78 78 table = {}
79 79 table.update(debugcommandsmod.command._table)
80 80 table.update(admin_commands_mod.command._table)
81 81
82 82 command = registrar.command(table)
83 83 INTENT_READONLY = registrar.INTENT_READONLY
84 84
85 85 # common command options
86 86
87 87 globalopts = [
88 88 (
89 89 b'R',
90 90 b'repository',
91 91 b'',
92 92 _(b'repository root directory or name of overlay bundle file'),
93 93 _(b'REPO'),
94 94 ),
95 95 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
96 96 (
97 97 b'y',
98 98 b'noninteractive',
99 99 None,
100 100 _(
101 101 b'do not prompt, automatically pick the first choice for all prompts'
102 102 ),
103 103 ),
104 104 (b'q', b'quiet', None, _(b'suppress output')),
105 105 (b'v', b'verbose', None, _(b'enable additional output')),
106 106 (
107 107 b'',
108 108 b'color',
109 109 b'',
110 110 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
111 111 # and should not be translated
112 112 _(b"when to colorize (boolean, always, auto, never, or debug)"),
113 113 _(b'TYPE'),
114 114 ),
115 115 (
116 116 b'',
117 117 b'config',
118 118 [],
119 119 _(b'set/override config option (use \'section.name=value\')'),
120 120 _(b'CONFIG'),
121 121 ),
122 122 (b'', b'debug', None, _(b'enable debugging output')),
123 123 (b'', b'debugger', None, _(b'start debugger')),
124 124 (
125 125 b'',
126 126 b'encoding',
127 127 encoding.encoding,
128 128 _(b'set the charset encoding'),
129 129 _(b'ENCODE'),
130 130 ),
131 131 (
132 132 b'',
133 133 b'encodingmode',
134 134 encoding.encodingmode,
135 135 _(b'set the charset encoding mode'),
136 136 _(b'MODE'),
137 137 ),
138 138 (b'', b'traceback', None, _(b'always print a traceback on exception')),
139 139 (b'', b'time', None, _(b'time how long the command takes')),
140 140 (b'', b'profile', None, _(b'print command execution profile')),
141 141 (b'', b'version', None, _(b'output version information and exit')),
142 142 (b'h', b'help', None, _(b'display help and exit')),
143 143 (b'', b'hidden', False, _(b'consider hidden changesets')),
144 144 (
145 145 b'',
146 146 b'pager',
147 147 b'auto',
148 148 _(b"when to paginate (boolean, always, auto, or never)"),
149 149 _(b'TYPE'),
150 150 ),
151 151 ]
152 152
153 153 dryrunopts = cmdutil.dryrunopts
154 154 remoteopts = cmdutil.remoteopts
155 155 walkopts = cmdutil.walkopts
156 156 commitopts = cmdutil.commitopts
157 157 commitopts2 = cmdutil.commitopts2
158 158 commitopts3 = cmdutil.commitopts3
159 159 formatteropts = cmdutil.formatteropts
160 160 templateopts = cmdutil.templateopts
161 161 logopts = cmdutil.logopts
162 162 diffopts = cmdutil.diffopts
163 163 diffwsopts = cmdutil.diffwsopts
164 164 diffopts2 = cmdutil.diffopts2
165 165 mergetoolopts = cmdutil.mergetoolopts
166 166 similarityopts = cmdutil.similarityopts
167 167 subrepoopts = cmdutil.subrepoopts
168 168 debugrevlogopts = cmdutil.debugrevlogopts
169 169
170 170 # Commands start here, listed alphabetically
171 171
172 172
173 173 @command(
174 174 b'abort',
175 175 dryrunopts,
176 176 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
177 177 helpbasic=True,
178 178 )
179 179 def abort(ui, repo, **opts):
180 180 """abort an unfinished operation (EXPERIMENTAL)
181 181
182 182 Aborts a multistep operation like graft, histedit, rebase, merge,
183 183 and unshelve if they are in an unfinished state.
184 184
185 185 use --dry-run/-n to dry run the command.
186 186 """
187 187 dryrun = opts.get('dry_run')
188 188 abortstate = cmdutil.getunfinishedstate(repo)
189 189 if not abortstate:
190 190 raise error.StateError(_(b'no operation in progress'))
191 191 if not abortstate.abortfunc:
192 192 raise error.InputError(
193 193 (
194 194 _(b"%s in progress but does not support 'hg abort'")
195 195 % (abortstate._opname)
196 196 ),
197 197 hint=abortstate.hint(),
198 198 )
199 199 if dryrun:
200 200 ui.status(
201 201 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
202 202 )
203 203 return
204 204 return abortstate.abortfunc(ui, repo)
205 205
206 206
207 207 @command(
208 208 b'add',
209 209 walkopts + subrepoopts + dryrunopts,
210 210 _(b'[OPTION]... [FILE]...'),
211 211 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
212 212 helpbasic=True,
213 213 inferrepo=True,
214 214 )
215 215 def add(ui, repo, *pats, **opts):
216 216 """add the specified files on the next commit
217 217
218 218 Schedule files to be version controlled and added to the
219 219 repository.
220 220
221 221 The files will be added to the repository at the next commit. To
222 222 undo an add before that, see :hg:`forget`.
223 223
224 224 If no names are given, add all files to the repository (except
225 225 files matching ``.hgignore``).
226 226
227 227 .. container:: verbose
228 228
229 229 Examples:
230 230
231 231 - New (unknown) files are added
232 232 automatically by :hg:`add`::
233 233
234 234 $ ls
235 235 foo.c
236 236 $ hg status
237 237 ? foo.c
238 238 $ hg add
239 239 adding foo.c
240 240 $ hg status
241 241 A foo.c
242 242
243 243 - Specific files to be added can be specified::
244 244
245 245 $ ls
246 246 bar.c foo.c
247 247 $ hg status
248 248 ? bar.c
249 249 ? foo.c
250 250 $ hg add bar.c
251 251 $ hg status
252 252 A bar.c
253 253 ? foo.c
254 254
255 255 Returns 0 if all files are successfully added.
256 256 """
257 257
258 258 with repo.wlock(), repo.dirstate.changing_files(repo):
259 259 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
260 260 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
261 261 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
262 262 return rejected and 1 or 0
263 263
264 264
265 265 @command(
266 266 b'addremove',
267 267 similarityopts + subrepoopts + walkopts + dryrunopts,
268 268 _(b'[OPTION]... [FILE]...'),
269 269 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
270 270 inferrepo=True,
271 271 )
272 272 def addremove(ui, repo, *pats, **opts):
273 273 """add all new files, delete all missing files
274 274
275 275 Add all new files and remove all missing files from the
276 276 repository.
277 277
278 278 Unless names are given, new files are ignored if they match any of
279 279 the patterns in ``.hgignore``. As with add, these changes take
280 280 effect at the next commit.
281 281
282 282 Use the -s/--similarity option to detect renamed files. This
283 283 option takes a percentage between 0 (disabled) and 100 (files must
284 284 be identical) as its parameter. With a parameter greater than 0,
285 285 this compares every removed file with every added file and records
286 286 those similar enough as renames. Detecting renamed files this way
287 287 can be expensive. After using this option, :hg:`status -C` can be
288 288 used to check which files were identified as moved or renamed. If
289 289 not specified, -s/--similarity defaults to 100 and only renames of
290 290 identical files are detected.
291 291
292 292 .. container:: verbose
293 293
294 294 Examples:
295 295
296 296 - A number of files (bar.c and foo.c) are new,
297 297 while foobar.c has been removed (without using :hg:`remove`)
298 298 from the repository::
299 299
300 300 $ ls
301 301 bar.c foo.c
302 302 $ hg status
303 303 ! foobar.c
304 304 ? bar.c
305 305 ? foo.c
306 306 $ hg addremove
307 307 adding bar.c
308 308 adding foo.c
309 309 removing foobar.c
310 310 $ hg status
311 311 A bar.c
312 312 A foo.c
313 313 R foobar.c
314 314
315 315 - A file foobar.c was moved to foo.c without using :hg:`rename`.
316 316 Afterwards, it was edited slightly::
317 317
318 318 $ ls
319 319 foo.c
320 320 $ hg status
321 321 ! foobar.c
322 322 ? foo.c
323 323 $ hg addremove --similarity 90
324 324 removing foobar.c
325 325 adding foo.c
326 326 recording removal of foobar.c as rename to foo.c (94% similar)
327 327 $ hg status -C
328 328 A foo.c
329 329 foobar.c
330 330 R foobar.c
331 331
332 332 Returns 0 if all files are successfully added.
333 333 """
334 334 opts = pycompat.byteskwargs(opts)
335 335 if not opts.get(b'similarity'):
336 336 opts[b'similarity'] = b'100'
337 337 with repo.wlock(), repo.dirstate.changing_files(repo):
338 338 matcher = scmutil.match(repo[None], pats, opts)
339 339 relative = scmutil.anypats(pats, opts)
340 340 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
341 341 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
342 342
343 343
344 344 @command(
345 345 b'annotate|blame',
346 346 [
347 347 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
348 348 (
349 349 b'',
350 350 b'follow',
351 351 None,
352 352 _(b'follow copies/renames and list the filename (DEPRECATED)'),
353 353 ),
354 354 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
355 355 (b'a', b'text', None, _(b'treat all files as text')),
356 356 (b'u', b'user', None, _(b'list the author (long with -v)')),
357 357 (b'f', b'file', None, _(b'list the filename')),
358 358 (b'd', b'date', None, _(b'list the date (short with -q)')),
359 359 (b'n', b'number', None, _(b'list the revision number (default)')),
360 360 (b'c', b'changeset', None, _(b'list the changeset')),
361 361 (
362 362 b'l',
363 363 b'line-number',
364 364 None,
365 365 _(b'show line number at the first appearance'),
366 366 ),
367 367 (
368 368 b'',
369 369 b'skip',
370 370 [],
371 371 _(b'revset to not display (EXPERIMENTAL)'),
372 372 _(b'REV'),
373 373 ),
374 374 (
375 375 b'L',
376 376 b'line-range',
377 377 [],
378 378 _(b'follow line range of specified file (EXPERIMENTAL)'),
379 379 _(b'FILE,RANGE'),
380 380 ),
381 381 ]
382 382 + diffwsopts
383 383 + walkopts
384 384 + formatteropts,
385 385 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
386 386 helpcategory=command.CATEGORY_FILE_CONTENTS,
387 387 helpbasic=True,
388 388 inferrepo=True,
389 389 )
390 390 def annotate(ui, repo, *pats, **opts):
391 391 """show changeset information by line for each file
392 392
393 393 List changes in files, showing the revision id responsible for
394 394 each line.
395 395
396 396 This command is useful for discovering when a change was made and
397 397 by whom.
398 398
399 399 If you include --file, --user, or --date, the revision number is
400 400 suppressed unless you also include --number.
401 401
402 402 Without the -a/--text option, annotate will avoid processing files
403 403 it detects as binary. With -a, annotate will annotate the file
404 404 anyway, although the results will probably be neither useful
405 405 nor desirable.
406 406
407 407 .. container:: verbose
408 408
409 409 Use -L/--line-range FILE,M:N options to filter the output to the lines
410 410 from M to N in FILE. This option is incompatible with --no-follow and
411 411 cannot be combined with file pattern arguments. When combined with --rev
412 412 the line ranges refer to the state of the file at the requested revision.
413 413
414 414 .. container:: verbose
415 415
416 416 Template:
417 417
418 418 The following keywords are supported in addition to the common template
419 419 keywords and functions. See also :hg:`help templates`.
420 420
421 421 :lines: List of lines with annotation data.
422 422 :path: String. Repository-absolute path of the specified file.
423 423
424 424 And each entry of ``{lines}`` provides the following sub-keywords in
425 425 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
426 426
427 427 :line: String. Line content.
428 428 :lineno: Integer. Line number at that revision.
429 429 :path: String. Repository-absolute path of the file at that revision.
430 430
431 431 See :hg:`help templates.operators` for the list expansion syntax.
432 432
433 433 Returns 0 on success.
434 434 """
435 435 opts = pycompat.byteskwargs(opts)
436 436
437 437 linerange = opts.get(b'line_range')
438 438
439 439 if linerange and opts.get(b'no_follow'):
440 440 raise error.InputError(
441 441 _(b'--line-range is incompatible with --no-follow')
442 442 )
443 443
444 444 if pats and linerange:
445 445 raise error.InputError(
446 446 _(b'cannot combine filename or pattern and --line-range')
447 447 )
448 448
449 449 if not pats and not linerange:
450 450 raise error.InputError(
451 451 _(b'at least one filename or pattern is required')
452 452 )
453 453
454 454 if opts.get(b'follow'):
455 455 # --follow is deprecated and now just an alias for -f/--file
456 456 # to mimic the behavior of Mercurial before version 1.5
457 457 opts[b'file'] = True
458 458
459 459 if (
460 460 not opts.get(b'user')
461 461 and not opts.get(b'changeset')
462 462 and not opts.get(b'date')
463 463 and not opts.get(b'file')
464 464 ):
465 465 opts[b'number'] = True
466 466
467 467 linenumber = opts.get(b'line_number') is not None
468 468 if (
469 469 linenumber
470 470 and (not opts.get(b'changeset'))
471 471 and (not opts.get(b'number'))
472 472 ):
473 473 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
474 474
475 475 rev = opts.get(b'rev')
476 476 if rev:
477 477 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
478 478 ctx = logcmdutil.revsingle(repo, rev)
479 479
480 480 if not pats:
481 481 pats = [
482 482 fname
483 483 for fname, _ranges in logcmdutil._parselinerangeopt(repo, opts)
484 484 ]
485 485
486 486 ui.pager(b'annotate')
487 487 rootfm = ui.formatter(b'annotate', opts)
488 488 if ui.debugflag:
489 489 shorthex = pycompat.identity
490 490 else:
491 491
492 492 def shorthex(h):
493 493 return h[:12]
494 494
495 495 if ui.quiet:
496 496 datefunc = dateutil.shortdate
497 497 else:
498 498 datefunc = dateutil.datestr
499 499 if ctx.rev() is None:
500 500 if opts.get(b'changeset'):
501 501 # omit "+" suffix which is appended to node hex
502 502 def formatrev(rev):
503 503 if rev == wdirrev:
504 504 return b'%d' % ctx.p1().rev()
505 505 else:
506 506 return b'%d' % rev
507 507
508 508 else:
509 509
510 510 def formatrev(rev):
511 511 if rev == wdirrev:
512 512 return b'%d+' % ctx.p1().rev()
513 513 else:
514 514 return b'%d ' % rev
515 515
516 516 def formathex(h):
517 517 if h == repo.nodeconstants.wdirhex:
518 518 return b'%s+' % shorthex(hex(ctx.p1().node()))
519 519 else:
520 520 return b'%s ' % shorthex(h)
521 521
522 522 else:
523 523 formatrev = b'%d'.__mod__
524 524 formathex = shorthex
525 525
526 526 opmap = [
527 527 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
528 528 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
529 529 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
530 530 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
531 531 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
532 532 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
533 533 ]
534 534 opnamemap = {
535 535 b'rev': b'number',
536 536 b'node': b'changeset',
537 537 b'path': b'file',
538 538 b'lineno': b'line_number',
539 539 }
540 540
541 541 if rootfm.isplain():
542 542
543 543 def makefunc(get, fmt):
544 544 return lambda x: fmt(get(x))
545 545
546 546 else:
547 547
548 548 def makefunc(get, fmt):
549 549 return get
550 550
551 551 datahint = rootfm.datahint()
552 552 funcmap = [
553 553 (makefunc(get, fmt), sep)
554 554 for fn, sep, get, fmt in opmap
555 555 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
556 556 ]
557 557 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
558 558 fields = b' '.join(
559 559 fn
560 560 for fn, sep, get, fmt in opmap
561 561 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
562 562 )
563 563
564 564 def bad(x, y):
565 565 raise error.InputError(b"%s: %s" % (x, y))
566 566
567 567 m = scmutil.match(ctx, pats, opts, badfn=bad)
568 568
569 569 follow = not opts.get(b'no_follow')
570 570 diffopts = patch.difffeatureopts(
571 571 ui, opts, section=b'annotate', whitespace=True
572 572 )
573 573 skiprevs = opts.get(b'skip')
574 574 if skiprevs:
575 575 skiprevs = logcmdutil.revrange(repo, skiprevs)
576 576
577 577 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
578 578 for abs in ctx.walk(m):
579 579 fctx = ctx[abs]
580 580 rootfm.startitem()
581 581 rootfm.data(path=abs)
582 582 if not opts.get(b'text') and fctx.isbinary():
583 583 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
584 584 continue
585 585
586 586 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
587 587 lines = fctx.annotate(
588 588 follow=follow, skiprevs=skiprevs, diffopts=diffopts
589 589 )
590 590 if linerange:
591 591 _fname, (line_start, line_end) = list(
592 592 logcmdutil._parselinerangeopt(repo, opts)
593 593 )[0]
594 594 lines = [
595 595 line
596 596 for no, line in enumerate(lines)
597 597 if line_start <= no < line_end
598 598 ]
599 599
600 600 if not lines:
601 601 fm.end()
602 602 continue
603 603 formats = []
604 604 pieces = []
605 605
606 606 for f, sep in funcmap:
607 607 l = [f(n) for n in lines]
608 608 if fm.isplain():
609 609 sizes = [encoding.colwidth(x) for x in l]
610 610 ml = max(sizes)
611 611 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
612 612 else:
613 613 formats.append([b'%s'] * len(l))
614 614 pieces.append(l)
615 615
616 616 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
617 617 fm.startitem()
618 618 fm.context(fctx=n.fctx)
619 619 fm.write(fields, b"".join(f), *p)
620 620 if n.skip:
621 621 fmt = b"* %s"
622 622 else:
623 623 fmt = b": %s"
624 624 fm.write(b'line', fmt, n.text)
625 625
626 626 if not lines[-1].text.endswith(b'\n'):
627 627 fm.plain(b'\n')
628 628 fm.end()
629 629
630 630 rootfm.end()
631 631
632 632
633 633 @command(
634 634 b'archive',
635 635 [
636 636 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
637 637 (
638 638 b'p',
639 639 b'prefix',
640 640 b'',
641 641 _(b'directory prefix for files in archive'),
642 642 _(b'PREFIX'),
643 643 ),
644 644 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
645 645 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
646 646 ]
647 647 + subrepoopts
648 648 + walkopts,
649 649 _(b'[OPTION]... DEST'),
650 650 helpcategory=command.CATEGORY_IMPORT_EXPORT,
651 651 )
652 652 def archive(ui, repo, dest, **opts):
653 653 """create an unversioned archive of a repository revision
654 654
655 655 By default, the revision used is the parent of the working
656 656 directory; use -r/--rev to specify a different revision.
657 657
658 658 The archive type is automatically detected based on file
659 659 extension (to override, use -t/--type).
660 660
661 661 .. container:: verbose
662 662
663 663 Examples:
664 664
665 665 - create a zip file containing the 1.0 release::
666 666
667 667 hg archive -r 1.0 project-1.0.zip
668 668
669 669 - create a tarball excluding .hg files::
670 670
671 671 hg archive project.tar.gz -X ".hg*"
672 672
673 673 Valid types are:
674 674
675 675 :``files``: a directory full of files (default)
676 676 :``tar``: tar archive, uncompressed
677 677 :``tbz2``: tar archive, compressed using bzip2
678 678 :``tgz``: tar archive, compressed using gzip
679 679 :``txz``: tar archive, compressed using lzma (only in Python 3)
680 680 :``uzip``: zip archive, uncompressed
681 681 :``zip``: zip archive, compressed using deflate
682 682
683 683 The exact name of the destination archive or directory is given
684 684 using a format string; see :hg:`help export` for details.
685 685
686 686 Each member added to an archive file has a directory prefix
687 687 prepended. Use -p/--prefix to specify a format string for the
688 688 prefix. The default is the basename of the archive, with suffixes
689 689 removed.
690 690
691 691 Returns 0 on success.
692 692 """
693 693
694 694 rev = opts.get('rev')
695 695 if rev:
696 696 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
697 697 ctx = logcmdutil.revsingle(repo, rev)
698 698 if not ctx:
699 699 raise error.InputError(
700 700 _(b'no working directory: please specify a revision')
701 701 )
702 702 node = ctx.node()
703 703 dest = cmdutil.makefilename(ctx, dest)
704 704 if os.path.realpath(dest) == repo.root:
705 705 raise error.InputError(_(b'repository root cannot be destination'))
706 706
707 707 kind = opts.get('type') or archival.guesskind(dest) or b'files'
708 708 prefix = opts.get('prefix')
709 709
710 710 if dest == b'-':
711 711 if kind == b'files':
712 712 raise error.InputError(_(b'cannot archive plain files to stdout'))
713 713 dest = cmdutil.makefileobj(ctx, dest)
714 714 if not prefix:
715 715 prefix = os.path.basename(repo.root) + b'-%h'
716 716
717 717 prefix = cmdutil.makefilename(ctx, prefix)
718 718 match = scmutil.match(ctx, [], pycompat.byteskwargs(opts))
719 719 archival.archive(
720 720 repo,
721 721 dest,
722 722 node,
723 723 kind,
724 724 not opts.get('no_decode'),
725 725 match,
726 726 prefix,
727 727 subrepos=opts.get('subrepos'),
728 728 )
729 729
730 730
731 731 @command(
732 732 b'backout',
733 733 [
734 734 (
735 735 b'',
736 736 b'merge',
737 737 None,
738 738 _(b'merge with old dirstate parent after backout'),
739 739 ),
740 740 (
741 741 b'',
742 742 b'commit',
743 743 None,
744 744 _(b'commit if no conflicts were encountered (DEPRECATED)'),
745 745 ),
746 746 (b'', b'no-commit', None, _(b'do not commit')),
747 747 (
748 748 b'',
749 749 b'parent',
750 750 b'',
751 751 _(b'parent to choose when backing out merge (DEPRECATED)'),
752 752 _(b'REV'),
753 753 ),
754 754 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
755 755 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
756 756 ]
757 757 + mergetoolopts
758 758 + walkopts
759 759 + commitopts
760 760 + commitopts2,
761 761 _(b'[OPTION]... [-r] REV'),
762 762 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
763 763 )
764 764 def backout(ui, repo, node=None, rev=None, **opts):
765 765 """reverse effect of earlier changeset
766 766
767 767 Prepare a new changeset with the effect of REV undone in the
768 768 current working directory. If no conflicts were encountered,
769 769 it will be committed immediately.
770 770
771 771 If REV is the parent of the working directory, then this new changeset
772 772 is committed automatically (unless --no-commit is specified).
773 773
774 774 .. note::
775 775
776 776 :hg:`backout` cannot be used to fix either an unwanted or
777 777 incorrect merge.
778 778
779 779 .. container:: verbose
780 780
781 781 Examples:
782 782
783 783 - Reverse the effect of the parent of the working directory.
784 784 This backout will be committed immediately::
785 785
786 786 hg backout -r .
787 787
788 788 - Reverse the effect of previous bad revision 23::
789 789
790 790 hg backout -r 23
791 791
792 792 - Reverse the effect of previous bad revision 23 and
793 793 leave changes uncommitted::
794 794
795 795 hg backout -r 23 --no-commit
796 796 hg commit -m "Backout revision 23"
797 797
798 798 By default, the pending changeset will have one parent,
799 799 maintaining a linear history. With --merge, the pending
800 800 changeset will instead have two parents: the old parent of the
801 801 working directory and a new child of REV that simply undoes REV.
802 802
803 803 Before version 1.7, the behavior without --merge was equivalent
804 804 to specifying --merge followed by :hg:`update --clean .` to
805 805 cancel the merge and leave the child of REV as a head to be
806 806 merged separately.
807 807
808 808 See :hg:`help dates` for a list of formats valid for -d/--date.
809 809
810 810 See :hg:`help revert` for a way to restore files to the state
811 811 of another revision.
812 812
813 813 Returns 0 on success, 1 if nothing to backout or there are unresolved
814 814 files.
815 815 """
816 816 with repo.wlock(), repo.lock():
817 817 return _dobackout(ui, repo, node, rev, **opts)
818 818
819 819
820 820 def _dobackout(ui, repo, node=None, rev=None, **opts):
821 821 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
822 822
823 823 if rev and node:
824 824 raise error.InputError(_(b"please specify just one revision"))
825 825
826 826 if not rev:
827 827 rev = node
828 828
829 829 if not rev:
830 830 raise error.InputError(_(b"please specify a revision to backout"))
831 831
832 832 date = opts.get('date')
833 833 if date:
834 834 opts['date'] = dateutil.parsedate(date)
835 835
836 836 cmdutil.checkunfinished(repo)
837 837 cmdutil.bailifchanged(repo)
838 838 ctx = logcmdutil.revsingle(repo, rev)
839 839 node = ctx.node()
840 840
841 841 op1, op2 = repo.dirstate.parents()
842 842 if not repo.changelog.isancestor(node, op1):
843 843 raise error.InputError(
844 844 _(b'cannot backout change that is not an ancestor')
845 845 )
846 846
847 847 p1, p2 = repo.changelog.parents(node)
848 848 if p1 == repo.nullid:
849 849 raise error.InputError(_(b'cannot backout a change with no parents'))
850 850 if p2 != repo.nullid:
851 851 if not opts.get('parent'):
852 852 raise error.InputError(_(b'cannot backout a merge changeset'))
853 853 p = repo.lookup(opts['parent'])
854 854 if p not in (p1, p2):
855 855 raise error.InputError(
856 856 _(b'%s is not a parent of %s') % (short(p), short(node))
857 857 )
858 858 parent = p
859 859 else:
860 860 if opts.get('parent'):
861 861 raise error.InputError(
862 862 _(b'cannot use --parent on non-merge changeset')
863 863 )
864 864 parent = p1
865 865
866 866 # the backout should appear on the same branch
867 867 branch = repo.dirstate.branch()
868 868 bheads = repo.branchheads(branch)
869 869 rctx = scmutil.revsingle(repo, hex(parent))
870 870 if not opts.get('merge') and op1 != node:
871 871 with repo.transaction(b"backout"):
872 872 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
873 873 with ui.configoverride(overrides, b'backout'):
874 874 stats = mergemod.back_out(ctx, parent=repo[parent])
875 875 repo.setparents(op1, op2)
876 876 hg._showstats(repo, stats)
877 877 if stats.unresolvedcount:
878 878 repo.ui.status(
879 879 _(b"use 'hg resolve' to retry unresolved file merges\n")
880 880 )
881 881 return 1
882 882 else:
883 883 hg.clean(repo, node, show_stats=False)
884 884 repo.dirstate.setbranch(branch, repo.currenttransaction())
885 885 cmdutil.revert(ui, repo, rctx)
886 886
887 887 if opts.get('no_commit'):
888 888 msg = _(b"changeset %s backed out, don't forget to commit.\n")
889 889 ui.status(msg % short(node))
890 890 return 0
891 891
892 892 def commitfunc(ui, repo, message, match, opts):
893 893 editform = b'backout'
894 894 e = cmdutil.getcommiteditor(
895 895 editform=editform, **pycompat.strkwargs(opts)
896 896 )
897 897 if not message:
898 898 # we don't translate commit messages
899 899 message = b"Backed out changeset %s" % short(node)
900 900 e = cmdutil.getcommiteditor(edit=True, editform=editform)
901 901 return repo.commit(
902 902 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
903 903 )
904 904
905 905 # save to detect changes
906 906 tip = repo.changelog.tip()
907 907
908 908 newnode = cmdutil.commit(
909 909 ui, repo, commitfunc, [], pycompat.byteskwargs(opts)
910 910 )
911 911 if not newnode:
912 912 ui.status(_(b"nothing changed\n"))
913 913 return 1
914 914 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
915 915
916 916 def nice(node):
917 917 return b'%d:%s' % (repo.changelog.rev(node), short(node))
918 918
919 919 ui.status(
920 920 _(b'changeset %s backs out changeset %s\n')
921 921 % (nice(newnode), nice(node))
922 922 )
923 923 if opts.get('merge') and op1 != node:
924 924 hg.clean(repo, op1, show_stats=False)
925 925 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
926 926 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
927 927 with ui.configoverride(overrides, b'backout'):
928 928 return hg.merge(repo[b'tip'])
929 929 return 0
930 930
931 931
932 932 @command(
933 933 b'bisect',
934 934 [
935 935 (b'r', b'reset', False, _(b'reset bisect state')),
936 936 (b'g', b'good', False, _(b'mark changeset good')),
937 937 (b'b', b'bad', False, _(b'mark changeset bad')),
938 938 (b's', b'skip', False, _(b'skip testing changeset')),
939 939 (b'e', b'extend', False, _(b'extend the bisect range')),
940 940 (
941 941 b'c',
942 942 b'command',
943 943 b'',
944 944 _(b'use command to check changeset state'),
945 945 _(b'CMD'),
946 946 ),
947 947 (b'U', b'noupdate', False, _(b'do not update to target')),
948 948 ],
949 949 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
950 950 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
951 951 )
952 952 def bisect(
953 953 ui,
954 954 repo,
955 955 positional_1=None,
956 956 positional_2=None,
957 957 command=None,
958 958 reset=None,
959 959 good=None,
960 960 bad=None,
961 961 skip=None,
962 962 extend=None,
963 963 noupdate=None,
964 964 ):
965 965 """subdivision search of changesets
966 966
967 967 This command helps to find changesets which introduce problems. To
968 968 use, mark the earliest changeset you know exhibits the problem as
969 969 bad, then mark the latest changeset which is free from the problem
970 970 as good. Bisect will update your working directory to a revision
971 971 for testing (unless the -U/--noupdate option is specified). Once
972 972 you have performed tests, mark the working directory as good or
973 973 bad, and bisect will either update to another candidate changeset
974 974 or announce that it has found the bad revision.
975 975
976 976 As a shortcut, you can also use the revision argument to mark a
977 977 revision as good or bad without checking it out first.
978 978
979 979 If you supply a command, it will be used for automatic bisection.
980 980 The environment variable HG_NODE will contain the ID of the
981 981 changeset being tested. The exit status of the command will be
982 982 used to mark revisions as good or bad: status 0 means good, 125
983 983 means to skip the revision, 127 (command not found) will abort the
984 984 bisection, and any other non-zero exit status means the revision
985 985 is bad.
986 986
987 987 .. container:: verbose
988 988
989 989 Some examples:
990 990
991 991 - start a bisection with known bad revision 34, and good revision 12::
992 992
993 993 hg bisect --bad 34
994 994 hg bisect --good 12
995 995
996 996 - advance the current bisection by marking current revision as good or
997 997 bad::
998 998
999 999 hg bisect --good
1000 1000 hg bisect --bad
1001 1001
1002 1002 - mark the current revision, or a known revision, to be skipped (e.g. if
1003 1003 that revision is not usable because of another issue)::
1004 1004
1005 1005 hg bisect --skip
1006 1006 hg bisect --skip 23
1007 1007
1008 1008 - skip all revisions that do not touch directories ``foo`` or ``bar``::
1009 1009
1010 1010 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
1011 1011
1012 1012 - forget the current bisection::
1013 1013
1014 1014 hg bisect --reset
1015 1015
1016 1016 - use 'make && make tests' to automatically find the first broken
1017 1017 revision::
1018 1018
1019 1019 hg bisect --reset
1020 1020 hg bisect --bad 34
1021 1021 hg bisect --good 12
1022 1022 hg bisect --command "make && make tests"
1023 1023
1024 1024 - see all changesets whose states are already known in the current
1025 1025 bisection::
1026 1026
1027 1027 hg log -r "bisect(pruned)"
1028 1028
1029 1029 - see the changeset currently being bisected (especially useful
1030 1030 if running with -U/--noupdate)::
1031 1031
1032 1032 hg log -r "bisect(current)"
1033 1033
1034 1034 - see all changesets that took part in the current bisection::
1035 1035
1036 1036 hg log -r "bisect(range)"
1037 1037
1038 1038 - you can even get a nice graph::
1039 1039
1040 1040 hg log --graph -r "bisect(range)"
1041 1041
1042 1042 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
1043 1043
1044 1044 Returns 0 on success.
1045 1045 """
1046 1046 rev = []
1047 1047 # backward compatibility
1048 1048 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1049 1049 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1050 1050 cmd = positional_1
1051 1051 rev.append(positional_2)
1052 1052 if cmd == b"good":
1053 1053 good = True
1054 1054 elif cmd == b"bad":
1055 1055 bad = True
1056 1056 else:
1057 1057 reset = True
1058 1058 elif positional_2:
1059 1059 raise error.InputError(_(b'incompatible arguments'))
1060 1060 elif positional_1 is not None:
1061 1061 rev.append(positional_1)
1062 1062
1063 1063 incompatibles = {
1064 1064 b'--bad': bad,
1065 1065 b'--command': bool(command),
1066 1066 b'--extend': extend,
1067 1067 b'--good': good,
1068 1068 b'--reset': reset,
1069 1069 b'--skip': skip,
1070 1070 }
1071 1071
1072 1072 enabled = [x for x in incompatibles if incompatibles[x]]
1073 1073
1074 1074 if len(enabled) > 1:
1075 1075 raise error.InputError(
1076 1076 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1077 1077 )
1078 1078
1079 1079 if reset:
1080 1080 hbisect.resetstate(repo)
1081 1081 return
1082 1082
1083 1083 state = hbisect.load_state(repo)
1084 1084
1085 1085 if rev:
1086 1086 revs = logcmdutil.revrange(repo, rev)
1087 1087 goodnodes = state[b'good']
1088 1088 badnodes = state[b'bad']
1089 1089 if goodnodes and badnodes:
1090 1090 candidates = repo.revs(b'(%ln)::(%ln)', goodnodes, badnodes)
1091 1091 candidates += repo.revs(b'(%ln)::(%ln)', badnodes, goodnodes)
1092 1092 revs = candidates & revs
1093 1093 nodes = [repo.changelog.node(i) for i in revs]
1094 1094 else:
1095 1095 nodes = [repo.lookup(b'.')]
1096 1096
1097 1097 # update state
1098 1098 if good or bad or skip:
1099 1099 if good:
1100 1100 state[b'good'] += nodes
1101 1101 elif bad:
1102 1102 state[b'bad'] += nodes
1103 1103 elif skip:
1104 1104 state[b'skip'] += nodes
1105 1105 hbisect.save_state(repo, state)
1106 1106 if not (state[b'good'] and state[b'bad']):
1107 1107 return
1108 1108
1109 1109 def mayupdate(repo, node, show_stats=True):
1110 1110 """common used update sequence"""
1111 1111 if noupdate:
1112 1112 return
1113 1113 cmdutil.checkunfinished(repo)
1114 1114 cmdutil.bailifchanged(repo)
1115 1115 return hg.clean(repo, node, show_stats=show_stats)
1116 1116
1117 1117 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1118 1118
1119 1119 if command:
1120 1120 changesets = 1
1121 1121 if noupdate:
1122 1122 try:
1123 1123 node = state[b'current'][0]
1124 1124 except LookupError:
1125 1125 raise error.StateError(
1126 1126 _(
1127 1127 b'current bisect revision is unknown - '
1128 1128 b'start a new bisect to fix'
1129 1129 )
1130 1130 )
1131 1131 else:
1132 1132 node, p2 = repo.dirstate.parents()
1133 1133 if p2 != repo.nullid:
1134 1134 raise error.StateError(_(b'current bisect revision is a merge'))
1135 1135 if rev:
1136 1136 if not nodes:
1137 1137 raise error.InputError(_(b'empty revision set'))
1138 1138 node = repo[nodes[-1]].node()
1139 1139 with hbisect.restore_state(repo, state, node):
1140 1140 while changesets:
1141 1141 # update state
1142 1142 state[b'current'] = [node]
1143 1143 hbisect.save_state(repo, state)
1144 1144 status = ui.system(
1145 1145 command,
1146 1146 environ={b'HG_NODE': hex(node)},
1147 1147 blockedtag=b'bisect_check',
1148 1148 )
1149 1149 if status == 125:
1150 1150 transition = b"skip"
1151 1151 elif status == 0:
1152 1152 transition = b"good"
1153 1153 # status < 0 means process was killed
1154 1154 elif status == 127:
1155 1155 raise error.Abort(_(b"failed to execute %s") % command)
1156 1156 elif status < 0:
1157 1157 raise error.Abort(_(b"%s killed") % command)
1158 1158 else:
1159 1159 transition = b"bad"
1160 1160 state[transition].append(node)
1161 1161 ctx = repo[node]
1162 1162 summary = cmdutil.format_changeset_summary(ui, ctx, b'bisect')
1163 1163 ui.status(_(b'changeset %s: %s\n') % (summary, transition))
1164 1164 hbisect.checkstate(state)
1165 1165 # bisect
1166 1166 nodes, changesets, bgood = hbisect.bisect(repo, state)
1167 1167 # update to next check
1168 1168 node = nodes[0]
1169 1169 mayupdate(repo, node, show_stats=False)
1170 1170 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1171 1171 return
1172 1172
1173 1173 hbisect.checkstate(state)
1174 1174
1175 1175 # actually bisect
1176 1176 nodes, changesets, good = hbisect.bisect(repo, state)
1177 1177 if extend:
1178 1178 if not changesets:
1179 1179 extendctx = hbisect.extendrange(repo, state, nodes, good)
1180 1180 if extendctx is not None:
1181 1181 ui.write(
1182 1182 _(b"Extending search to changeset %s\n")
1183 1183 % cmdutil.format_changeset_summary(ui, extendctx, b'bisect')
1184 1184 )
1185 1185 state[b'current'] = [extendctx.node()]
1186 1186 hbisect.save_state(repo, state)
1187 1187 return mayupdate(repo, extendctx.node())
1188 1188 raise error.StateError(_(b"nothing to extend"))
1189 1189
1190 1190 if changesets == 0:
1191 1191 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1192 1192 else:
1193 1193 assert len(nodes) == 1 # only a single node can be tested next
1194 1194 node = nodes[0]
1195 1195 # compute the approximate number of remaining tests
1196 1196 tests, size = 0, 2
1197 1197 while size <= changesets:
1198 1198 tests, size = tests + 1, size * 2
1199 1199 rev = repo.changelog.rev(node)
1200 1200 summary = cmdutil.format_changeset_summary(ui, repo[rev], b'bisect')
1201 1201 ui.write(
1202 1202 _(
1203 1203 b"Testing changeset %s "
1204 1204 b"(%d changesets remaining, ~%d tests)\n"
1205 1205 )
1206 1206 % (summary, changesets, tests)
1207 1207 )
1208 1208 state[b'current'] = [node]
1209 1209 hbisect.save_state(repo, state)
1210 1210 return mayupdate(repo, node)
1211 1211
1212 1212
1213 1213 @command(
1214 1214 b'bookmarks|bookmark',
1215 1215 [
1216 1216 (b'f', b'force', False, _(b'force')),
1217 1217 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1218 1218 (b'd', b'delete', False, _(b'delete a given bookmark')),
1219 1219 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1220 1220 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1221 1221 (b'l', b'list', False, _(b'list existing bookmarks')),
1222 1222 ]
1223 1223 + formatteropts,
1224 1224 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1225 1225 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1226 1226 )
1227 1227 def bookmark(ui, repo, *names, **opts):
1228 1228 """create a new bookmark or list existing bookmarks
1229 1229
1230 1230 Bookmarks are labels on changesets to help track lines of development.
1231 1231 Bookmarks are unversioned and can be moved, renamed and deleted.
1232 1232 Deleting or moving a bookmark has no effect on the associated changesets.
1233 1233
1234 1234 Creating or updating to a bookmark causes it to be marked as 'active'.
1235 1235 The active bookmark is indicated with a '*'.
1236 1236 When a commit is made, the active bookmark will advance to the new commit.
1237 1237 A plain :hg:`update` will also advance an active bookmark, if possible.
1238 1238 Updating away from a bookmark will cause it to be deactivated.
1239 1239
1240 1240 Bookmarks can be pushed and pulled between repositories (see
1241 1241 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1242 1242 diverged, a new 'divergent bookmark' of the form 'name@path' will
1243 1243 be created. Using :hg:`merge` will resolve the divergence.
1244 1244
1245 1245 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1246 1246 the active bookmark's name.
1247 1247
1248 1248 A bookmark named '@' has the special property that :hg:`clone` will
1249 1249 check it out by default if it exists.
1250 1250
1251 1251 .. container:: verbose
1252 1252
1253 1253 Template:
1254 1254
1255 1255 The following keywords are supported in addition to the common template
1256 1256 keywords and functions such as ``{bookmark}``. See also
1257 1257 :hg:`help templates`.
1258 1258
1259 1259 :active: Boolean. True if the bookmark is active.
1260 1260
1261 1261 Examples:
1262 1262
1263 1263 - create an active bookmark for a new line of development::
1264 1264
1265 1265 hg book new-feature
1266 1266
1267 1267 - create an inactive bookmark as a place marker::
1268 1268
1269 1269 hg book -i reviewed
1270 1270
1271 1271 - create an inactive bookmark on another changeset::
1272 1272
1273 1273 hg book -r .^ tested
1274 1274
1275 1275 - rename bookmark turkey to dinner::
1276 1276
1277 1277 hg book -m turkey dinner
1278 1278
1279 1279 - move the '@' bookmark from another branch::
1280 1280
1281 1281 hg book -f @
1282 1282
1283 1283 - print only the active bookmark name::
1284 1284
1285 1285 hg book -ql .
1286 1286 """
1287 1287 force = opts.get('force')
1288 1288 rev = opts.get('rev')
1289 1289 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
1290 1290
1291 1291 action = cmdutil.check_at_most_one_arg(opts, 'delete', 'rename', 'list')
1292 1292 if action:
1293 1293 cmdutil.check_incompatible_arguments(opts, action, ['rev'])
1294 1294 elif names or rev:
1295 1295 action = 'add'
1296 1296 elif inactive:
1297 1297 action = 'inactive' # meaning deactivate
1298 1298 else:
1299 1299 action = 'list'
1300 1300
1301 1301 cmdutil.check_incompatible_arguments(opts, 'inactive', ['delete', 'list'])
1302 1302 if not names and action in {'add', 'delete'}:
1303 1303 raise error.InputError(_(b"bookmark name required"))
1304 1304
1305 1305 if action in {'add', 'delete', 'rename', 'inactive'}:
1306 1306 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1307 1307 if action == 'delete':
1308 1308 names = pycompat.maplist(repo._bookmarks.expandname, names)
1309 1309 bookmarks.delete(repo, tr, names)
1310 1310 elif action == 'rename':
1311 1311 if not names:
1312 1312 raise error.InputError(_(b"new bookmark name required"))
1313 1313 elif len(names) > 1:
1314 1314 raise error.InputError(
1315 1315 _(b"only one new bookmark name allowed")
1316 1316 )
1317 1317 oldname = repo._bookmarks.expandname(opts['rename'])
1318 1318 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1319 1319 elif action == 'add':
1320 1320 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1321 1321 elif action == 'inactive':
1322 1322 if len(repo._bookmarks) == 0:
1323 1323 ui.status(_(b"no bookmarks set\n"))
1324 1324 elif not repo._activebookmark:
1325 1325 ui.status(_(b"no active bookmark\n"))
1326 1326 else:
1327 1327 bookmarks.deactivate(repo)
1328 1328 elif action == 'list':
1329 1329 names = pycompat.maplist(repo._bookmarks.expandname, names)
1330 1330 with ui.formatter(b'bookmarks', pycompat.byteskwargs(opts)) as fm:
1331 1331 bookmarks.printbookmarks(ui, repo, fm, names)
1332 1332 else:
1333 1333 raise error.ProgrammingError(
1334 1334 b'invalid action: %s' % pycompat.sysbytes(action)
1335 1335 )
1336 1336
1337 1337
1338 1338 @command(
1339 1339 b'branch',
1340 1340 [
1341 1341 (
1342 1342 b'f',
1343 1343 b'force',
1344 1344 None,
1345 1345 _(b'set branch name even if it shadows an existing branch'),
1346 1346 ),
1347 1347 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1348 1348 (
1349 1349 b'r',
1350 1350 b'rev',
1351 1351 [],
1352 1352 _(b'change branches of the given revs (EXPERIMENTAL)'),
1353 1353 ),
1354 1354 ],
1355 1355 _(b'[-fC] [NAME]'),
1356 1356 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1357 1357 )
1358 1358 def branch(ui, repo, label=None, **opts):
1359 1359 """set or show the current branch name
1360 1360
1361 1361 .. note::
1362 1362
1363 1363 Branch names are permanent and global. Use :hg:`bookmark` to create a
1364 1364 light-weight bookmark instead. See :hg:`help glossary` for more
1365 1365 information about named branches and bookmarks.
1366 1366
1367 1367 With no argument, show the current branch name. With one argument,
1368 1368 set the working directory branch name (the branch will not exist
1369 1369 in the repository until the next commit). Standard practice
1370 1370 recommends that primary development take place on the 'default'
1371 1371 branch.
1372 1372
1373 1373 Unless -f/--force is specified, branch will not let you set a
1374 1374 branch name that already exists.
1375 1375
1376 1376 Use -C/--clean to reset the working directory branch to that of
1377 1377 the parent of the working directory, negating a previous branch
1378 1378 change.
1379 1379
1380 1380 Use the command :hg:`update` to switch to an existing branch. Use
1381 1381 :hg:`commit --close-branch` to mark this branch head as closed.
1382 1382 When all heads of a branch are closed, the branch will be
1383 1383 considered closed.
1384 1384
1385 1385 Returns 0 on success.
1386 1386 """
1387 1387 revs = opts.get('rev')
1388 1388 if label:
1389 1389 label = label.strip()
1390 1390
1391 1391 if not opts.get('clean') and not label:
1392 1392 if revs:
1393 1393 raise error.InputError(
1394 1394 _(b"no branch name specified for the revisions")
1395 1395 )
1396 1396 ui.write(b"%s\n" % repo.dirstate.branch())
1397 1397 return
1398 1398
1399 1399 with repo.wlock():
1400 1400 if opts.get('clean'):
1401 1401 label = repo[b'.'].branch()
1402 1402 repo.dirstate.setbranch(label, repo.currenttransaction())
1403 1403 ui.status(_(b'reset working directory to branch %s\n') % label)
1404 1404 elif label:
1405 1405 scmutil.checknewlabel(repo, label, b'branch')
1406 1406 if revs:
1407 1407 return cmdutil.changebranch(ui, repo, revs, label, **opts)
1408 1408
1409 1409 if not opts.get('force') and label in repo.branchmap():
1410 1410 if label not in [p.branch() for p in repo[None].parents()]:
1411 1411 raise error.InputError(
1412 1412 _(b'a branch of the same name already exists'),
1413 1413 # i18n: "it" refers to an existing branch
1414 1414 hint=_(b"use 'hg update' to switch to it"),
1415 1415 )
1416 1416
1417 1417 repo.dirstate.setbranch(label, repo.currenttransaction())
1418 1418 ui.status(_(b'marked working directory as branch %s\n') % label)
1419 1419
1420 1420 # find any open named branches aside from default
1421 1421 for n, h, t, c in repo.branchmap().iterbranches():
1422 1422 if n != b"default" and not c:
1423 1423 return 0
1424 1424 ui.status(
1425 1425 _(
1426 1426 b'(branches are permanent and global, '
1427 1427 b'did you want a bookmark?)\n'
1428 1428 )
1429 1429 )
1430 1430
1431 1431
1432 1432 @command(
1433 1433 b'branches',
1434 1434 [
1435 1435 (
1436 1436 b'a',
1437 1437 b'active',
1438 1438 False,
1439 1439 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1440 1440 ),
1441 1441 (b'c', b'closed', False, _(b'show normal and closed branches')),
1442 1442 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1443 1443 ]
1444 1444 + formatteropts,
1445 1445 _(b'[-c]'),
1446 1446 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1447 1447 intents={INTENT_READONLY},
1448 1448 )
1449 1449 def branches(ui, repo, active=False, closed=False, **opts):
1450 1450 """list repository named branches
1451 1451
1452 1452 List the repository's named branches, indicating which ones are
1453 1453 inactive. If -c/--closed is specified, also list branches which have
1454 1454 been marked closed (see :hg:`commit --close-branch`).
1455 1455
1456 1456 Use the command :hg:`update` to switch to an existing branch.
1457 1457
1458 1458 .. container:: verbose
1459 1459
1460 1460 Template:
1461 1461
1462 1462 The following keywords are supported in addition to the common template
1463 1463 keywords and functions such as ``{branch}``. See also
1464 1464 :hg:`help templates`.
1465 1465
1466 1466 :active: Boolean. True if the branch is active.
1467 1467 :closed: Boolean. True if the branch is closed.
1468 1468 :current: Boolean. True if it is the current branch.
1469 1469
1470 1470 Returns 0.
1471 1471 """
1472 1472
1473 1473 revs = opts.get('rev')
1474 1474 selectedbranches = None
1475 1475 if revs:
1476 1476 revs = logcmdutil.revrange(repo, revs)
1477 1477 getbi = repo.revbranchcache().branchinfo
1478 1478 selectedbranches = {getbi(r)[0] for r in revs}
1479 1479
1480 1480 ui.pager(b'branches')
1481 1481 fm = ui.formatter(b'branches', pycompat.byteskwargs(opts))
1482 1482 hexfunc = fm.hexfunc
1483 1483
1484 1484 allheads = set(repo.heads())
1485 1485 branches = []
1486 1486 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1487 1487 if selectedbranches is not None and tag not in selectedbranches:
1488 1488 continue
1489 1489 isactive = False
1490 1490 if not isclosed:
1491 1491 openheads = set(repo.branchmap().iteropen(heads))
1492 1492 isactive = bool(openheads & allheads)
1493 1493 branches.append((tag, repo[tip], isactive, not isclosed))
1494 1494 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1495 1495
1496 1496 for tag, ctx, isactive, isopen in branches:
1497 1497 if active and not isactive:
1498 1498 continue
1499 1499 if isactive:
1500 1500 label = b'branches.active'
1501 1501 notice = b''
1502 1502 elif not isopen:
1503 1503 if not closed:
1504 1504 continue
1505 1505 label = b'branches.closed'
1506 1506 notice = _(b' (closed)')
1507 1507 else:
1508 1508 label = b'branches.inactive'
1509 1509 notice = _(b' (inactive)')
1510 1510 current = tag == repo.dirstate.branch()
1511 1511 if current:
1512 1512 label = b'branches.current'
1513 1513
1514 1514 fm.startitem()
1515 1515 fm.write(b'branch', b'%s', tag, label=label)
1516 1516 rev = ctx.rev()
1517 1517 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1518 1518 fmt = b' ' * padsize + b' %d:%s'
1519 1519 fm.condwrite(
1520 1520 not ui.quiet,
1521 1521 b'rev node',
1522 1522 fmt,
1523 1523 rev,
1524 1524 hexfunc(ctx.node()),
1525 1525 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1526 1526 )
1527 1527 fm.context(ctx=ctx)
1528 1528 fm.data(active=isactive, closed=not isopen, current=current)
1529 1529 if not ui.quiet:
1530 1530 fm.plain(notice)
1531 1531 fm.plain(b'\n')
1532 1532 fm.end()
1533 1533
1534 1534
1535 1535 @command(
1536 1536 b'bundle',
1537 1537 [
1538 1538 (
1539 1539 b'',
1540 1540 b'exact',
1541 1541 None,
1542 1542 _(b'compute the base from the revision specified'),
1543 1543 ),
1544 1544 (
1545 1545 b'f',
1546 1546 b'force',
1547 1547 None,
1548 1548 _(b'run even when the destination is unrelated'),
1549 1549 ),
1550 1550 (
1551 1551 b'r',
1552 1552 b'rev',
1553 1553 [],
1554 1554 _(b'a changeset intended to be added to the destination'),
1555 1555 _(b'REV'),
1556 1556 ),
1557 1557 (
1558 1558 b'b',
1559 1559 b'branch',
1560 1560 [],
1561 1561 _(b'a specific branch you would like to bundle'),
1562 1562 _(b'BRANCH'),
1563 1563 ),
1564 1564 (
1565 1565 b'',
1566 1566 b'base',
1567 1567 [],
1568 1568 _(b'a base changeset assumed to be available at the destination'),
1569 1569 _(b'REV'),
1570 1570 ),
1571 1571 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1572 1572 (
1573 1573 b't',
1574 1574 b'type',
1575 1575 b'bzip2',
1576 1576 _(b'bundle compression type to use'),
1577 1577 _(b'TYPE'),
1578 1578 ),
1579 1579 ]
1580 1580 + remoteopts,
1581 1581 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]...'),
1582 1582 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1583 1583 )
1584 1584 def bundle(ui, repo, fname, *dests, **opts):
1585 1585 """create a bundle file
1586 1586
1587 1587 Generate a bundle file containing data to be transferred to another
1588 1588 repository.
1589 1589
1590 1590 To create a bundle containing all changesets, use -a/--all
1591 1591 (or --base null). Otherwise, hg assumes the destination will have
1592 1592 all the nodes you specify with --base parameters. Otherwise, hg
1593 1593 will assume the repository has all the nodes in destination, or
1594 1594 default-push/default if no destination is specified, where destination
1595 1595 is the repositories you provide through DEST option.
1596 1596
1597 1597 You can change bundle format with the -t/--type option. See
1598 1598 :hg:`help bundlespec` for documentation on this format. By default,
1599 1599 the most appropriate format is used and compression defaults to
1600 1600 bzip2.
1601 1601
1602 1602 The bundle file can then be transferred using conventional means
1603 1603 and applied to another repository with the unbundle or pull
1604 1604 command. This is useful when direct push and pull are not
1605 1605 available or when exporting an entire repository is undesirable.
1606 1606
1607 1607 Applying bundles preserves all changeset contents including
1608 1608 permissions, copy/rename information, and revision history.
1609 1609
1610 1610 Returns 0 on success, 1 if no changes found.
1611 1611 """
1612 1612
1613 1613 revs = None
1614 1614 if 'rev' in opts:
1615 1615 revstrings = opts['rev']
1616 1616 revs = logcmdutil.revrange(repo, revstrings)
1617 1617 if revstrings and not revs:
1618 1618 raise error.InputError(_(b'no commits to bundle'))
1619 1619
1620 1620 bundletype = opts.get('type', b'bzip2').lower()
1621 1621 try:
1622 1622 bundlespec = bundlecaches.parsebundlespec(
1623 1623 repo, bundletype, strict=False
1624 1624 )
1625 1625 except error.UnsupportedBundleSpecification as e:
1626 1626 raise error.InputError(
1627 1627 pycompat.bytestr(e),
1628 1628 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1629 1629 )
1630 1630 cgversion = bundlespec.params[b"cg.version"]
1631 1631
1632 1632 # Packed bundles are a pseudo bundle format for now.
1633 1633 if cgversion == b's1':
1634 1634 raise error.InputError(
1635 1635 _(b'packed bundles cannot be produced by "hg bundle"'),
1636 1636 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1637 1637 )
1638 1638 base_opt = opts.get('base')
1639 1639 if opts.get('all'):
1640 1640 if dests:
1641 1641 raise error.InputError(
1642 1642 _(b"--all is incompatible with specifying destinations")
1643 1643 )
1644 1644 if base_opt:
1645 1645 ui.warn(_(b"ignoring --base because --all was specified\n"))
1646 1646 if opts.get('exact'):
1647 1647 ui.warn(_(b"ignoring --exact because --all was specified\n"))
1648 1648 base = [nullrev]
1649 1649 elif opts.get('exact'):
1650 1650 if dests:
1651 1651 raise error.InputError(
1652 1652 _(b"--exact is incompatible with specifying destinations")
1653 1653 )
1654 1654 if base_opt:
1655 1655 ui.warn(_(b"ignoring --base because --exact was specified\n"))
1656 1656 base = repo.revs(b'parents(%ld) - %ld', revs, revs)
1657 1657 if not base:
1658 1658 base = [nullrev]
1659 1659 elif base_opt:
1660 1660 base = logcmdutil.revrange(repo, base_opt)
1661 1661 if not base:
1662 1662 # base specified, but nothing was selected
1663 1663 base = [nullrev]
1664 1664 else:
1665 1665 base = None
1666 1666 if cgversion not in changegroup.supportedoutgoingversions(repo):
1667 1667 raise error.Abort(
1668 1668 _(b"repository does not support bundle version %s") % cgversion
1669 1669 )
1670 1670
1671 1671 if base is not None:
1672 1672 if dests:
1673 1673 raise error.InputError(
1674 1674 _(b"--base is incompatible with specifying destinations")
1675 1675 )
1676 1676 cl = repo.changelog
1677 1677 common = [cl.node(rev) for rev in base]
1678 1678 heads = [cl.node(r) for r in revs] if revs else None
1679 1679 outgoing = discovery.outgoing(repo, common, heads)
1680 1680 missing = outgoing.missing
1681 1681 excluded = outgoing.excluded
1682 1682 else:
1683 1683 missing = set()
1684 1684 excluded = set()
1685 1685 for path in urlutil.get_push_paths(repo, ui, dests):
1686 1686 other = hg.peer(repo, pycompat.byteskwargs(opts), path)
1687 1687 if revs is not None:
1688 1688 hex_revs = [repo[r].hex() for r in revs]
1689 1689 else:
1690 1690 hex_revs = None
1691 1691 branches = (path.branch, [])
1692 1692 head_revs, checkout = hg.addbranchrevs(
1693 1693 repo, repo, branches, hex_revs
1694 1694 )
1695 1695 heads = (
1696 1696 head_revs
1697 1697 and pycompat.maplist(repo.lookup, head_revs)
1698 1698 or head_revs
1699 1699 )
1700 1700 outgoing = discovery.findcommonoutgoing(
1701 1701 repo,
1702 1702 other,
1703 1703 onlyheads=heads,
1704 1704 force=opts.get('force'),
1705 1705 portable=True,
1706 1706 )
1707 1707 missing.update(outgoing.missing)
1708 1708 excluded.update(outgoing.excluded)
1709 1709
1710 1710 if not missing:
1711 1711 scmutil.nochangesfound(ui, repo, not base and excluded)
1712 1712 return 1
1713 1713
1714 1714 # internal changeset are internal implementation details that should not
1715 1715 # leave the repository. Bundling with `hg bundle` create such risk.
1716 1716 bundled_internal = repo.revs(b"%ln and _internal()", missing)
1717 1717 if bundled_internal:
1718 1718 msg = _(b"cannot bundle internal changesets")
1719 1719 hint = _(b"%d internal changesets selected") % len(bundled_internal)
1720 1720 raise error.Abort(msg, hint=hint)
1721 1721
1722 1722 if heads:
1723 1723 outgoing = discovery.outgoing(
1724 1724 repo, missingroots=missing, ancestorsof=heads
1725 1725 )
1726 1726 else:
1727 1727 outgoing = discovery.outgoing(repo, missingroots=missing)
1728 1728 outgoing.excluded = sorted(excluded)
1729 1729
1730 1730 if cgversion == b'01': # bundle1
1731 1731 bversion = b'HG10' + bundlespec.wirecompression
1732 1732 bcompression = None
1733 1733 elif cgversion in (b'02', b'03'):
1734 1734 bversion = b'HG20'
1735 1735 bcompression = bundlespec.wirecompression
1736 1736 else:
1737 1737 raise error.ProgrammingError(
1738 1738 b'bundle: unexpected changegroup version %s' % cgversion
1739 1739 )
1740 1740
1741 1741 # TODO compression options should be derived from bundlespec parsing.
1742 1742 # This is a temporary hack to allow adjusting bundle compression
1743 1743 # level without a) formalizing the bundlespec changes to declare it
1744 1744 # b) introducing a command flag.
1745 1745 compopts = {}
1746 1746 complevel = ui.configint(
1747 1747 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1748 1748 )
1749 1749 if complevel is None:
1750 1750 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1751 1751 if complevel is not None:
1752 1752 compopts[b'level'] = complevel
1753 1753
1754 1754 compthreads = ui.configint(
1755 1755 b'experimental', b'bundlecompthreads.' + bundlespec.compression
1756 1756 )
1757 1757 if compthreads is None:
1758 1758 compthreads = ui.configint(b'experimental', b'bundlecompthreads')
1759 1759 if compthreads is not None:
1760 1760 compopts[b'threads'] = compthreads
1761 1761
1762 1762 # Bundling of obsmarker and phases is optional as not all clients
1763 1763 # support the necessary features.
1764 1764 cfg = ui.configbool
1765 1765 obsolescence_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker')
1766 1766 bundlespec.set_param(b'obsolescence', obsolescence_cfg, overwrite=False)
1767 1767 obs_mand_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker:mandatory')
1768 1768 bundlespec.set_param(
1769 1769 b'obsolescence-mandatory', obs_mand_cfg, overwrite=False
1770 1770 )
1771 1771 if not bundlespec.params.get(b'phases', False):
1772 1772 phases_cfg = cfg(b'experimental', b'bundle-phases')
1773 1773 bundlespec.set_param(b'phases', phases_cfg, overwrite=False)
1774 1774
1775 1775 bundle2.writenewbundle(
1776 1776 ui,
1777 1777 repo,
1778 1778 b'bundle',
1779 1779 fname,
1780 1780 bversion,
1781 1781 outgoing,
1782 1782 bundlespec.params,
1783 1783 compression=bcompression,
1784 1784 compopts=compopts,
1785 1785 )
1786 1786
1787 1787
1788 1788 @command(
1789 1789 b'cat',
1790 1790 [
1791 1791 (
1792 1792 b'o',
1793 1793 b'output',
1794 1794 b'',
1795 1795 _(b'print output to file with formatted name'),
1796 1796 _(b'FORMAT'),
1797 1797 ),
1798 1798 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1799 1799 (b'', b'decode', None, _(b'apply any matching decode filter')),
1800 1800 ]
1801 1801 + walkopts
1802 1802 + formatteropts,
1803 1803 _(b'[OPTION]... FILE...'),
1804 1804 helpcategory=command.CATEGORY_FILE_CONTENTS,
1805 1805 inferrepo=True,
1806 1806 intents={INTENT_READONLY},
1807 1807 )
1808 1808 def cat(ui, repo, file1, *pats, **opts):
1809 1809 """output the current or given revision of files
1810 1810
1811 1811 Print the specified files as they were at the given revision. If
1812 1812 no revision is given, the parent of the working directory is used.
1813 1813
1814 1814 Output may be to a file, in which case the name of the file is
1815 1815 given using a template string. See :hg:`help templates`. In addition
1816 1816 to the common template keywords, the following formatting rules are
1817 1817 supported:
1818 1818
1819 1819 :``%%``: literal "%" character
1820 1820 :``%s``: basename of file being printed
1821 1821 :``%d``: dirname of file being printed, or '.' if in repository root
1822 1822 :``%p``: root-relative path name of file being printed
1823 1823 :``%H``: changeset hash (40 hexadecimal digits)
1824 1824 :``%R``: changeset revision number
1825 1825 :``%h``: short-form changeset hash (12 hexadecimal digits)
1826 1826 :``%r``: zero-padded changeset revision number
1827 1827 :``%b``: basename of the exporting repository
1828 1828 :``\\``: literal "\\" character
1829 1829
1830 1830 .. container:: verbose
1831 1831
1832 1832 Template:
1833 1833
1834 1834 The following keywords are supported in addition to the common template
1835 1835 keywords and functions. See also :hg:`help templates`.
1836 1836
1837 1837 :data: String. File content.
1838 1838 :path: String. Repository-absolute path of the file.
1839 1839
1840 1840 Returns 0 on success.
1841 1841 """
1842 1842 rev = opts.get('rev')
1843 1843 if rev:
1844 1844 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1845 1845 ctx = logcmdutil.revsingle(repo, rev)
1846 1846 m = scmutil.match(ctx, (file1,) + pats, pycompat.byteskwargs(opts))
1847 1847 fntemplate = opts.pop('output', b'')
1848 1848 if cmdutil.isstdiofilename(fntemplate):
1849 1849 fntemplate = b''
1850 1850
1851 1851 if fntemplate:
1852 1852 fm = formatter.nullformatter(ui, b'cat', pycompat.byteskwargs(opts))
1853 1853 else:
1854 1854 ui.pager(b'cat')
1855 1855 fm = ui.formatter(b'cat', pycompat.byteskwargs(opts))
1856 1856 with fm:
1857 1857 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, b'', **opts)
1858 1858
1859 1859
1860 1860 @command(
1861 1861 b'clone',
1862 1862 [
1863 1863 (
1864 1864 b'U',
1865 1865 b'noupdate',
1866 1866 None,
1867 1867 _(
1868 1868 b'the clone will include an empty working '
1869 1869 b'directory (only a repository)'
1870 1870 ),
1871 1871 ),
1872 1872 (
1873 1873 b'u',
1874 1874 b'updaterev',
1875 1875 b'',
1876 1876 _(b'revision, tag, or branch to check out'),
1877 1877 _(b'REV'),
1878 1878 ),
1879 1879 (
1880 1880 b'r',
1881 1881 b'rev',
1882 1882 [],
1883 1883 _(
1884 1884 b'do not clone everything, but include this changeset'
1885 1885 b' and its ancestors'
1886 1886 ),
1887 1887 _(b'REV'),
1888 1888 ),
1889 1889 (
1890 1890 b'b',
1891 1891 b'branch',
1892 1892 [],
1893 1893 _(
1894 1894 b'do not clone everything, but include this branch\'s'
1895 1895 b' changesets and their ancestors'
1896 1896 ),
1897 1897 _(b'BRANCH'),
1898 1898 ),
1899 1899 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1900 1900 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1901 1901 (b'', b'stream', None, _(b'clone with minimal data processing')),
1902 1902 ]
1903 1903 + remoteopts,
1904 1904 _(b'[OPTION]... SOURCE [DEST]'),
1905 1905 helpcategory=command.CATEGORY_REPO_CREATION,
1906 1906 helpbasic=True,
1907 1907 norepo=True,
1908 1908 )
1909 1909 def clone(ui, source, dest=None, **opts):
1910 1910 """make a copy of an existing repository
1911 1911
1912 1912 Create a copy of an existing repository in a new directory.
1913 1913
1914 1914 If no destination directory name is specified, it defaults to the
1915 1915 basename of the source.
1916 1916
1917 1917 The location of the source is added to the new repository's
1918 1918 ``.hg/hgrc`` file, as the default to be used for future pulls.
1919 1919
1920 1920 Only local paths and ``ssh://`` URLs are supported as
1921 1921 destinations. For ``ssh://`` destinations, no working directory or
1922 1922 ``.hg/hgrc`` will be created on the remote side.
1923 1923
1924 1924 If the source repository has a bookmark called '@' set, that
1925 1925 revision will be checked out in the new repository by default.
1926 1926
1927 1927 To check out a particular version, use -u/--update, or
1928 1928 -U/--noupdate to create a clone with no working directory.
1929 1929
1930 1930 To pull only a subset of changesets, specify one or more revisions
1931 1931 identifiers with -r/--rev or branches with -b/--branch. The
1932 1932 resulting clone will contain only the specified changesets and
1933 1933 their ancestors. These options (or 'clone src#rev dest') imply
1934 1934 --pull, even for local source repositories.
1935 1935
1936 1936 In normal clone mode, the remote normalizes repository data into a common
1937 1937 exchange format and the receiving end translates this data into its local
1938 1938 storage format. --stream activates a different clone mode that essentially
1939 1939 copies repository files from the remote with minimal data processing. This
1940 1940 significantly reduces the CPU cost of a clone both remotely and locally.
1941 1941 However, it often increases the transferred data size by 30-40%. This can
1942 1942 result in substantially faster clones where I/O throughput is plentiful,
1943 1943 especially for larger repositories. A side-effect of --stream clones is
1944 1944 that storage settings and requirements on the remote are applied locally:
1945 1945 a modern client may inherit legacy or inefficient storage used by the
1946 1946 remote or a legacy Mercurial client may not be able to clone from a
1947 1947 modern Mercurial remote.
1948 1948
1949 1949 .. note::
1950 1950
1951 1951 Specifying a tag will include the tagged changeset but not the
1952 1952 changeset containing the tag.
1953 1953
1954 1954 .. container:: verbose
1955 1955
1956 1956 For efficiency, hardlinks are used for cloning whenever the
1957 1957 source and destination are on the same filesystem (note this
1958 1958 applies only to the repository data, not to the working
1959 1959 directory). Some filesystems, such as AFS, implement hardlinking
1960 1960 incorrectly, but do not report errors. In these cases, use the
1961 1961 --pull option to avoid hardlinking.
1962 1962
1963 1963 Mercurial will update the working directory to the first applicable
1964 1964 revision from this list:
1965 1965
1966 1966 a) null if -U or the source repository has no changesets
1967 1967 b) if -u . and the source repository is local, the first parent of
1968 1968 the source repository's working directory
1969 1969 c) the changeset specified with -u (if a branch name, this means the
1970 1970 latest head of that branch)
1971 1971 d) the changeset specified with -r
1972 1972 e) the tipmost head specified with -b
1973 1973 f) the tipmost head specified with the url#branch source syntax
1974 1974 g) the revision marked with the '@' bookmark, if present
1975 1975 h) the tipmost head of the default branch
1976 1976 i) tip
1977 1977
1978 1978 When cloning from servers that support it, Mercurial may fetch
1979 1979 pre-generated data from a server-advertised URL or inline from the
1980 1980 same stream. When this is done, hooks operating on incoming changesets
1981 1981 and changegroups may fire more than once, once for each pre-generated
1982 1982 bundle and as well as for any additional remaining data. In addition,
1983 1983 if an error occurs, the repository may be rolled back to a partial
1984 1984 clone. This behavior may change in future releases.
1985 1985 See :hg:`help -e clonebundles` for more.
1986 1986
1987 1987 Examples:
1988 1988
1989 1989 - clone a remote repository to a new directory named hg/::
1990 1990
1991 1991 hg clone https://www.mercurial-scm.org/repo/hg/
1992 1992
1993 1993 - create a lightweight local clone::
1994 1994
1995 1995 hg clone project/ project-feature/
1996 1996
1997 1997 - clone from an absolute path on an ssh server (note double-slash)::
1998 1998
1999 1999 hg clone ssh://user@server//home/projects/alpha/
2000 2000
2001 2001 - do a streaming clone while checking out a specified version::
2002 2002
2003 2003 hg clone --stream http://server/repo -u 1.5
2004 2004
2005 2005 - create a repository without changesets after a particular revision::
2006 2006
2007 2007 hg clone -r 04e544 experimental/ good/
2008 2008
2009 2009 - clone (and track) a particular named branch::
2010 2010
2011 2011 hg clone https://www.mercurial-scm.org/repo/hg/#stable
2012 2012
2013 2013 See :hg:`help urls` for details on specifying URLs.
2014 2014
2015 2015 Returns 0 on success.
2016 2016 """
2017 2017 cmdutil.check_at_most_one_arg(opts, 'noupdate', 'updaterev')
2018 2018
2019 2019 # --include/--exclude can come from narrow or sparse.
2020 2020 includepats, excludepats = None, None
2021 2021
2022 2022 # hg.clone() differentiates between None and an empty set. So make sure
2023 2023 # patterns are sets if narrow is requested without patterns.
2024 2024 if opts.get('narrow'):
2025 2025 includepats = set()
2026 2026 excludepats = set()
2027 2027
2028 2028 if opts.get('include'):
2029 2029 includepats = narrowspec.parsepatterns(opts.get('include'))
2030 2030 if opts.get('exclude'):
2031 2031 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
2032 2032
2033 2033 r = hg.clone(
2034 2034 ui,
2035 2035 pycompat.byteskwargs(opts),
2036 2036 source,
2037 2037 dest,
2038 2038 pull=opts.get('pull'),
2039 2039 stream=opts.get('stream') or opts.get('uncompressed'),
2040 2040 revs=opts.get('rev'),
2041 2041 update=opts.get('updaterev') or not opts.get('noupdate'),
2042 2042 branch=opts.get('branch'),
2043 2043 shareopts=opts.get('shareopts'),
2044 2044 storeincludepats=includepats,
2045 2045 storeexcludepats=excludepats,
2046 2046 depth=opts.get('depth') or None,
2047 2047 )
2048 2048
2049 2049 return r is None
2050 2050
2051 2051
2052 2052 @command(
2053 2053 b'commit|ci',
2054 2054 [
2055 2055 (
2056 2056 b'A',
2057 2057 b'addremove',
2058 2058 None,
2059 2059 _(b'mark new/missing files as added/removed before committing'),
2060 2060 ),
2061 2061 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
2062 2062 (b'', b'amend', None, _(b'amend the parent of the working directory')),
2063 2063 (b's', b'secret', None, _(b'use the secret phase for committing')),
2064 2064 (b'', b'draft', None, _(b'use the draft phase for committing')),
2065 2065 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
2066 2066 (
2067 2067 b'',
2068 2068 b'force-close-branch',
2069 2069 None,
2070 2070 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
2071 2071 ),
2072 2072 (b'i', b'interactive', None, _(b'use interactive mode')),
2073 2073 ]
2074 2074 + walkopts
2075 2075 + commitopts
2076 2076 + commitopts2
2077 2077 + subrepoopts,
2078 2078 _(b'[OPTION]... [FILE]...'),
2079 2079 helpcategory=command.CATEGORY_COMMITTING,
2080 2080 helpbasic=True,
2081 2081 inferrepo=True,
2082 2082 )
2083 2083 def commit(ui, repo, *pats, **opts):
2084 2084 """commit the specified files or all outstanding changes
2085 2085
2086 2086 Commit changes to the given files into the repository. Unlike a
2087 2087 centralized SCM, this operation is a local operation. See
2088 2088 :hg:`push` for a way to actively distribute your changes.
2089 2089
2090 2090 If a list of files is omitted, all changes reported by :hg:`status`
2091 2091 will be committed.
2092 2092
2093 2093 If you are committing the result of a merge, do not provide any
2094 2094 filenames or -I/-X filters.
2095 2095
2096 2096 If no commit message is specified, Mercurial starts your
2097 2097 configured editor where you can enter a message. In case your
2098 2098 commit fails, you will find a backup of your message in
2099 2099 ``.hg/last-message.txt``.
2100 2100
2101 2101 The --close-branch flag can be used to mark the current branch
2102 2102 head closed. When all heads of a branch are closed, the branch
2103 2103 will be considered closed and no longer listed.
2104 2104
2105 2105 The --amend flag can be used to amend the parent of the
2106 2106 working directory with a new commit that contains the changes
2107 2107 in the parent in addition to those currently reported by :hg:`status`,
2108 2108 if there are any. The old commit is stored in a backup bundle in
2109 2109 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2110 2110 on how to restore it).
2111 2111
2112 2112 Message, user and date are taken from the amended commit unless
2113 2113 specified. When a message isn't specified on the command line,
2114 2114 the editor will open with the message of the amended commit.
2115 2115
2116 2116 It is not possible to amend public changesets (see :hg:`help phases`)
2117 2117 or changesets that have children.
2118 2118
2119 2119 See :hg:`help dates` for a list of formats valid for -d/--date.
2120 2120
2121 2121 Returns 0 on success, 1 if nothing changed.
2122 2122
2123 2123 .. container:: verbose
2124 2124
2125 2125 Examples:
2126 2126
2127 2127 - commit all files ending in .py::
2128 2128
2129 2129 hg commit --include "set:**.py"
2130 2130
2131 2131 - commit all non-binary files::
2132 2132
2133 2133 hg commit --exclude "set:binary()"
2134 2134
2135 2135 - amend the current commit and set the date to now::
2136 2136
2137 2137 hg commit --amend --date now
2138 2138 """
2139 2139 cmdutil.check_at_most_one_arg(opts, 'draft', 'secret')
2140 2140 cmdutil.check_incompatible_arguments(opts, 'subrepos', ['amend'])
2141 2141 with repo.wlock(), repo.lock():
2142 2142 return _docommit(ui, repo, *pats, **opts)
2143 2143
2144 2144
2145 2145 def _docommit(ui, repo, *pats, **opts):
2146 2146 if opts.get('interactive'):
2147 2147 opts.pop('interactive')
2148 2148 ret = cmdutil.dorecord(
2149 2149 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2150 2150 )
2151 2151 # ret can be 0 (no changes to record) or the value returned by
2152 2152 # commit(), 1 if nothing changed or None on success.
2153 2153 return 1 if ret == 0 else ret
2154 2154
2155 2155 if opts.get('subrepos'):
2156 2156 # Let --subrepos on the command line override config setting.
2157 2157 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2158 2158
2159 2159 cmdutil.checkunfinished(repo, commit=True)
2160 2160
2161 2161 branch = repo[None].branch()
2162 2162 bheads = repo.branchheads(branch)
2163 2163 tip = repo.changelog.tip()
2164 2164
2165 2165 extra = {}
2166 2166 if opts.get('close_branch') or opts.get('force_close_branch'):
2167 2167 extra[b'close'] = b'1'
2168 2168
2169 2169 if repo[b'.'].closesbranch():
2170 2170 # Not ideal, but let us do an extra status early to prevent early
2171 2171 # bail out.
2172 2172 matcher = scmutil.match(
2173 2173 repo[None], pats, pycompat.byteskwargs(opts)
2174 2174 )
2175 2175 s = repo.status(match=matcher)
2176 2176 if s.modified or s.added or s.removed:
2177 2177 bheads = repo.branchheads(branch, closed=True)
2178 2178 else:
2179 2179 msg = _(b'current revision is already a branch closing head')
2180 2180 raise error.InputError(msg)
2181 2181
2182 2182 if not bheads:
2183 2183 raise error.InputError(
2184 2184 _(b'branch "%s" has no heads to close') % branch
2185 2185 )
2186 2186 elif (
2187 2187 branch == repo[b'.'].branch()
2188 2188 and repo[b'.'].node() not in bheads
2189 2189 and not opts.get('force_close_branch')
2190 2190 ):
2191 2191 hint = _(
2192 2192 b'use --force-close-branch to close branch from a non-head'
2193 2193 b' changeset'
2194 2194 )
2195 2195 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2196 2196 elif opts.get('amend'):
2197 2197 if (
2198 2198 repo[b'.'].p1().branch() != branch
2199 2199 and repo[b'.'].p2().branch() != branch
2200 2200 ):
2201 2201 raise error.InputError(_(b'can only close branch heads'))
2202 2202
2203 2203 if opts.get('amend'):
2204 2204 if ui.configbool(b'ui', b'commitsubrepos'):
2205 2205 raise error.InputError(
2206 2206 _(b'cannot amend with ui.commitsubrepos enabled')
2207 2207 )
2208 2208
2209 2209 old = repo[b'.']
2210 2210 rewriteutil.precheck(repo, [old.rev()], b'amend')
2211 2211
2212 2212 # Currently histedit gets confused if an amend happens while histedit
2213 2213 # is in progress. Since we have a checkunfinished command, we are
2214 2214 # temporarily honoring it.
2215 2215 #
2216 2216 # Note: eventually this guard will be removed. Please do not expect
2217 2217 # this behavior to remain.
2218 2218 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2219 2219 cmdutil.checkunfinished(repo)
2220 2220
2221 2221 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2222 2222 if node == old.node():
2223 2223 ui.status(_(b"nothing changed\n"))
2224 2224 return 1
2225 2225 else:
2226 2226
2227 2227 def commitfunc(ui, repo, message, match, opts):
2228 2228 overrides = {}
2229 2229 if opts.get(b'secret'):
2230 2230 overrides[(b'phases', b'new-commit')] = b'secret'
2231 2231 elif opts.get(b'draft'):
2232 2232 overrides[(b'phases', b'new-commit')] = b'draft'
2233 2233
2234 2234 baseui = repo.baseui
2235 2235 with baseui.configoverride(overrides, b'commit'):
2236 2236 with ui.configoverride(overrides, b'commit'):
2237 2237 editform = cmdutil.mergeeditform(
2238 2238 repo[None], b'commit.normal'
2239 2239 )
2240 2240 editor = cmdutil.getcommiteditor(
2241 2241 editform=editform, **pycompat.strkwargs(opts)
2242 2242 )
2243 2243 return repo.commit(
2244 2244 message,
2245 2245 opts.get(b'user'),
2246 2246 opts.get(b'date'),
2247 2247 match,
2248 2248 editor=editor,
2249 2249 extra=extra,
2250 2250 )
2251 2251
2252 2252 node = cmdutil.commit(
2253 2253 ui, repo, commitfunc, pats, pycompat.byteskwargs(opts)
2254 2254 )
2255 2255
2256 2256 if not node:
2257 2257 stat = cmdutil.postcommitstatus(
2258 2258 repo, pats, pycompat.byteskwargs(opts)
2259 2259 )
2260 2260 if stat.deleted:
2261 2261 ui.status(
2262 2262 _(
2263 2263 b"nothing changed (%d missing files, see "
2264 2264 b"'hg status')\n"
2265 2265 )
2266 2266 % len(stat.deleted)
2267 2267 )
2268 2268 else:
2269 2269 ui.status(_(b"nothing changed\n"))
2270 2270 return 1
2271 2271
2272 2272 cmdutil.commitstatus(repo, node, branch, bheads, tip, **opts)
2273 2273
2274 2274 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2275 2275 status(
2276 2276 ui,
2277 2277 repo,
2278 2278 modified=True,
2279 2279 added=True,
2280 2280 removed=True,
2281 2281 deleted=True,
2282 2282 unknown=True,
2283 2283 subrepos=opts.get('subrepos'),
2284 2284 )
2285 2285
2286 2286
2287 2287 @command(
2288 2288 b'config|showconfig|debugconfig',
2289 2289 [
2290 2290 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2291 2291 # This is experimental because we need
2292 2292 # * reasonable behavior around aliases,
2293 2293 # * decide if we display [debug] [experimental] and [devel] section par
2294 2294 # default
2295 2295 # * some way to display "generic" config entry (the one matching
2296 2296 # regexp,
2297 2297 # * proper display of the different value type
2298 2298 # * a better way to handle <DYNAMIC> values (and variable types),
2299 2299 # * maybe some type information ?
2300 2300 (
2301 2301 b'',
2302 2302 b'exp-all-known',
2303 2303 None,
2304 2304 _(b'show all known config option (EXPERIMENTAL)'),
2305 2305 ),
2306 2306 (b'e', b'edit', None, _(b'edit user config')),
2307 2307 (b'l', b'local', None, _(b'edit repository config')),
2308 2308 (b'', b'source', None, _(b'show source of configuration value')),
2309 2309 (
2310 2310 b'',
2311 2311 b'shared',
2312 2312 None,
2313 2313 _(b'edit shared source repository config (EXPERIMENTAL)'),
2314 2314 ),
2315 2315 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2316 2316 (b'g', b'global', None, _(b'edit global config')),
2317 2317 ]
2318 2318 + formatteropts,
2319 2319 _(b'[-u] [NAME]...'),
2320 2320 helpcategory=command.CATEGORY_HELP,
2321 2321 optionalrepo=True,
2322 2322 intents={INTENT_READONLY},
2323 2323 )
2324 2324 def config(ui, repo, *values, **opts):
2325 2325 """show combined config settings from all hgrc files
2326 2326
2327 2327 With no arguments, print names and values of all config items.
2328 2328
2329 2329 With one argument of the form section.name, print just the value
2330 2330 of that config item.
2331 2331
2332 2332 With multiple arguments, print names and values of all config
2333 2333 items with matching section names or section.names.
2334 2334
2335 2335 With --edit, start an editor on the user-level config file. With
2336 2336 --global, edit the system-wide config file. With --local, edit the
2337 2337 repository-level config file.
2338 2338
2339 2339 With --source, the source (filename and line number) is printed
2340 2340 for each config item.
2341 2341
2342 2342 See :hg:`help config` for more information about config files.
2343 2343
2344 2344 .. container:: verbose
2345 2345
2346 2346 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2347 2347 This file is not shared across shares when in share-safe mode.
2348 2348
2349 2349 Template:
2350 2350
2351 2351 The following keywords are supported. See also :hg:`help templates`.
2352 2352
2353 2353 :name: String. Config name.
2354 2354 :source: String. Filename and line number where the item is defined.
2355 2355 :value: String. Config value.
2356 2356
2357 2357 The --shared flag can be used to edit the config file of shared source
2358 2358 repository. It only works when you have shared using the experimental
2359 2359 share safe feature.
2360 2360
2361 2361 Returns 0 on success, 1 if NAME does not exist.
2362 2362
2363 2363 """
2364 2364
2365 2365 editopts = ('edit', 'local', 'global', 'shared', 'non_shared')
2366 2366 if any(opts.get(o) for o in editopts):
2367 2367 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2368 2368 if opts.get('local'):
2369 2369 if not repo:
2370 2370 raise error.InputError(
2371 2371 _(b"can't use --local outside a repository")
2372 2372 )
2373 2373 paths = [repo.vfs.join(b'hgrc')]
2374 2374 elif opts.get('global'):
2375 2375 paths = rcutil.systemrcpath()
2376 2376 elif opts.get('shared'):
2377 2377 if not repo.shared():
2378 2378 raise error.InputError(
2379 2379 _(b"repository is not shared; can't use --shared")
2380 2380 )
2381 2381 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2382 2382 raise error.InputError(
2383 2383 _(
2384 2384 b"share safe feature not enabled; "
2385 2385 b"unable to edit shared source repository config"
2386 2386 )
2387 2387 )
2388 2388 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2389 2389 elif opts.get('non_shared'):
2390 2390 paths = [repo.vfs.join(b'hgrc-not-shared')]
2391 2391 else:
2392 2392 paths = rcutil.userrcpath()
2393 2393
2394 2394 for f in paths:
2395 2395 if os.path.exists(f):
2396 2396 break
2397 2397 else:
2398 2398 if opts.get('global'):
2399 2399 samplehgrc = uimod.samplehgrcs[b'global']
2400 2400 elif opts.get('local'):
2401 2401 samplehgrc = uimod.samplehgrcs[b'local']
2402 2402 else:
2403 2403 samplehgrc = uimod.samplehgrcs[b'user']
2404 2404
2405 2405 f = paths[0]
2406 2406 util.writefile(f, util.tonativeeol(samplehgrc))
2407 2407
2408 2408 editor = ui.geteditor()
2409 2409 ui.system(
2410 2410 b"%s \"%s\"" % (editor, f),
2411 2411 onerr=error.InputError,
2412 2412 errprefix=_(b"edit failed"),
2413 2413 blockedtag=b'config_edit',
2414 2414 )
2415 2415 return
2416 2416 ui.pager(b'config')
2417 2417 fm = ui.formatter(b'config', pycompat.byteskwargs(opts))
2418 2418 for t, f in rcutil.rccomponents():
2419 2419 if t == b'path':
2420 2420 ui.debug(b'read config from: %s\n' % f)
2421 2421 elif t == b'resource':
2422 2422 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2423 2423 elif t == b'items':
2424 2424 # Don't print anything for 'items'.
2425 2425 pass
2426 2426 else:
2427 2427 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2428 2428 untrusted = bool(opts.get('untrusted'))
2429 2429
2430 2430 selsections = selentries = []
2431 2431 if values:
2432 2432 selsections = [v for v in values if b'.' not in v]
2433 2433 selentries = [v for v in values if b'.' in v]
2434 2434 uniquesel = len(selentries) == 1 and not selsections
2435 2435 selsections = set(selsections)
2436 2436 selentries = set(selentries)
2437 2437
2438 2438 matched = False
2439 2439 all_known = opts['exp_all_known']
2440 2440 show_source = ui.debugflag or opts.get('source')
2441 2441 entries = ui.walkconfig(untrusted=untrusted, all_known=all_known)
2442 2442 for section, name, value in entries:
2443 2443 source = ui.configsource(section, name, untrusted)
2444 2444 value = pycompat.bytestr(value)
2445 2445 defaultvalue = ui.configdefault(section, name)
2446 2446 if fm.isplain():
2447 2447 source = source or b'none'
2448 2448 value = value.replace(b'\n', b'\\n')
2449 2449 entryname = section + b'.' + name
2450 2450 if values and not (section in selsections or entryname in selentries):
2451 2451 continue
2452 2452 fm.startitem()
2453 2453 fm.condwrite(show_source, b'source', b'%s: ', source)
2454 2454 if uniquesel:
2455 2455 fm.data(name=entryname)
2456 2456 fm.write(b'value', b'%s\n', value)
2457 2457 else:
2458 2458 fm.write(b'name value', b'%s=%s\n', entryname, value)
2459 2459 if formatter.isprintable(defaultvalue):
2460 2460 fm.data(defaultvalue=defaultvalue)
2461 2461 elif isinstance(defaultvalue, list) and all(
2462 2462 formatter.isprintable(e) for e in defaultvalue
2463 2463 ):
2464 2464 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2465 2465 # TODO: no idea how to process unsupported defaultvalue types
2466 2466 matched = True
2467 2467 fm.end()
2468 2468 if matched:
2469 2469 return 0
2470 2470 return 1
2471 2471
2472 2472
2473 2473 @command(
2474 2474 b'continue',
2475 2475 dryrunopts,
2476 2476 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2477 2477 helpbasic=True,
2478 2478 )
2479 2479 def continuecmd(ui, repo, **opts):
2480 2480 """resumes an interrupted operation (EXPERIMENTAL)
2481 2481
2482 2482 Finishes a multistep operation like graft, histedit, rebase, merge,
2483 2483 and unshelve if they are in an interrupted state.
2484 2484
2485 2485 use --dry-run/-n to dry run the command.
2486 2486 """
2487 2487 dryrun = opts.get('dry_run')
2488 2488 contstate = cmdutil.getunfinishedstate(repo)
2489 2489 if not contstate:
2490 2490 raise error.StateError(_(b'no operation in progress'))
2491 2491 if not contstate.continuefunc:
2492 2492 raise error.StateError(
2493 2493 (
2494 2494 _(b"%s in progress but does not support 'hg continue'")
2495 2495 % (contstate._opname)
2496 2496 ),
2497 2497 hint=contstate.continuemsg(),
2498 2498 )
2499 2499 if dryrun:
2500 2500 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2501 2501 return
2502 2502 return contstate.continuefunc(ui, repo)
2503 2503
2504 2504
2505 2505 @command(
2506 2506 b'copy|cp',
2507 2507 [
2508 2508 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2509 2509 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2510 2510 (
2511 2511 b'',
2512 2512 b'at-rev',
2513 2513 b'',
2514 2514 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2515 2515 _(b'REV'),
2516 2516 ),
2517 2517 (
2518 2518 b'f',
2519 2519 b'force',
2520 2520 None,
2521 2521 _(b'forcibly copy over an existing managed file'),
2522 2522 ),
2523 2523 ]
2524 2524 + walkopts
2525 2525 + dryrunopts,
2526 2526 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2527 2527 helpcategory=command.CATEGORY_FILE_CONTENTS,
2528 2528 )
2529 2529 def copy(ui, repo, *pats, **opts):
2530 2530 """mark files as copied for the next commit
2531 2531
2532 2532 Mark dest as having copies of source files. If dest is a
2533 2533 directory, copies are put in that directory. If dest is a file,
2534 2534 the source must be a single file.
2535 2535
2536 2536 By default, this command copies the contents of files as they
2537 2537 exist in the working directory. If invoked with -A/--after, the
2538 2538 operation is recorded, but no copying is performed.
2539 2539
2540 2540 To undo marking a destination file as copied, use --forget. With that
2541 2541 option, all given (positional) arguments are unmarked as copies. The
2542 2542 destination file(s) will be left in place (still tracked). Note that
2543 2543 :hg:`copy --forget` behaves the same way as :hg:`rename --forget`.
2544 2544
2545 2545 This command takes effect with the next commit by default.
2546 2546
2547 2547 Returns 0 on success, 1 if errors are encountered.
2548 2548 """
2549 2549
2550 2550 context = lambda repo: repo.dirstate.changing_files(repo)
2551 2551 rev = opts.get('at_rev')
2552 2552
2553 2553 if rev:
2554 2554 ctx = logcmdutil.revsingle(repo, rev)
2555 2555 if ctx.rev() is not None:
2556 2556
2557 2557 def context(repo):
2558 2558 return util.nullcontextmanager()
2559 2559
2560 2560 opts['at_rev'] = ctx.rev()
2561 2561 with repo.wlock(), context(repo):
2562 2562 return cmdutil.copy(ui, repo, pats, pycompat.byteskwargs(opts))
2563 2563
2564 2564
2565 2565 @command(
2566 2566 b'debugcommands',
2567 2567 [],
2568 2568 _(b'[COMMAND]'),
2569 2569 helpcategory=command.CATEGORY_HELP,
2570 2570 norepo=True,
2571 2571 )
2572 2572 def debugcommands(ui, cmd=b'', *args):
2573 2573 """list all available commands and options"""
2574 2574 for cmd, vals in sorted(table.items()):
2575 2575 cmd = cmd.split(b'|')[0]
2576 2576 opts = b', '.join([i[1] for i in vals[1]])
2577 2577 ui.write(b'%s: %s\n' % (cmd, opts))
2578 2578
2579 2579
2580 2580 @command(
2581 2581 b'debugcomplete',
2582 2582 [(b'o', b'options', None, _(b'show the command options'))],
2583 2583 _(b'[-o] CMD'),
2584 2584 helpcategory=command.CATEGORY_HELP,
2585 2585 norepo=True,
2586 2586 )
2587 2587 def debugcomplete(ui, cmd=b'', **opts):
2588 2588 """returns the completion list associated with the given command"""
2589 2589
2590 2590 if opts.get('options'):
2591 2591 options = []
2592 2592 otables = [globalopts]
2593 2593 if cmd:
2594 2594 aliases, entry = cmdutil.findcmd(cmd, table, False)
2595 2595 otables.append(entry[1])
2596 2596 for t in otables:
2597 2597 for o in t:
2598 2598 if b"(DEPRECATED)" in o[3]:
2599 2599 continue
2600 2600 if o[0]:
2601 2601 options.append(b'-%s' % o[0])
2602 2602 options.append(b'--%s' % o[1])
2603 2603 ui.write(b"%s\n" % b"\n".join(options))
2604 2604 return
2605 2605
2606 2606 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2607 2607 if ui.verbose:
2608 2608 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2609 2609 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2610 2610
2611 2611
2612 2612 @command(
2613 2613 b'diff',
2614 2614 [
2615 2615 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2616 2616 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2617 2617 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2618 2618 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2619 2619 ]
2620 2620 + diffopts
2621 2621 + diffopts2
2622 2622 + walkopts
2623 2623 + subrepoopts,
2624 2624 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2625 2625 helpcategory=command.CATEGORY_FILE_CONTENTS,
2626 2626 helpbasic=True,
2627 2627 inferrepo=True,
2628 2628 intents={INTENT_READONLY},
2629 2629 )
2630 2630 def diff(ui, repo, *pats, **opts):
2631 2631 """diff repository (or selected files)
2632 2632
2633 2633 Show differences between revisions for the specified files.
2634 2634
2635 2635 Differences between files are shown using the unified diff format.
2636 2636
2637 2637 .. note::
2638 2638
2639 2639 :hg:`diff` may generate unexpected results for merges, as it will
2640 2640 default to comparing against the working directory's first
2641 2641 parent changeset if no revisions are specified. To diff against the
2642 2642 conflict regions, you can use `--config diff.merge=yes`.
2643 2643
2644 2644 By default, the working directory files are compared to its first parent. To
2645 2645 see the differences from another revision, use --from. To see the difference
2646 2646 to another revision, use --to. For example, :hg:`diff --from .^` will show
2647 2647 the differences from the working copy's grandparent to the working copy,
2648 2648 :hg:`diff --to .` will show the diff from the working copy to its parent
2649 2649 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2650 2650 show the diff between those two revisions.
2651 2651
2652 2652 Alternatively you can specify -c/--change with a revision to see the changes
2653 2653 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2654 2654 equivalent to :hg:`diff --from 42^ --to 42`)
2655 2655
2656 2656 Without the -a/--text option, diff will avoid generating diffs of
2657 2657 files it detects as binary. With -a, diff will generate a diff
2658 2658 anyway, probably with undesirable results.
2659 2659
2660 2660 Use the -g/--git option to generate diffs in the git extended diff
2661 2661 format. For more information, read :hg:`help diffs`.
2662 2662
2663 2663 .. container:: verbose
2664 2664
2665 2665 Examples:
2666 2666
2667 2667 - compare a file in the current working directory to its parent::
2668 2668
2669 2669 hg diff foo.c
2670 2670
2671 2671 - compare two historical versions of a directory, with rename info::
2672 2672
2673 2673 hg diff --git --from 1.0 --to 1.2 lib/
2674 2674
2675 2675 - get change stats relative to the last change on some date::
2676 2676
2677 2677 hg diff --stat --from "date('may 2')"
2678 2678
2679 2679 - diff all newly-added files that contain a keyword::
2680 2680
2681 2681 hg diff "set:added() and grep(GNU)"
2682 2682
2683 2683 - compare a revision and its parents::
2684 2684
2685 2685 hg diff -c 9353 # compare against first parent
2686 2686 hg diff --from 9353^ --to 9353 # same using revset syntax
2687 2687 hg diff --from 9353^2 --to 9353 # compare against the second parent
2688 2688
2689 2689 Returns 0 on success.
2690 2690 """
2691 2691
2692 2692 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2693 2693 opts = pycompat.byteskwargs(opts)
2694 2694 revs = opts.get(b'rev')
2695 2695 change = opts.get(b'change')
2696 2696 from_rev = opts.get(b'from')
2697 2697 to_rev = opts.get(b'to')
2698 2698 stat = opts.get(b'stat')
2699 2699 reverse = opts.get(b'reverse')
2700 2700
2701 2701 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2702 2702 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2703 2703 if change:
2704 2704 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2705 2705 ctx2 = logcmdutil.revsingle(repo, change, None)
2706 2706 ctx1 = diffutil.diff_parent(ctx2)
2707 2707 elif from_rev or to_rev:
2708 2708 repo = scmutil.unhidehashlikerevs(
2709 2709 repo, [from_rev] + [to_rev], b'nowarn'
2710 2710 )
2711 2711 ctx1 = logcmdutil.revsingle(repo, from_rev, None)
2712 2712 ctx2 = logcmdutil.revsingle(repo, to_rev, None)
2713 2713 else:
2714 2714 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2715 2715 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
2716 2716
2717 2717 if reverse:
2718 2718 ctxleft = ctx2
2719 2719 ctxright = ctx1
2720 2720 else:
2721 2721 ctxleft = ctx1
2722 2722 ctxright = ctx2
2723 2723
2724 2724 diffopts = patch.diffallopts(ui, opts)
2725 2725 m = scmutil.match(ctx2, pats, opts)
2726 2726 m = repo.narrowmatch(m)
2727 2727 ui.pager(b'diff')
2728 2728 logcmdutil.diffordiffstat(
2729 2729 ui,
2730 2730 repo,
2731 2731 diffopts,
2732 2732 ctxleft,
2733 2733 ctxright,
2734 2734 m,
2735 2735 stat=stat,
2736 2736 listsubrepos=opts.get(b'subrepos'),
2737 2737 root=opts.get(b'root'),
2738 2738 )
2739 2739
2740 2740
2741 2741 @command(
2742 2742 b'export',
2743 2743 [
2744 2744 (
2745 2745 b'B',
2746 2746 b'bookmark',
2747 2747 b'',
2748 2748 _(b'export changes only reachable by given bookmark'),
2749 2749 _(b'BOOKMARK'),
2750 2750 ),
2751 2751 (
2752 2752 b'o',
2753 2753 b'output',
2754 2754 b'',
2755 2755 _(b'print output to file with formatted name'),
2756 2756 _(b'FORMAT'),
2757 2757 ),
2758 2758 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2759 2759 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2760 2760 ]
2761 2761 + diffopts
2762 2762 + formatteropts,
2763 2763 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2764 2764 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2765 2765 helpbasic=True,
2766 2766 intents={INTENT_READONLY},
2767 2767 )
2768 2768 def export(ui, repo, *changesets, **opts):
2769 2769 """dump the header and diffs for one or more changesets
2770 2770
2771 2771 Print the changeset header and diffs for one or more revisions.
2772 2772 If no revision is given, the parent of the working directory is used.
2773 2773
2774 2774 The information shown in the changeset header is: author, date,
2775 2775 branch name (if non-default), changeset hash, parent(s) and commit
2776 2776 comment.
2777 2777
2778 2778 .. note::
2779 2779
2780 2780 :hg:`export` may generate unexpected diff output for merge
2781 2781 changesets, as it will compare the merge changeset against its
2782 2782 first parent only.
2783 2783
2784 2784 Output may be to a file, in which case the name of the file is
2785 2785 given using a template string. See :hg:`help templates`. In addition
2786 2786 to the common template keywords, the following formatting rules are
2787 2787 supported:
2788 2788
2789 2789 :``%%``: literal "%" character
2790 2790 :``%H``: changeset hash (40 hexadecimal digits)
2791 2791 :``%N``: number of patches being generated
2792 2792 :``%R``: changeset revision number
2793 2793 :``%b``: basename of the exporting repository
2794 2794 :``%h``: short-form changeset hash (12 hexadecimal digits)
2795 2795 :``%m``: first line of the commit message (only alphanumeric characters)
2796 2796 :``%n``: zero-padded sequence number, starting at 1
2797 2797 :``%r``: zero-padded changeset revision number
2798 2798 :``\\``: literal "\\" character
2799 2799
2800 2800 Without the -a/--text option, export will avoid generating diffs
2801 2801 of files it detects as binary. With -a, export will generate a
2802 2802 diff anyway, probably with undesirable results.
2803 2803
2804 2804 With -B/--bookmark changesets reachable by the given bookmark are
2805 2805 selected.
2806 2806
2807 2807 Use the -g/--git option to generate diffs in the git extended diff
2808 2808 format. See :hg:`help diffs` for more information.
2809 2809
2810 2810 With the --switch-parent option, the diff will be against the
2811 2811 second parent. It can be useful to review a merge.
2812 2812
2813 2813 .. container:: verbose
2814 2814
2815 2815 Template:
2816 2816
2817 2817 The following keywords are supported in addition to the common template
2818 2818 keywords and functions. See also :hg:`help templates`.
2819 2819
2820 2820 :diff: String. Diff content.
2821 2821 :parents: List of strings. Parent nodes of the changeset.
2822 2822
2823 2823 Examples:
2824 2824
2825 2825 - use export and import to transplant a bugfix to the current
2826 2826 branch::
2827 2827
2828 2828 hg export -r 9353 | hg import -
2829 2829
2830 2830 - export all the changesets between two revisions to a file with
2831 2831 rename information::
2832 2832
2833 2833 hg export --git -r 123:150 > changes.txt
2834 2834
2835 2835 - split outgoing changes into a series of patches with
2836 2836 descriptive names::
2837 2837
2838 2838 hg export -r "outgoing()" -o "%n-%m.patch"
2839 2839
2840 2840 Returns 0 on success.
2841 2841 """
2842 2842 opts = pycompat.byteskwargs(opts)
2843 2843 bookmark = opts.get(b'bookmark')
2844 2844 changesets += tuple(opts.get(b'rev', []))
2845 2845
2846 2846 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2847 2847
2848 2848 if bookmark:
2849 2849 if bookmark not in repo._bookmarks:
2850 2850 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2851 2851
2852 2852 revs = scmutil.bookmarkrevs(repo, bookmark)
2853 2853 else:
2854 2854 if not changesets:
2855 2855 changesets = [b'.']
2856 2856
2857 2857 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2858 2858 revs = logcmdutil.revrange(repo, changesets)
2859 2859
2860 2860 if not revs:
2861 2861 raise error.InputError(_(b"export requires at least one changeset"))
2862 2862 if len(revs) > 1:
2863 2863 ui.note(_(b'exporting patches:\n'))
2864 2864 else:
2865 2865 ui.note(_(b'exporting patch:\n'))
2866 2866
2867 2867 fntemplate = opts.get(b'output')
2868 2868 if cmdutil.isstdiofilename(fntemplate):
2869 2869 fntemplate = b''
2870 2870
2871 2871 if fntemplate:
2872 2872 fm = formatter.nullformatter(ui, b'export', opts)
2873 2873 else:
2874 2874 ui.pager(b'export')
2875 2875 fm = ui.formatter(b'export', opts)
2876 2876 with fm:
2877 2877 cmdutil.export(
2878 2878 repo,
2879 2879 revs,
2880 2880 fm,
2881 2881 fntemplate=fntemplate,
2882 2882 switch_parent=opts.get(b'switch_parent'),
2883 2883 opts=patch.diffallopts(ui, opts),
2884 2884 )
2885 2885
2886 2886
2887 2887 @command(
2888 2888 b'files',
2889 2889 [
2890 2890 (
2891 2891 b'r',
2892 2892 b'rev',
2893 2893 b'',
2894 2894 _(b'search the repository as it is in REV'),
2895 2895 _(b'REV'),
2896 2896 ),
2897 2897 (
2898 2898 b'0',
2899 2899 b'print0',
2900 2900 None,
2901 2901 _(b'end filenames with NUL, for use with xargs'),
2902 2902 ),
2903 2903 ]
2904 2904 + walkopts
2905 2905 + formatteropts
2906 2906 + subrepoopts,
2907 2907 _(b'[OPTION]... [FILE]...'),
2908 2908 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2909 2909 intents={INTENT_READONLY},
2910 2910 )
2911 2911 def files(ui, repo, *pats, **opts):
2912 2912 """list tracked files
2913 2913
2914 2914 Print files under Mercurial control in the working directory or
2915 2915 specified revision for given files (excluding removed files).
2916 2916 Files can be specified as filenames or filesets.
2917 2917
2918 2918 If no files are given to match, this command prints the names
2919 2919 of all files under Mercurial control.
2920 2920
2921 2921 .. container:: verbose
2922 2922
2923 2923 Template:
2924 2924
2925 2925 The following keywords are supported in addition to the common template
2926 2926 keywords and functions. See also :hg:`help templates`.
2927 2927
2928 2928 :flags: String. Character denoting file's symlink and executable bits.
2929 2929 :path: String. Repository-absolute path of the file.
2930 2930 :size: Integer. Size of the file in bytes.
2931 2931
2932 2932 Examples:
2933 2933
2934 2934 - list all files under the current directory::
2935 2935
2936 2936 hg files .
2937 2937
2938 2938 - shows sizes and flags for current revision::
2939 2939
2940 2940 hg files -vr .
2941 2941
2942 2942 - list all files named README::
2943 2943
2944 2944 hg files -I "**/README"
2945 2945
2946 2946 - list all binary files::
2947 2947
2948 2948 hg files "set:binary()"
2949 2949
2950 2950 - find files containing a regular expression::
2951 2951
2952 2952 hg files "set:grep('bob')"
2953 2953
2954 2954 - search tracked file contents with xargs and grep::
2955 2955
2956 2956 hg files -0 | xargs -0 grep foo
2957 2957
2958 2958 See :hg:`help patterns` and :hg:`help filesets` for more information
2959 2959 on specifying file patterns.
2960 2960
2961 2961 Returns 0 if a match is found, 1 otherwise.
2962 2962
2963 2963 """
2964 2964
2965 2965 opts = pycompat.byteskwargs(opts)
2966 2966 rev = opts.get(b'rev')
2967 2967 if rev:
2968 2968 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2969 2969 ctx = logcmdutil.revsingle(repo, rev, None)
2970 2970
2971 2971 end = b'\n'
2972 2972 if opts.get(b'print0'):
2973 2973 end = b'\0'
2974 2974 fmt = b'%s' + end
2975 2975
2976 2976 m = scmutil.match(ctx, pats, opts)
2977 2977 ui.pager(b'files')
2978 2978 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2979 2979 with ui.formatter(b'files', opts) as fm:
2980 2980 return cmdutil.files(
2981 2981 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2982 2982 )
2983 2983
2984 2984
2985 2985 @command(
2986 2986 b'forget',
2987 2987 [
2988 2988 (b'i', b'interactive', None, _(b'use interactive mode')),
2989 2989 ]
2990 2990 + walkopts
2991 2991 + dryrunopts,
2992 2992 _(b'[OPTION]... FILE...'),
2993 2993 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2994 2994 helpbasic=True,
2995 2995 inferrepo=True,
2996 2996 )
2997 2997 def forget(ui, repo, *pats, **opts):
2998 2998 """forget the specified files on the next commit
2999 2999
3000 3000 Mark the specified files so they will no longer be tracked
3001 3001 after the next commit.
3002 3002
3003 3003 This only removes files from the current branch, not from the
3004 3004 entire project history, and it does not delete them from the
3005 3005 working directory.
3006 3006
3007 3007 To delete the file from the working directory, see :hg:`remove`.
3008 3008
3009 3009 To undo a forget before the next commit, see :hg:`add`.
3010 3010
3011 3011 .. container:: verbose
3012 3012
3013 3013 Examples:
3014 3014
3015 3015 - forget newly-added binary files::
3016 3016
3017 3017 hg forget "set:added() and binary()"
3018 3018
3019 3019 - forget files that would be excluded by .hgignore::
3020 3020
3021 3021 hg forget "set:hgignore()"
3022 3022
3023 3023 Returns 0 on success.
3024 3024 """
3025 3025
3026 3026 if not pats:
3027 3027 raise error.InputError(_(b'no files specified'))
3028 3028
3029 3029 with repo.wlock(), repo.dirstate.changing_files(repo):
3030 3030 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
3031 3031 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
3032 3032 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
3033 3033 rejected = cmdutil.forget(
3034 3034 ui,
3035 3035 repo,
3036 3036 m,
3037 3037 prefix=b"",
3038 3038 uipathfn=uipathfn,
3039 3039 explicitonly=False,
3040 3040 dryrun=dryrun,
3041 3041 interactive=interactive,
3042 3042 )[0]
3043 3043 return rejected and 1 or 0
3044 3044
3045 3045
3046 3046 @command(
3047 3047 b'graft',
3048 3048 [
3049 3049 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
3050 3050 (
3051 3051 b'',
3052 3052 b'base',
3053 3053 b'',
3054 3054 _(b'base revision when doing the graft merge (ADVANCED)'),
3055 3055 _(b'REV'),
3056 3056 ),
3057 3057 (b'c', b'continue', False, _(b'resume interrupted graft')),
3058 3058 (b'', b'stop', False, _(b'stop interrupted graft')),
3059 3059 (b'', b'abort', False, _(b'abort interrupted graft')),
3060 3060 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3061 3061 (b'', b'log', None, _(b'append graft info to log message')),
3062 3062 (
3063 3063 b'',
3064 3064 b'no-commit',
3065 3065 None,
3066 3066 _(b"don't commit, just apply the changes in working directory"),
3067 3067 ),
3068 3068 (b'f', b'force', False, _(b'force graft')),
3069 3069 (
3070 3070 b'D',
3071 3071 b'currentdate',
3072 3072 False,
3073 3073 _(b'record the current date as commit date'),
3074 3074 ),
3075 3075 (
3076 3076 b'U',
3077 3077 b'currentuser',
3078 3078 False,
3079 3079 _(b'record the current user as committer'),
3080 3080 ),
3081 3081 ]
3082 3082 + commitopts2
3083 3083 + mergetoolopts
3084 3084 + dryrunopts,
3085 3085 _(b'[OPTION]... [-r REV]... REV...'),
3086 3086 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
3087 3087 )
3088 3088 def graft(ui, repo, *revs, **opts):
3089 3089 """copy changes from other branches onto the current branch
3090 3090
3091 3091 This command uses Mercurial's merge logic to copy individual
3092 3092 changes from other branches without merging branches in the
3093 3093 history graph. This is sometimes known as 'backporting' or
3094 3094 'cherry-picking'. By default, graft will copy user, date, and
3095 3095 description from the source changesets.
3096 3096
3097 3097 Changesets that are ancestors of the current revision, that have
3098 3098 already been grafted, or that are merges will be skipped.
3099 3099
3100 3100 If --log is specified, log messages will have a comment appended
3101 3101 of the form::
3102 3102
3103 3103 (grafted from CHANGESETHASH)
3104 3104
3105 3105 If --force is specified, revisions will be grafted even if they
3106 3106 are already ancestors of, or have been grafted to, the destination.
3107 3107 This is useful when the revisions have since been backed out.
3108 3108
3109 3109 If a graft merge results in conflicts, the graft process is
3110 3110 interrupted so that the current merge can be manually resolved.
3111 3111 Once all conflicts are addressed, the graft process can be
3112 3112 continued with the -c/--continue option.
3113 3113
3114 3114 The -c/--continue option reapplies all the earlier options.
3115 3115
3116 3116 .. container:: verbose
3117 3117
3118 3118 The --base option exposes more of how graft internally uses merge with a
3119 3119 custom base revision. --base can be used to specify another ancestor than
3120 3120 the first and only parent.
3121 3121
3122 3122 The command::
3123 3123
3124 3124 hg graft -r 345 --base 234
3125 3125
3126 3126 is thus pretty much the same as::
3127 3127
3128 3128 hg diff --from 234 --to 345 | hg import
3129 3129
3130 3130 but using merge to resolve conflicts and track moved files.
3131 3131
3132 3132 The result of a merge can thus be backported as a single commit by
3133 3133 specifying one of the merge parents as base, and thus effectively
3134 3134 grafting the changes from the other side.
3135 3135
3136 3136 It is also possible to collapse multiple changesets and clean up history
3137 3137 by specifying another ancestor as base, much like rebase --collapse
3138 3138 --keep.
3139 3139
3140 3140 The commit message can be tweaked after the fact using commit --amend .
3141 3141
3142 3142 For using non-ancestors as the base to backout changes, see the backout
3143 3143 command and the hidden --parent option.
3144 3144
3145 3145 .. container:: verbose
3146 3146
3147 3147 Examples:
3148 3148
3149 3149 - copy a single change to the stable branch and edit its description::
3150 3150
3151 3151 hg update stable
3152 3152 hg graft --edit 9393
3153 3153
3154 3154 - graft a range of changesets with one exception, updating dates::
3155 3155
3156 3156 hg graft -D "2085::2093 and not 2091"
3157 3157
3158 3158 - continue a graft after resolving conflicts::
3159 3159
3160 3160 hg graft -c
3161 3161
3162 3162 - show the source of a grafted changeset::
3163 3163
3164 3164 hg log --debug -r .
3165 3165
3166 3166 - show revisions sorted by date::
3167 3167
3168 3168 hg log -r "sort(all(), date)"
3169 3169
3170 3170 - backport the result of a merge as a single commit::
3171 3171
3172 3172 hg graft -r 123 --base 123^
3173 3173
3174 3174 - land a feature branch as one changeset::
3175 3175
3176 3176 hg up -cr default
3177 3177 hg graft -r featureX --base "ancestor('featureX', 'default')"
3178 3178
3179 3179 See :hg:`help revisions` for more about specifying revisions.
3180 3180
3181 3181 Returns 0 on successful completion, 1 if there are unresolved files.
3182 3182 """
3183 3183 with repo.wlock():
3184 3184 return _dograft(ui, repo, *revs, **opts)
3185 3185
3186 3186
3187 3187 def _dograft(ui, repo, *revs, **opts):
3188 3188 if revs and opts.get('rev'):
3189 3189 ui.warn(
3190 3190 _(
3191 3191 b'warning: inconsistent use of --rev might give unexpected '
3192 3192 b'revision ordering!\n'
3193 3193 )
3194 3194 )
3195 3195
3196 3196 revs = list(revs)
3197 3197 revs.extend(opts.get('rev'))
3198 3198 # a dict of data to be stored in state file
3199 3199 statedata = {}
3200 3200 # list of new nodes created by ongoing graft
3201 3201 statedata[b'newnodes'] = []
3202 3202
3203 3203 cmdutil.resolve_commit_options(ui, opts)
3204 3204
3205 3205 editor = cmdutil.getcommiteditor(editform=b'graft', **opts)
3206 3206
3207 3207 cmdutil.check_at_most_one_arg(opts, 'abort', 'stop', 'continue')
3208 3208
3209 3209 cont = False
3210 3210 if opts.get('no_commit'):
3211 3211 cmdutil.check_incompatible_arguments(
3212 3212 opts,
3213 3213 'no_commit',
3214 3214 ['edit', 'currentuser', 'currentdate', 'log'],
3215 3215 )
3216 3216
3217 3217 graftstate = statemod.cmdstate(repo, b'graftstate')
3218 3218
3219 3219 if opts.get('stop'):
3220 3220 cmdutil.check_incompatible_arguments(
3221 3221 opts,
3222 3222 'stop',
3223 3223 [
3224 3224 'edit',
3225 3225 'log',
3226 3226 'user',
3227 3227 'date',
3228 3228 'currentdate',
3229 3229 'currentuser',
3230 3230 'rev',
3231 3231 ],
3232 3232 )
3233 3233 return _stopgraft(ui, repo, graftstate)
3234 3234 elif opts.get('abort'):
3235 3235 cmdutil.check_incompatible_arguments(
3236 3236 opts,
3237 3237 'abort',
3238 3238 [
3239 3239 'edit',
3240 3240 'log',
3241 3241 'user',
3242 3242 'date',
3243 3243 'currentdate',
3244 3244 'currentuser',
3245 3245 'rev',
3246 3246 ],
3247 3247 )
3248 3248 return cmdutil.abortgraft(ui, repo, graftstate)
3249 3249 elif opts.get('continue'):
3250 3250 cont = True
3251 3251 if revs:
3252 3252 raise error.InputError(_(b"can't specify --continue and revisions"))
3253 3253 # read in unfinished revisions
3254 3254 if graftstate.exists():
3255 3255 statedata = cmdutil.readgraftstate(repo, graftstate)
3256 3256 if statedata.get(b'date'):
3257 3257 opts['date'] = statedata[b'date']
3258 3258 if statedata.get(b'user'):
3259 3259 opts['user'] = statedata[b'user']
3260 3260 if statedata.get(b'log'):
3261 3261 opts['log'] = True
3262 3262 if statedata.get(b'no_commit'):
3263 3263 opts['no_commit'] = statedata.get(b'no_commit')
3264 3264 if statedata.get(b'base'):
3265 3265 opts['base'] = statedata.get(b'base')
3266 3266 nodes = statedata[b'nodes']
3267 3267 revs = [repo[node].rev() for node in nodes]
3268 3268 else:
3269 3269 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3270 3270 else:
3271 3271 if not revs:
3272 3272 raise error.InputError(_(b'no revisions specified'))
3273 3273 cmdutil.checkunfinished(repo)
3274 3274 cmdutil.bailifchanged(repo)
3275 3275 revs = logcmdutil.revrange(repo, revs)
3276 3276
3277 3277 skipped = set()
3278 3278 basectx = None
3279 3279 if opts.get('base'):
3280 3280 basectx = logcmdutil.revsingle(repo, opts['base'], None)
3281 3281 if basectx is None:
3282 3282 # check for merges
3283 3283 for rev in repo.revs(b'%ld and merge()', revs):
3284 3284 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3285 3285 skipped.add(rev)
3286 3286 revs = [r for r in revs if r not in skipped]
3287 3287 if not revs:
3288 3288 return -1
3289 3289 if basectx is not None and len(revs) != 1:
3290 3290 raise error.InputError(_(b'only one revision allowed with --base '))
3291 3291
3292 3292 # Don't check in the --continue case, in effect retaining --force across
3293 3293 # --continues. That's because without --force, any revisions we decided to
3294 3294 # skip would have been filtered out here, so they wouldn't have made their
3295 3295 # way to the graftstate. With --force, any revisions we would have otherwise
3296 3296 # skipped would not have been filtered out, and if they hadn't been applied
3297 3297 # already, they'd have been in the graftstate.
3298 3298 if not (cont or opts.get('force')) and basectx is None:
3299 3299 # check for ancestors of dest branch
3300 3300 ancestors = repo.revs(b'%ld & (::.)', revs)
3301 3301 for rev in ancestors:
3302 3302 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3303 3303
3304 3304 revs = [r for r in revs if r not in ancestors]
3305 3305
3306 3306 if not revs:
3307 3307 return -1
3308 3308
3309 3309 # analyze revs for earlier grafts
3310 3310 ids = {}
3311 3311 for ctx in repo.set(b"%ld", revs):
3312 3312 ids[ctx.hex()] = ctx.rev()
3313 3313 n = ctx.extra().get(b'source')
3314 3314 if n:
3315 3315 ids[n] = ctx.rev()
3316 3316
3317 3317 # check ancestors for earlier grafts
3318 3318 ui.debug(b'scanning for duplicate grafts\n')
3319 3319
3320 3320 # The only changesets we can be sure doesn't contain grafts of any
3321 3321 # revs, are the ones that are common ancestors of *all* revs:
3322 3322 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3323 3323 ctx = repo[rev]
3324 3324 n = ctx.extra().get(b'source')
3325 3325 if n in ids:
3326 3326 try:
3327 3327 r = repo[n].rev()
3328 3328 except error.RepoLookupError:
3329 3329 r = None
3330 3330 if r in revs:
3331 3331 ui.warn(
3332 3332 _(
3333 3333 b'skipping revision %d:%s '
3334 3334 b'(already grafted to %d:%s)\n'
3335 3335 )
3336 3336 % (r, repo[r], rev, ctx)
3337 3337 )
3338 3338 revs.remove(r)
3339 3339 elif ids[n] in revs:
3340 3340 if r is None:
3341 3341 ui.warn(
3342 3342 _(
3343 3343 b'skipping already grafted revision %d:%s '
3344 3344 b'(%d:%s also has unknown origin %s)\n'
3345 3345 )
3346 3346 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3347 3347 )
3348 3348 else:
3349 3349 ui.warn(
3350 3350 _(
3351 3351 b'skipping already grafted revision %d:%s '
3352 3352 b'(%d:%s also has origin %d:%s)\n'
3353 3353 )
3354 3354 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3355 3355 )
3356 3356 revs.remove(ids[n])
3357 3357 elif ctx.hex() in ids:
3358 3358 r = ids[ctx.hex()]
3359 3359 if r in revs:
3360 3360 ui.warn(
3361 3361 _(
3362 3362 b'skipping already grafted revision %d:%s '
3363 3363 b'(was grafted from %d:%s)\n'
3364 3364 )
3365 3365 % (r, repo[r], rev, ctx)
3366 3366 )
3367 3367 revs.remove(r)
3368 3368 if not revs:
3369 3369 return -1
3370 3370
3371 3371 if opts.get('no_commit'):
3372 3372 statedata[b'no_commit'] = True
3373 3373 if opts.get('base'):
3374 3374 statedata[b'base'] = opts['base']
3375 3375 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3376 3376 desc = b'%d:%s "%s"' % (
3377 3377 ctx.rev(),
3378 3378 ctx,
3379 3379 ctx.description().split(b'\n', 1)[0],
3380 3380 )
3381 3381 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3382 3382 if names:
3383 3383 desc += b' (%s)' % b' '.join(names)
3384 3384 ui.status(_(b'grafting %s\n') % desc)
3385 3385 if opts.get('dry_run'):
3386 3386 continue
3387 3387
3388 3388 source = ctx.extra().get(b'source')
3389 3389 extra = {}
3390 3390 if source:
3391 3391 extra[b'source'] = source
3392 3392 extra[b'intermediate-source'] = ctx.hex()
3393 3393 else:
3394 3394 extra[b'source'] = ctx.hex()
3395 3395 user = ctx.user()
3396 3396 if opts.get('user'):
3397 3397 user = opts['user']
3398 3398 statedata[b'user'] = user
3399 3399 date = ctx.date()
3400 3400 if opts.get('date'):
3401 3401 date = opts['date']
3402 3402 statedata[b'date'] = date
3403 3403 message = ctx.description()
3404 3404 if opts.get('log'):
3405 3405 message += b'\n(grafted from %s)' % ctx.hex()
3406 3406 statedata[b'log'] = True
3407 3407
3408 3408 # we don't merge the first commit when continuing
3409 3409 if not cont:
3410 3410 # perform the graft merge with p1(rev) as 'ancestor'
3411 3411 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
3412 3412 base = ctx.p1() if basectx is None else basectx
3413 3413 with ui.configoverride(overrides, b'graft'):
3414 3414 stats = mergemod.graft(
3415 3415 repo, ctx, base, [b'local', b'graft', b'parent of graft']
3416 3416 )
3417 3417 # report any conflicts
3418 3418 if stats.unresolvedcount > 0:
3419 3419 # write out state for --continue
3420 3420 nodes = [repo[rev].hex() for rev in revs[pos:]]
3421 3421 statedata[b'nodes'] = nodes
3422 3422 stateversion = 1
3423 3423 graftstate.save(stateversion, statedata)
3424 3424 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3425 3425 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3426 3426 return 1
3427 3427 else:
3428 3428 cont = False
3429 3429
3430 3430 # commit if --no-commit is false
3431 3431 if not opts.get('no_commit'):
3432 3432 node = repo.commit(
3433 3433 text=message, user=user, date=date, extra=extra, editor=editor
3434 3434 )
3435 3435 if node is None:
3436 3436 ui.warn(
3437 3437 _(b'note: graft of %d:%s created no changes to commit\n')
3438 3438 % (ctx.rev(), ctx)
3439 3439 )
3440 3440 # checking that newnodes exist because old state files won't have it
3441 3441 elif statedata.get(b'newnodes') is not None:
3442 3442 nn = statedata[b'newnodes']
3443 3443 assert isinstance(nn, list) # list of bytes
3444 3444 nn.append(node)
3445 3445
3446 3446 # remove state when we complete successfully
3447 3447 if not opts.get('dry_run'):
3448 3448 graftstate.delete()
3449 3449
3450 3450 return 0
3451 3451
3452 3452
3453 3453 def _stopgraft(ui, repo, graftstate):
3454 3454 """stop the interrupted graft"""
3455 3455 if not graftstate.exists():
3456 3456 raise error.StateError(_(b"no interrupted graft found"))
3457 3457 pctx = repo[b'.']
3458 3458 mergemod.clean_update(pctx)
3459 3459 graftstate.delete()
3460 3460 ui.status(_(b"stopped the interrupted graft\n"))
3461 3461 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3462 3462 return 0
3463 3463
3464 3464
3465 3465 statemod.addunfinished(
3466 3466 b'graft',
3467 3467 fname=b'graftstate',
3468 3468 clearable=True,
3469 3469 stopflag=True,
3470 3470 continueflag=True,
3471 3471 abortfunc=cmdutil.hgabortgraft,
3472 3472 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3473 3473 )
3474 3474
3475 3475
3476 3476 @command(
3477 3477 b'grep',
3478 3478 [
3479 3479 (b'0', b'print0', None, _(b'end fields with NUL')),
3480 3480 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3481 3481 (
3482 3482 b'',
3483 3483 b'diff',
3484 3484 None,
3485 3485 _(
3486 3486 b'search revision differences for when the pattern was added '
3487 3487 b'or removed'
3488 3488 ),
3489 3489 ),
3490 3490 (b'a', b'text', None, _(b'treat all files as text')),
3491 3491 (
3492 3492 b'f',
3493 3493 b'follow',
3494 3494 None,
3495 3495 _(
3496 3496 b'follow changeset history,'
3497 3497 b' or file history across copies and renames'
3498 3498 ),
3499 3499 ),
3500 3500 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3501 3501 (
3502 3502 b'l',
3503 3503 b'files-with-matches',
3504 3504 None,
3505 3505 _(b'print only filenames and revisions that match'),
3506 3506 ),
3507 3507 (b'n', b'line-number', None, _(b'print matching line numbers')),
3508 3508 (
3509 3509 b'r',
3510 3510 b'rev',
3511 3511 [],
3512 3512 _(b'search files changed within revision range'),
3513 3513 _(b'REV'),
3514 3514 ),
3515 3515 (
3516 3516 b'',
3517 3517 b'all-files',
3518 3518 None,
3519 3519 _(
3520 3520 b'include all files in the changeset while grepping (DEPRECATED)'
3521 3521 ),
3522 3522 ),
3523 3523 (b'u', b'user', None, _(b'list the author (long with -v)')),
3524 3524 (b'd', b'date', None, _(b'list the date (short with -q)')),
3525 3525 ]
3526 3526 + formatteropts
3527 3527 + walkopts,
3528 3528 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3529 3529 helpcategory=command.CATEGORY_FILE_CONTENTS,
3530 3530 inferrepo=True,
3531 3531 intents={INTENT_READONLY},
3532 3532 )
3533 3533 def grep(ui, repo, pattern, *pats, **opts):
3534 3534 """search for a pattern in specified files
3535 3535
3536 3536 Search the working directory or revision history for a regular
3537 3537 expression in the specified files for the entire repository.
3538 3538
3539 3539 By default, grep searches the repository files in the working
3540 3540 directory and prints the files where it finds a match. To specify
3541 3541 historical revisions instead of the working directory, use the
3542 3542 --rev flag.
3543 3543
3544 3544 To search instead historical revision differences that contains a
3545 3545 change in match status ("-" for a match that becomes a non-match,
3546 3546 or "+" for a non-match that becomes a match), use the --diff flag.
3547 3547
3548 3548 PATTERN can be any Python (roughly Perl-compatible) regular
3549 3549 expression.
3550 3550
3551 3551 If no FILEs are specified and the --rev flag isn't supplied, all
3552 3552 files in the working directory are searched. When using the --rev
3553 3553 flag and specifying FILEs, use the --follow argument to also
3554 3554 follow the specified FILEs across renames and copies.
3555 3555
3556 3556 .. container:: verbose
3557 3557
3558 3558 Template:
3559 3559
3560 3560 The following keywords are supported in addition to the common template
3561 3561 keywords and functions. See also :hg:`help templates`.
3562 3562
3563 3563 :change: String. Character denoting insertion ``+`` or removal ``-``.
3564 3564 Available if ``--diff`` is specified.
3565 3565 :lineno: Integer. Line number of the match.
3566 3566 :path: String. Repository-absolute path of the file.
3567 3567 :texts: List of text chunks.
3568 3568
3569 3569 And each entry of ``{texts}`` provides the following sub-keywords.
3570 3570
3571 3571 :matched: Boolean. True if the chunk matches the specified pattern.
3572 3572 :text: String. Chunk content.
3573 3573
3574 3574 See :hg:`help templates.operators` for the list expansion syntax.
3575 3575
3576 3576 Returns 0 if a match is found, 1 otherwise.
3577 3577
3578 3578 """
3579 3579 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3580 3580
3581 3581 diff = opts.get('all') or opts.get('diff')
3582 3582 follow = opts.get('follow')
3583 3583 if opts.get('all_files') is None and not diff:
3584 3584 opts['all_files'] = True
3585 3585 plaingrep = (
3586 3586 opts.get('all_files') and not opts.get('rev') and not opts.get('follow')
3587 3587 )
3588 3588 all_files = opts.get('all_files')
3589 3589 if plaingrep:
3590 3590 opts['rev'] = [b'wdir()']
3591 3591
3592 3592 reflags = re.M
3593 3593 if opts.get('ignore_case'):
3594 3594 reflags |= re.I
3595 3595 try:
3596 3596 regexp = util.re.compile(pattern, reflags)
3597 3597 except re.error as inst:
3598 3598 ui.warn(
3599 3599 _(b"grep: invalid match pattern: %s\n")
3600 3600 % stringutil.forcebytestr(inst)
3601 3601 )
3602 3602 return 1
3603 3603 sep, eol = b':', b'\n'
3604 3604 if opts.get('print0'):
3605 3605 sep = eol = b'\0'
3606 3606
3607 3607 searcher = grepmod.grepsearcher(
3608 3608 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3609 3609 )
3610 3610
3611 3611 getfile = searcher._getfile
3612 3612
3613 3613 uipathfn = scmutil.getuipathfn(repo)
3614 3614
3615 3615 def display(fm, fn, ctx, pstates, states):
3616 3616 rev = scmutil.intrev(ctx)
3617 3617 if fm.isplain():
3618 3618 formatuser = ui.shortuser
3619 3619 else:
3620 3620 formatuser = pycompat.bytestr
3621 3621 if ui.quiet:
3622 3622 datefmt = b'%Y-%m-%d'
3623 3623 else:
3624 3624 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3625 3625 found = False
3626 3626
3627 3627 @util.cachefunc
3628 3628 def binary():
3629 3629 flog = getfile(fn)
3630 3630 try:
3631 3631 return stringutil.binary(flog.read(ctx.filenode(fn)))
3632 3632 except error.WdirUnsupported:
3633 3633 return ctx[fn].isbinary()
3634 3634
3635 3635 fieldnamemap = {b'linenumber': b'lineno'}
3636 3636 if diff:
3637 3637 iter = grepmod.difflinestates(pstates, states)
3638 3638 else:
3639 3639 iter = [(b'', l) for l in states]
3640 3640 for change, l in iter:
3641 3641 fm.startitem()
3642 3642 fm.context(ctx=ctx)
3643 3643 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3644 3644 fm.plain(uipathfn(fn), label=b'grep.filename')
3645 3645
3646 3646 cols = [
3647 3647 (b'rev', b'%d', rev, not plaingrep, b''),
3648 3648 (
3649 3649 b'linenumber',
3650 3650 b'%d',
3651 3651 l.linenum,
3652 3652 opts.get('line_number'),
3653 3653 b'',
3654 3654 ),
3655 3655 ]
3656 3656 if diff:
3657 3657 cols.append(
3658 3658 (
3659 3659 b'change',
3660 3660 b'%s',
3661 3661 change,
3662 3662 True,
3663 3663 b'grep.inserted '
3664 3664 if change == b'+'
3665 3665 else b'grep.deleted ',
3666 3666 )
3667 3667 )
3668 3668 cols.extend(
3669 3669 [
3670 3670 (
3671 3671 b'user',
3672 3672 b'%s',
3673 3673 formatuser(ctx.user()),
3674 3674 opts.get('user'),
3675 3675 b'',
3676 3676 ),
3677 3677 (
3678 3678 b'date',
3679 3679 b'%s',
3680 3680 fm.formatdate(ctx.date(), datefmt),
3681 3681 opts.get('date'),
3682 3682 b'',
3683 3683 ),
3684 3684 ]
3685 3685 )
3686 3686 for name, fmt, data, cond, extra_label in cols:
3687 3687 if cond:
3688 3688 fm.plain(sep, label=b'grep.sep')
3689 3689 field = fieldnamemap.get(name, name)
3690 3690 label = extra_label + (b'grep.%s' % name)
3691 3691 fm.condwrite(cond, field, fmt, data, label=label)
3692 3692 if not opts.get('files_with_matches'):
3693 3693 fm.plain(sep, label=b'grep.sep')
3694 3694 if not opts.get('text') and binary():
3695 3695 fm.plain(_(b" Binary file matches"))
3696 3696 else:
3697 3697 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3698 3698 fm.plain(eol)
3699 3699 found = True
3700 3700 if opts.get('files_with_matches'):
3701 3701 break
3702 3702 return found
3703 3703
3704 3704 def displaymatches(fm, l):
3705 3705 p = 0
3706 3706 for s, e in l.findpos(regexp):
3707 3707 if p < s:
3708 3708 fm.startitem()
3709 3709 fm.write(b'text', b'%s', l.line[p:s])
3710 3710 fm.data(matched=False)
3711 3711 fm.startitem()
3712 3712 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3713 3713 fm.data(matched=True)
3714 3714 p = e
3715 3715 if p < len(l.line):
3716 3716 fm.startitem()
3717 3717 fm.write(b'text', b'%s', l.line[p:])
3718 3718 fm.data(matched=False)
3719 3719 fm.end()
3720 3720
3721 3721 found = False
3722 3722
3723 3723 wopts = logcmdutil.walkopts(
3724 3724 pats=pats,
3725 3725 opts=pycompat.byteskwargs(opts),
3726 3726 revspec=opts['rev'],
3727 3727 include_pats=opts['include'],
3728 3728 exclude_pats=opts['exclude'],
3729 3729 follow=follow,
3730 3730 force_changelog_traversal=all_files,
3731 3731 filter_revisions_by_pats=not all_files,
3732 3732 )
3733 3733 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3734 3734
3735 3735 ui.pager(b'grep')
3736 3736 fm = ui.formatter(b'grep', pycompat.byteskwargs(opts))
3737 3737 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3738 3738 r = display(fm, fn, ctx, pstates, states)
3739 3739 found = found or r
3740 3740 if r and not diff and not all_files:
3741 3741 searcher.skipfile(fn, ctx.rev())
3742 3742 fm.end()
3743 3743
3744 3744 return not found
3745 3745
3746 3746
3747 3747 @command(
3748 3748 b'heads',
3749 3749 [
3750 3750 (
3751 3751 b'r',
3752 3752 b'rev',
3753 3753 b'',
3754 3754 _(b'show only heads which are descendants of STARTREV'),
3755 3755 _(b'STARTREV'),
3756 3756 ),
3757 3757 (b't', b'topo', False, _(b'show topological heads only')),
3758 3758 (
3759 3759 b'a',
3760 3760 b'active',
3761 3761 False,
3762 3762 _(b'show active branchheads only (DEPRECATED)'),
3763 3763 ),
3764 3764 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3765 3765 ]
3766 3766 + templateopts,
3767 3767 _(b'[-ct] [-r STARTREV] [REV]...'),
3768 3768 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3769 3769 intents={INTENT_READONLY},
3770 3770 )
3771 3771 def heads(ui, repo, *branchrevs, **opts):
3772 3772 """show branch heads
3773 3773
3774 3774 With no arguments, show all open branch heads in the repository.
3775 3775 Branch heads are changesets that have no descendants on the
3776 3776 same branch. They are where development generally takes place and
3777 3777 are the usual targets for update and merge operations.
3778 3778
3779 3779 If one or more REVs are given, only open branch heads on the
3780 3780 branches associated with the specified changesets are shown. This
3781 3781 means that you can use :hg:`heads .` to see the heads on the
3782 3782 currently checked-out branch.
3783 3783
3784 3784 If -c/--closed is specified, also show branch heads marked closed
3785 3785 (see :hg:`commit --close-branch`).
3786 3786
3787 3787 If STARTREV is specified, only those heads that are descendants of
3788 3788 STARTREV will be displayed.
3789 3789
3790 3790 If -t/--topo is specified, named branch mechanics will be ignored and only
3791 3791 topological heads (changesets with no children) will be shown.
3792 3792
3793 3793 Returns 0 if matching heads are found, 1 if not.
3794 3794 """
3795 3795
3796 3796 start = None
3797 3797 rev = opts.get('rev')
3798 3798 if rev:
3799 3799 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3800 3800 start = logcmdutil.revsingle(repo, rev, None).node()
3801 3801
3802 3802 if opts.get('topo'):
3803 3803 heads = [repo[h] for h in repo.heads(start)]
3804 3804 else:
3805 3805 heads = []
3806 3806 for branch in repo.branchmap():
3807 3807 heads += repo.branchheads(branch, start, opts.get('closed'))
3808 3808 heads = [repo[h] for h in heads]
3809 3809
3810 3810 if branchrevs:
3811 3811 branches = {
3812 3812 repo[r].branch() for r in logcmdutil.revrange(repo, branchrevs)
3813 3813 }
3814 3814 heads = [h for h in heads if h.branch() in branches]
3815 3815
3816 3816 if opts.get('active') and branchrevs:
3817 3817 dagheads = repo.heads(start)
3818 3818 heads = [h for h in heads if h.node() in dagheads]
3819 3819
3820 3820 if branchrevs:
3821 3821 haveheads = {h.branch() for h in heads}
3822 3822 if branches - haveheads:
3823 3823 headless = b', '.join(b for b in branches - haveheads)
3824 3824 msg = _(b'no open branch heads found on branches %s')
3825 3825 if opts.get('rev'):
3826 3826 msg += _(b' (started at %s)') % opts['rev']
3827 3827 ui.warn((msg + b'\n') % headless)
3828 3828
3829 3829 if not heads:
3830 3830 return 1
3831 3831
3832 3832 ui.pager(b'heads')
3833 3833 heads = sorted(heads, key=lambda x: -(x.rev()))
3834 3834 displayer = logcmdutil.changesetdisplayer(
3835 3835 ui, repo, pycompat.byteskwargs(opts)
3836 3836 )
3837 3837 for ctx in heads:
3838 3838 displayer.show(ctx)
3839 3839 displayer.close()
3840 3840
3841 3841
3842 3842 @command(
3843 3843 b'help',
3844 3844 [
3845 3845 (b'e', b'extension', None, _(b'show only help for extensions')),
3846 3846 (b'c', b'command', None, _(b'show only help for commands')),
3847 3847 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3848 3848 (
3849 3849 b's',
3850 3850 b'system',
3851 3851 [],
3852 3852 _(b'show help for specific platform(s)'),
3853 3853 _(b'PLATFORM'),
3854 3854 ),
3855 3855 ],
3856 3856 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3857 3857 helpcategory=command.CATEGORY_HELP,
3858 3858 norepo=True,
3859 3859 intents={INTENT_READONLY},
3860 3860 )
3861 3861 def help_(ui, name=None, **opts):
3862 3862 """show help for a given topic or a help overview
3863 3863
3864 3864 With no arguments, print a list of commands with short help messages.
3865 3865
3866 3866 Given a topic, extension, or command name, print help for that
3867 3867 topic.
3868 3868
3869 3869 Returns 0 if successful.
3870 3870 """
3871 3871
3872 3872 keep = opts.get('system') or []
3873 3873 if len(keep) == 0:
3874 3874 if pycompat.sysplatform.startswith(b'win'):
3875 3875 keep.append(b'windows')
3876 3876 elif pycompat.sysplatform == b'OpenVMS':
3877 3877 keep.append(b'vms')
3878 3878 elif pycompat.sysplatform == b'plan9':
3879 3879 keep.append(b'plan9')
3880 3880 else:
3881 3881 keep.append(b'unix')
3882 3882 keep.append(pycompat.sysplatform.lower())
3883 3883 if ui.verbose:
3884 3884 keep.append(b'verbose')
3885 3885
3886 3886 commands = sys.modules[__name__]
3887 3887 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3888 3888 ui.pager(b'help')
3889 3889 ui.write(formatted)
3890 3890
3891 3891
3892 3892 @command(
3893 3893 b'identify|id',
3894 3894 [
3895 3895 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3896 3896 (b'n', b'num', None, _(b'show local revision number')),
3897 3897 (b'i', b'id', None, _(b'show global revision id')),
3898 3898 (b'b', b'branch', None, _(b'show branch')),
3899 3899 (b't', b'tags', None, _(b'show tags')),
3900 3900 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3901 3901 ]
3902 3902 + remoteopts
3903 3903 + formatteropts,
3904 3904 _(b'[-nibtB] [-r REV] [SOURCE]'),
3905 3905 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3906 3906 optionalrepo=True,
3907 3907 intents={INTENT_READONLY},
3908 3908 )
3909 3909 def identify(
3910 3910 ui,
3911 3911 repo,
3912 3912 source=None,
3913 3913 rev=None,
3914 3914 num=None,
3915 3915 id=None,
3916 3916 branch=None,
3917 3917 tags=None,
3918 3918 bookmarks=None,
3919 3919 **opts
3920 3920 ):
3921 3921 """identify the working directory or specified revision
3922 3922
3923 3923 Print a summary identifying the repository state at REV using one or
3924 3924 two parent hash identifiers, followed by a "+" if the working
3925 3925 directory has uncommitted changes, the branch name (if not default),
3926 3926 a list of tags, and a list of bookmarks.
3927 3927
3928 3928 When REV is not given, print a summary of the current state of the
3929 3929 repository including the working directory. Specify -r. to get information
3930 3930 of the working directory parent without scanning uncommitted changes.
3931 3931
3932 3932 Specifying a path to a repository root or Mercurial bundle will
3933 3933 cause lookup to operate on that repository/bundle.
3934 3934
3935 3935 .. container:: verbose
3936 3936
3937 3937 Template:
3938 3938
3939 3939 The following keywords are supported in addition to the common template
3940 3940 keywords and functions. See also :hg:`help templates`.
3941 3941
3942 3942 :dirty: String. Character ``+`` denoting if the working directory has
3943 3943 uncommitted changes.
3944 3944 :id: String. One or two nodes, optionally followed by ``+``.
3945 3945 :parents: List of strings. Parent nodes of the changeset.
3946 3946
3947 3947 Examples:
3948 3948
3949 3949 - generate a build identifier for the working directory::
3950 3950
3951 3951 hg id --id > build-id.dat
3952 3952
3953 3953 - find the revision corresponding to a tag::
3954 3954
3955 3955 hg id -n -r 1.3
3956 3956
3957 3957 - check the most recent revision of a remote repository::
3958 3958
3959 3959 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3960 3960
3961 3961 See :hg:`log` for generating more information about specific revisions,
3962 3962 including full hash identifiers.
3963 3963
3964 3964 Returns 0 if successful.
3965 3965 """
3966 3966
3967 3967 opts = pycompat.byteskwargs(opts)
3968 3968 if not repo and not source:
3969 3969 raise error.InputError(
3970 3970 _(b"there is no Mercurial repository here (.hg not found)")
3971 3971 )
3972 3972
3973 3973 default = not (num or id or branch or tags or bookmarks)
3974 3974 output = []
3975 3975 revs = []
3976 3976
3977 3977 peer = None
3978 3978 try:
3979 3979 if source:
3980 3980 path = urlutil.get_unique_pull_path_obj(b'identify', ui, source)
3981 3981 # only pass ui when no repo
3982 3982 peer = hg.peer(repo or ui, opts, path)
3983 3983 repo = peer.local()
3984 3984 branches = (path.branch, [])
3985 3985 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3986 3986
3987 3987 fm = ui.formatter(b'identify', opts)
3988 3988 fm.startitem()
3989 3989
3990 3990 if not repo:
3991 3991 if num or branch or tags:
3992 3992 raise error.InputError(
3993 3993 _(b"can't query remote revision number, branch, or tags")
3994 3994 )
3995 3995 if not rev and revs:
3996 3996 rev = revs[0]
3997 3997 if not rev:
3998 3998 rev = b"tip"
3999 3999
4000 4000 remoterev = peer.lookup(rev)
4001 4001 hexrev = fm.hexfunc(remoterev)
4002 4002 if default or id:
4003 4003 output = [hexrev]
4004 4004 fm.data(id=hexrev)
4005 4005
4006 4006 @util.cachefunc
4007 4007 def getbms():
4008 4008 bms = []
4009 4009
4010 4010 if b'bookmarks' in peer.listkeys(b'namespaces'):
4011 4011 hexremoterev = hex(remoterev)
4012 4012 bms = [
4013 4013 bm
4014 4014 for bm, bmr in peer.listkeys(b'bookmarks').items()
4015 4015 if bmr == hexremoterev
4016 4016 ]
4017 4017
4018 4018 return sorted(bms)
4019 4019
4020 4020 if fm.isplain():
4021 4021 if bookmarks:
4022 4022 output.extend(getbms())
4023 4023 elif default and not ui.quiet:
4024 4024 # multiple bookmarks for a single parent separated by '/'
4025 4025 bm = b'/'.join(getbms())
4026 4026 if bm:
4027 4027 output.append(bm)
4028 4028 else:
4029 4029 fm.data(node=hex(remoterev))
4030 4030 if bookmarks or b'bookmarks' in fm.datahint():
4031 4031 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
4032 4032 else:
4033 4033 if rev:
4034 4034 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
4035 4035 ctx = logcmdutil.revsingle(repo, rev, None)
4036 4036
4037 4037 if ctx.rev() is None:
4038 4038 ctx = repo[None]
4039 4039 parents = ctx.parents()
4040 4040 taglist = []
4041 4041 for p in parents:
4042 4042 taglist.extend(p.tags())
4043 4043
4044 4044 dirty = b""
4045 4045 if ctx.dirty(missing=True, merge=False, branch=False):
4046 4046 dirty = b'+'
4047 4047 fm.data(dirty=dirty)
4048 4048
4049 4049 hexoutput = [fm.hexfunc(p.node()) for p in parents]
4050 4050 if default or id:
4051 4051 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
4052 4052 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
4053 4053
4054 4054 if num:
4055 4055 numoutput = [b"%d" % p.rev() for p in parents]
4056 4056 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
4057 4057
4058 4058 fm.data(
4059 4059 parents=fm.formatlist(
4060 4060 [fm.hexfunc(p.node()) for p in parents], name=b'node'
4061 4061 )
4062 4062 )
4063 4063 else:
4064 4064 hexoutput = fm.hexfunc(ctx.node())
4065 4065 if default or id:
4066 4066 output = [hexoutput]
4067 4067 fm.data(id=hexoutput)
4068 4068
4069 4069 if num:
4070 4070 output.append(pycompat.bytestr(ctx.rev()))
4071 4071 taglist = ctx.tags()
4072 4072
4073 4073 if default and not ui.quiet:
4074 4074 b = ctx.branch()
4075 4075 if b != b'default':
4076 4076 output.append(b"(%s)" % b)
4077 4077
4078 4078 # multiple tags for a single parent separated by '/'
4079 4079 t = b'/'.join(taglist)
4080 4080 if t:
4081 4081 output.append(t)
4082 4082
4083 4083 # multiple bookmarks for a single parent separated by '/'
4084 4084 bm = b'/'.join(ctx.bookmarks())
4085 4085 if bm:
4086 4086 output.append(bm)
4087 4087 else:
4088 4088 if branch:
4089 4089 output.append(ctx.branch())
4090 4090
4091 4091 if tags:
4092 4092 output.extend(taglist)
4093 4093
4094 4094 if bookmarks:
4095 4095 output.extend(ctx.bookmarks())
4096 4096
4097 4097 fm.data(node=ctx.hex())
4098 4098 fm.data(branch=ctx.branch())
4099 4099 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
4100 4100 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4101 4101 fm.context(ctx=ctx)
4102 4102
4103 4103 fm.plain(b"%s\n" % b' '.join(output))
4104 4104 fm.end()
4105 4105 finally:
4106 4106 if peer:
4107 4107 peer.close()
4108 4108
4109 4109
4110 4110 @command(
4111 4111 b'import|patch',
4112 4112 [
4113 4113 (
4114 4114 b'p',
4115 4115 b'strip',
4116 4116 1,
4117 4117 _(
4118 4118 b'directory strip option for patch. This has the same '
4119 4119 b'meaning as the corresponding patch option'
4120 4120 ),
4121 4121 _(b'NUM'),
4122 4122 ),
4123 4123 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4124 4124 (b'', b'secret', None, _(b'use the secret phase for committing')),
4125 4125 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4126 4126 (
4127 4127 b'f',
4128 4128 b'force',
4129 4129 None,
4130 4130 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4131 4131 ),
4132 4132 (
4133 4133 b'',
4134 4134 b'no-commit',
4135 4135 None,
4136 4136 _(b"don't commit, just update the working directory"),
4137 4137 ),
4138 4138 (
4139 4139 b'',
4140 4140 b'bypass',
4141 4141 None,
4142 4142 _(b"apply patch without touching the working directory"),
4143 4143 ),
4144 4144 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4145 4145 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4146 4146 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4147 4147 (
4148 4148 b'',
4149 4149 b'import-branch',
4150 4150 None,
4151 4151 _(b'use any branch information in patch (implied by --exact)'),
4152 4152 ),
4153 4153 ]
4154 4154 + commitopts
4155 4155 + commitopts2
4156 4156 + similarityopts,
4157 4157 _(b'[OPTION]... PATCH...'),
4158 4158 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4159 4159 )
4160 4160 def import_(ui, repo, patch1=None, *patches, **opts):
4161 4161 """import an ordered set of patches
4162 4162
4163 4163 Import a list of patches and commit them individually (unless
4164 4164 --no-commit is specified).
4165 4165
4166 4166 To read a patch from standard input (stdin), use "-" as the patch
4167 4167 name. If a URL is specified, the patch will be downloaded from
4168 4168 there.
4169 4169
4170 4170 Import first applies changes to the working directory (unless
4171 4171 --bypass is specified), import will abort if there are outstanding
4172 4172 changes.
4173 4173
4174 4174 Use --bypass to apply and commit patches directly to the
4175 4175 repository, without affecting the working directory. Without
4176 4176 --exact, patches will be applied on top of the working directory
4177 4177 parent revision.
4178 4178
4179 4179 You can import a patch straight from a mail message. Even patches
4180 4180 as attachments work (to use the body part, it must have type
4181 4181 text/plain or text/x-patch). From and Subject headers of email
4182 4182 message are used as default committer and commit message. All
4183 4183 text/plain body parts before first diff are added to the commit
4184 4184 message.
4185 4185
4186 4186 If the imported patch was generated by :hg:`export`, user and
4187 4187 description from patch override values from message headers and
4188 4188 body. Values given on command line with -m/--message and -u/--user
4189 4189 override these.
4190 4190
4191 4191 If --exact is specified, import will set the working directory to
4192 4192 the parent of each patch before applying it, and will abort if the
4193 4193 resulting changeset has a different ID than the one recorded in
4194 4194 the patch. This will guard against various ways that portable
4195 4195 patch formats and mail systems might fail to transfer Mercurial
4196 4196 data or metadata. See :hg:`bundle` for lossless transmission.
4197 4197
4198 4198 Use --partial to ensure a changeset will be created from the patch
4199 4199 even if some hunks fail to apply. Hunks that fail to apply will be
4200 4200 written to a <target-file>.rej file. Conflicts can then be resolved
4201 4201 by hand before :hg:`commit --amend` is run to update the created
4202 4202 changeset. This flag exists to let people import patches that
4203 4203 partially apply without losing the associated metadata (author,
4204 4204 date, description, ...).
4205 4205
4206 4206 .. note::
4207 4207
4208 4208 When no hunks apply cleanly, :hg:`import --partial` will create
4209 4209 an empty changeset, importing only the patch metadata.
4210 4210
4211 4211 With -s/--similarity, hg will attempt to discover renames and
4212 4212 copies in the patch in the same way as :hg:`addremove`.
4213 4213
4214 4214 It is possible to use external patch programs to perform the patch
4215 4215 by setting the ``ui.patch`` configuration option. For the default
4216 4216 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4217 4217 See :hg:`help config` for more information about configuration
4218 4218 files and how to use these options.
4219 4219
4220 4220 See :hg:`help dates` for a list of formats valid for -d/--date.
4221 4221
4222 4222 .. container:: verbose
4223 4223
4224 4224 Examples:
4225 4225
4226 4226 - import a traditional patch from a website and detect renames::
4227 4227
4228 4228 hg import -s 80 http://example.com/bugfix.patch
4229 4229
4230 4230 - import a changeset from an hgweb server::
4231 4231
4232 4232 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4233 4233
4234 4234 - import all the patches in an Unix-style mbox::
4235 4235
4236 4236 hg import incoming-patches.mbox
4237 4237
4238 4238 - import patches from stdin::
4239 4239
4240 4240 hg import -
4241 4241
4242 4242 - attempt to exactly restore an exported changeset (not always
4243 4243 possible)::
4244 4244
4245 4245 hg import --exact proposed-fix.patch
4246 4246
4247 4247 - use an external tool to apply a patch which is too fuzzy for
4248 4248 the default internal tool.
4249 4249
4250 4250 hg import --config ui.patch="patch --merge" fuzzy.patch
4251 4251
4252 4252 - change the default fuzzing from 2 to a less strict 7
4253 4253
4254 4254 hg import --config ui.fuzz=7 fuzz.patch
4255 4255
4256 4256 Returns 0 on success, 1 on partial success (see --partial).
4257 4257 """
4258 4258
4259 4259 cmdutil.check_incompatible_arguments(
4260 4260 opts, 'no_commit', ['bypass', 'secret']
4261 4261 )
4262 4262 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
4263 4263
4264 4264 if not patch1:
4265 4265 raise error.InputError(_(b'need at least one patch to import'))
4266 4266
4267 4267 patches = (patch1,) + patches
4268 4268
4269 4269 date = opts.get('date')
4270 4270 if date:
4271 4271 opts['date'] = dateutil.parsedate(date)
4272 4272
4273 4273 exact = opts.get('exact')
4274 4274 update = not opts.get('bypass')
4275 4275 try:
4276 4276 sim = float(opts.get('similarity') or 0)
4277 4277 except ValueError:
4278 4278 raise error.InputError(_(b'similarity must be a number'))
4279 4279 if sim < 0 or sim > 100:
4280 4280 raise error.InputError(_(b'similarity must be between 0 and 100'))
4281 4281 if sim and not update:
4282 4282 raise error.InputError(_(b'cannot use --similarity with --bypass'))
4283 4283
4284 4284 base = opts["base"]
4285 4285 msgs = []
4286 4286 ret = 0
4287 4287
4288 4288 with repo.wlock():
4289 4289 if update:
4290 4290 cmdutil.checkunfinished(repo)
4291 4291 if exact or not opts.get('force'):
4292 4292 cmdutil.bailifchanged(repo)
4293 4293
4294 4294 if not opts.get('no_commit'):
4295 4295 lock = repo.lock
4296 4296 tr = lambda: repo.transaction(b'import')
4297 4297 else:
4298 4298 lock = util.nullcontextmanager
4299 4299 tr = util.nullcontextmanager
4300 4300 with lock(), tr():
4301 4301 parents = repo[None].parents()
4302 4302 for patchurl in patches:
4303 4303 if patchurl == b'-':
4304 4304 ui.status(_(b'applying patch from stdin\n'))
4305 4305 patchfile = ui.fin
4306 4306 patchurl = b'stdin' # for error message
4307 4307 else:
4308 4308 patchurl = os.path.join(base, patchurl)
4309 4309 ui.status(_(b'applying %s\n') % patchurl)
4310 4310 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4311 4311
4312 4312 haspatch = False
4313 4313 for hunk in patch.split(patchfile):
4314 4314 with patch.extract(ui, hunk) as patchdata:
4315 4315 msg, node, rej = cmdutil.tryimportone(
4316 4316 ui,
4317 4317 repo,
4318 4318 patchdata,
4319 4319 parents,
4320 4320 pycompat.byteskwargs(opts),
4321 4321 msgs,
4322 4322 hg.clean,
4323 4323 )
4324 4324 if msg:
4325 4325 haspatch = True
4326 4326 ui.note(msg + b'\n')
4327 4327 if update or exact:
4328 4328 parents = repo[None].parents()
4329 4329 else:
4330 4330 parents = [repo[node]]
4331 4331 if rej:
4332 4332 ui.write_err(_(b"patch applied partially\n"))
4333 4333 ui.write_err(
4334 4334 _(
4335 4335 b"(fix the .rej files and run "
4336 4336 b"`hg commit --amend`)\n"
4337 4337 )
4338 4338 )
4339 4339 ret = 1
4340 4340 break
4341 4341
4342 4342 if not haspatch:
4343 4343 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4344 4344
4345 4345 if msgs:
4346 4346 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4347 4347 return ret
4348 4348
4349 4349
4350 4350 @command(
4351 4351 b'incoming|in',
4352 4352 [
4353 4353 (
4354 4354 b'f',
4355 4355 b'force',
4356 4356 None,
4357 4357 _(b'run even if remote repository is unrelated'),
4358 4358 ),
4359 4359 (b'n', b'newest-first', None, _(b'show newest record first')),
4360 4360 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4361 4361 (
4362 4362 b'r',
4363 4363 b'rev',
4364 4364 [],
4365 4365 _(b'a remote changeset intended to be added'),
4366 4366 _(b'REV'),
4367 4367 ),
4368 4368 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4369 4369 (
4370 4370 b'b',
4371 4371 b'branch',
4372 4372 [],
4373 4373 _(b'a specific branch you would like to pull'),
4374 4374 _(b'BRANCH'),
4375 4375 ),
4376 4376 ]
4377 4377 + logopts
4378 4378 + remoteopts
4379 4379 + subrepoopts,
4380 4380 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4381 4381 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4382 4382 )
4383 4383 def incoming(ui, repo, source=b"default", **opts):
4384 4384 """show new changesets found in source
4385 4385
4386 4386 Show new changesets found in the specified path/URL or the default
4387 4387 pull location. These are the changesets that would have been pulled
4388 4388 by :hg:`pull` at the time you issued this command.
4389 4389
4390 4390 See pull for valid source format details.
4391 4391
4392 4392 .. container:: verbose
4393 4393
4394 4394 With -B/--bookmarks, the result of bookmark comparison between
4395 4395 local and remote repositories is displayed. With -v/--verbose,
4396 4396 status is also displayed for each bookmark like below::
4397 4397
4398 4398 BM1 01234567890a added
4399 4399 BM2 1234567890ab advanced
4400 4400 BM3 234567890abc diverged
4401 4401 BM4 34567890abcd changed
4402 4402
4403 4403 The action taken locally when pulling depends on the
4404 4404 status of each bookmark:
4405 4405
4406 4406 :``added``: pull will create it
4407 4407 :``advanced``: pull will update it
4408 4408 :``diverged``: pull will create a divergent bookmark
4409 4409 :``changed``: result depends on remote changesets
4410 4410
4411 4411 From the point of view of pulling behavior, bookmark
4412 4412 existing only in the remote repository are treated as ``added``,
4413 4413 even if it is in fact locally deleted.
4414 4414
4415 4415 .. container:: verbose
4416 4416
4417 4417 For remote repository, using --bundle avoids downloading the
4418 4418 changesets twice if the incoming is followed by a pull.
4419 4419
4420 4420 Examples:
4421 4421
4422 4422 - show incoming changes with patches and full description::
4423 4423
4424 4424 hg incoming -vp
4425 4425
4426 4426 - show incoming changes excluding merges, store a bundle::
4427 4427
4428 4428 hg in -vpM --bundle incoming.hg
4429 4429 hg pull incoming.hg
4430 4430
4431 4431 - briefly list changes inside a bundle::
4432 4432
4433 4433 hg in changes.hg -T "{desc|firstline}\\n"
4434 4434
4435 4435 Returns 0 if there are incoming changes, 1 otherwise.
4436 4436 """
4437 4437 opts = pycompat.byteskwargs(opts)
4438 4438 if opts.get(b'graph'):
4439 4439 logcmdutil.checkunsupportedgraphflags([], opts)
4440 4440
4441 4441 def display(other, chlist, displayer):
4442 4442 revdag = logcmdutil.graphrevs(other, chlist, opts)
4443 4443 logcmdutil.displaygraph(
4444 4444 ui, repo, revdag, displayer, graphmod.asciiedges
4445 4445 )
4446 4446
4447 4447 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4448 4448 return 0
4449 4449
4450 4450 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4451 4451
4452 4452 if opts.get(b'bookmarks'):
4453 4453 srcs = urlutil.get_pull_paths(repo, ui, [source])
4454 4454 for path in srcs:
4455 4455 # XXX the "branches" options are not used. Should it be used?
4456 4456 other = hg.peer(repo, opts, path)
4457 4457 try:
4458 4458 if b'bookmarks' not in other.listkeys(b'namespaces'):
4459 4459 ui.warn(_(b"remote doesn't support bookmarks\n"))
4460 4460 return 0
4461 4461 ui.pager(b'incoming')
4462 4462 ui.status(
4463 4463 _(b'comparing with %s\n') % urlutil.hidepassword(path.loc)
4464 4464 )
4465 4465 return bookmarks.incoming(
4466 4466 ui, repo, other, mode=path.bookmarks_mode
4467 4467 )
4468 4468 finally:
4469 4469 other.close()
4470 4470
4471 4471 return hg.incoming(ui, repo, source, opts)
4472 4472
4473 4473
4474 4474 @command(
4475 4475 b'init',
4476 4476 remoteopts,
4477 4477 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4478 4478 helpcategory=command.CATEGORY_REPO_CREATION,
4479 4479 helpbasic=True,
4480 4480 norepo=True,
4481 4481 )
4482 4482 def init(ui, dest=b".", **opts):
4483 4483 """create a new repository in the given directory
4484 4484
4485 4485 Initialize a new repository in the given directory. If the given
4486 4486 directory does not exist, it will be created.
4487 4487
4488 4488 If no directory is given, the current directory is used.
4489 4489
4490 4490 It is possible to specify an ``ssh://`` URL as the destination.
4491 4491 See :hg:`help urls` for more information.
4492 4492
4493 4493 Returns 0 on success.
4494 4494 """
4495 4495 opts = pycompat.byteskwargs(opts)
4496 4496 path = urlutil.get_clone_path_obj(ui, dest)
4497 4497 peer = hg.peer(ui, opts, path, create=True)
4498 4498 peer.close()
4499 4499
4500 4500
4501 4501 @command(
4502 4502 b'locate',
4503 4503 [
4504 4504 (
4505 4505 b'r',
4506 4506 b'rev',
4507 4507 b'',
4508 4508 _(b'search the repository as it is in REV'),
4509 4509 _(b'REV'),
4510 4510 ),
4511 4511 (
4512 4512 b'0',
4513 4513 b'print0',
4514 4514 None,
4515 4515 _(b'end filenames with NUL, for use with xargs'),
4516 4516 ),
4517 4517 (
4518 4518 b'f',
4519 4519 b'fullpath',
4520 4520 None,
4521 4521 _(b'print complete paths from the filesystem root'),
4522 4522 ),
4523 4523 ]
4524 4524 + walkopts,
4525 4525 _(b'[OPTION]... [PATTERN]...'),
4526 4526 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4527 4527 )
4528 4528 def locate(ui, repo, *pats, **opts):
4529 4529 """locate files matching specific patterns (DEPRECATED)
4530 4530
4531 4531 Print files under Mercurial control in the working directory whose
4532 4532 names match the given patterns.
4533 4533
4534 4534 By default, this command searches all directories in the working
4535 4535 directory. To search just the current directory and its
4536 4536 subdirectories, use "--include .".
4537 4537
4538 4538 If no patterns are given to match, this command prints the names
4539 4539 of all files under Mercurial control in the working directory.
4540 4540
4541 4541 If you want to feed the output of this command into the "xargs"
4542 4542 command, use the -0 option to both this command and "xargs". This
4543 4543 will avoid the problem of "xargs" treating single filenames that
4544 4544 contain whitespace as multiple filenames.
4545 4545
4546 4546 See :hg:`help files` for a more versatile command.
4547 4547
4548 4548 Returns 0 if a match is found, 1 otherwise.
4549 4549 """
4550 4550 if opts.get('print0'):
4551 4551 end = b'\0'
4552 4552 else:
4553 4553 end = b'\n'
4554 4554 ctx = logcmdutil.revsingle(repo, opts.get('rev'), None)
4555 4555
4556 4556 ret = 1
4557 4557 m = scmutil.match(
4558 4558 ctx,
4559 4559 pats,
4560 4560 pycompat.byteskwargs(opts),
4561 4561 default=b'relglob',
4562 4562 badfn=lambda x, y: False,
4563 4563 )
4564 4564
4565 4565 ui.pager(b'locate')
4566 4566 if ctx.rev() is None:
4567 4567 # When run on the working copy, "locate" includes removed files, so
4568 4568 # we get the list of files from the dirstate.
4569 4569 filesgen = sorted(repo.dirstate.matches(m))
4570 4570 else:
4571 4571 filesgen = ctx.matches(m)
4572 4572 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4573 4573 for abs in filesgen:
4574 4574 if opts.get('fullpath'):
4575 4575 ui.write(repo.wjoin(abs), end)
4576 4576 else:
4577 4577 ui.write(uipathfn(abs), end)
4578 4578 ret = 0
4579 4579
4580 4580 return ret
4581 4581
4582 4582
4583 4583 @command(
4584 4584 b'log|history',
4585 4585 [
4586 4586 (
4587 4587 b'f',
4588 4588 b'follow',
4589 4589 None,
4590 4590 _(
4591 4591 b'follow changeset history, or file history across copies and renames'
4592 4592 ),
4593 4593 ),
4594 4594 (
4595 4595 b'',
4596 4596 b'follow-first',
4597 4597 None,
4598 4598 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4599 4599 ),
4600 4600 (
4601 4601 b'd',
4602 4602 b'date',
4603 4603 b'',
4604 4604 _(b'show revisions matching date spec'),
4605 4605 _(b'DATE'),
4606 4606 ),
4607 4607 (b'C', b'copies', None, _(b'show copied files')),
4608 4608 (
4609 4609 b'k',
4610 4610 b'keyword',
4611 4611 [],
4612 4612 _(b'do case-insensitive search for a given text'),
4613 4613 _(b'TEXT'),
4614 4614 ),
4615 4615 (
4616 4616 b'r',
4617 4617 b'rev',
4618 4618 [],
4619 4619 _(b'revisions to select or follow from'),
4620 4620 _(b'REV'),
4621 4621 ),
4622 4622 (
4623 4623 b'L',
4624 4624 b'line-range',
4625 4625 [],
4626 4626 _(b'follow line range of specified file (EXPERIMENTAL)'),
4627 4627 _(b'FILE,RANGE'),
4628 4628 ),
4629 4629 (
4630 4630 b'',
4631 4631 b'removed',
4632 4632 None,
4633 4633 _(b'include revisions where files were removed'),
4634 4634 ),
4635 4635 (
4636 4636 b'm',
4637 4637 b'only-merges',
4638 4638 None,
4639 4639 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4640 4640 ),
4641 4641 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4642 4642 (
4643 4643 b'',
4644 4644 b'only-branch',
4645 4645 [],
4646 4646 _(
4647 4647 b'show only changesets within the given named branch (DEPRECATED)'
4648 4648 ),
4649 4649 _(b'BRANCH'),
4650 4650 ),
4651 4651 (
4652 4652 b'b',
4653 4653 b'branch',
4654 4654 [],
4655 4655 _(b'show changesets within the given named branch'),
4656 4656 _(b'BRANCH'),
4657 4657 ),
4658 4658 (
4659 4659 b'B',
4660 4660 b'bookmark',
4661 4661 [],
4662 4662 _(b"show changesets within the given bookmark"),
4663 4663 _(b'BOOKMARK'),
4664 4664 ),
4665 4665 (
4666 4666 b'P',
4667 4667 b'prune',
4668 4668 [],
4669 4669 _(b'do not display revision or any of its ancestors'),
4670 4670 _(b'REV'),
4671 4671 ),
4672 4672 ]
4673 4673 + logopts
4674 4674 + walkopts,
4675 4675 _(b'[OPTION]... [FILE]'),
4676 4676 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4677 4677 helpbasic=True,
4678 4678 inferrepo=True,
4679 4679 intents={INTENT_READONLY},
4680 4680 )
4681 4681 def log(ui, repo, *pats, **opts):
4682 4682 """show revision history of entire repository or files
4683 4683
4684 4684 Print the revision history of the specified files or the entire
4685 4685 project.
4686 4686
4687 4687 If no revision range is specified, the default is ``tip:0`` unless
4688 4688 --follow is set.
4689 4689
4690 4690 File history is shown without following rename or copy history of
4691 4691 files. Use -f/--follow with a filename to follow history across
4692 4692 renames and copies. --follow without a filename will only show
4693 4693 ancestors of the starting revisions. The starting revisions can be
4694 4694 specified by -r/--rev, which default to the working directory parent.
4695 4695
4696 4696 By default this command prints revision number and changeset id,
4697 4697 tags, non-trivial parents, user, date and time, and a summary for
4698 4698 each commit. When the -v/--verbose switch is used, the list of
4699 4699 changed files and full commit message are shown.
4700 4700
4701 4701 With --graph the revisions are shown as an ASCII art DAG with the most
4702 4702 recent changeset at the top.
4703 4703 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4704 4704 involved in an unresolved merge conflict, '_' closes a branch,
4705 4705 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4706 4706 changeset from the lines below is a parent of the 'o' merge on the same
4707 4707 line.
4708 4708 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4709 4709 of a '|' indicates one or more revisions in a path are omitted.
4710 4710
4711 4711 .. container:: verbose
4712 4712
4713 4713 Use -L/--line-range FILE,M:N options to follow the history of lines
4714 4714 from M to N in FILE. With -p/--patch only diff hunks affecting
4715 4715 specified line range will be shown. This option requires --follow;
4716 4716 it can be specified multiple times. Currently, this option is not
4717 4717 compatible with --graph. This option is experimental.
4718 4718
4719 4719 .. note::
4720 4720
4721 4721 :hg:`log --patch` may generate unexpected diff output for merge
4722 4722 changesets, as it will only compare the merge changeset against
4723 4723 its first parent. Also, only files different from BOTH parents
4724 4724 will appear in files:.
4725 4725
4726 4726 .. note::
4727 4727
4728 4728 For performance reasons, :hg:`log FILE` may omit duplicate changes
4729 4729 made on branches and will not show removals or mode changes. To
4730 4730 see all such changes, use the --removed switch.
4731 4731
4732 4732 .. container:: verbose
4733 4733
4734 4734 .. note::
4735 4735
4736 4736 The history resulting from -L/--line-range options depends on diff
4737 4737 options; for instance if white-spaces are ignored, respective changes
4738 4738 with only white-spaces in specified line range will not be listed.
4739 4739
4740 4740 .. container:: verbose
4741 4741
4742 4742 Some examples:
4743 4743
4744 4744 - changesets with full descriptions and file lists::
4745 4745
4746 4746 hg log -v
4747 4747
4748 4748 - changesets ancestral to the working directory::
4749 4749
4750 4750 hg log -f
4751 4751
4752 4752 - last 10 commits on the current branch::
4753 4753
4754 4754 hg log -l 10 -b .
4755 4755
4756 4756 - changesets showing all modifications of a file, including removals::
4757 4757
4758 4758 hg log --removed file.c
4759 4759
4760 4760 - all changesets that touch a directory, with diffs, excluding merges::
4761 4761
4762 4762 hg log -Mp lib/
4763 4763
4764 4764 - all revision numbers that match a keyword::
4765 4765
4766 4766 hg log -k bug --template "{rev}\\n"
4767 4767
4768 4768 - the full hash identifier of the working directory parent::
4769 4769
4770 4770 hg log -r . --template "{node}\\n"
4771 4771
4772 4772 - list available log templates::
4773 4773
4774 4774 hg log -T list
4775 4775
4776 4776 - check if a given changeset is included in a tagged release::
4777 4777
4778 4778 hg log -r "a21ccf and ancestor(1.9)"
4779 4779
4780 4780 - find all changesets by some user in a date range::
4781 4781
4782 4782 hg log -k alice -d "may 2008 to jul 2008"
4783 4783
4784 4784 - summary of all changesets after the last tag::
4785 4785
4786 4786 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4787 4787
4788 4788 - changesets touching lines 13 to 23 for file.c::
4789 4789
4790 4790 hg log -L file.c,13:23
4791 4791
4792 4792 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4793 4793 main.c with patch::
4794 4794
4795 4795 hg log -L file.c,13:23 -L main.c,2:6 -p
4796 4796
4797 4797 See :hg:`help dates` for a list of formats valid for -d/--date.
4798 4798
4799 4799 See :hg:`help revisions` for more about specifying and ordering
4800 4800 revisions.
4801 4801
4802 4802 See :hg:`help templates` for more about pre-packaged styles and
4803 4803 specifying custom templates. The default template used by the log
4804 4804 command can be customized via the ``command-templates.log`` configuration
4805 4805 setting.
4806 4806
4807 4807 Returns 0 on success.
4808 4808
4809 4809 """
4810 4810 opts = pycompat.byteskwargs(opts)
4811 4811 linerange = opts.get(b'line_range')
4812 4812
4813 4813 if linerange and not opts.get(b'follow'):
4814 4814 raise error.InputError(_(b'--line-range requires --follow'))
4815 4815
4816 4816 if linerange and pats:
4817 4817 # TODO: take pats as patterns with no line-range filter
4818 4818 raise error.InputError(
4819 4819 _(b'FILE arguments are not compatible with --line-range option')
4820 4820 )
4821 4821
4822 4822 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4823 4823 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4824 4824 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4825 4825 if linerange:
4826 4826 # TODO: should follow file history from logcmdutil._initialrevs(),
4827 4827 # then filter the result by logcmdutil._makerevset() and --limit
4828 4828 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4829 4829
4830 4830 getcopies = None
4831 4831 if opts.get(b'copies'):
4832 4832 endrev = None
4833 4833 if revs:
4834 4834 endrev = revs.max() + 1
4835 4835 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4836 4836
4837 4837 ui.pager(b'log')
4838 4838 displayer = logcmdutil.changesetdisplayer(
4839 4839 ui, repo, opts, differ, buffered=True
4840 4840 )
4841 4841 if opts.get(b'graph'):
4842 4842 displayfn = logcmdutil.displaygraphrevs
4843 4843 else:
4844 4844 displayfn = logcmdutil.displayrevs
4845 4845 displayfn(ui, repo, revs, displayer, getcopies)
4846 4846
4847 4847
4848 4848 @command(
4849 4849 b'manifest',
4850 4850 [
4851 4851 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4852 4852 (b'', b'all', False, _(b"list files from all revisions")),
4853 4853 ]
4854 4854 + formatteropts,
4855 4855 _(b'[-r REV]'),
4856 4856 helpcategory=command.CATEGORY_MAINTENANCE,
4857 4857 intents={INTENT_READONLY},
4858 4858 )
4859 4859 def manifest(ui, repo, node=None, rev=None, **opts):
4860 4860 """output the current or given revision of the project manifest
4861 4861
4862 4862 Print a list of version controlled files for the given revision.
4863 4863 If no revision is given, the first parent of the working directory
4864 4864 is used, or the null revision if no revision is checked out.
4865 4865
4866 4866 With -v, print file permissions, symlink and executable bits.
4867 4867 With --debug, print file revision hashes.
4868 4868
4869 4869 If option --all is specified, the list of all files from all revisions
4870 4870 is printed. This includes deleted and renamed files.
4871 4871
4872 4872 Returns 0 on success.
4873 4873 """
4874 4874 fm = ui.formatter(b'manifest', pycompat.byteskwargs(opts))
4875 4875
4876 4876 if opts.get('all'):
4877 4877 if rev or node:
4878 4878 raise error.InputError(_(b"can't specify a revision with --all"))
4879 4879
4880 4880 res = set()
4881 4881 for rev in repo:
4882 4882 ctx = repo[rev]
4883 4883 res |= set(ctx.files())
4884 4884
4885 4885 ui.pager(b'manifest')
4886 4886 for f in sorted(res):
4887 4887 fm.startitem()
4888 4888 fm.write(b"path", b'%s\n', f)
4889 4889 fm.end()
4890 4890 return
4891 4891
4892 4892 if rev and node:
4893 4893 raise error.InputError(_(b"please specify just one revision"))
4894 4894
4895 4895 if not node:
4896 4896 node = rev
4897 4897
4898 4898 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4899 4899 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4900 4900 if node:
4901 4901 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4902 4902 ctx = logcmdutil.revsingle(repo, node)
4903 4903 mf = ctx.manifest()
4904 4904 ui.pager(b'manifest')
4905 4905 for f in ctx:
4906 4906 fm.startitem()
4907 4907 fm.context(ctx=ctx)
4908 4908 fl = ctx[f].flags()
4909 4909 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4910 4910 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4911 4911 fm.write(b'path', b'%s\n', f)
4912 4912 fm.end()
4913 4913
4914 4914
4915 4915 @command(
4916 4916 b'merge',
4917 4917 [
4918 4918 (
4919 4919 b'f',
4920 4920 b'force',
4921 4921 None,
4922 4922 _(b'force a merge including outstanding changes (DEPRECATED)'),
4923 4923 ),
4924 4924 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4925 4925 (
4926 4926 b'P',
4927 4927 b'preview',
4928 4928 None,
4929 4929 _(b'review revisions to merge (no merge is performed)'),
4930 4930 ),
4931 4931 (b'', b'abort', None, _(b'abort the ongoing merge')),
4932 4932 ]
4933 4933 + mergetoolopts,
4934 4934 _(b'[-P] [[-r] REV]'),
4935 4935 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4936 4936 helpbasic=True,
4937 4937 )
4938 4938 def merge(ui, repo, node=None, **opts):
4939 4939 """merge another revision into working directory
4940 4940
4941 4941 The current working directory is updated with all changes made in
4942 4942 the requested revision since the last common predecessor revision.
4943 4943
4944 4944 Files that changed between either parent are marked as changed for
4945 4945 the next commit and a commit must be performed before any further
4946 4946 updates to the repository are allowed. The next commit will have
4947 4947 two parents.
4948 4948
4949 4949 ``--tool`` can be used to specify the merge tool used for file
4950 4950 merges. It overrides the HGMERGE environment variable and your
4951 4951 configuration files. See :hg:`help merge-tools` for options.
4952 4952
4953 4953 If no revision is specified, the working directory's parent is a
4954 4954 head revision, and the current branch contains exactly one other
4955 4955 head, the other head is merged with by default. Otherwise, an
4956 4956 explicit revision with which to merge must be provided.
4957 4957
4958 4958 See :hg:`help resolve` for information on handling file conflicts.
4959 4959
4960 4960 To undo an uncommitted merge, use :hg:`merge --abort` which
4961 4961 will check out a clean copy of the original merge parent, losing
4962 4962 all changes.
4963 4963
4964 4964 Returns 0 on success, 1 if there are unresolved files.
4965 4965 """
4966 4966
4967 4967 abort = opts.get('abort')
4968 4968 if abort and repo.dirstate.p2() == repo.nullid:
4969 4969 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4970 4970 cmdutil.check_incompatible_arguments(opts, 'abort', ['rev', 'preview'])
4971 4971 if abort:
4972 4972 state = cmdutil.getunfinishedstate(repo)
4973 4973 if state and state._opname != b'merge':
4974 4974 raise error.StateError(
4975 4975 _(b'cannot abort merge with %s in progress') % (state._opname),
4976 4976 hint=state.hint(),
4977 4977 )
4978 4978 if node:
4979 4979 raise error.InputError(_(b"cannot specify a node with --abort"))
4980 4980 return hg.abortmerge(repo.ui, repo)
4981 4981
4982 4982 if opts.get('rev') and node:
4983 4983 raise error.InputError(_(b"please specify just one revision"))
4984 4984 if not node:
4985 4985 node = opts.get('rev')
4986 4986
4987 4987 if node:
4988 4988 ctx = logcmdutil.revsingle(repo, node)
4989 4989 else:
4990 4990 if ui.configbool(b'commands', b'merge.require-rev'):
4991 4991 raise error.InputError(
4992 4992 _(
4993 4993 b'configuration requires specifying revision to merge '
4994 4994 b'with'
4995 4995 )
4996 4996 )
4997 4997 ctx = repo[destutil.destmerge(repo)]
4998 4998
4999 4999 if ctx.node() is None:
5000 5000 raise error.InputError(
5001 5001 _(b'merging with the working copy has no effect')
5002 5002 )
5003 5003
5004 5004 if opts.get('preview'):
5005 5005 # find nodes that are ancestors of p2 but not of p1
5006 5006 p1 = repo[b'.'].node()
5007 5007 p2 = ctx.node()
5008 5008 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5009 5009
5010 5010 displayer = logcmdutil.changesetdisplayer(
5011 5011 ui, repo, pycompat.byteskwargs(opts)
5012 5012 )
5013 5013 for node in nodes:
5014 5014 displayer.show(repo[node])
5015 5015 displayer.close()
5016 5016 return 0
5017 5017
5018 5018 # ui.forcemerge is an internal variable, do not document
5019 5019 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
5020 5020 with ui.configoverride(overrides, b'merge'):
5021 5021 force = opts.get('force')
5022 5022 labels = [b'working copy', b'merge rev', b'common ancestor']
5023 5023 return hg.merge(ctx, force=force, labels=labels)
5024 5024
5025 5025
5026 5026 statemod.addunfinished(
5027 5027 b'merge',
5028 5028 fname=None,
5029 5029 clearable=True,
5030 5030 allowcommit=True,
5031 5031 cmdmsg=_(b'outstanding uncommitted merge'),
5032 5032 abortfunc=hg.abortmerge,
5033 5033 statushint=_(
5034 5034 b'To continue: hg commit\nTo abort: hg merge --abort'
5035 5035 ),
5036 5036 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
5037 5037 )
5038 5038
5039 5039
5040 5040 @command(
5041 5041 b'outgoing|out',
5042 5042 [
5043 5043 (
5044 5044 b'f',
5045 5045 b'force',
5046 5046 None,
5047 5047 _(b'run even when the destination is unrelated'),
5048 5048 ),
5049 5049 (
5050 5050 b'r',
5051 5051 b'rev',
5052 5052 [],
5053 5053 _(b'a changeset intended to be included in the destination'),
5054 5054 _(b'REV'),
5055 5055 ),
5056 5056 (b'n', b'newest-first', None, _(b'show newest record first')),
5057 5057 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
5058 5058 (
5059 5059 b'b',
5060 5060 b'branch',
5061 5061 [],
5062 5062 _(b'a specific branch you would like to push'),
5063 5063 _(b'BRANCH'),
5064 5064 ),
5065 5065 ]
5066 5066 + logopts
5067 5067 + remoteopts
5068 5068 + subrepoopts,
5069 5069 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]...'),
5070 5070 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5071 5071 )
5072 5072 def outgoing(ui, repo, *dests, **opts):
5073 5073 """show changesets not found in the destination
5074 5074
5075 5075 Show changesets not found in the specified destination repository
5076 5076 or the default push location. These are the changesets that would
5077 5077 be pushed if a push was requested.
5078 5078
5079 5079 See pull for details of valid destination formats.
5080 5080
5081 5081 .. container:: verbose
5082 5082
5083 5083 With -B/--bookmarks, the result of bookmark comparison between
5084 5084 local and remote repositories is displayed. With -v/--verbose,
5085 5085 status is also displayed for each bookmark like below::
5086 5086
5087 5087 BM1 01234567890a added
5088 5088 BM2 deleted
5089 5089 BM3 234567890abc advanced
5090 5090 BM4 34567890abcd diverged
5091 5091 BM5 4567890abcde changed
5092 5092
5093 5093 The action taken when pushing depends on the
5094 5094 status of each bookmark:
5095 5095
5096 5096 :``added``: push with ``-B`` will create it
5097 5097 :``deleted``: push with ``-B`` will delete it
5098 5098 :``advanced``: push will update it
5099 5099 :``diverged``: push with ``-B`` will update it
5100 5100 :``changed``: push with ``-B`` will update it
5101 5101
5102 5102 From the point of view of pushing behavior, bookmarks
5103 5103 existing only in the remote repository are treated as
5104 5104 ``deleted``, even if it is in fact added remotely.
5105 5105
5106 5106 Returns 0 if there are outgoing changes, 1 otherwise.
5107 5107 """
5108 5108 opts = pycompat.byteskwargs(opts)
5109 5109 if opts.get(b'bookmarks'):
5110 5110 for path in urlutil.get_push_paths(repo, ui, dests):
5111 5111 other = hg.peer(repo, opts, path)
5112 5112 try:
5113 5113 if b'bookmarks' not in other.listkeys(b'namespaces'):
5114 5114 ui.warn(_(b"remote doesn't support bookmarks\n"))
5115 5115 return 0
5116 5116 ui.status(
5117 5117 _(b'comparing with %s\n') % urlutil.hidepassword(path.loc)
5118 5118 )
5119 5119 ui.pager(b'outgoing')
5120 5120 return bookmarks.outgoing(ui, repo, other)
5121 5121 finally:
5122 5122 other.close()
5123 5123
5124 5124 return hg.outgoing(ui, repo, dests, opts)
5125 5125
5126 5126
5127 5127 @command(
5128 5128 b'parents',
5129 5129 [
5130 5130 (
5131 5131 b'r',
5132 5132 b'rev',
5133 5133 b'',
5134 5134 _(b'show parents of the specified revision'),
5135 5135 _(b'REV'),
5136 5136 ),
5137 5137 ]
5138 5138 + templateopts,
5139 5139 _(b'[-r REV] [FILE]'),
5140 5140 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5141 5141 inferrepo=True,
5142 5142 )
5143 5143 def parents(ui, repo, file_=None, **opts):
5144 5144 """show the parents of the working directory or revision (DEPRECATED)
5145 5145
5146 5146 Print the working directory's parent revisions. If a revision is
5147 5147 given via -r/--rev, the parent of that revision will be printed.
5148 5148 If a file argument is given, the revision in which the file was
5149 5149 last changed (before the working directory revision or the
5150 5150 argument to --rev if given) is printed.
5151 5151
5152 5152 This command is equivalent to::
5153 5153
5154 5154 hg log -r "p1()+p2()" or
5155 5155 hg log -r "p1(REV)+p2(REV)" or
5156 5156 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5157 5157 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5158 5158
5159 5159 See :hg:`summary` and :hg:`help revsets` for related information.
5160 5160
5161 5161 Returns 0 on success.
5162 5162 """
5163 5163
5164 5164 opts = pycompat.byteskwargs(opts)
5165 5165 rev = opts.get(b'rev')
5166 5166 if rev:
5167 5167 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5168 5168 ctx = logcmdutil.revsingle(repo, rev, None)
5169 5169
5170 5170 if file_:
5171 5171 m = scmutil.match(ctx, (file_,), opts)
5172 5172 if m.anypats() or len(m.files()) != 1:
5173 5173 raise error.InputError(_(b'can only specify an explicit filename'))
5174 5174 file_ = m.files()[0]
5175 5175 filenodes = []
5176 5176 for cp in ctx.parents():
5177 5177 if not cp:
5178 5178 continue
5179 5179 try:
5180 5180 filenodes.append(cp.filenode(file_))
5181 5181 except error.LookupError:
5182 5182 pass
5183 5183 if not filenodes:
5184 5184 raise error.InputError(_(b"'%s' not found in manifest") % file_)
5185 5185 p = []
5186 5186 for fn in filenodes:
5187 5187 fctx = repo.filectx(file_, fileid=fn)
5188 5188 p.append(fctx.node())
5189 5189 else:
5190 5190 p = [cp.node() for cp in ctx.parents()]
5191 5191
5192 5192 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5193 5193 for n in p:
5194 5194 if n != repo.nullid:
5195 5195 displayer.show(repo[n])
5196 5196 displayer.close()
5197 5197
5198 5198
5199 5199 @command(
5200 5200 b'paths',
5201 5201 formatteropts,
5202 5202 _(b'[NAME]'),
5203 5203 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5204 5204 optionalrepo=True,
5205 5205 intents={INTENT_READONLY},
5206 5206 )
5207 5207 def paths(ui, repo, search=None, **opts):
5208 5208 """show aliases for remote repositories
5209 5209
5210 5210 Show definition of symbolic path name NAME. If no name is given,
5211 5211 show definition of all available names.
5212 5212
5213 5213 Option -q/--quiet suppresses all output when searching for NAME
5214 5214 and shows only the path names when listing all definitions.
5215 5215
5216 5216 Path names are defined in the [paths] section of your
5217 5217 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5218 5218 repository, ``.hg/hgrc`` is used, too.
5219 5219
5220 5220 The path names ``default`` and ``default-push`` have a special
5221 5221 meaning. When performing a push or pull operation, they are used
5222 5222 as fallbacks if no location is specified on the command-line.
5223 5223 When ``default-push`` is set, it will be used for push and
5224 5224 ``default`` will be used for pull; otherwise ``default`` is used
5225 5225 as the fallback for both. When cloning a repository, the clone
5226 5226 source is written as ``default`` in ``.hg/hgrc``.
5227 5227
5228 5228 .. note::
5229 5229
5230 5230 ``default`` and ``default-push`` apply to all inbound (e.g.
5231 5231 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5232 5232 and :hg:`bundle`) operations.
5233 5233
5234 5234 See :hg:`help urls` for more information.
5235 5235
5236 5236 .. container:: verbose
5237 5237
5238 5238 Template:
5239 5239
5240 5240 The following keywords are supported. See also :hg:`help templates`.
5241 5241
5242 5242 :name: String. Symbolic name of the path alias.
5243 5243 :pushurl: String. URL for push operations.
5244 5244 :url: String. URL or directory path for the other operations.
5245 5245
5246 5246 Returns 0 on success.
5247 5247 """
5248 5248
5249 5249 pathitems = urlutil.list_paths(ui, search)
5250 5250 ui.pager(b'paths')
5251 5251
5252 5252 fm = ui.formatter(b'paths', pycompat.byteskwargs(opts))
5253 5253 if fm.isplain():
5254 5254 hidepassword = urlutil.hidepassword
5255 5255 else:
5256 5256 hidepassword = bytes
5257 5257 if ui.quiet:
5258 5258 namefmt = b'%s\n'
5259 5259 else:
5260 5260 namefmt = b'%s = '
5261 5261 showsubopts = not search and not ui.quiet
5262 5262
5263 5263 for name, path in pathitems:
5264 5264 fm.startitem()
5265 5265 fm.condwrite(not search, b'name', namefmt, name)
5266 5266 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5267 5267 for subopt, value in sorted(path.suboptions.items()):
5268 5268 assert subopt not in (b'name', b'url')
5269 5269 if showsubopts:
5270 5270 fm.plain(b'%s:%s = ' % (name, subopt))
5271 5271 display = urlutil.path_suboptions_display[subopt]
5272 5272 value = display(value)
5273 5273 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5274 5274
5275 5275 fm.end()
5276 5276
5277 5277 if search and not pathitems:
5278 5278 if not ui.quiet:
5279 5279 ui.warn(_(b"not found!\n"))
5280 5280 return 1
5281 5281 else:
5282 5282 return 0
5283 5283
5284 5284
5285 5285 @command(
5286 5286 b'phase',
5287 5287 [
5288 5288 (b'p', b'public', False, _(b'set changeset phase to public')),
5289 5289 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5290 5290 (b's', b'secret', False, _(b'set changeset phase to secret')),
5291 5291 (b'f', b'force', False, _(b'allow to move boundary backward')),
5292 5292 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5293 5293 ],
5294 5294 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5295 5295 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5296 5296 )
5297 5297 def phase(ui, repo, *revs, **opts):
5298 5298 """set or show the current phase name
5299 5299
5300 5300 With no argument, show the phase name of the current revision(s).
5301 5301
5302 5302 With one of -p/--public, -d/--draft or -s/--secret, change the
5303 5303 phase value of the specified revisions.
5304 5304
5305 5305 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5306 5306 lower phase to a higher phase. Phases are ordered as follows::
5307 5307
5308 5308 public < draft < secret
5309 5309
5310 5310 Returns 0 on success, 1 if some phases could not be changed.
5311 5311
5312 5312 (For more information about the phases concept, see :hg:`help phases`.)
5313 5313 """
5314 5314 opts = pycompat.byteskwargs(opts)
5315 5315 # search for a unique phase argument
5316 5316 targetphase = None
5317 5317 for idx, name in enumerate(phases.cmdphasenames):
5318 5318 if opts[name]:
5319 5319 if targetphase is not None:
5320 5320 raise error.InputError(_(b'only one phase can be specified'))
5321 5321 targetphase = idx
5322 5322
5323 5323 # look for specified revision
5324 5324 revs = list(revs)
5325 5325 revs.extend(opts[b'rev'])
5326 5326 if revs:
5327 5327 revs = logcmdutil.revrange(repo, revs)
5328 5328 else:
5329 5329 # display both parents as the second parent phase can influence
5330 5330 # the phase of a merge commit
5331 5331 revs = [c.rev() for c in repo[None].parents()]
5332 5332
5333 5333 ret = 0
5334 5334 if targetphase is None:
5335 5335 # display
5336 5336 for r in revs:
5337 5337 ctx = repo[r]
5338 5338 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5339 5339 else:
5340 5340 with repo.lock(), repo.transaction(b"phase") as tr:
5341 5341 # set phase
5342 5342 if not revs:
5343 5343 raise error.InputError(_(b'empty revision set'))
5344 5344 nodes = [repo[r].node() for r in revs]
5345 5345 # moving revision from public to draft may hide them
5346 5346 # We have to check result on an unfiltered repository
5347 5347 unfi = repo.unfiltered()
5348 5348 getphase = unfi._phasecache.phase
5349 5349 olddata = [getphase(unfi, r) for r in unfi]
5350 5350 phases.advanceboundary(repo, tr, targetphase, nodes)
5351 5351 if opts[b'force']:
5352 5352 phases.retractboundary(repo, tr, targetphase, nodes)
5353 5353 getphase = unfi._phasecache.phase
5354 5354 newdata = [getphase(unfi, r) for r in unfi]
5355 5355 changes = sum(newdata[r] != olddata[r] for r in unfi)
5356 5356 cl = unfi.changelog
5357 5357 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5358 5358 if rejected:
5359 5359 ui.warn(
5360 5360 _(
5361 5361 b'cannot move %i changesets to a higher '
5362 5362 b'phase, use --force\n'
5363 5363 )
5364 5364 % len(rejected)
5365 5365 )
5366 5366 ret = 1
5367 5367 if changes:
5368 5368 msg = _(b'phase changed for %i changesets\n') % changes
5369 5369 if ret:
5370 5370 ui.status(msg)
5371 5371 else:
5372 5372 ui.note(msg)
5373 5373 else:
5374 5374 ui.warn(_(b'no phases changed\n'))
5375 5375 return ret
5376 5376
5377 5377
5378 5378 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5379 5379 """Run after a changegroup has been added via pull/unbundle
5380 5380
5381 5381 This takes arguments below:
5382 5382
5383 5383 :modheads: change of heads by pull/unbundle
5384 5384 :optupdate: updating working directory is needed or not
5385 5385 :checkout: update destination revision (or None to default destination)
5386 5386 :brev: a name, which might be a bookmark to be activated after updating
5387 5387
5388 5388 return True if update raise any conflict, False otherwise.
5389 5389 """
5390 5390 if modheads == 0:
5391 5391 return False
5392 5392 if optupdate:
5393 5393 try:
5394 5394 return hg.updatetotally(ui, repo, checkout, brev)
5395 5395 except error.UpdateAbort as inst:
5396 5396 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5397 5397 hint = inst.hint
5398 5398 raise error.UpdateAbort(msg, hint=hint)
5399 5399 if modheads is not None and modheads > 1:
5400 5400 currentbranchheads = len(repo.branchheads())
5401 5401 if currentbranchheads == modheads:
5402 5402 ui.status(
5403 5403 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5404 5404 )
5405 5405 elif currentbranchheads > 1:
5406 5406 ui.status(
5407 5407 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5408 5408 )
5409 5409 else:
5410 5410 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5411 5411 elif not ui.configbool(b'commands', b'update.requiredest'):
5412 5412 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5413 5413 return False
5414 5414
5415 5415
5416 5416 @command(
5417 5417 b'pull',
5418 5418 [
5419 5419 (
5420 5420 b'u',
5421 5421 b'update',
5422 5422 None,
5423 5423 _(b'update to new branch head if new descendants were pulled'),
5424 5424 ),
5425 5425 (
5426 5426 b'f',
5427 5427 b'force',
5428 5428 None,
5429 5429 _(b'run even when remote repository is unrelated'),
5430 5430 ),
5431 5431 (
5432 5432 b'',
5433 5433 b'confirm',
5434 5434 None,
5435 5435 _(b'confirm pull before applying changes'),
5436 5436 ),
5437 5437 (
5438 5438 b'r',
5439 5439 b'rev',
5440 5440 [],
5441 5441 _(b'a remote changeset intended to be added'),
5442 5442 _(b'REV'),
5443 5443 ),
5444 5444 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5445 5445 (
5446 5446 b'b',
5447 5447 b'branch',
5448 5448 [],
5449 5449 _(b'a specific branch you would like to pull'),
5450 5450 _(b'BRANCH'),
5451 5451 ),
5452 5452 (
5453 5453 b'',
5454 5454 b'remote-hidden',
5455 5455 False,
5456 5456 _(b"include changesets hidden on the remote (EXPERIMENTAL)"),
5457 5457 ),
5458 5458 ]
5459 5459 + remoteopts,
5460 5460 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5461 5461 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5462 5462 helpbasic=True,
5463 5463 )
5464 5464 def pull(ui, repo, *sources, **opts):
5465 5465 """pull changes from the specified source
5466 5466
5467 5467 Pull changes from a remote repository to a local one.
5468 5468
5469 5469 This finds all changes from the repository at the specified path
5470 5470 or URL and adds them to a local repository (the current one unless
5471 5471 -R is specified). By default, this does not update the copy of the
5472 5472 project in the working directory.
5473 5473
5474 5474 When cloning from servers that support it, Mercurial may fetch
5475 5475 pre-generated data. When this is done, hooks operating on incoming
5476 5476 changesets and changegroups may fire more than once, once for each
5477 5477 pre-generated bundle and as well as for any additional remaining
5478 5478 data. See :hg:`help -e clonebundles` for more.
5479 5479
5480 5480 Use :hg:`incoming` if you want to see what would have been added
5481 5481 by a pull at the time you issued this command. If you then decide
5482 5482 to add those changes to the repository, you should use :hg:`pull
5483 5483 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5484 5484
5485 5485 If SOURCE is omitted, the 'default' path will be used.
5486 5486 See :hg:`help urls` for more information.
5487 5487
5488 5488 If multiple sources are specified, they will be pulled sequentially as if
5489 5489 the command was run multiple time. If --update is specify and the command
5490 5490 will stop at the first failed --update.
5491 5491
5492 5492 Specifying bookmark as ``.`` is equivalent to specifying the active
5493 5493 bookmark's name.
5494 5494
5495 5495 .. container:: verbose
5496 5496
5497 5497 One can use the `--remote-hidden` flag to pull changesets
5498 5498 hidden on the remote. This flag is "best effort", and will only
5499 5499 work if the server supports the feature and is configured to
5500 5500 allow the user to access hidden changesets. This option is
5501 5501 experimental and backwards compatibility is not garanteed.
5502 5502
5503 5503 Returns 0 on success, 1 if an update had unresolved files.
5504 5504 """
5505 5505
5506 5506 if ui.configbool(b'commands', b'update.requiredest') and opts.get('update'):
5507 5507 msg = _(b'update destination required by configuration')
5508 5508 hint = _(b'use hg pull followed by hg update DEST')
5509 5509 raise error.InputError(msg, hint=hint)
5510 5510
5511 5511 update_conflict = None
5512 5512
5513 5513 for path in urlutil.get_pull_paths(repo, ui, sources):
5514 5514 ui.status(_(b'pulling from %s\n') % urlutil.hidepassword(path.loc))
5515 5515 ui.flush()
5516 5516 other = hg.peer(
5517 5517 repo,
5518 5518 pycompat.byteskwargs(opts),
5519 5519 path,
5520 5520 remotehidden=opts['remote_hidden'],
5521 5521 )
5522 5522 update_conflict = None
5523 5523 try:
5524 5524 branches = (path.branch, opts.get('branch', []))
5525 5525 revs, checkout = hg.addbranchrevs(
5526 5526 repo,
5527 5527 other,
5528 5528 branches,
5529 5529 opts.get('rev'),
5530 5530 remotehidden=opts['remote_hidden'],
5531 5531 )
5532 5532
5533 5533 pullopargs = {}
5534 5534
5535 5535 nodes = None
5536 5536 if opts.get('bookmark') or revs:
5537 5537 # The list of bookmark used here is the same used to actually update
5538 5538 # the bookmark names, to avoid the race from issue 4689 and we do
5539 5539 # all lookup and bookmark queries in one go so they see the same
5540 5540 # version of the server state (issue 4700).
5541 5541 nodes = []
5542 5542 fnodes = []
5543 5543 revs = revs or []
5544 5544 if revs and not other.capable(b'lookup'):
5545 5545 err = _(
5546 5546 b"other repository doesn't support revision lookup, "
5547 5547 b"so a rev cannot be specified."
5548 5548 )
5549 5549 raise error.Abort(err)
5550 5550 with other.commandexecutor() as e:
5551 5551 fremotebookmarks = e.callcommand(
5552 5552 b'listkeys', {b'namespace': b'bookmarks'}
5553 5553 )
5554 5554 for r in revs:
5555 5555 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5556 5556 remotebookmarks = fremotebookmarks.result()
5557 5557 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5558 5558 pullopargs[b'remotebookmarks'] = remotebookmarks
5559 5559 for b in opts.get('bookmark', []):
5560 5560 b = repo._bookmarks.expandname(b)
5561 5561 if b not in remotebookmarks:
5562 5562 raise error.InputError(
5563 5563 _(b'remote bookmark %s not found!') % b
5564 5564 )
5565 5565 nodes.append(remotebookmarks[b])
5566 5566 for i, rev in enumerate(revs):
5567 5567 node = fnodes[i].result()
5568 5568 nodes.append(node)
5569 5569 if rev == checkout:
5570 5570 checkout = node
5571 5571
5572 5572 wlock = util.nullcontextmanager()
5573 5573 if opts.get('update'):
5574 5574 wlock = repo.wlock()
5575 5575 with wlock:
5576 5576 pullopargs.update(opts.get('opargs', {}))
5577 5577 modheads = exchange.pull(
5578 5578 repo,
5579 5579 other,
5580 5580 path=path,
5581 5581 heads=nodes,
5582 5582 force=opts.get('force'),
5583 5583 bookmarks=opts.get('bookmark', ()),
5584 5584 opargs=pullopargs,
5585 5585 confirm=opts.get('confirm'),
5586 5586 ).cgresult
5587 5587
5588 5588 # brev is a name, which might be a bookmark to be activated at
5589 5589 # the end of the update. In other words, it is an explicit
5590 5590 # destination of the update
5591 5591 brev = None
5592 5592
5593 5593 if checkout:
5594 5594 checkout = repo.unfiltered().changelog.rev(checkout)
5595 5595
5596 5596 # order below depends on implementation of
5597 5597 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5598 5598 # because 'checkout' is determined without it.
5599 5599 if opts.get('rev'):
5600 5600 brev = opts['rev'][0]
5601 5601 elif opts.get('branch'):
5602 5602 brev = opts['branch'][0]
5603 5603 else:
5604 5604 brev = path.branch
5605 5605
5606 5606 # XXX path: we are losing the `path` object here. Keeping it
5607 5607 # would be valuable. For example as a "variant" as we do
5608 5608 # for pushes.
5609 5609 repo._subtoppath = path.loc
5610 5610 try:
5611 5611 update_conflict = postincoming(
5612 5612 ui, repo, modheads, opts.get('update'), checkout, brev
5613 5613 )
5614 5614 except error.FilteredRepoLookupError as exc:
5615 5615 msg = _(b'cannot update to target: %s') % exc.args[0]
5616 5616 exc.args = (msg,) + exc.args[1:]
5617 5617 raise
5618 5618 finally:
5619 5619 del repo._subtoppath
5620 5620
5621 5621 finally:
5622 5622 other.close()
5623 5623 # skip the remaining pull source if they are some conflict.
5624 5624 if update_conflict:
5625 5625 break
5626 5626 if update_conflict:
5627 5627 return 1
5628 5628 else:
5629 5629 return 0
5630 5630
5631 5631
5632 5632 @command(
5633 5633 b'purge|clean',
5634 5634 [
5635 5635 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5636 5636 (b'', b'all', None, _(b'purge ignored files too')),
5637 5637 (b'i', b'ignored', None, _(b'purge only ignored files')),
5638 5638 (b'', b'dirs', None, _(b'purge empty directories')),
5639 5639 (b'', b'files', None, _(b'purge files')),
5640 5640 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5641 5641 (
5642 5642 b'0',
5643 5643 b'print0',
5644 5644 None,
5645 5645 _(
5646 5646 b'end filenames with NUL, for use with xargs'
5647 5647 b' (implies -p/--print)'
5648 5648 ),
5649 5649 ),
5650 5650 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5651 5651 ]
5652 5652 + cmdutil.walkopts,
5653 5653 _(b'hg purge [OPTION]... [DIR]...'),
5654 5654 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5655 5655 )
5656 5656 def purge(ui, repo, *dirs, **opts):
5657 5657 """removes files not tracked by Mercurial
5658 5658
5659 5659 Delete files not known to Mercurial. This is useful to test local
5660 5660 and uncommitted changes in an otherwise-clean source tree.
5661 5661
5662 5662 This means that purge will delete the following by default:
5663 5663
5664 5664 - Unknown files: files marked with "?" by :hg:`status`
5665 5665 - Empty directories: in fact Mercurial ignores directories unless
5666 5666 they contain files under source control management
5667 5667
5668 5668 But it will leave untouched:
5669 5669
5670 5670 - Modified and unmodified tracked files
5671 5671 - Ignored files (unless -i or --all is specified)
5672 5672 - New files added to the repository (with :hg:`add`)
5673 5673
5674 5674 The --files and --dirs options can be used to direct purge to delete
5675 5675 only files, only directories, or both. If neither option is given,
5676 5676 both will be deleted.
5677 5677
5678 5678 If directories are given on the command line, only files in these
5679 5679 directories are considered.
5680 5680
5681 5681 Be careful with purge, as you could irreversibly delete some files
5682 5682 you forgot to add to the repository. If you only want to print the
5683 5683 list of files that this program would delete, use the --print
5684 5684 option.
5685 5685 """
5686 5686 cmdutil.check_at_most_one_arg(opts, 'all', 'ignored')
5687 5687
5688 5688 act = not opts.get('print')
5689 5689 eol = b'\n'
5690 5690 if opts.get('print0'):
5691 5691 eol = b'\0'
5692 5692 act = False # --print0 implies --print
5693 5693 if opts.get('all', False):
5694 5694 ignored = True
5695 5695 unknown = True
5696 5696 else:
5697 5697 ignored = opts.get('ignored', False)
5698 5698 unknown = not ignored
5699 5699
5700 5700 removefiles = opts.get('files')
5701 5701 removedirs = opts.get('dirs')
5702 5702 confirm = opts.get('confirm')
5703 5703 if confirm is None:
5704 5704 try:
5705 5705 extensions.find(b'purge')
5706 5706 confirm = False
5707 5707 except KeyError:
5708 5708 confirm = True
5709 5709
5710 5710 if not removefiles and not removedirs:
5711 5711 removefiles = True
5712 5712 removedirs = True
5713 5713
5714 5714 match = scmutil.match(repo[None], dirs, pycompat.byteskwargs(opts))
5715 5715
5716 5716 paths = mergemod.purge(
5717 5717 repo,
5718 5718 match,
5719 5719 unknown=unknown,
5720 5720 ignored=ignored,
5721 5721 removeemptydirs=removedirs,
5722 5722 removefiles=removefiles,
5723 5723 abortonerror=opts.get('abort_on_err'),
5724 5724 noop=not act,
5725 5725 confirm=confirm,
5726 5726 )
5727 5727
5728 5728 for path in paths:
5729 5729 if not act:
5730 5730 ui.write(b'%s%s' % (path, eol))
5731 5731
5732 5732
5733 5733 @command(
5734 5734 b'push',
5735 5735 [
5736 5736 (b'f', b'force', None, _(b'force push')),
5737 5737 (
5738 5738 b'r',
5739 5739 b'rev',
5740 5740 [],
5741 5741 _(b'a changeset intended to be included in the destination'),
5742 5742 _(b'REV'),
5743 5743 ),
5744 5744 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5745 5745 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5746 5746 (
5747 5747 b'b',
5748 5748 b'branch',
5749 5749 [],
5750 5750 _(b'a specific branch you would like to push'),
5751 5751 _(b'BRANCH'),
5752 5752 ),
5753 5753 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5754 5754 (
5755 5755 b'',
5756 5756 b'pushvars',
5757 5757 [],
5758 5758 _(b'variables that can be sent to server (ADVANCED)'),
5759 5759 ),
5760 5760 (
5761 5761 b'',
5762 5762 b'publish',
5763 5763 False,
5764 5764 _(b'push the changeset as public (EXPERIMENTAL)'),
5765 5765 ),
5766 5766 ]
5767 5767 + remoteopts,
5768 5768 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
5769 5769 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5770 5770 helpbasic=True,
5771 5771 )
5772 5772 def push(ui, repo, *dests, **opts):
5773 5773 """push changes to the specified destination
5774 5774
5775 5775 Push changesets from the local repository to the specified
5776 5776 destination.
5777 5777
5778 5778 This operation is symmetrical to pull: it is identical to a pull
5779 5779 in the destination repository from the current one.
5780 5780
5781 5781 By default, push will not allow creation of new heads at the
5782 5782 destination, since multiple heads would make it unclear which head
5783 5783 to use. In this situation, it is recommended to pull and merge
5784 5784 before pushing.
5785 5785
5786 5786 Use --new-branch if you want to allow push to create a new named
5787 5787 branch that is not present at the destination. This allows you to
5788 5788 only create a new branch without forcing other changes.
5789 5789
5790 5790 .. note::
5791 5791
5792 5792 Extra care should be taken with the -f/--force option,
5793 5793 which will push all new heads on all branches, an action which will
5794 5794 almost always cause confusion for collaborators.
5795 5795
5796 5796 If -r/--rev is used, the specified revision and all its ancestors
5797 5797 will be pushed to the remote repository.
5798 5798
5799 5799 If -B/--bookmark is used, the specified bookmarked revision, its
5800 5800 ancestors, and the bookmark will be pushed to the remote
5801 5801 repository. Specifying ``.`` is equivalent to specifying the active
5802 5802 bookmark's name. Use the --all-bookmarks option for pushing all
5803 5803 current bookmarks.
5804 5804
5805 5805 Please see :hg:`help urls` for important details about ``ssh://``
5806 5806 URLs. If DESTINATION is omitted, a default path will be used.
5807 5807
5808 5808 When passed multiple destinations, push will process them one after the
5809 5809 other, but stop should an error occur.
5810 5810
5811 5811 .. container:: verbose
5812 5812
5813 5813 The --pushvars option sends strings to the server that become
5814 5814 environment variables prepended with ``HG_USERVAR_``. For example,
5815 5815 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5816 5816 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5817 5817
5818 5818 pushvars can provide for user-overridable hooks as well as set debug
5819 5819 levels. One example is having a hook that blocks commits containing
5820 5820 conflict markers, but enables the user to override the hook if the file
5821 5821 is using conflict markers for testing purposes or the file format has
5822 5822 strings that look like conflict markers.
5823 5823
5824 5824 By default, servers will ignore `--pushvars`. To enable it add the
5825 5825 following to your configuration file::
5826 5826
5827 5827 [push]
5828 5828 pushvars.server = true
5829 5829
5830 5830 Returns 0 if push was successful, 1 if nothing to push.
5831 5831 """
5832 5832
5833 5833 opts = pycompat.byteskwargs(opts)
5834 5834
5835 5835 if opts.get(b'all_bookmarks'):
5836 5836 cmdutil.check_incompatible_arguments(
5837 5837 opts,
5838 5838 b'all_bookmarks',
5839 5839 [b'bookmark', b'rev'],
5840 5840 )
5841 5841 opts[b'bookmark'] = list(repo._bookmarks)
5842 5842
5843 5843 if opts.get(b'bookmark'):
5844 5844 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5845 5845 for b in opts[b'bookmark']:
5846 5846 # translate -B options to -r so changesets get pushed
5847 5847 b = repo._bookmarks.expandname(b)
5848 5848 if b in repo._bookmarks:
5849 5849 opts.setdefault(b'rev', []).append(b)
5850 5850 else:
5851 5851 # if we try to push a deleted bookmark, translate it to null
5852 5852 # this lets simultaneous -r, -b options continue working
5853 5853 opts.setdefault(b'rev', []).append(b"null")
5854 5854
5855 5855 some_pushed = False
5856 5856 result = 0
5857 5857 for path in urlutil.get_push_paths(repo, ui, dests):
5858 5858 dest = path.loc
5859 5859 branches = (path.branch, opts.get(b'branch') or [])
5860 5860 ui.status(_(b'pushing to %s\n') % urlutil.hidepassword(dest))
5861 5861 revs, checkout = hg.addbranchrevs(
5862 5862 repo, repo, branches, opts.get(b'rev')
5863 5863 )
5864 5864 other = hg.peer(repo, opts, dest)
5865 5865
5866 5866 try:
5867 5867 if revs:
5868 5868 revs = [repo[r].node() for r in logcmdutil.revrange(repo, revs)]
5869 5869 if not revs:
5870 5870 raise error.InputError(
5871 5871 _(b"specified revisions evaluate to an empty set"),
5872 5872 hint=_(b"use different revision arguments"),
5873 5873 )
5874 5874 elif path.pushrev:
5875 5875 # It doesn't make any sense to specify ancestor revisions. So limit
5876 5876 # to DAG heads to make discovery simpler.
5877 5877 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5878 5878 revs = scmutil.revrange(repo, [expr])
5879 5879 revs = [repo[rev].node() for rev in revs]
5880 5880 if not revs:
5881 5881 raise error.InputError(
5882 5882 _(
5883 5883 b'default push revset for path evaluates to an empty set'
5884 5884 )
5885 5885 )
5886 5886 elif ui.configbool(b'commands', b'push.require-revs'):
5887 5887 raise error.InputError(
5888 5888 _(b'no revisions specified to push'),
5889 5889 hint=_(b'did you mean "hg push -r ."?'),
5890 5890 )
5891 5891
5892 5892 repo._subtoppath = dest
5893 5893 try:
5894 5894 # push subrepos depth-first for coherent ordering
5895 5895 c = repo[b'.']
5896 5896 subs = c.substate # only repos that are committed
5897 5897 for s in sorted(subs):
5898 5898 sub_result = c.sub(s).push(opts)
5899 5899 if sub_result == 0:
5900 5900 return 1
5901 5901 finally:
5902 5902 del repo._subtoppath
5903 5903
5904 5904 opargs = dict(
5905 5905 opts.get(b'opargs', {})
5906 5906 ) # copy opargs since we may mutate it
5907 5907 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5908 5908
5909 5909 pushop = exchange.push(
5910 5910 repo,
5911 5911 other,
5912 5912 opts.get(b'force'),
5913 5913 revs=revs,
5914 5914 newbranch=opts.get(b'new_branch'),
5915 5915 bookmarks=opts.get(b'bookmark', ()),
5916 5916 publish=opts.get(b'publish'),
5917 5917 opargs=opargs,
5918 5918 )
5919 5919
5920 5920 if pushop.cgresult == 0:
5921 5921 result = 1
5922 5922 elif pushop.cgresult is not None:
5923 5923 some_pushed = True
5924 5924
5925 5925 if pushop.bkresult is not None:
5926 5926 if pushop.bkresult == 2:
5927 5927 result = 2
5928 5928 elif not result and pushop.bkresult:
5929 5929 result = 2
5930 5930
5931 5931 if result:
5932 5932 break
5933 5933
5934 5934 finally:
5935 5935 other.close()
5936 5936 if result == 0 and not some_pushed:
5937 5937 result = 1
5938 5938 return result
5939 5939
5940 5940
5941 5941 @command(
5942 5942 b'recover',
5943 5943 [
5944 5944 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5945 5945 ],
5946 5946 helpcategory=command.CATEGORY_MAINTENANCE,
5947 5947 )
5948 5948 def recover(ui, repo, **opts):
5949 5949 """roll back an interrupted transaction
5950 5950
5951 5951 Recover from an interrupted commit or pull.
5952 5952
5953 5953 This command tries to fix the repository status after an
5954 5954 interrupted operation. It should only be necessary when Mercurial
5955 5955 suggests it.
5956 5956
5957 5957 Returns 0 if successful, 1 if nothing to recover or verify fails.
5958 5958 """
5959 5959 ret = repo.recover()
5960 5960 if ret:
5961 5961 if opts['verify']:
5962 5962 return hg.verify(repo)
5963 5963 else:
5964 5964 msg = _(
5965 5965 b"(verify step skipped, run `hg verify` to check your "
5966 5966 b"repository content)\n"
5967 5967 )
5968 5968 ui.warn(msg)
5969 5969 return 0
5970 5970 return 1
5971 5971
5972 5972
5973 5973 @command(
5974 5974 b'remove|rm',
5975 5975 [
5976 5976 (b'A', b'after', None, _(b'record delete for missing files')),
5977 5977 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5978 5978 ]
5979 5979 + subrepoopts
5980 5980 + walkopts
5981 5981 + dryrunopts,
5982 5982 _(b'[OPTION]... FILE...'),
5983 5983 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5984 5984 helpbasic=True,
5985 5985 inferrepo=True,
5986 5986 )
5987 5987 def remove(ui, repo, *pats, **opts):
5988 5988 """remove the specified files on the next commit
5989 5989
5990 5990 Schedule the indicated files for removal from the current branch.
5991 5991
5992 5992 This command schedules the files to be removed at the next commit.
5993 5993 To undo a remove before that, see :hg:`revert`. To undo added
5994 5994 files, see :hg:`forget`.
5995 5995
5996 5996 .. container:: verbose
5997 5997
5998 5998 -A/--after can be used to remove only files that have already
5999 5999 been deleted, -f/--force can be used to force deletion, and -Af
6000 6000 can be used to remove files from the next revision without
6001 6001 deleting them from the working directory.
6002 6002
6003 6003 The following table details the behavior of remove for different
6004 6004 file states (columns) and option combinations (rows). The file
6005 6005 states are Added [A], Clean [C], Modified [M] and Missing [!]
6006 6006 (as reported by :hg:`status`). The actions are Warn, Remove
6007 6007 (from branch) and Delete (from disk):
6008 6008
6009 6009 ========= == == == ==
6010 6010 opt/state A C M !
6011 6011 ========= == == == ==
6012 6012 none W RD W R
6013 6013 -f R RD RD R
6014 6014 -A W W W R
6015 6015 -Af R R R R
6016 6016 ========= == == == ==
6017 6017
6018 6018 .. note::
6019 6019
6020 6020 :hg:`remove` never deletes files in Added [A] state from the
6021 6021 working directory, not even if ``--force`` is specified.
6022 6022
6023 6023 Returns 0 on success, 1 if any warnings encountered.
6024 6024 """
6025 6025
6026 6026 after, force = opts.get('after'), opts.get('force')
6027 6027 dryrun = opts.get('dry_run')
6028 6028 if not pats and not after:
6029 6029 raise error.InputError(_(b'no files specified'))
6030 6030
6031 6031 with repo.wlock(), repo.dirstate.changing_files(repo):
6032 6032 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
6033 6033 subrepos = opts.get('subrepos')
6034 6034 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
6035 6035 return cmdutil.remove(
6036 6036 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
6037 6037 )
6038 6038
6039 6039
6040 6040 @command(
6041 6041 b'rename|move|mv',
6042 6042 [
6043 6043 (b'', b'forget', None, _(b'unmark a destination file as renamed')),
6044 6044 (b'A', b'after', None, _(b'record a rename that has already occurred')),
6045 6045 (
6046 6046 b'',
6047 6047 b'at-rev',
6048 6048 b'',
6049 6049 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
6050 6050 _(b'REV'),
6051 6051 ),
6052 6052 (
6053 6053 b'f',
6054 6054 b'force',
6055 6055 None,
6056 6056 _(b'forcibly move over an existing managed file'),
6057 6057 ),
6058 6058 ]
6059 6059 + walkopts
6060 6060 + dryrunopts,
6061 6061 _(b'[OPTION]... SOURCE... DEST'),
6062 6062 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6063 6063 )
6064 6064 def rename(ui, repo, *pats, **opts):
6065 6065 """rename files; equivalent of copy + remove
6066 6066
6067 6067 Mark dest as copies of sources; mark sources for deletion. If dest
6068 6068 is a directory, copies are put in that directory. If dest is a
6069 6069 file, there can only be one source.
6070 6070
6071 6071 By default, this command copies the contents of files as they
6072 6072 exist in the working directory. If invoked with -A/--after, the
6073 6073 operation is recorded, but no copying is performed.
6074 6074
6075 6075 To undo marking a destination file as renamed, use --forget. With that
6076 6076 option, all given (positional) arguments are unmarked as renames. The
6077 6077 destination file(s) will be left in place (still tracked). The source
6078 6078 file(s) will not be restored. Note that :hg:`rename --forget` behaves
6079 6079 the same way as :hg:`copy --forget`.
6080 6080
6081 6081 This command takes effect with the next commit by default.
6082 6082
6083 6083 Returns 0 on success, 1 if errors are encountered.
6084 6084 """
6085 6085 context = lambda repo: repo.dirstate.changing_files(repo)
6086 6086 rev = opts.get('at_rev')
6087 6087
6088 6088 if rev:
6089 6089 ctx = logcmdutil.revsingle(repo, rev)
6090 6090 if ctx.rev() is not None:
6091 6091
6092 6092 def context(repo):
6093 6093 return util.nullcontextmanager()
6094 6094
6095 6095 opts['at_rev'] = ctx.rev()
6096 6096 with repo.wlock(), context(repo):
6097 6097 return cmdutil.copy(
6098 6098 ui, repo, pats, pycompat.byteskwargs(opts), rename=True
6099 6099 )
6100 6100
6101 6101
6102 6102 @command(
6103 6103 b'resolve',
6104 6104 [
6105 6105 (b'a', b'all', None, _(b'select all unresolved files')),
6106 6106 (b'l', b'list', None, _(b'list state of files needing merge')),
6107 6107 (b'm', b'mark', None, _(b'mark files as resolved')),
6108 6108 (b'u', b'unmark', None, _(b'mark files as unresolved')),
6109 6109 (b'n', b'no-status', None, _(b'hide status prefix')),
6110 6110 (b'', b're-merge', None, _(b're-merge files')),
6111 6111 ]
6112 6112 + mergetoolopts
6113 6113 + walkopts
6114 6114 + formatteropts,
6115 6115 _(b'[OPTION]... [FILE]...'),
6116 6116 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6117 6117 inferrepo=True,
6118 6118 )
6119 6119 def resolve(ui, repo, *pats, **opts):
6120 6120 """redo merges or set/view the merge status of files
6121 6121
6122 6122 Merges with unresolved conflicts are often the result of
6123 6123 non-interactive merging using the ``internal:merge`` configuration
6124 6124 setting, or a command-line merge tool like ``diff3``. The resolve
6125 6125 command is used to manage the files involved in a merge, after
6126 6126 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6127 6127 working directory must have two parents). See :hg:`help
6128 6128 merge-tools` for information on configuring merge tools.
6129 6129
6130 6130 The resolve command can be used in the following ways:
6131 6131
6132 6132 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
6133 6133 the specified files, discarding any previous merge attempts. Re-merging
6134 6134 is not performed for files already marked as resolved. Use ``--all/-a``
6135 6135 to select all unresolved files. ``--tool`` can be used to specify
6136 6136 the merge tool used for the given files. It overrides the HGMERGE
6137 6137 environment variable and your configuration files. Previous file
6138 6138 contents are saved with a ``.orig`` suffix.
6139 6139
6140 6140 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6141 6141 (e.g. after having manually fixed-up the files). The default is
6142 6142 to mark all unresolved files.
6143 6143
6144 6144 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6145 6145 default is to mark all resolved files.
6146 6146
6147 6147 - :hg:`resolve -l`: list files which had or still have conflicts.
6148 6148 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6149 6149 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
6150 6150 the list. See :hg:`help filesets` for details.
6151 6151
6152 6152 .. note::
6153 6153
6154 6154 Mercurial will not let you commit files with unresolved merge
6155 6155 conflicts. You must use :hg:`resolve -m ...` before you can
6156 6156 commit after a conflicting merge.
6157 6157
6158 6158 .. container:: verbose
6159 6159
6160 6160 Template:
6161 6161
6162 6162 The following keywords are supported in addition to the common template
6163 6163 keywords and functions. See also :hg:`help templates`.
6164 6164
6165 6165 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
6166 6166 :path: String. Repository-absolute path of the file.
6167 6167
6168 6168 Returns 0 on success, 1 if any files fail a resolve attempt.
6169 6169 """
6170 6170
6171 6171 opts = pycompat.byteskwargs(opts)
6172 6172 confirm = ui.configbool(b'commands', b'resolve.confirm')
6173 6173 flaglist = b'all mark unmark list no_status re_merge'.split()
6174 6174 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
6175 6175
6176 6176 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
6177 6177 if actioncount > 1:
6178 6178 raise error.InputError(_(b"too many actions specified"))
6179 6179 elif actioncount == 0 and ui.configbool(
6180 6180 b'commands', b'resolve.explicit-re-merge'
6181 6181 ):
6182 6182 hint = _(b'use --mark, --unmark, --list or --re-merge')
6183 6183 raise error.InputError(_(b'no action specified'), hint=hint)
6184 6184 if pats and all:
6185 6185 raise error.InputError(_(b"can't specify --all and patterns"))
6186 6186 if not (all or pats or show or mark or unmark):
6187 6187 raise error.InputError(
6188 6188 _(b'no files or directories specified'),
6189 6189 hint=b'use --all to re-merge all unresolved files',
6190 6190 )
6191 6191
6192 6192 if confirm:
6193 6193 if all:
6194 6194 if ui.promptchoice(
6195 6195 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
6196 6196 ):
6197 6197 raise error.CanceledError(_(b'user quit'))
6198 6198 if mark and not pats:
6199 6199 if ui.promptchoice(
6200 6200 _(
6201 6201 b'mark all unresolved files as resolved (yn)?'
6202 6202 b'$$ &Yes $$ &No'
6203 6203 )
6204 6204 ):
6205 6205 raise error.CanceledError(_(b'user quit'))
6206 6206 if unmark and not pats:
6207 6207 if ui.promptchoice(
6208 6208 _(
6209 6209 b'mark all resolved files as unresolved (yn)?'
6210 6210 b'$$ &Yes $$ &No'
6211 6211 )
6212 6212 ):
6213 6213 raise error.CanceledError(_(b'user quit'))
6214 6214
6215 6215 uipathfn = scmutil.getuipathfn(repo)
6216 6216
6217 6217 if show:
6218 6218 ui.pager(b'resolve')
6219 6219 fm = ui.formatter(b'resolve', opts)
6220 6220 ms = mergestatemod.mergestate.read(repo)
6221 6221 wctx = repo[None]
6222 6222 m = scmutil.match(wctx, pats, opts)
6223 6223
6224 6224 # Labels and keys based on merge state. Unresolved path conflicts show
6225 6225 # as 'P'. Resolved path conflicts show as 'R', the same as normal
6226 6226 # resolved conflicts.
6227 6227 mergestateinfo = {
6228 6228 mergestatemod.MERGE_RECORD_UNRESOLVED: (
6229 6229 b'resolve.unresolved',
6230 6230 b'U',
6231 6231 ),
6232 6232 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
6233 6233 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
6234 6234 b'resolve.unresolved',
6235 6235 b'P',
6236 6236 ),
6237 6237 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
6238 6238 b'resolve.resolved',
6239 6239 b'R',
6240 6240 ),
6241 6241 }
6242 6242
6243 6243 for f in ms:
6244 6244 if not m(f):
6245 6245 continue
6246 6246
6247 6247 label, key = mergestateinfo[ms[f]]
6248 6248 fm.startitem()
6249 6249 fm.context(ctx=wctx)
6250 6250 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
6251 6251 fm.data(path=f)
6252 6252 fm.plain(b'%s\n' % uipathfn(f), label=label)
6253 6253 fm.end()
6254 6254 return 0
6255 6255
6256 6256 with repo.wlock():
6257 6257 ms = mergestatemod.mergestate.read(repo)
6258 6258
6259 6259 if not (ms.active() or repo.dirstate.p2() != repo.nullid):
6260 6260 raise error.StateError(
6261 6261 _(b'resolve command not applicable when not merging')
6262 6262 )
6263 6263
6264 6264 wctx = repo[None]
6265 6265 m = scmutil.match(wctx, pats, opts)
6266 6266 ret = 0
6267 6267 didwork = False
6268 6268
6269 6269 hasconflictmarkers = []
6270 6270 if mark:
6271 6271 markcheck = ui.config(b'commands', b'resolve.mark-check')
6272 6272 if markcheck not in [b'warn', b'abort']:
6273 6273 # Treat all invalid / unrecognized values as 'none'.
6274 6274 markcheck = False
6275 6275 for f in ms:
6276 6276 if not m(f):
6277 6277 continue
6278 6278
6279 6279 didwork = True
6280 6280
6281 6281 # path conflicts must be resolved manually
6282 6282 if ms[f] in (
6283 6283 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6284 6284 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
6285 6285 ):
6286 6286 if mark:
6287 6287 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
6288 6288 elif unmark:
6289 6289 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
6290 6290 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
6291 6291 ui.warn(
6292 6292 _(b'%s: path conflict must be resolved manually\n')
6293 6293 % uipathfn(f)
6294 6294 )
6295 6295 continue
6296 6296
6297 6297 if mark:
6298 6298 if markcheck:
6299 6299 fdata = repo.wvfs.tryread(f)
6300 6300 if (
6301 6301 filemerge.hasconflictmarkers(fdata)
6302 6302 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6303 6303 ):
6304 6304 hasconflictmarkers.append(f)
6305 6305 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6306 6306 elif unmark:
6307 6307 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6308 6308 else:
6309 6309 # backup pre-resolve (merge uses .orig for its own purposes)
6310 6310 a = repo.wjoin(f)
6311 6311 try:
6312 6312 util.copyfile(a, a + b".resolve")
6313 6313 except FileNotFoundError:
6314 6314 pass
6315 6315
6316 6316 try:
6317 6317 # preresolve file
6318 6318 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6319 6319 with ui.configoverride(overrides, b'resolve'):
6320 6320 r = ms.resolve(f, wctx)
6321 6321 if r:
6322 6322 ret = 1
6323 6323 finally:
6324 6324 ms.commit()
6325 6325
6326 6326 # replace filemerge's .orig file with our resolve file
6327 6327 try:
6328 6328 util.rename(
6329 6329 a + b".resolve", scmutil.backuppath(ui, repo, f)
6330 6330 )
6331 6331 except FileNotFoundError:
6332 6332 pass
6333 6333
6334 6334 if hasconflictmarkers:
6335 6335 ui.warn(
6336 6336 _(
6337 6337 b'warning: the following files still have conflict '
6338 6338 b'markers:\n'
6339 6339 )
6340 6340 + b''.join(
6341 6341 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6342 6342 )
6343 6343 )
6344 6344 if markcheck == b'abort' and not all and not pats:
6345 6345 raise error.StateError(
6346 6346 _(b'conflict markers detected'),
6347 6347 hint=_(b'use --all to mark anyway'),
6348 6348 )
6349 6349
6350 6350 ms.commit()
6351 6351 branchmerge = repo.dirstate.p2() != repo.nullid
6352 6352 # resolve is not doing a parent change here, however, `record updates`
6353 6353 # will call some dirstate API that at intended for parent changes call.
6354 6354 # Ideally we would not need this and could implement a lighter version
6355 6355 # of the recordupdateslogic that will not have to deal with the part
6356 6356 # related to parent changes. However this would requires that:
6357 6357 # - we are sure we passed around enough information at update/merge
6358 6358 # time to no longer needs it at `hg resolve time`
6359 6359 # - we are sure we store that information well enough to be able to reuse it
6360 6360 # - we are the necessary logic to reuse it right.
6361 6361 #
6362 6362 # All this should eventually happens, but in the mean time, we use this
6363 6363 # context manager slightly out of the context it should be.
6364 6364 with repo.dirstate.changing_parents(repo):
6365 6365 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6366 6366
6367 6367 if not didwork and pats:
6368 6368 hint = None
6369 6369 if not any([p for p in pats if p.find(b':') >= 0]):
6370 6370 pats = [b'path:%s' % p for p in pats]
6371 6371 m = scmutil.match(wctx, pats, opts)
6372 6372 for f in ms:
6373 6373 if not m(f):
6374 6374 continue
6375 6375
6376 6376 def flag(o):
6377 6377 if o == b're_merge':
6378 6378 return b'--re-merge '
6379 6379 return b'-%s ' % o[0:1]
6380 6380
6381 6381 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6382 6382 hint = _(b"(try: hg resolve %s%s)\n") % (
6383 6383 flags,
6384 6384 b' '.join(pats),
6385 6385 )
6386 6386 break
6387 6387 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6388 6388 if hint:
6389 6389 ui.warn(hint)
6390 6390
6391 6391 unresolvedf = ms.unresolvedcount()
6392 6392 if not unresolvedf:
6393 6393 ui.status(_(b'(no more unresolved files)\n'))
6394 6394 cmdutil.checkafterresolved(repo)
6395 6395
6396 6396 return ret
6397 6397
6398 6398
6399 6399 @command(
6400 6400 b'revert',
6401 6401 [
6402 6402 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6403 6403 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6404 6404 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6405 6405 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6406 6406 (b'i', b'interactive', None, _(b'interactively select the changes')),
6407 6407 ]
6408 6408 + walkopts
6409 6409 + dryrunopts,
6410 6410 _(b'[OPTION]... [-r REV] [NAME]...'),
6411 6411 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6412 6412 )
6413 6413 def revert(ui, repo, *pats, **opts):
6414 6414 """restore files to their checkout state
6415 6415
6416 6416 .. note::
6417 6417
6418 6418 To check out earlier revisions, you should use :hg:`update REV`.
6419 6419 To cancel an uncommitted merge (and lose your changes),
6420 6420 use :hg:`merge --abort`.
6421 6421
6422 6422 With no revision specified, revert the specified files or directories
6423 6423 to the contents they had in the parent of the working directory.
6424 6424 This restores the contents of files to an unmodified
6425 6425 state and unschedules adds, removes, copies, and renames. If the
6426 6426 working directory has two parents, you must explicitly specify a
6427 6427 revision.
6428 6428
6429 6429 Using the -r/--rev or -d/--date options, revert the given files or
6430 6430 directories to their states as of a specific revision. Because
6431 6431 revert does not change the working directory parents, this will
6432 6432 cause these files to appear modified. This can be helpful to "back
6433 6433 out" some or all of an earlier change. See :hg:`backout` for a
6434 6434 related method.
6435 6435
6436 6436 Modified files are saved with a .orig suffix before reverting.
6437 6437 To disable these backups, use --no-backup. It is possible to store
6438 6438 the backup files in a custom directory relative to the root of the
6439 6439 repository by setting the ``ui.origbackuppath`` configuration
6440 6440 option.
6441 6441
6442 6442 See :hg:`help dates` for a list of formats valid for -d/--date.
6443 6443
6444 6444 See :hg:`help backout` for a way to reverse the effect of an
6445 6445 earlier changeset.
6446 6446
6447 6447 Returns 0 on success.
6448 6448 """
6449 6449
6450 6450 if opts.get("date"):
6451 6451 cmdutil.check_incompatible_arguments(opts, 'date', ['rev'])
6452 6452 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6453 6453
6454 6454 parent, p2 = repo.dirstate.parents()
6455 6455 if not opts.get('rev') and p2 != repo.nullid:
6456 6456 # revert after merge is a trap for new users (issue2915)
6457 6457 raise error.InputError(
6458 6458 _(b'uncommitted merge with no revision specified'),
6459 6459 hint=_(b"use 'hg update' or see 'hg help revert'"),
6460 6460 )
6461 6461
6462 6462 rev = opts.get('rev')
6463 6463 if rev:
6464 6464 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6465 6465 ctx = logcmdutil.revsingle(repo, rev)
6466 6466
6467 6467 if not (
6468 6468 pats
6469 6469 or opts.get('include')
6470 6470 or opts.get('exclude')
6471 6471 or opts.get('all')
6472 6472 or opts.get('interactive')
6473 6473 ):
6474 6474 msg = _(b"no files or directories specified")
6475 6475 if p2 != repo.nullid:
6476 6476 hint = _(
6477 6477 b"uncommitted merge, use --all to discard all changes,"
6478 6478 b" or 'hg update -C .' to abort the merge"
6479 6479 )
6480 6480 raise error.InputError(msg, hint=hint)
6481 6481 dirty = any(repo.status())
6482 6482 node = ctx.node()
6483 6483 if node != parent:
6484 6484 if dirty:
6485 6485 hint = (
6486 6486 _(
6487 6487 b"uncommitted changes, use --all to discard all"
6488 6488 b" changes, or 'hg update %d' to update"
6489 6489 )
6490 6490 % ctx.rev()
6491 6491 )
6492 6492 else:
6493 6493 hint = (
6494 6494 _(
6495 6495 b"use --all to revert all files,"
6496 6496 b" or 'hg update %d' to update"
6497 6497 )
6498 6498 % ctx.rev()
6499 6499 )
6500 6500 elif dirty:
6501 6501 hint = _(b"uncommitted changes, use --all to discard all changes")
6502 6502 else:
6503 6503 hint = _(b"use --all to revert all files")
6504 6504 raise error.InputError(msg, hint=hint)
6505 6505
6506 6506 return cmdutil.revert(ui, repo, ctx, *pats, **opts)
6507 6507
6508 6508
6509 6509 @command(
6510 6510 b'rollback',
6511 6511 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6512 6512 helpcategory=command.CATEGORY_MAINTENANCE,
6513 6513 )
6514 6514 def rollback(ui, repo, **opts):
6515 6515 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6516 6516
6517 6517 Please use :hg:`commit --amend` instead of rollback to correct
6518 6518 mistakes in the last commit.
6519 6519
6520 6520 This command should be used with care. There is only one level of
6521 6521 rollback, and there is no way to undo a rollback. It will also
6522 6522 restore the dirstate at the time of the last transaction, losing
6523 6523 any dirstate changes since that time. This command does not alter
6524 6524 the working directory.
6525 6525
6526 6526 Transactions are used to encapsulate the effects of all commands
6527 6527 that create new changesets or propagate existing changesets into a
6528 6528 repository.
6529 6529
6530 6530 .. container:: verbose
6531 6531
6532 6532 For example, the following commands are transactional, and their
6533 6533 effects can be rolled back:
6534 6534
6535 6535 - commit
6536 6536 - import
6537 6537 - pull
6538 6538 - push (with this repository as the destination)
6539 6539 - unbundle
6540 6540
6541 6541 To avoid permanent data loss, rollback will refuse to rollback a
6542 6542 commit transaction if it isn't checked out. Use --force to
6543 6543 override this protection.
6544 6544
6545 6545 The rollback command can be entirely disabled by setting the
6546 6546 ``ui.rollback`` configuration setting to false. If you're here
6547 6547 because you want to use rollback and it's disabled, you can
6548 6548 re-enable the command by setting ``ui.rollback`` to true.
6549 6549
6550 6550 This command is not intended for use on public repositories. Once
6551 6551 changes are visible for pull by other users, rolling a transaction
6552 6552 back locally is ineffective (someone else may already have pulled
6553 6553 the changes). Furthermore, a race is possible with readers of the
6554 6554 repository; for example an in-progress pull from the repository
6555 6555 may fail if a rollback is performed.
6556 6556
6557 6557 Returns 0 on success, 1 if no rollback data is available.
6558 6558 """
6559 6559 if not ui.configbool(b'ui', b'rollback'):
6560 6560 raise error.Abort(
6561 6561 _(b'rollback is disabled because it is unsafe'),
6562 6562 hint=b'see `hg help -v rollback` for information',
6563 6563 )
6564 6564 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6565 6565
6566 6566
6567 6567 @command(
6568 6568 b'root',
6569 6569 [] + formatteropts,
6570 6570 intents={INTENT_READONLY},
6571 6571 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6572 6572 )
6573 6573 def root(ui, repo, **opts):
6574 6574 """print the root (top) of the current working directory
6575 6575
6576 6576 Print the root directory of the current repository.
6577 6577
6578 6578 .. container:: verbose
6579 6579
6580 6580 Template:
6581 6581
6582 6582 The following keywords are supported in addition to the common template
6583 6583 keywords and functions. See also :hg:`help templates`.
6584 6584
6585 6585 :hgpath: String. Path to the .hg directory.
6586 6586 :storepath: String. Path to the directory holding versioned data.
6587 6587
6588 6588 Returns 0 on success.
6589 6589 """
6590 6590 opts = pycompat.byteskwargs(opts)
6591 6591 with ui.formatter(b'root', opts) as fm:
6592 6592 fm.startitem()
6593 6593 fm.write(b'reporoot', b'%s\n', repo.root)
6594 6594 fm.data(hgpath=repo.path, storepath=repo.spath)
6595 6595
6596 6596
6597 6597 @command(
6598 6598 b'serve',
6599 6599 [
6600 6600 (
6601 6601 b'A',
6602 6602 b'accesslog',
6603 6603 b'',
6604 6604 _(b'name of access log file to write to'),
6605 6605 _(b'FILE'),
6606 6606 ),
6607 6607 (b'd', b'daemon', None, _(b'run server in background')),
6608 6608 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6609 6609 (
6610 6610 b'E',
6611 6611 b'errorlog',
6612 6612 b'',
6613 6613 _(b'name of error log file to write to'),
6614 6614 _(b'FILE'),
6615 6615 ),
6616 6616 # use string type, then we can check if something was passed
6617 6617 (
6618 6618 b'p',
6619 6619 b'port',
6620 6620 b'',
6621 6621 _(b'port to listen on (default: 8000)'),
6622 6622 _(b'PORT'),
6623 6623 ),
6624 6624 (
6625 6625 b'a',
6626 6626 b'address',
6627 6627 b'',
6628 6628 _(b'address to listen on (default: all interfaces)'),
6629 6629 _(b'ADDR'),
6630 6630 ),
6631 6631 (
6632 6632 b'',
6633 6633 b'prefix',
6634 6634 b'',
6635 6635 _(b'prefix path to serve from (default: server root)'),
6636 6636 _(b'PREFIX'),
6637 6637 ),
6638 6638 (
6639 6639 b'n',
6640 6640 b'name',
6641 6641 b'',
6642 6642 _(b'name to show in web pages (default: working directory)'),
6643 6643 _(b'NAME'),
6644 6644 ),
6645 6645 (
6646 6646 b'',
6647 6647 b'web-conf',
6648 6648 b'',
6649 6649 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6650 6650 _(b'FILE'),
6651 6651 ),
6652 6652 (
6653 6653 b'',
6654 6654 b'webdir-conf',
6655 6655 b'',
6656 6656 _(b'name of the hgweb config file (DEPRECATED)'),
6657 6657 _(b'FILE'),
6658 6658 ),
6659 6659 (
6660 6660 b'',
6661 6661 b'pid-file',
6662 6662 b'',
6663 6663 _(b'name of file to write process ID to'),
6664 6664 _(b'FILE'),
6665 6665 ),
6666 6666 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6667 6667 (
6668 6668 b'',
6669 6669 b'cmdserver',
6670 6670 b'',
6671 6671 _(b'for remote clients (ADVANCED)'),
6672 6672 _(b'MODE'),
6673 6673 ),
6674 6674 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6675 6675 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6676 6676 (b'6', b'ipv6', None, _(b'use IPv6 instead of IPv4')),
6677 6677 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6678 6678 (b'', b'print-url', None, _(b'start and print only the URL')),
6679 6679 ]
6680 6680 + subrepoopts,
6681 6681 _(b'[OPTION]...'),
6682 6682 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6683 6683 helpbasic=True,
6684 6684 optionalrepo=True,
6685 6685 )
6686 6686 def serve(ui, repo, **opts):
6687 6687 """start stand-alone webserver
6688 6688
6689 6689 Start a local HTTP repository browser and pull server. You can use
6690 6690 this for ad-hoc sharing and browsing of repositories. It is
6691 6691 recommended to use a real web server to serve a repository for
6692 6692 longer periods of time.
6693 6693
6694 6694 Please note that the server does not implement access control.
6695 6695 This means that, by default, anybody can read from the server and
6696 6696 nobody can write to it by default. Set the ``web.allow-push``
6697 6697 option to ``*`` to allow everybody to push to the server. You
6698 6698 should use a real web server if you need to authenticate users.
6699 6699
6700 6700 By default, the server logs accesses to stdout and errors to
6701 6701 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6702 6702 files.
6703 6703
6704 6704 To have the server choose a free port number to listen on, specify
6705 6705 a port number of 0; in this case, the server will print the port
6706 6706 number it uses.
6707 6707
6708 6708 Returns 0 on success.
6709 6709 """
6710 6710
6711 6711 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6712 6712 opts = pycompat.byteskwargs(opts)
6713 6713 if opts[b"print_url"] and ui.verbose:
6714 6714 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6715 6715
6716 6716 if opts[b"stdio"]:
6717 6717 if repo is None:
6718 6718 raise error.RepoError(
6719 6719 _(b"there is no Mercurial repository here (.hg not found)")
6720 6720 )
6721 6721 accesshidden = False
6722 6722 if repo.filtername is None:
6723 6723 allow = ui.configlist(
6724 6724 b'experimental', b'server.allow-hidden-access'
6725 6725 )
6726 6726 user = procutil.getuser()
6727 6727 if allow and scmutil.ismember(ui, user, allow):
6728 6728 accesshidden = True
6729 6729 else:
6730 6730 msg = (
6731 6731 _(
6732 6732 b'ignoring request to access hidden changeset by '
6733 6733 b'unauthorized user: %s\n'
6734 6734 )
6735 6735 % user
6736 6736 )
6737 6737 ui.warn(msg)
6738 6738
6739 6739 s = wireprotoserver.sshserver(ui, repo, accesshidden=accesshidden)
6740 6740 s.serve_forever()
6741 6741 return
6742 6742
6743 6743 service = server.createservice(ui, repo, opts)
6744 6744 return server.runservice(opts, initfn=service.init, runfn=service.run)
6745 6745
6746 6746
6747 6747 @command(
6748 6748 b'shelve',
6749 6749 [
6750 6750 (
6751 6751 b'A',
6752 6752 b'addremove',
6753 6753 None,
6754 6754 _(b'mark new/missing files as added/removed before shelving'),
6755 6755 ),
6756 6756 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6757 6757 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6758 6758 (
6759 6759 b'',
6760 6760 b'date',
6761 6761 b'',
6762 6762 _(b'shelve with the specified commit date'),
6763 6763 _(b'DATE'),
6764 6764 ),
6765 6765 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6766 6766 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6767 6767 (
6768 6768 b'k',
6769 6769 b'keep',
6770 6770 False,
6771 6771 _(b'shelve, but keep changes in the working directory'),
6772 6772 ),
6773 6773 (b'l', b'list', None, _(b'list current shelves')),
6774 6774 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6775 6775 (
6776 6776 b'n',
6777 6777 b'name',
6778 6778 b'',
6779 6779 _(b'use the given name for the shelved commit'),
6780 6780 _(b'NAME'),
6781 6781 ),
6782 6782 (
6783 6783 b'p',
6784 6784 b'patch',
6785 6785 None,
6786 6786 _(
6787 6787 b'output patches for changes (provide the names of the shelved '
6788 6788 b'changes as positional arguments)'
6789 6789 ),
6790 6790 ),
6791 6791 (b'i', b'interactive', None, _(b'interactive mode')),
6792 6792 (
6793 6793 b'',
6794 6794 b'stat',
6795 6795 None,
6796 6796 _(
6797 6797 b'output diffstat-style summary of changes (provide the names of '
6798 6798 b'the shelved changes as positional arguments)'
6799 6799 ),
6800 6800 ),
6801 6801 ]
6802 6802 + cmdutil.walkopts,
6803 6803 _(b'hg shelve [OPTION]... [FILE]...'),
6804 6804 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6805 6805 )
6806 6806 def shelve(ui, repo, *pats, **opts):
6807 6807 """save and set aside changes from the working directory
6808 6808
6809 6809 Shelving takes files that "hg status" reports as not clean, saves
6810 6810 the modifications to a bundle (a shelved change), and reverts the
6811 6811 files so that their state in the working directory becomes clean.
6812 6812
6813 6813 To restore these changes to the working directory, using "hg
6814 6814 unshelve"; this will work even if you switch to a different
6815 6815 commit.
6816 6816
6817 6817 When no files are specified, "hg shelve" saves all not-clean
6818 6818 files. If specific files or directories are named, only changes to
6819 6819 those files are shelved.
6820 6820
6821 6821 In bare shelve (when no files are specified, without interactive,
6822 6822 include and exclude option), shelving remembers information if the
6823 6823 working directory was on newly created branch, in other words working
6824 6824 directory was on different branch than its first parent. In this
6825 6825 situation unshelving restores branch information to the working directory.
6826 6826
6827 6827 Each shelved change has a name that makes it easier to find later.
6828 6828 The name of a shelved change defaults to being based on the active
6829 6829 bookmark, or if there is no active bookmark, the current named
6830 6830 branch. To specify a different name, use ``--name``.
6831 6831
6832 6832 To see a list of existing shelved changes, use the ``--list``
6833 6833 option. For each shelved change, this will print its name, age,
6834 6834 and description; use ``--patch`` or ``--stat`` for more details.
6835 6835
6836 6836 To delete specific shelved changes, use ``--delete``. To delete
6837 6837 all shelved changes, use ``--cleanup``.
6838 6838 """
6839 6839 opts = pycompat.byteskwargs(opts)
6840 6840 allowables = [
6841 6841 (b'addremove', {b'create'}), # 'create' is pseudo action
6842 6842 (b'unknown', {b'create'}),
6843 6843 (b'cleanup', {b'cleanup'}),
6844 6844 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6845 6845 (b'delete', {b'delete'}),
6846 6846 (b'edit', {b'create'}),
6847 6847 (b'keep', {b'create'}),
6848 6848 (b'list', {b'list'}),
6849 6849 (b'message', {b'create'}),
6850 6850 (b'name', {b'create'}),
6851 6851 (b'patch', {b'patch', b'list'}),
6852 6852 (b'stat', {b'stat', b'list'}),
6853 6853 ]
6854 6854
6855 6855 def checkopt(opt):
6856 6856 if opts.get(opt):
6857 6857 for i, allowable in allowables:
6858 6858 if opts[i] and opt not in allowable:
6859 6859 raise error.InputError(
6860 6860 _(
6861 6861 b"options '--%s' and '--%s' may not be "
6862 6862 b"used together"
6863 6863 )
6864 6864 % (opt, i)
6865 6865 )
6866 6866 return True
6867 6867
6868 6868 if checkopt(b'cleanup'):
6869 6869 if pats:
6870 6870 raise error.InputError(
6871 6871 _(b"cannot specify names when using '--cleanup'")
6872 6872 )
6873 6873 return shelvemod.cleanupcmd(ui, repo)
6874 6874 elif checkopt(b'delete'):
6875 6875 return shelvemod.deletecmd(ui, repo, pats)
6876 6876 elif checkopt(b'list'):
6877 6877 return shelvemod.listcmd(ui, repo, pats, opts)
6878 6878 elif checkopt(b'patch') or checkopt(b'stat'):
6879 6879 return shelvemod.patchcmds(ui, repo, pats, opts)
6880 6880 else:
6881 6881 return shelvemod.createcmd(ui, repo, pats, opts)
6882 6882
6883 6883
6884 6884 _NOTTERSE = b'nothing'
6885 6885
6886 6886
6887 6887 @command(
6888 6888 b'status|st',
6889 6889 [
6890 6890 (b'A', b'all', None, _(b'show status of all files')),
6891 6891 (b'm', b'modified', None, _(b'show only modified files')),
6892 6892 (b'a', b'added', None, _(b'show only added files')),
6893 6893 (b'r', b'removed', None, _(b'show only removed files')),
6894 6894 (b'd', b'deleted', None, _(b'show only missing files')),
6895 6895 (b'c', b'clean', None, _(b'show only files without changes')),
6896 6896 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6897 6897 (b'i', b'ignored', None, _(b'show only ignored files')),
6898 6898 (b'n', b'no-status', None, _(b'hide status prefix')),
6899 6899 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6900 6900 (
6901 6901 b'C',
6902 6902 b'copies',
6903 6903 None,
6904 6904 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6905 6905 ),
6906 6906 (
6907 6907 b'0',
6908 6908 b'print0',
6909 6909 None,
6910 6910 _(b'end filenames with NUL, for use with xargs'),
6911 6911 ),
6912 6912 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6913 6913 (
6914 6914 b'',
6915 6915 b'change',
6916 6916 b'',
6917 6917 _(b'list the changed files of a revision'),
6918 6918 _(b'REV'),
6919 6919 ),
6920 6920 ]
6921 6921 + walkopts
6922 6922 + subrepoopts
6923 6923 + formatteropts,
6924 6924 _(b'[OPTION]... [FILE]...'),
6925 6925 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6926 6926 helpbasic=True,
6927 6927 inferrepo=True,
6928 6928 intents={INTENT_READONLY},
6929 6929 )
6930 6930 def status(ui, repo, *pats, **opts):
6931 6931 """show changed files in the working directory
6932 6932
6933 6933 Show status of files in the repository. If names are given, only
6934 6934 files that match are shown. Files that are clean or ignored or
6935 6935 the source of a copy/move operation, are not listed unless
6936 6936 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6937 6937 Unless options described with "show only ..." are given, the
6938 6938 options -mardu are used.
6939 6939
6940 6940 Option -q/--quiet hides untracked (unknown and ignored) files
6941 6941 unless explicitly requested with -u/--unknown or -i/--ignored.
6942 6942
6943 6943 .. note::
6944 6944
6945 6945 :hg:`status` may appear to disagree with diff if permissions have
6946 6946 changed or a merge has occurred. The standard diff format does
6947 6947 not report permission changes and diff only reports changes
6948 6948 relative to one merge parent.
6949 6949
6950 6950 If one revision is given, it is used as the base revision.
6951 6951 If two revisions are given, the differences between them are
6952 6952 shown. The --change option can also be used as a shortcut to list
6953 6953 the changed files of a revision from its first parent.
6954 6954
6955 6955 The codes used to show the status of files are::
6956 6956
6957 6957 M = modified
6958 6958 A = added
6959 6959 R = removed
6960 6960 C = clean
6961 6961 ! = missing (deleted by non-hg command, but still tracked)
6962 6962 ? = not tracked
6963 6963 I = ignored
6964 6964 = origin of the previous file (with --copies)
6965 6965
6966 6966 .. container:: verbose
6967 6967
6968 6968 The -t/--terse option abbreviates the output by showing only the directory
6969 6969 name if all the files in it share the same status. The option takes an
6970 6970 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6971 6971 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6972 6972 for 'ignored' and 'c' for clean.
6973 6973
6974 6974 It abbreviates only those statuses which are passed. Note that clean and
6975 6975 ignored files are not displayed with '--terse ic' unless the -c/--clean
6976 6976 and -i/--ignored options are also used.
6977 6977
6978 6978 The -v/--verbose option shows information when the repository is in an
6979 6979 unfinished merge, shelve, rebase state etc. You can have this behavior
6980 6980 turned on by default by enabling the ``commands.status.verbose`` option.
6981 6981
6982 6982 You can skip displaying some of these states by setting
6983 6983 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6984 6984 'histedit', 'merge', 'rebase', or 'unshelve'.
6985 6985
6986 6986 Template:
6987 6987
6988 6988 The following keywords are supported in addition to the common template
6989 6989 keywords and functions. See also :hg:`help templates`.
6990 6990
6991 6991 :path: String. Repository-absolute path of the file.
6992 6992 :source: String. Repository-absolute path of the file originated from.
6993 6993 Available if ``--copies`` is specified.
6994 6994 :status: String. Character denoting file's status.
6995 6995
6996 6996 Examples:
6997 6997
6998 6998 - show changes in the working directory relative to a
6999 6999 changeset::
7000 7000
7001 7001 hg status --rev 9353
7002 7002
7003 7003 - show changes in the working directory relative to the
7004 7004 current directory (see :hg:`help patterns` for more information)::
7005 7005
7006 7006 hg status re:
7007 7007
7008 7008 - show all changes including copies in an existing changeset::
7009 7009
7010 7010 hg status --copies --change 9353
7011 7011
7012 7012 - get a NUL separated list of added files, suitable for xargs::
7013 7013
7014 7014 hg status -an0
7015 7015
7016 7016 - show more information about the repository status, abbreviating
7017 7017 added, removed, modified, deleted, and untracked paths::
7018 7018
7019 7019 hg status -v -t mardu
7020 7020
7021 7021 Returns 0 on success.
7022 7022
7023 7023 """
7024 7024
7025 7025 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
7026 7026 opts = pycompat.byteskwargs(opts)
7027 7027 revs = opts.get(b'rev', [])
7028 7028 change = opts.get(b'change', b'')
7029 7029 terse = opts.get(b'terse', _NOTTERSE)
7030 7030 if terse is _NOTTERSE:
7031 7031 if revs:
7032 7032 terse = b''
7033 7033 else:
7034 7034 terse = ui.config(b'commands', b'status.terse')
7035 7035
7036 7036 if revs and terse:
7037 7037 msg = _(b'cannot use --terse with --rev')
7038 7038 raise error.InputError(msg)
7039 7039 elif change:
7040 7040 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
7041 7041 ctx2 = logcmdutil.revsingle(repo, change, None)
7042 7042 ctx1 = ctx2.p1()
7043 7043 else:
7044 7044 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
7045 7045 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
7046 7046
7047 7047 forcerelativevalue = None
7048 7048 if ui.hasconfig(b'commands', b'status.relative'):
7049 7049 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
7050 7050 uipathfn = scmutil.getuipathfn(
7051 7051 repo,
7052 7052 legacyrelativevalue=bool(pats),
7053 7053 forcerelativevalue=forcerelativevalue,
7054 7054 )
7055 7055
7056 7056 if opts.get(b'print0'):
7057 7057 end = b'\0'
7058 7058 else:
7059 7059 end = b'\n'
7060 7060 states = b'modified added removed deleted unknown ignored clean'.split()
7061 7061 show = [k for k in states if opts.get(k)]
7062 7062 if opts.get(b'all'):
7063 7063 show += ui.quiet and (states[:4] + [b'clean']) or states
7064 7064
7065 7065 if not show:
7066 7066 if ui.quiet:
7067 7067 show = states[:4]
7068 7068 else:
7069 7069 show = states[:5]
7070 7070
7071 7071 m = scmutil.match(ctx2, pats, opts)
7072 7072 if terse:
7073 7073 # we need to compute clean and unknown to terse
7074 7074 stat = repo.status(
7075 7075 ctx1.node(),
7076 7076 ctx2.node(),
7077 7077 m,
7078 7078 b'ignored' in show or b'i' in terse,
7079 7079 clean=True,
7080 7080 unknown=True,
7081 7081 listsubrepos=opts.get(b'subrepos'),
7082 7082 )
7083 7083
7084 7084 stat = cmdutil.tersedir(stat, terse)
7085 7085 else:
7086 7086 stat = repo.status(
7087 7087 ctx1.node(),
7088 7088 ctx2.node(),
7089 7089 m,
7090 7090 b'ignored' in show,
7091 7091 b'clean' in show,
7092 7092 b'unknown' in show,
7093 7093 opts.get(b'subrepos'),
7094 7094 )
7095 7095
7096 7096 changestates = zip(
7097 7097 states,
7098 7098 pycompat.iterbytestr(b'MAR!?IC'),
7099 7099 [getattr(stat, s.decode('utf8')) for s in states],
7100 7100 )
7101 7101
7102 7102 copy = {}
7103 7103 show_copies = ui.configbool(b'ui', b'statuscopies')
7104 7104 if opts.get(b'copies') is not None:
7105 7105 show_copies = opts.get(b'copies')
7106 7106 show_copies = (show_copies or opts.get(b'all')) and not opts.get(
7107 7107 b'no_status'
7108 7108 )
7109 7109 if show_copies:
7110 7110 copy = copies.pathcopies(ctx1, ctx2, m)
7111 7111
7112 7112 morestatus = None
7113 7113 if (
7114 7114 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
7115 7115 and not ui.plain()
7116 7116 and not opts.get(b'print0')
7117 7117 ):
7118 7118 morestatus = cmdutil.readmorestatus(repo)
7119 7119
7120 7120 ui.pager(b'status')
7121 7121 fm = ui.formatter(b'status', opts)
7122 7122 fmt = b'%s' + end
7123 7123 showchar = not opts.get(b'no_status')
7124 7124
7125 7125 for state, char, files in changestates:
7126 7126 if state in show:
7127 7127 label = b'status.' + state
7128 7128 for f in files:
7129 7129 fm.startitem()
7130 7130 fm.context(ctx=ctx2)
7131 7131 fm.data(itemtype=b'file', path=f)
7132 7132 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
7133 7133 fm.plain(fmt % uipathfn(f), label=label)
7134 7134 if f in copy:
7135 7135 fm.data(source=copy[f])
7136 7136 fm.plain(
7137 7137 (b' %s' + end) % uipathfn(copy[f]),
7138 7138 label=b'status.copied',
7139 7139 )
7140 7140 if morestatus:
7141 7141 morestatus.formatfile(f, fm)
7142 7142
7143 7143 if morestatus:
7144 7144 morestatus.formatfooter(fm)
7145 7145 fm.end()
7146 7146
7147 7147
7148 7148 @command(
7149 7149 b'summary|sum',
7150 7150 [(b'', b'remote', None, _(b'check for push and pull'))],
7151 7151 b'[--remote]',
7152 7152 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7153 7153 helpbasic=True,
7154 7154 intents={INTENT_READONLY},
7155 7155 )
7156 7156 def summary(ui, repo, **opts):
7157 7157 """summarize working directory state
7158 7158
7159 7159 This generates a brief summary of the working directory state,
7160 7160 including parents, branch, commit status, phase and available updates.
7161 7161
7162 7162 With the --remote option, this will check the default paths for
7163 7163 incoming and outgoing changes. This can be time-consuming.
7164 7164
7165 7165 Returns 0 on success.
7166 7166 """
7167 7167
7168 7168 ui.pager(b'summary')
7169 7169 ctx = repo[None]
7170 7170 parents = ctx.parents()
7171 7171 pnode = parents[0].node()
7172 7172 marks = []
7173 7173
7174 7174 try:
7175 7175 ms = mergestatemod.mergestate.read(repo)
7176 7176 except error.UnsupportedMergeRecords as e:
7177 7177 s = b' '.join(e.recordtypes)
7178 7178 ui.warn(
7179 7179 _(b'warning: merge state has unsupported record types: %s\n') % s
7180 7180 )
7181 7181 unresolved = []
7182 7182 else:
7183 7183 unresolved = list(ms.unresolved())
7184 7184
7185 7185 for p in parents:
7186 7186 # label with log.changeset (instead of log.parent) since this
7187 7187 # shows a working directory parent *changeset*:
7188 7188 # i18n: column positioning for "hg summary"
7189 7189 ui.write(
7190 7190 _(b'parent: %d:%s ') % (p.rev(), p),
7191 7191 label=logcmdutil.changesetlabels(p),
7192 7192 )
7193 7193 ui.write(b' '.join(p.tags()), label=b'log.tag')
7194 7194 if p.bookmarks():
7195 7195 marks.extend(p.bookmarks())
7196 7196 if p.rev() == -1:
7197 7197 if not len(repo):
7198 7198 ui.write(_(b' (empty repository)'))
7199 7199 else:
7200 7200 ui.write(_(b' (no revision checked out)'))
7201 7201 if p.obsolete():
7202 7202 ui.write(_(b' (obsolete)'))
7203 7203 if p.isunstable():
7204 7204 instabilities = (
7205 7205 ui.label(instability, b'trouble.%s' % instability)
7206 7206 for instability in p.instabilities()
7207 7207 )
7208 7208 ui.write(b' (' + b', '.join(instabilities) + b')')
7209 7209 ui.write(b'\n')
7210 7210 if p.description():
7211 7211 ui.status(
7212 7212 b' ' + p.description().splitlines()[0].strip() + b'\n',
7213 7213 label=b'log.summary',
7214 7214 )
7215 7215
7216 7216 branch = ctx.branch()
7217 7217 bheads = repo.branchheads(branch)
7218 7218 # i18n: column positioning for "hg summary"
7219 7219 m = _(b'branch: %s\n') % branch
7220 7220 if branch != b'default':
7221 7221 ui.write(m, label=b'log.branch')
7222 7222 else:
7223 7223 ui.status(m, label=b'log.branch')
7224 7224
7225 7225 if marks:
7226 7226 active = repo._activebookmark
7227 7227 # i18n: column positioning for "hg summary"
7228 7228 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
7229 7229 if active is not None:
7230 7230 if active in marks:
7231 7231 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
7232 7232 marks.remove(active)
7233 7233 else:
7234 7234 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
7235 7235 for m in marks:
7236 7236 ui.write(b' ' + m, label=b'log.bookmark')
7237 7237 ui.write(b'\n', label=b'log.bookmark')
7238 7238
7239 7239 status = repo.status(unknown=True)
7240 7240
7241 7241 c = repo.dirstate.copies()
7242 7242 copied, renamed = [], []
7243 7243 for d, s in c.items():
7244 7244 if s in status.removed:
7245 7245 status.removed.remove(s)
7246 7246 renamed.append(d)
7247 7247 else:
7248 7248 copied.append(d)
7249 7249 if d in status.added:
7250 7250 status.added.remove(d)
7251 7251
7252 7252 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7253 7253
7254 7254 labels = [
7255 7255 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7256 7256 (ui.label(_(b'%d added'), b'status.added'), status.added),
7257 7257 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7258 7258 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7259 7259 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7260 7260 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7261 7261 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7262 7262 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7263 7263 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7264 7264 ]
7265 7265 t = []
7266 7266 for l, s in labels:
7267 7267 if s:
7268 7268 t.append(l % len(s))
7269 7269
7270 7270 t = b', '.join(t)
7271 7271 cleanworkdir = False
7272 7272
7273 7273 if repo.vfs.exists(b'graftstate'):
7274 7274 t += _(b' (graft in progress)')
7275 7275 if repo.vfs.exists(b'updatestate'):
7276 7276 t += _(b' (interrupted update)')
7277 7277 elif len(parents) > 1:
7278 7278 t += _(b' (merge)')
7279 7279 elif branch != parents[0].branch():
7280 7280 t += _(b' (new branch)')
7281 7281 elif parents[0].closesbranch() and pnode in repo.branchheads(
7282 7282 branch, closed=True
7283 7283 ):
7284 7284 t += _(b' (head closed)')
7285 7285 elif not (
7286 7286 status.modified
7287 7287 or status.added
7288 7288 or status.removed
7289 7289 or renamed
7290 7290 or copied
7291 7291 or subs
7292 7292 ):
7293 7293 t += _(b' (clean)')
7294 7294 cleanworkdir = True
7295 7295 elif pnode not in bheads:
7296 7296 t += _(b' (new branch head)')
7297 7297
7298 7298 if parents:
7299 7299 pendingphase = max(p.phase() for p in parents)
7300 7300 else:
7301 7301 pendingphase = phases.public
7302 7302
7303 7303 if pendingphase > phases.newcommitphase(ui):
7304 7304 t += b' (%s)' % phases.phasenames[pendingphase]
7305 7305
7306 7306 if cleanworkdir:
7307 7307 # i18n: column positioning for "hg summary"
7308 7308 ui.status(_(b'commit: %s\n') % t.strip())
7309 7309 else:
7310 7310 # i18n: column positioning for "hg summary"
7311 7311 ui.write(_(b'commit: %s\n') % t.strip())
7312 7312
7313 7313 # all ancestors of branch heads - all ancestors of parent = new csets
7314 7314 new = len(
7315 7315 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7316 7316 )
7317 7317
7318 7318 if new == 0:
7319 7319 # i18n: column positioning for "hg summary"
7320 7320 ui.status(_(b'update: (current)\n'))
7321 7321 elif pnode not in bheads:
7322 7322 # i18n: column positioning for "hg summary"
7323 7323 ui.write(_(b'update: %d new changesets (update)\n') % new)
7324 7324 else:
7325 7325 # i18n: column positioning for "hg summary"
7326 7326 ui.write(
7327 7327 _(b'update: %d new changesets, %d branch heads (merge)\n')
7328 7328 % (new, len(bheads))
7329 7329 )
7330 7330
7331 7331 t = []
7332 7332 draft = len(repo.revs(b'draft()'))
7333 7333 if draft:
7334 7334 t.append(_(b'%d draft') % draft)
7335 7335 secret = len(repo.revs(b'secret()'))
7336 7336 if secret:
7337 7337 t.append(_(b'%d secret') % secret)
7338 7338
7339 7339 if draft or secret:
7340 7340 ui.status(_(b'phases: %s\n') % b', '.join(t))
7341 7341
7342 7342 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7343 7343 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7344 7344 numtrouble = len(repo.revs(trouble + b"()"))
7345 7345 # We write all the possibilities to ease translation
7346 7346 troublemsg = {
7347 7347 b"orphan": _(b"orphan: %d changesets"),
7348 7348 b"contentdivergent": _(b"content-divergent: %d changesets"),
7349 7349 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7350 7350 }
7351 7351 if numtrouble > 0:
7352 7352 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7353 7353
7354 7354 cmdutil.summaryhooks(ui, repo)
7355 7355
7356 7356 if opts.get('remote'):
7357 7357 needsincoming, needsoutgoing = True, True
7358 7358 else:
7359 7359 needsincoming, needsoutgoing = False, False
7360 7360 for i, o in cmdutil.summaryremotehooks(
7361 7361 ui, repo, pycompat.byteskwargs(opts), None
7362 7362 ):
7363 7363 if i:
7364 7364 needsincoming = True
7365 7365 if o:
7366 7366 needsoutgoing = True
7367 7367 if not needsincoming and not needsoutgoing:
7368 7368 return
7369 7369
7370 7370 def getincoming():
7371 7371 # XXX We should actually skip this if no default is specified, instead
7372 7372 # of passing "default" which will resolve as "./default/" if no default
7373 7373 # path is defined.
7374 7374 path = urlutil.get_unique_pull_path_obj(b'summary', ui, b'default')
7375 7375 sbranch = path.branch
7376 7376 try:
7377 7377 other = hg.peer(repo, {}, path)
7378 7378 except error.RepoError:
7379 7379 if opts.get('remote'):
7380 7380 raise
7381 7381 return path.loc, sbranch, None, None, None
7382 7382 branches = (path.branch, [])
7383 7383 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7384 7384 if revs:
7385 7385 revs = [other.lookup(rev) for rev in revs]
7386 7386 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(path.loc))
7387 7387 with repo.ui.silent():
7388 7388 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7389 7389 return path.loc, sbranch, other, commoninc, commoninc[1]
7390 7390
7391 7391 if needsincoming:
7392 7392 source, sbranch, sother, commoninc, incoming = getincoming()
7393 7393 else:
7394 7394 source = sbranch = sother = commoninc = incoming = None
7395 7395
7396 7396 def getoutgoing():
7397 7397 # XXX We should actually skip this if no default is specified, instead
7398 7398 # of passing "default" which will resolve as "./default/" if no default
7399 7399 # path is defined.
7400 7400 d = None
7401 7401 if b'default-push' in ui.paths:
7402 7402 d = b'default-push'
7403 7403 elif b'default' in ui.paths:
7404 7404 d = b'default'
7405 7405 path = None
7406 7406 if d is not None:
7407 7407 path = urlutil.get_unique_push_path(b'summary', repo, ui, d)
7408 7408 dest = path.loc
7409 7409 dbranch = path.branch
7410 7410 else:
7411 7411 dest = b'default'
7412 7412 dbranch = None
7413 7413 revs, checkout = hg.addbranchrevs(repo, repo, (dbranch, []), None)
7414 7414 if source != dest:
7415 7415 try:
7416 7416 dother = hg.peer(repo, {}, path if path is not None else dest)
7417 7417 except error.RepoError:
7418 7418 if opts.get('remote'):
7419 7419 raise
7420 7420 return dest, dbranch, None, None
7421 7421 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(dest))
7422 7422 elif sother is None:
7423 7423 # there is no explicit destination peer, but source one is invalid
7424 7424 return dest, dbranch, None, None
7425 7425 else:
7426 7426 dother = sother
7427 7427 if source != dest or (sbranch is not None and sbranch != dbranch):
7428 7428 common = None
7429 7429 else:
7430 7430 common = commoninc
7431 7431 if revs:
7432 7432 revs = [repo.lookup(rev) for rev in revs]
7433 7433 with repo.ui.silent():
7434 7434 outgoing = discovery.findcommonoutgoing(
7435 7435 repo, dother, onlyheads=revs, commoninc=common
7436 7436 )
7437 7437 return dest, dbranch, dother, outgoing
7438 7438
7439 7439 if needsoutgoing:
7440 7440 dest, dbranch, dother, outgoing = getoutgoing()
7441 7441 else:
7442 7442 dest = dbranch = dother = outgoing = None
7443 7443
7444 7444 if opts.get('remote'):
7445 7445 # Help pytype. --remote sets both `needsincoming` and `needsoutgoing`.
7446 7446 # The former always sets `sother` (or raises an exception if it can't);
7447 7447 # the latter always sets `outgoing`.
7448 7448 assert sother is not None
7449 7449 assert outgoing is not None
7450 7450
7451 7451 t = []
7452 7452 if incoming:
7453 7453 t.append(_(b'1 or more incoming'))
7454 7454 o = outgoing.missing
7455 7455 if o:
7456 7456 t.append(_(b'%d outgoing') % len(o))
7457 7457 other = dother or sother
7458 7458 if b'bookmarks' in other.listkeys(b'namespaces'):
7459 7459 counts = bookmarks.summary(repo, other)
7460 7460 if counts[0] > 0:
7461 7461 t.append(_(b'%d incoming bookmarks') % counts[0])
7462 7462 if counts[1] > 0:
7463 7463 t.append(_(b'%d outgoing bookmarks') % counts[1])
7464 7464
7465 7465 if t:
7466 7466 # i18n: column positioning for "hg summary"
7467 7467 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7468 7468 else:
7469 7469 # i18n: column positioning for "hg summary"
7470 7470 ui.status(_(b'remote: (synced)\n'))
7471 7471
7472 7472 cmdutil.summaryremotehooks(
7473 7473 ui,
7474 7474 repo,
7475 7475 pycompat.byteskwargs(opts),
7476 7476 (
7477 7477 (source, sbranch, sother, commoninc),
7478 7478 (dest, dbranch, dother, outgoing),
7479 7479 ),
7480 7480 )
7481 7481
7482 7482
7483 7483 @command(
7484 7484 b'tag',
7485 7485 [
7486 7486 (b'f', b'force', None, _(b'force tag')),
7487 7487 (b'l', b'local', None, _(b'make the tag local')),
7488 7488 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7489 7489 (b'', b'remove', None, _(b'remove a tag')),
7490 7490 # -l/--local is already there, commitopts cannot be used
7491 7491 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7492 7492 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7493 7493 ]
7494 7494 + commitopts2,
7495 7495 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7496 7496 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7497 7497 )
7498 7498 def tag(ui, repo, name1, *names, **opts):
7499 7499 """add one or more tags for the current or given revision
7500 7500
7501 7501 Name a particular revision using <name>.
7502 7502
7503 7503 Tags are used to name particular revisions of the repository and are
7504 7504 very useful to compare different revisions, to go back to significant
7505 7505 earlier versions or to mark branch points as releases, etc. Changing
7506 7506 an existing tag is normally disallowed; use -f/--force to override.
7507 7507
7508 7508 If no revision is given, the parent of the working directory is
7509 7509 used.
7510 7510
7511 7511 To facilitate version control, distribution, and merging of tags,
7512 7512 they are stored as a file named ".hgtags" which is managed similarly
7513 7513 to other project files and can be hand-edited if necessary. This
7514 7514 also means that tagging creates a new commit. The file
7515 7515 ".hg/localtags" is used for local tags (not shared among
7516 7516 repositories).
7517 7517
7518 7518 Tag commits are usually made at the head of a branch. If the parent
7519 7519 of the working directory is not a branch head, :hg:`tag` aborts; use
7520 7520 -f/--force to force the tag commit to be based on a non-head
7521 7521 changeset.
7522 7522
7523 7523 See :hg:`help dates` for a list of formats valid for -d/--date.
7524 7524
7525 7525 Since tag names have priority over branch names during revision
7526 7526 lookup, using an existing branch name as a tag name is discouraged.
7527 7527
7528 7528 Returns 0 on success.
7529 7529 """
7530 7530 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7531 7531
7532 7532 with repo.wlock(), repo.lock():
7533 7533 rev_ = b"."
7534 7534 names = [t.strip() for t in (name1,) + names]
7535 7535 if len(names) != len(set(names)):
7536 7536 raise error.InputError(_(b'tag names must be unique'))
7537 7537 for n in names:
7538 7538 scmutil.checknewlabel(repo, n, b'tag')
7539 7539 if not n:
7540 7540 raise error.InputError(
7541 7541 _(b'tag names cannot consist entirely of whitespace')
7542 7542 )
7543 7543 if opts.get('rev'):
7544 7544 rev_ = opts['rev']
7545 7545 message = opts.get('message')
7546 7546 if opts.get('remove'):
7547 7547 if opts.get('local'):
7548 7548 expectedtype = b'local'
7549 7549 else:
7550 7550 expectedtype = b'global'
7551 7551
7552 7552 for n in names:
7553 7553 if repo.tagtype(n) == b'global':
7554 7554 alltags = tagsmod.findglobaltags(ui, repo)
7555 7555 if alltags[n][0] == repo.nullid:
7556 7556 raise error.InputError(
7557 7557 _(b"tag '%s' is already removed") % n
7558 7558 )
7559 7559 if not repo.tagtype(n):
7560 7560 raise error.InputError(_(b"tag '%s' does not exist") % n)
7561 7561 if repo.tagtype(n) != expectedtype:
7562 7562 if expectedtype == b'global':
7563 7563 raise error.InputError(
7564 7564 _(b"tag '%s' is not a global tag") % n
7565 7565 )
7566 7566 else:
7567 7567 raise error.InputError(
7568 7568 _(b"tag '%s' is not a local tag") % n
7569 7569 )
7570 7570 rev_ = b'null'
7571 7571 if not message:
7572 7572 # we don't translate commit messages
7573 7573 message = b'Removed tag %s' % b', '.join(names)
7574 7574 elif not opts.get('force'):
7575 7575 for n in names:
7576 7576 if n in repo.tags():
7577 7577 raise error.InputError(
7578 7578 _(b"tag '%s' already exists (use -f to force)") % n
7579 7579 )
7580 7580 if not opts.get('local'):
7581 7581 p1, p2 = repo.dirstate.parents()
7582 7582 if p2 != repo.nullid:
7583 7583 raise error.StateError(_(b'uncommitted merge'))
7584 7584 bheads = repo.branchheads()
7585 7585 if not opts.get('force') and bheads and p1 not in bheads:
7586 7586 raise error.InputError(
7587 7587 _(
7588 7588 b'working directory is not at a branch head '
7589 7589 b'(use -f to force)'
7590 7590 )
7591 7591 )
7592 7592 node = logcmdutil.revsingle(repo, rev_).node()
7593 7593
7594 7594 # don't allow tagging the null rev or the working directory
7595 7595 if node is None:
7596 7596 raise error.InputError(_(b"cannot tag working directory"))
7597 7597 elif not opts.get('remove') and node == nullid:
7598 7598 raise error.InputError(_(b"cannot tag null revision"))
7599 7599
7600 7600 if not message:
7601 7601 # we don't translate commit messages
7602 7602 message = b'Added tag %s for changeset %s' % (
7603 7603 b', '.join(names),
7604 7604 short(node),
7605 7605 )
7606 7606
7607 7607 date = opts.get('date')
7608 7608 if date:
7609 7609 date = dateutil.parsedate(date)
7610 7610
7611 7611 if opts.get('remove'):
7612 7612 editform = b'tag.remove'
7613 7613 else:
7614 7614 editform = b'tag.add'
7615 7615 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7616 7616
7617 7617 tagsmod.tag(
7618 7618 repo,
7619 7619 names,
7620 7620 node,
7621 7621 message,
7622 7622 opts.get('local'),
7623 7623 opts.get('user'),
7624 7624 date,
7625 7625 editor=editor,
7626 7626 )
7627 7627
7628 7628
7629 7629 @command(
7630 7630 b'tags',
7631 7631 formatteropts,
7632 7632 b'',
7633 7633 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7634 7634 intents={INTENT_READONLY},
7635 7635 )
7636 7636 def tags(ui, repo, **opts):
7637 7637 """list repository tags
7638 7638
7639 7639 This lists both regular and local tags. When the -v/--verbose
7640 7640 switch is used, a third column "local" is printed for local tags.
7641 7641 When the -q/--quiet switch is used, only the tag name is printed.
7642 7642
7643 7643 .. container:: verbose
7644 7644
7645 7645 Template:
7646 7646
7647 7647 The following keywords are supported in addition to the common template
7648 7648 keywords and functions such as ``{tag}``. See also
7649 7649 :hg:`help templates`.
7650 7650
7651 7651 :type: String. ``local`` for local tags.
7652 7652
7653 7653 Returns 0 on success.
7654 7654 """
7655 7655
7656 7656 ui.pager(b'tags')
7657 7657 fm = ui.formatter(b'tags', pycompat.byteskwargs(opts))
7658 7658 hexfunc = fm.hexfunc
7659 7659
7660 7660 for t, n in reversed(repo.tagslist()):
7661 7661 hn = hexfunc(n)
7662 7662 label = b'tags.normal'
7663 7663 tagtype = repo.tagtype(t)
7664 7664 if not tagtype or tagtype == b'global':
7665 7665 tagtype = b''
7666 7666 else:
7667 7667 label = b'tags.' + tagtype
7668 7668
7669 7669 fm.startitem()
7670 7670 fm.context(repo=repo)
7671 7671 fm.write(b'tag', b'%s', t, label=label)
7672 7672 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7673 7673 fm.condwrite(
7674 7674 not ui.quiet,
7675 7675 b'rev node',
7676 7676 fmt,
7677 7677 repo.changelog.rev(n),
7678 7678 hn,
7679 7679 label=label,
7680 7680 )
7681 7681 fm.condwrite(
7682 7682 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7683 7683 )
7684 7684 fm.plain(b'\n')
7685 7685 fm.end()
7686 7686
7687 7687
7688 7688 @command(
7689 7689 b'tip',
7690 7690 [
7691 7691 (b'p', b'patch', None, _(b'show patch')),
7692 7692 (b'g', b'git', None, _(b'use git extended diff format')),
7693 7693 ]
7694 7694 + templateopts,
7695 7695 _(b'[-p] [-g]'),
7696 7696 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7697 7697 )
7698 7698 def tip(ui, repo, **opts):
7699 7699 """show the tip revision (DEPRECATED)
7700 7700
7701 7701 The tip revision (usually just called the tip) is the changeset
7702 7702 most recently added to the repository (and therefore the most
7703 7703 recently changed head).
7704 7704
7705 7705 If you have just made a commit, that commit will be the tip. If
7706 7706 you have just pulled changes from another repository, the tip of
7707 7707 that repository becomes the current tip. The "tip" tag is special
7708 7708 and cannot be renamed or assigned to a different changeset.
7709 7709
7710 7710 This command is deprecated, please use :hg:`heads` instead.
7711 7711
7712 7712 Returns 0 on success.
7713 7713 """
7714 7714 opts = pycompat.byteskwargs(opts)
7715 7715 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7716 7716 displayer.show(repo[b'tip'])
7717 7717 displayer.close()
7718 7718
7719 7719
7720 7720 @command(
7721 7721 b'unbundle',
7722 7722 [
7723 7723 (
7724 7724 b'u',
7725 7725 b'update',
7726 7726 None,
7727 7727 _(b'update to new branch head if changesets were unbundled'),
7728 7728 )
7729 7729 ],
7730 7730 _(b'[-u] FILE...'),
7731 7731 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7732 7732 )
7733 def unbundle(ui, repo, fname1, *fnames, **opts):
7733 def unbundle(ui, repo, fname1, *fnames, _unbundle_source=b'unbundle', **opts):
7734 7734 """apply one or more bundle files
7735 7735
7736 7736 Apply one or more bundle files generated by :hg:`bundle`.
7737 7737
7738 7738 Returns 0 on success, 1 if an update has unresolved files.
7739 7739 """
7740 7740 fnames = (fname1,) + fnames
7741 7741
7742 7742 with repo.lock():
7743 7743 for fname in fnames:
7744 7744 f = hg.openpath(ui, fname)
7745 7745 gen = exchange.readbundle(ui, f, fname)
7746 7746 if isinstance(gen, streamclone.streamcloneapplier):
7747 7747 raise error.InputError(
7748 7748 _(
7749 7749 b'packed bundles cannot be applied with '
7750 7750 b'"hg unbundle"'
7751 7751 ),
7752 7752 hint=_(b'use "hg debugapplystreamclonebundle"'),
7753 7753 )
7754 7754 url = b'bundle:' + fname
7755 7755 try:
7756 7756 txnname = b'unbundle'
7757 7757 if not isinstance(gen, bundle2.unbundle20):
7758 7758 txnname = b'unbundle\n%s' % urlutil.hidepassword(url)
7759 7759 with repo.transaction(txnname) as tr:
7760 7760 op = bundle2.applybundle(
7761 repo, gen, tr, source=b'unbundle', url=url
7761 repo,
7762 gen,
7763 tr,
7764 source=_unbundle_source, # used by debug::unbundle
7765 url=url,
7762 7766 )
7763 7767 except error.BundleUnknownFeatureError as exc:
7764 7768 raise error.Abort(
7765 7769 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7766 7770 hint=_(
7767 7771 b"see https://mercurial-scm.org/"
7768 7772 b"wiki/BundleFeature for more "
7769 7773 b"information"
7770 7774 ),
7771 7775 )
7772 7776 modheads = bundle2.combinechangegroupresults(op)
7773 7777
7774 7778 if postincoming(ui, repo, modheads, opts.get('update'), None, None):
7775 7779 return 1
7776 7780 else:
7777 7781 return 0
7778 7782
7779 7783
7780 7784 @command(
7781 7785 b'unshelve',
7782 7786 [
7783 7787 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7784 7788 (
7785 7789 b'c',
7786 7790 b'continue',
7787 7791 None,
7788 7792 _(b'continue an incomplete unshelve operation'),
7789 7793 ),
7790 7794 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7791 7795 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7792 7796 (
7793 7797 b'n',
7794 7798 b'name',
7795 7799 b'',
7796 7800 _(b'restore shelved change with given name'),
7797 7801 _(b'NAME'),
7798 7802 ),
7799 7803 (b't', b'tool', b'', _(b'specify merge tool')),
7800 7804 (
7801 7805 b'',
7802 7806 b'date',
7803 7807 b'',
7804 7808 _(b'set date for temporary commits (DEPRECATED)'),
7805 7809 _(b'DATE'),
7806 7810 ),
7807 7811 ],
7808 7812 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7809 7813 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7810 7814 )
7811 7815 def unshelve(ui, repo, *shelved, **opts):
7812 7816 """restore a shelved change to the working directory
7813 7817
7814 7818 This command accepts an optional name of a shelved change to
7815 7819 restore. If none is given, the most recent shelved change is used.
7816 7820
7817 7821 If a shelved change is applied successfully, the bundle that
7818 7822 contains the shelved changes is moved to a backup location
7819 7823 (.hg/shelve-backup).
7820 7824
7821 7825 Since you can restore a shelved change on top of an arbitrary
7822 7826 commit, it is possible that unshelving will result in a conflict
7823 7827 between your changes and the commits you are unshelving onto. If
7824 7828 this occurs, you must resolve the conflict, then use
7825 7829 ``--continue`` to complete the unshelve operation. (The bundle
7826 7830 will not be moved until you successfully complete the unshelve.)
7827 7831
7828 7832 (Alternatively, you can use ``--abort`` to abandon an unshelve
7829 7833 that causes a conflict. This reverts the unshelved changes, and
7830 7834 leaves the bundle in place.)
7831 7835
7832 7836 If bare shelved change (without interactive, include and exclude
7833 7837 option) was done on newly created branch it would restore branch
7834 7838 information to the working directory.
7835 7839
7836 7840 After a successful unshelve, the shelved changes are stored in a
7837 7841 backup directory. Only the N most recent backups are kept. N
7838 7842 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7839 7843 configuration option.
7840 7844
7841 7845 .. container:: verbose
7842 7846
7843 7847 Timestamp in seconds is used to decide order of backups. More
7844 7848 than ``maxbackups`` backups are kept, if same timestamp
7845 7849 prevents from deciding exact order of them, for safety.
7846 7850
7847 7851 Selected changes can be unshelved with ``--interactive`` flag.
7848 7852 The working directory is updated with the selected changes, and
7849 7853 only the unselected changes remain shelved.
7850 7854 Note: The whole shelve is applied to working directory first before
7851 7855 running interactively. So, this will bring up all the conflicts between
7852 7856 working directory and the shelve, irrespective of which changes will be
7853 7857 unshelved.
7854 7858 """
7855 7859 with repo.wlock():
7856 7860 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7857 7861
7858 7862
7859 7863 statemod.addunfinished(
7860 7864 b'unshelve',
7861 7865 fname=b'shelvedstate',
7862 7866 continueflag=True,
7863 7867 abortfunc=shelvemod.hgabortunshelve,
7864 7868 continuefunc=shelvemod.hgcontinueunshelve,
7865 7869 cmdmsg=_(b'unshelve already in progress'),
7866 7870 )
7867 7871
7868 7872
7869 7873 @command(
7870 7874 b'update|up|checkout|co',
7871 7875 [
7872 7876 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7873 7877 (b'c', b'check', None, _(b'require clean working directory')),
7874 7878 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7875 7879 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7876 7880 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7877 7881 ]
7878 7882 + mergetoolopts,
7879 7883 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7880 7884 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7881 7885 helpbasic=True,
7882 7886 )
7883 7887 def update(ui, repo, node=None, **opts):
7884 7888 """update working directory (or switch revisions)
7885 7889
7886 7890 Update the repository's working directory to the specified
7887 7891 changeset. If no changeset is specified, update to the tip of the
7888 7892 current named branch and move the active bookmark (see :hg:`help
7889 7893 bookmarks`).
7890 7894
7891 7895 Update sets the working directory's parent revision to the specified
7892 7896 changeset (see :hg:`help parents`).
7893 7897
7894 7898 If the changeset is not a descendant or ancestor of the working
7895 7899 directory's parent and there are uncommitted changes, the update is
7896 7900 aborted. With the -c/--check option, the working directory is checked
7897 7901 for uncommitted changes; if none are found, the working directory is
7898 7902 updated to the specified changeset.
7899 7903
7900 7904 .. container:: verbose
7901 7905
7902 7906 The -C/--clean, -c/--check, and -m/--merge options control what
7903 7907 happens if the working directory contains uncommitted changes.
7904 7908 At most of one of them can be specified.
7905 7909
7906 7910 1. If no option is specified, and if
7907 7911 the requested changeset is an ancestor or descendant of
7908 7912 the working directory's parent, the uncommitted changes
7909 7913 are merged into the requested changeset and the merged
7910 7914 result is left uncommitted. If the requested changeset is
7911 7915 not an ancestor or descendant (that is, it is on another
7912 7916 branch), the update is aborted and the uncommitted changes
7913 7917 are preserved.
7914 7918
7915 7919 2. With the -m/--merge option, the update is allowed even if the
7916 7920 requested changeset is not an ancestor or descendant of
7917 7921 the working directory's parent.
7918 7922
7919 7923 3. With the -c/--check option, the update is aborted and the
7920 7924 uncommitted changes are preserved.
7921 7925
7922 7926 4. With the -C/--clean option, uncommitted changes are discarded and
7923 7927 the working directory is updated to the requested changeset.
7924 7928
7925 7929 To cancel an uncommitted merge (and lose your changes), use
7926 7930 :hg:`merge --abort`.
7927 7931
7928 7932 Use null as the changeset to remove the working directory (like
7929 7933 :hg:`clone -U`).
7930 7934
7931 7935 If you want to revert just one file to an older revision, use
7932 7936 :hg:`revert [-r REV] NAME`.
7933 7937
7934 7938 See :hg:`help dates` for a list of formats valid for -d/--date.
7935 7939
7936 7940 Returns 0 on success, 1 if there are unresolved files.
7937 7941 """
7938 7942 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7939 7943 rev = opts.get('rev')
7940 7944 date = opts.get('date')
7941 7945 clean = opts.get('clean')
7942 7946 check = opts.get('check')
7943 7947 merge = opts.get('merge')
7944 7948 if rev and node:
7945 7949 raise error.InputError(_(b"please specify just one revision"))
7946 7950
7947 7951 if ui.configbool(b'commands', b'update.requiredest'):
7948 7952 if not node and not rev and not date:
7949 7953 raise error.InputError(
7950 7954 _(b'you must specify a destination'),
7951 7955 hint=_(b'for example: hg update ".::"'),
7952 7956 )
7953 7957
7954 7958 if rev is None or rev == b'':
7955 7959 rev = node
7956 7960
7957 7961 if date and rev is not None:
7958 7962 raise error.InputError(_(b"you can't specify a revision and a date"))
7959 7963
7960 7964 updatecheck = None
7961 7965 if check or merge is not None and not merge:
7962 7966 updatecheck = b'abort'
7963 7967 elif merge or check is not None and not check:
7964 7968 updatecheck = b'none'
7965 7969
7966 7970 with repo.wlock():
7967 7971 cmdutil.clearunfinished(repo)
7968 7972 if date:
7969 7973 rev = cmdutil.finddate(ui, repo, date)
7970 7974
7971 7975 # if we defined a bookmark, we have to remember the original name
7972 7976 brev = rev
7973 7977 if rev:
7974 7978 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7975 7979 ctx = logcmdutil.revsingle(repo, rev, default=None)
7976 7980 rev = ctx.rev()
7977 7981 hidden = ctx.hidden()
7978 7982 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7979 7983 with ui.configoverride(overrides, b'update'):
7980 7984 ret = hg.updatetotally(
7981 7985 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7982 7986 )
7983 7987 if hidden:
7984 7988 ctxstr = ctx.hex()[:12]
7985 7989 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7986 7990
7987 7991 if ctx.obsolete():
7988 7992 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7989 7993 ui.warn(b"(%s)\n" % obsfatemsg)
7990 7994 return ret
7991 7995
7992 7996
7993 7997 @command(
7994 7998 b'verify',
7995 7999 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7996 8000 helpcategory=command.CATEGORY_MAINTENANCE,
7997 8001 )
7998 8002 def verify(ui, repo, **opts):
7999 8003 """verify the integrity of the repository
8000 8004
8001 8005 Verify the integrity of the current repository.
8002 8006
8003 8007 This will perform an extensive check of the repository's
8004 8008 integrity, validating the hashes and checksums of each entry in
8005 8009 the changelog, manifest, and tracked files, as well as the
8006 8010 integrity of their crosslinks and indices.
8007 8011
8008 8012 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
8009 8013 for more information about recovery from corruption of the
8010 8014 repository.
8011 8015
8012 8016 For an alternative UI with a lot more control over the verification
8013 8017 process and better error reporting, try `hg help admin::verify`.
8014 8018
8015 8019 Returns 0 on success, 1 if errors are encountered.
8016 8020 """
8017 8021 level = None
8018 8022 if opts['full']:
8019 8023 level = verifymod.VERIFY_FULL
8020 8024 return hg.verify(repo, level)
8021 8025
8022 8026
8023 8027 @command(
8024 8028 b'version',
8025 8029 [] + formatteropts,
8026 8030 helpcategory=command.CATEGORY_HELP,
8027 8031 norepo=True,
8028 8032 intents={INTENT_READONLY},
8029 8033 )
8030 8034 def version_(ui, **opts):
8031 8035 """output version and copyright information
8032 8036
8033 8037 .. container:: verbose
8034 8038
8035 8039 Template:
8036 8040
8037 8041 The following keywords are supported. See also :hg:`help templates`.
8038 8042
8039 8043 :extensions: List of extensions.
8040 8044 :ver: String. Version number.
8041 8045
8042 8046 And each entry of ``{extensions}`` provides the following sub-keywords
8043 8047 in addition to ``{ver}``.
8044 8048
8045 8049 :bundled: Boolean. True if included in the release.
8046 8050 :name: String. Extension name.
8047 8051 """
8048 8052 if ui.verbose:
8049 8053 ui.pager(b'version')
8050 8054 fm = ui.formatter(b"version", pycompat.byteskwargs(opts))
8051 8055 fm.startitem()
8052 8056 fm.write(
8053 8057 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
8054 8058 )
8055 8059 license = _(
8056 8060 b"(see https://mercurial-scm.org for more information)\n"
8057 8061 b"\nCopyright (C) 2005-2023 Olivia Mackall and others\n"
8058 8062 b"This is free software; see the source for copying conditions. "
8059 8063 b"There is NO\nwarranty; "
8060 8064 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
8061 8065 )
8062 8066 if not ui.quiet:
8063 8067 fm.plain(license)
8064 8068
8065 8069 if ui.verbose:
8066 8070 fm.plain(_(b"\nEnabled extensions:\n\n"))
8067 8071 # format names and versions into columns
8068 8072 names = []
8069 8073 vers = []
8070 8074 isinternals = []
8071 8075 for name, module in sorted(extensions.extensions()):
8072 8076 names.append(name)
8073 8077 vers.append(extensions.moduleversion(module) or None)
8074 8078 isinternals.append(extensions.ismoduleinternal(module))
8075 8079 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
8076 8080 if names:
8077 8081 namefmt = b" %%-%ds " % max(len(n) for n in names)
8078 8082 places = [_(b"external"), _(b"internal")]
8079 8083 for n, v, p in zip(names, vers, isinternals):
8080 8084 fn.startitem()
8081 8085 fn.condwrite(ui.verbose, b"name", namefmt, n)
8082 8086 if ui.verbose:
8083 8087 fn.plain(b"%s " % places[p])
8084 8088 fn.data(bundled=p)
8085 8089 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
8086 8090 if ui.verbose:
8087 8091 fn.plain(b"\n")
8088 8092 fn.end()
8089 8093 fm.end()
8090 8094
8091 8095
8092 8096 def loadcmdtable(ui, name, cmdtable):
8093 8097 """Load command functions from specified cmdtable"""
8094 8098 overrides = [cmd for cmd in cmdtable if cmd in table]
8095 8099 if overrides:
8096 8100 ui.warn(
8097 8101 _(b"extension '%s' overrides commands: %s\n")
8098 8102 % (name, b" ".join(overrides))
8099 8103 )
8100 8104 table.update(cmdtable)
@@ -1,4751 +1,4775 b''
1 1 # debugcommands.py - command processing for debug* commands
2 2 #
3 3 # Copyright 2005-2016 Olivia Mackall <olivia@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
9 9 import binascii
10 10 import codecs
11 11 import collections
12 12 import contextlib
13 13 import difflib
14 14 import errno
15 15 import glob
16 16 import operator
17 17 import os
18 18 import platform
19 19 import random
20 20 import re
21 21 import socket
22 22 import ssl
23 23 import stat
24 24 import subprocess
25 25 import sys
26 26 import time
27 27
28 28 from .i18n import _
29 29 from .node import (
30 30 bin,
31 31 hex,
32 32 nullrev,
33 33 short,
34 34 )
35 35 from .pycompat import (
36 36 open,
37 37 )
38 38 from . import (
39 39 bundle2,
40 40 bundlerepo,
41 41 changegroup,
42 42 cmdutil,
43 43 color,
44 44 context,
45 45 copies,
46 46 dagparser,
47 47 dirstateutils,
48 48 encoding,
49 49 error,
50 50 exchange,
51 51 extensions,
52 52 filelog,
53 53 filemerge,
54 54 filesetlang,
55 55 formatter,
56 56 hg,
57 57 httppeer,
58 58 localrepo,
59 59 lock as lockmod,
60 60 logcmdutil,
61 61 manifest,
62 62 mergestate as mergestatemod,
63 63 metadata,
64 64 obsolete,
65 65 obsutil,
66 66 pathutil,
67 67 phases,
68 68 policy,
69 69 pvec,
70 70 pycompat,
71 71 registrar,
72 72 repair,
73 73 repoview,
74 74 requirements,
75 75 revlog,
76 76 revset,
77 77 revsetlang,
78 78 scmutil,
79 79 setdiscovery,
80 80 simplemerge,
81 81 sshpeer,
82 82 sslutil,
83 83 streamclone,
84 84 strip,
85 85 tags as tagsmod,
86 86 templater,
87 87 treediscovery,
88 88 upgrade,
89 89 url as urlmod,
90 90 util,
91 91 verify,
92 92 vfs as vfsmod,
93 93 wireprotoframing,
94 94 wireprotoserver,
95 95 )
96 96 from .interfaces import repository
97 97 from .stabletailgraph import stabletailsort
98 98 from .utils import (
99 99 cborutil,
100 100 compression,
101 101 dateutil,
102 102 procutil,
103 103 stringutil,
104 104 urlutil,
105 105 )
106 106
107 107 from .revlogutils import (
108 108 debug as revlog_debug,
109 109 nodemap,
110 110 rewrite,
111 111 sidedata,
112 112 )
113 113
114 114 release = lockmod.release
115 115
116 116 table = {}
117 117 table.update(strip.command._table)
118 118 command = registrar.command(table)
119 119
120 120
121 121 @command(b'debugancestor', [], _(b'[INDEX] REV1 REV2'), optionalrepo=True)
122 122 def debugancestor(ui, repo, *args):
123 123 """find the ancestor revision of two revisions in a given index"""
124 124 if len(args) == 3:
125 125 index, rev1, rev2 = args
126 126 r = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False), index)
127 127 lookup = r.lookup
128 128 elif len(args) == 2:
129 129 if not repo:
130 130 raise error.Abort(
131 131 _(b'there is no Mercurial repository here (.hg not found)')
132 132 )
133 133 rev1, rev2 = args
134 134 r = repo.changelog
135 135 lookup = repo.lookup
136 136 else:
137 137 raise error.Abort(_(b'either two or three arguments required'))
138 138 a = r.ancestor(lookup(rev1), lookup(rev2))
139 139 ui.write(b'%d:%s\n' % (r.rev(a), hex(a)))
140 140
141 141
142 142 @command(b'debugantivirusrunning', [])
143 143 def debugantivirusrunning(ui, repo):
144 144 """attempt to trigger an antivirus scanner to see if one is active"""
145 145 with repo.cachevfs.open('eicar-test-file.com', b'wb') as f:
146 146 f.write(
147 147 util.b85decode(
148 148 # This is a base85-armored version of the EICAR test file. See
149 149 # https://en.wikipedia.org/wiki/EICAR_test_file for details.
150 150 b'ST#=}P$fV?P+K%yP+C|uG$>GBDK|qyDK~v2MM*<JQY}+dK~6+LQba95P'
151 151 b'E<)&Nm5l)EmTEQR4qnHOhq9iNGnJx'
152 152 )
153 153 )
154 154 # Give an AV engine time to scan the file.
155 155 time.sleep(2)
156 156 util.unlink(repo.cachevfs.join('eicar-test-file.com'))
157 157
158 158
159 159 @command(b'debugapplystreamclonebundle', [], b'FILE')
160 160 def debugapplystreamclonebundle(ui, repo, fname):
161 161 """apply a stream clone bundle file"""
162 162 f = hg.openpath(ui, fname)
163 163 gen = exchange.readbundle(ui, f, fname)
164 164 gen.apply(repo)
165 165
166 166
167 167 @command(
168 168 b'debugbuilddag',
169 169 [
170 170 (
171 171 b'm',
172 172 b'mergeable-file',
173 173 None,
174 174 _(b'add single file mergeable changes'),
175 175 ),
176 176 (
177 177 b'o',
178 178 b'overwritten-file',
179 179 None,
180 180 _(b'add single file all revs overwrite'),
181 181 ),
182 182 (b'n', b'new-file', None, _(b'add new file at each rev')),
183 183 (
184 184 b'',
185 185 b'from-existing',
186 186 None,
187 187 _(b'continue from a non-empty repository'),
188 188 ),
189 189 ],
190 190 _(b'[OPTION]... [TEXT]'),
191 191 )
192 192 def debugbuilddag(
193 193 ui,
194 194 repo,
195 195 text=None,
196 196 mergeable_file=False,
197 197 overwritten_file=False,
198 198 new_file=False,
199 199 from_existing=False,
200 200 ):
201 201 """builds a repo with a given DAG from scratch in the current empty repo
202 202
203 203 The description of the DAG is read from stdin if not given on the
204 204 command line.
205 205
206 206 Elements:
207 207
208 208 - "+n" is a linear run of n nodes based on the current default parent
209 209 - "." is a single node based on the current default parent
210 210 - "$" resets the default parent to null (implied at the start);
211 211 otherwise the default parent is always the last node created
212 212 - "<p" sets the default parent to the backref p
213 213 - "*p" is a fork at parent p, which is a backref
214 214 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
215 215 - "/p2" is a merge of the preceding node and p2
216 216 - ":tag" defines a local tag for the preceding node
217 217 - "@branch" sets the named branch for subsequent nodes
218 218 - "#...\\n" is a comment up to the end of the line
219 219
220 220 Whitespace between the above elements is ignored.
221 221
222 222 A backref is either
223 223
224 224 - a number n, which references the node curr-n, where curr is the current
225 225 node, or
226 226 - the name of a local tag you placed earlier using ":tag", or
227 227 - empty to denote the default parent.
228 228
229 229 All string valued-elements are either strictly alphanumeric, or must
230 230 be enclosed in double quotes ("..."), with "\\" as escape character.
231 231 """
232 232
233 233 if text is None:
234 234 ui.status(_(b"reading DAG from stdin\n"))
235 235 text = ui.fin.read()
236 236
237 237 cl = repo.changelog
238 238 if len(cl) > 0 and not from_existing:
239 239 raise error.Abort(_(b'repository is not empty'))
240 240
241 241 # determine number of revs in DAG
242 242 total = 0
243 243 for type, data in dagparser.parsedag(text):
244 244 if type == b'n':
245 245 total += 1
246 246
247 247 if mergeable_file:
248 248 linesperrev = 2
249 249 # make a file with k lines per rev
250 250 initialmergedlines = [b'%d' % i for i in range(0, total * linesperrev)]
251 251 initialmergedlines.append(b"")
252 252
253 253 tags = []
254 254 progress = ui.makeprogress(
255 255 _(b'building'), unit=_(b'revisions'), total=total
256 256 )
257 257 with progress, repo.wlock(), repo.lock(), repo.transaction(b"builddag"):
258 258 at = -1
259 259 atbranch = b'default'
260 260 nodeids = []
261 261 id = 0
262 262 progress.update(id)
263 263 for type, data in dagparser.parsedag(text):
264 264 if type == b'n':
265 265 ui.note((b'node %s\n' % pycompat.bytestr(data)))
266 266 id, ps = data
267 267
268 268 files = []
269 269 filecontent = {}
270 270
271 271 p2 = None
272 272 if mergeable_file:
273 273 fn = b"mf"
274 274 p1 = repo[ps[0]]
275 275 if len(ps) > 1:
276 276 p2 = repo[ps[1]]
277 277 pa = p1.ancestor(p2)
278 278 base, local, other = [
279 279 x[fn].data() for x in (pa, p1, p2)
280 280 ]
281 281 m3 = simplemerge.Merge3Text(base, local, other)
282 282 ml = [
283 283 l.strip()
284 284 for l in simplemerge.render_minimized(m3)[0]
285 285 ]
286 286 ml.append(b"")
287 287 elif at > 0:
288 288 ml = p1[fn].data().split(b"\n")
289 289 else:
290 290 ml = initialmergedlines
291 291 ml[id * linesperrev] += b" r%i" % id
292 292 mergedtext = b"\n".join(ml)
293 293 files.append(fn)
294 294 filecontent[fn] = mergedtext
295 295
296 296 if overwritten_file:
297 297 fn = b"of"
298 298 files.append(fn)
299 299 filecontent[fn] = b"r%i\n" % id
300 300
301 301 if new_file:
302 302 fn = b"nf%i" % id
303 303 files.append(fn)
304 304 filecontent[fn] = b"r%i\n" % id
305 305 if len(ps) > 1:
306 306 if not p2:
307 307 p2 = repo[ps[1]]
308 308 for fn in p2:
309 309 if fn.startswith(b"nf"):
310 310 files.append(fn)
311 311 filecontent[fn] = p2[fn].data()
312 312
313 313 def fctxfn(repo, cx, path):
314 314 if path in filecontent:
315 315 return context.memfilectx(
316 316 repo, cx, path, filecontent[path]
317 317 )
318 318 return None
319 319
320 320 if len(ps) == 0 or ps[0] < 0:
321 321 pars = [None, None]
322 322 elif len(ps) == 1:
323 323 pars = [nodeids[ps[0]], None]
324 324 else:
325 325 pars = [nodeids[p] for p in ps]
326 326 cx = context.memctx(
327 327 repo,
328 328 pars,
329 329 b"r%i" % id,
330 330 files,
331 331 fctxfn,
332 332 date=(id, 0),
333 333 user=b"debugbuilddag",
334 334 extra={b'branch': atbranch},
335 335 )
336 336 nodeid = repo.commitctx(cx)
337 337 nodeids.append(nodeid)
338 338 at = id
339 339 elif type == b'l':
340 340 id, name = data
341 341 ui.note((b'tag %s\n' % name))
342 342 tags.append(b"%s %s\n" % (hex(repo.changelog.node(id)), name))
343 343 elif type == b'a':
344 344 ui.note((b'branch %s\n' % data))
345 345 atbranch = data
346 346 progress.update(id)
347 347
348 348 if tags:
349 349 repo.vfs.write(b"localtags", b"".join(tags))
350 350
351 351
352 352 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
353 353 indent_string = b' ' * indent
354 354 if all:
355 355 ui.writenoi18n(
356 356 b"%sformat: id, p1, p2, cset, delta base, len(delta)\n"
357 357 % indent_string
358 358 )
359 359
360 360 def showchunks(named):
361 361 ui.write(b"\n%s%s\n" % (indent_string, named))
362 362 for deltadata in gen.deltaiter():
363 363 node, p1, p2, cs, deltabase, delta, flags, sidedata = deltadata
364 364 ui.write(
365 365 b"%s%s %s %s %s %s %d\n"
366 366 % (
367 367 indent_string,
368 368 hex(node),
369 369 hex(p1),
370 370 hex(p2),
371 371 hex(cs),
372 372 hex(deltabase),
373 373 len(delta),
374 374 )
375 375 )
376 376
377 377 gen.changelogheader()
378 378 showchunks(b"changelog")
379 379 gen.manifestheader()
380 380 showchunks(b"manifest")
381 381 for chunkdata in iter(gen.filelogheader, {}):
382 382 fname = chunkdata[b'filename']
383 383 showchunks(fname)
384 384 else:
385 385 if isinstance(gen, bundle2.unbundle20):
386 386 raise error.Abort(_(b'use debugbundle2 for this file'))
387 387 gen.changelogheader()
388 388 for deltadata in gen.deltaiter():
389 389 node, p1, p2, cs, deltabase, delta, flags, sidedata = deltadata
390 390 ui.write(b"%s%s\n" % (indent_string, hex(node)))
391 391
392 392
393 393 def _debugobsmarkers(ui, part, indent=0, **opts):
394 394 """display version and markers contained in 'data'"""
395 395 data = part.read()
396 396 indent_string = b' ' * indent
397 397 try:
398 398 version, markers = obsolete._readmarkers(data)
399 399 except error.UnknownVersion as exc:
400 400 msg = b"%sunsupported version: %s (%d bytes)\n"
401 401 msg %= indent_string, exc.version, len(data)
402 402 ui.write(msg)
403 403 else:
404 404 msg = b"%sversion: %d (%d bytes)\n"
405 405 msg %= indent_string, version, len(data)
406 406 ui.write(msg)
407 407 fm = ui.formatter(b'debugobsolete', pycompat.byteskwargs(opts))
408 408 for rawmarker in sorted(markers):
409 409 m = obsutil.marker(None, rawmarker)
410 410 fm.startitem()
411 411 fm.plain(indent_string)
412 412 cmdutil.showmarker(fm, m)
413 413 fm.end()
414 414
415 415
416 416 def _debugphaseheads(ui, data, indent=0):
417 417 """display version and markers contained in 'data'"""
418 418 indent_string = b' ' * indent
419 419 headsbyphase = phases.binarydecode(data)
420 420 for phase in phases.allphases:
421 421 for head in headsbyphase[phase]:
422 422 ui.write(indent_string)
423 423 ui.write(b'%s %s\n' % (hex(head), phases.phasenames[phase]))
424 424
425 425
426 426 def _quasirepr(thing):
427 427 if isinstance(thing, (dict, util.sortdict, collections.OrderedDict)):
428 428 return b'{%s}' % (
429 429 b', '.join(b'%s: %s' % (k, thing[k]) for k in sorted(thing))
430 430 )
431 431 return pycompat.bytestr(repr(thing))
432 432
433 433
434 434 def _debugbundle2(ui, gen, all=None, **opts):
435 435 """lists the contents of a bundle2"""
436 436 if not isinstance(gen, bundle2.unbundle20):
437 437 raise error.Abort(_(b'not a bundle2 file'))
438 438 ui.write((b'Stream params: %s\n' % _quasirepr(gen.params)))
439 439 parttypes = opts.get('part_type', [])
440 440 for part in gen.iterparts():
441 441 if parttypes and part.type not in parttypes:
442 442 continue
443 443 msg = b'%s -- %s (mandatory: %r)\n'
444 444 ui.write((msg % (part.type, _quasirepr(part.params), part.mandatory)))
445 445 if part.type == b'changegroup':
446 446 version = part.params.get(b'version', b'01')
447 447 cg = changegroup.getunbundler(version, part, b'UN')
448 448 if not ui.quiet:
449 449 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
450 450 if part.type == b'obsmarkers':
451 451 if not ui.quiet:
452 452 _debugobsmarkers(ui, part, indent=4, **opts)
453 453 if part.type == b'phase-heads':
454 454 if not ui.quiet:
455 455 _debugphaseheads(ui, part, indent=4)
456 456
457 457
458 458 @command(
459 459 b'debugbundle',
460 460 [
461 461 (b'a', b'all', None, _(b'show all details')),
462 462 (b'', b'part-type', [], _(b'show only the named part type')),
463 463 (b'', b'spec', None, _(b'print the bundlespec of the bundle')),
464 464 ],
465 465 _(b'FILE'),
466 466 norepo=True,
467 467 )
468 468 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
469 469 """lists the contents of a bundle"""
470 470 with hg.openpath(ui, bundlepath) as f:
471 471 if spec:
472 472 spec = exchange.getbundlespec(ui, f)
473 473 ui.write(b'%s\n' % spec)
474 474 return
475 475
476 476 gen = exchange.readbundle(ui, f, bundlepath)
477 477 if isinstance(gen, bundle2.unbundle20):
478 478 return _debugbundle2(ui, gen, all=all, **opts)
479 479 _debugchangegroup(ui, gen, all=all, **opts)
480 480
481 481
482 482 @command(b'debugcapabilities', [], _(b'PATH'), norepo=True)
483 483 def debugcapabilities(ui, path, **opts):
484 484 """lists the capabilities of a remote peer"""
485 485 peer = hg.peer(ui, pycompat.byteskwargs(opts), path)
486 486 try:
487 487 caps = peer.capabilities()
488 488 ui.writenoi18n(b'Main capabilities:\n')
489 489 for c in sorted(caps):
490 490 ui.write(b' %s\n' % c)
491 491 b2caps = bundle2.bundle2caps(peer)
492 492 if b2caps:
493 493 ui.writenoi18n(b'Bundle2 capabilities:\n')
494 494 for key, values in sorted(b2caps.items()):
495 495 ui.write(b' %s\n' % key)
496 496 for v in values:
497 497 ui.write(b' %s\n' % v)
498 498 finally:
499 499 peer.close()
500 500
501 501
502 502 @command(
503 503 b'debugchangedfiles',
504 504 [
505 505 (
506 506 b'',
507 507 b'compute',
508 508 False,
509 509 b"compute information instead of reading it from storage",
510 510 ),
511 511 ],
512 512 b'REV',
513 513 )
514 514 def debugchangedfiles(ui, repo, rev, **opts):
515 515 """list the stored files changes for a revision"""
516 516 ctx = logcmdutil.revsingle(repo, rev, None)
517 517 files = None
518 518
519 519 if opts['compute']:
520 520 files = metadata.compute_all_files_changes(ctx)
521 521 else:
522 522 sd = repo.changelog.sidedata(ctx.rev())
523 523 files_block = sd.get(sidedata.SD_FILES)
524 524 if files_block is not None:
525 525 files = metadata.decode_files_sidedata(sd)
526 526 if files is not None:
527 527 for f in sorted(files.touched):
528 528 if f in files.added:
529 529 action = b"added"
530 530 elif f in files.removed:
531 531 action = b"removed"
532 532 elif f in files.merged:
533 533 action = b"merged"
534 534 elif f in files.salvaged:
535 535 action = b"salvaged"
536 536 else:
537 537 action = b"touched"
538 538
539 539 copy_parent = b""
540 540 copy_source = b""
541 541 if f in files.copied_from_p1:
542 542 copy_parent = b"p1"
543 543 copy_source = files.copied_from_p1[f]
544 544 elif f in files.copied_from_p2:
545 545 copy_parent = b"p2"
546 546 copy_source = files.copied_from_p2[f]
547 547
548 548 data = (action, copy_parent, f, copy_source)
549 549 template = b"%-8s %2s: %s, %s;\n"
550 550 ui.write(template % data)
551 551
552 552
553 553 @command(b'debugcheckstate', [], b'')
554 554 def debugcheckstate(ui, repo):
555 555 """validate the correctness of the current dirstate"""
556 556 errors = verify.verifier(repo)._verify_dirstate()
557 557 if errors:
558 558 errstr = _(b"dirstate inconsistent with current parent's manifest")
559 559 raise error.Abort(errstr)
560 560
561 561
562 562 @command(
563 563 b'debugcolor',
564 564 [(b'', b'style', None, _(b'show all configured styles'))],
565 565 b'hg debugcolor',
566 566 )
567 567 def debugcolor(ui, repo, **opts):
568 568 """show available color, effects or style"""
569 569 ui.writenoi18n(b'color mode: %s\n' % stringutil.pprint(ui._colormode))
570 570 if opts.get('style'):
571 571 return _debugdisplaystyle(ui)
572 572 else:
573 573 return _debugdisplaycolor(ui)
574 574
575 575
576 576 def _debugdisplaycolor(ui):
577 577 ui = ui.copy()
578 578 ui._styles.clear()
579 579 for effect in color._activeeffects(ui).keys():
580 580 ui._styles[effect] = effect
581 581 if ui._terminfoparams:
582 582 for k, v in ui.configitems(b'color'):
583 583 if k.startswith(b'color.'):
584 584 ui._styles[k] = k[6:]
585 585 elif k.startswith(b'terminfo.'):
586 586 ui._styles[k] = k[9:]
587 587 ui.write(_(b'available colors:\n'))
588 588 # sort label with a '_' after the other to group '_background' entry.
589 589 items = sorted(ui._styles.items(), key=lambda i: (b'_' in i[0], i[0], i[1]))
590 590 for colorname, label in items:
591 591 ui.write(b'%s\n' % colorname, label=label)
592 592
593 593
594 594 def _debugdisplaystyle(ui):
595 595 ui.write(_(b'available style:\n'))
596 596 if not ui._styles:
597 597 return
598 598 width = max(len(s) for s in ui._styles)
599 599 for label, effects in sorted(ui._styles.items()):
600 600 ui.write(b'%s' % label, label=label)
601 601 if effects:
602 602 # 50
603 603 ui.write(b': ')
604 604 ui.write(b' ' * (max(0, width - len(label))))
605 605 ui.write(b', '.join(ui.label(e, e) for e in effects.split()))
606 606 ui.write(b'\n')
607 607
608 608
609 609 @command(b'debugcreatestreamclonebundle', [], b'FILE')
610 610 def debugcreatestreamclonebundle(ui, repo, fname):
611 611 """create a stream clone bundle file
612 612
613 613 Stream bundles are special bundles that are essentially archives of
614 614 revlog files. They are commonly used for cloning very quickly.
615 615
616 616 This command creates a "version 1" stream clone, which is deprecated in
617 617 favor of newer versions of the stream protocol. Bundles using such newer
618 618 versions can be generated using the `hg bundle` command.
619 619 """
620 620 # TODO we may want to turn this into an abort when this functionality
621 621 # is moved into `hg bundle`.
622 622 if phases.hassecret(repo):
623 623 ui.warn(
624 624 _(
625 625 b'(warning: stream clone bundle will contain secret '
626 626 b'revisions)\n'
627 627 )
628 628 )
629 629
630 630 requirements, gen = streamclone.generatebundlev1(repo)
631 631 changegroup.writechunks(ui, gen, fname)
632 632
633 633 ui.write(_(b'bundle requirements: %s\n') % b', '.join(sorted(requirements)))
634 634
635 635
636 636 @command(
637 637 b'debugdag',
638 638 [
639 639 (b't', b'tags', None, _(b'use tags as labels')),
640 640 (b'b', b'branches', None, _(b'annotate with branch names')),
641 641 (b'', b'dots', None, _(b'use dots for runs')),
642 642 (b's', b'spaces', None, _(b'separate elements by spaces')),
643 643 ],
644 644 _(b'[OPTION]... [FILE [REV]...]'),
645 645 optionalrepo=True,
646 646 )
647 647 def debugdag(ui, repo, file_=None, *revs, **opts):
648 648 """format the changelog or an index DAG as a concise textual description
649 649
650 650 If you pass a revlog index, the revlog's DAG is emitted. If you list
651 651 revision numbers, they get labeled in the output as rN.
652 652
653 653 Otherwise, the changelog DAG of the current repo is emitted.
654 654 """
655 655 spaces = opts.get('spaces')
656 656 dots = opts.get('dots')
657 657 if file_:
658 658 rlog = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False), file_)
659 659 revs = {int(r) for r in revs}
660 660
661 661 def events():
662 662 for r in rlog:
663 663 yield b'n', (r, list(p for p in rlog.parentrevs(r) if p != -1))
664 664 if r in revs:
665 665 yield b'l', (r, b"r%i" % r)
666 666
667 667 elif repo:
668 668 cl = repo.changelog
669 669 tags = opts.get('tags')
670 670 branches = opts.get('branches')
671 671 if tags:
672 672 labels = {}
673 673 for l, n in repo.tags().items():
674 674 labels.setdefault(cl.rev(n), []).append(l)
675 675
676 676 def events():
677 677 b = b"default"
678 678 for r in cl:
679 679 if branches:
680 680 newb = cl.read(cl.node(r))[5][b'branch']
681 681 if newb != b:
682 682 yield b'a', newb
683 683 b = newb
684 684 yield b'n', (r, list(p for p in cl.parentrevs(r) if p != -1))
685 685 if tags:
686 686 ls = labels.get(r)
687 687 if ls:
688 688 for l in ls:
689 689 yield b'l', (r, l)
690 690
691 691 else:
692 692 raise error.Abort(_(b'need repo for changelog dag'))
693 693
694 694 for line in dagparser.dagtextlines(
695 695 events(),
696 696 addspaces=spaces,
697 697 wraplabels=True,
698 698 wrapannotations=True,
699 699 wrapnonlinear=dots,
700 700 usedots=dots,
701 701 maxlinewidth=70,
702 702 ):
703 703 ui.write(line)
704 704 ui.write(b"\n")
705 705
706 706
707 707 @command(b'debugdata', cmdutil.debugrevlogopts, _(b'-c|-m|FILE REV'))
708 708 def debugdata(ui, repo, file_, rev=None, **opts):
709 709 """dump the contents of a data file revision"""
710 710 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
711 711 if rev is not None:
712 712 raise error.InputError(
713 713 _(b'cannot specify a revision with other arguments')
714 714 )
715 715 file_, rev = None, file_
716 716 elif rev is None:
717 717 raise error.InputError(_(b'please specify a revision'))
718 718 r = cmdutil.openstorage(
719 719 repo, b'debugdata', file_, pycompat.byteskwargs(opts)
720 720 )
721 721 try:
722 722 ui.write(r.rawdata(r.lookup(rev)))
723 723 except KeyError:
724 724 raise error.Abort(_(b'invalid revision identifier %s') % rev)
725 725
726 726
727 727 @command(
728 728 b'debugdate',
729 729 [(b'e', b'extended', None, _(b'try extended date formats'))],
730 730 _(b'[-e] DATE [RANGE]'),
731 731 norepo=True,
732 732 optionalrepo=True,
733 733 )
734 734 def debugdate(ui, date, range=None, **opts):
735 735 """parse and display a date"""
736 736 if opts["extended"]:
737 737 d = dateutil.parsedate(date, dateutil.extendeddateformats)
738 738 else:
739 739 d = dateutil.parsedate(date)
740 740 ui.writenoi18n(b"internal: %d %d\n" % d)
741 741 ui.writenoi18n(b"standard: %s\n" % dateutil.datestr(d))
742 742 if range:
743 743 m = dateutil.matchdate(range)
744 744 ui.writenoi18n(b"match: %s\n" % m(d[0]))
745 745
746 746
747 747 @command(
748 748 b'debugdeltachain',
749 749 [
750 750 (
751 751 b'r',
752 752 b'rev',
753 753 [],
754 754 _('restrict processing to these revlog revisions'),
755 755 ),
756 756 (
757 757 b'',
758 758 b'all-info',
759 759 False,
760 760 _('compute all information unless specified otherwise'),
761 761 ),
762 762 (
763 763 b'',
764 764 b'size-info',
765 765 None,
766 766 _('compute information related to deltas size'),
767 767 ),
768 768 (
769 769 b'',
770 770 b'dist-info',
771 771 None,
772 772 _('compute information related to base distance'),
773 773 ),
774 774 (
775 775 b'',
776 776 b'sparse-info',
777 777 None,
778 778 _('compute information related to sparse read'),
779 779 ),
780 780 ]
781 781 + cmdutil.debugrevlogopts
782 782 + cmdutil.formatteropts,
783 783 _(b'-c|-m|FILE'),
784 784 optionalrepo=True,
785 785 )
786 786 def debugdeltachain(ui, repo, file_=None, **opts):
787 787 """dump information about delta chains in a revlog
788 788
789 789 Output can be templatized. Available template keywords are:
790 790
791 791 :``rev``: revision number
792 792 :``p1``: parent 1 revision number (for reference)
793 793 :``p2``: parent 2 revision number (for reference)
794 794
795 795 :``chainid``: delta chain identifier (numbered by unique base)
796 796 :``chainlen``: delta chain length to this revision
797 797
798 798 :``prevrev``: previous revision in delta chain
799 799 :``deltatype``: role of delta / how it was computed
800 800 - base: a full snapshot
801 801 - snap: an intermediate snapshot
802 802 - p1: a delta against the first parent
803 803 - p2: a delta against the second parent
804 804 - skip1: a delta against the same base as p1
805 805 (when p1 has empty delta
806 806 - skip2: a delta against the same base as p2
807 807 (when p2 has empty delta
808 808 - prev: a delta against the previous revision
809 809 - other: a delta against an arbitrary revision
810 810
811 811 :``compsize``: compressed size of revision
812 812 :``uncompsize``: uncompressed size of revision
813 813 :``chainsize``: total size of compressed revisions in chain
814 814 :``chainratio``: total chain size divided by uncompressed revision size
815 815 (new delta chains typically start at ratio 2.00)
816 816
817 817 :``lindist``: linear distance from base revision in delta chain to end
818 818 of this revision
819 819 :``extradist``: total size of revisions not part of this delta chain from
820 820 base of delta chain to end of this revision; a measurement
821 821 of how much extra data we need to read/seek across to read
822 822 the delta chain for this revision
823 823 :``extraratio``: extradist divided by chainsize; another representation of
824 824 how much unrelated data is needed to load this delta chain
825 825
826 826 If the repository is configured to use the sparse read, additional keywords
827 827 are available:
828 828
829 829 :``readsize``: total size of data read from the disk for a revision
830 830 (sum of the sizes of all the blocks)
831 831 :``largestblock``: size of the largest block of data read from the disk
832 832 :``readdensity``: density of useful bytes in the data read from the disk
833 833 :``srchunks``: in how many data hunks the whole revision would be read
834 834
835 835 It is possible to select the information to be computed, this can provide a
836 836 noticeable speedup to the command in some cases.
837 837
838 838 Always computed:
839 839
840 840 - ``rev``
841 841 - ``p1``
842 842 - ``p2``
843 843 - ``chainid``
844 844 - ``chainlen``
845 845 - ``prevrev``
846 846 - ``deltatype``
847 847
848 848 Computed with --no-size-info
849 849
850 850 - ``compsize``
851 851 - ``uncompsize``
852 852 - ``chainsize``
853 853 - ``chainratio``
854 854
855 855 Computed with --no-dist-info
856 856
857 857 - ``lindist``
858 858 - ``extradist``
859 859 - ``extraratio``
860 860
861 861 Skipped with --no-sparse-info
862 862
863 863 - ``readsize``
864 864 - ``largestblock``
865 865 - ``readdensity``
866 866 - ``srchunks``
867 867
868 868 --
869 869
870 870 The sparse read can be enabled with experimental.sparse-read = True
871 871 """
872 872 revs = None
873 873 revs_opt = opts.pop('rev', [])
874 874 if revs_opt:
875 875 revs = [int(r) for r in revs_opt]
876 876
877 877 all_info = opts.pop('all_info', False)
878 878 size_info = opts.pop('size_info', None)
879 879 if size_info is None:
880 880 size_info = all_info
881 881 dist_info = opts.pop('dist_info', None)
882 882 if dist_info is None:
883 883 dist_info = all_info
884 884 sparse_info = opts.pop('sparse_info', None)
885 885 if sparse_info is None:
886 886 sparse_info = all_info
887 887
888 888 revlog = cmdutil.openrevlog(
889 889 repo, b'debugdeltachain', file_, pycompat.byteskwargs(opts)
890 890 )
891 891 fm = ui.formatter(b'debugdeltachain', pycompat.byteskwargs(opts))
892 892
893 893 lines = revlog_debug.debug_delta_chain(
894 894 revlog,
895 895 revs=revs,
896 896 size_info=size_info,
897 897 dist_info=dist_info,
898 898 sparse_info=sparse_info,
899 899 )
900 900 # first entry is the header
901 901 header = next(lines)
902 902 fm.plain(header)
903 903 for entry in lines:
904 904 label = b' '.join(e[0] for e in entry)
905 905 format = b' '.join(e[1] for e in entry)
906 906 values = [e[3] for e in entry]
907 907 data = dict((e[2], e[3]) for e in entry)
908 908 fm.startitem()
909 909 fm.write(label, format, *values, **data)
910 910 fm.plain(b'\n')
911 911 fm.end()
912 912
913 913
914 914 @command(
915 915 b'debug-delta-find',
916 916 cmdutil.debugrevlogopts
917 917 + cmdutil.formatteropts
918 918 + [
919 919 (
920 920 b'',
921 921 b'source',
922 922 b'full',
923 923 _(b'input data feed to the process (full, storage, p1, p2, prev)'),
924 924 ),
925 925 ],
926 926 _(b'-c|-m|FILE REV'),
927 927 optionalrepo=True,
928 928 )
929 929 def debugdeltafind(ui, repo, arg_1, arg_2=None, source=b'full', **opts):
930 930 """display the computation to get to a valid delta for storing REV
931 931
932 932 This command will replay the process used to find the "best" delta to store
933 933 a revision and display information about all the steps used to get to that
934 934 result.
935 935
936 936 By default, the process is fed with a the full-text for the revision. This
937 937 can be controlled with the --source flag.
938 938
939 939 The revision use the revision number of the target storage (not changelog
940 940 revision number).
941 941
942 942 note: the process is initiated from a full text of the revision to store.
943 943 """
944 944 if arg_2 is None:
945 945 file_ = None
946 946 rev = arg_1
947 947 else:
948 948 file_ = arg_1
949 949 rev = arg_2
950 950
951 951 rev = int(rev)
952 952
953 953 revlog = cmdutil.openrevlog(
954 954 repo, b'debugdeltachain', file_, pycompat.byteskwargs(opts)
955 955 )
956 956 p1r, p2r = revlog.parentrevs(rev)
957 957
958 958 if source == b'full':
959 959 base_rev = nullrev
960 960 elif source == b'storage':
961 961 base_rev = revlog.deltaparent(rev)
962 962 elif source == b'p1':
963 963 base_rev = p1r
964 964 elif source == b'p2':
965 965 base_rev = p2r
966 966 elif source == b'prev':
967 967 base_rev = rev - 1
968 968 else:
969 969 raise error.InputError(b"invalid --source value: %s" % source)
970 970
971 971 revlog_debug.debug_delta_find(ui, revlog, rev, base_rev=base_rev)
972 972
973 973
974 974 @command(
975 975 b'debugdirstate|debugstate',
976 976 [
977 977 (
978 978 b'',
979 979 b'nodates',
980 980 None,
981 981 _(b'do not display the saved mtime (DEPRECATED)'),
982 982 ),
983 983 (b'', b'dates', True, _(b'display the saved mtime')),
984 984 (b'', b'datesort', None, _(b'sort by saved mtime')),
985 985 (
986 986 b'',
987 987 b'docket',
988 988 False,
989 989 _(b'display the docket (metadata file) instead'),
990 990 ),
991 991 (
992 992 b'',
993 993 b'all',
994 994 False,
995 995 _(b'display dirstate-v2 tree nodes that would not exist in v1'),
996 996 ),
997 997 ],
998 998 _(b'[OPTION]...'),
999 999 )
1000 1000 def debugstate(ui, repo, **opts):
1001 1001 """show the contents of the current dirstate"""
1002 1002
1003 1003 if opts.get("docket"):
1004 1004 if not repo.dirstate._use_dirstate_v2:
1005 1005 raise error.Abort(_(b'dirstate v1 does not have a docket'))
1006 1006
1007 1007 docket = repo.dirstate._map.docket
1008 1008 (
1009 1009 start_offset,
1010 1010 root_nodes,
1011 1011 nodes_with_entry,
1012 1012 nodes_with_copy,
1013 1013 unused_bytes,
1014 1014 _unused,
1015 1015 ignore_pattern,
1016 1016 ) = dirstateutils.v2.TREE_METADATA.unpack(docket.tree_metadata)
1017 1017
1018 1018 ui.write(_(b"size of dirstate data: %d\n") % docket.data_size)
1019 1019 ui.write(_(b"data file uuid: %s\n") % docket.uuid)
1020 1020 ui.write(_(b"start offset of root nodes: %d\n") % start_offset)
1021 1021 ui.write(_(b"number of root nodes: %d\n") % root_nodes)
1022 1022 ui.write(_(b"nodes with entries: %d\n") % nodes_with_entry)
1023 1023 ui.write(_(b"nodes with copies: %d\n") % nodes_with_copy)
1024 1024 ui.write(_(b"number of unused bytes: %d\n") % unused_bytes)
1025 1025 ui.write(
1026 1026 _(b"ignore pattern hash: %s\n") % binascii.hexlify(ignore_pattern)
1027 1027 )
1028 1028 return
1029 1029
1030 1030 nodates = not opts['dates']
1031 1031 if opts.get('nodates') is not None:
1032 1032 nodates = True
1033 1033 datesort = opts.get('datesort')
1034 1034
1035 1035 if datesort:
1036 1036
1037 1037 def keyfunc(entry):
1038 1038 filename, _state, _mode, _size, mtime = entry
1039 1039 return (mtime, filename)
1040 1040
1041 1041 else:
1042 1042 keyfunc = None # sort by filename
1043 1043 entries = list(repo.dirstate._map.debug_iter(all=opts['all']))
1044 1044 entries.sort(key=keyfunc)
1045 1045 for entry in entries:
1046 1046 filename, state, mode, size, mtime = entry
1047 1047 if mtime == -1:
1048 1048 timestr = b'unset '
1049 1049 elif nodates:
1050 1050 timestr = b'set '
1051 1051 else:
1052 1052 timestr = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(mtime))
1053 1053 timestr = encoding.strtolocal(timestr)
1054 1054 if mode & 0o20000:
1055 1055 mode = b'lnk'
1056 1056 else:
1057 1057 mode = b'%3o' % (mode & 0o777 & ~util.umask)
1058 1058 ui.write(b"%c %s %10d %s%s\n" % (state, mode, size, timestr, filename))
1059 1059 for f in repo.dirstate.copies():
1060 1060 ui.write(_(b"copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1061 1061
1062 1062
1063 1063 @command(
1064 1064 b'debugdirstateignorepatternshash',
1065 1065 [],
1066 1066 _(b''),
1067 1067 )
1068 1068 def debugdirstateignorepatternshash(ui, repo, **opts):
1069 1069 """show the hash of ignore patterns stored in dirstate if v2,
1070 1070 or nothing for dirstate-v2
1071 1071 """
1072 1072 if repo.dirstate._use_dirstate_v2:
1073 1073 docket = repo.dirstate._map.docket
1074 1074 hash_len = 20 # 160 bits for SHA-1
1075 1075 hash_bytes = docket.tree_metadata[-hash_len:]
1076 1076 ui.write(binascii.hexlify(hash_bytes) + b'\n')
1077 1077
1078 1078
1079 1079 @command(
1080 1080 b'debugdiscovery',
1081 1081 [
1082 1082 (b'', b'old', None, _(b'use old-style discovery')),
1083 1083 (
1084 1084 b'',
1085 1085 b'nonheads',
1086 1086 None,
1087 1087 _(b'use old-style discovery with non-heads included'),
1088 1088 ),
1089 1089 (b'', b'rev', [], b'restrict discovery to this set of revs'),
1090 1090 (b'', b'seed', b'12323', b'specify the random seed use for discovery'),
1091 1091 (
1092 1092 b'',
1093 1093 b'local-as-revs',
1094 1094 b"",
1095 1095 b'treat local has having these revisions only',
1096 1096 ),
1097 1097 (
1098 1098 b'',
1099 1099 b'remote-as-revs',
1100 1100 b"",
1101 1101 b'use local as remote, with only these revisions',
1102 1102 ),
1103 1103 ]
1104 1104 + cmdutil.remoteopts
1105 1105 + cmdutil.formatteropts,
1106 1106 _(b'[--rev REV] [OTHER]'),
1107 1107 )
1108 1108 def debugdiscovery(ui, repo, remoteurl=b"default", **opts):
1109 1109 """runs the changeset discovery protocol in isolation
1110 1110
1111 1111 The local peer can be "replaced" by a subset of the local repository by
1112 1112 using the `--local-as-revs` flag. In the same way, the usual `remote` peer
1113 1113 can be "replaced" by a subset of the local repository using the
1114 1114 `--remote-as-revs` flag. This is useful to efficiently debug pathological
1115 1115 discovery situations.
1116 1116
1117 1117 The following developer oriented config are relevant for people playing with this command:
1118 1118
1119 1119 * devel.discovery.exchange-heads=True
1120 1120
1121 1121 If False, the discovery will not start with
1122 1122 remote head fetching and local head querying.
1123 1123
1124 1124 * devel.discovery.grow-sample=True
1125 1125
1126 1126 If False, the sample size used in set discovery will not be increased
1127 1127 through the process
1128 1128
1129 1129 * devel.discovery.grow-sample.dynamic=True
1130 1130
1131 1131 When discovery.grow-sample.dynamic is True, the default, the sample size is
1132 1132 adapted to the shape of the undecided set (it is set to the max of:
1133 1133 <target-size>, len(roots(undecided)), len(heads(undecided)
1134 1134
1135 1135 * devel.discovery.grow-sample.rate=1.05
1136 1136
1137 1137 the rate at which the sample grow
1138 1138
1139 1139 * devel.discovery.randomize=True
1140 1140
1141 1141 If andom sampling during discovery are deterministic. It is meant for
1142 1142 integration tests.
1143 1143
1144 1144 * devel.discovery.sample-size=200
1145 1145
1146 1146 Control the initial size of the discovery sample
1147 1147
1148 1148 * devel.discovery.sample-size.initial=100
1149 1149
1150 1150 Control the initial size of the discovery for initial change
1151 1151 """
1152 1152 unfi = repo.unfiltered()
1153 1153
1154 1154 # setup potential extra filtering
1155 1155 local_revs = opts["local_as_revs"]
1156 1156 remote_revs = opts["remote_as_revs"]
1157 1157
1158 1158 # make sure tests are repeatable
1159 1159 random.seed(int(opts['seed']))
1160 1160
1161 1161 if not remote_revs:
1162 1162 path = urlutil.get_unique_pull_path_obj(
1163 1163 b'debugdiscovery', ui, remoteurl
1164 1164 )
1165 1165 branches = (path.branch, [])
1166 1166 remote = hg.peer(repo, pycompat.byteskwargs(opts), path)
1167 1167 ui.status(_(b'comparing with %s\n') % urlutil.hidepassword(path.loc))
1168 1168 else:
1169 1169 branches = (None, [])
1170 1170 remote_filtered_revs = logcmdutil.revrange(
1171 1171 unfi, [b"not (::(%s))" % remote_revs]
1172 1172 )
1173 1173 remote_filtered_revs = frozenset(remote_filtered_revs)
1174 1174
1175 1175 def remote_func(x):
1176 1176 return remote_filtered_revs
1177 1177
1178 1178 repoview.filtertable[b'debug-discovery-remote-filter'] = remote_func
1179 1179
1180 1180 remote = repo.peer()
1181 1181 remote._repo = remote._repo.filtered(b'debug-discovery-remote-filter')
1182 1182
1183 1183 if local_revs:
1184 1184 local_filtered_revs = logcmdutil.revrange(
1185 1185 unfi, [b"not (::(%s))" % local_revs]
1186 1186 )
1187 1187 local_filtered_revs = frozenset(local_filtered_revs)
1188 1188
1189 1189 def local_func(x):
1190 1190 return local_filtered_revs
1191 1191
1192 1192 repoview.filtertable[b'debug-discovery-local-filter'] = local_func
1193 1193 repo = repo.filtered(b'debug-discovery-local-filter')
1194 1194
1195 1195 data = {}
1196 1196 if opts.get('old'):
1197 1197
1198 1198 def doit(pushedrevs, remoteheads, remote=remote):
1199 1199 if not hasattr(remote, 'branches'):
1200 1200 # enable in-client legacy support
1201 1201 remote = localrepo.locallegacypeer(remote.local())
1202 1202 if remote_revs:
1203 1203 r = remote._repo.filtered(b'debug-discovery-remote-filter')
1204 1204 remote._repo = r
1205 1205 common, _in, hds = treediscovery.findcommonincoming(
1206 1206 repo, remote, force=True, audit=data
1207 1207 )
1208 1208 common = set(common)
1209 1209 if not opts.get('nonheads'):
1210 1210 ui.writenoi18n(
1211 1211 b"unpruned common: %s\n"
1212 1212 % b" ".join(sorted(short(n) for n in common))
1213 1213 )
1214 1214
1215 1215 clnode = repo.changelog.node
1216 1216 common = repo.revs(b'heads(::%ln)', common)
1217 1217 common = {clnode(r) for r in common}
1218 1218 return common, hds
1219 1219
1220 1220 else:
1221 1221
1222 1222 def doit(pushedrevs, remoteheads, remote=remote):
1223 1223 nodes = None
1224 1224 if pushedrevs:
1225 1225 revs = logcmdutil.revrange(repo, pushedrevs)
1226 1226 nodes = [repo[r].node() for r in revs]
1227 1227 common, any, hds = setdiscovery.findcommonheads(
1228 1228 ui,
1229 1229 repo,
1230 1230 remote,
1231 1231 ancestorsof=nodes,
1232 1232 audit=data,
1233 1233 abortwhenunrelated=False,
1234 1234 )
1235 1235 return common, hds
1236 1236
1237 1237 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches, revs=None)
1238 1238 localrevs = opts['rev']
1239 1239
1240 1240 fm = ui.formatter(b'debugdiscovery', pycompat.byteskwargs(opts))
1241 1241 if fm.strict_format:
1242 1242
1243 1243 @contextlib.contextmanager
1244 1244 def may_capture_output():
1245 1245 ui.pushbuffer()
1246 1246 yield
1247 1247 data[b'output'] = ui.popbuffer()
1248 1248
1249 1249 else:
1250 1250 may_capture_output = util.nullcontextmanager
1251 1251 with may_capture_output():
1252 1252 with util.timedcm('debug-discovery') as t:
1253 1253 common, hds = doit(localrevs, remoterevs)
1254 1254
1255 1255 # compute all statistics
1256 1256 if len(common) == 1 and repo.nullid in common:
1257 1257 common = set()
1258 1258 heads_common = set(common)
1259 1259 heads_remote = set(hds)
1260 1260 heads_local = set(repo.heads())
1261 1261 # note: they cannot be a local or remote head that is in common and not
1262 1262 # itself a head of common.
1263 1263 heads_common_local = heads_common & heads_local
1264 1264 heads_common_remote = heads_common & heads_remote
1265 1265 heads_common_both = heads_common & heads_remote & heads_local
1266 1266
1267 1267 all = repo.revs(b'all()')
1268 1268 common = repo.revs(b'::%ln', common)
1269 1269 roots_common = repo.revs(b'roots(::%ld)', common)
1270 1270 missing = repo.revs(b'not ::%ld', common)
1271 1271 heads_missing = repo.revs(b'heads(%ld)', missing)
1272 1272 roots_missing = repo.revs(b'roots(%ld)', missing)
1273 1273 assert len(common) + len(missing) == len(all)
1274 1274
1275 1275 initial_undecided = repo.revs(
1276 1276 b'not (::%ln or %ln::)', heads_common_remote, heads_common_local
1277 1277 )
1278 1278 heads_initial_undecided = repo.revs(b'heads(%ld)', initial_undecided)
1279 1279 roots_initial_undecided = repo.revs(b'roots(%ld)', initial_undecided)
1280 1280 common_initial_undecided = initial_undecided & common
1281 1281 missing_initial_undecided = initial_undecided & missing
1282 1282
1283 1283 data[b'elapsed'] = t.elapsed
1284 1284 data[b'nb-common-heads'] = len(heads_common)
1285 1285 data[b'nb-common-heads-local'] = len(heads_common_local)
1286 1286 data[b'nb-common-heads-remote'] = len(heads_common_remote)
1287 1287 data[b'nb-common-heads-both'] = len(heads_common_both)
1288 1288 data[b'nb-common-roots'] = len(roots_common)
1289 1289 data[b'nb-head-local'] = len(heads_local)
1290 1290 data[b'nb-head-local-missing'] = len(heads_local) - len(heads_common_local)
1291 1291 data[b'nb-head-remote'] = len(heads_remote)
1292 1292 data[b'nb-head-remote-unknown'] = len(heads_remote) - len(
1293 1293 heads_common_remote
1294 1294 )
1295 1295 data[b'nb-revs'] = len(all)
1296 1296 data[b'nb-revs-common'] = len(common)
1297 1297 data[b'nb-revs-missing'] = len(missing)
1298 1298 data[b'nb-missing-heads'] = len(heads_missing)
1299 1299 data[b'nb-missing-roots'] = len(roots_missing)
1300 1300 data[b'nb-ini_und'] = len(initial_undecided)
1301 1301 data[b'nb-ini_und-heads'] = len(heads_initial_undecided)
1302 1302 data[b'nb-ini_und-roots'] = len(roots_initial_undecided)
1303 1303 data[b'nb-ini_und-common'] = len(common_initial_undecided)
1304 1304 data[b'nb-ini_und-missing'] = len(missing_initial_undecided)
1305 1305
1306 1306 fm.startitem()
1307 1307 fm.data(**pycompat.strkwargs(data))
1308 1308 # display discovery summary
1309 1309 fm.plain(b"elapsed time: %(elapsed)f seconds\n" % data)
1310 1310 fm.plain(b"round-trips: %(total-roundtrips)9d\n" % data)
1311 1311 if b'total-round-trips-heads' in data:
1312 1312 fm.plain(
1313 1313 b" round-trips-heads: %(total-round-trips-heads)9d\n" % data
1314 1314 )
1315 1315 if b'total-round-trips-branches' in data:
1316 1316 fm.plain(
1317 1317 b" round-trips-branches: %(total-round-trips-branches)9d\n"
1318 1318 % data
1319 1319 )
1320 1320 if b'total-round-trips-between' in data:
1321 1321 fm.plain(
1322 1322 b" round-trips-between: %(total-round-trips-between)9d\n" % data
1323 1323 )
1324 1324 fm.plain(b"queries: %(total-queries)9d\n" % data)
1325 1325 if b'total-queries-branches' in data:
1326 1326 fm.plain(b" queries-branches: %(total-queries-branches)9d\n" % data)
1327 1327 if b'total-queries-between' in data:
1328 1328 fm.plain(b" queries-between: %(total-queries-between)9d\n" % data)
1329 1329 fm.plain(b"heads summary:\n")
1330 1330 fm.plain(b" total common heads: %(nb-common-heads)9d\n" % data)
1331 1331 fm.plain(b" also local heads: %(nb-common-heads-local)9d\n" % data)
1332 1332 fm.plain(b" also remote heads: %(nb-common-heads-remote)9d\n" % data)
1333 1333 fm.plain(b" both: %(nb-common-heads-both)9d\n" % data)
1334 1334 fm.plain(b" local heads: %(nb-head-local)9d\n" % data)
1335 1335 fm.plain(b" common: %(nb-common-heads-local)9d\n" % data)
1336 1336 fm.plain(b" missing: %(nb-head-local-missing)9d\n" % data)
1337 1337 fm.plain(b" remote heads: %(nb-head-remote)9d\n" % data)
1338 1338 fm.plain(b" common: %(nb-common-heads-remote)9d\n" % data)
1339 1339 fm.plain(b" unknown: %(nb-head-remote-unknown)9d\n" % data)
1340 1340 fm.plain(b"local changesets: %(nb-revs)9d\n" % data)
1341 1341 fm.plain(b" common: %(nb-revs-common)9d\n" % data)
1342 1342 fm.plain(b" heads: %(nb-common-heads)9d\n" % data)
1343 1343 fm.plain(b" roots: %(nb-common-roots)9d\n" % data)
1344 1344 fm.plain(b" missing: %(nb-revs-missing)9d\n" % data)
1345 1345 fm.plain(b" heads: %(nb-missing-heads)9d\n" % data)
1346 1346 fm.plain(b" roots: %(nb-missing-roots)9d\n" % data)
1347 1347 fm.plain(b" first undecided set: %(nb-ini_und)9d\n" % data)
1348 1348 fm.plain(b" heads: %(nb-ini_und-heads)9d\n" % data)
1349 1349 fm.plain(b" roots: %(nb-ini_und-roots)9d\n" % data)
1350 1350 fm.plain(b" common: %(nb-ini_und-common)9d\n" % data)
1351 1351 fm.plain(b" missing: %(nb-ini_und-missing)9d\n" % data)
1352 1352
1353 1353 if ui.verbose:
1354 1354 fm.plain(
1355 1355 b"common heads: %s\n"
1356 1356 % b" ".join(sorted(short(n) for n in heads_common))
1357 1357 )
1358 1358 fm.end()
1359 1359
1360 1360
1361 1361 _chunksize = 4 << 10
1362 1362
1363 1363
1364 1364 @command(
1365 1365 b'debugdownload',
1366 1366 [
1367 1367 (b'o', b'output', b'', _(b'path')),
1368 1368 ],
1369 1369 optionalrepo=True,
1370 1370 )
1371 1371 def debugdownload(ui, repo, url, output=None, **opts):
1372 1372 """download a resource using Mercurial logic and config"""
1373 1373 fh = urlmod.open(ui, url, output)
1374 1374
1375 1375 dest = ui
1376 1376 if output:
1377 1377 dest = open(output, b"wb", _chunksize)
1378 1378 try:
1379 1379 data = fh.read(_chunksize)
1380 1380 while data:
1381 1381 dest.write(data)
1382 1382 data = fh.read(_chunksize)
1383 1383 finally:
1384 1384 if output:
1385 1385 dest.close()
1386 1386
1387 1387
1388 1388 @command(b'debugextensions', cmdutil.formatteropts, [], optionalrepo=True)
1389 1389 def debugextensions(ui, repo, **opts):
1390 1390 '''show information about active extensions'''
1391 1391 exts = extensions.extensions(ui)
1392 1392 hgver = util.version()
1393 1393 fm = ui.formatter(b'debugextensions', pycompat.byteskwargs(opts))
1394 1394 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
1395 1395 isinternal = extensions.ismoduleinternal(extmod)
1396 1396 extsource = None
1397 1397
1398 1398 if hasattr(extmod, '__file__'):
1399 1399 extsource = pycompat.fsencode(extmod.__file__)
1400 1400 elif getattr(sys, 'oxidized', False):
1401 1401 extsource = pycompat.sysexecutable
1402 1402 if isinternal:
1403 1403 exttestedwith = [] # never expose magic string to users
1404 1404 else:
1405 1405 exttestedwith = getattr(extmod, 'testedwith', b'').split()
1406 1406 extbuglink = getattr(extmod, 'buglink', None)
1407 1407
1408 1408 fm.startitem()
1409 1409
1410 1410 if ui.quiet or ui.verbose:
1411 1411 fm.write(b'name', b'%s\n', extname)
1412 1412 else:
1413 1413 fm.write(b'name', b'%s', extname)
1414 1414 if isinternal or hgver in exttestedwith:
1415 1415 fm.plain(b'\n')
1416 1416 elif not exttestedwith:
1417 1417 fm.plain(_(b' (untested!)\n'))
1418 1418 else:
1419 1419 lasttestedversion = exttestedwith[-1]
1420 1420 fm.plain(b' (%s!)\n' % lasttestedversion)
1421 1421
1422 1422 fm.condwrite(
1423 1423 ui.verbose and extsource,
1424 1424 b'source',
1425 1425 _(b' location: %s\n'),
1426 1426 extsource or b"",
1427 1427 )
1428 1428
1429 1429 if ui.verbose:
1430 1430 fm.plain(_(b' bundled: %s\n') % [b'no', b'yes'][isinternal])
1431 1431 fm.data(bundled=isinternal)
1432 1432
1433 1433 fm.condwrite(
1434 1434 ui.verbose and exttestedwith,
1435 1435 b'testedwith',
1436 1436 _(b' tested with: %s\n'),
1437 1437 fm.formatlist(exttestedwith, name=b'ver'),
1438 1438 )
1439 1439
1440 1440 fm.condwrite(
1441 1441 ui.verbose and extbuglink,
1442 1442 b'buglink',
1443 1443 _(b' bug reporting: %s\n'),
1444 1444 extbuglink or b"",
1445 1445 )
1446 1446
1447 1447 fm.end()
1448 1448
1449 1449
1450 1450 @command(
1451 1451 b'debugfileset',
1452 1452 [
1453 1453 (
1454 1454 b'r',
1455 1455 b'rev',
1456 1456 b'',
1457 1457 _(b'apply the filespec on this revision'),
1458 1458 _(b'REV'),
1459 1459 ),
1460 1460 (
1461 1461 b'',
1462 1462 b'all-files',
1463 1463 False,
1464 1464 _(b'test files from all revisions and working directory'),
1465 1465 ),
1466 1466 (
1467 1467 b's',
1468 1468 b'show-matcher',
1469 1469 None,
1470 1470 _(b'print internal representation of matcher'),
1471 1471 ),
1472 1472 (
1473 1473 b'p',
1474 1474 b'show-stage',
1475 1475 [],
1476 1476 _(b'print parsed tree at the given stage'),
1477 1477 _(b'NAME'),
1478 1478 ),
1479 1479 ],
1480 1480 _(b'[-r REV] [--all-files] [OPTION]... FILESPEC'),
1481 1481 )
1482 1482 def debugfileset(ui, repo, expr, **opts):
1483 1483 '''parse and apply a fileset specification'''
1484 1484 from . import fileset
1485 1485
1486 1486 fileset.symbols # force import of fileset so we have predicates to optimize
1487 1487
1488 1488 ctx = logcmdutil.revsingle(repo, opts.get('rev'), None)
1489 1489
1490 1490 stages = [
1491 1491 (b'parsed', pycompat.identity),
1492 1492 (b'analyzed', filesetlang.analyze),
1493 1493 (b'optimized', filesetlang.optimize),
1494 1494 ]
1495 1495 stagenames = {n for n, f in stages}
1496 1496
1497 1497 showalways = set()
1498 1498 if ui.verbose and not opts['show_stage']:
1499 1499 # show parsed tree by --verbose (deprecated)
1500 1500 showalways.add(b'parsed')
1501 1501 if opts['show_stage'] == [b'all']:
1502 1502 showalways.update(stagenames)
1503 1503 else:
1504 1504 for n in opts['show_stage']:
1505 1505 if n not in stagenames:
1506 1506 raise error.Abort(_(b'invalid stage name: %s') % n)
1507 1507 showalways.update(opts['show_stage'])
1508 1508
1509 1509 tree = filesetlang.parse(expr)
1510 1510 for n, f in stages:
1511 1511 tree = f(tree)
1512 1512 if n in showalways:
1513 1513 if opts['show_stage'] or n != b'parsed':
1514 1514 ui.write(b"* %s:\n" % n)
1515 1515 ui.write(filesetlang.prettyformat(tree), b"\n")
1516 1516
1517 1517 files = set()
1518 1518 if opts['all_files']:
1519 1519 for r in repo:
1520 1520 c = repo[r]
1521 1521 files.update(c.files())
1522 1522 files.update(c.substate)
1523 1523 if opts['all_files'] or ctx.rev() is None:
1524 1524 wctx = repo[None]
1525 1525 files.update(
1526 1526 repo.dirstate.walk(
1527 1527 scmutil.matchall(repo),
1528 1528 subrepos=list(wctx.substate),
1529 1529 unknown=True,
1530 1530 ignored=True,
1531 1531 )
1532 1532 )
1533 1533 files.update(wctx.substate)
1534 1534 else:
1535 1535 files.update(ctx.files())
1536 1536 files.update(ctx.substate)
1537 1537
1538 1538 m = ctx.matchfileset(repo.getcwd(), expr)
1539 1539 if opts['show_matcher'] or (opts['show_matcher'] is None and ui.verbose):
1540 1540 ui.writenoi18n(b'* matcher:\n', stringutil.prettyrepr(m), b'\n')
1541 1541 for f in sorted(files):
1542 1542 if not m(f):
1543 1543 continue
1544 1544 ui.write(b"%s\n" % f)
1545 1545
1546 1546
1547 1547 @command(
1548 1548 b"debug-repair-issue6528",
1549 1549 [
1550 1550 (
1551 1551 b'',
1552 1552 b'to-report',
1553 1553 b'',
1554 1554 _(b'build a report of affected revisions to this file'),
1555 1555 _(b'FILE'),
1556 1556 ),
1557 1557 (
1558 1558 b'',
1559 1559 b'from-report',
1560 1560 b'',
1561 1561 _(b'repair revisions listed in this report file'),
1562 1562 _(b'FILE'),
1563 1563 ),
1564 1564 (
1565 1565 b'',
1566 1566 b'paranoid',
1567 1567 False,
1568 1568 _(b'check that both detection methods do the same thing'),
1569 1569 ),
1570 1570 ]
1571 1571 + cmdutil.dryrunopts,
1572 1572 )
1573 1573 def debug_repair_issue6528(ui, repo, **opts):
1574 1574 """find affected revisions and repair them. See issue6528 for more details.
1575 1575
1576 1576 The `--to-report` and `--from-report` flags allow you to cache and reuse the
1577 1577 computation of affected revisions for a given repository across clones.
1578 1578 The report format is line-based (with empty lines ignored):
1579 1579
1580 1580 ```
1581 1581 <ascii-hex of the affected revision>,... <unencoded filelog index filename>
1582 1582 ```
1583 1583
1584 1584 There can be multiple broken revisions per filelog, they are separated by
1585 1585 a comma with no spaces. The only space is between the revision(s) and the
1586 1586 filename.
1587 1587
1588 1588 Note that this does *not* mean that this repairs future affected revisions,
1589 1589 that needs a separate fix at the exchange level that was introduced in
1590 1590 Mercurial 5.9.1.
1591 1591
1592 1592 There is a `--paranoid` flag to test that the fast implementation is correct
1593 1593 by checking it against the slow implementation. Since this matter is quite
1594 1594 urgent and testing every edge-case is probably quite costly, we use this
1595 1595 method to test on large repositories as a fuzzing method of sorts.
1596 1596 """
1597 1597 cmdutil.check_incompatible_arguments(
1598 1598 opts, 'to_report', ['from_report', 'dry_run']
1599 1599 )
1600 1600 dry_run = opts.get('dry_run')
1601 1601 to_report = opts.get('to_report')
1602 1602 from_report = opts.get('from_report')
1603 1603 paranoid = opts.get('paranoid')
1604 1604 # TODO maybe add filelog pattern and revision pattern parameters to help
1605 1605 # narrow down the search for users that know what they're looking for?
1606 1606
1607 1607 if requirements.REVLOGV1_REQUIREMENT not in repo.requirements:
1608 1608 msg = b"can only repair revlogv1 repositories, v2 is not affected"
1609 1609 raise error.Abort(_(msg))
1610 1610
1611 1611 rewrite.repair_issue6528(
1612 1612 ui,
1613 1613 repo,
1614 1614 dry_run=dry_run,
1615 1615 to_report=to_report,
1616 1616 from_report=from_report,
1617 1617 paranoid=paranoid,
1618 1618 )
1619 1619
1620 1620
1621 1621 @command(b'debugformat', [] + cmdutil.formatteropts)
1622 1622 def debugformat(ui, repo, **opts):
1623 1623 """display format information about the current repository
1624 1624
1625 1625 Use --verbose to get extra information about current config value and
1626 1626 Mercurial default."""
1627 1627 maxvariantlength = max(len(fv.name) for fv in upgrade.allformatvariant)
1628 1628 maxvariantlength = max(len(b'format-variant'), maxvariantlength)
1629 1629
1630 1630 def makeformatname(name):
1631 1631 return b'%s:' + (b' ' * (maxvariantlength - len(name)))
1632 1632
1633 1633 fm = ui.formatter(b'debugformat', pycompat.byteskwargs(opts))
1634 1634 if fm.isplain():
1635 1635
1636 1636 def formatvalue(value):
1637 1637 if hasattr(value, 'startswith'):
1638 1638 return value
1639 1639 if value:
1640 1640 return b'yes'
1641 1641 else:
1642 1642 return b'no'
1643 1643
1644 1644 else:
1645 1645 formatvalue = pycompat.identity
1646 1646
1647 1647 fm.plain(b'format-variant')
1648 1648 fm.plain(b' ' * (maxvariantlength - len(b'format-variant')))
1649 1649 fm.plain(b' repo')
1650 1650 if ui.verbose:
1651 1651 fm.plain(b' config default')
1652 1652 fm.plain(b'\n')
1653 1653 for fv in upgrade.allformatvariant:
1654 1654 fm.startitem()
1655 1655 repovalue = fv.fromrepo(repo)
1656 1656 configvalue = fv.fromconfig(repo)
1657 1657
1658 1658 if repovalue != configvalue:
1659 1659 namelabel = b'formatvariant.name.mismatchconfig'
1660 1660 repolabel = b'formatvariant.repo.mismatchconfig'
1661 1661 elif repovalue != fv.default:
1662 1662 namelabel = b'formatvariant.name.mismatchdefault'
1663 1663 repolabel = b'formatvariant.repo.mismatchdefault'
1664 1664 else:
1665 1665 namelabel = b'formatvariant.name.uptodate'
1666 1666 repolabel = b'formatvariant.repo.uptodate'
1667 1667
1668 1668 fm.write(b'name', makeformatname(fv.name), fv.name, label=namelabel)
1669 1669 fm.write(b'repo', b' %3s', formatvalue(repovalue), label=repolabel)
1670 1670 if fv.default != configvalue:
1671 1671 configlabel = b'formatvariant.config.special'
1672 1672 else:
1673 1673 configlabel = b'formatvariant.config.default'
1674 1674 fm.condwrite(
1675 1675 ui.verbose,
1676 1676 b'config',
1677 1677 b' %6s',
1678 1678 formatvalue(configvalue),
1679 1679 label=configlabel,
1680 1680 )
1681 1681 fm.condwrite(
1682 1682 ui.verbose,
1683 1683 b'default',
1684 1684 b' %7s',
1685 1685 formatvalue(fv.default),
1686 1686 label=b'formatvariant.default',
1687 1687 )
1688 1688 fm.plain(b'\n')
1689 1689 fm.end()
1690 1690
1691 1691
1692 1692 @command(b'debugfsinfo', [], _(b'[PATH]'), norepo=True)
1693 1693 def debugfsinfo(ui, path=b"."):
1694 1694 """show information detected about current filesystem"""
1695 1695 ui.writenoi18n(b'path: %s\n' % path)
1696 1696 ui.writenoi18n(
1697 1697 b'mounted on: %s\n' % (util.getfsmountpoint(path) or b'(unknown)')
1698 1698 )
1699 1699 ui.writenoi18n(b'exec: %s\n' % (util.checkexec(path) and b'yes' or b'no'))
1700 1700 ui.writenoi18n(b'fstype: %s\n' % (util.getfstype(path) or b'(unknown)'))
1701 1701 ui.writenoi18n(
1702 1702 b'symlink: %s\n' % (util.checklink(path) and b'yes' or b'no')
1703 1703 )
1704 1704 ui.writenoi18n(
1705 1705 b'hardlink: %s\n' % (util.checknlink(path) and b'yes' or b'no')
1706 1706 )
1707 1707 casesensitive = b'(unknown)'
1708 1708 try:
1709 1709 with pycompat.namedtempfile(prefix=b'.debugfsinfo', dir=path) as f:
1710 1710 casesensitive = util.fscasesensitive(f.name) and b'yes' or b'no'
1711 1711 except OSError:
1712 1712 pass
1713 1713 ui.writenoi18n(b'case-sensitive: %s\n' % casesensitive)
1714 1714
1715 1715
1716 1716 @command(
1717 1717 b'debuggetbundle',
1718 1718 [
1719 1719 (b'H', b'head', [], _(b'id of head node'), _(b'ID')),
1720 1720 (b'C', b'common', [], _(b'id of common node'), _(b'ID')),
1721 1721 (
1722 1722 b't',
1723 1723 b'type',
1724 1724 b'bzip2',
1725 1725 _(b'bundle compression type to use'),
1726 1726 _(b'TYPE'),
1727 1727 ),
1728 1728 ],
1729 1729 _(b'REPO FILE [-H|-C ID]...'),
1730 1730 norepo=True,
1731 1731 )
1732 1732 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1733 1733 """retrieves a bundle from a repo
1734 1734
1735 1735 Every ID must be a full-length hex node id string. Saves the bundle to the
1736 1736 given file.
1737 1737 """
1738 1738 repo = hg.peer(ui, pycompat.byteskwargs(opts), repopath)
1739 1739 if not repo.capable(b'getbundle'):
1740 1740 raise error.Abort(b"getbundle() not supported by target repository")
1741 1741 args = {}
1742 1742 if common:
1743 1743 args['common'] = [bin(s) for s in common]
1744 1744 if head:
1745 1745 args['heads'] = [bin(s) for s in head]
1746 1746 # TODO: get desired bundlecaps from command line.
1747 1747 args['bundlecaps'] = None
1748 1748 bundle = repo.getbundle(b'debug', **args)
1749 1749
1750 1750 bundletype = opts.get('type', b'bzip2').lower()
1751 1751 btypes = {
1752 1752 b'none': b'HG10UN',
1753 1753 b'bzip2': b'HG10BZ',
1754 1754 b'gzip': b'HG10GZ',
1755 1755 b'bundle2': b'HG20',
1756 1756 }
1757 1757 bundletype = btypes.get(bundletype)
1758 1758 if bundletype not in bundle2.bundletypes:
1759 1759 raise error.Abort(_(b'unknown bundle type specified with --type'))
1760 1760 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
1761 1761
1762 1762
1763 1763 @command(b'debugignore', [], b'[FILE]...')
1764 1764 def debugignore(ui, repo, *files, **opts):
1765 1765 """display the combined ignore pattern and information about ignored files
1766 1766
1767 1767 With no argument display the combined ignore pattern.
1768 1768
1769 1769 Given space separated file names, shows if the given file is ignored and
1770 1770 if so, show the ignore rule (file and line number) that matched it.
1771 1771 """
1772 1772 ignore = repo.dirstate._ignore
1773 1773 if not files:
1774 1774 # Show all the patterns
1775 1775 ui.write(b"%s\n" % pycompat.byterepr(ignore))
1776 1776 else:
1777 1777 m = scmutil.match(repo[None], pats=files)
1778 1778 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
1779 1779 for f in m.files():
1780 1780 nf = util.normpath(f)
1781 1781 ignored = None
1782 1782 ignoredata = None
1783 1783 if nf != b'.':
1784 1784 if ignore(nf):
1785 1785 ignored = nf
1786 1786 ignoredata = repo.dirstate._ignorefileandline(nf)
1787 1787 else:
1788 1788 for p in pathutil.finddirs(nf):
1789 1789 if ignore(p):
1790 1790 ignored = p
1791 1791 ignoredata = repo.dirstate._ignorefileandline(p)
1792 1792 break
1793 1793 if ignored:
1794 1794 if ignored == nf:
1795 1795 ui.write(_(b"%s is ignored\n") % uipathfn(f))
1796 1796 else:
1797 1797 ui.write(
1798 1798 _(
1799 1799 b"%s is ignored because of "
1800 1800 b"containing directory %s\n"
1801 1801 )
1802 1802 % (uipathfn(f), ignored)
1803 1803 )
1804 1804 ignorefile, lineno, line = ignoredata
1805 1805 ui.write(
1806 1806 _(b"(ignore rule in %s, line %d: '%s')\n")
1807 1807 % (ignorefile, lineno, line)
1808 1808 )
1809 1809 else:
1810 1810 ui.write(_(b"%s is not ignored\n") % uipathfn(f))
1811 1811
1812 1812
1813 1813 @command(
1814 1814 b'debug-revlog-index|debugindex',
1815 1815 cmdutil.debugrevlogopts + cmdutil.formatteropts,
1816 1816 _(b'-c|-m|FILE'),
1817 1817 )
1818 1818 def debugindex(ui, repo, file_=None, **opts):
1819 1819 """dump index data for a revlog"""
1820 1820 opts = pycompat.byteskwargs(opts)
1821 1821 store = cmdutil.openstorage(repo, b'debugindex', file_, opts)
1822 1822
1823 1823 fm = ui.formatter(b'debugindex', opts)
1824 1824
1825 1825 revlog = getattr(store, '_revlog', store)
1826 1826
1827 1827 return revlog_debug.debug_index(
1828 1828 ui,
1829 1829 repo,
1830 1830 formatter=fm,
1831 1831 revlog=revlog,
1832 1832 full_node=ui.debugflag,
1833 1833 )
1834 1834
1835 1835
1836 1836 @command(
1837 1837 b'debugindexdot',
1838 1838 cmdutil.debugrevlogopts,
1839 1839 _(b'-c|-m|FILE'),
1840 1840 optionalrepo=True,
1841 1841 )
1842 1842 def debugindexdot(ui, repo, file_=None, **opts):
1843 1843 """dump an index DAG as a graphviz dot file"""
1844 1844 r = cmdutil.openstorage(
1845 1845 repo, b'debugindexdot', file_, pycompat.byteskwargs(opts)
1846 1846 )
1847 1847 ui.writenoi18n(b"digraph G {\n")
1848 1848 for i in r:
1849 1849 node = r.node(i)
1850 1850 pp = r.parents(node)
1851 1851 ui.write(b"\t%d -> %d\n" % (r.rev(pp[0]), i))
1852 1852 if pp[1] != repo.nullid:
1853 1853 ui.write(b"\t%d -> %d\n" % (r.rev(pp[1]), i))
1854 1854 ui.write(b"}\n")
1855 1855
1856 1856
1857 1857 @command(b'debugindexstats', [])
1858 1858 def debugindexstats(ui, repo):
1859 1859 """show stats related to the changelog index"""
1860 1860 repo.changelog.shortest(repo.nullid, 1)
1861 1861 index = repo.changelog.index
1862 1862 if not hasattr(index, 'stats'):
1863 1863 raise error.Abort(_(b'debugindexstats only works with native C code'))
1864 1864 for k, v in sorted(index.stats().items()):
1865 1865 ui.write(b'%s: %d\n' % (k, v))
1866 1866
1867 1867
1868 1868 @command(b'debuginstall', [] + cmdutil.formatteropts, b'', norepo=True)
1869 1869 def debuginstall(ui, **opts):
1870 1870 """test Mercurial installation
1871 1871
1872 1872 Returns 0 on success.
1873 1873 """
1874 1874 problems = 0
1875 1875
1876 1876 fm = ui.formatter(b'debuginstall', pycompat.byteskwargs(opts))
1877 1877 fm.startitem()
1878 1878
1879 1879 # encoding might be unknown or wrong. don't translate these messages.
1880 1880 fm.write(b'encoding', b"checking encoding (%s)...\n", encoding.encoding)
1881 1881 err = None
1882 1882 try:
1883 1883 codecs.lookup(pycompat.sysstr(encoding.encoding))
1884 1884 except LookupError as inst:
1885 1885 err = stringutil.forcebytestr(inst)
1886 1886 problems += 1
1887 1887 fm.condwrite(
1888 1888 err,
1889 1889 b'encodingerror',
1890 1890 b" %s\n (check that your locale is properly set)\n",
1891 1891 err,
1892 1892 )
1893 1893
1894 1894 # Python
1895 1895 pythonlib = None
1896 1896 if hasattr(os, '__file__'):
1897 1897 pythonlib = os.path.dirname(pycompat.fsencode(os.__file__))
1898 1898 elif getattr(sys, 'oxidized', False):
1899 1899 pythonlib = pycompat.sysexecutable
1900 1900
1901 1901 fm.write(
1902 1902 b'pythonexe',
1903 1903 _(b"checking Python executable (%s)\n"),
1904 1904 pycompat.sysexecutable or _(b"unknown"),
1905 1905 )
1906 1906 fm.write(
1907 1907 b'pythonimplementation',
1908 1908 _(b"checking Python implementation (%s)\n"),
1909 1909 pycompat.sysbytes(platform.python_implementation()),
1910 1910 )
1911 1911 fm.write(
1912 1912 b'pythonver',
1913 1913 _(b"checking Python version (%s)\n"),
1914 1914 (b"%d.%d.%d" % sys.version_info[:3]),
1915 1915 )
1916 1916 fm.write(
1917 1917 b'pythonlib',
1918 1918 _(b"checking Python lib (%s)...\n"),
1919 1919 pythonlib or _(b"unknown"),
1920 1920 )
1921 1921
1922 1922 try:
1923 1923 from . import rustext # pytype: disable=import-error
1924 1924
1925 1925 rustext.__doc__ # trigger lazy import
1926 1926 except ImportError:
1927 1927 rustext = None
1928 1928
1929 1929 security = set(sslutil.supportedprotocols)
1930 1930 if sslutil.hassni:
1931 1931 security.add(b'sni')
1932 1932
1933 1933 fm.write(
1934 1934 b'pythonsecurity',
1935 1935 _(b"checking Python security support (%s)\n"),
1936 1936 fm.formatlist(sorted(security), name=b'protocol', fmt=b'%s', sep=b','),
1937 1937 )
1938 1938
1939 1939 # These are warnings, not errors. So don't increment problem count. This
1940 1940 # may change in the future.
1941 1941 if b'tls1.2' not in security:
1942 1942 fm.plain(
1943 1943 _(
1944 1944 b' TLS 1.2 not supported by Python install; '
1945 1945 b'network connections lack modern security\n'
1946 1946 )
1947 1947 )
1948 1948 if b'sni' not in security:
1949 1949 fm.plain(
1950 1950 _(
1951 1951 b' SNI not supported by Python install; may have '
1952 1952 b'connectivity issues with some servers\n'
1953 1953 )
1954 1954 )
1955 1955
1956 1956 fm.plain(
1957 1957 _(
1958 1958 b"checking Rust extensions (%s)\n"
1959 1959 % (b'missing' if rustext is None else b'installed')
1960 1960 ),
1961 1961 )
1962 1962
1963 1963 # TODO print CA cert info
1964 1964
1965 1965 # hg version
1966 1966 hgver = util.version()
1967 1967 fm.write(
1968 1968 b'hgver', _(b"checking Mercurial version (%s)\n"), hgver.split(b'+')[0]
1969 1969 )
1970 1970 fm.write(
1971 1971 b'hgverextra',
1972 1972 _(b"checking Mercurial custom build (%s)\n"),
1973 1973 b'+'.join(hgver.split(b'+')[1:]),
1974 1974 )
1975 1975
1976 1976 # compiled modules
1977 1977 hgmodules = None
1978 1978 if hasattr(sys.modules[__name__], '__file__'):
1979 1979 hgmodules = os.path.dirname(pycompat.fsencode(__file__))
1980 1980 elif getattr(sys, 'oxidized', False):
1981 1981 hgmodules = pycompat.sysexecutable
1982 1982
1983 1983 fm.write(
1984 1984 b'hgmodulepolicy', _(b"checking module policy (%s)\n"), policy.policy
1985 1985 )
1986 1986 fm.write(
1987 1987 b'hgmodules',
1988 1988 _(b"checking installed modules (%s)...\n"),
1989 1989 hgmodules or _(b"unknown"),
1990 1990 )
1991 1991
1992 1992 rustandc = policy.policy in (b'rust+c', b'rust+c-allow')
1993 1993 rustext = rustandc # for now, that's the only case
1994 1994 cext = policy.policy in (b'c', b'allow') or rustandc
1995 1995 nopure = cext or rustext
1996 1996 if nopure:
1997 1997 err = None
1998 1998 try:
1999 1999 if cext:
2000 2000 from .cext import ( # pytype: disable=import-error
2001 2001 base85,
2002 2002 bdiff,
2003 2003 mpatch,
2004 2004 osutil,
2005 2005 )
2006 2006
2007 2007 # quiet pyflakes
2008 2008 dir(bdiff), dir(mpatch), dir(base85), dir(osutil)
2009 2009 if rustext:
2010 2010 from .rustext import ( # pytype: disable=import-error
2011 2011 ancestor,
2012 2012 dirstate,
2013 2013 )
2014 2014
2015 2015 dir(ancestor), dir(dirstate) # quiet pyflakes
2016 2016 except Exception as inst:
2017 2017 err = stringutil.forcebytestr(inst)
2018 2018 problems += 1
2019 2019 fm.condwrite(err, b'extensionserror', b" %s\n", err)
2020 2020
2021 2021 compengines = util.compengines._engines.values()
2022 2022 fm.write(
2023 2023 b'compengines',
2024 2024 _(b'checking registered compression engines (%s)\n'),
2025 2025 fm.formatlist(
2026 2026 sorted(e.name() for e in compengines),
2027 2027 name=b'compengine',
2028 2028 fmt=b'%s',
2029 2029 sep=b', ',
2030 2030 ),
2031 2031 )
2032 2032 fm.write(
2033 2033 b'compenginesavail',
2034 2034 _(b'checking available compression engines (%s)\n'),
2035 2035 fm.formatlist(
2036 2036 sorted(e.name() for e in compengines if e.available()),
2037 2037 name=b'compengine',
2038 2038 fmt=b'%s',
2039 2039 sep=b', ',
2040 2040 ),
2041 2041 )
2042 2042 wirecompengines = compression.compengines.supportedwireengines(
2043 2043 compression.SERVERROLE
2044 2044 )
2045 2045 fm.write(
2046 2046 b'compenginesserver',
2047 2047 _(
2048 2048 b'checking available compression engines '
2049 2049 b'for wire protocol (%s)\n'
2050 2050 ),
2051 2051 fm.formatlist(
2052 2052 [e.name() for e in wirecompengines if e.wireprotosupport()],
2053 2053 name=b'compengine',
2054 2054 fmt=b'%s',
2055 2055 sep=b', ',
2056 2056 ),
2057 2057 )
2058 2058 re2 = b'missing'
2059 2059 if util.has_re2():
2060 2060 re2 = b'available'
2061 2061 fm.plain(_(b'checking "re2" regexp engine (%s)\n') % re2)
2062 2062 fm.data(re2=bool(util._re2))
2063 2063
2064 2064 # templates
2065 2065 p = templater.templatedir()
2066 2066 fm.write(b'templatedirs', b'checking templates (%s)...\n', p or b'')
2067 2067 fm.condwrite(not p, b'', _(b" no template directories found\n"))
2068 2068 if p:
2069 2069 (m, fp) = templater.try_open_template(b"map-cmdline.default")
2070 2070 if m:
2071 2071 # template found, check if it is working
2072 2072 err = None
2073 2073 try:
2074 2074 templater.templater.frommapfile(m)
2075 2075 except Exception as inst:
2076 2076 err = stringutil.forcebytestr(inst)
2077 2077 p = None
2078 2078 fm.condwrite(err, b'defaulttemplateerror', b" %s\n", err)
2079 2079 else:
2080 2080 p = None
2081 2081 fm.condwrite(
2082 2082 p, b'defaulttemplate', _(b"checking default template (%s)\n"), m
2083 2083 )
2084 2084 fm.condwrite(
2085 2085 not m,
2086 2086 b'defaulttemplatenotfound',
2087 2087 _(b" template '%s' not found\n"),
2088 2088 b"default",
2089 2089 )
2090 2090 if not p:
2091 2091 problems += 1
2092 2092 fm.condwrite(
2093 2093 not p, b'', _(b" (templates seem to have been installed incorrectly)\n")
2094 2094 )
2095 2095
2096 2096 # editor
2097 2097 editor = ui.geteditor()
2098 2098 editor = util.expandpath(editor)
2099 2099 editorbin = procutil.shellsplit(editor)[0]
2100 2100 fm.write(b'editor', _(b"checking commit editor... (%s)\n"), editorbin)
2101 2101 cmdpath = procutil.findexe(editorbin)
2102 2102 fm.condwrite(
2103 2103 not cmdpath and editor == b'vi',
2104 2104 b'vinotfound',
2105 2105 _(
2106 2106 b" No commit editor set and can't find %s in PATH\n"
2107 2107 b" (specify a commit editor in your configuration"
2108 2108 b" file)\n"
2109 2109 ),
2110 2110 not cmdpath and editor == b'vi' and editorbin,
2111 2111 )
2112 2112 fm.condwrite(
2113 2113 not cmdpath and editor != b'vi',
2114 2114 b'editornotfound',
2115 2115 _(
2116 2116 b" Can't find editor '%s' in PATH\n"
2117 2117 b" (specify a commit editor in your configuration"
2118 2118 b" file)\n"
2119 2119 ),
2120 2120 not cmdpath and editorbin,
2121 2121 )
2122 2122 if not cmdpath and editor != b'vi':
2123 2123 problems += 1
2124 2124
2125 2125 # check username
2126 2126 username = None
2127 2127 err = None
2128 2128 try:
2129 2129 username = ui.username()
2130 2130 except error.Abort as e:
2131 2131 err = e.message
2132 2132 problems += 1
2133 2133
2134 2134 fm.condwrite(
2135 2135 username, b'username', _(b"checking username (%s)\n"), username
2136 2136 )
2137 2137 fm.condwrite(
2138 2138 err,
2139 2139 b'usernameerror',
2140 2140 _(
2141 2141 b"checking username...\n %s\n"
2142 2142 b" (specify a username in your configuration file)\n"
2143 2143 ),
2144 2144 err,
2145 2145 )
2146 2146
2147 2147 for name, mod in extensions.extensions():
2148 2148 handler = getattr(mod, 'debuginstall', None)
2149 2149 if handler is not None:
2150 2150 problems += handler(ui, fm)
2151 2151
2152 2152 fm.condwrite(not problems, b'', _(b"no problems detected\n"))
2153 2153 if not problems:
2154 2154 fm.data(problems=problems)
2155 2155 fm.condwrite(
2156 2156 problems,
2157 2157 b'problems',
2158 2158 _(b"%d problems detected, please check your install!\n"),
2159 2159 problems,
2160 2160 )
2161 2161 fm.end()
2162 2162
2163 2163 return problems
2164 2164
2165 2165
2166 2166 @command(b'debugknown', [], _(b'REPO ID...'), norepo=True)
2167 2167 def debugknown(ui, repopath, *ids, **opts):
2168 2168 """test whether node ids are known to a repo
2169 2169
2170 2170 Every ID must be a full-length hex node id string. Returns a list of 0s
2171 2171 and 1s indicating unknown/known.
2172 2172 """
2173 2173 repo = hg.peer(ui, pycompat.byteskwargs(opts), repopath)
2174 2174 if not repo.capable(b'known'):
2175 2175 raise error.Abort(b"known() not supported by target repository")
2176 2176 flags = repo.known([bin(s) for s in ids])
2177 2177 ui.write(b"%s\n" % (b"".join([f and b"1" or b"0" for f in flags])))
2178 2178
2179 2179
2180 2180 @command(b'debuglabelcomplete', [], _(b'LABEL...'))
2181 2181 def debuglabelcomplete(ui, repo, *args):
2182 2182 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2183 2183 debugnamecomplete(ui, repo, *args)
2184 2184
2185 2185
2186 2186 @command(
2187 2187 b'debuglocks',
2188 2188 [
2189 2189 (b'L', b'force-free-lock', None, _(b'free the store lock (DANGEROUS)')),
2190 2190 (
2191 2191 b'W',
2192 2192 b'force-free-wlock',
2193 2193 None,
2194 2194 _(b'free the working state lock (DANGEROUS)'),
2195 2195 ),
2196 2196 (b's', b'set-lock', None, _(b'set the store lock until stopped')),
2197 2197 (
2198 2198 b'S',
2199 2199 b'set-wlock',
2200 2200 None,
2201 2201 _(b'set the working state lock until stopped'),
2202 2202 ),
2203 2203 ],
2204 2204 _(b'[OPTION]...'),
2205 2205 )
2206 2206 def debuglocks(ui, repo, **opts):
2207 2207 """show or modify state of locks
2208 2208
2209 2209 By default, this command will show which locks are held. This
2210 2210 includes the user and process holding the lock, the amount of time
2211 2211 the lock has been held, and the machine name where the process is
2212 2212 running if it's not local.
2213 2213
2214 2214 Locks protect the integrity of Mercurial's data, so should be
2215 2215 treated with care. System crashes or other interruptions may cause
2216 2216 locks to not be properly released, though Mercurial will usually
2217 2217 detect and remove such stale locks automatically.
2218 2218
2219 2219 However, detecting stale locks may not always be possible (for
2220 2220 instance, on a shared filesystem). Removing locks may also be
2221 2221 blocked by filesystem permissions.
2222 2222
2223 2223 Setting a lock will prevent other commands from changing the data.
2224 2224 The command will wait until an interruption (SIGINT, SIGTERM, ...) occurs.
2225 2225 The set locks are removed when the command exits.
2226 2226
2227 2227 Returns 0 if no locks are held.
2228 2228
2229 2229 """
2230 2230
2231 2231 if opts.get('force_free_lock'):
2232 2232 repo.svfs.tryunlink(b'lock')
2233 2233 if opts.get('force_free_wlock'):
2234 2234 repo.vfs.tryunlink(b'wlock')
2235 2235 if opts.get('force_free_lock') or opts.get('force_free_wlock'):
2236 2236 return 0
2237 2237
2238 2238 locks = []
2239 2239 try:
2240 2240 if opts.get('set_wlock'):
2241 2241 try:
2242 2242 locks.append(repo.wlock(False))
2243 2243 except error.LockHeld:
2244 2244 raise error.Abort(_(b'wlock is already held'))
2245 2245 if opts.get('set_lock'):
2246 2246 try:
2247 2247 locks.append(repo.lock(False))
2248 2248 except error.LockHeld:
2249 2249 raise error.Abort(_(b'lock is already held'))
2250 2250 if len(locks):
2251 2251 try:
2252 2252 if ui.interactive():
2253 2253 prompt = _(b"ready to release the lock (y)? $$ &Yes")
2254 2254 ui.promptchoice(prompt)
2255 2255 else:
2256 2256 msg = b"%d locks held, waiting for signal\n"
2257 2257 msg %= len(locks)
2258 2258 ui.status(msg)
2259 2259 while True: # XXX wait for a signal
2260 2260 time.sleep(0.1)
2261 2261 except KeyboardInterrupt:
2262 2262 msg = b"signal-received releasing locks\n"
2263 2263 ui.status(msg)
2264 2264 return 0
2265 2265 finally:
2266 2266 release(*locks)
2267 2267
2268 2268 now = time.time()
2269 2269 held = 0
2270 2270
2271 2271 def report(vfs, name, method):
2272 2272 # this causes stale locks to get reaped for more accurate reporting
2273 2273 try:
2274 2274 l = method(False)
2275 2275 except error.LockHeld:
2276 2276 l = None
2277 2277
2278 2278 if l:
2279 2279 l.release()
2280 2280 else:
2281 2281 try:
2282 2282 st = vfs.lstat(name)
2283 2283 age = now - st[stat.ST_MTIME]
2284 2284 user = util.username(st.st_uid)
2285 2285 locker = vfs.readlock(name)
2286 2286 if b":" in locker:
2287 2287 host, pid = locker.split(b':')
2288 2288 if host == socket.gethostname():
2289 2289 locker = b'user %s, process %s' % (user or b'None', pid)
2290 2290 else:
2291 2291 locker = b'user %s, process %s, host %s' % (
2292 2292 user or b'None',
2293 2293 pid,
2294 2294 host,
2295 2295 )
2296 2296 ui.writenoi18n(b"%-6s %s (%ds)\n" % (name + b":", locker, age))
2297 2297 return 1
2298 2298 except FileNotFoundError:
2299 2299 pass
2300 2300
2301 2301 ui.writenoi18n(b"%-6s free\n" % (name + b":"))
2302 2302 return 0
2303 2303
2304 2304 held += report(repo.svfs, b"lock", repo.lock)
2305 2305 held += report(repo.vfs, b"wlock", repo.wlock)
2306 2306
2307 2307 return held
2308 2308
2309 2309
2310 2310 @command(
2311 2311 b'debugmanifestfulltextcache',
2312 2312 [
2313 2313 (b'', b'clear', False, _(b'clear the cache')),
2314 2314 (
2315 2315 b'a',
2316 2316 b'add',
2317 2317 [],
2318 2318 _(b'add the given manifest nodes to the cache'),
2319 2319 _(b'NODE'),
2320 2320 ),
2321 2321 ],
2322 2322 b'',
2323 2323 )
2324 2324 def debugmanifestfulltextcache(ui, repo, add=(), **opts):
2325 2325 """show, clear or amend the contents of the manifest fulltext cache"""
2326 2326
2327 2327 def getcache():
2328 2328 r = repo.manifestlog.getstorage(b'')
2329 2329 try:
2330 2330 return r._fulltextcache
2331 2331 except AttributeError:
2332 2332 msg = _(
2333 2333 b"Current revlog implementation doesn't appear to have a "
2334 2334 b"manifest fulltext cache\n"
2335 2335 )
2336 2336 raise error.Abort(msg)
2337 2337
2338 2338 if opts.get('clear'):
2339 2339 with repo.wlock():
2340 2340 cache = getcache()
2341 2341 cache.clear(clear_persisted_data=True)
2342 2342 return
2343 2343
2344 2344 if add:
2345 2345 with repo.wlock():
2346 2346 m = repo.manifestlog
2347 2347 store = m.getstorage(b'')
2348 2348 for n in add:
2349 2349 try:
2350 2350 manifest = m[store.lookup(n)]
2351 2351 except error.LookupError as e:
2352 2352 raise error.Abort(
2353 2353 bytes(e), hint=b"Check your manifest node id"
2354 2354 )
2355 2355 manifest.read() # stores revisision in cache too
2356 2356 return
2357 2357
2358 2358 cache = getcache()
2359 2359 if not len(cache):
2360 2360 ui.write(_(b'cache empty\n'))
2361 2361 else:
2362 2362 ui.write(
2363 2363 _(
2364 2364 b'cache contains %d manifest entries, in order of most to '
2365 2365 b'least recent:\n'
2366 2366 )
2367 2367 % (len(cache),)
2368 2368 )
2369 2369 totalsize = 0
2370 2370 for nodeid in cache:
2371 2371 # Use cache.get to not update the LRU order
2372 2372 data = cache.peek(nodeid)
2373 2373 size = len(data)
2374 2374 totalsize += size + 24 # 20 bytes nodeid, 4 bytes size
2375 2375 ui.write(
2376 2376 _(b'id: %s, size %s\n') % (hex(nodeid), util.bytecount(size))
2377 2377 )
2378 2378 ondisk = cache._opener.stat(b'manifestfulltextcache').st_size
2379 2379 ui.write(
2380 2380 _(b'total cache data size %s, on-disk %s\n')
2381 2381 % (util.bytecount(totalsize), util.bytecount(ondisk))
2382 2382 )
2383 2383
2384 2384
2385 2385 @command(b'debugmergestate', [] + cmdutil.templateopts, b'')
2386 2386 def debugmergestate(ui, repo, *args, **opts):
2387 2387 """print merge state
2388 2388
2389 2389 Use --verbose to print out information about whether v1 or v2 merge state
2390 2390 was chosen."""
2391 2391
2392 2392 if ui.verbose:
2393 2393 ms = mergestatemod.mergestate(repo)
2394 2394
2395 2395 # sort so that reasonable information is on top
2396 2396 v1records = ms._readrecordsv1()
2397 2397 v2records = ms._readrecordsv2()
2398 2398
2399 2399 if not v1records and not v2records:
2400 2400 pass
2401 2401 elif not v2records:
2402 2402 ui.writenoi18n(b'no version 2 merge state\n')
2403 2403 elif ms._v1v2match(v1records, v2records):
2404 2404 ui.writenoi18n(b'v1 and v2 states match: using v2\n')
2405 2405 else:
2406 2406 ui.writenoi18n(b'v1 and v2 states mismatch: using v1\n')
2407 2407
2408 2408 if not opts['template']:
2409 2409 opts['template'] = (
2410 2410 b'{if(commits, "", "no merge state found\n")}'
2411 2411 b'{commits % "{name}{if(label, " ({label})")}: {node}\n"}'
2412 2412 b'{files % "file: {path} (state \\"{state}\\")\n'
2413 2413 b'{if(local_path, "'
2414 2414 b' local path: {local_path} (hash {local_key}, flags \\"{local_flags}\\")\n'
2415 2415 b' ancestor path: {ancestor_path} (node {ancestor_node})\n'
2416 2416 b' other path: {other_path} (node {other_node})\n'
2417 2417 b'")}'
2418 2418 b'{if(rename_side, "'
2419 2419 b' rename side: {rename_side}\n'
2420 2420 b' renamed path: {renamed_path}\n'
2421 2421 b'")}'
2422 2422 b'{extras % " extra: {key} = {value}\n"}'
2423 2423 b'"}'
2424 2424 b'{extras % "extra: {file} ({key} = {value})\n"}'
2425 2425 )
2426 2426
2427 2427 ms = mergestatemod.mergestate.read(repo)
2428 2428
2429 2429 fm = ui.formatter(b'debugmergestate', pycompat.byteskwargs(opts))
2430 2430 fm.startitem()
2431 2431
2432 2432 fm_commits = fm.nested(b'commits')
2433 2433 if ms.active():
2434 2434 for name, node, label_index in (
2435 2435 (b'local', ms.local, 0),
2436 2436 (b'other', ms.other, 1),
2437 2437 ):
2438 2438 fm_commits.startitem()
2439 2439 fm_commits.data(name=name)
2440 2440 fm_commits.data(node=hex(node))
2441 2441 if ms._labels and len(ms._labels) > label_index:
2442 2442 fm_commits.data(label=ms._labels[label_index])
2443 2443 fm_commits.end()
2444 2444
2445 2445 fm_files = fm.nested(b'files')
2446 2446 if ms.active():
2447 2447 for f in ms:
2448 2448 fm_files.startitem()
2449 2449 fm_files.data(path=f)
2450 2450 state = ms._state[f]
2451 2451 fm_files.data(state=state[0])
2452 2452 if state[0] in (
2453 2453 mergestatemod.MERGE_RECORD_UNRESOLVED,
2454 2454 mergestatemod.MERGE_RECORD_RESOLVED,
2455 2455 ):
2456 2456 fm_files.data(local_key=state[1])
2457 2457 fm_files.data(local_path=state[2])
2458 2458 fm_files.data(ancestor_path=state[3])
2459 2459 fm_files.data(ancestor_node=state[4])
2460 2460 fm_files.data(other_path=state[5])
2461 2461 fm_files.data(other_node=state[6])
2462 2462 fm_files.data(local_flags=state[7])
2463 2463 elif state[0] in (
2464 2464 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
2465 2465 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
2466 2466 ):
2467 2467 fm_files.data(renamed_path=state[1])
2468 2468 fm_files.data(rename_side=state[2])
2469 2469 fm_extras = fm_files.nested(b'extras')
2470 2470 for k, v in sorted(ms.extras(f).items()):
2471 2471 fm_extras.startitem()
2472 2472 fm_extras.data(key=k)
2473 2473 fm_extras.data(value=v)
2474 2474 fm_extras.end()
2475 2475
2476 2476 fm_files.end()
2477 2477
2478 2478 fm_extras = fm.nested(b'extras')
2479 2479 for f, d in sorted(ms.allextras().items()):
2480 2480 if f in ms:
2481 2481 # If file is in mergestate, we have already processed it's extras
2482 2482 continue
2483 2483 for k, v in d.items():
2484 2484 fm_extras.startitem()
2485 2485 fm_extras.data(file=f)
2486 2486 fm_extras.data(key=k)
2487 2487 fm_extras.data(value=v)
2488 2488 fm_extras.end()
2489 2489
2490 2490 fm.end()
2491 2491
2492 2492
2493 2493 @command(b'debugnamecomplete', [], _(b'NAME...'))
2494 2494 def debugnamecomplete(ui, repo, *args):
2495 2495 '''complete "names" - tags, open branch names, bookmark names'''
2496 2496
2497 2497 names = set()
2498 2498 # since we previously only listed open branches, we will handle that
2499 2499 # specially (after this for loop)
2500 2500 for name, ns in repo.names.items():
2501 2501 if name != b'branches':
2502 2502 names.update(ns.listnames(repo))
2503 2503 names.update(
2504 2504 tag
2505 2505 for (tag, heads, tip, closed) in repo.branchmap().iterbranches()
2506 2506 if not closed
2507 2507 )
2508 2508 completions = set()
2509 2509 if not args:
2510 2510 args = [b'']
2511 2511 for a in args:
2512 2512 completions.update(n for n in names if n.startswith(a))
2513 2513 ui.write(b'\n'.join(sorted(completions)))
2514 2514 ui.write(b'\n')
2515 2515
2516 2516
2517 2517 @command(
2518 2518 b'debugnodemap',
2519 2519 (
2520 2520 cmdutil.debugrevlogopts
2521 2521 + [
2522 2522 (
2523 2523 b'',
2524 2524 b'dump-new',
2525 2525 False,
2526 2526 _(b'write a (new) persistent binary nodemap on stdout'),
2527 2527 ),
2528 2528 (b'', b'dump-disk', False, _(b'dump on-disk data on stdout')),
2529 2529 (
2530 2530 b'',
2531 2531 b'check',
2532 2532 False,
2533 2533 _(b'check that the data on disk data are correct.'),
2534 2534 ),
2535 2535 (
2536 2536 b'',
2537 2537 b'metadata',
2538 2538 False,
2539 2539 _(b'display the on disk meta data for the nodemap'),
2540 2540 ),
2541 2541 ]
2542 2542 ),
2543 2543 _(b'-c|-m|FILE'),
2544 2544 )
2545 2545 def debugnodemap(ui, repo, file_=None, **opts):
2546 2546 """write and inspect on disk nodemap"""
2547 2547 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
2548 2548 if file_ is not None:
2549 2549 raise error.InputError(
2550 2550 _(b'cannot specify a file with other arguments')
2551 2551 )
2552 2552 elif file_ is None:
2553 2553 opts['changelog'] = True
2554 2554 r = cmdutil.openstorage(
2555 2555 repo.unfiltered(), b'debugnodemap', file_, pycompat.byteskwargs(opts)
2556 2556 )
2557 2557 if isinstance(r, (manifest.manifestrevlog, filelog.filelog)):
2558 2558 r = r._revlog
2559 2559 if opts['dump_new']:
2560 2560 if hasattr(r.index, "nodemap_data_all"):
2561 2561 data = r.index.nodemap_data_all()
2562 2562 else:
2563 2563 data = nodemap.persistent_data(r.index)
2564 2564 ui.write(data)
2565 2565 elif opts['dump_disk']:
2566 2566 nm_data = nodemap.persisted_data(r)
2567 2567 if nm_data is not None:
2568 2568 docket, data = nm_data
2569 2569 ui.write(data[:])
2570 2570 elif opts['check']:
2571 2571 nm_data = nodemap.persisted_data(r)
2572 2572 if nm_data is not None:
2573 2573 docket, data = nm_data
2574 2574 return nodemap.check_data(ui, r.index, data)
2575 2575 elif opts['metadata']:
2576 2576 nm_data = nodemap.persisted_data(r)
2577 2577 if nm_data is not None:
2578 2578 docket, data = nm_data
2579 2579 ui.write((b"uid: %s\n") % docket.uid)
2580 2580 ui.write((b"tip-rev: %d\n") % docket.tip_rev)
2581 2581 ui.write((b"tip-node: %s\n") % hex(docket.tip_node))
2582 2582 ui.write((b"data-length: %d\n") % docket.data_length)
2583 2583 ui.write((b"data-unused: %d\n") % docket.data_unused)
2584 2584 unused_perc = docket.data_unused * 100.0 / docket.data_length
2585 2585 ui.write((b"data-unused: %2.3f%%\n") % unused_perc)
2586 2586
2587 2587
2588 2588 @command(
2589 2589 b'debugobsolete',
2590 2590 [
2591 2591 (b'', b'flags', 0, _(b'markers flag')),
2592 2592 (
2593 2593 b'',
2594 2594 b'record-parents',
2595 2595 False,
2596 2596 _(b'record parent information for the precursor'),
2597 2597 ),
2598 2598 (b'r', b'rev', [], _(b'display markers relevant to REV')),
2599 2599 (
2600 2600 b'',
2601 2601 b'exclusive',
2602 2602 False,
2603 2603 _(b'restrict display to markers only relevant to REV'),
2604 2604 ),
2605 2605 (b'', b'index', False, _(b'display index of the marker')),
2606 2606 (b'', b'delete', [], _(b'delete markers specified by indices')),
2607 2607 ]
2608 2608 + cmdutil.commitopts2
2609 2609 + cmdutil.formatteropts,
2610 2610 _(b'[OBSOLETED [REPLACEMENT ...]]'),
2611 2611 )
2612 2612 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2613 2613 """create arbitrary obsolete marker
2614 2614
2615 2615 With no arguments, displays the list of obsolescence markers."""
2616 2616
2617 2617 def parsenodeid(s):
2618 2618 try:
2619 2619 # We do not use revsingle/revrange functions here to accept
2620 2620 # arbitrary node identifiers, possibly not present in the
2621 2621 # local repository.
2622 2622 n = bin(s)
2623 2623 if len(n) != repo.nodeconstants.nodelen:
2624 2624 raise ValueError
2625 2625 return n
2626 2626 except ValueError:
2627 2627 raise error.InputError(
2628 2628 b'changeset references must be full hexadecimal '
2629 2629 b'node identifiers'
2630 2630 )
2631 2631
2632 2632 if opts.get('delete'):
2633 2633 indices = []
2634 2634 for v in opts.get('delete'):
2635 2635 try:
2636 2636 indices.append(int(v))
2637 2637 except ValueError:
2638 2638 raise error.InputError(
2639 2639 _(b'invalid index value: %r') % v,
2640 2640 hint=_(b'use integers for indices'),
2641 2641 )
2642 2642
2643 2643 if repo.currenttransaction():
2644 2644 raise error.Abort(
2645 2645 _(b'cannot delete obsmarkers in the middle of transaction.')
2646 2646 )
2647 2647
2648 2648 with repo.lock():
2649 2649 n = repair.deleteobsmarkers(repo.obsstore, indices)
2650 2650 ui.write(_(b'deleted %i obsolescence markers\n') % n)
2651 2651
2652 2652 return
2653 2653
2654 2654 if precursor is not None:
2655 2655 if opts['rev']:
2656 2656 raise error.InputError(
2657 2657 b'cannot select revision when creating marker'
2658 2658 )
2659 2659 metadata = {}
2660 2660 metadata[b'user'] = encoding.fromlocal(opts['user'] or ui.username())
2661 2661 succs = tuple(parsenodeid(succ) for succ in successors)
2662 2662 l = repo.lock()
2663 2663 try:
2664 2664 tr = repo.transaction(b'debugobsolete')
2665 2665 try:
2666 2666 date = opts.get('date')
2667 2667 if date:
2668 2668 date = dateutil.parsedate(date)
2669 2669 else:
2670 2670 date = None
2671 2671 prec = parsenodeid(precursor)
2672 2672 parents = None
2673 2673 if opts['record_parents']:
2674 2674 if prec not in repo.unfiltered():
2675 2675 raise error.Abort(
2676 2676 b'cannot used --record-parents on '
2677 2677 b'unknown changesets'
2678 2678 )
2679 2679 parents = repo.unfiltered()[prec].parents()
2680 2680 parents = tuple(p.node() for p in parents)
2681 2681 repo.obsstore.create(
2682 2682 tr,
2683 2683 prec,
2684 2684 succs,
2685 2685 opts['flags'],
2686 2686 parents=parents,
2687 2687 date=date,
2688 2688 metadata=metadata,
2689 2689 ui=ui,
2690 2690 )
2691 2691 tr.close()
2692 2692 except ValueError as exc:
2693 2693 raise error.Abort(
2694 2694 _(b'bad obsmarker input: %s') % stringutil.forcebytestr(exc)
2695 2695 )
2696 2696 finally:
2697 2697 tr.release()
2698 2698 finally:
2699 2699 l.release()
2700 2700 else:
2701 2701 if opts['rev']:
2702 2702 revs = logcmdutil.revrange(repo, opts['rev'])
2703 2703 nodes = [repo[r].node() for r in revs]
2704 2704 markers = list(
2705 2705 obsutil.getmarkers(
2706 2706 repo, nodes=nodes, exclusive=opts['exclusive']
2707 2707 )
2708 2708 )
2709 2709 markers.sort(key=lambda x: x._data)
2710 2710 else:
2711 2711 markers = obsutil.getmarkers(repo)
2712 2712
2713 2713 markerstoiter = markers
2714 2714 isrelevant = lambda m: True
2715 2715 if opts.get('rev') and opts.get('index'):
2716 2716 markerstoiter = obsutil.getmarkers(repo)
2717 2717 markerset = set(markers)
2718 2718 isrelevant = lambda m: m in markerset
2719 2719
2720 2720 fm = ui.formatter(b'debugobsolete', pycompat.byteskwargs(opts))
2721 2721 for i, m in enumerate(markerstoiter):
2722 2722 if not isrelevant(m):
2723 2723 # marker can be irrelevant when we're iterating over a set
2724 2724 # of markers (markerstoiter) which is bigger than the set
2725 2725 # of markers we want to display (markers)
2726 2726 # this can happen if both --index and --rev options are
2727 2727 # provided and thus we need to iterate over all of the markers
2728 2728 # to get the correct indices, but only display the ones that
2729 2729 # are relevant to --rev value
2730 2730 continue
2731 2731 fm.startitem()
2732 2732 ind = i if opts.get('index') else None
2733 2733 cmdutil.showmarker(fm, m, index=ind)
2734 2734 fm.end()
2735 2735
2736 2736
2737 2737 @command(
2738 2738 b'debugp1copies',
2739 2739 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
2740 2740 _(b'[-r REV]'),
2741 2741 )
2742 2742 def debugp1copies(ui, repo, **opts):
2743 2743 """dump copy information compared to p1"""
2744 2744
2745 2745 ctx = scmutil.revsingle(repo, opts.get('rev'), default=None)
2746 2746 for dst, src in ctx.p1copies().items():
2747 2747 ui.write(b'%s -> %s\n' % (src, dst))
2748 2748
2749 2749
2750 2750 @command(
2751 2751 b'debugp2copies',
2752 2752 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
2753 2753 _(b'[-r REV]'),
2754 2754 )
2755 2755 def debugp2copies(ui, repo, **opts):
2756 2756 """dump copy information compared to p2"""
2757 2757
2758 2758 ctx = scmutil.revsingle(repo, opts.get('rev'), default=None)
2759 2759 for dst, src in ctx.p2copies().items():
2760 2760 ui.write(b'%s -> %s\n' % (src, dst))
2761 2761
2762 2762
2763 2763 @command(
2764 2764 b'debugpathcomplete',
2765 2765 [
2766 2766 (b'f', b'full', None, _(b'complete an entire path')),
2767 2767 (b'n', b'normal', None, _(b'show only normal files')),
2768 2768 (b'a', b'added', None, _(b'show only added files')),
2769 2769 (b'r', b'removed', None, _(b'show only removed files')),
2770 2770 ],
2771 2771 _(b'FILESPEC...'),
2772 2772 )
2773 2773 def debugpathcomplete(ui, repo, *specs, **opts):
2774 2774 """complete part or all of a tracked path
2775 2775
2776 2776 This command supports shells that offer path name completion. It
2777 2777 currently completes only files already known to the dirstate.
2778 2778
2779 2779 Completion extends only to the next path segment unless
2780 2780 --full is specified, in which case entire paths are used."""
2781 2781
2782 2782 def complete(path, acceptable):
2783 2783 dirstate = repo.dirstate
2784 2784 spec = os.path.normpath(os.path.join(encoding.getcwd(), path))
2785 2785 rootdir = repo.root + pycompat.ossep
2786 2786 if spec != repo.root and not spec.startswith(rootdir):
2787 2787 return [], []
2788 2788 if os.path.isdir(spec):
2789 2789 spec += b'/'
2790 2790 spec = spec[len(rootdir) :]
2791 2791 fixpaths = pycompat.ossep != b'/'
2792 2792 if fixpaths:
2793 2793 spec = spec.replace(pycompat.ossep, b'/')
2794 2794 speclen = len(spec)
2795 2795 fullpaths = opts['full']
2796 2796 files, dirs = set(), set()
2797 2797 adddir, addfile = dirs.add, files.add
2798 2798 for f, st in dirstate.items():
2799 2799 if f.startswith(spec) and st.state in acceptable:
2800 2800 if fixpaths:
2801 2801 f = f.replace(b'/', pycompat.ossep)
2802 2802 if fullpaths:
2803 2803 addfile(f)
2804 2804 continue
2805 2805 s = f.find(pycompat.ossep, speclen)
2806 2806 if s >= 0:
2807 2807 adddir(f[:s])
2808 2808 else:
2809 2809 addfile(f)
2810 2810 return files, dirs
2811 2811
2812 2812 acceptable = b''
2813 2813 if opts['normal']:
2814 2814 acceptable += b'nm'
2815 2815 if opts['added']:
2816 2816 acceptable += b'a'
2817 2817 if opts['removed']:
2818 2818 acceptable += b'r'
2819 2819 cwd = repo.getcwd()
2820 2820 if not specs:
2821 2821 specs = [b'.']
2822 2822
2823 2823 files, dirs = set(), set()
2824 2824 for spec in specs:
2825 2825 f, d = complete(spec, acceptable or b'nmar')
2826 2826 files.update(f)
2827 2827 dirs.update(d)
2828 2828 files.update(dirs)
2829 2829 ui.write(b'\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2830 2830 ui.write(b'\n')
2831 2831
2832 2832
2833 2833 @command(
2834 2834 b'debugpathcopies',
2835 2835 cmdutil.walkopts,
2836 2836 b'hg debugpathcopies REV1 REV2 [FILE]',
2837 2837 inferrepo=True,
2838 2838 )
2839 2839 def debugpathcopies(ui, repo, rev1, rev2, *pats, **opts):
2840 2840 """show copies between two revisions"""
2841 2841 ctx1 = scmutil.revsingle(repo, rev1)
2842 2842 ctx2 = scmutil.revsingle(repo, rev2)
2843 2843 m = scmutil.match(ctx1, pats, opts)
2844 2844 for dst, src in sorted(copies.pathcopies(ctx1, ctx2, m).items()):
2845 2845 ui.write(b'%s -> %s\n' % (src, dst))
2846 2846
2847 2847
2848 2848 @command(b'debugpeer', [], _(b'PATH'), norepo=True)
2849 2849 def debugpeer(ui, path):
2850 2850 """establish a connection to a peer repository"""
2851 2851 # Always enable peer request logging. Requires --debug to display
2852 2852 # though.
2853 2853 overrides = {
2854 2854 (b'devel', b'debug.peer-request'): True,
2855 2855 }
2856 2856
2857 2857 with ui.configoverride(overrides):
2858 2858 peer = hg.peer(ui, {}, path)
2859 2859
2860 2860 try:
2861 2861 local = peer.local() is not None
2862 2862 canpush = peer.canpush()
2863 2863
2864 2864 ui.write(_(b'url: %s\n') % peer.url())
2865 2865 ui.write(_(b'local: %s\n') % (_(b'yes') if local else _(b'no')))
2866 2866 ui.write(
2867 2867 _(b'pushable: %s\n') % (_(b'yes') if canpush else _(b'no'))
2868 2868 )
2869 2869 finally:
2870 2870 peer.close()
2871 2871
2872 2872
2873 2873 @command(
2874 2874 b'debugpickmergetool',
2875 2875 [
2876 2876 (b'r', b'rev', b'', _(b'check for files in this revision'), _(b'REV')),
2877 2877 (b'', b'changedelete', None, _(b'emulate merging change and delete')),
2878 2878 ]
2879 2879 + cmdutil.walkopts
2880 2880 + cmdutil.mergetoolopts,
2881 2881 _(b'[PATTERN]...'),
2882 2882 inferrepo=True,
2883 2883 )
2884 2884 def debugpickmergetool(ui, repo, *pats, **opts):
2885 2885 """examine which merge tool is chosen for specified file
2886 2886
2887 2887 As described in :hg:`help merge-tools`, Mercurial examines
2888 2888 configurations below in this order to decide which merge tool is
2889 2889 chosen for specified file.
2890 2890
2891 2891 1. ``--tool`` option
2892 2892 2. ``HGMERGE`` environment variable
2893 2893 3. configurations in ``merge-patterns`` section
2894 2894 4. configuration of ``ui.merge``
2895 2895 5. configurations in ``merge-tools`` section
2896 2896 6. ``hgmerge`` tool (for historical reason only)
2897 2897 7. default tool for fallback (``:merge`` or ``:prompt``)
2898 2898
2899 2899 This command writes out examination result in the style below::
2900 2900
2901 2901 FILE = MERGETOOL
2902 2902
2903 2903 By default, all files known in the first parent context of the
2904 2904 working directory are examined. Use file patterns and/or -I/-X
2905 2905 options to limit target files. -r/--rev is also useful to examine
2906 2906 files in another context without actual updating to it.
2907 2907
2908 2908 With --debug, this command shows warning messages while matching
2909 2909 against ``merge-patterns`` and so on, too. It is recommended to
2910 2910 use this option with explicit file patterns and/or -I/-X options,
2911 2911 because this option increases amount of output per file according
2912 2912 to configurations in hgrc.
2913 2913
2914 2914 With -v/--verbose, this command shows configurations below at
2915 2915 first (only if specified).
2916 2916
2917 2917 - ``--tool`` option
2918 2918 - ``HGMERGE`` environment variable
2919 2919 - configuration of ``ui.merge``
2920 2920
2921 2921 If merge tool is chosen before matching against
2922 2922 ``merge-patterns``, this command can't show any helpful
2923 2923 information, even with --debug. In such case, information above is
2924 2924 useful to know why a merge tool is chosen.
2925 2925 """
2926 2926 overrides = {}
2927 2927 if opts['tool']:
2928 2928 overrides[(b'ui', b'forcemerge')] = opts['tool']
2929 2929 ui.notenoi18n(b'with --tool %r\n' % (pycompat.bytestr(opts['tool'])))
2930 2930
2931 2931 with ui.configoverride(overrides, b'debugmergepatterns'):
2932 2932 hgmerge = encoding.environ.get(b"HGMERGE")
2933 2933 if hgmerge is not None:
2934 2934 ui.notenoi18n(b'with HGMERGE=%r\n' % (pycompat.bytestr(hgmerge)))
2935 2935 uimerge = ui.config(b"ui", b"merge")
2936 2936 if uimerge:
2937 2937 ui.notenoi18n(b'with ui.merge=%r\n' % (pycompat.bytestr(uimerge)))
2938 2938
2939 2939 ctx = scmutil.revsingle(repo, opts.get('rev'))
2940 2940 m = scmutil.match(ctx, pats, pycompat.byteskwargs(opts))
2941 2941 changedelete = opts['changedelete']
2942 2942 for path in ctx.walk(m):
2943 2943 fctx = ctx[path]
2944 2944 with ui.silent(
2945 2945 error=True
2946 2946 ) if not ui.debugflag else util.nullcontextmanager():
2947 2947 tool, toolpath = filemerge._picktool(
2948 2948 repo,
2949 2949 ui,
2950 2950 path,
2951 2951 fctx.isbinary(),
2952 2952 b'l' in fctx.flags(),
2953 2953 changedelete,
2954 2954 )
2955 2955 ui.write(b'%s = %s\n' % (path, tool))
2956 2956
2957 2957
2958 2958 @command(b'debugpushkey', [], _(b'REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2959 2959 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2960 2960 """access the pushkey key/value protocol
2961 2961
2962 2962 With two args, list the keys in the given namespace.
2963 2963
2964 2964 With five args, set a key to new if it currently is set to old.
2965 2965 Reports success or failure.
2966 2966 """
2967 2967
2968 2968 target = hg.peer(ui, {}, repopath)
2969 2969 try:
2970 2970 if keyinfo:
2971 2971 key, old, new = keyinfo
2972 2972 with target.commandexecutor() as e:
2973 2973 r = e.callcommand(
2974 2974 b'pushkey',
2975 2975 {
2976 2976 b'namespace': namespace,
2977 2977 b'key': key,
2978 2978 b'old': old,
2979 2979 b'new': new,
2980 2980 },
2981 2981 ).result()
2982 2982
2983 2983 ui.status(pycompat.bytestr(r) + b'\n')
2984 2984 return not r
2985 2985 else:
2986 2986 for k, v in sorted(target.listkeys(namespace).items()):
2987 2987 ui.write(
2988 2988 b"%s\t%s\n"
2989 2989 % (stringutil.escapestr(k), stringutil.escapestr(v))
2990 2990 )
2991 2991 finally:
2992 2992 target.close()
2993 2993
2994 2994
2995 2995 @command(b'debugpvec', [], _(b'A B'))
2996 2996 def debugpvec(ui, repo, a, b=None):
2997 2997 ca = scmutil.revsingle(repo, a)
2998 2998 cb = scmutil.revsingle(repo, b)
2999 2999 pa = pvec.ctxpvec(ca)
3000 3000 pb = pvec.ctxpvec(cb)
3001 3001 if pa == pb:
3002 3002 rel = b"="
3003 3003 elif pa > pb:
3004 3004 rel = b">"
3005 3005 elif pa < pb:
3006 3006 rel = b"<"
3007 3007 elif pa | pb:
3008 3008 rel = b"|"
3009 3009 ui.write(_(b"a: %s\n") % pa)
3010 3010 ui.write(_(b"b: %s\n") % pb)
3011 3011 ui.write(_(b"depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3012 3012 ui.write(
3013 3013 _(b"delta: %d hdist: %d distance: %d relation: %s\n")
3014 3014 % (
3015 3015 abs(pa._depth - pb._depth),
3016 3016 pvec._hamming(pa._vec, pb._vec),
3017 3017 pa.distance(pb),
3018 3018 rel,
3019 3019 )
3020 3020 )
3021 3021
3022 3022
3023 3023 @command(
3024 3024 b'debugrebuilddirstate|debugrebuildstate',
3025 3025 [
3026 3026 (b'r', b'rev', b'', _(b'revision to rebuild to'), _(b'REV')),
3027 3027 (
3028 3028 b'',
3029 3029 b'minimal',
3030 3030 None,
3031 3031 _(
3032 3032 b'only rebuild files that are inconsistent with '
3033 3033 b'the working copy parent'
3034 3034 ),
3035 3035 ),
3036 3036 ],
3037 3037 _(b'[-r REV]'),
3038 3038 )
3039 3039 def debugrebuilddirstate(ui, repo, rev, **opts):
3040 3040 """rebuild the dirstate as it would look like for the given revision
3041 3041
3042 3042 If no revision is specified the first current parent will be used.
3043 3043
3044 3044 The dirstate will be set to the files of the given revision.
3045 3045 The actual working directory content or existing dirstate
3046 3046 information such as adds or removes is not considered.
3047 3047
3048 3048 ``minimal`` will only rebuild the dirstate status for files that claim to be
3049 3049 tracked but are not in the parent manifest, or that exist in the parent
3050 3050 manifest but are not in the dirstate. It will not change adds, removes, or
3051 3051 modified files that are in the working copy parent.
3052 3052
3053 3053 One use of this command is to make the next :hg:`status` invocation
3054 3054 check the actual file content.
3055 3055 """
3056 3056 ctx = scmutil.revsingle(repo, rev)
3057 3057 with repo.wlock():
3058 3058 if repo.currenttransaction() is not None:
3059 3059 msg = b'rebuild the dirstate outside of a transaction'
3060 3060 raise error.ProgrammingError(msg)
3061 3061 dirstate = repo.dirstate
3062 3062 changedfiles = None
3063 3063 # See command doc for what minimal does.
3064 3064 if opts.get('minimal'):
3065 3065 manifestfiles = set(ctx.manifest().keys())
3066 3066 dirstatefiles = set(dirstate)
3067 3067 manifestonly = manifestfiles - dirstatefiles
3068 3068 dsonly = dirstatefiles - manifestfiles
3069 3069 dsnotadded = {f for f in dsonly if not dirstate.get_entry(f).added}
3070 3070 changedfiles = manifestonly | dsnotadded
3071 3071
3072 3072 with dirstate.changing_parents(repo):
3073 3073 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3074 3074
3075 3075
3076 3076 @command(
3077 3077 b'debugrebuildfncache',
3078 3078 [
3079 3079 (
3080 3080 b'',
3081 3081 b'only-data',
3082 3082 False,
3083 3083 _(b'only look for wrong .d files (much faster)'),
3084 3084 )
3085 3085 ],
3086 3086 b'',
3087 3087 )
3088 3088 def debugrebuildfncache(ui, repo, **opts):
3089 3089 """rebuild the fncache file"""
3090 3090 repair.rebuildfncache(ui, repo, opts.get("only_data"))
3091 3091
3092 3092
3093 3093 @command(
3094 3094 b'debugrename',
3095 3095 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
3096 3096 _(b'[-r REV] [FILE]...'),
3097 3097 )
3098 3098 def debugrename(ui, repo, *pats, **opts):
3099 3099 """dump rename information"""
3100 3100
3101 3101 ctx = scmutil.revsingle(repo, opts.get('rev'))
3102 3102 m = scmutil.match(ctx, pats, pycompat.byteskwargs(opts))
3103 3103 for abs in ctx.walk(m):
3104 3104 fctx = ctx[abs]
3105 3105 o = fctx.filelog().renamed(fctx.filenode())
3106 3106 rel = repo.pathto(abs)
3107 3107 if o:
3108 3108 ui.write(_(b"%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3109 3109 else:
3110 3110 ui.write(_(b"%s not renamed\n") % rel)
3111 3111
3112 3112
3113 3113 @command(b'debugrequires|debugrequirements', [], b'')
3114 3114 def debugrequirements(ui, repo):
3115 3115 """print the current repo requirements"""
3116 3116 for r in sorted(repo.requirements):
3117 3117 ui.write(b"%s\n" % r)
3118 3118
3119 3119
3120 3120 @command(
3121 3121 b'debugrevlog',
3122 3122 cmdutil.debugrevlogopts + [(b'd', b'dump', False, _(b'dump index data'))],
3123 3123 _(b'-c|-m|FILE'),
3124 3124 optionalrepo=True,
3125 3125 )
3126 3126 def debugrevlog(ui, repo, file_=None, **opts):
3127 3127 """show data and statistics about a revlog"""
3128 3128 r = cmdutil.openrevlog(
3129 3129 repo, b'debugrevlog', file_, pycompat.byteskwargs(opts)
3130 3130 )
3131 3131
3132 3132 if opts.get("dump"):
3133 3133 revlog_debug.dump(ui, r)
3134 3134 else:
3135 3135 revlog_debug.debug_revlog(ui, r)
3136 3136 return 0
3137 3137
3138 3138
3139 3139 @command(
3140 3140 b'debugrevlogindex',
3141 3141 cmdutil.debugrevlogopts
3142 3142 + [(b'f', b'format', 0, _(b'revlog format'), _(b'FORMAT'))],
3143 3143 _(b'[-f FORMAT] -c|-m|FILE'),
3144 3144 optionalrepo=True,
3145 3145 )
3146 3146 def debugrevlogindex(ui, repo, file_=None, **opts):
3147 3147 """dump the contents of a revlog index"""
3148 3148 r = cmdutil.openrevlog(
3149 3149 repo, b'debugrevlogindex', file_, pycompat.byteskwargs(opts)
3150 3150 )
3151 3151 format = opts.get('format', 0)
3152 3152 if format not in (0, 1):
3153 3153 raise error.Abort(_(b"unknown format %d") % format)
3154 3154
3155 3155 if ui.debugflag:
3156 3156 shortfn = hex
3157 3157 else:
3158 3158 shortfn = short
3159 3159
3160 3160 # There might not be anything in r, so have a sane default
3161 3161 idlen = 12
3162 3162 for i in r:
3163 3163 idlen = len(shortfn(r.node(i)))
3164 3164 break
3165 3165
3166 3166 if format == 0:
3167 3167 if ui.verbose:
3168 3168 ui.writenoi18n(
3169 3169 b" rev offset length linkrev %s %s p2\n"
3170 3170 % (b"nodeid".ljust(idlen), b"p1".ljust(idlen))
3171 3171 )
3172 3172 else:
3173 3173 ui.writenoi18n(
3174 3174 b" rev linkrev %s %s p2\n"
3175 3175 % (b"nodeid".ljust(idlen), b"p1".ljust(idlen))
3176 3176 )
3177 3177 elif format == 1:
3178 3178 if ui.verbose:
3179 3179 ui.writenoi18n(
3180 3180 (
3181 3181 b" rev flag offset length size link p1"
3182 3182 b" p2 %s\n"
3183 3183 )
3184 3184 % b"nodeid".rjust(idlen)
3185 3185 )
3186 3186 else:
3187 3187 ui.writenoi18n(
3188 3188 b" rev flag size link p1 p2 %s\n"
3189 3189 % b"nodeid".rjust(idlen)
3190 3190 )
3191 3191
3192 3192 for i in r:
3193 3193 node = r.node(i)
3194 3194 if format == 0:
3195 3195 try:
3196 3196 pp = r.parents(node)
3197 3197 except Exception:
3198 3198 pp = [repo.nullid, repo.nullid]
3199 3199 if ui.verbose:
3200 3200 ui.write(
3201 3201 b"% 6d % 9d % 7d % 7d %s %s %s\n"
3202 3202 % (
3203 3203 i,
3204 3204 r.start(i),
3205 3205 r.length(i),
3206 3206 r.linkrev(i),
3207 3207 shortfn(node),
3208 3208 shortfn(pp[0]),
3209 3209 shortfn(pp[1]),
3210 3210 )
3211 3211 )
3212 3212 else:
3213 3213 ui.write(
3214 3214 b"% 6d % 7d %s %s %s\n"
3215 3215 % (
3216 3216 i,
3217 3217 r.linkrev(i),
3218 3218 shortfn(node),
3219 3219 shortfn(pp[0]),
3220 3220 shortfn(pp[1]),
3221 3221 )
3222 3222 )
3223 3223 elif format == 1:
3224 3224 pr = r.parentrevs(i)
3225 3225 if ui.verbose:
3226 3226 ui.write(
3227 3227 b"% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d %s\n"
3228 3228 % (
3229 3229 i,
3230 3230 r.flags(i),
3231 3231 r.start(i),
3232 3232 r.length(i),
3233 3233 r.rawsize(i),
3234 3234 r.linkrev(i),
3235 3235 pr[0],
3236 3236 pr[1],
3237 3237 shortfn(node),
3238 3238 )
3239 3239 )
3240 3240 else:
3241 3241 ui.write(
3242 3242 b"% 6d %04x % 8d % 6d % 6d % 6d %s\n"
3243 3243 % (
3244 3244 i,
3245 3245 r.flags(i),
3246 3246 r.rawsize(i),
3247 3247 r.linkrev(i),
3248 3248 pr[0],
3249 3249 pr[1],
3250 3250 shortfn(node),
3251 3251 )
3252 3252 )
3253 3253
3254 3254
3255 3255 @command(
3256 3256 b'debugrevspec',
3257 3257 [
3258 3258 (
3259 3259 b'',
3260 3260 b'optimize',
3261 3261 None,
3262 3262 _(b'print parsed tree after optimizing (DEPRECATED)'),
3263 3263 ),
3264 3264 (
3265 3265 b'',
3266 3266 b'show-revs',
3267 3267 True,
3268 3268 _(b'print list of result revisions (default)'),
3269 3269 ),
3270 3270 (
3271 3271 b's',
3272 3272 b'show-set',
3273 3273 None,
3274 3274 _(b'print internal representation of result set'),
3275 3275 ),
3276 3276 (
3277 3277 b'p',
3278 3278 b'show-stage',
3279 3279 [],
3280 3280 _(b'print parsed tree at the given stage'),
3281 3281 _(b'NAME'),
3282 3282 ),
3283 3283 (b'', b'no-optimized', False, _(b'evaluate tree without optimization')),
3284 3284 (b'', b'verify-optimized', False, _(b'verify optimized result')),
3285 3285 ],
3286 3286 b'REVSPEC',
3287 3287 )
3288 3288 def debugrevspec(ui, repo, expr, **opts):
3289 3289 """parse and apply a revision specification
3290 3290
3291 3291 Use -p/--show-stage option to print the parsed tree at the given stages.
3292 3292 Use -p all to print tree at every stage.
3293 3293
3294 3294 Use --no-show-revs option with -s or -p to print only the set
3295 3295 representation or the parsed tree respectively.
3296 3296
3297 3297 Use --verify-optimized to compare the optimized result with the unoptimized
3298 3298 one. Returns 1 if the optimized result differs.
3299 3299 """
3300 3300 aliases = ui.configitems(b'revsetalias')
3301 3301 stages = [
3302 3302 (b'parsed', lambda tree: tree),
3303 3303 (
3304 3304 b'expanded',
3305 3305 lambda tree: revsetlang.expandaliases(tree, aliases, ui.warn),
3306 3306 ),
3307 3307 (b'concatenated', revsetlang.foldconcat),
3308 3308 (b'analyzed', revsetlang.analyze),
3309 3309 (b'optimized', revsetlang.optimize),
3310 3310 ]
3311 3311 if opts['no_optimized']:
3312 3312 stages = stages[:-1]
3313 3313 if opts['verify_optimized'] and opts['no_optimized']:
3314 3314 raise error.Abort(
3315 3315 _(b'cannot use --verify-optimized with --no-optimized')
3316 3316 )
3317 3317 stagenames = {n for n, f in stages}
3318 3318
3319 3319 showalways = set()
3320 3320 showchanged = set()
3321 3321 if ui.verbose and not opts['show_stage']:
3322 3322 # show parsed tree by --verbose (deprecated)
3323 3323 showalways.add(b'parsed')
3324 3324 showchanged.update([b'expanded', b'concatenated'])
3325 3325 if opts['optimize']:
3326 3326 showalways.add(b'optimized')
3327 3327 if opts['show_stage'] and opts['optimize']:
3328 3328 raise error.Abort(_(b'cannot use --optimize with --show-stage'))
3329 3329 if opts['show_stage'] == [b'all']:
3330 3330 showalways.update(stagenames)
3331 3331 else:
3332 3332 for n in opts['show_stage']:
3333 3333 if n not in stagenames:
3334 3334 raise error.Abort(_(b'invalid stage name: %s') % n)
3335 3335 showalways.update(opts['show_stage'])
3336 3336
3337 3337 treebystage = {}
3338 3338 printedtree = None
3339 3339 tree = revsetlang.parse(expr, lookup=revset.lookupfn(repo))
3340 3340 for n, f in stages:
3341 3341 treebystage[n] = tree = f(tree)
3342 3342 if n in showalways or (n in showchanged and tree != printedtree):
3343 3343 if opts['show_stage'] or n != b'parsed':
3344 3344 ui.write(b"* %s:\n" % n)
3345 3345 ui.write(revsetlang.prettyformat(tree), b"\n")
3346 3346 printedtree = tree
3347 3347
3348 3348 if opts['verify_optimized']:
3349 3349 arevs = revset.makematcher(treebystage[b'analyzed'])(repo)
3350 3350 brevs = revset.makematcher(treebystage[b'optimized'])(repo)
3351 3351 if opts['show_set'] or (opts['show_set'] is None and ui.verbose):
3352 3352 ui.writenoi18n(
3353 3353 b"* analyzed set:\n", stringutil.prettyrepr(arevs), b"\n"
3354 3354 )
3355 3355 ui.writenoi18n(
3356 3356 b"* optimized set:\n", stringutil.prettyrepr(brevs), b"\n"
3357 3357 )
3358 3358 arevs = list(arevs)
3359 3359 brevs = list(brevs)
3360 3360 if arevs == brevs:
3361 3361 return 0
3362 3362 ui.writenoi18n(b'--- analyzed\n', label=b'diff.file_a')
3363 3363 ui.writenoi18n(b'+++ optimized\n', label=b'diff.file_b')
3364 3364 sm = difflib.SequenceMatcher(None, arevs, brevs)
3365 3365 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3366 3366 if tag in ('delete', 'replace'):
3367 3367 for c in arevs[alo:ahi]:
3368 3368 ui.write(b'-%d\n' % c, label=b'diff.deleted')
3369 3369 if tag in ('insert', 'replace'):
3370 3370 for c in brevs[blo:bhi]:
3371 3371 ui.write(b'+%d\n' % c, label=b'diff.inserted')
3372 3372 if tag == 'equal':
3373 3373 for c in arevs[alo:ahi]:
3374 3374 ui.write(b' %d\n' % c)
3375 3375 return 1
3376 3376
3377 3377 func = revset.makematcher(tree)
3378 3378 revs = func(repo)
3379 3379 if opts['show_set'] or (opts['show_set'] is None and ui.verbose):
3380 3380 ui.writenoi18n(b"* set:\n", stringutil.prettyrepr(revs), b"\n")
3381 3381 if not opts['show_revs']:
3382 3382 return
3383 3383 for c in revs:
3384 3384 ui.write(b"%d\n" % c)
3385 3385
3386 3386
3387 3387 @command(
3388 3388 b'debugserve',
3389 3389 [
3390 3390 (
3391 3391 b'',
3392 3392 b'sshstdio',
3393 3393 False,
3394 3394 _(b'run an SSH server bound to process handles'),
3395 3395 ),
3396 3396 (b'', b'logiofd', b'', _(b'file descriptor to log server I/O to')),
3397 3397 (b'', b'logiofile', b'', _(b'file to log server I/O to')),
3398 3398 ],
3399 3399 b'',
3400 3400 )
3401 3401 def debugserve(ui, repo, **opts):
3402 3402 """run a server with advanced settings
3403 3403
3404 3404 This command is similar to :hg:`serve`. It exists partially as a
3405 3405 workaround to the fact that ``hg serve --stdio`` must have specific
3406 3406 arguments for security reasons.
3407 3407 """
3408 3408 if not opts['sshstdio']:
3409 3409 raise error.Abort(_(b'only --sshstdio is currently supported'))
3410 3410
3411 3411 logfh = None
3412 3412
3413 3413 if opts['logiofd'] and opts['logiofile']:
3414 3414 raise error.Abort(_(b'cannot use both --logiofd and --logiofile'))
3415 3415
3416 3416 if opts['logiofd']:
3417 3417 # Ideally we would be line buffered. But line buffering in binary
3418 3418 # mode isn't supported and emits a warning in Python 3.8+. Disabling
3419 3419 # buffering could have performance impacts. But since this isn't
3420 3420 # performance critical code, it should be fine.
3421 3421 try:
3422 3422 logfh = os.fdopen(int(opts['logiofd']), 'ab', 0)
3423 3423 except OSError as e:
3424 3424 if e.errno != errno.ESPIPE:
3425 3425 raise
3426 3426 # can't seek a pipe, so `ab` mode fails on py3
3427 3427 logfh = os.fdopen(int(opts['logiofd']), 'wb', 0)
3428 3428 elif opts['logiofile']:
3429 3429 logfh = open(opts['logiofile'], b'ab', 0)
3430 3430
3431 3431 s = wireprotoserver.sshserver(ui, repo, logfh=logfh)
3432 3432 s.serve_forever()
3433 3433
3434 3434
3435 3435 @command(b'debugsetparents', [], _(b'REV1 [REV2]'))
3436 3436 def debugsetparents(ui, repo, rev1, rev2=None):
3437 3437 """manually set the parents of the current working directory (DANGEROUS)
3438 3438
3439 3439 This command is not what you are looking for and should not be used. Using
3440 3440 this command will most certainly results in slight corruption of the file
3441 3441 level histories within your repository. DO NOT USE THIS COMMAND.
3442 3442
3443 3443 The command updates the p1 and p2 fields in the dirstate, without touching
3444 3444 anything else. This useful for writing repository conversion tools, but
3445 3445 should be used with extreme care. For example, neither the working
3446 3446 directory nor the dirstate is updated, so file statuses may be incorrect
3447 3447 after running this command. Use it only if you are one of the few people who
3448 3448 deeply understands both conversion tools and file level histories. If you are
3449 3449 reading this help, you are not one of those people (most of them sailed west
3450 3450 from Mithlond anyway).
3451 3451
3452 3452 So, one more time, DO NOT USE THIS COMMAND.
3453 3453
3454 3454 Returns 0 on success.
3455 3455 """
3456 3456
3457 3457 node1 = scmutil.revsingle(repo, rev1).node()
3458 3458 node2 = scmutil.revsingle(repo, rev2, b'null').node()
3459 3459
3460 3460 with repo.wlock():
3461 3461 repo.setparents(node1, node2)
3462 3462
3463 3463
3464 3464 @command(b'debugsidedata', cmdutil.debugrevlogopts, _(b'-c|-m|FILE REV'))
3465 3465 def debugsidedata(ui, repo, file_, rev=None, **opts):
3466 3466 """dump the side data for a cl/manifest/file revision
3467 3467
3468 3468 Use --verbose to dump the sidedata content."""
3469 3469 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
3470 3470 if rev is not None:
3471 3471 raise error.InputError(
3472 3472 _(b'cannot specify a revision with other arguments')
3473 3473 )
3474 3474 file_, rev = None, file_
3475 3475 elif rev is None:
3476 3476 raise error.InputError(_(b'please specify a revision'))
3477 3477 r = cmdutil.openstorage(
3478 3478 repo, b'debugdata', file_, pycompat.byteskwargs(opts)
3479 3479 )
3480 3480 r = getattr(r, '_revlog', r)
3481 3481 try:
3482 3482 sidedata = r.sidedata(r.lookup(rev))
3483 3483 except KeyError:
3484 3484 raise error.Abort(_(b'invalid revision identifier %s') % rev)
3485 3485 if sidedata:
3486 3486 sidedata = list(sidedata.items())
3487 3487 sidedata.sort()
3488 3488 ui.writenoi18n(b'%d sidedata entries\n' % len(sidedata))
3489 3489 for key, value in sidedata:
3490 3490 ui.writenoi18n(b' entry-%04o size %d\n' % (key, len(value)))
3491 3491 if ui.verbose:
3492 3492 ui.writenoi18n(b' %s\n' % stringutil.pprint(value))
3493 3493
3494 3494
3495 3495 @command(b'debugssl', [], b'[SOURCE]', optionalrepo=True)
3496 3496 def debugssl(ui, repo, source=None, **opts):
3497 3497 """test a secure connection to a server
3498 3498
3499 3499 This builds the certificate chain for the server on Windows, installing the
3500 3500 missing intermediates and trusted root via Windows Update if necessary. It
3501 3501 does nothing on other platforms.
3502 3502
3503 3503 If SOURCE is omitted, the 'default' path will be used. If a URL is given,
3504 3504 that server is used. See :hg:`help urls` for more information.
3505 3505
3506 3506 If the update succeeds, retry the original operation. Otherwise, the cause
3507 3507 of the SSL error is likely another issue.
3508 3508 """
3509 3509 if not pycompat.iswindows:
3510 3510 raise error.Abort(
3511 3511 _(b'certificate chain building is only possible on Windows')
3512 3512 )
3513 3513
3514 3514 if not source:
3515 3515 if not repo:
3516 3516 raise error.Abort(
3517 3517 _(
3518 3518 b"there is no Mercurial repository here, and no "
3519 3519 b"server specified"
3520 3520 )
3521 3521 )
3522 3522 source = b"default"
3523 3523
3524 3524 path = urlutil.get_unique_pull_path_obj(b'debugssl', ui, source)
3525 3525 url = path.url
3526 3526
3527 3527 defaultport = {b'https': 443, b'ssh': 22}
3528 3528 if url.scheme in defaultport:
3529 3529 try:
3530 3530 addr = (url.host, int(url.port or defaultport[url.scheme]))
3531 3531 except ValueError:
3532 3532 raise error.Abort(_(b"malformed port number in URL"))
3533 3533 else:
3534 3534 raise error.Abort(_(b"only https and ssh connections are supported"))
3535 3535
3536 3536 from . import win32
3537 3537
3538 3538 s = ssl.wrap_socket(
3539 3539 socket.socket(),
3540 3540 ssl_version=ssl.PROTOCOL_TLS,
3541 3541 cert_reqs=ssl.CERT_NONE,
3542 3542 ca_certs=None,
3543 3543 )
3544 3544
3545 3545 try:
3546 3546 s.connect(addr)
3547 3547 cert = s.getpeercert(True)
3548 3548
3549 3549 ui.status(_(b'checking the certificate chain for %s\n') % url.host)
3550 3550
3551 3551 complete = win32.checkcertificatechain(cert, build=False)
3552 3552
3553 3553 if not complete:
3554 3554 ui.status(_(b'certificate chain is incomplete, updating... '))
3555 3555
3556 3556 if not win32.checkcertificatechain(cert):
3557 3557 ui.status(_(b'failed.\n'))
3558 3558 else:
3559 3559 ui.status(_(b'done.\n'))
3560 3560 else:
3561 3561 ui.status(_(b'full certificate chain is available\n'))
3562 3562 finally:
3563 3563 s.close()
3564 3564
3565 3565
3566 3566 @command(
3567 3567 b'debug::stable-tail-sort',
3568 3568 [
3569 3569 (
3570 3570 b'T',
3571 3571 b'template',
3572 3572 b'{rev}\n',
3573 3573 _(b'display with template'),
3574 3574 _(b'TEMPLATE'),
3575 3575 ),
3576 3576 ],
3577 3577 b'REV',
3578 3578 )
3579 3579 def debug_stable_tail_sort(ui, repo, revspec, template, **opts):
3580 3580 """display the stable-tail sort of the ancestors of a given node"""
3581 3581 rev = logcmdutil.revsingle(repo, revspec).rev()
3582 3582 cl = repo.changelog
3583 3583
3584 3584 displayer = logcmdutil.maketemplater(ui, repo, template)
3585 3585 sorted_revs = stabletailsort._stable_tail_sort_naive(cl, rev)
3586 3586 for ancestor_rev in sorted_revs:
3587 3587 displayer.show(repo[ancestor_rev])
3588 3588
3589 3589
3590 3590 @command(
3591 3591 b'debug::stable-tail-sort-leaps',
3592 3592 [
3593 3593 (
3594 3594 b'T',
3595 3595 b'template',
3596 3596 b'{rev}',
3597 3597 _(b'display with template'),
3598 3598 _(b'TEMPLATE'),
3599 3599 ),
3600 3600 (b's', b'specific', False, _(b'restrict to specific leaps')),
3601 3601 ],
3602 3602 b'REV',
3603 3603 )
3604 3604 def debug_stable_tail_sort_leaps(ui, repo, rspec, template, specific, **opts):
3605 3605 """display the leaps in the stable-tail sort of a node, one per line"""
3606 3606 rev = logcmdutil.revsingle(repo, rspec).rev()
3607 3607
3608 3608 if specific:
3609 3609 get_leaps = stabletailsort._find_specific_leaps_naive
3610 3610 else:
3611 3611 get_leaps = stabletailsort._find_all_leaps_naive
3612 3612
3613 3613 displayer = logcmdutil.maketemplater(ui, repo, template)
3614 3614 for source, target in get_leaps(repo.changelog, rev):
3615 3615 displayer.show(repo[source])
3616 3616 displayer.show(repo[target])
3617 3617 ui.write(b'\n')
3618 3618
3619 3619
3620 3620 @command(
3621 3621 b"debugbackupbundle",
3622 3622 [
3623 3623 (
3624 3624 b"",
3625 3625 b"recover",
3626 3626 b"",
3627 3627 b"brings the specified changeset back into the repository",
3628 3628 )
3629 3629 ]
3630 3630 + cmdutil.logopts,
3631 3631 _(b"hg debugbackupbundle [--recover HASH]"),
3632 3632 )
3633 3633 def debugbackupbundle(ui, repo, *pats, **opts):
3634 3634 """lists the changesets available in backup bundles
3635 3635
3636 3636 Without any arguments, this command prints a list of the changesets in each
3637 3637 backup bundle.
3638 3638
3639 3639 --recover takes a changeset hash and unbundles the first bundle that
3640 3640 contains that hash, which puts that changeset back in your repository.
3641 3641
3642 3642 --verbose will print the entire commit message and the bundle path for that
3643 3643 backup.
3644 3644 """
3645 3645 backups = list(
3646 3646 filter(
3647 3647 os.path.isfile, glob.glob(repo.vfs.join(b"strip-backup") + b"/*.hg")
3648 3648 )
3649 3649 )
3650 3650 backups.sort(key=lambda x: os.path.getmtime(x), reverse=True)
3651 3651
3652 3652 opts["bundle"] = b""
3653 3653 opts["force"] = None
3654 3654 limit = logcmdutil.getlimit(pycompat.byteskwargs(opts))
3655 3655
3656 3656 def display(other, chlist, displayer):
3657 3657 if opts.get("newest_first"):
3658 3658 chlist.reverse()
3659 3659 count = 0
3660 3660 for n in chlist:
3661 3661 if limit is not None and count >= limit:
3662 3662 break
3663 3663 parents = [
3664 3664 True for p in other.changelog.parents(n) if p != repo.nullid
3665 3665 ]
3666 3666 if opts.get("no_merges") and len(parents) == 2:
3667 3667 continue
3668 3668 count += 1
3669 3669 displayer.show(other[n])
3670 3670
3671 3671 recovernode = opts.get("recover")
3672 3672 if recovernode:
3673 3673 if scmutil.isrevsymbol(repo, recovernode):
3674 3674 ui.warn(_(b"%s already exists in the repo\n") % recovernode)
3675 3675 return
3676 3676 elif backups:
3677 3677 msg = _(
3678 3678 b"Recover changesets using: hg debugbackupbundle --recover "
3679 3679 b"<changeset hash>\n\nAvailable backup changesets:"
3680 3680 )
3681 3681 ui.status(msg, label=b"status.removed")
3682 3682 else:
3683 3683 ui.status(_(b"no backup changesets found\n"))
3684 3684 return
3685 3685
3686 3686 for backup in backups:
3687 3687 # Much of this is copied from the hg incoming logic
3688 3688 source = os.path.relpath(backup, encoding.getcwd())
3689 3689 path = urlutil.get_unique_pull_path_obj(
3690 3690 b'debugbackupbundle',
3691 3691 ui,
3692 3692 source,
3693 3693 )
3694 3694 try:
3695 3695 other = hg.peer(repo, pycompat.byteskwargs(opts), path)
3696 3696 except error.LookupError as ex:
3697 3697 msg = _(b"\nwarning: unable to open bundle %s") % path.loc
3698 3698 hint = _(b"\n(missing parent rev %s)\n") % short(ex.name)
3699 3699 ui.warn(msg, hint=hint)
3700 3700 continue
3701 3701 branches = (path.branch, opts.get('branch', []))
3702 3702 revs, checkout = hg.addbranchrevs(
3703 3703 repo, other, branches, opts.get("rev")
3704 3704 )
3705 3705
3706 3706 if revs:
3707 3707 revs = [other.lookup(rev) for rev in revs]
3708 3708
3709 3709 with ui.silent():
3710 3710 try:
3711 3711 other, chlist, cleanupfn = bundlerepo.getremotechanges(
3712 3712 ui, repo, other, revs, opts["bundle"], opts["force"]
3713 3713 )
3714 3714 except error.LookupError:
3715 3715 continue
3716 3716
3717 3717 try:
3718 3718 if not chlist:
3719 3719 continue
3720 3720 if recovernode:
3721 3721 with repo.lock(), repo.transaction(b"unbundle") as tr:
3722 3722 if scmutil.isrevsymbol(other, recovernode):
3723 3723 ui.status(_(b"Unbundling %s\n") % (recovernode))
3724 3724 f = hg.openpath(ui, path.loc)
3725 3725 gen = exchange.readbundle(ui, f, path.loc)
3726 3726 if isinstance(gen, bundle2.unbundle20):
3727 3727 bundle2.applybundle(
3728 3728 repo,
3729 3729 gen,
3730 3730 tr,
3731 3731 source=b"unbundle",
3732 3732 url=b"bundle:" + path.loc,
3733 3733 )
3734 3734 else:
3735 3735 gen.apply(repo, b"unbundle", b"bundle:" + path.loc)
3736 3736 break
3737 3737 else:
3738 3738 backupdate = encoding.strtolocal(
3739 3739 time.strftime(
3740 3740 "%a %H:%M, %Y-%m-%d",
3741 3741 time.localtime(os.path.getmtime(path.loc)),
3742 3742 )
3743 3743 )
3744 3744 ui.status(b"\n%s\n" % (backupdate.ljust(50)))
3745 3745 if ui.verbose:
3746 3746 ui.status(b"%s%s\n" % (b"bundle:".ljust(13), path.loc))
3747 3747 else:
3748 3748 opts[
3749 3749 "template"
3750 3750 ] = b"{label('status.modified', node|short)} {desc|firstline}\n"
3751 3751 displayer = logcmdutil.changesetdisplayer(
3752 3752 ui, other, pycompat.byteskwargs(opts), False
3753 3753 )
3754 3754 display(other, chlist, displayer)
3755 3755 displayer.close()
3756 3756 finally:
3757 3757 cleanupfn()
3758 3758
3759 3759
3760 3760 @command(
3761 3761 b'debugsub',
3762 3762 [(b'r', b'rev', b'', _(b'revision to check'), _(b'REV'))],
3763 3763 _(b'[-r REV] [REV]'),
3764 3764 )
3765 3765 def debugsub(ui, repo, rev=None):
3766 3766 ctx = scmutil.revsingle(repo, rev, None)
3767 3767 for k, v in sorted(ctx.substate.items()):
3768 3768 ui.writenoi18n(b'path %s\n' % k)
3769 3769 ui.writenoi18n(b' source %s\n' % v[0])
3770 3770 ui.writenoi18n(b' revision %s\n' % v[1])
3771 3771
3772 3772
3773 3773 @command(
3774 3774 b'debugshell',
3775 3775 [
3776 3776 (
3777 3777 b'c',
3778 3778 b'command',
3779 3779 b'',
3780 3780 _(b'program passed in as a string'),
3781 3781 _(b'COMMAND'),
3782 3782 )
3783 3783 ],
3784 3784 _(b'[-c COMMAND]'),
3785 3785 optionalrepo=True,
3786 3786 )
3787 3787 def debugshell(ui, repo, **opts):
3788 3788 """run an interactive Python interpreter
3789 3789
3790 3790 The local namespace is provided with a reference to the ui and
3791 3791 the repo instance (if available).
3792 3792 """
3793 3793 import code
3794 3794
3795 3795 imported_objects = {
3796 3796 'ui': ui,
3797 3797 'repo': repo,
3798 3798 }
3799 3799
3800 3800 # py2exe disables initialization of the site module, which is responsible
3801 3801 # for arranging for ``quit()`` to exit the interpreter. Manually initialize
3802 3802 # the stuff that site normally does here, so that the interpreter can be
3803 3803 # quit in a consistent manner, whether run with pyoxidizer, exewrapper.c,
3804 3804 # py.exe, or py2exe.
3805 3805 if getattr(sys, "frozen", None) == 'console_exe':
3806 3806 try:
3807 3807 import site
3808 3808
3809 3809 site.setcopyright()
3810 3810 site.sethelper()
3811 3811 site.setquit()
3812 3812 except ImportError:
3813 3813 site = None # Keep PyCharm happy
3814 3814
3815 3815 command = opts.get('command')
3816 3816 if command:
3817 3817 compiled = code.compile_command(encoding.strfromlocal(command))
3818 3818 code.InteractiveInterpreter(locals=imported_objects).runcode(compiled)
3819 3819 return
3820 3820
3821 3821 code.interact(local=imported_objects)
3822 3822
3823 3823
3824 3824 @command(
3825 3825 b'debug-revlog-stats',
3826 3826 [
3827 3827 (b'c', b'changelog', None, _(b'Display changelog statistics')),
3828 3828 (b'm', b'manifest', None, _(b'Display manifest statistics')),
3829 3829 (b'f', b'filelogs', None, _(b'Display filelogs statistics')),
3830 3830 ]
3831 3831 + cmdutil.formatteropts,
3832 3832 )
3833 3833 def debug_revlog_stats(ui, repo, **opts):
3834 3834 """display statistics about revlogs in the store"""
3835 3835 changelog = opts["changelog"]
3836 3836 manifest = opts["manifest"]
3837 3837 filelogs = opts["filelogs"]
3838 3838
3839 3839 if changelog is None and manifest is None and filelogs is None:
3840 3840 changelog = True
3841 3841 manifest = True
3842 3842 filelogs = True
3843 3843
3844 3844 repo = repo.unfiltered()
3845 3845 fm = ui.formatter(b'debug-revlog-stats', pycompat.byteskwargs(opts))
3846 3846 revlog_debug.debug_revlog_stats(repo, fm, changelog, manifest, filelogs)
3847 3847 fm.end()
3848 3848
3849 3849
3850 3850 @command(
3851 3851 b'debugsuccessorssets',
3852 3852 [(b'', b'closest', False, _(b'return closest successors sets only'))],
3853 3853 _(b'[REV]'),
3854 3854 )
3855 3855 def debugsuccessorssets(ui, repo, *revs, **opts):
3856 3856 """show set of successors for revision
3857 3857
3858 3858 A successors set of changeset A is a consistent group of revisions that
3859 3859 succeed A. It contains non-obsolete changesets only unless closests
3860 3860 successors set is set.
3861 3861
3862 3862 In most cases a changeset A has a single successors set containing a single
3863 3863 successor (changeset A replaced by A').
3864 3864
3865 3865 A changeset that is made obsolete with no successors are called "pruned".
3866 3866 Such changesets have no successors sets at all.
3867 3867
3868 3868 A changeset that has been "split" will have a successors set containing
3869 3869 more than one successor.
3870 3870
3871 3871 A changeset that has been rewritten in multiple different ways is called
3872 3872 "divergent". Such changesets have multiple successor sets (each of which
3873 3873 may also be split, i.e. have multiple successors).
3874 3874
3875 3875 Results are displayed as follows::
3876 3876
3877 3877 <rev1>
3878 3878 <successors-1A>
3879 3879 <rev2>
3880 3880 <successors-2A>
3881 3881 <successors-2B1> <successors-2B2> <successors-2B3>
3882 3882
3883 3883 Here rev2 has two possible (i.e. divergent) successors sets. The first
3884 3884 holds one element, whereas the second holds three (i.e. the changeset has
3885 3885 been split).
3886 3886 """
3887 3887 # passed to successorssets caching computation from one call to another
3888 3888 cache = {}
3889 3889 ctx2str = bytes
3890 3890 node2str = short
3891 3891 for rev in logcmdutil.revrange(repo, revs):
3892 3892 ctx = repo[rev]
3893 3893 ui.write(b'%s\n' % ctx2str(ctx))
3894 3894 for succsset in obsutil.successorssets(
3895 3895 repo, ctx.node(), closest=opts['closest'], cache=cache
3896 3896 ):
3897 3897 if succsset:
3898 3898 ui.write(b' ')
3899 3899 ui.write(node2str(succsset[0]))
3900 3900 for node in succsset[1:]:
3901 3901 ui.write(b' ')
3902 3902 ui.write(node2str(node))
3903 3903 ui.write(b'\n')
3904 3904
3905 3905
3906 3906 @command(b'debugtagscache', [])
3907 3907 def debugtagscache(ui, repo):
3908 3908 """display the contents of .hg/cache/hgtagsfnodes1"""
3909 3909 cache = tagsmod.hgtagsfnodescache(repo.unfiltered())
3910 3910 flog = repo.file(b'.hgtags')
3911 3911 for r in repo:
3912 3912 node = repo[r].node()
3913 3913 tagsnode = cache.getfnode(node, computemissing=False)
3914 3914 if tagsnode:
3915 3915 tagsnodedisplay = hex(tagsnode)
3916 3916 if not flog.hasnode(tagsnode):
3917 3917 tagsnodedisplay += b' (unknown node)'
3918 3918 elif tagsnode is None:
3919 3919 tagsnodedisplay = b'missing'
3920 3920 else:
3921 3921 tagsnodedisplay = b'invalid'
3922 3922
3923 3923 ui.write(b'%d %s %s\n' % (r, hex(node), tagsnodedisplay))
3924 3924
3925 3925
3926 3926 @command(
3927 3927 b'debugtemplate',
3928 3928 [
3929 3929 (b'r', b'rev', [], _(b'apply template on changesets'), _(b'REV')),
3930 3930 (b'D', b'define', [], _(b'define template keyword'), _(b'KEY=VALUE')),
3931 3931 ],
3932 3932 _(b'[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3933 3933 optionalrepo=True,
3934 3934 )
3935 3935 def debugtemplate(ui, repo, tmpl, **opts):
3936 3936 """parse and apply a template
3937 3937
3938 3938 If -r/--rev is given, the template is processed as a log template and
3939 3939 applied to the given changesets. Otherwise, it is processed as a generic
3940 3940 template.
3941 3941
3942 3942 Use --verbose to print the parsed tree.
3943 3943 """
3944 3944 revs = None
3945 3945 if opts['rev']:
3946 3946 if repo is None:
3947 3947 raise error.RepoError(
3948 3948 _(b'there is no Mercurial repository here (.hg not found)')
3949 3949 )
3950 3950 revs = logcmdutil.revrange(repo, opts['rev'])
3951 3951
3952 3952 props = {}
3953 3953 for d in opts['define']:
3954 3954 try:
3955 3955 k, v = (e.strip() for e in d.split(b'=', 1))
3956 3956 if not k or k == b'ui':
3957 3957 raise ValueError
3958 3958 props[k] = v
3959 3959 except ValueError:
3960 3960 raise error.Abort(_(b'malformed keyword definition: %s') % d)
3961 3961
3962 3962 if ui.verbose:
3963 3963 aliases = ui.configitems(b'templatealias')
3964 3964 tree = templater.parse(tmpl)
3965 3965 ui.note(templater.prettyformat(tree), b'\n')
3966 3966 newtree = templater.expandaliases(tree, aliases)
3967 3967 if newtree != tree:
3968 3968 ui.notenoi18n(
3969 3969 b"* expanded:\n", templater.prettyformat(newtree), b'\n'
3970 3970 )
3971 3971
3972 3972 if revs is None:
3973 3973 tres = formatter.templateresources(ui, repo)
3974 3974 t = formatter.maketemplater(ui, tmpl, resources=tres)
3975 3975 if ui.verbose:
3976 3976 kwds, funcs = t.symbolsuseddefault()
3977 3977 ui.writenoi18n(b"* keywords: %s\n" % b', '.join(sorted(kwds)))
3978 3978 ui.writenoi18n(b"* functions: %s\n" % b', '.join(sorted(funcs)))
3979 3979 ui.write(t.renderdefault(props))
3980 3980 else:
3981 3981 displayer = logcmdutil.maketemplater(ui, repo, tmpl)
3982 3982 if ui.verbose:
3983 3983 kwds, funcs = displayer.t.symbolsuseddefault()
3984 3984 ui.writenoi18n(b"* keywords: %s\n" % b', '.join(sorted(kwds)))
3985 3985 ui.writenoi18n(b"* functions: %s\n" % b', '.join(sorted(funcs)))
3986 3986 for r in revs:
3987 3987 displayer.show(repo[r], **pycompat.strkwargs(props))
3988 3988 displayer.close()
3989 3989
3990 3990
3991 3991 @command(
3992 3992 b'debuguigetpass',
3993 3993 [
3994 3994 (b'p', b'prompt', b'', _(b'prompt text'), _(b'TEXT')),
3995 3995 ],
3996 3996 _(b'[-p TEXT]'),
3997 3997 norepo=True,
3998 3998 )
3999 3999 def debuguigetpass(ui, prompt=b''):
4000 4000 """show prompt to type password"""
4001 4001 r = ui.getpass(prompt)
4002 4002 if r is None:
4003 4003 r = b"<default response>"
4004 4004 ui.writenoi18n(b'response: %s\n' % r)
4005 4005
4006 4006
4007 4007 @command(
4008 4008 b'debuguiprompt',
4009 4009 [
4010 4010 (b'p', b'prompt', b'', _(b'prompt text'), _(b'TEXT')),
4011 4011 ],
4012 4012 _(b'[-p TEXT]'),
4013 4013 norepo=True,
4014 4014 )
4015 4015 def debuguiprompt(ui, prompt=b''):
4016 4016 """show plain prompt"""
4017 4017 r = ui.prompt(prompt)
4018 4018 ui.writenoi18n(b'response: %s\n' % r)
4019 4019
4020 4020
4021 4021 @command(b'debugupdatecaches', [])
4022 4022 def debugupdatecaches(ui, repo, *pats, **opts):
4023 4023 """warm all known caches in the repository"""
4024 4024 with repo.wlock(), repo.lock():
4025 4025 repo.updatecaches(caches=repository.CACHES_ALL)
4026 4026
4027 4027
4028 4028 @command(
4029 4029 b'debugupgraderepo',
4030 4030 [
4031 4031 (
4032 4032 b'o',
4033 4033 b'optimize',
4034 4034 [],
4035 4035 _(b'extra optimization to perform'),
4036 4036 _(b'NAME'),
4037 4037 ),
4038 4038 (b'', b'run', False, _(b'performs an upgrade')),
4039 4039 (b'', b'backup', True, _(b'keep the old repository content around')),
4040 4040 (b'', b'changelog', None, _(b'select the changelog for upgrade')),
4041 4041 (b'', b'manifest', None, _(b'select the manifest for upgrade')),
4042 4042 (b'', b'filelogs', None, _(b'select all filelogs for upgrade')),
4043 4043 ],
4044 4044 )
4045 4045 def debugupgraderepo(ui, repo, run=False, optimize=None, backup=True, **opts):
4046 4046 """upgrade a repository to use different features
4047 4047
4048 4048 If no arguments are specified, the repository is evaluated for upgrade
4049 4049 and a list of problems and potential optimizations is printed.
4050 4050
4051 4051 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
4052 4052 can be influenced via additional arguments. More details will be provided
4053 4053 by the command output when run without ``--run``.
4054 4054
4055 4055 During the upgrade, the repository will be locked and no writes will be
4056 4056 allowed.
4057 4057
4058 4058 At the end of the upgrade, the repository may not be readable while new
4059 4059 repository data is swapped in. This window will be as long as it takes to
4060 4060 rename some directories inside the ``.hg`` directory. On most machines, this
4061 4061 should complete almost instantaneously and the chances of a consumer being
4062 4062 unable to access the repository should be low.
4063 4063
4064 4064 By default, all revlogs will be upgraded. You can restrict this using flags
4065 4065 such as `--manifest`:
4066 4066
4067 4067 * `--manifest`: only optimize the manifest
4068 4068 * `--no-manifest`: optimize all revlog but the manifest
4069 4069 * `--changelog`: optimize the changelog only
4070 4070 * `--no-changelog --no-manifest`: optimize filelogs only
4071 4071 * `--filelogs`: optimize the filelogs only
4072 4072 * `--no-changelog --no-manifest --no-filelogs`: skip all revlog optimizations
4073 4073 """
4074 4074 return upgrade.upgraderepo(
4075 4075 ui, repo, run=run, optimize=set(optimize), backup=backup, **opts
4076 4076 )
4077 4077
4078 4078
4079 4079 @command(
4080 b'debug::unbundle',
4081 [
4082 (
4083 b'u',
4084 b'update',
4085 None,
4086 _(b'update to new branch head if changesets were unbundled'),
4087 )
4088 ],
4089 _(b'[-u] FILE...'),
4090 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4091 )
4092 def debugunbundle(ui, repo, *args, **kwargs):
4093 """same as `hg unbundle`, but pretent to come from a push
4094
4095 This is useful to debug behavior and performance change in this case.
4096 """
4097 from . import commands # avoid cycle
4098
4099 unbundle = cmdutil.findcmd(b'unbundle', commands.table)[1][0]
4100 return unbundle(ui, repo, *args, _unbundle_source=b'push', **kwargs)
4101
4102
4103 @command(
4080 4104 b'debugwalk', cmdutil.walkopts, _(b'[OPTION]... [FILE]...'), inferrepo=True
4081 4105 )
4082 4106 def debugwalk(ui, repo, *pats, **opts):
4083 4107 """show how files match on given patterns"""
4084 4108 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
4085 4109 if ui.verbose:
4086 4110 ui.writenoi18n(b'* matcher:\n', stringutil.prettyrepr(m), b'\n')
4087 4111 items = list(repo[None].walk(m))
4088 4112 if not items:
4089 4113 return
4090 4114 f = lambda fn: fn
4091 4115 if ui.configbool(b'ui', b'slash') and pycompat.ossep != b'/':
4092 4116 f = lambda fn: util.normpath(fn)
4093 4117 fmt = b'f %%-%ds %%-%ds %%s' % (
4094 4118 max([len(abs) for abs in items]),
4095 4119 max([len(repo.pathto(abs)) for abs in items]),
4096 4120 )
4097 4121 for abs in items:
4098 4122 line = fmt % (
4099 4123 abs,
4100 4124 f(repo.pathto(abs)),
4101 4125 m.exact(abs) and b'exact' or b'',
4102 4126 )
4103 4127 ui.write(b"%s\n" % line.rstrip())
4104 4128
4105 4129
4106 4130 @command(b'debugwhyunstable', [], _(b'REV'))
4107 4131 def debugwhyunstable(ui, repo, rev):
4108 4132 """explain instabilities of a changeset"""
4109 4133 for entry in obsutil.whyunstable(repo, scmutil.revsingle(repo, rev)):
4110 4134 dnodes = b''
4111 4135 if entry.get(b'divergentnodes'):
4112 4136 dnodes = (
4113 4137 b' '.join(
4114 4138 b'%s (%s)' % (ctx.hex(), ctx.phasestr())
4115 4139 for ctx in entry[b'divergentnodes']
4116 4140 )
4117 4141 + b' '
4118 4142 )
4119 4143 ui.write(
4120 4144 b'%s: %s%s %s\n'
4121 4145 % (entry[b'instability'], dnodes, entry[b'reason'], entry[b'node'])
4122 4146 )
4123 4147
4124 4148
4125 4149 @command(
4126 4150 b'debugwireargs',
4127 4151 [
4128 4152 (b'', b'three', b'', b'three'),
4129 4153 (b'', b'four', b'', b'four'),
4130 4154 (b'', b'five', b'', b'five'),
4131 4155 ]
4132 4156 + cmdutil.remoteopts,
4133 4157 _(b'REPO [OPTIONS]... [ONE [TWO]]'),
4134 4158 norepo=True,
4135 4159 )
4136 4160 def debugwireargs(ui, repopath, *vals, **opts):
4137 4161 repo = hg.peer(ui, pycompat.byteskwargs(opts), repopath)
4138 4162 try:
4139 4163 for opt in cmdutil.remoteopts:
4140 4164 del opts[pycompat.sysstr(opt[1])]
4141 4165 args = {}
4142 4166 for k, v in opts.items():
4143 4167 if v:
4144 4168 args[k] = v
4145 4169
4146 4170 # run twice to check that we don't mess up the stream for the next command
4147 4171 res1 = repo.debugwireargs(*vals, **args)
4148 4172 res2 = repo.debugwireargs(*vals, **args)
4149 4173 ui.write(b"%s\n" % res1)
4150 4174 if res1 != res2:
4151 4175 ui.warn(b"%s\n" % res2)
4152 4176 finally:
4153 4177 repo.close()
4154 4178
4155 4179
4156 4180 def _parsewirelangblocks(fh):
4157 4181 activeaction = None
4158 4182 blocklines = []
4159 4183 lastindent = 0
4160 4184
4161 4185 for line in fh:
4162 4186 line = line.rstrip()
4163 4187 if not line:
4164 4188 continue
4165 4189
4166 4190 if line.startswith(b'#'):
4167 4191 continue
4168 4192
4169 4193 if not line.startswith(b' '):
4170 4194 # New block. Flush previous one.
4171 4195 if activeaction:
4172 4196 yield activeaction, blocklines
4173 4197
4174 4198 activeaction = line
4175 4199 blocklines = []
4176 4200 lastindent = 0
4177 4201 continue
4178 4202
4179 4203 # Else we start with an indent.
4180 4204
4181 4205 if not activeaction:
4182 4206 raise error.Abort(_(b'indented line outside of block'))
4183 4207
4184 4208 indent = len(line) - len(line.lstrip())
4185 4209
4186 4210 # If this line is indented more than the last line, concatenate it.
4187 4211 if indent > lastindent and blocklines:
4188 4212 blocklines[-1] += line.lstrip()
4189 4213 else:
4190 4214 blocklines.append(line)
4191 4215 lastindent = indent
4192 4216
4193 4217 # Flush last block.
4194 4218 if activeaction:
4195 4219 yield activeaction, blocklines
4196 4220
4197 4221
4198 4222 @command(
4199 4223 b'debugwireproto',
4200 4224 [
4201 4225 (b'', b'localssh', False, _(b'start an SSH server for this repo')),
4202 4226 (b'', b'peer', b'', _(b'construct a specific version of the peer')),
4203 4227 (
4204 4228 b'',
4205 4229 b'noreadstderr',
4206 4230 False,
4207 4231 _(b'do not read from stderr of the remote'),
4208 4232 ),
4209 4233 (
4210 4234 b'',
4211 4235 b'nologhandshake',
4212 4236 False,
4213 4237 _(b'do not log I/O related to the peer handshake'),
4214 4238 ),
4215 4239 ]
4216 4240 + cmdutil.remoteopts,
4217 4241 _(b'[PATH]'),
4218 4242 optionalrepo=True,
4219 4243 )
4220 4244 def debugwireproto(ui, repo, path=None, **opts):
4221 4245 """send wire protocol commands to a server
4222 4246
4223 4247 This command can be used to issue wire protocol commands to remote
4224 4248 peers and to debug the raw data being exchanged.
4225 4249
4226 4250 ``--localssh`` will start an SSH server against the current repository
4227 4251 and connect to that. By default, the connection will perform a handshake
4228 4252 and establish an appropriate peer instance.
4229 4253
4230 4254 ``--peer`` can be used to bypass the handshake protocol and construct a
4231 4255 peer instance using the specified class type. Valid values are ``raw``,
4232 4256 ``ssh1``. ``raw`` instances only allow sending raw data payloads and
4233 4257 don't support higher-level command actions.
4234 4258
4235 4259 ``--noreadstderr`` can be used to disable automatic reading from stderr
4236 4260 of the peer (for SSH connections only). Disabling automatic reading of
4237 4261 stderr is useful for making output more deterministic.
4238 4262
4239 4263 Commands are issued via a mini language which is specified via stdin.
4240 4264 The language consists of individual actions to perform. An action is
4241 4265 defined by a block. A block is defined as a line with no leading
4242 4266 space followed by 0 or more lines with leading space. Blocks are
4243 4267 effectively a high-level command with additional metadata.
4244 4268
4245 4269 Lines beginning with ``#`` are ignored.
4246 4270
4247 4271 The following sections denote available actions.
4248 4272
4249 4273 raw
4250 4274 ---
4251 4275
4252 4276 Send raw data to the server.
4253 4277
4254 4278 The block payload contains the raw data to send as one atomic send
4255 4279 operation. The data may not actually be delivered in a single system
4256 4280 call: it depends on the abilities of the transport being used.
4257 4281
4258 4282 Each line in the block is de-indented and concatenated. Then, that
4259 4283 value is evaluated as a Python b'' literal. This allows the use of
4260 4284 backslash escaping, etc.
4261 4285
4262 4286 raw+
4263 4287 ----
4264 4288
4265 4289 Behaves like ``raw`` except flushes output afterwards.
4266 4290
4267 4291 command <X>
4268 4292 -----------
4269 4293
4270 4294 Send a request to run a named command, whose name follows the ``command``
4271 4295 string.
4272 4296
4273 4297 Arguments to the command are defined as lines in this block. The format of
4274 4298 each line is ``<key> <value>``. e.g.::
4275 4299
4276 4300 command listkeys
4277 4301 namespace bookmarks
4278 4302
4279 4303 If the value begins with ``eval:``, it will be interpreted as a Python
4280 4304 literal expression. Otherwise values are interpreted as Python b'' literals.
4281 4305 This allows sending complex types and encoding special byte sequences via
4282 4306 backslash escaping.
4283 4307
4284 4308 The following arguments have special meaning:
4285 4309
4286 4310 ``PUSHFILE``
4287 4311 When defined, the *push* mechanism of the peer will be used instead
4288 4312 of the static request-response mechanism and the content of the
4289 4313 file specified in the value of this argument will be sent as the
4290 4314 command payload.
4291 4315
4292 4316 This can be used to submit a local bundle file to the remote.
4293 4317
4294 4318 batchbegin
4295 4319 ----------
4296 4320
4297 4321 Instruct the peer to begin a batched send.
4298 4322
4299 4323 All ``command`` blocks are queued for execution until the next
4300 4324 ``batchsubmit`` block.
4301 4325
4302 4326 batchsubmit
4303 4327 -----------
4304 4328
4305 4329 Submit previously queued ``command`` blocks as a batch request.
4306 4330
4307 4331 This action MUST be paired with a ``batchbegin`` action.
4308 4332
4309 4333 httprequest <method> <path>
4310 4334 ---------------------------
4311 4335
4312 4336 (HTTP peer only)
4313 4337
4314 4338 Send an HTTP request to the peer.
4315 4339
4316 4340 The HTTP request line follows the ``httprequest`` action. e.g. ``GET /foo``.
4317 4341
4318 4342 Arguments of the form ``<key>: <value>`` are interpreted as HTTP request
4319 4343 headers to add to the request. e.g. ``Accept: foo``.
4320 4344
4321 4345 The following arguments are special:
4322 4346
4323 4347 ``BODYFILE``
4324 4348 The content of the file defined as the value to this argument will be
4325 4349 transferred verbatim as the HTTP request body.
4326 4350
4327 4351 ``frame <type> <flags> <payload>``
4328 4352 Send a unified protocol frame as part of the request body.
4329 4353
4330 4354 All frames will be collected and sent as the body to the HTTP
4331 4355 request.
4332 4356
4333 4357 close
4334 4358 -----
4335 4359
4336 4360 Close the connection to the server.
4337 4361
4338 4362 flush
4339 4363 -----
4340 4364
4341 4365 Flush data written to the server.
4342 4366
4343 4367 readavailable
4344 4368 -------------
4345 4369
4346 4370 Close the write end of the connection and read all available data from
4347 4371 the server.
4348 4372
4349 4373 If the connection to the server encompasses multiple pipes, we poll both
4350 4374 pipes and read available data.
4351 4375
4352 4376 readline
4353 4377 --------
4354 4378
4355 4379 Read a line of output from the server. If there are multiple output
4356 4380 pipes, reads only the main pipe.
4357 4381
4358 4382 ereadline
4359 4383 ---------
4360 4384
4361 4385 Like ``readline``, but read from the stderr pipe, if available.
4362 4386
4363 4387 read <X>
4364 4388 --------
4365 4389
4366 4390 ``read()`` N bytes from the server's main output pipe.
4367 4391
4368 4392 eread <X>
4369 4393 ---------
4370 4394
4371 4395 ``read()`` N bytes from the server's stderr pipe, if available.
4372 4396
4373 4397 Specifying Unified Frame-Based Protocol Frames
4374 4398 ----------------------------------------------
4375 4399
4376 4400 It is possible to emit a *Unified Frame-Based Protocol* by using special
4377 4401 syntax.
4378 4402
4379 4403 A frame is composed as a type, flags, and payload. These can be parsed
4380 4404 from a string of the form:
4381 4405
4382 4406 <request-id> <stream-id> <stream-flags> <type> <flags> <payload>
4383 4407
4384 4408 ``request-id`` and ``stream-id`` are integers defining the request and
4385 4409 stream identifiers.
4386 4410
4387 4411 ``type`` can be an integer value for the frame type or the string name
4388 4412 of the type. The strings are defined in ``wireprotoframing.py``. e.g.
4389 4413 ``command-name``.
4390 4414
4391 4415 ``stream-flags`` and ``flags`` are a ``|`` delimited list of flag
4392 4416 components. Each component (and there can be just one) can be an integer
4393 4417 or a flag name for stream flags or frame flags, respectively. Values are
4394 4418 resolved to integers and then bitwise OR'd together.
4395 4419
4396 4420 ``payload`` represents the raw frame payload. If it begins with
4397 4421 ``cbor:``, the following string is evaluated as Python code and the
4398 4422 resulting object is fed into a CBOR encoder. Otherwise it is interpreted
4399 4423 as a Python byte string literal.
4400 4424 """
4401 4425 if opts['localssh'] and not repo:
4402 4426 raise error.Abort(_(b'--localssh requires a repository'))
4403 4427
4404 4428 if opts['peer'] and opts['peer'] not in (
4405 4429 b'raw',
4406 4430 b'ssh1',
4407 4431 ):
4408 4432 raise error.Abort(
4409 4433 _(b'invalid value for --peer'),
4410 4434 hint=_(b'valid values are "raw" and "ssh1"'),
4411 4435 )
4412 4436
4413 4437 if path and opts['localssh']:
4414 4438 raise error.Abort(_(b'cannot specify --localssh with an explicit path'))
4415 4439
4416 4440 if ui.interactive():
4417 4441 ui.write(_(b'(waiting for commands on stdin)\n'))
4418 4442
4419 4443 blocks = list(_parsewirelangblocks(ui.fin))
4420 4444
4421 4445 proc = None
4422 4446 stdin = None
4423 4447 stdout = None
4424 4448 stderr = None
4425 4449 opener = None
4426 4450
4427 4451 if opts['localssh']:
4428 4452 # We start the SSH server in its own process so there is process
4429 4453 # separation. This prevents a whole class of potential bugs around
4430 4454 # shared state from interfering with server operation.
4431 4455 args = procutil.hgcmd() + [
4432 4456 b'-R',
4433 4457 repo.root,
4434 4458 b'debugserve',
4435 4459 b'--sshstdio',
4436 4460 ]
4437 4461 proc = subprocess.Popen(
4438 4462 pycompat.rapply(procutil.tonativestr, args),
4439 4463 stdin=subprocess.PIPE,
4440 4464 stdout=subprocess.PIPE,
4441 4465 stderr=subprocess.PIPE,
4442 4466 bufsize=0,
4443 4467 )
4444 4468
4445 4469 stdin = proc.stdin
4446 4470 stdout = proc.stdout
4447 4471 stderr = proc.stderr
4448 4472
4449 4473 # We turn the pipes into observers so we can log I/O.
4450 4474 if ui.verbose or opts['peer'] == b'raw':
4451 4475 stdin = util.makeloggingfileobject(
4452 4476 ui, proc.stdin, b'i', logdata=True
4453 4477 )
4454 4478 stdout = util.makeloggingfileobject(
4455 4479 ui, proc.stdout, b'o', logdata=True
4456 4480 )
4457 4481 stderr = util.makeloggingfileobject(
4458 4482 ui, proc.stderr, b'e', logdata=True
4459 4483 )
4460 4484
4461 4485 # --localssh also implies the peer connection settings.
4462 4486
4463 4487 url = b'ssh://localserver'
4464 4488 autoreadstderr = not opts['noreadstderr']
4465 4489
4466 4490 if opts['peer'] == b'ssh1':
4467 4491 ui.write(_(b'creating ssh peer for wire protocol version 1\n'))
4468 4492 peer = sshpeer.sshv1peer(
4469 4493 ui,
4470 4494 url,
4471 4495 proc,
4472 4496 stdin,
4473 4497 stdout,
4474 4498 stderr,
4475 4499 None,
4476 4500 autoreadstderr=autoreadstderr,
4477 4501 )
4478 4502 elif opts['peer'] == b'raw':
4479 4503 ui.write(_(b'using raw connection to peer\n'))
4480 4504 peer = None
4481 4505 else:
4482 4506 ui.write(_(b'creating ssh peer from handshake results\n'))
4483 4507 peer = sshpeer._make_peer(
4484 4508 ui,
4485 4509 url,
4486 4510 proc,
4487 4511 stdin,
4488 4512 stdout,
4489 4513 stderr,
4490 4514 autoreadstderr=autoreadstderr,
4491 4515 )
4492 4516
4493 4517 elif path:
4494 4518 # We bypass hg.peer() so we can proxy the sockets.
4495 4519 # TODO consider not doing this because we skip
4496 4520 # ``hg.wirepeersetupfuncs`` and potentially other useful functionality.
4497 4521 u = urlutil.url(path)
4498 4522 if u.scheme != b'http':
4499 4523 raise error.Abort(_(b'only http:// paths are currently supported'))
4500 4524
4501 4525 url, authinfo = u.authinfo()
4502 4526 openerargs = {
4503 4527 'useragent': b'Mercurial debugwireproto',
4504 4528 }
4505 4529
4506 4530 # Turn pipes/sockets into observers so we can log I/O.
4507 4531 if ui.verbose:
4508 4532 openerargs.update(
4509 4533 {
4510 4534 'loggingfh': ui,
4511 4535 'loggingname': b's',
4512 4536 'loggingopts': {
4513 4537 'logdata': True,
4514 4538 'logdataapis': False,
4515 4539 },
4516 4540 }
4517 4541 )
4518 4542
4519 4543 if ui.debugflag:
4520 4544 openerargs['loggingopts']['logdataapis'] = True
4521 4545
4522 4546 # Don't send default headers when in raw mode. This allows us to
4523 4547 # bypass most of the behavior of our URL handling code so we can
4524 4548 # have near complete control over what's sent on the wire.
4525 4549 if opts['peer'] == b'raw':
4526 4550 openerargs['sendaccept'] = False
4527 4551
4528 4552 opener = urlmod.opener(ui, authinfo, **openerargs)
4529 4553
4530 4554 if opts['peer'] == b'raw':
4531 4555 ui.write(_(b'using raw connection to peer\n'))
4532 4556 peer = None
4533 4557 elif opts['peer']:
4534 4558 raise error.Abort(
4535 4559 _(b'--peer %s not supported with HTTP peers') % opts['peer']
4536 4560 )
4537 4561 else:
4538 4562 peer_path = urlutil.try_path(ui, path)
4539 4563 peer = httppeer._make_peer(ui, peer_path, opener=opener)
4540 4564
4541 4565 # We /could/ populate stdin/stdout with sock.makefile()...
4542 4566 else:
4543 4567 raise error.Abort(_(b'unsupported connection configuration'))
4544 4568
4545 4569 batchedcommands = None
4546 4570
4547 4571 # Now perform actions based on the parsed wire language instructions.
4548 4572 for action, lines in blocks:
4549 4573 if action in (b'raw', b'raw+'):
4550 4574 if not stdin:
4551 4575 raise error.Abort(_(b'cannot call raw/raw+ on this peer'))
4552 4576
4553 4577 # Concatenate the data together.
4554 4578 data = b''.join(l.lstrip() for l in lines)
4555 4579 data = stringutil.unescapestr(data)
4556 4580 stdin.write(data)
4557 4581
4558 4582 if action == b'raw+':
4559 4583 stdin.flush()
4560 4584 elif action == b'flush':
4561 4585 if not stdin:
4562 4586 raise error.Abort(_(b'cannot call flush on this peer'))
4563 4587 stdin.flush()
4564 4588 elif action.startswith(b'command'):
4565 4589 if not peer:
4566 4590 raise error.Abort(
4567 4591 _(
4568 4592 b'cannot send commands unless peer instance '
4569 4593 b'is available'
4570 4594 )
4571 4595 )
4572 4596
4573 4597 command = action.split(b' ', 1)[1]
4574 4598
4575 4599 args = {}
4576 4600 for line in lines:
4577 4601 # We need to allow empty values.
4578 4602 fields = line.lstrip().split(b' ', 1)
4579 4603 if len(fields) == 1:
4580 4604 key = fields[0]
4581 4605 value = b''
4582 4606 else:
4583 4607 key, value = fields
4584 4608
4585 4609 if value.startswith(b'eval:'):
4586 4610 value = stringutil.evalpythonliteral(value[5:])
4587 4611 else:
4588 4612 value = stringutil.unescapestr(value)
4589 4613
4590 4614 args[key] = value
4591 4615
4592 4616 if batchedcommands is not None:
4593 4617 batchedcommands.append((command, args))
4594 4618 continue
4595 4619
4596 4620 ui.status(_(b'sending %s command\n') % command)
4597 4621
4598 4622 if b'PUSHFILE' in args:
4599 4623 with open(args[b'PUSHFILE'], 'rb') as fh:
4600 4624 del args[b'PUSHFILE']
4601 4625 res, output = peer._callpush(
4602 4626 command, fh, **pycompat.strkwargs(args)
4603 4627 )
4604 4628 ui.status(_(b'result: %s\n') % stringutil.escapestr(res))
4605 4629 ui.status(
4606 4630 _(b'remote output: %s\n') % stringutil.escapestr(output)
4607 4631 )
4608 4632 else:
4609 4633 with peer.commandexecutor() as e:
4610 4634 res = e.callcommand(command, args).result()
4611 4635
4612 4636 ui.status(
4613 4637 _(b'response: %s\n')
4614 4638 % stringutil.pprint(res, bprefix=True, indent=2)
4615 4639 )
4616 4640
4617 4641 elif action == b'batchbegin':
4618 4642 if batchedcommands is not None:
4619 4643 raise error.Abort(_(b'nested batchbegin not allowed'))
4620 4644
4621 4645 batchedcommands = []
4622 4646 elif action == b'batchsubmit':
4623 4647 # There is a batching API we could go through. But it would be
4624 4648 # difficult to normalize requests into function calls. It is easier
4625 4649 # to bypass this layer and normalize to commands + args.
4626 4650 ui.status(
4627 4651 _(b'sending batch with %d sub-commands\n')
4628 4652 % len(batchedcommands)
4629 4653 )
4630 4654 assert peer is not None
4631 4655 for i, chunk in enumerate(peer._submitbatch(batchedcommands)):
4632 4656 ui.status(
4633 4657 _(b'response #%d: %s\n') % (i, stringutil.escapestr(chunk))
4634 4658 )
4635 4659
4636 4660 batchedcommands = None
4637 4661
4638 4662 elif action.startswith(b'httprequest '):
4639 4663 if not opener:
4640 4664 raise error.Abort(
4641 4665 _(b'cannot use httprequest without an HTTP peer')
4642 4666 )
4643 4667
4644 4668 request = action.split(b' ', 2)
4645 4669 if len(request) != 3:
4646 4670 raise error.Abort(
4647 4671 _(
4648 4672 b'invalid httprequest: expected format is '
4649 4673 b'"httprequest <method> <path>'
4650 4674 )
4651 4675 )
4652 4676
4653 4677 method, httppath = request[1:]
4654 4678 headers = {}
4655 4679 body = None
4656 4680 frames = []
4657 4681 for line in lines:
4658 4682 line = line.lstrip()
4659 4683 m = re.match(b'^([a-zA-Z0-9_-]+): (.*)$', line)
4660 4684 if m:
4661 4685 # Headers need to use native strings.
4662 4686 key = pycompat.strurl(m.group(1))
4663 4687 value = pycompat.strurl(m.group(2))
4664 4688 headers[key] = value
4665 4689 continue
4666 4690
4667 4691 if line.startswith(b'BODYFILE '):
4668 4692 with open(line.split(b' ', 1), b'rb') as fh:
4669 4693 body = fh.read()
4670 4694 elif line.startswith(b'frame '):
4671 4695 frame = wireprotoframing.makeframefromhumanstring(
4672 4696 line[len(b'frame ') :]
4673 4697 )
4674 4698
4675 4699 frames.append(frame)
4676 4700 else:
4677 4701 raise error.Abort(
4678 4702 _(b'unknown argument to httprequest: %s') % line
4679 4703 )
4680 4704
4681 4705 url = path + httppath
4682 4706
4683 4707 if frames:
4684 4708 body = b''.join(bytes(f) for f in frames)
4685 4709
4686 4710 req = urlmod.urlreq.request(pycompat.strurl(url), body, headers)
4687 4711
4688 4712 # urllib.Request insists on using has_data() as a proxy for
4689 4713 # determining the request method. Override that to use our
4690 4714 # explicitly requested method.
4691 4715 req.get_method = lambda: pycompat.sysstr(method)
4692 4716
4693 4717 try:
4694 4718 res = opener.open(req)
4695 4719 body = res.read()
4696 4720 except util.urlerr.urlerror as e:
4697 4721 # read() method must be called, but only exists in Python 2
4698 4722 getattr(e, 'read', lambda: None)()
4699 4723 continue
4700 4724
4701 4725 ct = res.headers.get('Content-Type')
4702 4726 if ct == 'application/mercurial-cbor':
4703 4727 ui.write(
4704 4728 _(b'cbor> %s\n')
4705 4729 % stringutil.pprint(
4706 4730 cborutil.decodeall(body), bprefix=True, indent=2
4707 4731 )
4708 4732 )
4709 4733
4710 4734 elif action == b'close':
4711 4735 assert peer is not None
4712 4736 peer.close()
4713 4737 elif action == b'readavailable':
4714 4738 if not stdout or not stderr:
4715 4739 raise error.Abort(
4716 4740 _(b'readavailable not available on this peer')
4717 4741 )
4718 4742
4719 4743 stdin.close()
4720 4744 stdout.read()
4721 4745 stderr.read()
4722 4746
4723 4747 elif action == b'readline':
4724 4748 if not stdout:
4725 4749 raise error.Abort(_(b'readline not available on this peer'))
4726 4750 stdout.readline()
4727 4751 elif action == b'ereadline':
4728 4752 if not stderr:
4729 4753 raise error.Abort(_(b'ereadline not available on this peer'))
4730 4754 stderr.readline()
4731 4755 elif action.startswith(b'read '):
4732 4756 count = int(action.split(b' ', 1)[1])
4733 4757 if not stdout:
4734 4758 raise error.Abort(_(b'read not available on this peer'))
4735 4759 stdout.read(count)
4736 4760 elif action.startswith(b'eread '):
4737 4761 count = int(action.split(b' ', 1)[1])
4738 4762 if not stderr:
4739 4763 raise error.Abort(_(b'eread not available on this peer'))
4740 4764 stderr.read(count)
4741 4765 else:
4742 4766 raise error.Abort(_(b'unknown action: %s') % action)
4743 4767
4744 4768 if batchedcommands is not None:
4745 4769 raise error.Abort(_(b'unclosed "batchbegin" request'))
4746 4770
4747 4771 if peer:
4748 4772 peer.close()
4749 4773
4750 4774 if proc:
4751 4775 proc.kill()
@@ -1,458 +1,460 b''
1 1 Show all commands except debug commands
2 2 $ hg debugcomplete
3 3 abort
4 4 add
5 5 addremove
6 6 admin::verify
7 7 annotate
8 8 archive
9 9 backout
10 10 bisect
11 11 bookmarks
12 12 branch
13 13 branches
14 14 bundle
15 15 cat
16 16 clone
17 17 commit
18 18 config
19 19 continue
20 20 copy
21 21 diff
22 22 export
23 23 files
24 24 forget
25 25 graft
26 26 grep
27 27 heads
28 28 help
29 29 identify
30 30 import
31 31 incoming
32 32 init
33 33 locate
34 34 log
35 35 manifest
36 36 merge
37 37 outgoing
38 38 parents
39 39 paths
40 40 phase
41 41 pull
42 42 purge
43 43 push
44 44 recover
45 45 remove
46 46 rename
47 47 resolve
48 48 revert
49 49 rollback
50 50 root
51 51 serve
52 52 shelve
53 53 status
54 54 summary
55 55 tag
56 56 tags
57 57 tip
58 58 unbundle
59 59 unshelve
60 60 update
61 61 verify
62 62 version
63 63
64 64 Show all commands that start with "a"
65 65 $ hg debugcomplete a
66 66 abort
67 67 add
68 68 addremove
69 69 admin::verify
70 70 annotate
71 71 archive
72 72
73 73 Do not show debug commands if there are other candidates
74 74 $ hg debugcomplete d
75 75 diff
76 76
77 77 Show debug commands if there are no other candidates
78 78 $ hg debugcomplete debug
79 79 debug-delta-find
80 80 debug-repair-issue6528
81 81 debug-revlog-index
82 82 debug-revlog-stats
83 83 debug::stable-tail-sort
84 84 debug::stable-tail-sort-leaps
85 debug::unbundle
85 86 debugancestor
86 87 debugantivirusrunning
87 88 debugapplystreamclonebundle
88 89 debugbackupbundle
89 90 debugbuilddag
90 91 debugbundle
91 92 debugcapabilities
92 93 debugchangedfiles
93 94 debugcheckstate
94 95 debugcolor
95 96 debugcommands
96 97 debugcomplete
97 98 debugconfig
98 99 debugcreatestreamclonebundle
99 100 debugdag
100 101 debugdata
101 102 debugdate
102 103 debugdeltachain
103 104 debugdirstate
104 105 debugdirstateignorepatternshash
105 106 debugdiscovery
106 107 debugdownload
107 108 debugextensions
108 109 debugfileset
109 110 debugformat
110 111 debugfsinfo
111 112 debuggetbundle
112 113 debugignore
113 114 debugindexdot
114 115 debugindexstats
115 116 debuginstall
116 117 debugknown
117 118 debuglabelcomplete
118 119 debuglocks
119 120 debugmanifestfulltextcache
120 121 debugmergestate
121 122 debugnamecomplete
122 123 debugnodemap
123 124 debugobsolete
124 125 debugp1copies
125 126 debugp2copies
126 127 debugpathcomplete
127 128 debugpathcopies
128 129 debugpeer
129 130 debugpickmergetool
130 131 debugpushkey
131 132 debugpvec
132 133 debugrebuilddirstate
133 134 debugrebuildfncache
134 135 debugrename
135 136 debugrequires
136 137 debugrevlog
137 138 debugrevlogindex
138 139 debugrevspec
139 140 debugserve
140 141 debugsetparents
141 142 debugshell
142 143 debugsidedata
143 144 debugssl
144 145 debugstrip
145 146 debugsub
146 147 debugsuccessorssets
147 148 debugtagscache
148 149 debugtemplate
149 150 debuguigetpass
150 151 debuguiprompt
151 152 debugupdatecaches
152 153 debugupgraderepo
153 154 debugwalk
154 155 debugwhyunstable
155 156 debugwireargs
156 157 debugwireproto
157 158
158 159 Do not show the alias of a debug command if there are other candidates
159 160 (this should hide rawcommit)
160 161 $ hg debugcomplete r
161 162 recover
162 163 remove
163 164 rename
164 165 resolve
165 166 revert
166 167 rollback
167 168 root
168 169 Show the alias of a debug command if there are no other candidates
169 170 $ hg debugcomplete rawc
170 171
171 172
172 173 Show the global options
173 174 $ hg debugcomplete --options | sort
174 175 --color
175 176 --config
176 177 --cwd
177 178 --debug
178 179 --debugger
179 180 --encoding
180 181 --encodingmode
181 182 --help
182 183 --hidden
183 184 --noninteractive
184 185 --pager
185 186 --profile
186 187 --quiet
187 188 --repository
188 189 --time
189 190 --traceback
190 191 --verbose
191 192 --version
192 193 -R
193 194 -h
194 195 -q
195 196 -v
196 197 -y
197 198
198 199 Show the options for the "serve" command
199 200 $ hg debugcomplete --options serve | sort
200 201 --accesslog
201 202 --address
202 203 --certificate
203 204 --cmdserver
204 205 --color
205 206 --config
206 207 --cwd
207 208 --daemon
208 209 --daemon-postexec
209 210 --debug
210 211 --debugger
211 212 --encoding
212 213 --encodingmode
213 214 --errorlog
214 215 --help
215 216 --hidden
216 217 --ipv6
217 218 --name
218 219 --noninteractive
219 220 --pager
220 221 --pid-file
221 222 --port
222 223 --prefix
223 224 --print-url
224 225 --profile
225 226 --quiet
226 227 --repository
227 228 --stdio
228 229 --style
229 230 --subrepos
230 231 --templates
231 232 --time
232 233 --traceback
233 234 --verbose
234 235 --version
235 236 --web-conf
236 237 -6
237 238 -A
238 239 -E
239 240 -R
240 241 -S
241 242 -a
242 243 -d
243 244 -h
244 245 -n
245 246 -p
246 247 -q
247 248 -t
248 249 -v
249 250 -y
250 251
251 252 Show an error if we use --options with an ambiguous abbreviation
252 253 $ hg debugcomplete --options s
253 254 hg: command 's' is ambiguous:
254 255 serve shelve showconfig status summary
255 256 [10]
256 257
257 258 Show all commands + options
258 259 $ hg debugcommands
259 260 abort: dry-run
260 261 add: include, exclude, subrepos, dry-run
261 262 addremove: similarity, subrepos, include, exclude, dry-run
262 263 admin::verify: check, option
263 264 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, skip, line-range, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, include, exclude, template
264 265 archive: no-decode, prefix, rev, type, subrepos, include, exclude
265 266 backout: merge, commit, no-commit, parent, rev, edit, tool, include, exclude, message, logfile, date, user
266 267 bisect: reset, good, bad, skip, extend, command, noupdate
267 268 bookmarks: force, rev, delete, rename, inactive, list, template
268 269 branch: force, clean, rev
269 270 branches: active, closed, rev, template
270 271 bundle: exact, force, rev, branch, base, all, type, ssh, remotecmd, insecure
271 272 cat: output, rev, decode, include, exclude, template
272 273 clone: noupdate, updaterev, rev, branch, pull, uncompressed, stream, ssh, remotecmd, insecure
273 274 commit: addremove, close-branch, amend, secret, draft, edit, force-close-branch, interactive, include, exclude, message, logfile, date, user, subrepos
274 275 config: untrusted, exp-all-known, edit, local, source, shared, non-shared, global, template
275 276 continue: dry-run
276 277 copy: forget, after, at-rev, force, include, exclude, dry-run
277 278 debug-delta-find: changelog, manifest, dir, template, source
278 279 debug-repair-issue6528: to-report, from-report, paranoid, dry-run
279 280 debug-revlog-index: changelog, manifest, dir, template
280 281 debug-revlog-stats: changelog, manifest, filelogs, template
281 282 debug::stable-tail-sort: template
282 283 debug::stable-tail-sort-leaps: template, specific
284 debug::unbundle: update
283 285 debugancestor:
284 286 debugantivirusrunning:
285 287 debugapplystreamclonebundle:
286 288 debugbackupbundle: recover, patch, git, limit, no-merges, stat, graph, style, template
287 289 debugbuilddag: mergeable-file, overwritten-file, new-file, from-existing
288 290 debugbundle: all, part-type, spec
289 291 debugcapabilities:
290 292 debugchangedfiles: compute
291 293 debugcheckstate:
292 294 debugcolor: style
293 295 debugcommands:
294 296 debugcomplete: options
295 297 debugcreatestreamclonebundle:
296 298 debugdag: tags, branches, dots, spaces
297 299 debugdata: changelog, manifest, dir
298 300 debugdate: extended
299 301 debugdeltachain: rev, all-info, size-info, dist-info, sparse-info, changelog, manifest, dir, template
300 302 debugdirstateignorepatternshash:
301 303 debugdirstate: nodates, dates, datesort, docket, all
302 304 debugdiscovery: old, nonheads, rev, seed, local-as-revs, remote-as-revs, ssh, remotecmd, insecure, template
303 305 debugdownload: output
304 306 debugextensions: template
305 307 debugfileset: rev, all-files, show-matcher, show-stage
306 308 debugformat: template
307 309 debugfsinfo:
308 310 debuggetbundle: head, common, type
309 311 debugignore:
310 312 debugindexdot: changelog, manifest, dir
311 313 debugindexstats:
312 314 debuginstall: template
313 315 debugknown:
314 316 debuglabelcomplete:
315 317 debuglocks: force-free-lock, force-free-wlock, set-lock, set-wlock
316 318 debugmanifestfulltextcache: clear, add
317 319 debugmergestate: style, template
318 320 debugnamecomplete:
319 321 debugnodemap: changelog, manifest, dir, dump-new, dump-disk, check, metadata
320 322 debugobsolete: flags, record-parents, rev, exclusive, index, delete, date, user, template
321 323 debugp1copies: rev
322 324 debugp2copies: rev
323 325 debugpathcomplete: full, normal, added, removed
324 326 debugpathcopies: include, exclude
325 327 debugpeer:
326 328 debugpickmergetool: rev, changedelete, include, exclude, tool
327 329 debugpushkey:
328 330 debugpvec:
329 331 debugrebuilddirstate: rev, minimal
330 332 debugrebuildfncache: only-data
331 333 debugrename: rev
332 334 debugrequires:
333 335 debugrevlog: changelog, manifest, dir, dump
334 336 debugrevlogindex: changelog, manifest, dir, format
335 337 debugrevspec: optimize, show-revs, show-set, show-stage, no-optimized, verify-optimized
336 338 debugserve: sshstdio, logiofd, logiofile
337 339 debugsetparents:
338 340 debugshell: command
339 341 debugsidedata: changelog, manifest, dir
340 342 debugssl:
341 343 debugstrip: rev, force, no-backup, nobackup, , keep, bookmark, soft
342 344 debugsub: rev
343 345 debugsuccessorssets: closest
344 346 debugtagscache:
345 347 debugtemplate: rev, define
346 348 debuguigetpass: prompt
347 349 debuguiprompt: prompt
348 350 debugupdatecaches:
349 351 debugupgraderepo: optimize, run, backup, changelog, manifest, filelogs
350 352 debugwalk: include, exclude
351 353 debugwhyunstable:
352 354 debugwireargs: three, four, five, ssh, remotecmd, insecure
353 355 debugwireproto: localssh, peer, noreadstderr, nologhandshake, ssh, remotecmd, insecure
354 356 diff: rev, from, to, change, text, git, binary, nodates, noprefix, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, unified, stat, root, include, exclude, subrepos
355 357 export: bookmark, output, switch-parent, rev, text, git, binary, nodates, template
356 358 files: rev, print0, include, exclude, template, subrepos
357 359 forget: interactive, include, exclude, dry-run
358 360 graft: rev, base, continue, stop, abort, edit, log, no-commit, force, currentdate, currentuser, date, user, tool, dry-run
359 361 grep: print0, all, diff, text, follow, ignore-case, files-with-matches, line-number, rev, all-files, user, date, template, include, exclude
360 362 heads: rev, topo, active, closed, style, template
361 363 help: extension, command, keyword, system
362 364 identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure, template
363 365 import: strip, base, secret, edit, force, no-commit, bypass, partial, exact, prefix, import-branch, message, logfile, date, user, similarity
364 366 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
365 367 init: ssh, remotecmd, insecure
366 368 locate: rev, print0, fullpath, include, exclude
367 369 log: follow, follow-first, date, copies, keyword, rev, line-range, removed, only-merges, user, only-branch, branch, bookmark, prune, patch, git, limit, no-merges, stat, graph, style, template, include, exclude
368 370 manifest: rev, all, template
369 371 merge: force, rev, preview, abort, tool
370 372 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
371 373 parents: rev, style, template
372 374 paths: template
373 375 phase: public, draft, secret, force, rev
374 376 pull: update, force, confirm, rev, bookmark, branch, remote-hidden, ssh, remotecmd, insecure
375 377 purge: abort-on-err, all, ignored, dirs, files, print, print0, confirm, include, exclude
376 378 push: force, rev, bookmark, all-bookmarks, branch, new-branch, pushvars, publish, ssh, remotecmd, insecure
377 379 recover: verify
378 380 remove: after, force, subrepos, include, exclude, dry-run
379 381 rename: forget, after, at-rev, force, include, exclude, dry-run
380 382 resolve: all, list, mark, unmark, no-status, re-merge, tool, include, exclude, template
381 383 revert: all, date, rev, no-backup, interactive, include, exclude, dry-run
382 384 rollback: dry-run, force
383 385 root: template
384 386 serve: accesslog, daemon, daemon-postexec, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate, print-url, subrepos
385 387 shelve: addremove, unknown, cleanup, date, delete, edit, keep, list, message, name, patch, interactive, stat, include, exclude
386 388 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, terse, copies, print0, rev, change, include, exclude, subrepos, template
387 389 summary: remote
388 390 tag: force, local, rev, remove, edit, message, date, user
389 391 tags: template
390 392 tip: patch, git, style, template
391 393 unbundle: update
392 394 unshelve: abort, continue, interactive, keep, name, tool, date
393 395 update: clean, check, merge, date, rev, tool
394 396 verify: full
395 397 version: template
396 398
397 399 $ hg init a
398 400 $ cd a
399 401 $ echo fee > fee
400 402 $ hg ci -q -Amfee
401 403 $ hg tag fee
402 404 $ mkdir fie
403 405 $ echo dead > fie/dead
404 406 $ echo live > fie/live
405 407 $ hg bookmark fo
406 408 $ hg branch -q fie
407 409 $ hg ci -q -Amfie
408 410 $ echo fo > fo
409 411 $ hg branch -qf default
410 412 $ hg ci -q -Amfo
411 413 $ echo Fum > Fum
412 414 $ hg ci -q -AmFum
413 415 $ hg bookmark Fum
414 416
415 417 Test debugpathcomplete
416 418
417 419 $ hg debugpathcomplete f
418 420 fee
419 421 fie
420 422 fo
421 423 $ hg debugpathcomplete -f f
422 424 fee
423 425 fie/dead
424 426 fie/live
425 427 fo
426 428
427 429 $ hg rm Fum
428 430 $ hg debugpathcomplete -r F
429 431 Fum
430 432
431 433 Test debugnamecomplete
432 434
433 435 $ hg debugnamecomplete
434 436 Fum
435 437 default
436 438 fee
437 439 fie
438 440 fo
439 441 tip
440 442 $ hg debugnamecomplete f
441 443 fee
442 444 fie
443 445 fo
444 446
445 447 Test debuglabelcomplete, a deprecated name for debugnamecomplete that is still
446 448 used for completions in some shells.
447 449
448 450 $ hg debuglabelcomplete
449 451 Fum
450 452 default
451 453 fee
452 454 fie
453 455 fo
454 456 tip
455 457 $ hg debuglabelcomplete f
456 458 fee
457 459 fie
458 460 fo
@@ -1,818 +1,831 b''
1 1 $ cat << EOF >> $HGRCPATH
2 2 > [ui]
3 3 > interactive=yes
4 4 > EOF
5 5
6 6 $ hg init debugrevlog
7 7 $ cd debugrevlog
8 8 $ echo a > a
9 9 $ hg ci -Am adda
10 10 adding a
11 11 $ hg rm .
12 12 removing a
13 13 $ hg ci -Am make-it-empty
14 14 $ hg revert --all -r 0
15 15 adding a
16 16 $ hg ci -Am make-it-full
17 17 #if reporevlogstore
18 18 $ hg debugrevlog -c
19 19 format : 1
20 20 flags : (none)
21 21
22 22 revisions : 3
23 23 merges : 0 ( 0.00%)
24 24 normal : 3 (100.00%)
25 25 revisions : 3
26 26 empty : 0 ( 0.00%)
27 27 text : 0 (100.00%)
28 28 delta : 0 (100.00%)
29 29 snapshot : 3 (100.00%)
30 30 lvl-0 : 3 (100.00%)
31 31 deltas : 0 ( 0.00%)
32 32 revision size : 191
33 33 snapshot : 191 (100.00%)
34 34 lvl-0 : 191 (100.00%)
35 35 deltas : 0 ( 0.00%)
36 36
37 37 chunks : 3
38 38 0x75 (u) : 3 (100.00%)
39 39 chunks size : 191
40 40 0x75 (u) : 191 (100.00%)
41 41
42 42
43 43 total-stored-content: 188 bytes
44 44
45 45 avg chain length : 0
46 46 max chain length : 0
47 47 max chain reach : 67
48 48 compression ratio : 0
49 49
50 50 uncompressed data size (min/max/avg) : 57 / 66 / 62
51 51 full revision size (min/max/avg) : 58 / 67 / 63
52 52 inter-snapshot size (min/max/avg) : 0 / 0 / 0
53 53 delta size (min/max/avg) : 0 / 0 / 0
54 54 $ hg debugrevlog -m
55 55 format : 1
56 56 flags : inline, generaldelta
57 57
58 58 revisions : 3
59 59 merges : 0 ( 0.00%)
60 60 normal : 3 (100.00%)
61 61 revisions : 3
62 62 empty : 1 (33.33%)
63 63 text : 1 (100.00%)
64 64 delta : 0 ( 0.00%)
65 65 snapshot : 2 (66.67%)
66 66 lvl-0 : 2 (66.67%)
67 67 deltas : 0 ( 0.00%)
68 68 revision size : 88
69 69 snapshot : 88 (100.00%)
70 70 lvl-0 : 88 (100.00%)
71 71 deltas : 0 ( 0.00%)
72 72
73 73 chunks : 3
74 74 empty : 1 (33.33%)
75 75 0x75 (u) : 2 (66.67%)
76 76 chunks size : 88
77 77 empty : 0 ( 0.00%)
78 78 0x75 (u) : 88 (100.00%)
79 79
80 80
81 81 total-stored-content: 86 bytes
82 82
83 83 avg chain length : 0
84 84 max chain length : 0
85 85 max chain reach : 44
86 86 compression ratio : 0
87 87
88 88 uncompressed data size (min/max/avg) : 0 / 43 / 28
89 89 full revision size (min/max/avg) : 44 / 44 / 44
90 90 inter-snapshot size (min/max/avg) : 0 / 0 / 0
91 91 delta size (min/max/avg) : 0 / 0 / 0
92 92 $ hg debugrevlog a
93 93 format : 1
94 94 flags : inline, generaldelta
95 95
96 96 revisions : 1
97 97 merges : 0 ( 0.00%)
98 98 normal : 1 (100.00%)
99 99 revisions : 1
100 100 empty : 0 ( 0.00%)
101 101 text : 0 (100.00%)
102 102 delta : 0 (100.00%)
103 103 snapshot : 1 (100.00%)
104 104 lvl-0 : 1 (100.00%)
105 105 deltas : 0 ( 0.00%)
106 106 revision size : 3
107 107 snapshot : 3 (100.00%)
108 108 lvl-0 : 3 (100.00%)
109 109 deltas : 0 ( 0.00%)
110 110
111 111 chunks : 1
112 112 0x75 (u) : 1 (100.00%)
113 113 chunks size : 3
114 114 0x75 (u) : 3 (100.00%)
115 115
116 116
117 117 total-stored-content: 2 bytes
118 118
119 119 avg chain length : 0
120 120 max chain length : 0
121 121 max chain reach : 3
122 122 compression ratio : 0
123 123
124 124 uncompressed data size (min/max/avg) : 2 / 2 / 2
125 125 full revision size (min/max/avg) : 3 / 3 / 3
126 126 inter-snapshot size (min/max/avg) : 0 / 0 / 0
127 127 delta size (min/max/avg) : 0 / 0 / 0
128 128 #endif
129 129
130 130 Test debugindex, with and without the --verbose/--debug flag
131 131 $ hg debugrevlogindex a
132 132 rev linkrev nodeid p1 p2
133 133 0 0 b789fdd96dc2 000000000000 000000000000
134 134
135 135 #if no-reposimplestore
136 136 $ hg --verbose debugrevlogindex a
137 137 rev offset length linkrev nodeid p1 p2
138 138 0 0 3 0 b789fdd96dc2 000000000000 000000000000
139 139
140 140 $ hg --debug debugrevlogindex a
141 141 rev offset length linkrev nodeid p1 p2
142 142 0 0 3 0 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
143 143 #endif
144 144
145 145 $ hg debugrevlogindex -f 1 a
146 146 rev flag size link p1 p2 nodeid
147 147 0 0000 2 0 -1 -1 b789fdd96dc2
148 148
149 149 #if no-reposimplestore
150 150 $ hg --verbose debugrevlogindex -f 1 a
151 151 rev flag offset length size link p1 p2 nodeid
152 152 0 0000 0 3 2 0 -1 -1 b789fdd96dc2
153 153
154 154 $ hg --debug debugrevlogindex -f 1 a
155 155 rev flag offset length size link p1 p2 nodeid
156 156 0 0000 0 3 2 0 -1 -1 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
157 157 #endif
158 158
159 159 $ hg debugindex -c
160 160 rev linkrev nodeid p1-nodeid p2-nodeid
161 161 0 0 07f494440405 000000000000 000000000000
162 162 1 1 8cccb4b5fec2 07f494440405 000000000000
163 163 2 2 b1e228c512c5 8cccb4b5fec2 000000000000
164 164 $ hg debugindex -c --debug
165 165 rev rank linkrev nodeid p1-rev p1-nodeid p2-rev p2-nodeid full-size delta-base flags comp-mode data-offset chunk-size sd-comp-mode sidedata-offset sd-chunk-size
166 166 0 -1 0 07f4944404050f47db2e5c5071e0e84e7a27bba9 -1 0000000000000000000000000000000000000000 -1 0000000000000000000000000000000000000000 57 0 0 2 0 58 inline 0 0
167 167 1 -1 1 8cccb4b5fec20cafeb99dd01c26d4dee8ea4388a 0 07f4944404050f47db2e5c5071e0e84e7a27bba9 -1 0000000000000000000000000000000000000000 66 1 0 2 58 67 inline 0 0
168 168 2 -1 2 b1e228c512c5d7066d70562ed839c3323a62d6d2 1 8cccb4b5fec20cafeb99dd01c26d4dee8ea4388a -1 0000000000000000000000000000000000000000 65 2 0 2 125 66 inline 0 0
169 169 $ hg debugindex -m
170 170 rev linkrev nodeid p1-nodeid p2-nodeid
171 171 0 0 a0c8bcbbb45c 000000000000 000000000000
172 172 1 1 57faf8a737ae a0c8bcbbb45c 000000000000
173 173 2 2 a35b10320954 57faf8a737ae 000000000000
174 174 $ hg debugindex -m --debug
175 175 rev rank linkrev nodeid p1-rev p1-nodeid p2-rev p2-nodeid full-size delta-base flags comp-mode data-offset chunk-size sd-comp-mode sidedata-offset sd-chunk-size
176 176 0 -1 0 a0c8bcbbb45c63b90b70ad007bf38961f64f2af0 -1 0000000000000000000000000000000000000000 -1 0000000000000000000000000000000000000000 43 0 0 2 0 44 inline 0 0
177 177 1 -1 1 57faf8a737ae7faf490582941a82319ba6529dca 0 a0c8bcbbb45c63b90b70ad007bf38961f64f2af0 -1 0000000000000000000000000000000000000000 0 1 0 2 44 0 inline 0 0
178 178 2 -1 2 a35b103209548032201c16c7688cb2657f037a38 1 57faf8a737ae7faf490582941a82319ba6529dca -1 0000000000000000000000000000000000000000 43 2 0 2 44 44 inline 0 0
179 179 $ hg debugindex a
180 180 rev linkrev nodeid p1-nodeid p2-nodeid
181 181 0 0 b789fdd96dc2 000000000000 000000000000
182 182 $ hg debugindex --debug a
183 183 rev rank linkrev nodeid p1-rev p1-nodeid p2-rev p2-nodeid full-size delta-base flags comp-mode data-offset chunk-size sd-comp-mode sidedata-offset sd-chunk-size
184 184 0 -1 0 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 -1 0000000000000000000000000000000000000000 -1 0000000000000000000000000000000000000000 2 0 0 2 0 3 inline 0 0
185 185
186 186 debugdelta chain basic output
187 187
188 188 #if reporevlogstore pure rust
189 189 $ hg debugindexstats
190 190 abort: debugindexstats only works with native C code
191 191 [255]
192 192 #endif
193 193 #if reporevlogstore no-pure no-rust
194 194 $ hg debugindexstats
195 195 node trie capacity: 4
196 196 node trie count: 2
197 197 node trie depth: 1
198 198 node trie last rev scanned: -1 (no-rust !)
199 199 node trie last rev scanned: 3 (rust !)
200 200 node trie lookups: 4 (no-rust !)
201 201 node trie lookups: 2 (rust !)
202 202 node trie misses: 1
203 203 node trie splits: 1
204 204 revs in memory: 3
205 205 #endif
206 206
207 207 #if reporevlogstore no-pure
208 208 $ hg debugdeltachain -m --all-info
209 209 rev p1 p2 chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio readsize largestblk rddensity srchunks
210 210 0 -1 -1 1 1 -1 base 44 43 44 1.02326 44 0 0.00000 44 44 1.00000 1
211 211 1 0 -1 2 1 -1 base 0 0 0 0.00000 0 0 0.00000 0 0 1.00000 1
212 212 2 1 -1 3 1 -1 base 44 43 44 1.02326 44 0 0.00000 44 44 1.00000 1
213 213
214 214 $ hg debugdeltachain -m -T '{rev} {chainid} {chainlen}\n'
215 215 0 1 1
216 216 1 2 1
217 217 2 3 1
218 218
219 219 $ hg debugdeltachain -m -Tjson --size-info
220 220 [
221 221 {
222 222 "chainid": 1,
223 223 "chainlen": 1,
224 224 "chainratio": 1.0232558139534884,
225 225 "chainsize": 44,
226 226 "compsize": 44,
227 227 "deltatype": "base",
228 228 "p1": -1,
229 229 "p2": -1,
230 230 "prevrev": -1,
231 231 "rev": 0,
232 232 "uncompsize": 43
233 233 },
234 234 {
235 235 "chainid": 2,
236 236 "chainlen": 1,
237 237 "chainratio": 0,
238 238 "chainsize": 0,
239 239 "compsize": 0,
240 240 "deltatype": "base",
241 241 "p1": 0,
242 242 "p2": -1,
243 243 "prevrev": -1,
244 244 "rev": 1,
245 245 "uncompsize": 0
246 246 },
247 247 {
248 248 "chainid": 3,
249 249 "chainlen": 1,
250 250 "chainratio": 1.0232558139534884,
251 251 "chainsize": 44,
252 252 "compsize": 44,
253 253 "deltatype": "base",
254 254 "p1": 1,
255 255 "p2": -1,
256 256 "prevrev": -1,
257 257 "rev": 2,
258 258 "uncompsize": 43
259 259 }
260 260 ]
261 261
262 262 $ hg debugdeltachain -m -Tjson --all-info
263 263 [
264 264 {
265 265 "chainid": 1,
266 266 "chainlen": 1,
267 267 "chainratio": 1.0232558139534884,
268 268 "chainsize": 44,
269 269 "compsize": 44,
270 270 "deltatype": "base",
271 271 "extradist": 0,
272 272 "extraratio": 0.0,
273 273 "largestblock": 44,
274 274 "lindist": 44,
275 275 "p1": -1,
276 276 "p2": -1,
277 277 "prevrev": -1,
278 278 "readdensity": 1.0,
279 279 "readsize": 44,
280 280 "rev": 0,
281 281 "srchunks": 1,
282 282 "uncompsize": 43
283 283 },
284 284 {
285 285 "chainid": 2,
286 286 "chainlen": 1,
287 287 "chainratio": 0,
288 288 "chainsize": 0,
289 289 "compsize": 0,
290 290 "deltatype": "base",
291 291 "extradist": 0,
292 292 "extraratio": 0,
293 293 "largestblock": 0,
294 294 "lindist": 0,
295 295 "p1": 0,
296 296 "p2": -1,
297 297 "prevrev": -1,
298 298 "readdensity": 1,
299 299 "readsize": 0,
300 300 "rev": 1,
301 301 "srchunks": 1,
302 302 "uncompsize": 0
303 303 },
304 304 {
305 305 "chainid": 3,
306 306 "chainlen": 1,
307 307 "chainratio": 1.0232558139534884,
308 308 "chainsize": 44,
309 309 "compsize": 44,
310 310 "deltatype": "base",
311 311 "extradist": 0,
312 312 "extraratio": 0.0,
313 313 "largestblock": 44,
314 314 "lindist": 44,
315 315 "p1": 1,
316 316 "p2": -1,
317 317 "prevrev": -1,
318 318 "readdensity": 1.0,
319 319 "readsize": 44,
320 320 "rev": 2,
321 321 "srchunks": 1,
322 322 "uncompsize": 43
323 323 }
324 324 ]
325 325
326 326 debugdelta chain with sparse read enabled
327 327
328 328 $ cat >> $HGRCPATH <<EOF
329 329 > [experimental]
330 330 > sparse-read = True
331 331 > EOF
332 332 $ hg debugdeltachain -m --all-info
333 333 rev p1 p2 chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio readsize largestblk rddensity srchunks
334 334 0 -1 -1 1 1 -1 base 44 43 44 1.02326 44 0 0.00000 44 44 1.00000 1
335 335 1 0 -1 2 1 -1 base 0 0 0 0.00000 0 0 0.00000 0 0 1.00000 1
336 336 2 1 -1 3 1 -1 base 44 43 44 1.02326 44 0 0.00000 44 44 1.00000 1
337 337
338 338 $ hg debugdeltachain -m --sparse-info -T '{rev} {chainid} {chainlen} {readsize} {largestblock} {readdensity}\n'
339 339 0 1 1 44 44 1.0
340 340 1 2 1 0 0 1
341 341 2 3 1 44 44 1.0
342 342
343 343 $ hg debugdeltachain -m -Tjson --sparse-info
344 344 [
345 345 {
346 346 "chainid": 1,
347 347 "chainlen": 1,
348 348 "deltatype": "base",
349 349 "largestblock": 44,
350 350 "p1": -1,
351 351 "p2": -1,
352 352 "prevrev": -1,
353 353 "readdensity": 1.0,
354 354 "readsize": 44,
355 355 "rev": 0,
356 356 "srchunks": 1
357 357 },
358 358 {
359 359 "chainid": 2,
360 360 "chainlen": 1,
361 361 "deltatype": "base",
362 362 "largestblock": 0,
363 363 "p1": 0,
364 364 "p2": -1,
365 365 "prevrev": -1,
366 366 "readdensity": 1,
367 367 "readsize": 0,
368 368 "rev": 1,
369 369 "srchunks": 1
370 370 },
371 371 {
372 372 "chainid": 3,
373 373 "chainlen": 1,
374 374 "deltatype": "base",
375 375 "largestblock": 44,
376 376 "p1": 1,
377 377 "p2": -1,
378 378 "prevrev": -1,
379 379 "readdensity": 1.0,
380 380 "readsize": 44,
381 381 "rev": 2,
382 382 "srchunks": 1
383 383 }
384 384 ]
385 385
386 386 $ hg debugdeltachain -m -Tjson --all-info
387 387 [
388 388 {
389 389 "chainid": 1,
390 390 "chainlen": 1,
391 391 "chainratio": 1.0232558139534884,
392 392 "chainsize": 44,
393 393 "compsize": 44,
394 394 "deltatype": "base",
395 395 "extradist": 0,
396 396 "extraratio": 0.0,
397 397 "largestblock": 44,
398 398 "lindist": 44,
399 399 "p1": -1,
400 400 "p2": -1,
401 401 "prevrev": -1,
402 402 "readdensity": 1.0,
403 403 "readsize": 44,
404 404 "rev": 0,
405 405 "srchunks": 1,
406 406 "uncompsize": 43
407 407 },
408 408 {
409 409 "chainid": 2,
410 410 "chainlen": 1,
411 411 "chainratio": 0,
412 412 "chainsize": 0,
413 413 "compsize": 0,
414 414 "deltatype": "base",
415 415 "extradist": 0,
416 416 "extraratio": 0,
417 417 "largestblock": 0,
418 418 "lindist": 0,
419 419 "p1": 0,
420 420 "p2": -1,
421 421 "prevrev": -1,
422 422 "readdensity": 1,
423 423 "readsize": 0,
424 424 "rev": 1,
425 425 "srchunks": 1,
426 426 "uncompsize": 0
427 427 },
428 428 {
429 429 "chainid": 3,
430 430 "chainlen": 1,
431 431 "chainratio": 1.0232558139534884,
432 432 "chainsize": 44,
433 433 "compsize": 44,
434 434 "deltatype": "base",
435 435 "extradist": 0,
436 436 "extraratio": 0.0,
437 437 "largestblock": 44,
438 438 "lindist": 44,
439 439 "p1": 1,
440 440 "p2": -1,
441 441 "prevrev": -1,
442 442 "readdensity": 1.0,
443 443 "readsize": 44,
444 444 "rev": 2,
445 445 "srchunks": 1,
446 446 "uncompsize": 43
447 447 }
448 448 ]
449 449
450 450 $ printf "This test checks things.\n" >> a
451 451 $ hg ci -m a
452 452 $ hg branch other
453 453 marked working directory as branch other
454 454 (branches are permanent and global, did you want a bookmark?)
455 455 $ for i in `$TESTDIR/seq.py 5`; do
456 456 > printf "shorter ${i}" >> a
457 457 > hg ci -m "a other:$i"
458 458 > hg up -q default
459 459 > printf "for the branch default we want longer chains: ${i}" >> a
460 460 > hg ci -m "a default:$i"
461 461 > hg up -q other
462 462 > done
463 463 $ hg debugdeltachain a -T '{rev} {srchunks}\n' --all-info\
464 464 > --config experimental.sparse-read.density-threshold=0.50 \
465 465 > --config experimental.sparse-read.min-gap-size=0
466 466 0 1
467 467 1 1
468 468 2 1
469 469 3 1
470 470 4 1
471 471 5 1
472 472 6 1
473 473 7 1
474 474 8 1
475 475 9 1
476 476 10 2 (no-zstd !)
477 477 10 1 (zstd !)
478 478 11 1
479 479 $ hg --config extensions.strip= strip --no-backup -r 1
480 480 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
481 481
482 482 Test max chain len
483 483 $ cat >> $HGRCPATH << EOF
484 484 > [format]
485 485 > maxchainlen=4
486 486 > EOF
487 487
488 488 $ printf "This test checks if maxchainlen config value is respected also it can serve as basic test for debugrevlog -d <file>.\n" >> a
489 489 $ hg ci -m a
490 490 $ printf "b\n" >> a
491 491 $ hg ci -m a
492 492 $ printf "c\n" >> a
493 493 $ hg ci -m a
494 494 $ printf "d\n" >> a
495 495 $ hg ci -m a
496 496 $ printf "e\n" >> a
497 497 $ hg ci -m a
498 498 $ printf "f\n" >> a
499 499 $ hg ci -m a
500 500 $ printf 'g\n' >> a
501 501 $ hg ci -m a
502 502 $ printf 'h\n' >> a
503 503 $ hg ci -m a
504 504
505 505 $ hg debugrevlog -d a
506 506 # rev p1rev p2rev start end deltastart base p1 p2 rawsize totalsize compression heads chainlen
507 507 0 -1 -1 0 ??? 0 0 0 0 ??? ???? ? 1 0 (glob)
508 508 1 0 -1 ??? ??? 0 0 0 0 ??? ???? ? 1 1 (glob)
509 509 2 1 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 2 (glob)
510 510 3 2 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 3 (glob)
511 511 4 3 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 4 (glob)
512 512 5 4 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 0 (glob)
513 513 6 5 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 1 (glob)
514 514 7 6 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 2 (glob)
515 515 8 7 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 3 (glob)
516 516 #endif
517 517
518 518 Test debuglocks command:
519 519
520 520 $ hg debuglocks
521 521 lock: free
522 522 wlock: free
523 523
524 524 * Test setting the lock
525 525
526 526 waitlock <file> will wait for file to be created. If it isn't in a reasonable
527 527 amount of time, displays error message and returns 1
528 528 $ waitlock() {
529 529 > start=`date +%s`
530 530 > timeout=5
531 531 > while [ \( ! -f $1 \) -a \( ! -L $1 \) ]; do
532 532 > now=`date +%s`
533 533 > if [ "`expr $now - $start`" -gt $timeout ]; then
534 534 > echo "timeout: $1 was not created in $timeout seconds"
535 535 > return 1
536 536 > fi
537 537 > sleep 0.1
538 538 > done
539 539 > }
540 540 $ dolock() {
541 541 > {
542 542 > waitlock .hg/unlock
543 543 > rm -f .hg/unlock
544 544 > echo y
545 545 > } | hg debuglocks "$@" > /dev/null
546 546 > }
547 547 $ dolock -s &
548 548 $ waitlock .hg/store/lock
549 549
550 550 $ hg debuglocks
551 551 lock: user *, process * (*s) (glob)
552 552 wlock: free
553 553 [1]
554 554 $ touch .hg/unlock
555 555 $ wait
556 556 $ [ -f .hg/store/lock ] || echo "There is no lock"
557 557 There is no lock
558 558
559 559 * Test setting the wlock
560 560
561 561 $ dolock -S &
562 562 $ waitlock .hg/wlock
563 563
564 564 $ hg debuglocks
565 565 lock: free
566 566 wlock: user *, process * (*s) (glob)
567 567 [1]
568 568 $ touch .hg/unlock
569 569 $ wait
570 570 $ [ -f .hg/wlock ] || echo "There is no wlock"
571 571 There is no wlock
572 572
573 573 * Test setting both locks
574 574
575 575 $ dolock -Ss &
576 576 $ waitlock .hg/wlock && waitlock .hg/store/lock
577 577
578 578 $ hg debuglocks
579 579 lock: user *, process * (*s) (glob)
580 580 wlock: user *, process * (*s) (glob)
581 581 [2]
582 582
583 583 * Test failing to set a lock
584 584
585 585 $ hg debuglocks -s
586 586 abort: lock is already held
587 587 [255]
588 588
589 589 $ hg debuglocks -S
590 590 abort: wlock is already held
591 591 [255]
592 592
593 593 $ touch .hg/unlock
594 594 $ wait
595 595
596 596 $ hg debuglocks
597 597 lock: free
598 598 wlock: free
599 599
600 600 * Test forcing the lock
601 601
602 602 $ dolock -s &
603 603 $ waitlock .hg/store/lock
604 604
605 605 $ hg debuglocks
606 606 lock: user *, process * (*s) (glob)
607 607 wlock: free
608 608 [1]
609 609
610 610 $ hg debuglocks -L
611 611
612 612 $ hg debuglocks
613 613 lock: free
614 614 wlock: free
615 615
616 616 $ touch .hg/unlock
617 617 $ wait
618 618
619 619 * Test forcing the wlock
620 620
621 621 $ dolock -S &
622 622 $ waitlock .hg/wlock
623 623
624 624 $ hg debuglocks
625 625 lock: free
626 626 wlock: user *, process * (*s) (glob)
627 627 [1]
628 628
629 629 $ hg debuglocks -W
630 630
631 631 $ hg debuglocks
632 632 lock: free
633 633 wlock: free
634 634
635 635 $ touch .hg/unlock
636 636 $ wait
637 637
638 638 Test WdirUnsupported exception
639 639
640 640 $ hg debugdata -c ffffffffffffffffffffffffffffffffffffffff
641 641 abort: working directory revision cannot be specified
642 642 [255]
643 643
644 644 Test cache warming command
645 645
646 646 $ rm -rf .hg/cache/
647 647 $ hg debugupdatecaches --debug
648 648 updating the branch cache
649 649 $ ls -r .hg/cache/*
650 650 .hg/cache/tags2-served
651 651 .hg/cache/tags2
652 652 .hg/cache/rbc-revs-v1
653 653 .hg/cache/rbc-names-v1
654 654 .hg/cache/hgtagsfnodes1
655 655 .hg/cache/branch2-visible-hidden
656 656 .hg/cache/branch2-visible
657 657 .hg/cache/branch2-served.hidden
658 658 .hg/cache/branch2-served
659 659 .hg/cache/branch2-immutable
660 660 .hg/cache/branch2-base
661 661
662 Test debug::unbundle
663
664 $ hg bundle --exact --rev tip foo.hg
665 1 changesets found
666 $ hg debug::unbundle foo.hg
667 adding changesets
668 adding manifests
669 adding file changes
670 added 0 changesets with 0 changes to 1 files (no-pure !)
671 9 local changesets published (no-pure !)
672 3 local changesets published (pure !)
673 (run 'hg update' to get a working copy)
674
662 675 Test debugcolor
663 676
664 677 #if no-windows
665 678 $ hg debugcolor --style --color always | grep -E 'mode|style|log\.'
666 679 color mode: 'ansi'
667 680 available style:
668 681 \x1b[0;33mlog.changeset\x1b[0m: \x1b[0;33myellow\x1b[0m (esc)
669 682 #endif
670 683
671 684 $ hg debugcolor --style --color never
672 685 color mode: None
673 686 available style:
674 687
675 688 $ cd ..
676 689
677 690 Test internal debugstacktrace command
678 691
679 692 $ cat > debugstacktrace.py << EOF
680 693 > from mercurial import (
681 694 > util,
682 695 > )
683 696 > from mercurial.utils import (
684 697 > procutil,
685 698 > )
686 699 > def f():
687 700 > util.debugstacktrace(f=procutil.stdout)
688 701 > g()
689 702 > def g():
690 703 > util.dst(b'hello from g\\n', skip=1)
691 704 > h()
692 705 > def h():
693 706 > util.dst(b'hi ...\\nfrom h hidden in g', 1, depth=2)
694 707 > f()
695 708 > EOF
696 709 $ "$PYTHON" debugstacktrace.py
697 710 stacktrace at:
698 711 *debugstacktrace.py:15 in * (glob)
699 712 *debugstacktrace.py:8 in f (glob)
700 713 hello from g at:
701 714 *debugstacktrace.py:15 in * (glob)
702 715 *debugstacktrace.py:9 in f (glob)
703 716 hi ...
704 717 from h hidden in g at:
705 718 *debugstacktrace.py:9 in f (glob)
706 719 *debugstacktrace.py:12 in g (glob)
707 720
708 721 Test debugcapabilities command:
709 722
710 723 $ hg debugcapabilities ./debugrevlog/
711 724 Main capabilities:
712 725 branchmap
713 726 $USUAL_BUNDLE2_CAPS$
714 727 getbundle
715 728 known
716 729 lookup
717 730 pushkey
718 731 unbundle
719 732 Bundle2 capabilities:
720 733 HG20
721 734 bookmarks
722 735 changegroup
723 736 01
724 737 02
725 738 03
726 739 checkheads
727 740 related
728 741 digests
729 742 md5
730 743 sha1
731 744 sha512
732 745 error
733 746 abort
734 747 unsupportedcontent
735 748 pushraced
736 749 pushkey
737 750 hgtagsfnodes
738 751 listkeys
739 752 phases
740 753 heads
741 754 pushkey
742 755 remote-changegroup
743 756 http
744 757 https
745 758 stream
746 759 v2
747 760
748 761 Test debugpeer
749 762
750 763 $ hg debugpeer ssh://user@dummy/debugrevlog
751 764 url: ssh://user@dummy/debugrevlog
752 765 local: no
753 766 pushable: yes
754 767
755 768 #if rust
756 769
757 770 $ hg --debug debugpeer ssh://user@dummy/debugrevlog
758 771 running .* ".*[/\\]dummyssh" ['"]user@dummy['"] ['"]hg -R debugrevlog serve --stdio['"] (re)
759 772 devel-peer-request: hello+between
760 773 devel-peer-request: pairs: 81 bytes
761 774 sending hello command
762 775 sending between command
763 776 remote: 473
764 777 remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlog-compression-zstd,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
765 778 remote: 1
766 779 devel-peer-request: protocaps
767 780 devel-peer-request: caps: * bytes (glob)
768 781 sending protocaps command
769 782 url: ssh://user@dummy/debugrevlog
770 783 local: no
771 784 pushable: yes
772 785
773 786 #endif
774 787
775 788 #if no-rust zstd
776 789
777 790 $ hg --debug debugpeer ssh://user@dummy/debugrevlog
778 791 running .* ".*[/\\]dummyssh" ['"]user@dummy['"] ['"]hg -R debugrevlog serve --stdio['"] (re)
779 792 devel-peer-request: hello+between
780 793 devel-peer-request: pairs: 81 bytes
781 794 sending hello command
782 795 sending between command
783 796 remote: 473
784 797 remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlog-compression-zstd,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
785 798 remote: 1
786 799 devel-peer-request: protocaps
787 800 devel-peer-request: caps: * bytes (glob)
788 801 sending protocaps command
789 802 url: ssh://user@dummy/debugrevlog
790 803 local: no
791 804 pushable: yes
792 805
793 806 #endif
794 807
795 808 #if no-rust no-zstd
796 809
797 810 $ hg --debug debugpeer ssh://user@dummy/debugrevlog
798 811 running .* ".*[/\\]dummyssh" ['"]user@dummy['"] ['"]hg -R debugrevlog serve --stdio['"] (re)
799 812 devel-peer-request: hello+between
800 813 devel-peer-request: pairs: 81 bytes
801 814 sending hello command
802 815 sending between command
803 816 remote: 449
804 817 remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
805 818 remote: 1
806 819 devel-peer-request: protocaps
807 820 devel-peer-request: caps: * bytes (glob)
808 821 sending protocaps command
809 822 url: ssh://user@dummy/debugrevlog
810 823 local: no
811 824 pushable: yes
812 825
813 826 #endif
814 827
815 828 Test debugshell
816 829
817 830 $ hg debugshell -c 'ui.write(b"%s\n" % ui.username())'
818 831 test
@@ -1,4106 +1,4108 b''
1 1 Short help:
2 2
3 3 $ hg
4 4 Mercurial Distributed SCM
5 5
6 6 basic commands:
7 7
8 8 add add the specified files on the next commit
9 9 annotate show changeset information by line for each file
10 10 clone make a copy of an existing repository
11 11 commit commit the specified files or all outstanding changes
12 12 diff diff repository (or selected files)
13 13 export dump the header and diffs for one or more changesets
14 14 forget forget the specified files on the next commit
15 15 init create a new repository in the given directory
16 16 log show revision history of entire repository or files
17 17 merge merge another revision into working directory
18 18 pull pull changes from the specified source
19 19 push push changes to the specified destination
20 20 remove remove the specified files on the next commit
21 21 serve start stand-alone webserver
22 22 status show changed files in the working directory
23 23 summary summarize working directory state
24 24 update update working directory (or switch revisions)
25 25
26 26 (use 'hg help' for the full list of commands or 'hg -v' for details)
27 27
28 28 $ hg -q
29 29 add add the specified files on the next commit
30 30 annotate show changeset information by line for each file
31 31 clone make a copy of an existing repository
32 32 commit commit the specified files or all outstanding changes
33 33 diff diff repository (or selected files)
34 34 export dump the header and diffs for one or more changesets
35 35 forget forget the specified files on the next commit
36 36 init create a new repository in the given directory
37 37 log show revision history of entire repository or files
38 38 merge merge another revision into working directory
39 39 pull pull changes from the specified source
40 40 push push changes to the specified destination
41 41 remove remove the specified files on the next commit
42 42 serve start stand-alone webserver
43 43 status show changed files in the working directory
44 44 summary summarize working directory state
45 45 update update working directory (or switch revisions)
46 46
47 47 Extra extensions will be printed in help output in a non-reliable order since
48 48 the extension is unknown.
49 49 #if no-extraextensions
50 50
51 51 $ hg help
52 52 Mercurial Distributed SCM
53 53
54 54 list of commands:
55 55
56 56 Repository creation:
57 57
58 58 clone make a copy of an existing repository
59 59 init create a new repository in the given directory
60 60
61 61 Remote repository management:
62 62
63 63 incoming show new changesets found in source
64 64 outgoing show changesets not found in the destination
65 65 paths show aliases for remote repositories
66 66 pull pull changes from the specified source
67 67 push push changes to the specified destination
68 68 serve start stand-alone webserver
69 69
70 70 Change creation:
71 71
72 72 commit commit the specified files or all outstanding changes
73 73
74 74 Change manipulation:
75 75
76 76 backout reverse effect of earlier changeset
77 77 graft copy changes from other branches onto the current branch
78 78 merge merge another revision into working directory
79 79
80 80 Change organization:
81 81
82 82 bookmarks create a new bookmark or list existing bookmarks
83 83 branch set or show the current branch name
84 84 branches list repository named branches
85 85 phase set or show the current phase name
86 86 tag add one or more tags for the current or given revision
87 87 tags list repository tags
88 88
89 89 File content management:
90 90
91 91 annotate show changeset information by line for each file
92 92 cat output the current or given revision of files
93 93 copy mark files as copied for the next commit
94 94 diff diff repository (or selected files)
95 95 grep search for a pattern in specified files
96 96
97 97 Change navigation:
98 98
99 99 bisect subdivision search of changesets
100 100 heads show branch heads
101 101 identify identify the working directory or specified revision
102 102 log show revision history of entire repository or files
103 103
104 104 Working directory management:
105 105
106 106 add add the specified files on the next commit
107 107 addremove add all new files, delete all missing files
108 108 files list tracked files
109 109 forget forget the specified files on the next commit
110 110 purge removes files not tracked by Mercurial
111 111 remove remove the specified files on the next commit
112 112 rename rename files; equivalent of copy + remove
113 113 resolve redo merges or set/view the merge status of files
114 114 revert restore files to their checkout state
115 115 root print the root (top) of the current working directory
116 116 shelve save and set aside changes from the working directory
117 117 status show changed files in the working directory
118 118 summary summarize working directory state
119 119 unshelve restore a shelved change to the working directory
120 120 update update working directory (or switch revisions)
121 121
122 122 Change import/export:
123 123
124 124 archive create an unversioned archive of a repository revision
125 125 bundle create a bundle file
126 126 export dump the header and diffs for one or more changesets
127 127 import import an ordered set of patches
128 128 unbundle apply one or more bundle files
129 129
130 130 Repository maintenance:
131 131
132 132 admin::verify
133 133 verify the integrity of the repository
134 134 manifest output the current or given revision of the project manifest
135 135 recover roll back an interrupted transaction
136 136 verify verify the integrity of the repository
137 137
138 138 Help:
139 139
140 140 config show combined config settings from all hgrc files
141 141 help show help for a given topic or a help overview
142 142 version output version and copyright information
143 143
144 144 additional help topics:
145 145
146 146 Mercurial identifiers:
147 147
148 148 filesets Specifying File Sets
149 149 hgignore Syntax for Mercurial Ignore Files
150 150 patterns File Name Patterns
151 151 revisions Specifying Revisions
152 152 urls URL Paths
153 153
154 154 Mercurial output:
155 155
156 156 color Colorizing Outputs
157 157 dates Date Formats
158 158 diffs Diff Formats
159 159 templating Template Usage
160 160
161 161 Mercurial configuration:
162 162
163 163 config Configuration Files
164 164 environment Environment Variables
165 165 extensions Using Additional Features
166 166 flags Command-line flags
167 167 hgweb Configuring hgweb
168 168 merge-tools Merge Tools
169 169 pager Pager Support
170 170 rust Rust in Mercurial
171 171
172 172 Concepts:
173 173
174 174 bundlespec Bundle File Formats
175 175 evolution Safely rewriting history (EXPERIMENTAL)
176 176 glossary Glossary
177 177 phases Working with Phases
178 178 subrepos Subrepositories
179 179
180 180 Miscellaneous:
181 181
182 182 deprecated Deprecated Features
183 183 internals Technical implementation topics
184 184 scripting Using Mercurial from scripts and automation
185 185
186 186 (use 'hg help -v' to show built-in aliases and global options)
187 187
188 188 $ hg -q help
189 189 Repository creation:
190 190
191 191 clone make a copy of an existing repository
192 192 init create a new repository in the given directory
193 193
194 194 Remote repository management:
195 195
196 196 incoming show new changesets found in source
197 197 outgoing show changesets not found in the destination
198 198 paths show aliases for remote repositories
199 199 pull pull changes from the specified source
200 200 push push changes to the specified destination
201 201 serve start stand-alone webserver
202 202
203 203 Change creation:
204 204
205 205 commit commit the specified files or all outstanding changes
206 206
207 207 Change manipulation:
208 208
209 209 backout reverse effect of earlier changeset
210 210 graft copy changes from other branches onto the current branch
211 211 merge merge another revision into working directory
212 212
213 213 Change organization:
214 214
215 215 bookmarks create a new bookmark or list existing bookmarks
216 216 branch set or show the current branch name
217 217 branches list repository named branches
218 218 phase set or show the current phase name
219 219 tag add one or more tags for the current or given revision
220 220 tags list repository tags
221 221
222 222 File content management:
223 223
224 224 annotate show changeset information by line for each file
225 225 cat output the current or given revision of files
226 226 copy mark files as copied for the next commit
227 227 diff diff repository (or selected files)
228 228 grep search for a pattern in specified files
229 229
230 230 Change navigation:
231 231
232 232 bisect subdivision search of changesets
233 233 heads show branch heads
234 234 identify identify the working directory or specified revision
235 235 log show revision history of entire repository or files
236 236
237 237 Working directory management:
238 238
239 239 add add the specified files on the next commit
240 240 addremove add all new files, delete all missing files
241 241 files list tracked files
242 242 forget forget the specified files on the next commit
243 243 purge removes files not tracked by Mercurial
244 244 remove remove the specified files on the next commit
245 245 rename rename files; equivalent of copy + remove
246 246 resolve redo merges or set/view the merge status of files
247 247 revert restore files to their checkout state
248 248 root print the root (top) of the current working directory
249 249 shelve save and set aside changes from the working directory
250 250 status show changed files in the working directory
251 251 summary summarize working directory state
252 252 unshelve restore a shelved change to the working directory
253 253 update update working directory (or switch revisions)
254 254
255 255 Change import/export:
256 256
257 257 archive create an unversioned archive of a repository revision
258 258 bundle create a bundle file
259 259 export dump the header and diffs for one or more changesets
260 260 import import an ordered set of patches
261 261 unbundle apply one or more bundle files
262 262
263 263 Repository maintenance:
264 264
265 265 admin::verify
266 266 verify the integrity of the repository
267 267 manifest output the current or given revision of the project manifest
268 268 recover roll back an interrupted transaction
269 269 verify verify the integrity of the repository
270 270
271 271 Help:
272 272
273 273 config show combined config settings from all hgrc files
274 274 help show help for a given topic or a help overview
275 275 version output version and copyright information
276 276
277 277 additional help topics:
278 278
279 279 Mercurial identifiers:
280 280
281 281 filesets Specifying File Sets
282 282 hgignore Syntax for Mercurial Ignore Files
283 283 patterns File Name Patterns
284 284 revisions Specifying Revisions
285 285 urls URL Paths
286 286
287 287 Mercurial output:
288 288
289 289 color Colorizing Outputs
290 290 dates Date Formats
291 291 diffs Diff Formats
292 292 templating Template Usage
293 293
294 294 Mercurial configuration:
295 295
296 296 config Configuration Files
297 297 environment Environment Variables
298 298 extensions Using Additional Features
299 299 flags Command-line flags
300 300 hgweb Configuring hgweb
301 301 merge-tools Merge Tools
302 302 pager Pager Support
303 303 rust Rust in Mercurial
304 304
305 305 Concepts:
306 306
307 307 bundlespec Bundle File Formats
308 308 evolution Safely rewriting history (EXPERIMENTAL)
309 309 glossary Glossary
310 310 phases Working with Phases
311 311 subrepos Subrepositories
312 312
313 313 Miscellaneous:
314 314
315 315 deprecated Deprecated Features
316 316 internals Technical implementation topics
317 317 scripting Using Mercurial from scripts and automation
318 318
319 319 Test extension help:
320 320 $ hg help extensions --config extensions.rebase= --config extensions.children=
321 321 Using Additional Features
322 322 """""""""""""""""""""""""
323 323
324 324 Mercurial has the ability to add new features through the use of
325 325 extensions. Extensions may add new commands, add options to existing
326 326 commands, change the default behavior of commands, or implement hooks.
327 327
328 328 To enable the "foo" extension, either shipped with Mercurial or in the
329 329 Python search path, create an entry for it in your configuration file,
330 330 like this:
331 331
332 332 [extensions]
333 333 foo =
334 334
335 335 You may also specify the full path to an extension:
336 336
337 337 [extensions]
338 338 myfeature = ~/.hgext/myfeature.py
339 339
340 340 See 'hg help config' for more information on configuration files.
341 341
342 342 Extensions are not loaded by default for a variety of reasons: they can
343 343 increase startup overhead; they may be meant for advanced usage only; they
344 344 may provide potentially dangerous abilities (such as letting you destroy
345 345 or modify history); they might not be ready for prime time; or they may
346 346 alter some usual behaviors of stock Mercurial. It is thus up to the user
347 347 to activate extensions as needed.
348 348
349 349 To explicitly disable an extension enabled in a configuration file of
350 350 broader scope, prepend its path with !:
351 351
352 352 [extensions]
353 353 # disabling extension bar residing in /path/to/extension/bar.py
354 354 bar = !/path/to/extension/bar.py
355 355 # ditto, but no path was supplied for extension baz
356 356 baz = !
357 357
358 358 enabled extensions:
359 359
360 360 children command to display child changesets (DEPRECATED)
361 361 rebase command to move sets of revisions to a different ancestor
362 362
363 363 disabled extensions:
364 364
365 365 acl hooks for controlling repository access
366 366 blackbox log repository events to a blackbox for debugging
367 367 bugzilla hooks for integrating with the Bugzilla bug tracker
368 368 censor erase file content at a given revision
369 369 churn command to display statistics about repository history
370 370 clonebundles advertise pre-generated bundles to seed clones
371 371 closehead close arbitrary heads without checking them out first
372 372 convert import revisions from foreign VCS repositories into
373 373 Mercurial
374 374 eol automatically manage newlines in repository files
375 375 extdiff command to allow external programs to compare revisions
376 376 factotum http authentication with factotum
377 377 fastexport export repositories as git fast-import stream
378 378 githelp try mapping git commands to Mercurial commands
379 379 gpg commands to sign and verify changesets
380 380 hgk browse the repository in a graphical way
381 381 highlight syntax highlighting for hgweb (requires Pygments)
382 382 histedit interactive history editing
383 383 keyword expand keywords in tracked files
384 384 largefiles track large binary files
385 385 mq manage a stack of patches
386 386 notify hooks for sending email push notifications
387 387 patchbomb command to send changesets as (a series of) patch emails
388 388 relink recreates hardlinks between repository clones
389 389 schemes extend schemes with shortcuts to repository swarms
390 390 share share a common history between several working directories
391 391 transplant command to transplant changesets from another branch
392 392 win32mbcs allow the use of MBCS paths with problematic encodings
393 393 zeroconf discover and advertise repositories on the local network
394 394
395 395 #endif
396 396
397 397 Verify that deprecated extensions are included if --verbose:
398 398
399 399 $ hg -v help extensions | grep children
400 400 children command to display child changesets (DEPRECATED)
401 401
402 402 Verify that extension keywords appear in help templates
403 403
404 404 $ hg help --config extensions.transplant= templating|grep transplant > /dev/null
405 405
406 406 Test short command list with verbose option
407 407
408 408 $ hg -v help shortlist
409 409 Mercurial Distributed SCM
410 410
411 411 basic commands:
412 412
413 413 abort abort an unfinished operation (EXPERIMENTAL)
414 414 add add the specified files on the next commit
415 415 annotate, blame
416 416 show changeset information by line for each file
417 417 clone make a copy of an existing repository
418 418 commit, ci commit the specified files or all outstanding changes
419 419 continue resumes an interrupted operation (EXPERIMENTAL)
420 420 diff diff repository (or selected files)
421 421 export dump the header and diffs for one or more changesets
422 422 forget forget the specified files on the next commit
423 423 init create a new repository in the given directory
424 424 log, history show revision history of entire repository or files
425 425 merge merge another revision into working directory
426 426 pull pull changes from the specified source
427 427 push push changes to the specified destination
428 428 remove, rm remove the specified files on the next commit
429 429 serve start stand-alone webserver
430 430 status, st show changed files in the working directory
431 431 summary, sum summarize working directory state
432 432 update, up, checkout, co
433 433 update working directory (or switch revisions)
434 434
435 435 global options ([+] can be repeated):
436 436
437 437 -R --repository REPO repository root directory or name of overlay bundle
438 438 file
439 439 --cwd DIR change working directory
440 440 -y --noninteractive do not prompt, automatically pick the first choice for
441 441 all prompts
442 442 -q --quiet suppress output
443 443 -v --verbose enable additional output
444 444 --color TYPE when to colorize (boolean, always, auto, never, or
445 445 debug)
446 446 --config CONFIG [+] set/override config option (use 'section.name=value')
447 447 --debug enable debugging output
448 448 --debugger start debugger
449 449 --encoding ENCODE set the charset encoding (default: ascii)
450 450 --encodingmode MODE set the charset encoding mode (default: strict)
451 451 --traceback always print a traceback on exception
452 452 --time time how long the command takes
453 453 --profile print command execution profile
454 454 --version output version information and exit
455 455 -h --help display help and exit
456 456 --hidden consider hidden changesets
457 457 --pager TYPE when to paginate (boolean, always, auto, or never)
458 458 (default: auto)
459 459
460 460 (use 'hg help' for the full list of commands)
461 461
462 462 $ hg add -h
463 463 hg add [OPTION]... [FILE]...
464 464
465 465 add the specified files on the next commit
466 466
467 467 Schedule files to be version controlled and added to the repository.
468 468
469 469 The files will be added to the repository at the next commit. To undo an
470 470 add before that, see 'hg forget'.
471 471
472 472 If no names are given, add all files to the repository (except files
473 473 matching ".hgignore").
474 474
475 475 Returns 0 if all files are successfully added.
476 476
477 477 options ([+] can be repeated):
478 478
479 479 -I --include PATTERN [+] include names matching the given patterns
480 480 -X --exclude PATTERN [+] exclude names matching the given patterns
481 481 -S --subrepos recurse into subrepositories
482 482 -n --dry-run do not perform actions, just print output
483 483
484 484 (some details hidden, use --verbose to show complete help)
485 485
486 486 Verbose help for add
487 487
488 488 $ hg add -hv
489 489 hg add [OPTION]... [FILE]...
490 490
491 491 add the specified files on the next commit
492 492
493 493 Schedule files to be version controlled and added to the repository.
494 494
495 495 The files will be added to the repository at the next commit. To undo an
496 496 add before that, see 'hg forget'.
497 497
498 498 If no names are given, add all files to the repository (except files
499 499 matching ".hgignore").
500 500
501 501 Examples:
502 502
503 503 - New (unknown) files are added automatically by 'hg add':
504 504
505 505 $ ls
506 506 foo.c
507 507 $ hg status
508 508 ? foo.c
509 509 $ hg add
510 510 adding foo.c
511 511 $ hg status
512 512 A foo.c
513 513
514 514 - Specific files to be added can be specified:
515 515
516 516 $ ls
517 517 bar.c foo.c
518 518 $ hg status
519 519 ? bar.c
520 520 ? foo.c
521 521 $ hg add bar.c
522 522 $ hg status
523 523 A bar.c
524 524 ? foo.c
525 525
526 526 Returns 0 if all files are successfully added.
527 527
528 528 options ([+] can be repeated):
529 529
530 530 -I --include PATTERN [+] include names matching the given patterns
531 531 -X --exclude PATTERN [+] exclude names matching the given patterns
532 532 -S --subrepos recurse into subrepositories
533 533 -n --dry-run do not perform actions, just print output
534 534
535 535 global options ([+] can be repeated):
536 536
537 537 -R --repository REPO repository root directory or name of overlay bundle
538 538 file
539 539 --cwd DIR change working directory
540 540 -y --noninteractive do not prompt, automatically pick the first choice for
541 541 all prompts
542 542 -q --quiet suppress output
543 543 -v --verbose enable additional output
544 544 --color TYPE when to colorize (boolean, always, auto, never, or
545 545 debug)
546 546 --config CONFIG [+] set/override config option (use 'section.name=value')
547 547 --debug enable debugging output
548 548 --debugger start debugger
549 549 --encoding ENCODE set the charset encoding (default: ascii)
550 550 --encodingmode MODE set the charset encoding mode (default: strict)
551 551 --traceback always print a traceback on exception
552 552 --time time how long the command takes
553 553 --profile print command execution profile
554 554 --version output version information and exit
555 555 -h --help display help and exit
556 556 --hidden consider hidden changesets
557 557 --pager TYPE when to paginate (boolean, always, auto, or never)
558 558 (default: auto)
559 559
560 560 Test the textwidth config option
561 561
562 562 $ hg root -h --config ui.textwidth=50
563 563 hg root
564 564
565 565 print the root (top) of the current working
566 566 directory
567 567
568 568 Print the root directory of the current
569 569 repository.
570 570
571 571 Returns 0 on success.
572 572
573 573 options:
574 574
575 575 -T --template TEMPLATE display with template
576 576
577 577 (some details hidden, use --verbose to show
578 578 complete help)
579 579
580 580 Test help option with version option
581 581
582 582 $ hg add -h --version
583 583 Mercurial Distributed SCM (version *) (glob)
584 584 (see https://mercurial-scm.org for more information)
585 585
586 586 Copyright (C) 2005-* Olivia Mackall and others (glob)
587 587 This is free software; see the source for copying conditions. There is NO
588 588 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
589 589
590 590 $ hg add --skjdfks
591 591 hg add: option --skjdfks not recognized
592 592 hg add [OPTION]... [FILE]...
593 593
594 594 add the specified files on the next commit
595 595
596 596 options ([+] can be repeated):
597 597
598 598 -I --include PATTERN [+] include names matching the given patterns
599 599 -X --exclude PATTERN [+] exclude names matching the given patterns
600 600 -S --subrepos recurse into subrepositories
601 601 -n --dry-run do not perform actions, just print output
602 602
603 603 (use 'hg add -h' to show more help)
604 604 [10]
605 605
606 606 Test ambiguous command help
607 607
608 608 $ hg help ad
609 609 list of commands:
610 610
611 611 Working directory management:
612 612
613 613 add add the specified files on the next commit
614 614 addremove add all new files, delete all missing files
615 615
616 616 Repository maintenance:
617 617
618 618 admin::verify
619 619 verify the integrity of the repository
620 620
621 621 (use 'hg help -v ad' to show built-in aliases and global options)
622 622
623 623 Test command without options
624 624
625 625 $ hg help verify
626 626 hg verify
627 627
628 628 verify the integrity of the repository
629 629
630 630 Verify the integrity of the current repository.
631 631
632 632 This will perform an extensive check of the repository's integrity,
633 633 validating the hashes and checksums of each entry in the changelog,
634 634 manifest, and tracked files, as well as the integrity of their crosslinks
635 635 and indices.
636 636
637 637 Please see https://mercurial-scm.org/wiki/RepositoryCorruption for more
638 638 information about recovery from corruption of the repository.
639 639
640 640 For an alternative UI with a lot more control over the verification
641 641 process and better error reporting, try 'hg help admin::verify'.
642 642
643 643 Returns 0 on success, 1 if errors are encountered.
644 644
645 645 options:
646 646
647 647 (some details hidden, use --verbose to show complete help)
648 648
649 649 $ hg help diff
650 650 hg diff [OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...
651 651
652 652 diff repository (or selected files)
653 653
654 654 Show differences between revisions for the specified files.
655 655
656 656 Differences between files are shown using the unified diff format.
657 657
658 658 Note:
659 659 'hg diff' may generate unexpected results for merges, as it will
660 660 default to comparing against the working directory's first parent
661 661 changeset if no revisions are specified. To diff against the conflict
662 662 regions, you can use '--config diff.merge=yes'.
663 663
664 664 By default, the working directory files are compared to its first parent.
665 665 To see the differences from another revision, use --from. To see the
666 666 difference to another revision, use --to. For example, 'hg diff --from .^'
667 667 will show the differences from the working copy's grandparent to the
668 668 working copy, 'hg diff --to .' will show the diff from the working copy to
669 669 its parent (i.e. the reverse of the default), and 'hg diff --from 1.0 --to
670 670 1.2' will show the diff between those two revisions.
671 671
672 672 Alternatively you can specify -c/--change with a revision to see the
673 673 changes in that changeset relative to its first parent (i.e. 'hg diff -c
674 674 42' is equivalent to 'hg diff --from 42^ --to 42')
675 675
676 676 Without the -a/--text option, diff will avoid generating diffs of files it
677 677 detects as binary. With -a, diff will generate a diff anyway, probably
678 678 with undesirable results.
679 679
680 680 Use the -g/--git option to generate diffs in the git extended diff format.
681 681 For more information, read 'hg help diffs'.
682 682
683 683 Returns 0 on success.
684 684
685 685 options ([+] can be repeated):
686 686
687 687 --from REV1 revision to diff from
688 688 --to REV2 revision to diff to
689 689 -c --change REV change made by revision
690 690 -a --text treat all files as text
691 691 -g --git use git extended diff format
692 692 --binary generate binary diffs in git mode (default)
693 693 --nodates omit dates from diff headers
694 694 --noprefix omit a/ and b/ prefixes from filenames
695 695 -p --show-function show which function each change is in
696 696 --reverse produce a diff that undoes the changes
697 697 -w --ignore-all-space ignore white space when comparing lines
698 698 -b --ignore-space-change ignore changes in the amount of white space
699 699 -B --ignore-blank-lines ignore changes whose lines are all blank
700 700 -Z --ignore-space-at-eol ignore changes in whitespace at EOL
701 701 -U --unified NUM number of lines of context to show
702 702 --stat output diffstat-style summary of changes
703 703 --root DIR produce diffs relative to subdirectory
704 704 -I --include PATTERN [+] include names matching the given patterns
705 705 -X --exclude PATTERN [+] exclude names matching the given patterns
706 706 -S --subrepos recurse into subrepositories
707 707
708 708 (some details hidden, use --verbose to show complete help)
709 709
710 710 $ hg help status
711 711 hg status [OPTION]... [FILE]...
712 712
713 713 aliases: st
714 714
715 715 show changed files in the working directory
716 716
717 717 Show status of files in the repository. If names are given, only files
718 718 that match are shown. Files that are clean or ignored or the source of a
719 719 copy/move operation, are not listed unless -c/--clean, -i/--ignored,
720 720 -C/--copies or -A/--all are given. Unless options described with "show
721 721 only ..." are given, the options -mardu are used.
722 722
723 723 Option -q/--quiet hides untracked (unknown and ignored) files unless
724 724 explicitly requested with -u/--unknown or -i/--ignored.
725 725
726 726 Note:
727 727 'hg status' may appear to disagree with diff if permissions have
728 728 changed or a merge has occurred. The standard diff format does not
729 729 report permission changes and diff only reports changes relative to one
730 730 merge parent.
731 731
732 732 If one revision is given, it is used as the base revision. If two
733 733 revisions are given, the differences between them are shown. The --change
734 734 option can also be used as a shortcut to list the changed files of a
735 735 revision from its first parent.
736 736
737 737 The codes used to show the status of files are:
738 738
739 739 M = modified
740 740 A = added
741 741 R = removed
742 742 C = clean
743 743 ! = missing (deleted by non-hg command, but still tracked)
744 744 ? = not tracked
745 745 I = ignored
746 746 = origin of the previous file (with --copies)
747 747
748 748 Returns 0 on success.
749 749
750 750 options ([+] can be repeated):
751 751
752 752 -A --all show status of all files
753 753 -m --modified show only modified files
754 754 -a --added show only added files
755 755 -r --removed show only removed files
756 756 -d --deleted show only missing files
757 757 -c --clean show only files without changes
758 758 -u --unknown show only unknown (not tracked) files
759 759 -i --ignored show only ignored files
760 760 -n --no-status hide status prefix
761 761 -C --copies show source of copied files
762 762 -0 --print0 end filenames with NUL, for use with xargs
763 763 --rev REV [+] show difference from revision
764 764 --change REV list the changed files of a revision
765 765 -I --include PATTERN [+] include names matching the given patterns
766 766 -X --exclude PATTERN [+] exclude names matching the given patterns
767 767 -S --subrepos recurse into subrepositories
768 768 -T --template TEMPLATE display with template
769 769
770 770 (some details hidden, use --verbose to show complete help)
771 771
772 772 $ hg -q help status
773 773 hg status [OPTION]... [FILE]...
774 774
775 775 show changed files in the working directory
776 776
777 777 $ hg help foo
778 778 abort: no such help topic: foo
779 779 (try 'hg help --keyword foo')
780 780 [10]
781 781
782 782 $ hg skjdfks
783 783 hg: unknown command 'skjdfks'
784 784 (use 'hg help' for a list of commands)
785 785 [10]
786 786
787 787 Typoed command gives suggestion
788 788 $ hg puls
789 789 hg: unknown command 'puls'
790 790 (did you mean one of pull, push?)
791 791 [10]
792 792
793 793 Not enabled extension gets suggested
794 794
795 795 $ hg rebase
796 796 hg: unknown command 'rebase'
797 797 'rebase' is provided by the following extension:
798 798
799 799 rebase command to move sets of revisions to a different ancestor
800 800
801 801 (use 'hg help extensions' for information on enabling extensions)
802 802 [10]
803 803
804 804 Disabled extension gets suggested
805 805 $ hg --config extensions.rebase=! rebase
806 806 hg: unknown command 'rebase'
807 807 'rebase' is provided by the following extension:
808 808
809 809 rebase command to move sets of revisions to a different ancestor
810 810
811 811 (use 'hg help extensions' for information on enabling extensions)
812 812 [10]
813 813
814 814 Checking that help adapts based on the config:
815 815
816 816 $ hg help diff --config ui.tweakdefaults=true | grep -E -e '^ *(-g|config)'
817 817 -g --[no-]git use git extended diff format (default: on from
818 818 config)
819 819
820 820 Make sure that we don't run afoul of the help system thinking that
821 821 this is a section and erroring out weirdly.
822 822
823 823 $ hg .log
824 824 hg: unknown command '.log'
825 825 (did you mean log?)
826 826 [10]
827 827
828 828 $ hg log.
829 829 hg: unknown command 'log.'
830 830 (did you mean log?)
831 831 [10]
832 832 $ hg pu.lh
833 833 hg: unknown command 'pu.lh'
834 834 (did you mean one of pull, push?)
835 835 [10]
836 836
837 837 $ cat > helpext.py <<EOF
838 838 > import os
839 839 > from mercurial import commands, fancyopts, registrar
840 840 >
841 841 > def func(arg):
842 842 > return '%sfoo' % arg
843 843 > class customopt(fancyopts.customopt):
844 844 > def newstate(self, oldstate, newparam, abort):
845 845 > return '%sbar' % oldstate
846 846 > cmdtable = {}
847 847 > command = registrar.command(cmdtable)
848 848 >
849 849 > @command(b'nohelp',
850 850 > [(b'', b'longdesc', 3, b'x'*67),
851 851 > (b'n', b'', None, b'normal desc'),
852 852 > (b'', b'newline', b'', b'line1\nline2'),
853 853 > (b'', b'default-off', False, b'enable X'),
854 854 > (b'', b'default-on', True, b'enable Y'),
855 855 > (b'', b'callableopt', func, b'adds foo'),
856 856 > (b'', b'customopt', customopt(''), b'adds bar'),
857 857 > (b'', b'customopt-withdefault', customopt('foo'), b'adds bar')],
858 858 > b'hg nohelp',
859 859 > norepo=True)
860 860 > @command(b'debugoptADV', [(b'', b'aopt', None, b'option is (ADVANCED)')])
861 861 > @command(b'debugoptDEP', [(b'', b'dopt', None, b'option is (DEPRECATED)')])
862 862 > @command(b'debugoptEXP', [(b'', b'eopt', None, b'option is (EXPERIMENTAL)')])
863 863 > def nohelp(ui, *args, **kwargs):
864 864 > pass
865 865 >
866 866 > @command(b'hashelp', [], b'hg hashelp', norepo=True)
867 867 > def hashelp(ui, *args, **kwargs):
868 868 > """Extension command's help"""
869 869 >
870 870 > def uisetup(ui):
871 871 > ui.setconfig(b'alias', b'shellalias', b'!echo hi', b'helpext')
872 872 > ui.setconfig(b'alias', b'hgalias', b'summary', b'helpext')
873 873 > ui.setconfig(b'alias', b'hgalias:doc', b'My doc', b'helpext')
874 874 > ui.setconfig(b'alias', b'hgalias:category', b'navigation', b'helpext')
875 875 > ui.setconfig(b'alias', b'hgaliasnodoc', b'summary', b'helpext')
876 876 >
877 877 > EOF
878 878 $ echo '[extensions]' >> $HGRCPATH
879 879 $ echo "helpext = `pwd`/helpext.py" >> $HGRCPATH
880 880
881 881 Test for aliases
882 882
883 883 $ hg help | grep hgalias
884 884 hgalias My doc
885 885
886 886 $ hg help hgalias
887 887 hg hgalias [--remote]
888 888
889 889 alias for: hg summary
890 890
891 891 My doc
892 892
893 893 defined by: helpext
894 894
895 895 options:
896 896
897 897 --remote check for push and pull
898 898
899 899 (some details hidden, use --verbose to show complete help)
900 900 $ hg help hgaliasnodoc
901 901 hg hgaliasnodoc [--remote]
902 902
903 903 alias for: hg summary
904 904
905 905 summarize working directory state
906 906
907 907 This generates a brief summary of the working directory state, including
908 908 parents, branch, commit status, phase and available updates.
909 909
910 910 With the --remote option, this will check the default paths for incoming
911 911 and outgoing changes. This can be time-consuming.
912 912
913 913 Returns 0 on success.
914 914
915 915 defined by: helpext
916 916
917 917 options:
918 918
919 919 --remote check for push and pull
920 920
921 921 (some details hidden, use --verbose to show complete help)
922 922
923 923 $ hg help shellalias
924 924 hg shellalias
925 925
926 926 shell alias for: echo hi
927 927
928 928 (no help text available)
929 929
930 930 defined by: helpext
931 931
932 932 (some details hidden, use --verbose to show complete help)
933 933
934 934 Test command with no help text
935 935
936 936 $ hg help nohelp
937 937 hg nohelp
938 938
939 939 (no help text available)
940 940
941 941 options:
942 942
943 943 --longdesc VALUE
944 944 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
945 945 xxxxxxxxxxxxxxxxxxxxxxx (default: 3)
946 946 -n -- normal desc
947 947 --newline VALUE line1 line2
948 948 --default-off enable X
949 949 --[no-]default-on enable Y (default: on)
950 950 --callableopt VALUE adds foo
951 951 --customopt VALUE adds bar
952 952 --customopt-withdefault VALUE adds bar (default: foo)
953 953
954 954 (some details hidden, use --verbose to show complete help)
955 955
956 956 Test that default list of commands includes extension commands that have help,
957 957 but not those that don't, except in verbose mode, when a keyword is passed, or
958 958 when help about the extension is requested.
959 959
960 960 #if no-extraextensions
961 961
962 962 $ hg help | grep hashelp
963 963 hashelp Extension command's help
964 964 $ hg help | grep nohelp
965 965 [1]
966 966 $ hg help -v | grep nohelp
967 967 nohelp (no help text available)
968 968
969 969 $ hg help -k nohelp
970 970 Commands:
971 971
972 972 nohelp hg nohelp
973 973
974 974 Extension Commands:
975 975
976 976 nohelp (no help text available)
977 977
978 978 $ hg help helpext
979 979 helpext extension - no help text available
980 980
981 981 list of commands:
982 982
983 983 hashelp Extension command's help
984 984 nohelp (no help text available)
985 985
986 986 (use 'hg help -v helpext' to show built-in aliases and global options)
987 987
988 988 #endif
989 989
990 990 Test list of internal help commands
991 991
992 992 $ hg help debug
993 993 debug commands (internal and unsupported):
994 994
995 995 debug-delta-find
996 996 display the computation to get to a valid delta for storing REV
997 997 debug-repair-issue6528
998 998 find affected revisions and repair them. See issue6528 for more
999 999 details.
1000 1000 debug-revlog-index
1001 1001 dump index data for a revlog
1002 1002 debug-revlog-stats
1003 1003 display statistics about revlogs in the store
1004 1004 debug::stable-tail-sort
1005 1005 display the stable-tail sort of the ancestors of a given node
1006 1006 debug::stable-tail-sort-leaps
1007 1007 display the leaps in the stable-tail sort of a node, one per
1008 1008 line
1009 debug::unbundle
1010 same as 'hg unbundle', but pretent to come from a push
1009 1011 debugancestor
1010 1012 find the ancestor revision of two revisions in a given index
1011 1013 debugantivirusrunning
1012 1014 attempt to trigger an antivirus scanner to see if one is active
1013 1015 debugapplystreamclonebundle
1014 1016 apply a stream clone bundle file
1015 1017 debugbackupbundle
1016 1018 lists the changesets available in backup bundles
1017 1019 debugbuilddag
1018 1020 builds a repo with a given DAG from scratch in the current
1019 1021 empty repo
1020 1022 debugbundle lists the contents of a bundle
1021 1023 debugcapabilities
1022 1024 lists the capabilities of a remote peer
1023 1025 debugchangedfiles
1024 1026 list the stored files changes for a revision
1025 1027 debugcheckstate
1026 1028 validate the correctness of the current dirstate
1027 1029 debugcolor show available color, effects or style
1028 1030 debugcommands
1029 1031 list all available commands and options
1030 1032 debugcomplete
1031 1033 returns the completion list associated with the given command
1032 1034 debugcreatestreamclonebundle
1033 1035 create a stream clone bundle file
1034 1036 debugdag format the changelog or an index DAG as a concise textual
1035 1037 description
1036 1038 debugdata dump the contents of a data file revision
1037 1039 debugdate parse and display a date
1038 1040 debugdeltachain
1039 1041 dump information about delta chains in a revlog
1040 1042 debugdirstate
1041 1043 show the contents of the current dirstate
1042 1044 debugdirstateignorepatternshash
1043 1045 show the hash of ignore patterns stored in dirstate if v2,
1044 1046 debugdiscovery
1045 1047 runs the changeset discovery protocol in isolation
1046 1048 debugdownload
1047 1049 download a resource using Mercurial logic and config
1048 1050 debugextensions
1049 1051 show information about active extensions
1050 1052 debugfileset parse and apply a fileset specification
1051 1053 debugformat display format information about the current repository
1052 1054 debugfsinfo show information detected about current filesystem
1053 1055 debuggetbundle
1054 1056 retrieves a bundle from a repo
1055 1057 debugignore display the combined ignore pattern and information about
1056 1058 ignored files
1057 1059 debugindexdot
1058 1060 dump an index DAG as a graphviz dot file
1059 1061 debugindexstats
1060 1062 show stats related to the changelog index
1061 1063 debuginstall test Mercurial installation
1062 1064 debugknown test whether node ids are known to a repo
1063 1065 debuglocks show or modify state of locks
1064 1066 debugmanifestfulltextcache
1065 1067 show, clear or amend the contents of the manifest fulltext
1066 1068 cache
1067 1069 debugmergestate
1068 1070 print merge state
1069 1071 debugnamecomplete
1070 1072 complete "names" - tags, open branch names, bookmark names
1071 1073 debugnodemap write and inspect on disk nodemap
1072 1074 debugobsolete
1073 1075 create arbitrary obsolete marker
1074 1076 debugoptADV (no help text available)
1075 1077 debugoptDEP (no help text available)
1076 1078 debugoptEXP (no help text available)
1077 1079 debugp1copies
1078 1080 dump copy information compared to p1
1079 1081 debugp2copies
1080 1082 dump copy information compared to p2
1081 1083 debugpathcomplete
1082 1084 complete part or all of a tracked path
1083 1085 debugpathcopies
1084 1086 show copies between two revisions
1085 1087 debugpeer establish a connection to a peer repository
1086 1088 debugpickmergetool
1087 1089 examine which merge tool is chosen for specified file
1088 1090 debugpushkey access the pushkey key/value protocol
1089 1091 debugpvec (no help text available)
1090 1092 debugrebuilddirstate
1091 1093 rebuild the dirstate as it would look like for the given
1092 1094 revision
1093 1095 debugrebuildfncache
1094 1096 rebuild the fncache file
1095 1097 debugrename dump rename information
1096 1098 debugrequires
1097 1099 print the current repo requirements
1098 1100 debugrevlog show data and statistics about a revlog
1099 1101 debugrevlogindex
1100 1102 dump the contents of a revlog index
1101 1103 debugrevspec parse and apply a revision specification
1102 1104 debugserve run a server with advanced settings
1103 1105 debugsetparents
1104 1106 manually set the parents of the current working directory
1105 1107 (DANGEROUS)
1106 1108 debugshell run an interactive Python interpreter
1107 1109 debugsidedata
1108 1110 dump the side data for a cl/manifest/file revision
1109 1111 debugssl test a secure connection to a server
1110 1112 debugstrip strip changesets and all their descendants from the repository
1111 1113 debugsub (no help text available)
1112 1114 debugsuccessorssets
1113 1115 show set of successors for revision
1114 1116 debugtagscache
1115 1117 display the contents of .hg/cache/hgtagsfnodes1
1116 1118 debugtemplate
1117 1119 parse and apply a template
1118 1120 debuguigetpass
1119 1121 show prompt to type password
1120 1122 debuguiprompt
1121 1123 show plain prompt
1122 1124 debugupdatecaches
1123 1125 warm all known caches in the repository
1124 1126 debugupgraderepo
1125 1127 upgrade a repository to use different features
1126 1128 debugwalk show how files match on given patterns
1127 1129 debugwhyunstable
1128 1130 explain instabilities of a changeset
1129 1131 debugwireargs
1130 1132 (no help text available)
1131 1133 debugwireproto
1132 1134 send wire protocol commands to a server
1133 1135
1134 1136 (use 'hg help -v debug' to show built-in aliases and global options)
1135 1137
1136 1138 internals topic renders index of available sub-topics
1137 1139
1138 1140 $ hg help internals
1139 1141 Technical implementation topics
1140 1142 """""""""""""""""""""""""""""""
1141 1143
1142 1144 To access a subtopic, use "hg help internals.{subtopic-name}"
1143 1145
1144 1146 bid-merge Bid Merge Algorithm
1145 1147 bundle2 Bundle2
1146 1148 bundles Bundles
1147 1149 cbor CBOR
1148 1150 censor Censor
1149 1151 changegroups Changegroups
1150 1152 config Config Registrar
1151 1153 dirstate-v2 dirstate-v2 file format
1152 1154 extensions Extension API
1153 1155 mergestate Mergestate
1154 1156 requirements Repository Requirements
1155 1157 revlogs Revision Logs
1156 1158 wireprotocol Wire Protocol
1157 1159 wireprotocolrpc
1158 1160 Wire Protocol RPC
1159 1161 wireprotocolv2
1160 1162 Wire Protocol Version 2
1161 1163
1162 1164 sub-topics can be accessed
1163 1165
1164 1166 $ hg help internals.changegroups
1165 1167 Changegroups
1166 1168 """"""""""""
1167 1169
1168 1170 Changegroups are representations of repository revlog data, specifically
1169 1171 the changelog data, root/flat manifest data, treemanifest data, and
1170 1172 filelogs.
1171 1173
1172 1174 There are 4 versions of changegroups: "1", "2", "3" and "4". From a high-
1173 1175 level, versions "1" and "2" are almost exactly the same, with the only
1174 1176 difference being an additional item in the *delta header*. Version "3"
1175 1177 adds support for storage flags in the *delta header* and optionally
1176 1178 exchanging treemanifests (enabled by setting an option on the
1177 1179 "changegroup" part in the bundle2). Version "4" adds support for
1178 1180 exchanging sidedata (additional revision metadata not part of the digest).
1179 1181
1180 1182 Changegroups when not exchanging treemanifests consist of 3 logical
1181 1183 segments:
1182 1184
1183 1185 +---------------------------------+
1184 1186 | | | |
1185 1187 | changeset | manifest | filelogs |
1186 1188 | | | |
1187 1189 | | | |
1188 1190 +---------------------------------+
1189 1191
1190 1192 When exchanging treemanifests, there are 4 logical segments:
1191 1193
1192 1194 +-------------------------------------------------+
1193 1195 | | | | |
1194 1196 | changeset | root | treemanifests | filelogs |
1195 1197 | | manifest | | |
1196 1198 | | | | |
1197 1199 +-------------------------------------------------+
1198 1200
1199 1201 The principle building block of each segment is a *chunk*. A *chunk* is a
1200 1202 framed piece of data:
1201 1203
1202 1204 +---------------------------------------+
1203 1205 | | |
1204 1206 | length | data |
1205 1207 | (4 bytes) | (<length - 4> bytes) |
1206 1208 | | |
1207 1209 +---------------------------------------+
1208 1210
1209 1211 All integers are big-endian signed integers. Each chunk starts with a
1210 1212 32-bit integer indicating the length of the entire chunk (including the
1211 1213 length field itself).
1212 1214
1213 1215 There is a special case chunk that has a value of 0 for the length
1214 1216 ("0x00000000"). We call this an *empty chunk*.
1215 1217
1216 1218 Delta Groups
1217 1219 ============
1218 1220
1219 1221 A *delta group* expresses the content of a revlog as a series of deltas,
1220 1222 or patches against previous revisions.
1221 1223
1222 1224 Delta groups consist of 0 or more *chunks* followed by the *empty chunk*
1223 1225 to signal the end of the delta group:
1224 1226
1225 1227 +------------------------------------------------------------------------+
1226 1228 | | | | | |
1227 1229 | chunk0 length | chunk0 data | chunk1 length | chunk1 data | 0x0 |
1228 1230 | (4 bytes) | (various) | (4 bytes) | (various) | (4 bytes) |
1229 1231 | | | | | |
1230 1232 +------------------------------------------------------------------------+
1231 1233
1232 1234 Each *chunk*'s data consists of the following:
1233 1235
1234 1236 +---------------------------------------+
1235 1237 | | |
1236 1238 | delta header | delta data |
1237 1239 | (various by version) | (various) |
1238 1240 | | |
1239 1241 +---------------------------------------+
1240 1242
1241 1243 The *delta data* is a series of *delta*s that describe a diff from an
1242 1244 existing entry (either that the recipient already has, or previously
1243 1245 specified in the bundle/changegroup).
1244 1246
1245 1247 The *delta header* is different between versions "1", "2", "3" and "4" of
1246 1248 the changegroup format.
1247 1249
1248 1250 Version 1 (headerlen=80):
1249 1251
1250 1252 +------------------------------------------------------+
1251 1253 | | | | |
1252 1254 | node | p1 node | p2 node | link node |
1253 1255 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
1254 1256 | | | | |
1255 1257 +------------------------------------------------------+
1256 1258
1257 1259 Version 2 (headerlen=100):
1258 1260
1259 1261 +------------------------------------------------------------------+
1260 1262 | | | | | |
1261 1263 | node | p1 node | p2 node | base node | link node |
1262 1264 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
1263 1265 | | | | | |
1264 1266 +------------------------------------------------------------------+
1265 1267
1266 1268 Version 3 (headerlen=102):
1267 1269
1268 1270 +------------------------------------------------------------------------------+
1269 1271 | | | | | | |
1270 1272 | node | p1 node | p2 node | base node | link node | flags |
1271 1273 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (2 bytes) |
1272 1274 | | | | | | |
1273 1275 +------------------------------------------------------------------------------+
1274 1276
1275 1277 Version 4 (headerlen=103):
1276 1278
1277 1279 +------------------------------------------------------------------------------+----------+
1278 1280 | | | | | | | |
1279 1281 | node | p1 node | p2 node | base node | link node | flags | pflags |
1280 1282 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (2 bytes) | (1 byte) |
1281 1283 | | | | | | | |
1282 1284 +------------------------------------------------------------------------------+----------+
1283 1285
1284 1286 The *delta data* consists of "chunklen - 4 - headerlen" bytes, which
1285 1287 contain a series of *delta*s, densely packed (no separators). These deltas
1286 1288 describe a diff from an existing entry (either that the recipient already
1287 1289 has, or previously specified in the bundle/changegroup). The format is
1288 1290 described more fully in "hg help internals.bdiff", but briefly:
1289 1291
1290 1292 +---------------------------------------------------------------+
1291 1293 | | | | |
1292 1294 | start offset | end offset | new length | content |
1293 1295 | (4 bytes) | (4 bytes) | (4 bytes) | (<new length> bytes) |
1294 1296 | | | | |
1295 1297 +---------------------------------------------------------------+
1296 1298
1297 1299 Please note that the length field in the delta data does *not* include
1298 1300 itself.
1299 1301
1300 1302 In version 1, the delta is always applied against the previous node from
1301 1303 the changegroup or the first parent if this is the first entry in the
1302 1304 changegroup.
1303 1305
1304 1306 In version 2 and up, the delta base node is encoded in the entry in the
1305 1307 changegroup. This allows the delta to be expressed against any parent,
1306 1308 which can result in smaller deltas and more efficient encoding of data.
1307 1309
1308 1310 The *flags* field holds bitwise flags affecting the processing of revision
1309 1311 data. The following flags are defined:
1310 1312
1311 1313 32768
1312 1314 Censored revision. The revision's fulltext has been replaced by censor
1313 1315 metadata. May only occur on file revisions.
1314 1316
1315 1317 16384
1316 1318 Ellipsis revision. Revision hash does not match data (likely due to
1317 1319 rewritten parents).
1318 1320
1319 1321 8192
1320 1322 Externally stored. The revision fulltext contains "key:value" "\n"
1321 1323 delimited metadata defining an object stored elsewhere. Used by the LFS
1322 1324 extension.
1323 1325
1324 1326 4096
1325 1327 Contains copy information. This revision changes files in a way that
1326 1328 could affect copy tracing. This does *not* affect changegroup handling,
1327 1329 but is relevant for other parts of Mercurial.
1328 1330
1329 1331 For historical reasons, the integer values are identical to revlog version
1330 1332 1 per-revision storage flags and correspond to bits being set in this
1331 1333 2-byte field. Bits were allocated starting from the most-significant bit,
1332 1334 hence the reverse ordering and allocation of these flags.
1333 1335
1334 1336 The *pflags* (protocol flags) field holds bitwise flags affecting the
1335 1337 protocol itself. They are first in the header since they may affect the
1336 1338 handling of the rest of the fields in a future version. They are defined
1337 1339 as such:
1338 1340
1339 1341 1 indicates whether to read a chunk of sidedata (of variable length) right
1340 1342 after the revision flags.
1341 1343
1342 1344 Changeset Segment
1343 1345 =================
1344 1346
1345 1347 The *changeset segment* consists of a single *delta group* holding
1346 1348 changelog data. The *empty chunk* at the end of the *delta group* denotes
1347 1349 the boundary to the *manifest segment*.
1348 1350
1349 1351 Manifest Segment
1350 1352 ================
1351 1353
1352 1354 The *manifest segment* consists of a single *delta group* holding manifest
1353 1355 data. If treemanifests are in use, it contains only the manifest for the
1354 1356 root directory of the repository. Otherwise, it contains the entire
1355 1357 manifest data. The *empty chunk* at the end of the *delta group* denotes
1356 1358 the boundary to the next segment (either the *treemanifests segment* or
1357 1359 the *filelogs segment*, depending on version and the request options).
1358 1360
1359 1361 Treemanifests Segment
1360 1362 ---------------------
1361 1363
1362 1364 The *treemanifests segment* only exists in changegroup version "3" and
1363 1365 "4", and only if the 'treemanifest' param is part of the bundle2
1364 1366 changegroup part (it is not possible to use changegroup version 3 or 4
1365 1367 outside of bundle2). Aside from the filenames in the *treemanifests
1366 1368 segment* containing a trailing "/" character, it behaves identically to
1367 1369 the *filelogs segment* (see below). The final sub-segment is followed by
1368 1370 an *empty chunk* (logically, a sub-segment with filename size 0). This
1369 1371 denotes the boundary to the *filelogs segment*.
1370 1372
1371 1373 Filelogs Segment
1372 1374 ================
1373 1375
1374 1376 The *filelogs segment* consists of multiple sub-segments, each
1375 1377 corresponding to an individual file whose data is being described:
1376 1378
1377 1379 +--------------------------------------------------+
1378 1380 | | | | | |
1379 1381 | filelog0 | filelog1 | filelog2 | ... | 0x0 |
1380 1382 | | | | | (4 bytes) |
1381 1383 | | | | | |
1382 1384 +--------------------------------------------------+
1383 1385
1384 1386 The final filelog sub-segment is followed by an *empty chunk* (logically,
1385 1387 a sub-segment with filename size 0). This denotes the end of the segment
1386 1388 and of the overall changegroup.
1387 1389
1388 1390 Each filelog sub-segment consists of the following:
1389 1391
1390 1392 +------------------------------------------------------+
1391 1393 | | | |
1392 1394 | filename length | filename | delta group |
1393 1395 | (4 bytes) | (<length - 4> bytes) | (various) |
1394 1396 | | | |
1395 1397 +------------------------------------------------------+
1396 1398
1397 1399 That is, a *chunk* consisting of the filename (not terminated or padded)
1398 1400 followed by N chunks constituting the *delta group* for this file. The
1399 1401 *empty chunk* at the end of each *delta group* denotes the boundary to the
1400 1402 next filelog sub-segment.
1401 1403
1402 1404 non-existent subtopics print an error
1403 1405
1404 1406 $ hg help internals.foo
1405 1407 abort: no such help topic: internals.foo
1406 1408 (try 'hg help --keyword foo')
1407 1409 [10]
1408 1410
1409 1411 test advanced, deprecated and experimental options are hidden in command help
1410 1412 $ hg help debugoptADV
1411 1413 hg debugoptADV
1412 1414
1413 1415 (no help text available)
1414 1416
1415 1417 options:
1416 1418
1417 1419 (some details hidden, use --verbose to show complete help)
1418 1420 $ hg help debugoptDEP
1419 1421 hg debugoptDEP
1420 1422
1421 1423 (no help text available)
1422 1424
1423 1425 options:
1424 1426
1425 1427 (some details hidden, use --verbose to show complete help)
1426 1428
1427 1429 $ hg help debugoptEXP
1428 1430 hg debugoptEXP
1429 1431
1430 1432 (no help text available)
1431 1433
1432 1434 options:
1433 1435
1434 1436 (some details hidden, use --verbose to show complete help)
1435 1437
1436 1438 test advanced, deprecated and experimental options are shown with -v
1437 1439 $ hg help -v debugoptADV | grep aopt
1438 1440 --aopt option is (ADVANCED)
1439 1441 $ hg help -v debugoptDEP | grep dopt
1440 1442 --dopt option is (DEPRECATED)
1441 1443 $ hg help -v debugoptEXP | grep eopt
1442 1444 --eopt option is (EXPERIMENTAL)
1443 1445
1444 1446 #if gettext
1445 1447 test deprecated option is hidden with translation with untranslated description
1446 1448 (use many globy for not failing on changed transaction)
1447 1449 $ LANGUAGE=sv hg help debugoptDEP
1448 1450 hg debugoptDEP
1449 1451
1450 1452 (*) (glob)
1451 1453
1452 1454 options:
1453 1455
1454 1456 (some details hidden, use --verbose to show complete help)
1455 1457 #endif
1456 1458
1457 1459 Test commands that collide with topics (issue4240)
1458 1460
1459 1461 $ hg config -hq
1460 1462 hg config [-u] [NAME]...
1461 1463
1462 1464 show combined config settings from all hgrc files
1463 1465 $ hg showconfig -hq
1464 1466 hg config [-u] [NAME]...
1465 1467
1466 1468 show combined config settings from all hgrc files
1467 1469
1468 1470 Test a help topic
1469 1471
1470 1472 $ hg help dates
1471 1473 Date Formats
1472 1474 """"""""""""
1473 1475
1474 1476 Some commands allow the user to specify a date, e.g.:
1475 1477
1476 1478 - backout, commit, import, tag: Specify the commit date.
1477 1479 - log, revert, update: Select revision(s) by date.
1478 1480
1479 1481 Many date formats are valid. Here are some examples:
1480 1482
1481 1483 - "Wed Dec 6 13:18:29 2006" (local timezone assumed)
1482 1484 - "Dec 6 13:18 -0600" (year assumed, time offset provided)
1483 1485 - "Dec 6 13:18 UTC" (UTC and GMT are aliases for +0000)
1484 1486 - "Dec 6" (midnight)
1485 1487 - "13:18" (today assumed)
1486 1488 - "3:39" (3:39AM assumed)
1487 1489 - "3:39pm" (15:39)
1488 1490 - "2006-12-06 13:18:29" (ISO 8601 format)
1489 1491 - "2006-12-6 13:18"
1490 1492 - "2006-12-6"
1491 1493 - "12-6"
1492 1494 - "12/6"
1493 1495 - "12/6/6" (Dec 6 2006)
1494 1496 - "today" (midnight)
1495 1497 - "yesterday" (midnight)
1496 1498 - "now" - right now
1497 1499
1498 1500 Lastly, there is Mercurial's internal format:
1499 1501
1500 1502 - "1165411109 0" (Wed Dec 6 13:18:29 2006 UTC)
1501 1503
1502 1504 This is the internal representation format for dates. The first number is
1503 1505 the number of seconds since the epoch (1970-01-01 00:00 UTC). The second
1504 1506 is the offset of the local timezone, in seconds west of UTC (negative if
1505 1507 the timezone is east of UTC).
1506 1508
1507 1509 The log command also accepts date ranges:
1508 1510
1509 1511 - "<DATE" - at or before a given date/time
1510 1512 - ">DATE" - on or after a given date/time
1511 1513 - "DATE to DATE" - a date range, inclusive
1512 1514 - "-DAYS" - within a given number of days from today
1513 1515
1514 1516 Test repeated config section name
1515 1517
1516 1518 $ hg help config.host
1517 1519 "http_proxy.host"
1518 1520 Host name and (optional) port of the proxy server, for example
1519 1521 "myproxy:8000".
1520 1522
1521 1523 "smtp.host"
1522 1524 Host name of mail server, e.g. "mail.example.com".
1523 1525
1524 1526
1525 1527 Test section name with dot
1526 1528
1527 1529 $ hg help config.ui.username
1528 1530 "ui.username"
1529 1531 The committer of a changeset created when running "commit". Typically
1530 1532 a person's name and email address, e.g. "Fred Widget
1531 1533 <fred@example.com>". Environment variables in the username are
1532 1534 expanded.
1533 1535
1534 1536 (default: "$EMAIL" or "username@hostname". If the username in hgrc is
1535 1537 empty, e.g. if the system admin set "username =" in the system hgrc,
1536 1538 it has to be specified manually or in a different hgrc file)
1537 1539
1538 1540
1539 1541 $ hg help config.annotate.git
1540 1542 abort: help section not found: config.annotate.git
1541 1543 [10]
1542 1544
1543 1545 $ hg help config.update.check
1544 1546 "commands.update.check"
1545 1547 Determines what level of checking 'hg update' will perform before
1546 1548 moving to a destination revision. Valid values are "abort", "none",
1547 1549 "linear", and "noconflict".
1548 1550
1549 1551 - "abort" always fails if the working directory has uncommitted
1550 1552 changes.
1551 1553 - "none" performs no checking, and may result in a merge with
1552 1554 uncommitted changes.
1553 1555 - "linear" allows any update as long as it follows a straight line in
1554 1556 the revision history, and may trigger a merge with uncommitted
1555 1557 changes.
1556 1558 - "noconflict" will allow any update which would not trigger a merge
1557 1559 with uncommitted changes, if any are present.
1558 1560
1559 1561 (default: "linear")
1560 1562
1561 1563
1562 1564 $ hg help config.commands.update.check
1563 1565 "commands.update.check"
1564 1566 Determines what level of checking 'hg update' will perform before
1565 1567 moving to a destination revision. Valid values are "abort", "none",
1566 1568 "linear", and "noconflict".
1567 1569
1568 1570 - "abort" always fails if the working directory has uncommitted
1569 1571 changes.
1570 1572 - "none" performs no checking, and may result in a merge with
1571 1573 uncommitted changes.
1572 1574 - "linear" allows any update as long as it follows a straight line in
1573 1575 the revision history, and may trigger a merge with uncommitted
1574 1576 changes.
1575 1577 - "noconflict" will allow any update which would not trigger a merge
1576 1578 with uncommitted changes, if any are present.
1577 1579
1578 1580 (default: "linear")
1579 1581
1580 1582
1581 1583 $ hg help config.ommands.update.check
1582 1584 abort: help section not found: config.ommands.update.check
1583 1585 [10]
1584 1586
1585 1587 Unrelated trailing paragraphs shouldn't be included
1586 1588
1587 1589 $ hg help config.extramsg | grep '^$'
1588 1590
1589 1591
1590 1592 Test capitalized section name
1591 1593
1592 1594 $ hg help scripting.HGPLAIN > /dev/null
1593 1595
1594 1596 Help subsection:
1595 1597
1596 1598 $ hg help config.charsets |grep "Email example:" > /dev/null
1597 1599 [1]
1598 1600
1599 1601 Show nested definitions
1600 1602 ("profiling.type"[break]"ls"[break]"stat"[break])
1601 1603
1602 1604 $ hg help config.type | grep -E '^$'|wc -l
1603 1605 \s*3 (re)
1604 1606
1605 1607 $ hg help config.profiling.type.ls
1606 1608 "profiling.type.ls"
1607 1609 Use Python's built-in instrumenting profiler. This profiler works on
1608 1610 all platforms, but each line number it reports is the first line of
1609 1611 a function. This restriction makes it difficult to identify the
1610 1612 expensive parts of a non-trivial function.
1611 1613
1612 1614
1613 1615 Separate sections from subsections
1614 1616
1615 1617 $ hg help config.format | grep -E '^ ("|-)|^\s*$' | uniq
1616 1618 "format"
1617 1619 --------
1618 1620
1619 1621 "usegeneraldelta"
1620 1622
1621 1623 "dotencode"
1622 1624
1623 1625 "usefncache"
1624 1626
1625 1627 "use-dirstate-v2"
1626 1628
1627 1629 "use-dirstate-v2.automatic-upgrade-of-mismatching-repositories"
1628 1630
1629 1631 "use-dirstate-v2.automatic-upgrade-of-mismatching-repositories:quiet"
1630 1632
1631 1633 "use-dirstate-tracked-hint"
1632 1634
1633 1635 "use-dirstate-tracked-hint.automatic-upgrade-of-mismatching-repositories"
1634 1636
1635 1637 "use-dirstate-tracked-hint.automatic-upgrade-of-mismatching-repositories:quiet"
1636 1638
1637 1639 "use-persistent-nodemap"
1638 1640
1639 1641 "use-share-safe"
1640 1642
1641 1643 "use-share-safe.automatic-upgrade-of-mismatching-repositories"
1642 1644
1643 1645 "use-share-safe.automatic-upgrade-of-mismatching-repositories:quiet"
1644 1646
1645 1647 "usestore"
1646 1648
1647 1649 "sparse-revlog"
1648 1650
1649 1651 "revlog-compression"
1650 1652
1651 1653 "bookmarks-in-store"
1652 1654
1653 1655 "profiling"
1654 1656 -----------
1655 1657
1656 1658 "format"
1657 1659
1658 1660 "progress"
1659 1661 ----------
1660 1662
1661 1663 "format"
1662 1664
1663 1665
1664 1666 Last item in help config.*:
1665 1667
1666 1668 $ hg help config.`hg help config|grep '^ "'| \
1667 1669 > tail -1|sed 's![ "]*!!g'`| \
1668 1670 > grep 'hg help -c config' > /dev/null
1669 1671 [1]
1670 1672
1671 1673 note to use help -c for general hg help config:
1672 1674
1673 1675 $ hg help config |grep 'hg help -c config' > /dev/null
1674 1676
1675 1677 Test templating help
1676 1678
1677 1679 $ hg help templating | grep -E '(desc|diffstat|firstline|nonempty) '
1678 1680 desc String. The text of the changeset description.
1679 1681 diffstat String. Statistics of changes with the following format:
1680 1682 firstline Any text. Returns the first line of text.
1681 1683 nonempty Any text. Returns '(none)' if the string is empty.
1682 1684
1683 1685 Test deprecated items
1684 1686
1685 1687 $ hg help -v templating | grep currentbookmark
1686 1688 currentbookmark
1687 1689 $ hg help templating | (grep currentbookmark || true)
1688 1690
1689 1691 Test help hooks
1690 1692
1691 1693 $ cat > helphook1.py <<EOF
1692 1694 > from mercurial import help
1693 1695 >
1694 1696 > def rewrite(ui, topic, doc):
1695 1697 > return doc + b'\nhelphook1\n'
1696 1698 >
1697 1699 > def extsetup(ui):
1698 1700 > help.addtopichook(b'revisions', rewrite)
1699 1701 > EOF
1700 1702 $ cat > helphook2.py <<EOF
1701 1703 > from mercurial import help
1702 1704 >
1703 1705 > def rewrite(ui, topic, doc):
1704 1706 > return doc + b'\nhelphook2\n'
1705 1707 >
1706 1708 > def extsetup(ui):
1707 1709 > help.addtopichook(b'revisions', rewrite)
1708 1710 > EOF
1709 1711 $ echo '[extensions]' >> $HGRCPATH
1710 1712 $ echo "helphook1 = `pwd`/helphook1.py" >> $HGRCPATH
1711 1713 $ echo "helphook2 = `pwd`/helphook2.py" >> $HGRCPATH
1712 1714 $ hg help revsets | grep helphook
1713 1715 helphook1
1714 1716 helphook2
1715 1717
1716 1718 help -c should only show debug --debug
1717 1719
1718 1720 $ hg help -c --debug|grep -E debug|wc -l|grep -E '^\s*0\s*$'
1719 1721 [1]
1720 1722
1721 1723 help -c should only show deprecated for -v
1722 1724
1723 1725 $ hg help -c -v|grep -E DEPRECATED|wc -l|grep -E '^\s*0\s*$'
1724 1726 [1]
1725 1727
1726 1728 Test -s / --system
1727 1729
1728 1730 $ hg help config.files -s windows |grep 'etc/mercurial' | \
1729 1731 > wc -l | sed -e 's/ //g'
1730 1732 0
1731 1733 $ hg help config.files --system unix | grep 'USER' | \
1732 1734 > wc -l | sed -e 's/ //g'
1733 1735 0
1734 1736
1735 1737 Test -e / -c / -k combinations
1736 1738
1737 1739 $ hg help -c|grep -E '^[A-Z].*:|^ debug'
1738 1740 Commands:
1739 1741 $ hg help -e|grep -E '^[A-Z].*:|^ debug'
1740 1742 Extensions:
1741 1743 $ hg help -k|grep -E '^[A-Z].*:|^ debug'
1742 1744 Topics:
1743 1745 Commands:
1744 1746 Extensions:
1745 1747 Extension Commands:
1746 1748 $ hg help -c schemes
1747 1749 abort: no such help topic: schemes
1748 1750 (try 'hg help --keyword schemes')
1749 1751 [10]
1750 1752 $ hg help -e schemes |head -1
1751 1753 schemes extension - extend schemes with shortcuts to repository swarms
1752 1754 $ hg help -c -k dates |grep -E '^(Topics|Extensions|Commands):'
1753 1755 Commands:
1754 1756 $ hg help -e -k a |grep -E '^(Topics|Extensions|Commands):'
1755 1757 Extensions:
1756 1758 $ hg help -e -c -k date |grep -E '^(Topics|Extensions|Commands):'
1757 1759 Extensions:
1758 1760 Commands:
1759 1761 $ hg help -c commit > /dev/null
1760 1762 $ hg help -e -c commit > /dev/null
1761 1763 $ hg help -e commit
1762 1764 abort: no such help topic: commit
1763 1765 (try 'hg help --keyword commit')
1764 1766 [10]
1765 1767
1766 1768 Test keyword search help
1767 1769
1768 1770 $ cat > prefixedname.py <<EOF
1769 1771 > '''matched against word "clone"
1770 1772 > '''
1771 1773 > EOF
1772 1774 $ echo '[extensions]' >> $HGRCPATH
1773 1775 $ echo "dot.dot.prefixedname = `pwd`/prefixedname.py" >> $HGRCPATH
1774 1776 $ hg help -k clone
1775 1777 Topics:
1776 1778
1777 1779 config Configuration Files
1778 1780 extensions Using Additional Features
1779 1781 glossary Glossary
1780 1782 phases Working with Phases
1781 1783 subrepos Subrepositories
1782 1784 urls URL Paths
1783 1785
1784 1786 Commands:
1785 1787
1786 1788 bookmarks create a new bookmark or list existing bookmarks
1787 1789 clone make a copy of an existing repository
1788 1790 paths show aliases for remote repositories
1789 1791 pull pull changes from the specified source
1790 1792 update update working directory (or switch revisions)
1791 1793
1792 1794 Extensions:
1793 1795
1794 1796 clonebundles advertise pre-generated bundles to seed clones
1795 1797 narrow create clones which fetch history data for subset of files
1796 1798 (EXPERIMENTAL)
1797 1799 prefixedname matched against word "clone"
1798 1800 relink recreates hardlinks between repository clones
1799 1801
1800 1802 Extension Commands:
1801 1803
1802 1804 admin::clone-bundles-clear remove existing clone bundle caches
1803 1805 admin::clone-bundles-refresh generate clone bundles according to the
1804 1806 configuration
1805 1807 qclone clone main and patch repository at same time
1806 1808
1807 1809 Test unfound topic
1808 1810
1809 1811 $ hg help nonexistingtopicthatwillneverexisteverever
1810 1812 abort: no such help topic: nonexistingtopicthatwillneverexisteverever
1811 1813 (try 'hg help --keyword nonexistingtopicthatwillneverexisteverever')
1812 1814 [10]
1813 1815
1814 1816 Test unfound keyword
1815 1817
1816 1818 $ hg help --keyword nonexistingwordthatwillneverexisteverever
1817 1819 abort: no matches
1818 1820 (try 'hg help' for a list of topics)
1819 1821 [10]
1820 1822
1821 1823 Test omit indicating for help
1822 1824
1823 1825 $ cat > addverboseitems.py <<EOF
1824 1826 > r'''extension to test omit indicating.
1825 1827 >
1826 1828 > This paragraph is never omitted (for extension)
1827 1829 >
1828 1830 > .. container:: verbose
1829 1831 >
1830 1832 > This paragraph is omitted,
1831 1833 > if :hg:\`help\` is invoked without \`\`-v\`\` (for extension)
1832 1834 >
1833 1835 > This paragraph is never omitted, too (for extension)
1834 1836 > '''
1835 1837 > from mercurial import commands, help
1836 1838 > testtopic = br"""This paragraph is never omitted (for topic).
1837 1839 >
1838 1840 > .. container:: verbose
1839 1841 >
1840 1842 > This paragraph is omitted,
1841 1843 > if :hg:\`help\` is invoked without \`\`-v\`\` (for topic)
1842 1844 >
1843 1845 > This paragraph is never omitted, too (for topic)
1844 1846 > """
1845 1847 > def extsetup(ui):
1846 1848 > help.helptable.append(([b"topic-containing-verbose"],
1847 1849 > b"This is the topic to test omit indicating.",
1848 1850 > lambda ui: testtopic))
1849 1851 > EOF
1850 1852 $ echo '[extensions]' >> $HGRCPATH
1851 1853 $ echo "addverboseitems = `pwd`/addverboseitems.py" >> $HGRCPATH
1852 1854 $ hg help addverboseitems
1853 1855 addverboseitems extension - extension to test omit indicating.
1854 1856
1855 1857 This paragraph is never omitted (for extension)
1856 1858
1857 1859 This paragraph is never omitted, too (for extension)
1858 1860
1859 1861 (some details hidden, use --verbose to show complete help)
1860 1862
1861 1863 no commands defined
1862 1864 $ hg help -v addverboseitems
1863 1865 addverboseitems extension - extension to test omit indicating.
1864 1866
1865 1867 This paragraph is never omitted (for extension)
1866 1868
1867 1869 This paragraph is omitted, if 'hg help' is invoked without "-v" (for
1868 1870 extension)
1869 1871
1870 1872 This paragraph is never omitted, too (for extension)
1871 1873
1872 1874 no commands defined
1873 1875 $ hg help topic-containing-verbose
1874 1876 This is the topic to test omit indicating.
1875 1877 """"""""""""""""""""""""""""""""""""""""""
1876 1878
1877 1879 This paragraph is never omitted (for topic).
1878 1880
1879 1881 This paragraph is never omitted, too (for topic)
1880 1882
1881 1883 (some details hidden, use --verbose to show complete help)
1882 1884 $ hg help -v topic-containing-verbose
1883 1885 This is the topic to test omit indicating.
1884 1886 """"""""""""""""""""""""""""""""""""""""""
1885 1887
1886 1888 This paragraph is never omitted (for topic).
1887 1889
1888 1890 This paragraph is omitted, if 'hg help' is invoked without "-v" (for
1889 1891 topic)
1890 1892
1891 1893 This paragraph is never omitted, too (for topic)
1892 1894
1893 1895 Test section lookup
1894 1896
1895 1897 $ hg help revset.merge
1896 1898 "merge()"
1897 1899 Changeset is a merge changeset.
1898 1900
1899 1901 $ hg help glossary.dag
1900 1902 DAG
1901 1903 The repository of changesets of a distributed version control system
1902 1904 (DVCS) can be described as a directed acyclic graph (DAG), consisting
1903 1905 of nodes and edges, where nodes correspond to changesets and edges
1904 1906 imply a parent -> child relation. This graph can be visualized by
1905 1907 graphical tools such as 'hg log --graph'. In Mercurial, the DAG is
1906 1908 limited by the requirement for children to have at most two parents.
1907 1909
1908 1910
1909 1911 $ hg help hgrc.paths
1910 1912 "paths"
1911 1913 -------
1912 1914
1913 1915 Assigns symbolic names and behavior to repositories.
1914 1916
1915 1917 Options are symbolic names defining the URL or directory that is the
1916 1918 location of the repository. Example:
1917 1919
1918 1920 [paths]
1919 1921 my_server = https://example.com/my_repo
1920 1922 local_path = /home/me/repo
1921 1923
1922 1924 These symbolic names can be used from the command line. To pull from
1923 1925 "my_server": 'hg pull my_server'. To push to "local_path": 'hg push
1924 1926 local_path'. You can check 'hg help urls' for details about valid URLs.
1925 1927
1926 1928 Options containing colons (":") denote sub-options that can influence
1927 1929 behavior for that specific path. Example:
1928 1930
1929 1931 [paths]
1930 1932 my_server = https://example.com/my_path
1931 1933 my_server:pushurl = ssh://example.com/my_path
1932 1934
1933 1935 Paths using the 'path://otherpath' scheme will inherit the sub-options
1934 1936 value from the path they point to.
1935 1937
1936 1938 The following sub-options can be defined:
1937 1939
1938 1940 "multi-urls"
1939 1941 A boolean option. When enabled the value of the '[paths]' entry will be
1940 1942 parsed as a list and the alias will resolve to multiple destination. If
1941 1943 some of the list entry use the 'path://' syntax, the suboption will be
1942 1944 inherited individually.
1943 1945
1944 1946 "pushurl"
1945 1947 The URL to use for push operations. If not defined, the location
1946 1948 defined by the path's main entry is used.
1947 1949
1948 1950 "pushrev"
1949 1951 A revset defining which revisions to push by default.
1950 1952
1951 1953 When 'hg push' is executed without a "-r" argument, the revset defined
1952 1954 by this sub-option is evaluated to determine what to push.
1953 1955
1954 1956 For example, a value of "." will push the working directory's revision
1955 1957 by default.
1956 1958
1957 1959 Revsets specifying bookmarks will not result in the bookmark being
1958 1960 pushed.
1959 1961
1960 1962 "bookmarks.mode"
1961 1963 How bookmark will be dealt during the exchange. It support the following
1962 1964 value
1963 1965
1964 1966 - "default": the default behavior, local and remote bookmarks are
1965 1967 "merged" on push/pull.
1966 1968 - "mirror": when pulling, replace local bookmarks by remote bookmarks.
1967 1969 This is useful to replicate a repository, or as an optimization.
1968 1970 - "ignore": ignore bookmarks during exchange. (This currently only
1969 1971 affect pulling)
1970 1972
1971 1973 The following special named paths exist:
1972 1974
1973 1975 "default"
1974 1976 The URL or directory to use when no source or remote is specified.
1975 1977
1976 1978 'hg clone' will automatically define this path to the location the
1977 1979 repository was cloned from.
1978 1980
1979 1981 "default-push"
1980 1982 (deprecated) The URL or directory for the default 'hg push' location.
1981 1983 "default:pushurl" should be used instead.
1982 1984
1983 1985 $ hg help glossary.mcguffin
1984 1986 abort: help section not found: glossary.mcguffin
1985 1987 [10]
1986 1988
1987 1989 $ hg help glossary.mc.guffin
1988 1990 abort: help section not found: glossary.mc.guffin
1989 1991 [10]
1990 1992
1991 1993 $ hg help template.files
1992 1994 files List of strings. All files modified, added, or removed by
1993 1995 this changeset.
1994 1996 files(pattern)
1995 1997 All files of the current changeset matching the pattern. See
1996 1998 'hg help patterns'.
1997 1999
1998 2000 Test section lookup by translated message
1999 2001
2000 2002 str.lower() instead of encoding.lower(str) on translated message might
2001 2003 make message meaningless, because some encoding uses 0x41(A) - 0x5a(Z)
2002 2004 as the second or later byte of multi-byte character.
2003 2005
2004 2006 For example, "\x8bL\x98^" (translation of "record" in ja_JP.cp932)
2005 2007 contains 0x4c (L). str.lower() replaces 0x4c(L) by 0x6c(l) and this
2006 2008 replacement makes message meaningless.
2007 2009
2008 2010 This tests that section lookup by translated string isn't broken by
2009 2011 such str.lower().
2010 2012
2011 2013 $ "$PYTHON" <<EOF
2012 2014 > def escape(s):
2013 2015 > return b''.join(br'\\u%x' % ord(uc) for uc in s.decode('cp932'))
2014 2016 > # translation of "record" in ja_JP.cp932
2015 2017 > upper = b"\x8bL\x98^"
2016 2018 > # str.lower()-ed section name should be treated as different one
2017 2019 > lower = b"\x8bl\x98^"
2018 2020 > with open('ambiguous.py', 'wb') as fp:
2019 2021 > fp.write(b"""# ambiguous section names in ja_JP.cp932
2020 2022 > u'''summary of extension
2021 2023 >
2022 2024 > %s
2023 2025 > ----
2024 2026 >
2025 2027 > Upper name should show only this message
2026 2028 >
2027 2029 > %s
2028 2030 > ----
2029 2031 >
2030 2032 > Lower name should show only this message
2031 2033 >
2032 2034 > subsequent section
2033 2035 > ------------------
2034 2036 >
2035 2037 > This should be hidden at 'hg help ambiguous' with section name.
2036 2038 > '''
2037 2039 > """ % (escape(upper), escape(lower)))
2038 2040 > EOF
2039 2041
2040 2042 $ cat >> $HGRCPATH <<EOF
2041 2043 > [extensions]
2042 2044 > ambiguous = ./ambiguous.py
2043 2045 > EOF
2044 2046
2045 2047 $ "$PYTHON" <<EOF | sh
2046 2048 > from mercurial.utils import procutil
2047 2049 > upper = b"\x8bL\x98^"
2048 2050 > procutil.stdout.write(b"hg --encoding cp932 help -e ambiguous.%s\n" % upper)
2049 2051 > EOF
2050 2052 \x8bL\x98^ (esc)
2051 2053 ----
2052 2054
2053 2055 Upper name should show only this message
2054 2056
2055 2057
2056 2058 $ "$PYTHON" <<EOF | sh
2057 2059 > from mercurial.utils import procutil
2058 2060 > lower = b"\x8bl\x98^"
2059 2061 > procutil.stdout.write(b"hg --encoding cp932 help -e ambiguous.%s\n" % lower)
2060 2062 > EOF
2061 2063 \x8bl\x98^ (esc)
2062 2064 ----
2063 2065
2064 2066 Lower name should show only this message
2065 2067
2066 2068
2067 2069 $ cat >> $HGRCPATH <<EOF
2068 2070 > [extensions]
2069 2071 > ambiguous = !
2070 2072 > EOF
2071 2073
2072 2074 Show help content of disabled extensions
2073 2075
2074 2076 $ cat >> $HGRCPATH <<EOF
2075 2077 > [extensions]
2076 2078 > ambiguous = !./ambiguous.py
2077 2079 > EOF
2078 2080 $ hg help -e ambiguous
2079 2081 ambiguous extension - (no help text available)
2080 2082
2081 2083 (use 'hg help extensions' for information on enabling extensions)
2082 2084
2083 2085 Test dynamic list of merge tools only shows up once
2084 2086 $ hg help merge-tools
2085 2087 Merge Tools
2086 2088 """""""""""
2087 2089
2088 2090 To merge files Mercurial uses merge tools.
2089 2091
2090 2092 A merge tool combines two different versions of a file into a merged file.
2091 2093 Merge tools are given the two files and the greatest common ancestor of
2092 2094 the two file versions, so they can determine the changes made on both
2093 2095 branches.
2094 2096
2095 2097 Merge tools are used both for 'hg resolve', 'hg merge', 'hg update', 'hg
2096 2098 backout' and in several extensions.
2097 2099
2098 2100 Usually, the merge tool tries to automatically reconcile the files by
2099 2101 combining all non-overlapping changes that occurred separately in the two
2100 2102 different evolutions of the same initial base file. Furthermore, some
2101 2103 interactive merge programs make it easier to manually resolve conflicting
2102 2104 merges, either in a graphical way, or by inserting some conflict markers.
2103 2105 Mercurial does not include any interactive merge programs but relies on
2104 2106 external tools for that.
2105 2107
2106 2108 Available merge tools
2107 2109 =====================
2108 2110
2109 2111 External merge tools and their properties are configured in the merge-
2110 2112 tools configuration section - see hgrc(5) - but they can often just be
2111 2113 named by their executable.
2112 2114
2113 2115 A merge tool is generally usable if its executable can be found on the
2114 2116 system and if it can handle the merge. The executable is found if it is an
2115 2117 absolute or relative executable path or the name of an application in the
2116 2118 executable search path. The tool is assumed to be able to handle the merge
2117 2119 if it can handle symlinks if the file is a symlink, if it can handle
2118 2120 binary files if the file is binary, and if a GUI is available if the tool
2119 2121 requires a GUI.
2120 2122
2121 2123 There are some internal merge tools which can be used. The internal merge
2122 2124 tools are:
2123 2125
2124 2126 ":dump"
2125 2127 Creates three versions of the files to merge, containing the contents of
2126 2128 local, other and base. These files can then be used to perform a merge
2127 2129 manually. If the file to be merged is named "a.txt", these files will
2128 2130 accordingly be named "a.txt.local", "a.txt.other" and "a.txt.base" and
2129 2131 they will be placed in the same directory as "a.txt".
2130 2132
2131 2133 This implies premerge. Therefore, files aren't dumped, if premerge runs
2132 2134 successfully. Use :forcedump to forcibly write files out.
2133 2135
2134 2136 (actual capabilities: binary, symlink)
2135 2137
2136 2138 ":fail"
2137 2139 Rather than attempting to merge files that were modified on both
2138 2140 branches, it marks them as unresolved. The resolve command must be used
2139 2141 to resolve these conflicts.
2140 2142
2141 2143 (actual capabilities: binary, symlink)
2142 2144
2143 2145 ":forcedump"
2144 2146 Creates three versions of the files as same as :dump, but omits
2145 2147 premerge.
2146 2148
2147 2149 (actual capabilities: binary, symlink)
2148 2150
2149 2151 ":local"
2150 2152 Uses the local 'p1()' version of files as the merged version.
2151 2153
2152 2154 (actual capabilities: binary, symlink)
2153 2155
2154 2156 ":merge"
2155 2157 Uses the internal non-interactive simple merge algorithm for merging
2156 2158 files. It will fail if there are any conflicts and leave markers in the
2157 2159 partially merged file. Markers will have two sections, one for each side
2158 2160 of merge.
2159 2161
2160 2162 ":merge-local"
2161 2163 Like :merge, but resolve all conflicts non-interactively in favor of the
2162 2164 local 'p1()' changes.
2163 2165
2164 2166 ":merge-other"
2165 2167 Like :merge, but resolve all conflicts non-interactively in favor of the
2166 2168 other 'p2()' changes.
2167 2169
2168 2170 ":merge3"
2169 2171 Uses the internal non-interactive simple merge algorithm for merging
2170 2172 files. It will fail if there are any conflicts and leave markers in the
2171 2173 partially merged file. Marker will have three sections, one from each
2172 2174 side of the merge and one for the base content.
2173 2175
2174 2176 ":mergediff"
2175 2177 Uses the internal non-interactive simple merge algorithm for merging
2176 2178 files. It will fail if there are any conflicts and leave markers in the
2177 2179 partially merged file. The marker will have two sections, one with the
2178 2180 content from one side of the merge, and one with a diff from the base
2179 2181 content to the content on the other side. (experimental)
2180 2182
2181 2183 ":other"
2182 2184 Uses the other 'p2()' version of files as the merged version.
2183 2185
2184 2186 (actual capabilities: binary, symlink)
2185 2187
2186 2188 ":prompt"
2187 2189 Asks the user which of the local 'p1()' or the other 'p2()' version to
2188 2190 keep as the merged version.
2189 2191
2190 2192 (actual capabilities: binary, symlink)
2191 2193
2192 2194 ":tagmerge"
2193 2195 Uses the internal tag merge algorithm (experimental).
2194 2196
2195 2197 ":union"
2196 2198 Uses the internal non-interactive simple merge algorithm for merging
2197 2199 files. It will use both local and other sides for conflict regions by
2198 2200 adding local on top of other. No markers are inserted.
2199 2201
2200 2202 ":union-other-first"
2201 2203 Like :union, but add other on top of local.
2202 2204
2203 2205 Internal tools are always available and do not require a GUI but will by
2204 2206 default not handle symlinks or binary files. See next section for detail
2205 2207 about "actual capabilities" described above.
2206 2208
2207 2209 Choosing a merge tool
2208 2210 =====================
2209 2211
2210 2212 Mercurial uses these rules when deciding which merge tool to use:
2211 2213
2212 2214 1. If a tool has been specified with the --tool option to merge or
2213 2215 resolve, it is used. If it is the name of a tool in the merge-tools
2214 2216 configuration, its configuration is used. Otherwise the specified tool
2215 2217 must be executable by the shell.
2216 2218 2. If the "HGMERGE" environment variable is present, its value is used and
2217 2219 must be executable by the shell.
2218 2220 3. If the filename of the file to be merged matches any of the patterns in
2219 2221 the merge-patterns configuration section, the first usable merge tool
2220 2222 corresponding to a matching pattern is used.
2221 2223 4. If ui.merge is set it will be considered next. If the value is not the
2222 2224 name of a configured tool, the specified value is used and must be
2223 2225 executable by the shell. Otherwise the named tool is used if it is
2224 2226 usable.
2225 2227 5. If any usable merge tools are present in the merge-tools configuration
2226 2228 section, the one with the highest priority is used.
2227 2229 6. If a program named "hgmerge" can be found on the system, it is used -
2228 2230 but it will by default not be used for symlinks and binary files.
2229 2231 7. If the file to be merged is not binary and is not a symlink, then
2230 2232 internal ":merge" is used.
2231 2233 8. Otherwise, ":prompt" is used.
2232 2234
2233 2235 For historical reason, Mercurial treats merge tools as below while
2234 2236 examining rules above.
2235 2237
2236 2238 step specified via binary symlink
2237 2239 ----------------------------------
2238 2240 1. --tool o/o o/o
2239 2241 2. HGMERGE o/o o/o
2240 2242 3. merge-patterns o/o(*) x/?(*)
2241 2243 4. ui.merge x/?(*) x/?(*)
2242 2244
2243 2245 Each capability column indicates Mercurial behavior for internal/external
2244 2246 merge tools at examining each rule.
2245 2247
2246 2248 - "o": "assume that a tool has capability"
2247 2249 - "x": "assume that a tool does not have capability"
2248 2250 - "?": "check actual capability of a tool"
2249 2251
2250 2252 If "merge.strict-capability-check" configuration is true, Mercurial checks
2251 2253 capabilities of merge tools strictly in (*) cases above (= each capability
2252 2254 column becomes "?/?"). It is false by default for backward compatibility.
2253 2255
2254 2256 Note:
2255 2257 After selecting a merge program, Mercurial will by default attempt to
2256 2258 merge the files using a simple merge algorithm first. Only if it
2257 2259 doesn't succeed because of conflicting changes will Mercurial actually
2258 2260 execute the merge program. Whether to use the simple merge algorithm
2259 2261 first can be controlled by the premerge setting of the merge tool.
2260 2262 Premerge is enabled by default unless the file is binary or a symlink.
2261 2263
2262 2264 See the merge-tools and ui sections of hgrc(5) for details on the
2263 2265 configuration of merge tools.
2264 2266
2265 2267 Compression engines listed in `hg help bundlespec`
2266 2268
2267 2269 $ hg help bundlespec | grep gzip
2268 2270 "v1" bundles can only use the "gzip", "bzip2", and "none" compression
2269 2271 An algorithm that produces smaller bundles than "gzip".
2270 2272 This engine will likely produce smaller bundles than "gzip" but will be
2271 2273 "gzip"
2272 2274 better compression than "gzip". It also frequently yields better (?)
2273 2275
2274 2276 Test usage of section marks in help documents
2275 2277
2276 2278 $ cd "$TESTDIR"/../doc
2277 2279 $ "$PYTHON" check-seclevel.py
2278 2280 $ cd $TESTTMP
2279 2281
2280 2282 #if serve
2281 2283
2282 2284 Test the help pages in hgweb.
2283 2285
2284 2286 Dish up an empty repo; serve it cold.
2285 2287
2286 2288 $ hg init "$TESTTMP/test"
2287 2289 $ hg serve -R "$TESTTMP/test" -n test -p $HGPORT -d --pid-file=hg.pid
2288 2290 $ cat hg.pid >> $DAEMON_PIDS
2289 2291
2290 2292 $ get-with-headers.py $LOCALIP:$HGPORT "help"
2291 2293 200 Script output follows
2292 2294
2293 2295 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
2294 2296 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
2295 2297 <head>
2296 2298 <link rel="icon" href="/static/hgicon.png" type="image/png" />
2297 2299 <meta name="robots" content="index, nofollow" />
2298 2300 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
2299 2301 <script type="text/javascript" src="/static/mercurial.js"></script>
2300 2302
2301 2303 <title>Help: Index</title>
2302 2304 </head>
2303 2305 <body>
2304 2306
2305 2307 <div class="container">
2306 2308 <div class="menu">
2307 2309 <div class="logo">
2308 2310 <a href="https://mercurial-scm.org/">
2309 2311 <img src="/static/hglogo.png" alt="mercurial" /></a>
2310 2312 </div>
2311 2313 <ul>
2312 2314 <li><a href="/shortlog">log</a></li>
2313 2315 <li><a href="/graph">graph</a></li>
2314 2316 <li><a href="/tags">tags</a></li>
2315 2317 <li><a href="/bookmarks">bookmarks</a></li>
2316 2318 <li><a href="/branches">branches</a></li>
2317 2319 </ul>
2318 2320 <ul>
2319 2321 <li class="active">help</li>
2320 2322 </ul>
2321 2323 </div>
2322 2324
2323 2325 <div class="main">
2324 2326 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
2325 2327
2326 2328 <form class="search" action="/log">
2327 2329
2328 2330 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
2329 2331 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
2330 2332 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
2331 2333 </form>
2332 2334 <table class="bigtable">
2333 2335 <tr><td colspan="2"><h2><a name="topics" href="#topics">Topics</a></h2></td></tr>
2334 2336
2335 2337 <tr><td>
2336 2338 <a href="/help/bundlespec">
2337 2339 bundlespec
2338 2340 </a>
2339 2341 </td><td>
2340 2342 Bundle File Formats
2341 2343 </td></tr>
2342 2344 <tr><td>
2343 2345 <a href="/help/color">
2344 2346 color
2345 2347 </a>
2346 2348 </td><td>
2347 2349 Colorizing Outputs
2348 2350 </td></tr>
2349 2351 <tr><td>
2350 2352 <a href="/help/config">
2351 2353 config
2352 2354 </a>
2353 2355 </td><td>
2354 2356 Configuration Files
2355 2357 </td></tr>
2356 2358 <tr><td>
2357 2359 <a href="/help/dates">
2358 2360 dates
2359 2361 </a>
2360 2362 </td><td>
2361 2363 Date Formats
2362 2364 </td></tr>
2363 2365 <tr><td>
2364 2366 <a href="/help/deprecated">
2365 2367 deprecated
2366 2368 </a>
2367 2369 </td><td>
2368 2370 Deprecated Features
2369 2371 </td></tr>
2370 2372 <tr><td>
2371 2373 <a href="/help/diffs">
2372 2374 diffs
2373 2375 </a>
2374 2376 </td><td>
2375 2377 Diff Formats
2376 2378 </td></tr>
2377 2379 <tr><td>
2378 2380 <a href="/help/environment">
2379 2381 environment
2380 2382 </a>
2381 2383 </td><td>
2382 2384 Environment Variables
2383 2385 </td></tr>
2384 2386 <tr><td>
2385 2387 <a href="/help/evolution">
2386 2388 evolution
2387 2389 </a>
2388 2390 </td><td>
2389 2391 Safely rewriting history (EXPERIMENTAL)
2390 2392 </td></tr>
2391 2393 <tr><td>
2392 2394 <a href="/help/extensions">
2393 2395 extensions
2394 2396 </a>
2395 2397 </td><td>
2396 2398 Using Additional Features
2397 2399 </td></tr>
2398 2400 <tr><td>
2399 2401 <a href="/help/filesets">
2400 2402 filesets
2401 2403 </a>
2402 2404 </td><td>
2403 2405 Specifying File Sets
2404 2406 </td></tr>
2405 2407 <tr><td>
2406 2408 <a href="/help/flags">
2407 2409 flags
2408 2410 </a>
2409 2411 </td><td>
2410 2412 Command-line flags
2411 2413 </td></tr>
2412 2414 <tr><td>
2413 2415 <a href="/help/glossary">
2414 2416 glossary
2415 2417 </a>
2416 2418 </td><td>
2417 2419 Glossary
2418 2420 </td></tr>
2419 2421 <tr><td>
2420 2422 <a href="/help/hgignore">
2421 2423 hgignore
2422 2424 </a>
2423 2425 </td><td>
2424 2426 Syntax for Mercurial Ignore Files
2425 2427 </td></tr>
2426 2428 <tr><td>
2427 2429 <a href="/help/hgweb">
2428 2430 hgweb
2429 2431 </a>
2430 2432 </td><td>
2431 2433 Configuring hgweb
2432 2434 </td></tr>
2433 2435 <tr><td>
2434 2436 <a href="/help/internals">
2435 2437 internals
2436 2438 </a>
2437 2439 </td><td>
2438 2440 Technical implementation topics
2439 2441 </td></tr>
2440 2442 <tr><td>
2441 2443 <a href="/help/merge-tools">
2442 2444 merge-tools
2443 2445 </a>
2444 2446 </td><td>
2445 2447 Merge Tools
2446 2448 </td></tr>
2447 2449 <tr><td>
2448 2450 <a href="/help/pager">
2449 2451 pager
2450 2452 </a>
2451 2453 </td><td>
2452 2454 Pager Support
2453 2455 </td></tr>
2454 2456 <tr><td>
2455 2457 <a href="/help/patterns">
2456 2458 patterns
2457 2459 </a>
2458 2460 </td><td>
2459 2461 File Name Patterns
2460 2462 </td></tr>
2461 2463 <tr><td>
2462 2464 <a href="/help/phases">
2463 2465 phases
2464 2466 </a>
2465 2467 </td><td>
2466 2468 Working with Phases
2467 2469 </td></tr>
2468 2470 <tr><td>
2469 2471 <a href="/help/revisions">
2470 2472 revisions
2471 2473 </a>
2472 2474 </td><td>
2473 2475 Specifying Revisions
2474 2476 </td></tr>
2475 2477 <tr><td>
2476 2478 <a href="/help/rust">
2477 2479 rust
2478 2480 </a>
2479 2481 </td><td>
2480 2482 Rust in Mercurial
2481 2483 </td></tr>
2482 2484 <tr><td>
2483 2485 <a href="/help/scripting">
2484 2486 scripting
2485 2487 </a>
2486 2488 </td><td>
2487 2489 Using Mercurial from scripts and automation
2488 2490 </td></tr>
2489 2491 <tr><td>
2490 2492 <a href="/help/subrepos">
2491 2493 subrepos
2492 2494 </a>
2493 2495 </td><td>
2494 2496 Subrepositories
2495 2497 </td></tr>
2496 2498 <tr><td>
2497 2499 <a href="/help/templating">
2498 2500 templating
2499 2501 </a>
2500 2502 </td><td>
2501 2503 Template Usage
2502 2504 </td></tr>
2503 2505 <tr><td>
2504 2506 <a href="/help/urls">
2505 2507 urls
2506 2508 </a>
2507 2509 </td><td>
2508 2510 URL Paths
2509 2511 </td></tr>
2510 2512 <tr><td>
2511 2513 <a href="/help/topic-containing-verbose">
2512 2514 topic-containing-verbose
2513 2515 </a>
2514 2516 </td><td>
2515 2517 This is the topic to test omit indicating.
2516 2518 </td></tr>
2517 2519
2518 2520
2519 2521 <tr><td colspan="2"><h2><a name="main" href="#main">Main Commands</a></h2></td></tr>
2520 2522
2521 2523 <tr><td>
2522 2524 <a href="/help/abort">
2523 2525 abort
2524 2526 </a>
2525 2527 </td><td>
2526 2528 abort an unfinished operation (EXPERIMENTAL)
2527 2529 </td></tr>
2528 2530 <tr><td>
2529 2531 <a href="/help/add">
2530 2532 add
2531 2533 </a>
2532 2534 </td><td>
2533 2535 add the specified files on the next commit
2534 2536 </td></tr>
2535 2537 <tr><td>
2536 2538 <a href="/help/annotate">
2537 2539 annotate
2538 2540 </a>
2539 2541 </td><td>
2540 2542 show changeset information by line for each file
2541 2543 </td></tr>
2542 2544 <tr><td>
2543 2545 <a href="/help/clone">
2544 2546 clone
2545 2547 </a>
2546 2548 </td><td>
2547 2549 make a copy of an existing repository
2548 2550 </td></tr>
2549 2551 <tr><td>
2550 2552 <a href="/help/commit">
2551 2553 commit
2552 2554 </a>
2553 2555 </td><td>
2554 2556 commit the specified files or all outstanding changes
2555 2557 </td></tr>
2556 2558 <tr><td>
2557 2559 <a href="/help/continue">
2558 2560 continue
2559 2561 </a>
2560 2562 </td><td>
2561 2563 resumes an interrupted operation (EXPERIMENTAL)
2562 2564 </td></tr>
2563 2565 <tr><td>
2564 2566 <a href="/help/diff">
2565 2567 diff
2566 2568 </a>
2567 2569 </td><td>
2568 2570 diff repository (or selected files)
2569 2571 </td></tr>
2570 2572 <tr><td>
2571 2573 <a href="/help/export">
2572 2574 export
2573 2575 </a>
2574 2576 </td><td>
2575 2577 dump the header and diffs for one or more changesets
2576 2578 </td></tr>
2577 2579 <tr><td>
2578 2580 <a href="/help/forget">
2579 2581 forget
2580 2582 </a>
2581 2583 </td><td>
2582 2584 forget the specified files on the next commit
2583 2585 </td></tr>
2584 2586 <tr><td>
2585 2587 <a href="/help/init">
2586 2588 init
2587 2589 </a>
2588 2590 </td><td>
2589 2591 create a new repository in the given directory
2590 2592 </td></tr>
2591 2593 <tr><td>
2592 2594 <a href="/help/log">
2593 2595 log
2594 2596 </a>
2595 2597 </td><td>
2596 2598 show revision history of entire repository or files
2597 2599 </td></tr>
2598 2600 <tr><td>
2599 2601 <a href="/help/merge">
2600 2602 merge
2601 2603 </a>
2602 2604 </td><td>
2603 2605 merge another revision into working directory
2604 2606 </td></tr>
2605 2607 <tr><td>
2606 2608 <a href="/help/pull">
2607 2609 pull
2608 2610 </a>
2609 2611 </td><td>
2610 2612 pull changes from the specified source
2611 2613 </td></tr>
2612 2614 <tr><td>
2613 2615 <a href="/help/push">
2614 2616 push
2615 2617 </a>
2616 2618 </td><td>
2617 2619 push changes to the specified destination
2618 2620 </td></tr>
2619 2621 <tr><td>
2620 2622 <a href="/help/remove">
2621 2623 remove
2622 2624 </a>
2623 2625 </td><td>
2624 2626 remove the specified files on the next commit
2625 2627 </td></tr>
2626 2628 <tr><td>
2627 2629 <a href="/help/serve">
2628 2630 serve
2629 2631 </a>
2630 2632 </td><td>
2631 2633 start stand-alone webserver
2632 2634 </td></tr>
2633 2635 <tr><td>
2634 2636 <a href="/help/status">
2635 2637 status
2636 2638 </a>
2637 2639 </td><td>
2638 2640 show changed files in the working directory
2639 2641 </td></tr>
2640 2642 <tr><td>
2641 2643 <a href="/help/summary">
2642 2644 summary
2643 2645 </a>
2644 2646 </td><td>
2645 2647 summarize working directory state
2646 2648 </td></tr>
2647 2649 <tr><td>
2648 2650 <a href="/help/update">
2649 2651 update
2650 2652 </a>
2651 2653 </td><td>
2652 2654 update working directory (or switch revisions)
2653 2655 </td></tr>
2654 2656
2655 2657
2656 2658
2657 2659 <tr><td colspan="2"><h2><a name="other" href="#other">Other Commands</a></h2></td></tr>
2658 2660
2659 2661 <tr><td>
2660 2662 <a href="/help/addremove">
2661 2663 addremove
2662 2664 </a>
2663 2665 </td><td>
2664 2666 add all new files, delete all missing files
2665 2667 </td></tr>
2666 2668 <tr><td>
2667 2669 <a href="/help/admin::verify">
2668 2670 admin::verify
2669 2671 </a>
2670 2672 </td><td>
2671 2673 verify the integrity of the repository
2672 2674 </td></tr>
2673 2675 <tr><td>
2674 2676 <a href="/help/archive">
2675 2677 archive
2676 2678 </a>
2677 2679 </td><td>
2678 2680 create an unversioned archive of a repository revision
2679 2681 </td></tr>
2680 2682 <tr><td>
2681 2683 <a href="/help/backout">
2682 2684 backout
2683 2685 </a>
2684 2686 </td><td>
2685 2687 reverse effect of earlier changeset
2686 2688 </td></tr>
2687 2689 <tr><td>
2688 2690 <a href="/help/bisect">
2689 2691 bisect
2690 2692 </a>
2691 2693 </td><td>
2692 2694 subdivision search of changesets
2693 2695 </td></tr>
2694 2696 <tr><td>
2695 2697 <a href="/help/bookmarks">
2696 2698 bookmarks
2697 2699 </a>
2698 2700 </td><td>
2699 2701 create a new bookmark or list existing bookmarks
2700 2702 </td></tr>
2701 2703 <tr><td>
2702 2704 <a href="/help/branch">
2703 2705 branch
2704 2706 </a>
2705 2707 </td><td>
2706 2708 set or show the current branch name
2707 2709 </td></tr>
2708 2710 <tr><td>
2709 2711 <a href="/help/branches">
2710 2712 branches
2711 2713 </a>
2712 2714 </td><td>
2713 2715 list repository named branches
2714 2716 </td></tr>
2715 2717 <tr><td>
2716 2718 <a href="/help/bundle">
2717 2719 bundle
2718 2720 </a>
2719 2721 </td><td>
2720 2722 create a bundle file
2721 2723 </td></tr>
2722 2724 <tr><td>
2723 2725 <a href="/help/cat">
2724 2726 cat
2725 2727 </a>
2726 2728 </td><td>
2727 2729 output the current or given revision of files
2728 2730 </td></tr>
2729 2731 <tr><td>
2730 2732 <a href="/help/config">
2731 2733 config
2732 2734 </a>
2733 2735 </td><td>
2734 2736 show combined config settings from all hgrc files
2735 2737 </td></tr>
2736 2738 <tr><td>
2737 2739 <a href="/help/copy">
2738 2740 copy
2739 2741 </a>
2740 2742 </td><td>
2741 2743 mark files as copied for the next commit
2742 2744 </td></tr>
2743 2745 <tr><td>
2744 2746 <a href="/help/files">
2745 2747 files
2746 2748 </a>
2747 2749 </td><td>
2748 2750 list tracked files
2749 2751 </td></tr>
2750 2752 <tr><td>
2751 2753 <a href="/help/graft">
2752 2754 graft
2753 2755 </a>
2754 2756 </td><td>
2755 2757 copy changes from other branches onto the current branch
2756 2758 </td></tr>
2757 2759 <tr><td>
2758 2760 <a href="/help/grep">
2759 2761 grep
2760 2762 </a>
2761 2763 </td><td>
2762 2764 search for a pattern in specified files
2763 2765 </td></tr>
2764 2766 <tr><td>
2765 2767 <a href="/help/hashelp">
2766 2768 hashelp
2767 2769 </a>
2768 2770 </td><td>
2769 2771 Extension command's help
2770 2772 </td></tr>
2771 2773 <tr><td>
2772 2774 <a href="/help/heads">
2773 2775 heads
2774 2776 </a>
2775 2777 </td><td>
2776 2778 show branch heads
2777 2779 </td></tr>
2778 2780 <tr><td>
2779 2781 <a href="/help/help">
2780 2782 help
2781 2783 </a>
2782 2784 </td><td>
2783 2785 show help for a given topic or a help overview
2784 2786 </td></tr>
2785 2787 <tr><td>
2786 2788 <a href="/help/hgalias">
2787 2789 hgalias
2788 2790 </a>
2789 2791 </td><td>
2790 2792 My doc
2791 2793 </td></tr>
2792 2794 <tr><td>
2793 2795 <a href="/help/hgaliasnodoc">
2794 2796 hgaliasnodoc
2795 2797 </a>
2796 2798 </td><td>
2797 2799 summarize working directory state
2798 2800 </td></tr>
2799 2801 <tr><td>
2800 2802 <a href="/help/identify">
2801 2803 identify
2802 2804 </a>
2803 2805 </td><td>
2804 2806 identify the working directory or specified revision
2805 2807 </td></tr>
2806 2808 <tr><td>
2807 2809 <a href="/help/import">
2808 2810 import
2809 2811 </a>
2810 2812 </td><td>
2811 2813 import an ordered set of patches
2812 2814 </td></tr>
2813 2815 <tr><td>
2814 2816 <a href="/help/incoming">
2815 2817 incoming
2816 2818 </a>
2817 2819 </td><td>
2818 2820 show new changesets found in source
2819 2821 </td></tr>
2820 2822 <tr><td>
2821 2823 <a href="/help/manifest">
2822 2824 manifest
2823 2825 </a>
2824 2826 </td><td>
2825 2827 output the current or given revision of the project manifest
2826 2828 </td></tr>
2827 2829 <tr><td>
2828 2830 <a href="/help/nohelp">
2829 2831 nohelp
2830 2832 </a>
2831 2833 </td><td>
2832 2834 (no help text available)
2833 2835 </td></tr>
2834 2836 <tr><td>
2835 2837 <a href="/help/outgoing">
2836 2838 outgoing
2837 2839 </a>
2838 2840 </td><td>
2839 2841 show changesets not found in the destination
2840 2842 </td></tr>
2841 2843 <tr><td>
2842 2844 <a href="/help/paths">
2843 2845 paths
2844 2846 </a>
2845 2847 </td><td>
2846 2848 show aliases for remote repositories
2847 2849 </td></tr>
2848 2850 <tr><td>
2849 2851 <a href="/help/phase">
2850 2852 phase
2851 2853 </a>
2852 2854 </td><td>
2853 2855 set or show the current phase name
2854 2856 </td></tr>
2855 2857 <tr><td>
2856 2858 <a href="/help/purge">
2857 2859 purge
2858 2860 </a>
2859 2861 </td><td>
2860 2862 removes files not tracked by Mercurial
2861 2863 </td></tr>
2862 2864 <tr><td>
2863 2865 <a href="/help/recover">
2864 2866 recover
2865 2867 </a>
2866 2868 </td><td>
2867 2869 roll back an interrupted transaction
2868 2870 </td></tr>
2869 2871 <tr><td>
2870 2872 <a href="/help/rename">
2871 2873 rename
2872 2874 </a>
2873 2875 </td><td>
2874 2876 rename files; equivalent of copy + remove
2875 2877 </td></tr>
2876 2878 <tr><td>
2877 2879 <a href="/help/resolve">
2878 2880 resolve
2879 2881 </a>
2880 2882 </td><td>
2881 2883 redo merges or set/view the merge status of files
2882 2884 </td></tr>
2883 2885 <tr><td>
2884 2886 <a href="/help/revert">
2885 2887 revert
2886 2888 </a>
2887 2889 </td><td>
2888 2890 restore files to their checkout state
2889 2891 </td></tr>
2890 2892 <tr><td>
2891 2893 <a href="/help/root">
2892 2894 root
2893 2895 </a>
2894 2896 </td><td>
2895 2897 print the root (top) of the current working directory
2896 2898 </td></tr>
2897 2899 <tr><td>
2898 2900 <a href="/help/shellalias">
2899 2901 shellalias
2900 2902 </a>
2901 2903 </td><td>
2902 2904 (no help text available)
2903 2905 </td></tr>
2904 2906 <tr><td>
2905 2907 <a href="/help/shelve">
2906 2908 shelve
2907 2909 </a>
2908 2910 </td><td>
2909 2911 save and set aside changes from the working directory
2910 2912 </td></tr>
2911 2913 <tr><td>
2912 2914 <a href="/help/tag">
2913 2915 tag
2914 2916 </a>
2915 2917 </td><td>
2916 2918 add one or more tags for the current or given revision
2917 2919 </td></tr>
2918 2920 <tr><td>
2919 2921 <a href="/help/tags">
2920 2922 tags
2921 2923 </a>
2922 2924 </td><td>
2923 2925 list repository tags
2924 2926 </td></tr>
2925 2927 <tr><td>
2926 2928 <a href="/help/unbundle">
2927 2929 unbundle
2928 2930 </a>
2929 2931 </td><td>
2930 2932 apply one or more bundle files
2931 2933 </td></tr>
2932 2934 <tr><td>
2933 2935 <a href="/help/unshelve">
2934 2936 unshelve
2935 2937 </a>
2936 2938 </td><td>
2937 2939 restore a shelved change to the working directory
2938 2940 </td></tr>
2939 2941 <tr><td>
2940 2942 <a href="/help/verify">
2941 2943 verify
2942 2944 </a>
2943 2945 </td><td>
2944 2946 verify the integrity of the repository
2945 2947 </td></tr>
2946 2948 <tr><td>
2947 2949 <a href="/help/version">
2948 2950 version
2949 2951 </a>
2950 2952 </td><td>
2951 2953 output version and copyright information
2952 2954 </td></tr>
2953 2955
2954 2956
2955 2957 </table>
2956 2958 </div>
2957 2959 </div>
2958 2960
2959 2961
2960 2962
2961 2963 </body>
2962 2964 </html>
2963 2965
2964 2966
2965 2967 $ get-with-headers.py $LOCALIP:$HGPORT "help/add"
2966 2968 200 Script output follows
2967 2969
2968 2970 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
2969 2971 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
2970 2972 <head>
2971 2973 <link rel="icon" href="/static/hgicon.png" type="image/png" />
2972 2974 <meta name="robots" content="index, nofollow" />
2973 2975 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
2974 2976 <script type="text/javascript" src="/static/mercurial.js"></script>
2975 2977
2976 2978 <title>Help: add</title>
2977 2979 </head>
2978 2980 <body>
2979 2981
2980 2982 <div class="container">
2981 2983 <div class="menu">
2982 2984 <div class="logo">
2983 2985 <a href="https://mercurial-scm.org/">
2984 2986 <img src="/static/hglogo.png" alt="mercurial" /></a>
2985 2987 </div>
2986 2988 <ul>
2987 2989 <li><a href="/shortlog">log</a></li>
2988 2990 <li><a href="/graph">graph</a></li>
2989 2991 <li><a href="/tags">tags</a></li>
2990 2992 <li><a href="/bookmarks">bookmarks</a></li>
2991 2993 <li><a href="/branches">branches</a></li>
2992 2994 </ul>
2993 2995 <ul>
2994 2996 <li class="active"><a href="/help">help</a></li>
2995 2997 </ul>
2996 2998 </div>
2997 2999
2998 3000 <div class="main">
2999 3001 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3000 3002 <h3>Help: add</h3>
3001 3003
3002 3004 <form class="search" action="/log">
3003 3005
3004 3006 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3005 3007 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3006 3008 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3007 3009 </form>
3008 3010 <div id="doc">
3009 3011 <p>
3010 3012 hg add [OPTION]... [FILE]...
3011 3013 </p>
3012 3014 <p>
3013 3015 add the specified files on the next commit
3014 3016 </p>
3015 3017 <p>
3016 3018 Schedule files to be version controlled and added to the
3017 3019 repository.
3018 3020 </p>
3019 3021 <p>
3020 3022 The files will be added to the repository at the next commit. To
3021 3023 undo an add before that, see 'hg forget'.
3022 3024 </p>
3023 3025 <p>
3024 3026 If no names are given, add all files to the repository (except
3025 3027 files matching &quot;.hgignore&quot;).
3026 3028 </p>
3027 3029 <p>
3028 3030 Examples:
3029 3031 </p>
3030 3032 <ul>
3031 3033 <li> New (unknown) files are added automatically by 'hg add':
3032 3034 <pre>
3033 3035 \$ ls (re)
3034 3036 foo.c
3035 3037 \$ hg status (re)
3036 3038 ? foo.c
3037 3039 \$ hg add (re)
3038 3040 adding foo.c
3039 3041 \$ hg status (re)
3040 3042 A foo.c
3041 3043 </pre>
3042 3044 <li> Specific files to be added can be specified:
3043 3045 <pre>
3044 3046 \$ ls (re)
3045 3047 bar.c foo.c
3046 3048 \$ hg status (re)
3047 3049 ? bar.c
3048 3050 ? foo.c
3049 3051 \$ hg add bar.c (re)
3050 3052 \$ hg status (re)
3051 3053 A bar.c
3052 3054 ? foo.c
3053 3055 </pre>
3054 3056 </ul>
3055 3057 <p>
3056 3058 Returns 0 if all files are successfully added.
3057 3059 </p>
3058 3060 <p>
3059 3061 options ([+] can be repeated):
3060 3062 </p>
3061 3063 <table>
3062 3064 <tr><td>-I</td>
3063 3065 <td>--include PATTERN [+]</td>
3064 3066 <td>include names matching the given patterns</td></tr>
3065 3067 <tr><td>-X</td>
3066 3068 <td>--exclude PATTERN [+]</td>
3067 3069 <td>exclude names matching the given patterns</td></tr>
3068 3070 <tr><td>-S</td>
3069 3071 <td>--subrepos</td>
3070 3072 <td>recurse into subrepositories</td></tr>
3071 3073 <tr><td>-n</td>
3072 3074 <td>--dry-run</td>
3073 3075 <td>do not perform actions, just print output</td></tr>
3074 3076 </table>
3075 3077 <p>
3076 3078 global options ([+] can be repeated):
3077 3079 </p>
3078 3080 <table>
3079 3081 <tr><td>-R</td>
3080 3082 <td>--repository REPO</td>
3081 3083 <td>repository root directory or name of overlay bundle file</td></tr>
3082 3084 <tr><td></td>
3083 3085 <td>--cwd DIR</td>
3084 3086 <td>change working directory</td></tr>
3085 3087 <tr><td>-y</td>
3086 3088 <td>--noninteractive</td>
3087 3089 <td>do not prompt, automatically pick the first choice for all prompts</td></tr>
3088 3090 <tr><td>-q</td>
3089 3091 <td>--quiet</td>
3090 3092 <td>suppress output</td></tr>
3091 3093 <tr><td>-v</td>
3092 3094 <td>--verbose</td>
3093 3095 <td>enable additional output</td></tr>
3094 3096 <tr><td></td>
3095 3097 <td>--color TYPE</td>
3096 3098 <td>when to colorize (boolean, always, auto, never, or debug)</td></tr>
3097 3099 <tr><td></td>
3098 3100 <td>--config CONFIG [+]</td>
3099 3101 <td>set/override config option (use 'section.name=value')</td></tr>
3100 3102 <tr><td></td>
3101 3103 <td>--debug</td>
3102 3104 <td>enable debugging output</td></tr>
3103 3105 <tr><td></td>
3104 3106 <td>--debugger</td>
3105 3107 <td>start debugger</td></tr>
3106 3108 <tr><td></td>
3107 3109 <td>--encoding ENCODE</td>
3108 3110 <td>set the charset encoding (default: ascii)</td></tr>
3109 3111 <tr><td></td>
3110 3112 <td>--encodingmode MODE</td>
3111 3113 <td>set the charset encoding mode (default: strict)</td></tr>
3112 3114 <tr><td></td>
3113 3115 <td>--traceback</td>
3114 3116 <td>always print a traceback on exception</td></tr>
3115 3117 <tr><td></td>
3116 3118 <td>--time</td>
3117 3119 <td>time how long the command takes</td></tr>
3118 3120 <tr><td></td>
3119 3121 <td>--profile</td>
3120 3122 <td>print command execution profile</td></tr>
3121 3123 <tr><td></td>
3122 3124 <td>--version</td>
3123 3125 <td>output version information and exit</td></tr>
3124 3126 <tr><td>-h</td>
3125 3127 <td>--help</td>
3126 3128 <td>display help and exit</td></tr>
3127 3129 <tr><td></td>
3128 3130 <td>--hidden</td>
3129 3131 <td>consider hidden changesets</td></tr>
3130 3132 <tr><td></td>
3131 3133 <td>--pager TYPE</td>
3132 3134 <td>when to paginate (boolean, always, auto, or never) (default: auto)</td></tr>
3133 3135 </table>
3134 3136
3135 3137 </div>
3136 3138 </div>
3137 3139 </div>
3138 3140
3139 3141
3140 3142
3141 3143 </body>
3142 3144 </html>
3143 3145
3144 3146
3145 3147 $ get-with-headers.py $LOCALIP:$HGPORT "help/remove"
3146 3148 200 Script output follows
3147 3149
3148 3150 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3149 3151 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3150 3152 <head>
3151 3153 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3152 3154 <meta name="robots" content="index, nofollow" />
3153 3155 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3154 3156 <script type="text/javascript" src="/static/mercurial.js"></script>
3155 3157
3156 3158 <title>Help: remove</title>
3157 3159 </head>
3158 3160 <body>
3159 3161
3160 3162 <div class="container">
3161 3163 <div class="menu">
3162 3164 <div class="logo">
3163 3165 <a href="https://mercurial-scm.org/">
3164 3166 <img src="/static/hglogo.png" alt="mercurial" /></a>
3165 3167 </div>
3166 3168 <ul>
3167 3169 <li><a href="/shortlog">log</a></li>
3168 3170 <li><a href="/graph">graph</a></li>
3169 3171 <li><a href="/tags">tags</a></li>
3170 3172 <li><a href="/bookmarks">bookmarks</a></li>
3171 3173 <li><a href="/branches">branches</a></li>
3172 3174 </ul>
3173 3175 <ul>
3174 3176 <li class="active"><a href="/help">help</a></li>
3175 3177 </ul>
3176 3178 </div>
3177 3179
3178 3180 <div class="main">
3179 3181 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3180 3182 <h3>Help: remove</h3>
3181 3183
3182 3184 <form class="search" action="/log">
3183 3185
3184 3186 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3185 3187 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3186 3188 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3187 3189 </form>
3188 3190 <div id="doc">
3189 3191 <p>
3190 3192 hg remove [OPTION]... FILE...
3191 3193 </p>
3192 3194 <p>
3193 3195 aliases: rm
3194 3196 </p>
3195 3197 <p>
3196 3198 remove the specified files on the next commit
3197 3199 </p>
3198 3200 <p>
3199 3201 Schedule the indicated files for removal from the current branch.
3200 3202 </p>
3201 3203 <p>
3202 3204 This command schedules the files to be removed at the next commit.
3203 3205 To undo a remove before that, see 'hg revert'. To undo added
3204 3206 files, see 'hg forget'.
3205 3207 </p>
3206 3208 <p>
3207 3209 -A/--after can be used to remove only files that have already
3208 3210 been deleted, -f/--force can be used to force deletion, and -Af
3209 3211 can be used to remove files from the next revision without
3210 3212 deleting them from the working directory.
3211 3213 </p>
3212 3214 <p>
3213 3215 The following table details the behavior of remove for different
3214 3216 file states (columns) and option combinations (rows). The file
3215 3217 states are Added [A], Clean [C], Modified [M] and Missing [!]
3216 3218 (as reported by 'hg status'). The actions are Warn, Remove
3217 3219 (from branch) and Delete (from disk):
3218 3220 </p>
3219 3221 <table>
3220 3222 <tr><td>opt/state</td>
3221 3223 <td>A</td>
3222 3224 <td>C</td>
3223 3225 <td>M</td>
3224 3226 <td>!</td></tr>
3225 3227 <tr><td>none</td>
3226 3228 <td>W</td>
3227 3229 <td>RD</td>
3228 3230 <td>W</td>
3229 3231 <td>R</td></tr>
3230 3232 <tr><td>-f</td>
3231 3233 <td>R</td>
3232 3234 <td>RD</td>
3233 3235 <td>RD</td>
3234 3236 <td>R</td></tr>
3235 3237 <tr><td>-A</td>
3236 3238 <td>W</td>
3237 3239 <td>W</td>
3238 3240 <td>W</td>
3239 3241 <td>R</td></tr>
3240 3242 <tr><td>-Af</td>
3241 3243 <td>R</td>
3242 3244 <td>R</td>
3243 3245 <td>R</td>
3244 3246 <td>R</td></tr>
3245 3247 </table>
3246 3248 <p>
3247 3249 <b>Note:</b>
3248 3250 </p>
3249 3251 <p>
3250 3252 'hg remove' never deletes files in Added [A] state from the
3251 3253 working directory, not even if &quot;--force&quot; is specified.
3252 3254 </p>
3253 3255 <p>
3254 3256 Returns 0 on success, 1 if any warnings encountered.
3255 3257 </p>
3256 3258 <p>
3257 3259 options ([+] can be repeated):
3258 3260 </p>
3259 3261 <table>
3260 3262 <tr><td>-A</td>
3261 3263 <td>--after</td>
3262 3264 <td>record delete for missing files</td></tr>
3263 3265 <tr><td>-f</td>
3264 3266 <td>--force</td>
3265 3267 <td>forget added files, delete modified files</td></tr>
3266 3268 <tr><td>-S</td>
3267 3269 <td>--subrepos</td>
3268 3270 <td>recurse into subrepositories</td></tr>
3269 3271 <tr><td>-I</td>
3270 3272 <td>--include PATTERN [+]</td>
3271 3273 <td>include names matching the given patterns</td></tr>
3272 3274 <tr><td>-X</td>
3273 3275 <td>--exclude PATTERN [+]</td>
3274 3276 <td>exclude names matching the given patterns</td></tr>
3275 3277 <tr><td>-n</td>
3276 3278 <td>--dry-run</td>
3277 3279 <td>do not perform actions, just print output</td></tr>
3278 3280 </table>
3279 3281 <p>
3280 3282 global options ([+] can be repeated):
3281 3283 </p>
3282 3284 <table>
3283 3285 <tr><td>-R</td>
3284 3286 <td>--repository REPO</td>
3285 3287 <td>repository root directory or name of overlay bundle file</td></tr>
3286 3288 <tr><td></td>
3287 3289 <td>--cwd DIR</td>
3288 3290 <td>change working directory</td></tr>
3289 3291 <tr><td>-y</td>
3290 3292 <td>--noninteractive</td>
3291 3293 <td>do not prompt, automatically pick the first choice for all prompts</td></tr>
3292 3294 <tr><td>-q</td>
3293 3295 <td>--quiet</td>
3294 3296 <td>suppress output</td></tr>
3295 3297 <tr><td>-v</td>
3296 3298 <td>--verbose</td>
3297 3299 <td>enable additional output</td></tr>
3298 3300 <tr><td></td>
3299 3301 <td>--color TYPE</td>
3300 3302 <td>when to colorize (boolean, always, auto, never, or debug)</td></tr>
3301 3303 <tr><td></td>
3302 3304 <td>--config CONFIG [+]</td>
3303 3305 <td>set/override config option (use 'section.name=value')</td></tr>
3304 3306 <tr><td></td>
3305 3307 <td>--debug</td>
3306 3308 <td>enable debugging output</td></tr>
3307 3309 <tr><td></td>
3308 3310 <td>--debugger</td>
3309 3311 <td>start debugger</td></tr>
3310 3312 <tr><td></td>
3311 3313 <td>--encoding ENCODE</td>
3312 3314 <td>set the charset encoding (default: ascii)</td></tr>
3313 3315 <tr><td></td>
3314 3316 <td>--encodingmode MODE</td>
3315 3317 <td>set the charset encoding mode (default: strict)</td></tr>
3316 3318 <tr><td></td>
3317 3319 <td>--traceback</td>
3318 3320 <td>always print a traceback on exception</td></tr>
3319 3321 <tr><td></td>
3320 3322 <td>--time</td>
3321 3323 <td>time how long the command takes</td></tr>
3322 3324 <tr><td></td>
3323 3325 <td>--profile</td>
3324 3326 <td>print command execution profile</td></tr>
3325 3327 <tr><td></td>
3326 3328 <td>--version</td>
3327 3329 <td>output version information and exit</td></tr>
3328 3330 <tr><td>-h</td>
3329 3331 <td>--help</td>
3330 3332 <td>display help and exit</td></tr>
3331 3333 <tr><td></td>
3332 3334 <td>--hidden</td>
3333 3335 <td>consider hidden changesets</td></tr>
3334 3336 <tr><td></td>
3335 3337 <td>--pager TYPE</td>
3336 3338 <td>when to paginate (boolean, always, auto, or never) (default: auto)</td></tr>
3337 3339 </table>
3338 3340
3339 3341 </div>
3340 3342 </div>
3341 3343 </div>
3342 3344
3343 3345
3344 3346
3345 3347 </body>
3346 3348 </html>
3347 3349
3348 3350
3349 3351 $ get-with-headers.py $LOCALIP:$HGPORT "help/dates"
3350 3352 200 Script output follows
3351 3353
3352 3354 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3353 3355 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3354 3356 <head>
3355 3357 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3356 3358 <meta name="robots" content="index, nofollow" />
3357 3359 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3358 3360 <script type="text/javascript" src="/static/mercurial.js"></script>
3359 3361
3360 3362 <title>Help: dates</title>
3361 3363 </head>
3362 3364 <body>
3363 3365
3364 3366 <div class="container">
3365 3367 <div class="menu">
3366 3368 <div class="logo">
3367 3369 <a href="https://mercurial-scm.org/">
3368 3370 <img src="/static/hglogo.png" alt="mercurial" /></a>
3369 3371 </div>
3370 3372 <ul>
3371 3373 <li><a href="/shortlog">log</a></li>
3372 3374 <li><a href="/graph">graph</a></li>
3373 3375 <li><a href="/tags">tags</a></li>
3374 3376 <li><a href="/bookmarks">bookmarks</a></li>
3375 3377 <li><a href="/branches">branches</a></li>
3376 3378 </ul>
3377 3379 <ul>
3378 3380 <li class="active"><a href="/help">help</a></li>
3379 3381 </ul>
3380 3382 </div>
3381 3383
3382 3384 <div class="main">
3383 3385 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3384 3386 <h3>Help: dates</h3>
3385 3387
3386 3388 <form class="search" action="/log">
3387 3389
3388 3390 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3389 3391 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3390 3392 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3391 3393 </form>
3392 3394 <div id="doc">
3393 3395 <h1>Date Formats</h1>
3394 3396 <p>
3395 3397 Some commands allow the user to specify a date, e.g.:
3396 3398 </p>
3397 3399 <ul>
3398 3400 <li> backout, commit, import, tag: Specify the commit date.
3399 3401 <li> log, revert, update: Select revision(s) by date.
3400 3402 </ul>
3401 3403 <p>
3402 3404 Many date formats are valid. Here are some examples:
3403 3405 </p>
3404 3406 <ul>
3405 3407 <li> &quot;Wed Dec 6 13:18:29 2006&quot; (local timezone assumed)
3406 3408 <li> &quot;Dec 6 13:18 -0600&quot; (year assumed, time offset provided)
3407 3409 <li> &quot;Dec 6 13:18 UTC&quot; (UTC and GMT are aliases for +0000)
3408 3410 <li> &quot;Dec 6&quot; (midnight)
3409 3411 <li> &quot;13:18&quot; (today assumed)
3410 3412 <li> &quot;3:39&quot; (3:39AM assumed)
3411 3413 <li> &quot;3:39pm&quot; (15:39)
3412 3414 <li> &quot;2006-12-06 13:18:29&quot; (ISO 8601 format)
3413 3415 <li> &quot;2006-12-6 13:18&quot;
3414 3416 <li> &quot;2006-12-6&quot;
3415 3417 <li> &quot;12-6&quot;
3416 3418 <li> &quot;12/6&quot;
3417 3419 <li> &quot;12/6/6&quot; (Dec 6 2006)
3418 3420 <li> &quot;today&quot; (midnight)
3419 3421 <li> &quot;yesterday&quot; (midnight)
3420 3422 <li> &quot;now&quot; - right now
3421 3423 </ul>
3422 3424 <p>
3423 3425 Lastly, there is Mercurial's internal format:
3424 3426 </p>
3425 3427 <ul>
3426 3428 <li> &quot;1165411109 0&quot; (Wed Dec 6 13:18:29 2006 UTC)
3427 3429 </ul>
3428 3430 <p>
3429 3431 This is the internal representation format for dates. The first number
3430 3432 is the number of seconds since the epoch (1970-01-01 00:00 UTC). The
3431 3433 second is the offset of the local timezone, in seconds west of UTC
3432 3434 (negative if the timezone is east of UTC).
3433 3435 </p>
3434 3436 <p>
3435 3437 The log command also accepts date ranges:
3436 3438 </p>
3437 3439 <ul>
3438 3440 <li> &quot;&lt;DATE&quot; - at or before a given date/time
3439 3441 <li> &quot;&gt;DATE&quot; - on or after a given date/time
3440 3442 <li> &quot;DATE to DATE&quot; - a date range, inclusive
3441 3443 <li> &quot;-DAYS&quot; - within a given number of days from today
3442 3444 </ul>
3443 3445
3444 3446 </div>
3445 3447 </div>
3446 3448 </div>
3447 3449
3448 3450
3449 3451
3450 3452 </body>
3451 3453 </html>
3452 3454
3453 3455
3454 3456 $ get-with-headers.py $LOCALIP:$HGPORT "help/pager"
3455 3457 200 Script output follows
3456 3458
3457 3459 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3458 3460 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3459 3461 <head>
3460 3462 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3461 3463 <meta name="robots" content="index, nofollow" />
3462 3464 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3463 3465 <script type="text/javascript" src="/static/mercurial.js"></script>
3464 3466
3465 3467 <title>Help: pager</title>
3466 3468 </head>
3467 3469 <body>
3468 3470
3469 3471 <div class="container">
3470 3472 <div class="menu">
3471 3473 <div class="logo">
3472 3474 <a href="https://mercurial-scm.org/">
3473 3475 <img src="/static/hglogo.png" alt="mercurial" /></a>
3474 3476 </div>
3475 3477 <ul>
3476 3478 <li><a href="/shortlog">log</a></li>
3477 3479 <li><a href="/graph">graph</a></li>
3478 3480 <li><a href="/tags">tags</a></li>
3479 3481 <li><a href="/bookmarks">bookmarks</a></li>
3480 3482 <li><a href="/branches">branches</a></li>
3481 3483 </ul>
3482 3484 <ul>
3483 3485 <li class="active"><a href="/help">help</a></li>
3484 3486 </ul>
3485 3487 </div>
3486 3488
3487 3489 <div class="main">
3488 3490 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3489 3491 <h3>Help: pager</h3>
3490 3492
3491 3493 <form class="search" action="/log">
3492 3494
3493 3495 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3494 3496 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3495 3497 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3496 3498 </form>
3497 3499 <div id="doc">
3498 3500 <h1>Pager Support</h1>
3499 3501 <p>
3500 3502 Some Mercurial commands can produce a lot of output, and Mercurial will
3501 3503 attempt to use a pager to make those commands more pleasant.
3502 3504 </p>
3503 3505 <p>
3504 3506 To set the pager that should be used, set the application variable:
3505 3507 </p>
3506 3508 <pre>
3507 3509 [pager]
3508 3510 pager = less -FRX
3509 3511 </pre>
3510 3512 <p>
3511 3513 If no pager is set in the user or repository configuration, Mercurial uses the
3512 3514 environment variable $PAGER. If $PAGER is not set, pager.pager from the default
3513 3515 or system configuration is used. If none of these are set, a default pager will
3514 3516 be used, typically 'less' on Unix and 'more' on Windows.
3515 3517 </p>
3516 3518 <p>
3517 3519 You can disable the pager for certain commands by adding them to the
3518 3520 pager.ignore list:
3519 3521 </p>
3520 3522 <pre>
3521 3523 [pager]
3522 3524 ignore = version, help, update
3523 3525 </pre>
3524 3526 <p>
3525 3527 To ignore global commands like 'hg version' or 'hg help', you have
3526 3528 to specify them in your user configuration file.
3527 3529 </p>
3528 3530 <p>
3529 3531 To control whether the pager is used at all for an individual command,
3530 3532 you can use --pager=&lt;value&gt;:
3531 3533 </p>
3532 3534 <ul>
3533 3535 <li> use as needed: 'auto'.
3534 3536 <li> require the pager: 'yes' or 'on'.
3535 3537 <li> suppress the pager: 'no' or 'off' (any unrecognized value will also work).
3536 3538 </ul>
3537 3539 <p>
3538 3540 To globally turn off all attempts to use a pager, set:
3539 3541 </p>
3540 3542 <pre>
3541 3543 [ui]
3542 3544 paginate = never
3543 3545 </pre>
3544 3546 <p>
3545 3547 which will prevent the pager from running.
3546 3548 </p>
3547 3549
3548 3550 </div>
3549 3551 </div>
3550 3552 </div>
3551 3553
3552 3554
3553 3555
3554 3556 </body>
3555 3557 </html>
3556 3558
3557 3559
3558 3560 Sub-topic indexes rendered properly
3559 3561
3560 3562 $ get-with-headers.py $LOCALIP:$HGPORT "help/internals"
3561 3563 200 Script output follows
3562 3564
3563 3565 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3564 3566 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3565 3567 <head>
3566 3568 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3567 3569 <meta name="robots" content="index, nofollow" />
3568 3570 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3569 3571 <script type="text/javascript" src="/static/mercurial.js"></script>
3570 3572
3571 3573 <title>Help: internals</title>
3572 3574 </head>
3573 3575 <body>
3574 3576
3575 3577 <div class="container">
3576 3578 <div class="menu">
3577 3579 <div class="logo">
3578 3580 <a href="https://mercurial-scm.org/">
3579 3581 <img src="/static/hglogo.png" alt="mercurial" /></a>
3580 3582 </div>
3581 3583 <ul>
3582 3584 <li><a href="/shortlog">log</a></li>
3583 3585 <li><a href="/graph">graph</a></li>
3584 3586 <li><a href="/tags">tags</a></li>
3585 3587 <li><a href="/bookmarks">bookmarks</a></li>
3586 3588 <li><a href="/branches">branches</a></li>
3587 3589 </ul>
3588 3590 <ul>
3589 3591 <li><a href="/help">help</a></li>
3590 3592 </ul>
3591 3593 </div>
3592 3594
3593 3595 <div class="main">
3594 3596 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3595 3597
3596 3598 <form class="search" action="/log">
3597 3599
3598 3600 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3599 3601 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3600 3602 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3601 3603 </form>
3602 3604 <table class="bigtable">
3603 3605 <tr><td colspan="2"><h2><a name="topics" href="#topics">Topics</a></h2></td></tr>
3604 3606
3605 3607 <tr><td>
3606 3608 <a href="/help/internals.bid-merge">
3607 3609 bid-merge
3608 3610 </a>
3609 3611 </td><td>
3610 3612 Bid Merge Algorithm
3611 3613 </td></tr>
3612 3614 <tr><td>
3613 3615 <a href="/help/internals.bundle2">
3614 3616 bundle2
3615 3617 </a>
3616 3618 </td><td>
3617 3619 Bundle2
3618 3620 </td></tr>
3619 3621 <tr><td>
3620 3622 <a href="/help/internals.bundles">
3621 3623 bundles
3622 3624 </a>
3623 3625 </td><td>
3624 3626 Bundles
3625 3627 </td></tr>
3626 3628 <tr><td>
3627 3629 <a href="/help/internals.cbor">
3628 3630 cbor
3629 3631 </a>
3630 3632 </td><td>
3631 3633 CBOR
3632 3634 </td></tr>
3633 3635 <tr><td>
3634 3636 <a href="/help/internals.censor">
3635 3637 censor
3636 3638 </a>
3637 3639 </td><td>
3638 3640 Censor
3639 3641 </td></tr>
3640 3642 <tr><td>
3641 3643 <a href="/help/internals.changegroups">
3642 3644 changegroups
3643 3645 </a>
3644 3646 </td><td>
3645 3647 Changegroups
3646 3648 </td></tr>
3647 3649 <tr><td>
3648 3650 <a href="/help/internals.config">
3649 3651 config
3650 3652 </a>
3651 3653 </td><td>
3652 3654 Config Registrar
3653 3655 </td></tr>
3654 3656 <tr><td>
3655 3657 <a href="/help/internals.dirstate-v2">
3656 3658 dirstate-v2
3657 3659 </a>
3658 3660 </td><td>
3659 3661 dirstate-v2 file format
3660 3662 </td></tr>
3661 3663 <tr><td>
3662 3664 <a href="/help/internals.extensions">
3663 3665 extensions
3664 3666 </a>
3665 3667 </td><td>
3666 3668 Extension API
3667 3669 </td></tr>
3668 3670 <tr><td>
3669 3671 <a href="/help/internals.mergestate">
3670 3672 mergestate
3671 3673 </a>
3672 3674 </td><td>
3673 3675 Mergestate
3674 3676 </td></tr>
3675 3677 <tr><td>
3676 3678 <a href="/help/internals.requirements">
3677 3679 requirements
3678 3680 </a>
3679 3681 </td><td>
3680 3682 Repository Requirements
3681 3683 </td></tr>
3682 3684 <tr><td>
3683 3685 <a href="/help/internals.revlogs">
3684 3686 revlogs
3685 3687 </a>
3686 3688 </td><td>
3687 3689 Revision Logs
3688 3690 </td></tr>
3689 3691 <tr><td>
3690 3692 <a href="/help/internals.wireprotocol">
3691 3693 wireprotocol
3692 3694 </a>
3693 3695 </td><td>
3694 3696 Wire Protocol
3695 3697 </td></tr>
3696 3698 <tr><td>
3697 3699 <a href="/help/internals.wireprotocolrpc">
3698 3700 wireprotocolrpc
3699 3701 </a>
3700 3702 </td><td>
3701 3703 Wire Protocol RPC
3702 3704 </td></tr>
3703 3705 <tr><td>
3704 3706 <a href="/help/internals.wireprotocolv2">
3705 3707 wireprotocolv2
3706 3708 </a>
3707 3709 </td><td>
3708 3710 Wire Protocol Version 2
3709 3711 </td></tr>
3710 3712
3711 3713
3712 3714
3713 3715
3714 3716
3715 3717 </table>
3716 3718 </div>
3717 3719 </div>
3718 3720
3719 3721
3720 3722
3721 3723 </body>
3722 3724 </html>
3723 3725
3724 3726
3725 3727 Sub-topic topics rendered properly
3726 3728
3727 3729 $ get-with-headers.py $LOCALIP:$HGPORT "help/internals.changegroups"
3728 3730 200 Script output follows
3729 3731
3730 3732 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3731 3733 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3732 3734 <head>
3733 3735 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3734 3736 <meta name="robots" content="index, nofollow" />
3735 3737 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3736 3738 <script type="text/javascript" src="/static/mercurial.js"></script>
3737 3739
3738 3740 <title>Help: internals.changegroups</title>
3739 3741 </head>
3740 3742 <body>
3741 3743
3742 3744 <div class="container">
3743 3745 <div class="menu">
3744 3746 <div class="logo">
3745 3747 <a href="https://mercurial-scm.org/">
3746 3748 <img src="/static/hglogo.png" alt="mercurial" /></a>
3747 3749 </div>
3748 3750 <ul>
3749 3751 <li><a href="/shortlog">log</a></li>
3750 3752 <li><a href="/graph">graph</a></li>
3751 3753 <li><a href="/tags">tags</a></li>
3752 3754 <li><a href="/bookmarks">bookmarks</a></li>
3753 3755 <li><a href="/branches">branches</a></li>
3754 3756 </ul>
3755 3757 <ul>
3756 3758 <li class="active"><a href="/help">help</a></li>
3757 3759 </ul>
3758 3760 </div>
3759 3761
3760 3762 <div class="main">
3761 3763 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3762 3764 <h3>Help: internals.changegroups</h3>
3763 3765
3764 3766 <form class="search" action="/log">
3765 3767
3766 3768 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3767 3769 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3768 3770 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3769 3771 </form>
3770 3772 <div id="doc">
3771 3773 <h1>Changegroups</h1>
3772 3774 <p>
3773 3775 Changegroups are representations of repository revlog data, specifically
3774 3776 the changelog data, root/flat manifest data, treemanifest data, and
3775 3777 filelogs.
3776 3778 </p>
3777 3779 <p>
3778 3780 There are 4 versions of changegroups: &quot;1&quot;, &quot;2&quot;, &quot;3&quot; and &quot;4&quot;. From a
3779 3781 high-level, versions &quot;1&quot; and &quot;2&quot; are almost exactly the same, with the
3780 3782 only difference being an additional item in the *delta header*. Version
3781 3783 &quot;3&quot; adds support for storage flags in the *delta header* and optionally
3782 3784 exchanging treemanifests (enabled by setting an option on the
3783 3785 &quot;changegroup&quot; part in the bundle2). Version &quot;4&quot; adds support for exchanging
3784 3786 sidedata (additional revision metadata not part of the digest).
3785 3787 </p>
3786 3788 <p>
3787 3789 Changegroups when not exchanging treemanifests consist of 3 logical
3788 3790 segments:
3789 3791 </p>
3790 3792 <pre>
3791 3793 +---------------------------------+
3792 3794 | | | |
3793 3795 | changeset | manifest | filelogs |
3794 3796 | | | |
3795 3797 | | | |
3796 3798 +---------------------------------+
3797 3799 </pre>
3798 3800 <p>
3799 3801 When exchanging treemanifests, there are 4 logical segments:
3800 3802 </p>
3801 3803 <pre>
3802 3804 +-------------------------------------------------+
3803 3805 | | | | |
3804 3806 | changeset | root | treemanifests | filelogs |
3805 3807 | | manifest | | |
3806 3808 | | | | |
3807 3809 +-------------------------------------------------+
3808 3810 </pre>
3809 3811 <p>
3810 3812 The principle building block of each segment is a *chunk*. A *chunk*
3811 3813 is a framed piece of data:
3812 3814 </p>
3813 3815 <pre>
3814 3816 +---------------------------------------+
3815 3817 | | |
3816 3818 | length | data |
3817 3819 | (4 bytes) | (&lt;length - 4&gt; bytes) |
3818 3820 | | |
3819 3821 +---------------------------------------+
3820 3822 </pre>
3821 3823 <p>
3822 3824 All integers are big-endian signed integers. Each chunk starts with a 32-bit
3823 3825 integer indicating the length of the entire chunk (including the length field
3824 3826 itself).
3825 3827 </p>
3826 3828 <p>
3827 3829 There is a special case chunk that has a value of 0 for the length
3828 3830 (&quot;0x00000000&quot;). We call this an *empty chunk*.
3829 3831 </p>
3830 3832 <h2>Delta Groups</h2>
3831 3833 <p>
3832 3834 A *delta group* expresses the content of a revlog as a series of deltas,
3833 3835 or patches against previous revisions.
3834 3836 </p>
3835 3837 <p>
3836 3838 Delta groups consist of 0 or more *chunks* followed by the *empty chunk*
3837 3839 to signal the end of the delta group:
3838 3840 </p>
3839 3841 <pre>
3840 3842 +------------------------------------------------------------------------+
3841 3843 | | | | | |
3842 3844 | chunk0 length | chunk0 data | chunk1 length | chunk1 data | 0x0 |
3843 3845 | (4 bytes) | (various) | (4 bytes) | (various) | (4 bytes) |
3844 3846 | | | | | |
3845 3847 +------------------------------------------------------------------------+
3846 3848 </pre>
3847 3849 <p>
3848 3850 Each *chunk*'s data consists of the following:
3849 3851 </p>
3850 3852 <pre>
3851 3853 +---------------------------------------+
3852 3854 | | |
3853 3855 | delta header | delta data |
3854 3856 | (various by version) | (various) |
3855 3857 | | |
3856 3858 +---------------------------------------+
3857 3859 </pre>
3858 3860 <p>
3859 3861 The *delta data* is a series of *delta*s that describe a diff from an existing
3860 3862 entry (either that the recipient already has, or previously specified in the
3861 3863 bundle/changegroup).
3862 3864 </p>
3863 3865 <p>
3864 3866 The *delta header* is different between versions &quot;1&quot;, &quot;2&quot;, &quot;3&quot; and &quot;4&quot;
3865 3867 of the changegroup format.
3866 3868 </p>
3867 3869 <p>
3868 3870 Version 1 (headerlen=80):
3869 3871 </p>
3870 3872 <pre>
3871 3873 +------------------------------------------------------+
3872 3874 | | | | |
3873 3875 | node | p1 node | p2 node | link node |
3874 3876 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
3875 3877 | | | | |
3876 3878 +------------------------------------------------------+
3877 3879 </pre>
3878 3880 <p>
3879 3881 Version 2 (headerlen=100):
3880 3882 </p>
3881 3883 <pre>
3882 3884 +------------------------------------------------------------------+
3883 3885 | | | | | |
3884 3886 | node | p1 node | p2 node | base node | link node |
3885 3887 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
3886 3888 | | | | | |
3887 3889 +------------------------------------------------------------------+
3888 3890 </pre>
3889 3891 <p>
3890 3892 Version 3 (headerlen=102):
3891 3893 </p>
3892 3894 <pre>
3893 3895 +------------------------------------------------------------------------------+
3894 3896 | | | | | | |
3895 3897 | node | p1 node | p2 node | base node | link node | flags |
3896 3898 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (2 bytes) |
3897 3899 | | | | | | |
3898 3900 +------------------------------------------------------------------------------+
3899 3901 </pre>
3900 3902 <p>
3901 3903 Version 4 (headerlen=103):
3902 3904 </p>
3903 3905 <pre>
3904 3906 +------------------------------------------------------------------------------+----------+
3905 3907 | | | | | | | |
3906 3908 | node | p1 node | p2 node | base node | link node | flags | pflags |
3907 3909 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (2 bytes) | (1 byte) |
3908 3910 | | | | | | | |
3909 3911 +------------------------------------------------------------------------------+----------+
3910 3912 </pre>
3911 3913 <p>
3912 3914 The *delta data* consists of &quot;chunklen - 4 - headerlen&quot; bytes, which contain a
3913 3915 series of *delta*s, densely packed (no separators). These deltas describe a diff
3914 3916 from an existing entry (either that the recipient already has, or previously
3915 3917 specified in the bundle/changegroup). The format is described more fully in
3916 3918 &quot;hg help internals.bdiff&quot;, but briefly:
3917 3919 </p>
3918 3920 <pre>
3919 3921 +---------------------------------------------------------------+
3920 3922 | | | | |
3921 3923 | start offset | end offset | new length | content |
3922 3924 | (4 bytes) | (4 bytes) | (4 bytes) | (&lt;new length&gt; bytes) |
3923 3925 | | | | |
3924 3926 +---------------------------------------------------------------+
3925 3927 </pre>
3926 3928 <p>
3927 3929 Please note that the length field in the delta data does *not* include itself.
3928 3930 </p>
3929 3931 <p>
3930 3932 In version 1, the delta is always applied against the previous node from
3931 3933 the changegroup or the first parent if this is the first entry in the
3932 3934 changegroup.
3933 3935 </p>
3934 3936 <p>
3935 3937 In version 2 and up, the delta base node is encoded in the entry in the
3936 3938 changegroup. This allows the delta to be expressed against any parent,
3937 3939 which can result in smaller deltas and more efficient encoding of data.
3938 3940 </p>
3939 3941 <p>
3940 3942 The *flags* field holds bitwise flags affecting the processing of revision
3941 3943 data. The following flags are defined:
3942 3944 </p>
3943 3945 <dl>
3944 3946 <dt>32768
3945 3947 <dd>Censored revision. The revision's fulltext has been replaced by censor metadata. May only occur on file revisions.
3946 3948 <dt>16384
3947 3949 <dd>Ellipsis revision. Revision hash does not match data (likely due to rewritten parents).
3948 3950 <dt>8192
3949 3951 <dd>Externally stored. The revision fulltext contains &quot;key:value&quot; &quot;\n&quot; delimited metadata defining an object stored elsewhere. Used by the LFS extension.
3950 3952 <dt>4096
3951 3953 <dd>Contains copy information. This revision changes files in a way that could affect copy tracing. This does *not* affect changegroup handling, but is relevant for other parts of Mercurial.
3952 3954 </dl>
3953 3955 <p>
3954 3956 For historical reasons, the integer values are identical to revlog version 1
3955 3957 per-revision storage flags and correspond to bits being set in this 2-byte
3956 3958 field. Bits were allocated starting from the most-significant bit, hence the
3957 3959 reverse ordering and allocation of these flags.
3958 3960 </p>
3959 3961 <p>
3960 3962 The *pflags* (protocol flags) field holds bitwise flags affecting the protocol
3961 3963 itself. They are first in the header since they may affect the handling of the
3962 3964 rest of the fields in a future version. They are defined as such:
3963 3965 </p>
3964 3966 <dl>
3965 3967 <dt>1 indicates whether to read a chunk of sidedata (of variable length) right
3966 3968 <dd>after the revision flags.
3967 3969 </dl>
3968 3970 <h2>Changeset Segment</h2>
3969 3971 <p>
3970 3972 The *changeset segment* consists of a single *delta group* holding
3971 3973 changelog data. The *empty chunk* at the end of the *delta group* denotes
3972 3974 the boundary to the *manifest segment*.
3973 3975 </p>
3974 3976 <h2>Manifest Segment</h2>
3975 3977 <p>
3976 3978 The *manifest segment* consists of a single *delta group* holding manifest
3977 3979 data. If treemanifests are in use, it contains only the manifest for the
3978 3980 root directory of the repository. Otherwise, it contains the entire
3979 3981 manifest data. The *empty chunk* at the end of the *delta group* denotes
3980 3982 the boundary to the next segment (either the *treemanifests segment* or the
3981 3983 *filelogs segment*, depending on version and the request options).
3982 3984 </p>
3983 3985 <h3>Treemanifests Segment</h3>
3984 3986 <p>
3985 3987 The *treemanifests segment* only exists in changegroup version &quot;3&quot; and &quot;4&quot;,
3986 3988 and only if the 'treemanifest' param is part of the bundle2 changegroup part
3987 3989 (it is not possible to use changegroup version 3 or 4 outside of bundle2).
3988 3990 Aside from the filenames in the *treemanifests segment* containing a
3989 3991 trailing &quot;/&quot; character, it behaves identically to the *filelogs segment*
3990 3992 (see below). The final sub-segment is followed by an *empty chunk* (logically,
3991 3993 a sub-segment with filename size 0). This denotes the boundary to the
3992 3994 *filelogs segment*.
3993 3995 </p>
3994 3996 <h2>Filelogs Segment</h2>
3995 3997 <p>
3996 3998 The *filelogs segment* consists of multiple sub-segments, each
3997 3999 corresponding to an individual file whose data is being described:
3998 4000 </p>
3999 4001 <pre>
4000 4002 +--------------------------------------------------+
4001 4003 | | | | | |
4002 4004 | filelog0 | filelog1 | filelog2 | ... | 0x0 |
4003 4005 | | | | | (4 bytes) |
4004 4006 | | | | | |
4005 4007 +--------------------------------------------------+
4006 4008 </pre>
4007 4009 <p>
4008 4010 The final filelog sub-segment is followed by an *empty chunk* (logically,
4009 4011 a sub-segment with filename size 0). This denotes the end of the segment
4010 4012 and of the overall changegroup.
4011 4013 </p>
4012 4014 <p>
4013 4015 Each filelog sub-segment consists of the following:
4014 4016 </p>
4015 4017 <pre>
4016 4018 +------------------------------------------------------+
4017 4019 | | | |
4018 4020 | filename length | filename | delta group |
4019 4021 | (4 bytes) | (&lt;length - 4&gt; bytes) | (various) |
4020 4022 | | | |
4021 4023 +------------------------------------------------------+
4022 4024 </pre>
4023 4025 <p>
4024 4026 That is, a *chunk* consisting of the filename (not terminated or padded)
4025 4027 followed by N chunks constituting the *delta group* for this file. The
4026 4028 *empty chunk* at the end of each *delta group* denotes the boundary to the
4027 4029 next filelog sub-segment.
4028 4030 </p>
4029 4031
4030 4032 </div>
4031 4033 </div>
4032 4034 </div>
4033 4035
4034 4036
4035 4037
4036 4038 </body>
4037 4039 </html>
4038 4040
4039 4041
4040 4042 $ get-with-headers.py 127.0.0.1:$HGPORT "help/unknowntopic"
4041 4043 404 Not Found
4042 4044
4043 4045 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
4044 4046 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
4045 4047 <head>
4046 4048 <link rel="icon" href="/static/hgicon.png" type="image/png" />
4047 4049 <meta name="robots" content="index, nofollow" />
4048 4050 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
4049 4051 <script type="text/javascript" src="/static/mercurial.js"></script>
4050 4052
4051 4053 <title>test: error</title>
4052 4054 </head>
4053 4055 <body>
4054 4056
4055 4057 <div class="container">
4056 4058 <div class="menu">
4057 4059 <div class="logo">
4058 4060 <a href="https://mercurial-scm.org/">
4059 4061 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
4060 4062 </div>
4061 4063 <ul>
4062 4064 <li><a href="/shortlog">log</a></li>
4063 4065 <li><a href="/graph">graph</a></li>
4064 4066 <li><a href="/tags">tags</a></li>
4065 4067 <li><a href="/bookmarks">bookmarks</a></li>
4066 4068 <li><a href="/branches">branches</a></li>
4067 4069 </ul>
4068 4070 <ul>
4069 4071 <li><a href="/help">help</a></li>
4070 4072 </ul>
4071 4073 </div>
4072 4074
4073 4075 <div class="main">
4074 4076
4075 4077 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
4076 4078 <h3>error</h3>
4077 4079
4078 4080
4079 4081 <form class="search" action="/log">
4080 4082
4081 4083 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
4082 4084 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
4083 4085 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
4084 4086 </form>
4085 4087
4086 4088 <div class="description">
4087 4089 <p>
4088 4090 An error occurred while processing your request:
4089 4091 </p>
4090 4092 <p>
4091 4093 Not Found
4092 4094 </p>
4093 4095 </div>
4094 4096 </div>
4095 4097 </div>
4096 4098
4097 4099
4098 4100
4099 4101 </body>
4100 4102 </html>
4101 4103
4102 4104 [1]
4103 4105
4104 4106 $ killdaemons.py
4105 4107
4106 4108 #endif
General Comments 0
You need to be logged in to leave comments. Login now