##// END OF EJS Templates
deltas: add a debug-delta-find command to analyse delta search...
marmoute -
r50123:b909dd35 default
parent child Browse files
Show More
@@ -1,4991 +1,5051 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 string
25 25 import subprocess
26 26 import sys
27 27 import time
28 28
29 29 from .i18n import _
30 30 from .node import (
31 31 bin,
32 32 hex,
33 33 nullrev,
34 34 short,
35 35 )
36 36 from .pycompat import (
37 37 getattr,
38 38 open,
39 39 )
40 40 from . import (
41 41 bundle2,
42 42 bundlerepo,
43 43 changegroup,
44 44 cmdutil,
45 45 color,
46 46 context,
47 47 copies,
48 48 dagparser,
49 49 dirstateutils,
50 50 encoding,
51 51 error,
52 52 exchange,
53 53 extensions,
54 54 filemerge,
55 55 filesetlang,
56 56 formatter,
57 57 hg,
58 58 httppeer,
59 59 localrepo,
60 60 lock as lockmod,
61 61 logcmdutil,
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 revlogutils,
76 77 revset,
77 78 revsetlang,
78 79 scmutil,
79 80 setdiscovery,
80 81 simplemerge,
81 82 sshpeer,
82 83 sslutil,
83 84 streamclone,
84 85 strip,
85 86 tags as tagsmod,
86 87 templater,
87 88 treediscovery,
88 89 upgrade,
89 90 url as urlmod,
90 91 util,
91 92 vfs as vfsmod,
92 93 wireprotoframing,
93 94 wireprotoserver,
94 95 )
95 96 from .interfaces import repository
96 97 from .utils import (
97 98 cborutil,
98 99 compression,
99 100 dateutil,
100 101 procutil,
101 102 stringutil,
102 103 urlutil,
103 104 )
104 105
105 106 from .revlogutils import (
106 107 constants as revlog_constants,
107 108 deltas as deltautil,
108 109 nodemap,
109 110 rewrite,
110 111 sidedata,
111 112 )
112 113
113 114 release = lockmod.release
114 115
115 116 table = {}
116 117 table.update(strip.command._table)
117 118 command = registrar.command(table)
118 119
119 120
120 121 @command(b'debugancestor', [], _(b'[INDEX] REV1 REV2'), optionalrepo=True)
121 122 def debugancestor(ui, repo, *args):
122 123 """find the ancestor revision of two revisions in a given index"""
123 124 if len(args) == 3:
124 125 index, rev1, rev2 = args
125 126 r = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False), index)
126 127 lookup = r.lookup
127 128 elif len(args) == 2:
128 129 if not repo:
129 130 raise error.Abort(
130 131 _(b'there is no Mercurial repository here (.hg not found)')
131 132 )
132 133 rev1, rev2 = args
133 134 r = repo.changelog
134 135 lookup = repo.lookup
135 136 else:
136 137 raise error.Abort(_(b'either two or three arguments required'))
137 138 a = r.ancestor(lookup(rev1), lookup(rev2))
138 139 ui.write(b'%d:%s\n' % (r.rev(a), hex(a)))
139 140
140 141
141 142 @command(b'debugantivirusrunning', [])
142 143 def debugantivirusrunning(ui, repo):
143 144 """attempt to trigger an antivirus scanner to see if one is active"""
144 145 with repo.cachevfs.open('eicar-test-file.com', b'wb') as f:
145 146 f.write(
146 147 util.b85decode(
147 148 # This is a base85-armored version of the EICAR test file. See
148 149 # https://en.wikipedia.org/wiki/EICAR_test_file for details.
149 150 b'ST#=}P$fV?P+K%yP+C|uG$>GBDK|qyDK~v2MM*<JQY}+dK~6+LQba95P'
150 151 b'E<)&Nm5l)EmTEQR4qnHOhq9iNGnJx'
151 152 )
152 153 )
153 154 # Give an AV engine time to scan the file.
154 155 time.sleep(2)
155 156 util.unlink(repo.cachevfs.join('eicar-test-file.com'))
156 157
157 158
158 159 @command(b'debugapplystreamclonebundle', [], b'FILE')
159 160 def debugapplystreamclonebundle(ui, repo, fname):
160 161 """apply a stream clone bundle file"""
161 162 f = hg.openpath(ui, fname)
162 163 gen = exchange.readbundle(ui, f, fname)
163 164 gen.apply(repo)
164 165
165 166
166 167 @command(
167 168 b'debugbuilddag',
168 169 [
169 170 (
170 171 b'm',
171 172 b'mergeable-file',
172 173 None,
173 174 _(b'add single file mergeable changes'),
174 175 ),
175 176 (
176 177 b'o',
177 178 b'overwritten-file',
178 179 None,
179 180 _(b'add single file all revs overwrite'),
180 181 ),
181 182 (b'n', b'new-file', None, _(b'add new file at each rev')),
182 183 (
183 184 b'',
184 185 b'from-existing',
185 186 None,
186 187 _(b'continue from a non-empty repository'),
187 188 ),
188 189 ],
189 190 _(b'[OPTION]... [TEXT]'),
190 191 )
191 192 def debugbuilddag(
192 193 ui,
193 194 repo,
194 195 text=None,
195 196 mergeable_file=False,
196 197 overwritten_file=False,
197 198 new_file=False,
198 199 from_existing=False,
199 200 ):
200 201 """builds a repo with a given DAG from scratch in the current empty repo
201 202
202 203 The description of the DAG is read from stdin if not given on the
203 204 command line.
204 205
205 206 Elements:
206 207
207 208 - "+n" is a linear run of n nodes based on the current default parent
208 209 - "." is a single node based on the current default parent
209 210 - "$" resets the default parent to null (implied at the start);
210 211 otherwise the default parent is always the last node created
211 212 - "<p" sets the default parent to the backref p
212 213 - "*p" is a fork at parent p, which is a backref
213 214 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
214 215 - "/p2" is a merge of the preceding node and p2
215 216 - ":tag" defines a local tag for the preceding node
216 217 - "@branch" sets the named branch for subsequent nodes
217 218 - "#...\\n" is a comment up to the end of the line
218 219
219 220 Whitespace between the above elements is ignored.
220 221
221 222 A backref is either
222 223
223 224 - a number n, which references the node curr-n, where curr is the current
224 225 node, or
225 226 - the name of a local tag you placed earlier using ":tag", or
226 227 - empty to denote the default parent.
227 228
228 229 All string valued-elements are either strictly alphanumeric, or must
229 230 be enclosed in double quotes ("..."), with "\\" as escape character.
230 231 """
231 232
232 233 if text is None:
233 234 ui.status(_(b"reading DAG from stdin\n"))
234 235 text = ui.fin.read()
235 236
236 237 cl = repo.changelog
237 238 if len(cl) > 0 and not from_existing:
238 239 raise error.Abort(_(b'repository is not empty'))
239 240
240 241 # determine number of revs in DAG
241 242 total = 0
242 243 for type, data in dagparser.parsedag(text):
243 244 if type == b'n':
244 245 total += 1
245 246
246 247 if mergeable_file:
247 248 linesperrev = 2
248 249 # make a file with k lines per rev
249 250 initialmergedlines = [
250 251 b'%d' % i for i in pycompat.xrange(0, total * linesperrev)
251 252 ]
252 253 initialmergedlines.append(b"")
253 254
254 255 tags = []
255 256 progress = ui.makeprogress(
256 257 _(b'building'), unit=_(b'revisions'), total=total
257 258 )
258 259 with progress, repo.wlock(), repo.lock(), repo.transaction(b"builddag"):
259 260 at = -1
260 261 atbranch = b'default'
261 262 nodeids = []
262 263 id = 0
263 264 progress.update(id)
264 265 for type, data in dagparser.parsedag(text):
265 266 if type == b'n':
266 267 ui.note((b'node %s\n' % pycompat.bytestr(data)))
267 268 id, ps = data
268 269
269 270 files = []
270 271 filecontent = {}
271 272
272 273 p2 = None
273 274 if mergeable_file:
274 275 fn = b"mf"
275 276 p1 = repo[ps[0]]
276 277 if len(ps) > 1:
277 278 p2 = repo[ps[1]]
278 279 pa = p1.ancestor(p2)
279 280 base, local, other = [
280 281 x[fn].data() for x in (pa, p1, p2)
281 282 ]
282 283 m3 = simplemerge.Merge3Text(base, local, other)
283 284 ml = [
284 285 l.strip()
285 286 for l in simplemerge.render_minimized(m3)[0]
286 287 ]
287 288 ml.append(b"")
288 289 elif at > 0:
289 290 ml = p1[fn].data().split(b"\n")
290 291 else:
291 292 ml = initialmergedlines
292 293 ml[id * linesperrev] += b" r%i" % id
293 294 mergedtext = b"\n".join(ml)
294 295 files.append(fn)
295 296 filecontent[fn] = mergedtext
296 297
297 298 if overwritten_file:
298 299 fn = b"of"
299 300 files.append(fn)
300 301 filecontent[fn] = b"r%i\n" % id
301 302
302 303 if new_file:
303 304 fn = b"nf%i" % id
304 305 files.append(fn)
305 306 filecontent[fn] = b"r%i\n" % id
306 307 if len(ps) > 1:
307 308 if not p2:
308 309 p2 = repo[ps[1]]
309 310 for fn in p2:
310 311 if fn.startswith(b"nf"):
311 312 files.append(fn)
312 313 filecontent[fn] = p2[fn].data()
313 314
314 315 def fctxfn(repo, cx, path):
315 316 if path in filecontent:
316 317 return context.memfilectx(
317 318 repo, cx, path, filecontent[path]
318 319 )
319 320 return None
320 321
321 322 if len(ps) == 0 or ps[0] < 0:
322 323 pars = [None, None]
323 324 elif len(ps) == 1:
324 325 pars = [nodeids[ps[0]], None]
325 326 else:
326 327 pars = [nodeids[p] for p in ps]
327 328 cx = context.memctx(
328 329 repo,
329 330 pars,
330 331 b"r%i" % id,
331 332 files,
332 333 fctxfn,
333 334 date=(id, 0),
334 335 user=b"debugbuilddag",
335 336 extra={b'branch': atbranch},
336 337 )
337 338 nodeid = repo.commitctx(cx)
338 339 nodeids.append(nodeid)
339 340 at = id
340 341 elif type == b'l':
341 342 id, name = data
342 343 ui.note((b'tag %s\n' % name))
343 344 tags.append(b"%s %s\n" % (hex(repo.changelog.node(id)), name))
344 345 elif type == b'a':
345 346 ui.note((b'branch %s\n' % data))
346 347 atbranch = data
347 348 progress.update(id)
348 349
349 350 if tags:
350 351 repo.vfs.write(b"localtags", b"".join(tags))
351 352
352 353
353 354 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
354 355 indent_string = b' ' * indent
355 356 if all:
356 357 ui.writenoi18n(
357 358 b"%sformat: id, p1, p2, cset, delta base, len(delta)\n"
358 359 % indent_string
359 360 )
360 361
361 362 def showchunks(named):
362 363 ui.write(b"\n%s%s\n" % (indent_string, named))
363 364 for deltadata in gen.deltaiter():
364 365 node, p1, p2, cs, deltabase, delta, flags, sidedata = deltadata
365 366 ui.write(
366 367 b"%s%s %s %s %s %s %d\n"
367 368 % (
368 369 indent_string,
369 370 hex(node),
370 371 hex(p1),
371 372 hex(p2),
372 373 hex(cs),
373 374 hex(deltabase),
374 375 len(delta),
375 376 )
376 377 )
377 378
378 379 gen.changelogheader()
379 380 showchunks(b"changelog")
380 381 gen.manifestheader()
381 382 showchunks(b"manifest")
382 383 for chunkdata in iter(gen.filelogheader, {}):
383 384 fname = chunkdata[b'filename']
384 385 showchunks(fname)
385 386 else:
386 387 if isinstance(gen, bundle2.unbundle20):
387 388 raise error.Abort(_(b'use debugbundle2 for this file'))
388 389 gen.changelogheader()
389 390 for deltadata in gen.deltaiter():
390 391 node, p1, p2, cs, deltabase, delta, flags, sidedata = deltadata
391 392 ui.write(b"%s%s\n" % (indent_string, hex(node)))
392 393
393 394
394 395 def _debugobsmarkers(ui, part, indent=0, **opts):
395 396 """display version and markers contained in 'data'"""
396 397 opts = pycompat.byteskwargs(opts)
397 398 data = part.read()
398 399 indent_string = b' ' * indent
399 400 try:
400 401 version, markers = obsolete._readmarkers(data)
401 402 except error.UnknownVersion as exc:
402 403 msg = b"%sunsupported version: %s (%d bytes)\n"
403 404 msg %= indent_string, exc.version, len(data)
404 405 ui.write(msg)
405 406 else:
406 407 msg = b"%sversion: %d (%d bytes)\n"
407 408 msg %= indent_string, version, len(data)
408 409 ui.write(msg)
409 410 fm = ui.formatter(b'debugobsolete', opts)
410 411 for rawmarker in sorted(markers):
411 412 m = obsutil.marker(None, rawmarker)
412 413 fm.startitem()
413 414 fm.plain(indent_string)
414 415 cmdutil.showmarker(fm, m)
415 416 fm.end()
416 417
417 418
418 419 def _debugphaseheads(ui, data, indent=0):
419 420 """display version and markers contained in 'data'"""
420 421 indent_string = b' ' * indent
421 422 headsbyphase = phases.binarydecode(data)
422 423 for phase in phases.allphases:
423 424 for head in headsbyphase[phase]:
424 425 ui.write(indent_string)
425 426 ui.write(b'%s %s\n' % (hex(head), phases.phasenames[phase]))
426 427
427 428
428 429 def _quasirepr(thing):
429 430 if isinstance(thing, (dict, util.sortdict, collections.OrderedDict)):
430 431 return b'{%s}' % (
431 432 b', '.join(b'%s: %s' % (k, thing[k]) for k in sorted(thing))
432 433 )
433 434 return pycompat.bytestr(repr(thing))
434 435
435 436
436 437 def _debugbundle2(ui, gen, all=None, **opts):
437 438 """lists the contents of a bundle2"""
438 439 if not isinstance(gen, bundle2.unbundle20):
439 440 raise error.Abort(_(b'not a bundle2 file'))
440 441 ui.write((b'Stream params: %s\n' % _quasirepr(gen.params)))
441 442 parttypes = opts.get('part_type', [])
442 443 for part in gen.iterparts():
443 444 if parttypes and part.type not in parttypes:
444 445 continue
445 446 msg = b'%s -- %s (mandatory: %r)\n'
446 447 ui.write((msg % (part.type, _quasirepr(part.params), part.mandatory)))
447 448 if part.type == b'changegroup':
448 449 version = part.params.get(b'version', b'01')
449 450 cg = changegroup.getunbundler(version, part, b'UN')
450 451 if not ui.quiet:
451 452 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
452 453 if part.type == b'obsmarkers':
453 454 if not ui.quiet:
454 455 _debugobsmarkers(ui, part, indent=4, **opts)
455 456 if part.type == b'phase-heads':
456 457 if not ui.quiet:
457 458 _debugphaseheads(ui, part, indent=4)
458 459
459 460
460 461 @command(
461 462 b'debugbundle',
462 463 [
463 464 (b'a', b'all', None, _(b'show all details')),
464 465 (b'', b'part-type', [], _(b'show only the named part type')),
465 466 (b'', b'spec', None, _(b'print the bundlespec of the bundle')),
466 467 ],
467 468 _(b'FILE'),
468 469 norepo=True,
469 470 )
470 471 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
471 472 """lists the contents of a bundle"""
472 473 with hg.openpath(ui, bundlepath) as f:
473 474 if spec:
474 475 spec = exchange.getbundlespec(ui, f)
475 476 ui.write(b'%s\n' % spec)
476 477 return
477 478
478 479 gen = exchange.readbundle(ui, f, bundlepath)
479 480 if isinstance(gen, bundle2.unbundle20):
480 481 return _debugbundle2(ui, gen, all=all, **opts)
481 482 _debugchangegroup(ui, gen, all=all, **opts)
482 483
483 484
484 485 @command(b'debugcapabilities', [], _(b'PATH'), norepo=True)
485 486 def debugcapabilities(ui, path, **opts):
486 487 """lists the capabilities of a remote peer"""
487 488 opts = pycompat.byteskwargs(opts)
488 489 peer = hg.peer(ui, opts, path)
489 490 try:
490 491 caps = peer.capabilities()
491 492 ui.writenoi18n(b'Main capabilities:\n')
492 493 for c in sorted(caps):
493 494 ui.write(b' %s\n' % c)
494 495 b2caps = bundle2.bundle2caps(peer)
495 496 if b2caps:
496 497 ui.writenoi18n(b'Bundle2 capabilities:\n')
497 498 for key, values in sorted(b2caps.items()):
498 499 ui.write(b' %s\n' % key)
499 500 for v in values:
500 501 ui.write(b' %s\n' % v)
501 502 finally:
502 503 peer.close()
503 504
504 505
505 506 @command(
506 507 b'debugchangedfiles',
507 508 [
508 509 (
509 510 b'',
510 511 b'compute',
511 512 False,
512 513 b"compute information instead of reading it from storage",
513 514 ),
514 515 ],
515 516 b'REV',
516 517 )
517 518 def debugchangedfiles(ui, repo, rev, **opts):
518 519 """list the stored files changes for a revision"""
519 520 ctx = logcmdutil.revsingle(repo, rev, None)
520 521 files = None
521 522
522 523 if opts['compute']:
523 524 files = metadata.compute_all_files_changes(ctx)
524 525 else:
525 526 sd = repo.changelog.sidedata(ctx.rev())
526 527 files_block = sd.get(sidedata.SD_FILES)
527 528 if files_block is not None:
528 529 files = metadata.decode_files_sidedata(sd)
529 530 if files is not None:
530 531 for f in sorted(files.touched):
531 532 if f in files.added:
532 533 action = b"added"
533 534 elif f in files.removed:
534 535 action = b"removed"
535 536 elif f in files.merged:
536 537 action = b"merged"
537 538 elif f in files.salvaged:
538 539 action = b"salvaged"
539 540 else:
540 541 action = b"touched"
541 542
542 543 copy_parent = b""
543 544 copy_source = b""
544 545 if f in files.copied_from_p1:
545 546 copy_parent = b"p1"
546 547 copy_source = files.copied_from_p1[f]
547 548 elif f in files.copied_from_p2:
548 549 copy_parent = b"p2"
549 550 copy_source = files.copied_from_p2[f]
550 551
551 552 data = (action, copy_parent, f, copy_source)
552 553 template = b"%-8s %2s: %s, %s;\n"
553 554 ui.write(template % data)
554 555
555 556
556 557 @command(b'debugcheckstate', [], b'')
557 558 def debugcheckstate(ui, repo):
558 559 """validate the correctness of the current dirstate"""
559 560 parent1, parent2 = repo.dirstate.parents()
560 561 m1 = repo[parent1].manifest()
561 562 m2 = repo[parent2].manifest()
562 563 errors = 0
563 564 for err in repo.dirstate.verify(m1, m2):
564 565 ui.warn(err[0] % err[1:])
565 566 errors += 1
566 567 if errors:
567 568 errstr = _(b".hg/dirstate inconsistent with current parent's manifest")
568 569 raise error.Abort(errstr)
569 570
570 571
571 572 @command(
572 573 b'debugcolor',
573 574 [(b'', b'style', None, _(b'show all configured styles'))],
574 575 b'hg debugcolor',
575 576 )
576 577 def debugcolor(ui, repo, **opts):
577 578 """show available color, effects or style"""
578 579 ui.writenoi18n(b'color mode: %s\n' % stringutil.pprint(ui._colormode))
579 580 if opts.get('style'):
580 581 return _debugdisplaystyle(ui)
581 582 else:
582 583 return _debugdisplaycolor(ui)
583 584
584 585
585 586 def _debugdisplaycolor(ui):
586 587 ui = ui.copy()
587 588 ui._styles.clear()
588 589 for effect in color._activeeffects(ui).keys():
589 590 ui._styles[effect] = effect
590 591 if ui._terminfoparams:
591 592 for k, v in ui.configitems(b'color'):
592 593 if k.startswith(b'color.'):
593 594 ui._styles[k] = k[6:]
594 595 elif k.startswith(b'terminfo.'):
595 596 ui._styles[k] = k[9:]
596 597 ui.write(_(b'available colors:\n'))
597 598 # sort label with a '_' after the other to group '_background' entry.
598 599 items = sorted(ui._styles.items(), key=lambda i: (b'_' in i[0], i[0], i[1]))
599 600 for colorname, label in items:
600 601 ui.write(b'%s\n' % colorname, label=label)
601 602
602 603
603 604 def _debugdisplaystyle(ui):
604 605 ui.write(_(b'available style:\n'))
605 606 if not ui._styles:
606 607 return
607 608 width = max(len(s) for s in ui._styles)
608 609 for label, effects in sorted(ui._styles.items()):
609 610 ui.write(b'%s' % label, label=label)
610 611 if effects:
611 612 # 50
612 613 ui.write(b': ')
613 614 ui.write(b' ' * (max(0, width - len(label))))
614 615 ui.write(b', '.join(ui.label(e, e) for e in effects.split()))
615 616 ui.write(b'\n')
616 617
617 618
618 619 @command(b'debugcreatestreamclonebundle', [], b'FILE')
619 620 def debugcreatestreamclonebundle(ui, repo, fname):
620 621 """create a stream clone bundle file
621 622
622 623 Stream bundles are special bundles that are essentially archives of
623 624 revlog files. They are commonly used for cloning very quickly.
624 625 """
625 626 # TODO we may want to turn this into an abort when this functionality
626 627 # is moved into `hg bundle`.
627 628 if phases.hassecret(repo):
628 629 ui.warn(
629 630 _(
630 631 b'(warning: stream clone bundle will contain secret '
631 632 b'revisions)\n'
632 633 )
633 634 )
634 635
635 636 requirements, gen = streamclone.generatebundlev1(repo)
636 637 changegroup.writechunks(ui, gen, fname)
637 638
638 639 ui.write(_(b'bundle requirements: %s\n') % b', '.join(sorted(requirements)))
639 640
640 641
641 642 @command(
642 643 b'debugdag',
643 644 [
644 645 (b't', b'tags', None, _(b'use tags as labels')),
645 646 (b'b', b'branches', None, _(b'annotate with branch names')),
646 647 (b'', b'dots', None, _(b'use dots for runs')),
647 648 (b's', b'spaces', None, _(b'separate elements by spaces')),
648 649 ],
649 650 _(b'[OPTION]... [FILE [REV]...]'),
650 651 optionalrepo=True,
651 652 )
652 653 def debugdag(ui, repo, file_=None, *revs, **opts):
653 654 """format the changelog or an index DAG as a concise textual description
654 655
655 656 If you pass a revlog index, the revlog's DAG is emitted. If you list
656 657 revision numbers, they get labeled in the output as rN.
657 658
658 659 Otherwise, the changelog DAG of the current repo is emitted.
659 660 """
660 661 spaces = opts.get('spaces')
661 662 dots = opts.get('dots')
662 663 if file_:
663 664 rlog = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False), file_)
664 665 revs = {int(r) for r in revs}
665 666
666 667 def events():
667 668 for r in rlog:
668 669 yield b'n', (r, list(p for p in rlog.parentrevs(r) if p != -1))
669 670 if r in revs:
670 671 yield b'l', (r, b"r%i" % r)
671 672
672 673 elif repo:
673 674 cl = repo.changelog
674 675 tags = opts.get('tags')
675 676 branches = opts.get('branches')
676 677 if tags:
677 678 labels = {}
678 679 for l, n in repo.tags().items():
679 680 labels.setdefault(cl.rev(n), []).append(l)
680 681
681 682 def events():
682 683 b = b"default"
683 684 for r in cl:
684 685 if branches:
685 686 newb = cl.read(cl.node(r))[5][b'branch']
686 687 if newb != b:
687 688 yield b'a', newb
688 689 b = newb
689 690 yield b'n', (r, list(p for p in cl.parentrevs(r) if p != -1))
690 691 if tags:
691 692 ls = labels.get(r)
692 693 if ls:
693 694 for l in ls:
694 695 yield b'l', (r, l)
695 696
696 697 else:
697 698 raise error.Abort(_(b'need repo for changelog dag'))
698 699
699 700 for line in dagparser.dagtextlines(
700 701 events(),
701 702 addspaces=spaces,
702 703 wraplabels=True,
703 704 wrapannotations=True,
704 705 wrapnonlinear=dots,
705 706 usedots=dots,
706 707 maxlinewidth=70,
707 708 ):
708 709 ui.write(line)
709 710 ui.write(b"\n")
710 711
711 712
712 713 @command(b'debugdata', cmdutil.debugrevlogopts, _(b'-c|-m|FILE REV'))
713 714 def debugdata(ui, repo, file_, rev=None, **opts):
714 715 """dump the contents of a data file revision"""
715 716 opts = pycompat.byteskwargs(opts)
716 717 if opts.get(b'changelog') or opts.get(b'manifest') or opts.get(b'dir'):
717 718 if rev is not None:
718 719 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
719 720 file_, rev = None, file_
720 721 elif rev is None:
721 722 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
722 723 r = cmdutil.openstorage(repo, b'debugdata', file_, opts)
723 724 try:
724 725 ui.write(r.rawdata(r.lookup(rev)))
725 726 except KeyError:
726 727 raise error.Abort(_(b'invalid revision identifier %s') % rev)
727 728
728 729
729 730 @command(
730 731 b'debugdate',
731 732 [(b'e', b'extended', None, _(b'try extended date formats'))],
732 733 _(b'[-e] DATE [RANGE]'),
733 734 norepo=True,
734 735 optionalrepo=True,
735 736 )
736 737 def debugdate(ui, date, range=None, **opts):
737 738 """parse and display a date"""
738 739 if opts["extended"]:
739 740 d = dateutil.parsedate(date, dateutil.extendeddateformats)
740 741 else:
741 742 d = dateutil.parsedate(date)
742 743 ui.writenoi18n(b"internal: %d %d\n" % d)
743 744 ui.writenoi18n(b"standard: %s\n" % dateutil.datestr(d))
744 745 if range:
745 746 m = dateutil.matchdate(range)
746 747 ui.writenoi18n(b"match: %s\n" % m(d[0]))
747 748
748 749
749 750 @command(
750 751 b'debugdeltachain',
751 752 cmdutil.debugrevlogopts + cmdutil.formatteropts,
752 753 _(b'-c|-m|FILE'),
753 754 optionalrepo=True,
754 755 )
755 756 def debugdeltachain(ui, repo, file_=None, **opts):
756 757 """dump information about delta chains in a revlog
757 758
758 759 Output can be templatized. Available template keywords are:
759 760
760 761 :``rev``: revision number
761 762 :``p1``: parent 1 revision number (for reference)
762 763 :``p2``: parent 2 revision number (for reference)
763 764 :``chainid``: delta chain identifier (numbered by unique base)
764 765 :``chainlen``: delta chain length to this revision
765 766 :``prevrev``: previous revision in delta chain
766 767 :``deltatype``: role of delta / how it was computed
767 768 - base: a full snapshot
768 769 - snap: an intermediate snapshot
769 770 - p1: a delta against the first parent
770 771 - p2: a delta against the second parent
771 772 - skip1: a delta against the same base as p1
772 773 (when p1 has empty delta
773 774 - skip2: a delta against the same base as p2
774 775 (when p2 has empty delta
775 776 - prev: a delta against the previous revision
776 777 - other: a delta against an arbitrary revision
777 778 :``compsize``: compressed size of revision
778 779 :``uncompsize``: uncompressed size of revision
779 780 :``chainsize``: total size of compressed revisions in chain
780 781 :``chainratio``: total chain size divided by uncompressed revision size
781 782 (new delta chains typically start at ratio 2.00)
782 783 :``lindist``: linear distance from base revision in delta chain to end
783 784 of this revision
784 785 :``extradist``: total size of revisions not part of this delta chain from
785 786 base of delta chain to end of this revision; a measurement
786 787 of how much extra data we need to read/seek across to read
787 788 the delta chain for this revision
788 789 :``extraratio``: extradist divided by chainsize; another representation of
789 790 how much unrelated data is needed to load this delta chain
790 791
791 792 If the repository is configured to use the sparse read, additional keywords
792 793 are available:
793 794
794 795 :``readsize``: total size of data read from the disk for a revision
795 796 (sum of the sizes of all the blocks)
796 797 :``largestblock``: size of the largest block of data read from the disk
797 798 :``readdensity``: density of useful bytes in the data read from the disk
798 799 :``srchunks``: in how many data hunks the whole revision would be read
799 800
800 801 The sparse read can be enabled with experimental.sparse-read = True
801 802 """
802 803 opts = pycompat.byteskwargs(opts)
803 804 r = cmdutil.openrevlog(repo, b'debugdeltachain', file_, opts)
804 805 index = r.index
805 806 start = r.start
806 807 length = r.length
807 808 generaldelta = r._generaldelta
808 809 withsparseread = getattr(r, '_withsparseread', False)
809 810
810 811 # security to avoid crash on corrupted revlogs
811 812 total_revs = len(index)
812 813
813 814 def revinfo(rev):
814 815 e = index[rev]
815 816 compsize = e[revlog_constants.ENTRY_DATA_COMPRESSED_LENGTH]
816 817 uncompsize = e[revlog_constants.ENTRY_DATA_UNCOMPRESSED_LENGTH]
817 818 chainsize = 0
818 819
819 820 base = e[revlog_constants.ENTRY_DELTA_BASE]
820 821 p1 = e[revlog_constants.ENTRY_PARENT_1]
821 822 p2 = e[revlog_constants.ENTRY_PARENT_2]
822 823
823 824 # If the parents of a revision has an empty delta, we never try to delta
824 825 # against that parent, but directly against the delta base of that
825 826 # parent (recursively). It avoids adding a useless entry in the chain.
826 827 #
827 828 # However we need to detect that as a special case for delta-type, that
828 829 # is not simply "other".
829 830 p1_base = p1
830 831 if p1 != nullrev and p1 < total_revs:
831 832 e1 = index[p1]
832 833 while e1[revlog_constants.ENTRY_DATA_COMPRESSED_LENGTH] == 0:
833 834 new_base = e1[revlog_constants.ENTRY_DELTA_BASE]
834 835 if (
835 836 new_base == p1_base
836 837 or new_base == nullrev
837 838 or new_base >= total_revs
838 839 ):
839 840 break
840 841 p1_base = new_base
841 842 e1 = index[p1_base]
842 843 p2_base = p2
843 844 if p2 != nullrev and p2 < total_revs:
844 845 e2 = index[p2]
845 846 while e2[revlog_constants.ENTRY_DATA_COMPRESSED_LENGTH] == 0:
846 847 new_base = e2[revlog_constants.ENTRY_DELTA_BASE]
847 848 if (
848 849 new_base == p2_base
849 850 or new_base == nullrev
850 851 or new_base >= total_revs
851 852 ):
852 853 break
853 854 p2_base = new_base
854 855 e2 = index[p2_base]
855 856
856 857 if generaldelta:
857 858 if base == p1:
858 859 deltatype = b'p1'
859 860 elif base == p2:
860 861 deltatype = b'p2'
861 862 elif base == rev:
862 863 deltatype = b'base'
863 864 elif base == p1_base:
864 865 deltatype = b'skip1'
865 866 elif base == p2_base:
866 867 deltatype = b'skip2'
867 868 elif r.issnapshot(rev):
868 869 deltatype = b'snap'
869 870 elif base == rev - 1:
870 871 deltatype = b'prev'
871 872 else:
872 873 deltatype = b'other'
873 874 else:
874 875 if base == rev:
875 876 deltatype = b'base'
876 877 else:
877 878 deltatype = b'prev'
878 879
879 880 chain = r._deltachain(rev)[0]
880 881 for iterrev in chain:
881 882 e = index[iterrev]
882 883 chainsize += e[revlog_constants.ENTRY_DATA_COMPRESSED_LENGTH]
883 884
884 885 return p1, p2, compsize, uncompsize, deltatype, chain, chainsize
885 886
886 887 fm = ui.formatter(b'debugdeltachain', opts)
887 888
888 889 fm.plain(
889 890 b' rev p1 p2 chain# chainlen prev delta '
890 891 b'size rawsize chainsize ratio lindist extradist '
891 892 b'extraratio'
892 893 )
893 894 if withsparseread:
894 895 fm.plain(b' readsize largestblk rddensity srchunks')
895 896 fm.plain(b'\n')
896 897
897 898 chainbases = {}
898 899 for rev in r:
899 900 p1, p2, comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
900 901 chainbase = chain[0]
901 902 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
902 903 basestart = start(chainbase)
903 904 revstart = start(rev)
904 905 lineardist = revstart + comp - basestart
905 906 extradist = lineardist - chainsize
906 907 try:
907 908 prevrev = chain[-2]
908 909 except IndexError:
909 910 prevrev = -1
910 911
911 912 if uncomp != 0:
912 913 chainratio = float(chainsize) / float(uncomp)
913 914 else:
914 915 chainratio = chainsize
915 916
916 917 if chainsize != 0:
917 918 extraratio = float(extradist) / float(chainsize)
918 919 else:
919 920 extraratio = extradist
920 921
921 922 fm.startitem()
922 923 fm.write(
923 924 b'rev p1 p2 chainid chainlen prevrev deltatype compsize '
924 925 b'uncompsize chainsize chainratio lindist extradist '
925 926 b'extraratio',
926 927 b'%7d %7d %7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f',
927 928 rev,
928 929 p1,
929 930 p2,
930 931 chainid,
931 932 len(chain),
932 933 prevrev,
933 934 deltatype,
934 935 comp,
935 936 uncomp,
936 937 chainsize,
937 938 chainratio,
938 939 lineardist,
939 940 extradist,
940 941 extraratio,
941 942 rev=rev,
942 943 chainid=chainid,
943 944 chainlen=len(chain),
944 945 prevrev=prevrev,
945 946 deltatype=deltatype,
946 947 compsize=comp,
947 948 uncompsize=uncomp,
948 949 chainsize=chainsize,
949 950 chainratio=chainratio,
950 951 lindist=lineardist,
951 952 extradist=extradist,
952 953 extraratio=extraratio,
953 954 )
954 955 if withsparseread:
955 956 readsize = 0
956 957 largestblock = 0
957 958 srchunks = 0
958 959
959 960 for revschunk in deltautil.slicechunk(r, chain):
960 961 srchunks += 1
961 962 blkend = start(revschunk[-1]) + length(revschunk[-1])
962 963 blksize = blkend - start(revschunk[0])
963 964
964 965 readsize += blksize
965 966 if largestblock < blksize:
966 967 largestblock = blksize
967 968
968 969 if readsize:
969 970 readdensity = float(chainsize) / float(readsize)
970 971 else:
971 972 readdensity = 1
972 973
973 974 fm.write(
974 975 b'readsize largestblock readdensity srchunks',
975 976 b' %10d %10d %9.5f %8d',
976 977 readsize,
977 978 largestblock,
978 979 readdensity,
979 980 srchunks,
980 981 readsize=readsize,
981 982 largestblock=largestblock,
982 983 readdensity=readdensity,
983 984 srchunks=srchunks,
984 985 )
985 986
986 987 fm.plain(b'\n')
987 988
988 989 fm.end()
989 990
990 991
991 992 @command(
993 b'debug-delta-find',
994 cmdutil.debugrevlogopts + cmdutil.formatteropts,
995 _(b'-c|-m|FILE REV'),
996 optionalrepo=True,
997 )
998 def debugdeltafind(ui, repo, arg_1, arg_2=None, **opts):
999 """display the computation to get to a valid delta for storing REV
1000
1001 This command will replay the process used to find the "best" delta to store
1002 a revision and display information about all the steps used to get to that
1003 result.
1004
1005 The revision use the revision number of the target storage (not changelog
1006 revision number).
1007
1008 note: the process is initiated from a full text of the revision to store.
1009 """
1010 opts = pycompat.byteskwargs(opts)
1011 if arg_2 is None:
1012 file_ = None
1013 rev = arg_1
1014 else:
1015 file_ = arg_1
1016 rev = arg_2
1017
1018 rev = int(rev)
1019
1020 revlog = cmdutil.openrevlog(repo, b'debugdeltachain', file_, opts)
1021
1022 deltacomputer = deltautil.deltacomputer(
1023 revlog,
1024 write_debug=ui.write,
1025 debug_search=True,
1026 )
1027
1028 node = revlog.node(rev)
1029 p1r, p2r = revlog.parentrevs(rev)
1030 p1 = revlog.node(p1r)
1031 p2 = revlog.node(p2r)
1032 btext = [revlog.revision(rev)]
1033 textlen = len(btext[0])
1034 cachedelta = None
1035 flags = revlog.flags(rev)
1036
1037 revinfo = revlogutils.revisioninfo(
1038 node,
1039 p1,
1040 p2,
1041 btext,
1042 textlen,
1043 cachedelta,
1044 flags,
1045 )
1046
1047 fh = revlog._datafp()
1048 deltacomputer.finddeltainfo(revinfo, fh, target_rev=rev)
1049
1050
1051 @command(
992 1052 b'debugdirstate|debugstate',
993 1053 [
994 1054 (
995 1055 b'',
996 1056 b'nodates',
997 1057 None,
998 1058 _(b'do not display the saved mtime (DEPRECATED)'),
999 1059 ),
1000 1060 (b'', b'dates', True, _(b'display the saved mtime')),
1001 1061 (b'', b'datesort', None, _(b'sort by saved mtime')),
1002 1062 (
1003 1063 b'',
1004 1064 b'docket',
1005 1065 False,
1006 1066 _(b'display the docket (metadata file) instead'),
1007 1067 ),
1008 1068 (
1009 1069 b'',
1010 1070 b'all',
1011 1071 False,
1012 1072 _(b'display dirstate-v2 tree nodes that would not exist in v1'),
1013 1073 ),
1014 1074 ],
1015 1075 _(b'[OPTION]...'),
1016 1076 )
1017 1077 def debugstate(ui, repo, **opts):
1018 1078 """show the contents of the current dirstate"""
1019 1079
1020 1080 if opts.get("docket"):
1021 1081 if not repo.dirstate._use_dirstate_v2:
1022 1082 raise error.Abort(_(b'dirstate v1 does not have a docket'))
1023 1083
1024 1084 docket = repo.dirstate._map.docket
1025 1085 (
1026 1086 start_offset,
1027 1087 root_nodes,
1028 1088 nodes_with_entry,
1029 1089 nodes_with_copy,
1030 1090 unused_bytes,
1031 1091 _unused,
1032 1092 ignore_pattern,
1033 1093 ) = dirstateutils.v2.TREE_METADATA.unpack(docket.tree_metadata)
1034 1094
1035 1095 ui.write(_(b"size of dirstate data: %d\n") % docket.data_size)
1036 1096 ui.write(_(b"data file uuid: %s\n") % docket.uuid)
1037 1097 ui.write(_(b"start offset of root nodes: %d\n") % start_offset)
1038 1098 ui.write(_(b"number of root nodes: %d\n") % root_nodes)
1039 1099 ui.write(_(b"nodes with entries: %d\n") % nodes_with_entry)
1040 1100 ui.write(_(b"nodes with copies: %d\n") % nodes_with_copy)
1041 1101 ui.write(_(b"number of unused bytes: %d\n") % unused_bytes)
1042 1102 ui.write(
1043 1103 _(b"ignore pattern hash: %s\n") % binascii.hexlify(ignore_pattern)
1044 1104 )
1045 1105 return
1046 1106
1047 1107 nodates = not opts['dates']
1048 1108 if opts.get('nodates') is not None:
1049 1109 nodates = True
1050 1110 datesort = opts.get('datesort')
1051 1111
1052 1112 if datesort:
1053 1113
1054 1114 def keyfunc(entry):
1055 1115 filename, _state, _mode, _size, mtime = entry
1056 1116 return (mtime, filename)
1057 1117
1058 1118 else:
1059 1119 keyfunc = None # sort by filename
1060 1120 entries = list(repo.dirstate._map.debug_iter(all=opts['all']))
1061 1121 entries.sort(key=keyfunc)
1062 1122 for entry in entries:
1063 1123 filename, state, mode, size, mtime = entry
1064 1124 if mtime == -1:
1065 1125 timestr = b'unset '
1066 1126 elif nodates:
1067 1127 timestr = b'set '
1068 1128 else:
1069 1129 timestr = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(mtime))
1070 1130 timestr = encoding.strtolocal(timestr)
1071 1131 if mode & 0o20000:
1072 1132 mode = b'lnk'
1073 1133 else:
1074 1134 mode = b'%3o' % (mode & 0o777 & ~util.umask)
1075 1135 ui.write(b"%c %s %10d %s%s\n" % (state, mode, size, timestr, filename))
1076 1136 for f in repo.dirstate.copies():
1077 1137 ui.write(_(b"copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1078 1138
1079 1139
1080 1140 @command(
1081 1141 b'debugdirstateignorepatternshash',
1082 1142 [],
1083 1143 _(b''),
1084 1144 )
1085 1145 def debugdirstateignorepatternshash(ui, repo, **opts):
1086 1146 """show the hash of ignore patterns stored in dirstate if v2,
1087 1147 or nothing for dirstate-v2
1088 1148 """
1089 1149 if repo.dirstate._use_dirstate_v2:
1090 1150 docket = repo.dirstate._map.docket
1091 1151 hash_len = 20 # 160 bits for SHA-1
1092 1152 hash_bytes = docket.tree_metadata[-hash_len:]
1093 1153 ui.write(binascii.hexlify(hash_bytes) + b'\n')
1094 1154
1095 1155
1096 1156 @command(
1097 1157 b'debugdiscovery',
1098 1158 [
1099 1159 (b'', b'old', None, _(b'use old-style discovery')),
1100 1160 (
1101 1161 b'',
1102 1162 b'nonheads',
1103 1163 None,
1104 1164 _(b'use old-style discovery with non-heads included'),
1105 1165 ),
1106 1166 (b'', b'rev', [], b'restrict discovery to this set of revs'),
1107 1167 (b'', b'seed', b'12323', b'specify the random seed use for discovery'),
1108 1168 (
1109 1169 b'',
1110 1170 b'local-as-revs',
1111 1171 b"",
1112 1172 b'treat local has having these revisions only',
1113 1173 ),
1114 1174 (
1115 1175 b'',
1116 1176 b'remote-as-revs',
1117 1177 b"",
1118 1178 b'use local as remote, with only these revisions',
1119 1179 ),
1120 1180 ]
1121 1181 + cmdutil.remoteopts
1122 1182 + cmdutil.formatteropts,
1123 1183 _(b'[--rev REV] [OTHER]'),
1124 1184 )
1125 1185 def debugdiscovery(ui, repo, remoteurl=b"default", **opts):
1126 1186 """runs the changeset discovery protocol in isolation
1127 1187
1128 1188 The local peer can be "replaced" by a subset of the local repository by
1129 1189 using the `--local-as-revs` flag. Int he same way, usual `remote` peer can
1130 1190 be "replaced" by a subset of the local repository using the
1131 1191 `--local-as-revs` flag. This is useful to efficiently debug pathological
1132 1192 discovery situation.
1133 1193
1134 1194 The following developer oriented config are relevant for people playing with this command:
1135 1195
1136 1196 * devel.discovery.exchange-heads=True
1137 1197
1138 1198 If False, the discovery will not start with
1139 1199 remote head fetching and local head querying.
1140 1200
1141 1201 * devel.discovery.grow-sample=True
1142 1202
1143 1203 If False, the sample size used in set discovery will not be increased
1144 1204 through the process
1145 1205
1146 1206 * devel.discovery.grow-sample.dynamic=True
1147 1207
1148 1208 When discovery.grow-sample.dynamic is True, the default, the sample size is
1149 1209 adapted to the shape of the undecided set (it is set to the max of:
1150 1210 <target-size>, len(roots(undecided)), len(heads(undecided)
1151 1211
1152 1212 * devel.discovery.grow-sample.rate=1.05
1153 1213
1154 1214 the rate at which the sample grow
1155 1215
1156 1216 * devel.discovery.randomize=True
1157 1217
1158 1218 If andom sampling during discovery are deterministic. It is meant for
1159 1219 integration tests.
1160 1220
1161 1221 * devel.discovery.sample-size=200
1162 1222
1163 1223 Control the initial size of the discovery sample
1164 1224
1165 1225 * devel.discovery.sample-size.initial=100
1166 1226
1167 1227 Control the initial size of the discovery for initial change
1168 1228 """
1169 1229 opts = pycompat.byteskwargs(opts)
1170 1230 unfi = repo.unfiltered()
1171 1231
1172 1232 # setup potential extra filtering
1173 1233 local_revs = opts[b"local_as_revs"]
1174 1234 remote_revs = opts[b"remote_as_revs"]
1175 1235
1176 1236 # make sure tests are repeatable
1177 1237 random.seed(int(opts[b'seed']))
1178 1238
1179 1239 if not remote_revs:
1180 1240
1181 1241 remoteurl, branches = urlutil.get_unique_pull_path(
1182 1242 b'debugdiscovery', repo, ui, remoteurl
1183 1243 )
1184 1244 remote = hg.peer(repo, opts, remoteurl)
1185 1245 ui.status(_(b'comparing with %s\n') % urlutil.hidepassword(remoteurl))
1186 1246 else:
1187 1247 branches = (None, [])
1188 1248 remote_filtered_revs = logcmdutil.revrange(
1189 1249 unfi, [b"not (::(%s))" % remote_revs]
1190 1250 )
1191 1251 remote_filtered_revs = frozenset(remote_filtered_revs)
1192 1252
1193 1253 def remote_func(x):
1194 1254 return remote_filtered_revs
1195 1255
1196 1256 repoview.filtertable[b'debug-discovery-remote-filter'] = remote_func
1197 1257
1198 1258 remote = repo.peer()
1199 1259 remote._repo = remote._repo.filtered(b'debug-discovery-remote-filter')
1200 1260
1201 1261 if local_revs:
1202 1262 local_filtered_revs = logcmdutil.revrange(
1203 1263 unfi, [b"not (::(%s))" % local_revs]
1204 1264 )
1205 1265 local_filtered_revs = frozenset(local_filtered_revs)
1206 1266
1207 1267 def local_func(x):
1208 1268 return local_filtered_revs
1209 1269
1210 1270 repoview.filtertable[b'debug-discovery-local-filter'] = local_func
1211 1271 repo = repo.filtered(b'debug-discovery-local-filter')
1212 1272
1213 1273 data = {}
1214 1274 if opts.get(b'old'):
1215 1275
1216 1276 def doit(pushedrevs, remoteheads, remote=remote):
1217 1277 if not util.safehasattr(remote, b'branches'):
1218 1278 # enable in-client legacy support
1219 1279 remote = localrepo.locallegacypeer(remote.local())
1220 1280 common, _in, hds = treediscovery.findcommonincoming(
1221 1281 repo, remote, force=True, audit=data
1222 1282 )
1223 1283 common = set(common)
1224 1284 if not opts.get(b'nonheads'):
1225 1285 ui.writenoi18n(
1226 1286 b"unpruned common: %s\n"
1227 1287 % b" ".join(sorted(short(n) for n in common))
1228 1288 )
1229 1289
1230 1290 clnode = repo.changelog.node
1231 1291 common = repo.revs(b'heads(::%ln)', common)
1232 1292 common = {clnode(r) for r in common}
1233 1293 return common, hds
1234 1294
1235 1295 else:
1236 1296
1237 1297 def doit(pushedrevs, remoteheads, remote=remote):
1238 1298 nodes = None
1239 1299 if pushedrevs:
1240 1300 revs = logcmdutil.revrange(repo, pushedrevs)
1241 1301 nodes = [repo[r].node() for r in revs]
1242 1302 common, any, hds = setdiscovery.findcommonheads(
1243 1303 ui, repo, remote, ancestorsof=nodes, audit=data
1244 1304 )
1245 1305 return common, hds
1246 1306
1247 1307 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches, revs=None)
1248 1308 localrevs = opts[b'rev']
1249 1309
1250 1310 fm = ui.formatter(b'debugdiscovery', opts)
1251 1311 if fm.strict_format:
1252 1312
1253 1313 @contextlib.contextmanager
1254 1314 def may_capture_output():
1255 1315 ui.pushbuffer()
1256 1316 yield
1257 1317 data[b'output'] = ui.popbuffer()
1258 1318
1259 1319 else:
1260 1320 may_capture_output = util.nullcontextmanager
1261 1321 with may_capture_output():
1262 1322 with util.timedcm('debug-discovery') as t:
1263 1323 common, hds = doit(localrevs, remoterevs)
1264 1324
1265 1325 # compute all statistics
1266 1326 heads_common = set(common)
1267 1327 heads_remote = set(hds)
1268 1328 heads_local = set(repo.heads())
1269 1329 # note: they cannot be a local or remote head that is in common and not
1270 1330 # itself a head of common.
1271 1331 heads_common_local = heads_common & heads_local
1272 1332 heads_common_remote = heads_common & heads_remote
1273 1333 heads_common_both = heads_common & heads_remote & heads_local
1274 1334
1275 1335 all = repo.revs(b'all()')
1276 1336 common = repo.revs(b'::%ln', common)
1277 1337 roots_common = repo.revs(b'roots(::%ld)', common)
1278 1338 missing = repo.revs(b'not ::%ld', common)
1279 1339 heads_missing = repo.revs(b'heads(%ld)', missing)
1280 1340 roots_missing = repo.revs(b'roots(%ld)', missing)
1281 1341 assert len(common) + len(missing) == len(all)
1282 1342
1283 1343 initial_undecided = repo.revs(
1284 1344 b'not (::%ln or %ln::)', heads_common_remote, heads_common_local
1285 1345 )
1286 1346 heads_initial_undecided = repo.revs(b'heads(%ld)', initial_undecided)
1287 1347 roots_initial_undecided = repo.revs(b'roots(%ld)', initial_undecided)
1288 1348 common_initial_undecided = initial_undecided & common
1289 1349 missing_initial_undecided = initial_undecided & missing
1290 1350
1291 1351 data[b'elapsed'] = t.elapsed
1292 1352 data[b'nb-common-heads'] = len(heads_common)
1293 1353 data[b'nb-common-heads-local'] = len(heads_common_local)
1294 1354 data[b'nb-common-heads-remote'] = len(heads_common_remote)
1295 1355 data[b'nb-common-heads-both'] = len(heads_common_both)
1296 1356 data[b'nb-common-roots'] = len(roots_common)
1297 1357 data[b'nb-head-local'] = len(heads_local)
1298 1358 data[b'nb-head-local-missing'] = len(heads_local) - len(heads_common_local)
1299 1359 data[b'nb-head-remote'] = len(heads_remote)
1300 1360 data[b'nb-head-remote-unknown'] = len(heads_remote) - len(
1301 1361 heads_common_remote
1302 1362 )
1303 1363 data[b'nb-revs'] = len(all)
1304 1364 data[b'nb-revs-common'] = len(common)
1305 1365 data[b'nb-revs-missing'] = len(missing)
1306 1366 data[b'nb-missing-heads'] = len(heads_missing)
1307 1367 data[b'nb-missing-roots'] = len(roots_missing)
1308 1368 data[b'nb-ini_und'] = len(initial_undecided)
1309 1369 data[b'nb-ini_und-heads'] = len(heads_initial_undecided)
1310 1370 data[b'nb-ini_und-roots'] = len(roots_initial_undecided)
1311 1371 data[b'nb-ini_und-common'] = len(common_initial_undecided)
1312 1372 data[b'nb-ini_und-missing'] = len(missing_initial_undecided)
1313 1373
1314 1374 fm.startitem()
1315 1375 fm.data(**pycompat.strkwargs(data))
1316 1376 # display discovery summary
1317 1377 fm.plain(b"elapsed time: %(elapsed)f seconds\n" % data)
1318 1378 fm.plain(b"round-trips: %(total-roundtrips)9d\n" % data)
1319 1379 fm.plain(b"queries: %(total-queries)9d\n" % data)
1320 1380 fm.plain(b"heads summary:\n")
1321 1381 fm.plain(b" total common heads: %(nb-common-heads)9d\n" % data)
1322 1382 fm.plain(b" also local heads: %(nb-common-heads-local)9d\n" % data)
1323 1383 fm.plain(b" also remote heads: %(nb-common-heads-remote)9d\n" % data)
1324 1384 fm.plain(b" both: %(nb-common-heads-both)9d\n" % data)
1325 1385 fm.plain(b" local heads: %(nb-head-local)9d\n" % data)
1326 1386 fm.plain(b" common: %(nb-common-heads-local)9d\n" % data)
1327 1387 fm.plain(b" missing: %(nb-head-local-missing)9d\n" % data)
1328 1388 fm.plain(b" remote heads: %(nb-head-remote)9d\n" % data)
1329 1389 fm.plain(b" common: %(nb-common-heads-remote)9d\n" % data)
1330 1390 fm.plain(b" unknown: %(nb-head-remote-unknown)9d\n" % data)
1331 1391 fm.plain(b"local changesets: %(nb-revs)9d\n" % data)
1332 1392 fm.plain(b" common: %(nb-revs-common)9d\n" % data)
1333 1393 fm.plain(b" heads: %(nb-common-heads)9d\n" % data)
1334 1394 fm.plain(b" roots: %(nb-common-roots)9d\n" % data)
1335 1395 fm.plain(b" missing: %(nb-revs-missing)9d\n" % data)
1336 1396 fm.plain(b" heads: %(nb-missing-heads)9d\n" % data)
1337 1397 fm.plain(b" roots: %(nb-missing-roots)9d\n" % data)
1338 1398 fm.plain(b" first undecided set: %(nb-ini_und)9d\n" % data)
1339 1399 fm.plain(b" heads: %(nb-ini_und-heads)9d\n" % data)
1340 1400 fm.plain(b" roots: %(nb-ini_und-roots)9d\n" % data)
1341 1401 fm.plain(b" common: %(nb-ini_und-common)9d\n" % data)
1342 1402 fm.plain(b" missing: %(nb-ini_und-missing)9d\n" % data)
1343 1403
1344 1404 if ui.verbose:
1345 1405 fm.plain(
1346 1406 b"common heads: %s\n"
1347 1407 % b" ".join(sorted(short(n) for n in heads_common))
1348 1408 )
1349 1409 fm.end()
1350 1410
1351 1411
1352 1412 _chunksize = 4 << 10
1353 1413
1354 1414
1355 1415 @command(
1356 1416 b'debugdownload',
1357 1417 [
1358 1418 (b'o', b'output', b'', _(b'path')),
1359 1419 ],
1360 1420 optionalrepo=True,
1361 1421 )
1362 1422 def debugdownload(ui, repo, url, output=None, **opts):
1363 1423 """download a resource using Mercurial logic and config"""
1364 1424 fh = urlmod.open(ui, url, output)
1365 1425
1366 1426 dest = ui
1367 1427 if output:
1368 1428 dest = open(output, b"wb", _chunksize)
1369 1429 try:
1370 1430 data = fh.read(_chunksize)
1371 1431 while data:
1372 1432 dest.write(data)
1373 1433 data = fh.read(_chunksize)
1374 1434 finally:
1375 1435 if output:
1376 1436 dest.close()
1377 1437
1378 1438
1379 1439 @command(b'debugextensions', cmdutil.formatteropts, [], optionalrepo=True)
1380 1440 def debugextensions(ui, repo, **opts):
1381 1441 '''show information about active extensions'''
1382 1442 opts = pycompat.byteskwargs(opts)
1383 1443 exts = extensions.extensions(ui)
1384 1444 hgver = util.version()
1385 1445 fm = ui.formatter(b'debugextensions', opts)
1386 1446 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
1387 1447 isinternal = extensions.ismoduleinternal(extmod)
1388 1448 extsource = None
1389 1449
1390 1450 if util.safehasattr(extmod, '__file__'):
1391 1451 extsource = pycompat.fsencode(extmod.__file__)
1392 1452 elif getattr(sys, 'oxidized', False):
1393 1453 extsource = pycompat.sysexecutable
1394 1454 if isinternal:
1395 1455 exttestedwith = [] # never expose magic string to users
1396 1456 else:
1397 1457 exttestedwith = getattr(extmod, 'testedwith', b'').split()
1398 1458 extbuglink = getattr(extmod, 'buglink', None)
1399 1459
1400 1460 fm.startitem()
1401 1461
1402 1462 if ui.quiet or ui.verbose:
1403 1463 fm.write(b'name', b'%s\n', extname)
1404 1464 else:
1405 1465 fm.write(b'name', b'%s', extname)
1406 1466 if isinternal or hgver in exttestedwith:
1407 1467 fm.plain(b'\n')
1408 1468 elif not exttestedwith:
1409 1469 fm.plain(_(b' (untested!)\n'))
1410 1470 else:
1411 1471 lasttestedversion = exttestedwith[-1]
1412 1472 fm.plain(b' (%s!)\n' % lasttestedversion)
1413 1473
1414 1474 fm.condwrite(
1415 1475 ui.verbose and extsource,
1416 1476 b'source',
1417 1477 _(b' location: %s\n'),
1418 1478 extsource or b"",
1419 1479 )
1420 1480
1421 1481 if ui.verbose:
1422 1482 fm.plain(_(b' bundled: %s\n') % [b'no', b'yes'][isinternal])
1423 1483 fm.data(bundled=isinternal)
1424 1484
1425 1485 fm.condwrite(
1426 1486 ui.verbose and exttestedwith,
1427 1487 b'testedwith',
1428 1488 _(b' tested with: %s\n'),
1429 1489 fm.formatlist(exttestedwith, name=b'ver'),
1430 1490 )
1431 1491
1432 1492 fm.condwrite(
1433 1493 ui.verbose and extbuglink,
1434 1494 b'buglink',
1435 1495 _(b' bug reporting: %s\n'),
1436 1496 extbuglink or b"",
1437 1497 )
1438 1498
1439 1499 fm.end()
1440 1500
1441 1501
1442 1502 @command(
1443 1503 b'debugfileset',
1444 1504 [
1445 1505 (
1446 1506 b'r',
1447 1507 b'rev',
1448 1508 b'',
1449 1509 _(b'apply the filespec on this revision'),
1450 1510 _(b'REV'),
1451 1511 ),
1452 1512 (
1453 1513 b'',
1454 1514 b'all-files',
1455 1515 False,
1456 1516 _(b'test files from all revisions and working directory'),
1457 1517 ),
1458 1518 (
1459 1519 b's',
1460 1520 b'show-matcher',
1461 1521 None,
1462 1522 _(b'print internal representation of matcher'),
1463 1523 ),
1464 1524 (
1465 1525 b'p',
1466 1526 b'show-stage',
1467 1527 [],
1468 1528 _(b'print parsed tree at the given stage'),
1469 1529 _(b'NAME'),
1470 1530 ),
1471 1531 ],
1472 1532 _(b'[-r REV] [--all-files] [OPTION]... FILESPEC'),
1473 1533 )
1474 1534 def debugfileset(ui, repo, expr, **opts):
1475 1535 '''parse and apply a fileset specification'''
1476 1536 from . import fileset
1477 1537
1478 1538 fileset.symbols # force import of fileset so we have predicates to optimize
1479 1539 opts = pycompat.byteskwargs(opts)
1480 1540 ctx = logcmdutil.revsingle(repo, opts.get(b'rev'), None)
1481 1541
1482 1542 stages = [
1483 1543 (b'parsed', pycompat.identity),
1484 1544 (b'analyzed', filesetlang.analyze),
1485 1545 (b'optimized', filesetlang.optimize),
1486 1546 ]
1487 1547 stagenames = {n for n, f in stages}
1488 1548
1489 1549 showalways = set()
1490 1550 if ui.verbose and not opts[b'show_stage']:
1491 1551 # show parsed tree by --verbose (deprecated)
1492 1552 showalways.add(b'parsed')
1493 1553 if opts[b'show_stage'] == [b'all']:
1494 1554 showalways.update(stagenames)
1495 1555 else:
1496 1556 for n in opts[b'show_stage']:
1497 1557 if n not in stagenames:
1498 1558 raise error.Abort(_(b'invalid stage name: %s') % n)
1499 1559 showalways.update(opts[b'show_stage'])
1500 1560
1501 1561 tree = filesetlang.parse(expr)
1502 1562 for n, f in stages:
1503 1563 tree = f(tree)
1504 1564 if n in showalways:
1505 1565 if opts[b'show_stage'] or n != b'parsed':
1506 1566 ui.write(b"* %s:\n" % n)
1507 1567 ui.write(filesetlang.prettyformat(tree), b"\n")
1508 1568
1509 1569 files = set()
1510 1570 if opts[b'all_files']:
1511 1571 for r in repo:
1512 1572 c = repo[r]
1513 1573 files.update(c.files())
1514 1574 files.update(c.substate)
1515 1575 if opts[b'all_files'] or ctx.rev() is None:
1516 1576 wctx = repo[None]
1517 1577 files.update(
1518 1578 repo.dirstate.walk(
1519 1579 scmutil.matchall(repo),
1520 1580 subrepos=list(wctx.substate),
1521 1581 unknown=True,
1522 1582 ignored=True,
1523 1583 )
1524 1584 )
1525 1585 files.update(wctx.substate)
1526 1586 else:
1527 1587 files.update(ctx.files())
1528 1588 files.update(ctx.substate)
1529 1589
1530 1590 m = ctx.matchfileset(repo.getcwd(), expr)
1531 1591 if opts[b'show_matcher'] or (opts[b'show_matcher'] is None and ui.verbose):
1532 1592 ui.writenoi18n(b'* matcher:\n', stringutil.prettyrepr(m), b'\n')
1533 1593 for f in sorted(files):
1534 1594 if not m(f):
1535 1595 continue
1536 1596 ui.write(b"%s\n" % f)
1537 1597
1538 1598
1539 1599 @command(
1540 1600 b"debug-repair-issue6528",
1541 1601 [
1542 1602 (
1543 1603 b'',
1544 1604 b'to-report',
1545 1605 b'',
1546 1606 _(b'build a report of affected revisions to this file'),
1547 1607 _(b'FILE'),
1548 1608 ),
1549 1609 (
1550 1610 b'',
1551 1611 b'from-report',
1552 1612 b'',
1553 1613 _(b'repair revisions listed in this report file'),
1554 1614 _(b'FILE'),
1555 1615 ),
1556 1616 (
1557 1617 b'',
1558 1618 b'paranoid',
1559 1619 False,
1560 1620 _(b'check that both detection methods do the same thing'),
1561 1621 ),
1562 1622 ]
1563 1623 + cmdutil.dryrunopts,
1564 1624 )
1565 1625 def debug_repair_issue6528(ui, repo, **opts):
1566 1626 """find affected revisions and repair them. See issue6528 for more details.
1567 1627
1568 1628 The `--to-report` and `--from-report` flags allow you to cache and reuse the
1569 1629 computation of affected revisions for a given repository across clones.
1570 1630 The report format is line-based (with empty lines ignored):
1571 1631
1572 1632 ```
1573 1633 <ascii-hex of the affected revision>,... <unencoded filelog index filename>
1574 1634 ```
1575 1635
1576 1636 There can be multiple broken revisions per filelog, they are separated by
1577 1637 a comma with no spaces. The only space is between the revision(s) and the
1578 1638 filename.
1579 1639
1580 1640 Note that this does *not* mean that this repairs future affected revisions,
1581 1641 that needs a separate fix at the exchange level that was introduced in
1582 1642 Mercurial 5.9.1.
1583 1643
1584 1644 There is a `--paranoid` flag to test that the fast implementation is correct
1585 1645 by checking it against the slow implementation. Since this matter is quite
1586 1646 urgent and testing every edge-case is probably quite costly, we use this
1587 1647 method to test on large repositories as a fuzzing method of sorts.
1588 1648 """
1589 1649 cmdutil.check_incompatible_arguments(
1590 1650 opts, 'to_report', ['from_report', 'dry_run']
1591 1651 )
1592 1652 dry_run = opts.get('dry_run')
1593 1653 to_report = opts.get('to_report')
1594 1654 from_report = opts.get('from_report')
1595 1655 paranoid = opts.get('paranoid')
1596 1656 # TODO maybe add filelog pattern and revision pattern parameters to help
1597 1657 # narrow down the search for users that know what they're looking for?
1598 1658
1599 1659 if requirements.REVLOGV1_REQUIREMENT not in repo.requirements:
1600 1660 msg = b"can only repair revlogv1 repositories, v2 is not affected"
1601 1661 raise error.Abort(_(msg))
1602 1662
1603 1663 rewrite.repair_issue6528(
1604 1664 ui,
1605 1665 repo,
1606 1666 dry_run=dry_run,
1607 1667 to_report=to_report,
1608 1668 from_report=from_report,
1609 1669 paranoid=paranoid,
1610 1670 )
1611 1671
1612 1672
1613 1673 @command(b'debugformat', [] + cmdutil.formatteropts)
1614 1674 def debugformat(ui, repo, **opts):
1615 1675 """display format information about the current repository
1616 1676
1617 1677 Use --verbose to get extra information about current config value and
1618 1678 Mercurial default."""
1619 1679 opts = pycompat.byteskwargs(opts)
1620 1680 maxvariantlength = max(len(fv.name) for fv in upgrade.allformatvariant)
1621 1681 maxvariantlength = max(len(b'format-variant'), maxvariantlength)
1622 1682
1623 1683 def makeformatname(name):
1624 1684 return b'%s:' + (b' ' * (maxvariantlength - len(name)))
1625 1685
1626 1686 fm = ui.formatter(b'debugformat', opts)
1627 1687 if fm.isplain():
1628 1688
1629 1689 def formatvalue(value):
1630 1690 if util.safehasattr(value, b'startswith'):
1631 1691 return value
1632 1692 if value:
1633 1693 return b'yes'
1634 1694 else:
1635 1695 return b'no'
1636 1696
1637 1697 else:
1638 1698 formatvalue = pycompat.identity
1639 1699
1640 1700 fm.plain(b'format-variant')
1641 1701 fm.plain(b' ' * (maxvariantlength - len(b'format-variant')))
1642 1702 fm.plain(b' repo')
1643 1703 if ui.verbose:
1644 1704 fm.plain(b' config default')
1645 1705 fm.plain(b'\n')
1646 1706 for fv in upgrade.allformatvariant:
1647 1707 fm.startitem()
1648 1708 repovalue = fv.fromrepo(repo)
1649 1709 configvalue = fv.fromconfig(repo)
1650 1710
1651 1711 if repovalue != configvalue:
1652 1712 namelabel = b'formatvariant.name.mismatchconfig'
1653 1713 repolabel = b'formatvariant.repo.mismatchconfig'
1654 1714 elif repovalue != fv.default:
1655 1715 namelabel = b'formatvariant.name.mismatchdefault'
1656 1716 repolabel = b'formatvariant.repo.mismatchdefault'
1657 1717 else:
1658 1718 namelabel = b'formatvariant.name.uptodate'
1659 1719 repolabel = b'formatvariant.repo.uptodate'
1660 1720
1661 1721 fm.write(b'name', makeformatname(fv.name), fv.name, label=namelabel)
1662 1722 fm.write(b'repo', b' %3s', formatvalue(repovalue), label=repolabel)
1663 1723 if fv.default != configvalue:
1664 1724 configlabel = b'formatvariant.config.special'
1665 1725 else:
1666 1726 configlabel = b'formatvariant.config.default'
1667 1727 fm.condwrite(
1668 1728 ui.verbose,
1669 1729 b'config',
1670 1730 b' %6s',
1671 1731 formatvalue(configvalue),
1672 1732 label=configlabel,
1673 1733 )
1674 1734 fm.condwrite(
1675 1735 ui.verbose,
1676 1736 b'default',
1677 1737 b' %7s',
1678 1738 formatvalue(fv.default),
1679 1739 label=b'formatvariant.default',
1680 1740 )
1681 1741 fm.plain(b'\n')
1682 1742 fm.end()
1683 1743
1684 1744
1685 1745 @command(b'debugfsinfo', [], _(b'[PATH]'), norepo=True)
1686 1746 def debugfsinfo(ui, path=b"."):
1687 1747 """show information detected about current filesystem"""
1688 1748 ui.writenoi18n(b'path: %s\n' % path)
1689 1749 ui.writenoi18n(
1690 1750 b'mounted on: %s\n' % (util.getfsmountpoint(path) or b'(unknown)')
1691 1751 )
1692 1752 ui.writenoi18n(b'exec: %s\n' % (util.checkexec(path) and b'yes' or b'no'))
1693 1753 ui.writenoi18n(b'fstype: %s\n' % (util.getfstype(path) or b'(unknown)'))
1694 1754 ui.writenoi18n(
1695 1755 b'symlink: %s\n' % (util.checklink(path) and b'yes' or b'no')
1696 1756 )
1697 1757 ui.writenoi18n(
1698 1758 b'hardlink: %s\n' % (util.checknlink(path) and b'yes' or b'no')
1699 1759 )
1700 1760 casesensitive = b'(unknown)'
1701 1761 try:
1702 1762 with pycompat.namedtempfile(prefix=b'.debugfsinfo', dir=path) as f:
1703 1763 casesensitive = util.fscasesensitive(f.name) and b'yes' or b'no'
1704 1764 except OSError:
1705 1765 pass
1706 1766 ui.writenoi18n(b'case-sensitive: %s\n' % casesensitive)
1707 1767
1708 1768
1709 1769 @command(
1710 1770 b'debuggetbundle',
1711 1771 [
1712 1772 (b'H', b'head', [], _(b'id of head node'), _(b'ID')),
1713 1773 (b'C', b'common', [], _(b'id of common node'), _(b'ID')),
1714 1774 (
1715 1775 b't',
1716 1776 b'type',
1717 1777 b'bzip2',
1718 1778 _(b'bundle compression type to use'),
1719 1779 _(b'TYPE'),
1720 1780 ),
1721 1781 ],
1722 1782 _(b'REPO FILE [-H|-C ID]...'),
1723 1783 norepo=True,
1724 1784 )
1725 1785 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1726 1786 """retrieves a bundle from a repo
1727 1787
1728 1788 Every ID must be a full-length hex node id string. Saves the bundle to the
1729 1789 given file.
1730 1790 """
1731 1791 opts = pycompat.byteskwargs(opts)
1732 1792 repo = hg.peer(ui, opts, repopath)
1733 1793 if not repo.capable(b'getbundle'):
1734 1794 raise error.Abort(b"getbundle() not supported by target repository")
1735 1795 args = {}
1736 1796 if common:
1737 1797 args['common'] = [bin(s) for s in common]
1738 1798 if head:
1739 1799 args['heads'] = [bin(s) for s in head]
1740 1800 # TODO: get desired bundlecaps from command line.
1741 1801 args['bundlecaps'] = None
1742 1802 bundle = repo.getbundle(b'debug', **args)
1743 1803
1744 1804 bundletype = opts.get(b'type', b'bzip2').lower()
1745 1805 btypes = {
1746 1806 b'none': b'HG10UN',
1747 1807 b'bzip2': b'HG10BZ',
1748 1808 b'gzip': b'HG10GZ',
1749 1809 b'bundle2': b'HG20',
1750 1810 }
1751 1811 bundletype = btypes.get(bundletype)
1752 1812 if bundletype not in bundle2.bundletypes:
1753 1813 raise error.Abort(_(b'unknown bundle type specified with --type'))
1754 1814 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
1755 1815
1756 1816
1757 1817 @command(b'debugignore', [], b'[FILE]')
1758 1818 def debugignore(ui, repo, *files, **opts):
1759 1819 """display the combined ignore pattern and information about ignored files
1760 1820
1761 1821 With no argument display the combined ignore pattern.
1762 1822
1763 1823 Given space separated file names, shows if the given file is ignored and
1764 1824 if so, show the ignore rule (file and line number) that matched it.
1765 1825 """
1766 1826 ignore = repo.dirstate._ignore
1767 1827 if not files:
1768 1828 # Show all the patterns
1769 1829 ui.write(b"%s\n" % pycompat.byterepr(ignore))
1770 1830 else:
1771 1831 m = scmutil.match(repo[None], pats=files)
1772 1832 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
1773 1833 for f in m.files():
1774 1834 nf = util.normpath(f)
1775 1835 ignored = None
1776 1836 ignoredata = None
1777 1837 if nf != b'.':
1778 1838 if ignore(nf):
1779 1839 ignored = nf
1780 1840 ignoredata = repo.dirstate._ignorefileandline(nf)
1781 1841 else:
1782 1842 for p in pathutil.finddirs(nf):
1783 1843 if ignore(p):
1784 1844 ignored = p
1785 1845 ignoredata = repo.dirstate._ignorefileandline(p)
1786 1846 break
1787 1847 if ignored:
1788 1848 if ignored == nf:
1789 1849 ui.write(_(b"%s is ignored\n") % uipathfn(f))
1790 1850 else:
1791 1851 ui.write(
1792 1852 _(
1793 1853 b"%s is ignored because of "
1794 1854 b"containing directory %s\n"
1795 1855 )
1796 1856 % (uipathfn(f), ignored)
1797 1857 )
1798 1858 ignorefile, lineno, line = ignoredata
1799 1859 ui.write(
1800 1860 _(b"(ignore rule in %s, line %d: '%s')\n")
1801 1861 % (ignorefile, lineno, line)
1802 1862 )
1803 1863 else:
1804 1864 ui.write(_(b"%s is not ignored\n") % uipathfn(f))
1805 1865
1806 1866
1807 1867 @command(
1808 1868 b'debugindex',
1809 1869 cmdutil.debugrevlogopts + cmdutil.formatteropts,
1810 1870 _(b'-c|-m|FILE'),
1811 1871 )
1812 1872 def debugindex(ui, repo, file_=None, **opts):
1813 1873 """dump index data for a storage primitive"""
1814 1874 opts = pycompat.byteskwargs(opts)
1815 1875 store = cmdutil.openstorage(repo, b'debugindex', file_, opts)
1816 1876
1817 1877 if ui.debugflag:
1818 1878 shortfn = hex
1819 1879 else:
1820 1880 shortfn = short
1821 1881
1822 1882 idlen = 12
1823 1883 for i in store:
1824 1884 idlen = len(shortfn(store.node(i)))
1825 1885 break
1826 1886
1827 1887 fm = ui.formatter(b'debugindex', opts)
1828 1888 fm.plain(
1829 1889 b' rev linkrev %s %s p2\n'
1830 1890 % (b'nodeid'.ljust(idlen), b'p1'.ljust(idlen))
1831 1891 )
1832 1892
1833 1893 for rev in store:
1834 1894 node = store.node(rev)
1835 1895 parents = store.parents(node)
1836 1896
1837 1897 fm.startitem()
1838 1898 fm.write(b'rev', b'%6d ', rev)
1839 1899 fm.write(b'linkrev', b'%7d ', store.linkrev(rev))
1840 1900 fm.write(b'node', b'%s ', shortfn(node))
1841 1901 fm.write(b'p1', b'%s ', shortfn(parents[0]))
1842 1902 fm.write(b'p2', b'%s', shortfn(parents[1]))
1843 1903 fm.plain(b'\n')
1844 1904
1845 1905 fm.end()
1846 1906
1847 1907
1848 1908 @command(
1849 1909 b'debugindexdot',
1850 1910 cmdutil.debugrevlogopts,
1851 1911 _(b'-c|-m|FILE'),
1852 1912 optionalrepo=True,
1853 1913 )
1854 1914 def debugindexdot(ui, repo, file_=None, **opts):
1855 1915 """dump an index DAG as a graphviz dot file"""
1856 1916 opts = pycompat.byteskwargs(opts)
1857 1917 r = cmdutil.openstorage(repo, b'debugindexdot', file_, opts)
1858 1918 ui.writenoi18n(b"digraph G {\n")
1859 1919 for i in r:
1860 1920 node = r.node(i)
1861 1921 pp = r.parents(node)
1862 1922 ui.write(b"\t%d -> %d\n" % (r.rev(pp[0]), i))
1863 1923 if pp[1] != repo.nullid:
1864 1924 ui.write(b"\t%d -> %d\n" % (r.rev(pp[1]), i))
1865 1925 ui.write(b"}\n")
1866 1926
1867 1927
1868 1928 @command(b'debugindexstats', [])
1869 1929 def debugindexstats(ui, repo):
1870 1930 """show stats related to the changelog index"""
1871 1931 repo.changelog.shortest(repo.nullid, 1)
1872 1932 index = repo.changelog.index
1873 1933 if not util.safehasattr(index, b'stats'):
1874 1934 raise error.Abort(_(b'debugindexstats only works with native code'))
1875 1935 for k, v in sorted(index.stats().items()):
1876 1936 ui.write(b'%s: %d\n' % (k, v))
1877 1937
1878 1938
1879 1939 @command(b'debuginstall', [] + cmdutil.formatteropts, b'', norepo=True)
1880 1940 def debuginstall(ui, **opts):
1881 1941 """test Mercurial installation
1882 1942
1883 1943 Returns 0 on success.
1884 1944 """
1885 1945 opts = pycompat.byteskwargs(opts)
1886 1946
1887 1947 problems = 0
1888 1948
1889 1949 fm = ui.formatter(b'debuginstall', opts)
1890 1950 fm.startitem()
1891 1951
1892 1952 # encoding might be unknown or wrong. don't translate these messages.
1893 1953 fm.write(b'encoding', b"checking encoding (%s)...\n", encoding.encoding)
1894 1954 err = None
1895 1955 try:
1896 1956 codecs.lookup(pycompat.sysstr(encoding.encoding))
1897 1957 except LookupError as inst:
1898 1958 err = stringutil.forcebytestr(inst)
1899 1959 problems += 1
1900 1960 fm.condwrite(
1901 1961 err,
1902 1962 b'encodingerror',
1903 1963 b" %s\n (check that your locale is properly set)\n",
1904 1964 err,
1905 1965 )
1906 1966
1907 1967 # Python
1908 1968 pythonlib = None
1909 1969 if util.safehasattr(os, '__file__'):
1910 1970 pythonlib = os.path.dirname(pycompat.fsencode(os.__file__))
1911 1971 elif getattr(sys, 'oxidized', False):
1912 1972 pythonlib = pycompat.sysexecutable
1913 1973
1914 1974 fm.write(
1915 1975 b'pythonexe',
1916 1976 _(b"checking Python executable (%s)\n"),
1917 1977 pycompat.sysexecutable or _(b"unknown"),
1918 1978 )
1919 1979 fm.write(
1920 1980 b'pythonimplementation',
1921 1981 _(b"checking Python implementation (%s)\n"),
1922 1982 pycompat.sysbytes(platform.python_implementation()),
1923 1983 )
1924 1984 fm.write(
1925 1985 b'pythonver',
1926 1986 _(b"checking Python version (%s)\n"),
1927 1987 (b"%d.%d.%d" % sys.version_info[:3]),
1928 1988 )
1929 1989 fm.write(
1930 1990 b'pythonlib',
1931 1991 _(b"checking Python lib (%s)...\n"),
1932 1992 pythonlib or _(b"unknown"),
1933 1993 )
1934 1994
1935 1995 try:
1936 1996 from . import rustext # pytype: disable=import-error
1937 1997
1938 1998 rustext.__doc__ # trigger lazy import
1939 1999 except ImportError:
1940 2000 rustext = None
1941 2001
1942 2002 security = set(sslutil.supportedprotocols)
1943 2003 if sslutil.hassni:
1944 2004 security.add(b'sni')
1945 2005
1946 2006 fm.write(
1947 2007 b'pythonsecurity',
1948 2008 _(b"checking Python security support (%s)\n"),
1949 2009 fm.formatlist(sorted(security), name=b'protocol', fmt=b'%s', sep=b','),
1950 2010 )
1951 2011
1952 2012 # These are warnings, not errors. So don't increment problem count. This
1953 2013 # may change in the future.
1954 2014 if b'tls1.2' not in security:
1955 2015 fm.plain(
1956 2016 _(
1957 2017 b' TLS 1.2 not supported by Python install; '
1958 2018 b'network connections lack modern security\n'
1959 2019 )
1960 2020 )
1961 2021 if b'sni' not in security:
1962 2022 fm.plain(
1963 2023 _(
1964 2024 b' SNI not supported by Python install; may have '
1965 2025 b'connectivity issues with some servers\n'
1966 2026 )
1967 2027 )
1968 2028
1969 2029 fm.plain(
1970 2030 _(
1971 2031 b"checking Rust extensions (%s)\n"
1972 2032 % (b'missing' if rustext is None else b'installed')
1973 2033 ),
1974 2034 )
1975 2035
1976 2036 # TODO print CA cert info
1977 2037
1978 2038 # hg version
1979 2039 hgver = util.version()
1980 2040 fm.write(
1981 2041 b'hgver', _(b"checking Mercurial version (%s)\n"), hgver.split(b'+')[0]
1982 2042 )
1983 2043 fm.write(
1984 2044 b'hgverextra',
1985 2045 _(b"checking Mercurial custom build (%s)\n"),
1986 2046 b'+'.join(hgver.split(b'+')[1:]),
1987 2047 )
1988 2048
1989 2049 # compiled modules
1990 2050 hgmodules = None
1991 2051 if util.safehasattr(sys.modules[__name__], '__file__'):
1992 2052 hgmodules = os.path.dirname(pycompat.fsencode(__file__))
1993 2053 elif getattr(sys, 'oxidized', False):
1994 2054 hgmodules = pycompat.sysexecutable
1995 2055
1996 2056 fm.write(
1997 2057 b'hgmodulepolicy', _(b"checking module policy (%s)\n"), policy.policy
1998 2058 )
1999 2059 fm.write(
2000 2060 b'hgmodules',
2001 2061 _(b"checking installed modules (%s)...\n"),
2002 2062 hgmodules or _(b"unknown"),
2003 2063 )
2004 2064
2005 2065 rustandc = policy.policy in (b'rust+c', b'rust+c-allow')
2006 2066 rustext = rustandc # for now, that's the only case
2007 2067 cext = policy.policy in (b'c', b'allow') or rustandc
2008 2068 nopure = cext or rustext
2009 2069 if nopure:
2010 2070 err = None
2011 2071 try:
2012 2072 if cext:
2013 2073 from .cext import ( # pytype: disable=import-error
2014 2074 base85,
2015 2075 bdiff,
2016 2076 mpatch,
2017 2077 osutil,
2018 2078 )
2019 2079
2020 2080 # quiet pyflakes
2021 2081 dir(bdiff), dir(mpatch), dir(base85), dir(osutil)
2022 2082 if rustext:
2023 2083 from .rustext import ( # pytype: disable=import-error
2024 2084 ancestor,
2025 2085 dirstate,
2026 2086 )
2027 2087
2028 2088 dir(ancestor), dir(dirstate) # quiet pyflakes
2029 2089 except Exception as inst:
2030 2090 err = stringutil.forcebytestr(inst)
2031 2091 problems += 1
2032 2092 fm.condwrite(err, b'extensionserror', b" %s\n", err)
2033 2093
2034 2094 compengines = util.compengines._engines.values()
2035 2095 fm.write(
2036 2096 b'compengines',
2037 2097 _(b'checking registered compression engines (%s)\n'),
2038 2098 fm.formatlist(
2039 2099 sorted(e.name() for e in compengines),
2040 2100 name=b'compengine',
2041 2101 fmt=b'%s',
2042 2102 sep=b', ',
2043 2103 ),
2044 2104 )
2045 2105 fm.write(
2046 2106 b'compenginesavail',
2047 2107 _(b'checking available compression engines (%s)\n'),
2048 2108 fm.formatlist(
2049 2109 sorted(e.name() for e in compengines if e.available()),
2050 2110 name=b'compengine',
2051 2111 fmt=b'%s',
2052 2112 sep=b', ',
2053 2113 ),
2054 2114 )
2055 2115 wirecompengines = compression.compengines.supportedwireengines(
2056 2116 compression.SERVERROLE
2057 2117 )
2058 2118 fm.write(
2059 2119 b'compenginesserver',
2060 2120 _(
2061 2121 b'checking available compression engines '
2062 2122 b'for wire protocol (%s)\n'
2063 2123 ),
2064 2124 fm.formatlist(
2065 2125 [e.name() for e in wirecompengines if e.wireprotosupport()],
2066 2126 name=b'compengine',
2067 2127 fmt=b'%s',
2068 2128 sep=b', ',
2069 2129 ),
2070 2130 )
2071 2131 re2 = b'missing'
2072 2132 if util._re2:
2073 2133 re2 = b'available'
2074 2134 fm.plain(_(b'checking "re2" regexp engine (%s)\n') % re2)
2075 2135 fm.data(re2=bool(util._re2))
2076 2136
2077 2137 # templates
2078 2138 p = templater.templatedir()
2079 2139 fm.write(b'templatedirs', b'checking templates (%s)...\n', p or b'')
2080 2140 fm.condwrite(not p, b'', _(b" no template directories found\n"))
2081 2141 if p:
2082 2142 (m, fp) = templater.try_open_template(b"map-cmdline.default")
2083 2143 if m:
2084 2144 # template found, check if it is working
2085 2145 err = None
2086 2146 try:
2087 2147 templater.templater.frommapfile(m)
2088 2148 except Exception as inst:
2089 2149 err = stringutil.forcebytestr(inst)
2090 2150 p = None
2091 2151 fm.condwrite(err, b'defaulttemplateerror', b" %s\n", err)
2092 2152 else:
2093 2153 p = None
2094 2154 fm.condwrite(
2095 2155 p, b'defaulttemplate', _(b"checking default template (%s)\n"), m
2096 2156 )
2097 2157 fm.condwrite(
2098 2158 not m,
2099 2159 b'defaulttemplatenotfound',
2100 2160 _(b" template '%s' not found\n"),
2101 2161 b"default",
2102 2162 )
2103 2163 if not p:
2104 2164 problems += 1
2105 2165 fm.condwrite(
2106 2166 not p, b'', _(b" (templates seem to have been installed incorrectly)\n")
2107 2167 )
2108 2168
2109 2169 # editor
2110 2170 editor = ui.geteditor()
2111 2171 editor = util.expandpath(editor)
2112 2172 editorbin = procutil.shellsplit(editor)[0]
2113 2173 fm.write(b'editor', _(b"checking commit editor... (%s)\n"), editorbin)
2114 2174 cmdpath = procutil.findexe(editorbin)
2115 2175 fm.condwrite(
2116 2176 not cmdpath and editor == b'vi',
2117 2177 b'vinotfound',
2118 2178 _(
2119 2179 b" No commit editor set and can't find %s in PATH\n"
2120 2180 b" (specify a commit editor in your configuration"
2121 2181 b" file)\n"
2122 2182 ),
2123 2183 not cmdpath and editor == b'vi' and editorbin,
2124 2184 )
2125 2185 fm.condwrite(
2126 2186 not cmdpath and editor != b'vi',
2127 2187 b'editornotfound',
2128 2188 _(
2129 2189 b" Can't find editor '%s' in PATH\n"
2130 2190 b" (specify a commit editor in your configuration"
2131 2191 b" file)\n"
2132 2192 ),
2133 2193 not cmdpath and editorbin,
2134 2194 )
2135 2195 if not cmdpath and editor != b'vi':
2136 2196 problems += 1
2137 2197
2138 2198 # check username
2139 2199 username = None
2140 2200 err = None
2141 2201 try:
2142 2202 username = ui.username()
2143 2203 except error.Abort as e:
2144 2204 err = e.message
2145 2205 problems += 1
2146 2206
2147 2207 fm.condwrite(
2148 2208 username, b'username', _(b"checking username (%s)\n"), username
2149 2209 )
2150 2210 fm.condwrite(
2151 2211 err,
2152 2212 b'usernameerror',
2153 2213 _(
2154 2214 b"checking username...\n %s\n"
2155 2215 b" (specify a username in your configuration file)\n"
2156 2216 ),
2157 2217 err,
2158 2218 )
2159 2219
2160 2220 for name, mod in extensions.extensions():
2161 2221 handler = getattr(mod, 'debuginstall', None)
2162 2222 if handler is not None:
2163 2223 problems += handler(ui, fm)
2164 2224
2165 2225 fm.condwrite(not problems, b'', _(b"no problems detected\n"))
2166 2226 if not problems:
2167 2227 fm.data(problems=problems)
2168 2228 fm.condwrite(
2169 2229 problems,
2170 2230 b'problems',
2171 2231 _(b"%d problems detected, please check your install!\n"),
2172 2232 problems,
2173 2233 )
2174 2234 fm.end()
2175 2235
2176 2236 return problems
2177 2237
2178 2238
2179 2239 @command(b'debugknown', [], _(b'REPO ID...'), norepo=True)
2180 2240 def debugknown(ui, repopath, *ids, **opts):
2181 2241 """test whether node ids are known to a repo
2182 2242
2183 2243 Every ID must be a full-length hex node id string. Returns a list of 0s
2184 2244 and 1s indicating unknown/known.
2185 2245 """
2186 2246 opts = pycompat.byteskwargs(opts)
2187 2247 repo = hg.peer(ui, opts, repopath)
2188 2248 if not repo.capable(b'known'):
2189 2249 raise error.Abort(b"known() not supported by target repository")
2190 2250 flags = repo.known([bin(s) for s in ids])
2191 2251 ui.write(b"%s\n" % (b"".join([f and b"1" or b"0" for f in flags])))
2192 2252
2193 2253
2194 2254 @command(b'debuglabelcomplete', [], _(b'LABEL...'))
2195 2255 def debuglabelcomplete(ui, repo, *args):
2196 2256 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2197 2257 debugnamecomplete(ui, repo, *args)
2198 2258
2199 2259
2200 2260 @command(
2201 2261 b'debuglocks',
2202 2262 [
2203 2263 (b'L', b'force-free-lock', None, _(b'free the store lock (DANGEROUS)')),
2204 2264 (
2205 2265 b'W',
2206 2266 b'force-free-wlock',
2207 2267 None,
2208 2268 _(b'free the working state lock (DANGEROUS)'),
2209 2269 ),
2210 2270 (b's', b'set-lock', None, _(b'set the store lock until stopped')),
2211 2271 (
2212 2272 b'S',
2213 2273 b'set-wlock',
2214 2274 None,
2215 2275 _(b'set the working state lock until stopped'),
2216 2276 ),
2217 2277 ],
2218 2278 _(b'[OPTION]...'),
2219 2279 )
2220 2280 def debuglocks(ui, repo, **opts):
2221 2281 """show or modify state of locks
2222 2282
2223 2283 By default, this command will show which locks are held. This
2224 2284 includes the user and process holding the lock, the amount of time
2225 2285 the lock has been held, and the machine name where the process is
2226 2286 running if it's not local.
2227 2287
2228 2288 Locks protect the integrity of Mercurial's data, so should be
2229 2289 treated with care. System crashes or other interruptions may cause
2230 2290 locks to not be properly released, though Mercurial will usually
2231 2291 detect and remove such stale locks automatically.
2232 2292
2233 2293 However, detecting stale locks may not always be possible (for
2234 2294 instance, on a shared filesystem). Removing locks may also be
2235 2295 blocked by filesystem permissions.
2236 2296
2237 2297 Setting a lock will prevent other commands from changing the data.
2238 2298 The command will wait until an interruption (SIGINT, SIGTERM, ...) occurs.
2239 2299 The set locks are removed when the command exits.
2240 2300
2241 2301 Returns 0 if no locks are held.
2242 2302
2243 2303 """
2244 2304
2245 2305 if opts.get('force_free_lock'):
2246 2306 repo.svfs.tryunlink(b'lock')
2247 2307 if opts.get('force_free_wlock'):
2248 2308 repo.vfs.tryunlink(b'wlock')
2249 2309 if opts.get('force_free_lock') or opts.get('force_free_wlock'):
2250 2310 return 0
2251 2311
2252 2312 locks = []
2253 2313 try:
2254 2314 if opts.get('set_wlock'):
2255 2315 try:
2256 2316 locks.append(repo.wlock(False))
2257 2317 except error.LockHeld:
2258 2318 raise error.Abort(_(b'wlock is already held'))
2259 2319 if opts.get('set_lock'):
2260 2320 try:
2261 2321 locks.append(repo.lock(False))
2262 2322 except error.LockHeld:
2263 2323 raise error.Abort(_(b'lock is already held'))
2264 2324 if len(locks):
2265 2325 try:
2266 2326 if ui.interactive():
2267 2327 prompt = _(b"ready to release the lock (y)? $$ &Yes")
2268 2328 ui.promptchoice(prompt)
2269 2329 else:
2270 2330 msg = b"%d locks held, waiting for signal\n"
2271 2331 msg %= len(locks)
2272 2332 ui.status(msg)
2273 2333 while True: # XXX wait for a signal
2274 2334 time.sleep(0.1)
2275 2335 except KeyboardInterrupt:
2276 2336 msg = b"signal-received releasing locks\n"
2277 2337 ui.status(msg)
2278 2338 return 0
2279 2339 finally:
2280 2340 release(*locks)
2281 2341
2282 2342 now = time.time()
2283 2343 held = 0
2284 2344
2285 2345 def report(vfs, name, method):
2286 2346 # this causes stale locks to get reaped for more accurate reporting
2287 2347 try:
2288 2348 l = method(False)
2289 2349 except error.LockHeld:
2290 2350 l = None
2291 2351
2292 2352 if l:
2293 2353 l.release()
2294 2354 else:
2295 2355 try:
2296 2356 st = vfs.lstat(name)
2297 2357 age = now - st[stat.ST_MTIME]
2298 2358 user = util.username(st.st_uid)
2299 2359 locker = vfs.readlock(name)
2300 2360 if b":" in locker:
2301 2361 host, pid = locker.split(b':')
2302 2362 if host == socket.gethostname():
2303 2363 locker = b'user %s, process %s' % (user or b'None', pid)
2304 2364 else:
2305 2365 locker = b'user %s, process %s, host %s' % (
2306 2366 user or b'None',
2307 2367 pid,
2308 2368 host,
2309 2369 )
2310 2370 ui.writenoi18n(b"%-6s %s (%ds)\n" % (name + b":", locker, age))
2311 2371 return 1
2312 2372 except OSError as e:
2313 2373 if e.errno != errno.ENOENT:
2314 2374 raise
2315 2375
2316 2376 ui.writenoi18n(b"%-6s free\n" % (name + b":"))
2317 2377 return 0
2318 2378
2319 2379 held += report(repo.svfs, b"lock", repo.lock)
2320 2380 held += report(repo.vfs, b"wlock", repo.wlock)
2321 2381
2322 2382 return held
2323 2383
2324 2384
2325 2385 @command(
2326 2386 b'debugmanifestfulltextcache',
2327 2387 [
2328 2388 (b'', b'clear', False, _(b'clear the cache')),
2329 2389 (
2330 2390 b'a',
2331 2391 b'add',
2332 2392 [],
2333 2393 _(b'add the given manifest nodes to the cache'),
2334 2394 _(b'NODE'),
2335 2395 ),
2336 2396 ],
2337 2397 b'',
2338 2398 )
2339 2399 def debugmanifestfulltextcache(ui, repo, add=(), **opts):
2340 2400 """show, clear or amend the contents of the manifest fulltext cache"""
2341 2401
2342 2402 def getcache():
2343 2403 r = repo.manifestlog.getstorage(b'')
2344 2404 try:
2345 2405 return r._fulltextcache
2346 2406 except AttributeError:
2347 2407 msg = _(
2348 2408 b"Current revlog implementation doesn't appear to have a "
2349 2409 b"manifest fulltext cache\n"
2350 2410 )
2351 2411 raise error.Abort(msg)
2352 2412
2353 2413 if opts.get('clear'):
2354 2414 with repo.wlock():
2355 2415 cache = getcache()
2356 2416 cache.clear(clear_persisted_data=True)
2357 2417 return
2358 2418
2359 2419 if add:
2360 2420 with repo.wlock():
2361 2421 m = repo.manifestlog
2362 2422 store = m.getstorage(b'')
2363 2423 for n in add:
2364 2424 try:
2365 2425 manifest = m[store.lookup(n)]
2366 2426 except error.LookupError as e:
2367 2427 raise error.Abort(
2368 2428 bytes(e), hint=b"Check your manifest node id"
2369 2429 )
2370 2430 manifest.read() # stores revisision in cache too
2371 2431 return
2372 2432
2373 2433 cache = getcache()
2374 2434 if not len(cache):
2375 2435 ui.write(_(b'cache empty\n'))
2376 2436 else:
2377 2437 ui.write(
2378 2438 _(
2379 2439 b'cache contains %d manifest entries, in order of most to '
2380 2440 b'least recent:\n'
2381 2441 )
2382 2442 % (len(cache),)
2383 2443 )
2384 2444 totalsize = 0
2385 2445 for nodeid in cache:
2386 2446 # Use cache.get to not update the LRU order
2387 2447 data = cache.peek(nodeid)
2388 2448 size = len(data)
2389 2449 totalsize += size + 24 # 20 bytes nodeid, 4 bytes size
2390 2450 ui.write(
2391 2451 _(b'id: %s, size %s\n') % (hex(nodeid), util.bytecount(size))
2392 2452 )
2393 2453 ondisk = cache._opener.stat(b'manifestfulltextcache').st_size
2394 2454 ui.write(
2395 2455 _(b'total cache data size %s, on-disk %s\n')
2396 2456 % (util.bytecount(totalsize), util.bytecount(ondisk))
2397 2457 )
2398 2458
2399 2459
2400 2460 @command(b'debugmergestate', [] + cmdutil.templateopts, b'')
2401 2461 def debugmergestate(ui, repo, *args, **opts):
2402 2462 """print merge state
2403 2463
2404 2464 Use --verbose to print out information about whether v1 or v2 merge state
2405 2465 was chosen."""
2406 2466
2407 2467 if ui.verbose:
2408 2468 ms = mergestatemod.mergestate(repo)
2409 2469
2410 2470 # sort so that reasonable information is on top
2411 2471 v1records = ms._readrecordsv1()
2412 2472 v2records = ms._readrecordsv2()
2413 2473
2414 2474 if not v1records and not v2records:
2415 2475 pass
2416 2476 elif not v2records:
2417 2477 ui.writenoi18n(b'no version 2 merge state\n')
2418 2478 elif ms._v1v2match(v1records, v2records):
2419 2479 ui.writenoi18n(b'v1 and v2 states match: using v2\n')
2420 2480 else:
2421 2481 ui.writenoi18n(b'v1 and v2 states mismatch: using v1\n')
2422 2482
2423 2483 opts = pycompat.byteskwargs(opts)
2424 2484 if not opts[b'template']:
2425 2485 opts[b'template'] = (
2426 2486 b'{if(commits, "", "no merge state found\n")}'
2427 2487 b'{commits % "{name}{if(label, " ({label})")}: {node}\n"}'
2428 2488 b'{files % "file: {path} (state \\"{state}\\")\n'
2429 2489 b'{if(local_path, "'
2430 2490 b' local path: {local_path} (hash {local_key}, flags \\"{local_flags}\\")\n'
2431 2491 b' ancestor path: {ancestor_path} (node {ancestor_node})\n'
2432 2492 b' other path: {other_path} (node {other_node})\n'
2433 2493 b'")}'
2434 2494 b'{if(rename_side, "'
2435 2495 b' rename side: {rename_side}\n'
2436 2496 b' renamed path: {renamed_path}\n'
2437 2497 b'")}'
2438 2498 b'{extras % " extra: {key} = {value}\n"}'
2439 2499 b'"}'
2440 2500 b'{extras % "extra: {file} ({key} = {value})\n"}'
2441 2501 )
2442 2502
2443 2503 ms = mergestatemod.mergestate.read(repo)
2444 2504
2445 2505 fm = ui.formatter(b'debugmergestate', opts)
2446 2506 fm.startitem()
2447 2507
2448 2508 fm_commits = fm.nested(b'commits')
2449 2509 if ms.active():
2450 2510 for name, node, label_index in (
2451 2511 (b'local', ms.local, 0),
2452 2512 (b'other', ms.other, 1),
2453 2513 ):
2454 2514 fm_commits.startitem()
2455 2515 fm_commits.data(name=name)
2456 2516 fm_commits.data(node=hex(node))
2457 2517 if ms._labels and len(ms._labels) > label_index:
2458 2518 fm_commits.data(label=ms._labels[label_index])
2459 2519 fm_commits.end()
2460 2520
2461 2521 fm_files = fm.nested(b'files')
2462 2522 if ms.active():
2463 2523 for f in ms:
2464 2524 fm_files.startitem()
2465 2525 fm_files.data(path=f)
2466 2526 state = ms._state[f]
2467 2527 fm_files.data(state=state[0])
2468 2528 if state[0] in (
2469 2529 mergestatemod.MERGE_RECORD_UNRESOLVED,
2470 2530 mergestatemod.MERGE_RECORD_RESOLVED,
2471 2531 ):
2472 2532 fm_files.data(local_key=state[1])
2473 2533 fm_files.data(local_path=state[2])
2474 2534 fm_files.data(ancestor_path=state[3])
2475 2535 fm_files.data(ancestor_node=state[4])
2476 2536 fm_files.data(other_path=state[5])
2477 2537 fm_files.data(other_node=state[6])
2478 2538 fm_files.data(local_flags=state[7])
2479 2539 elif state[0] in (
2480 2540 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
2481 2541 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
2482 2542 ):
2483 2543 fm_files.data(renamed_path=state[1])
2484 2544 fm_files.data(rename_side=state[2])
2485 2545 fm_extras = fm_files.nested(b'extras')
2486 2546 for k, v in sorted(ms.extras(f).items()):
2487 2547 fm_extras.startitem()
2488 2548 fm_extras.data(key=k)
2489 2549 fm_extras.data(value=v)
2490 2550 fm_extras.end()
2491 2551
2492 2552 fm_files.end()
2493 2553
2494 2554 fm_extras = fm.nested(b'extras')
2495 2555 for f, d in sorted(ms.allextras().items()):
2496 2556 if f in ms:
2497 2557 # If file is in mergestate, we have already processed it's extras
2498 2558 continue
2499 2559 for k, v in d.items():
2500 2560 fm_extras.startitem()
2501 2561 fm_extras.data(file=f)
2502 2562 fm_extras.data(key=k)
2503 2563 fm_extras.data(value=v)
2504 2564 fm_extras.end()
2505 2565
2506 2566 fm.end()
2507 2567
2508 2568
2509 2569 @command(b'debugnamecomplete', [], _(b'NAME...'))
2510 2570 def debugnamecomplete(ui, repo, *args):
2511 2571 '''complete "names" - tags, open branch names, bookmark names'''
2512 2572
2513 2573 names = set()
2514 2574 # since we previously only listed open branches, we will handle that
2515 2575 # specially (after this for loop)
2516 2576 for name, ns in repo.names.items():
2517 2577 if name != b'branches':
2518 2578 names.update(ns.listnames(repo))
2519 2579 names.update(
2520 2580 tag
2521 2581 for (tag, heads, tip, closed) in repo.branchmap().iterbranches()
2522 2582 if not closed
2523 2583 )
2524 2584 completions = set()
2525 2585 if not args:
2526 2586 args = [b'']
2527 2587 for a in args:
2528 2588 completions.update(n for n in names if n.startswith(a))
2529 2589 ui.write(b'\n'.join(sorted(completions)))
2530 2590 ui.write(b'\n')
2531 2591
2532 2592
2533 2593 @command(
2534 2594 b'debugnodemap',
2535 2595 [
2536 2596 (
2537 2597 b'',
2538 2598 b'dump-new',
2539 2599 False,
2540 2600 _(b'write a (new) persistent binary nodemap on stdout'),
2541 2601 ),
2542 2602 (b'', b'dump-disk', False, _(b'dump on-disk data on stdout')),
2543 2603 (
2544 2604 b'',
2545 2605 b'check',
2546 2606 False,
2547 2607 _(b'check that the data on disk data are correct.'),
2548 2608 ),
2549 2609 (
2550 2610 b'',
2551 2611 b'metadata',
2552 2612 False,
2553 2613 _(b'display the on disk meta data for the nodemap'),
2554 2614 ),
2555 2615 ],
2556 2616 )
2557 2617 def debugnodemap(ui, repo, **opts):
2558 2618 """write and inspect on disk nodemap"""
2559 2619 if opts['dump_new']:
2560 2620 unfi = repo.unfiltered()
2561 2621 cl = unfi.changelog
2562 2622 if util.safehasattr(cl.index, "nodemap_data_all"):
2563 2623 data = cl.index.nodemap_data_all()
2564 2624 else:
2565 2625 data = nodemap.persistent_data(cl.index)
2566 2626 ui.write(data)
2567 2627 elif opts['dump_disk']:
2568 2628 unfi = repo.unfiltered()
2569 2629 cl = unfi.changelog
2570 2630 nm_data = nodemap.persisted_data(cl)
2571 2631 if nm_data is not None:
2572 2632 docket, data = nm_data
2573 2633 ui.write(data[:])
2574 2634 elif opts['check']:
2575 2635 unfi = repo.unfiltered()
2576 2636 cl = unfi.changelog
2577 2637 nm_data = nodemap.persisted_data(cl)
2578 2638 if nm_data is not None:
2579 2639 docket, data = nm_data
2580 2640 return nodemap.check_data(ui, cl.index, data)
2581 2641 elif opts['metadata']:
2582 2642 unfi = repo.unfiltered()
2583 2643 cl = unfi.changelog
2584 2644 nm_data = nodemap.persisted_data(cl)
2585 2645 if nm_data is not None:
2586 2646 docket, data = nm_data
2587 2647 ui.write((b"uid: %s\n") % docket.uid)
2588 2648 ui.write((b"tip-rev: %d\n") % docket.tip_rev)
2589 2649 ui.write((b"tip-node: %s\n") % hex(docket.tip_node))
2590 2650 ui.write((b"data-length: %d\n") % docket.data_length)
2591 2651 ui.write((b"data-unused: %d\n") % docket.data_unused)
2592 2652 unused_perc = docket.data_unused * 100.0 / docket.data_length
2593 2653 ui.write((b"data-unused: %2.3f%%\n") % unused_perc)
2594 2654
2595 2655
2596 2656 @command(
2597 2657 b'debugobsolete',
2598 2658 [
2599 2659 (b'', b'flags', 0, _(b'markers flag')),
2600 2660 (
2601 2661 b'',
2602 2662 b'record-parents',
2603 2663 False,
2604 2664 _(b'record parent information for the precursor'),
2605 2665 ),
2606 2666 (b'r', b'rev', [], _(b'display markers relevant to REV')),
2607 2667 (
2608 2668 b'',
2609 2669 b'exclusive',
2610 2670 False,
2611 2671 _(b'restrict display to markers only relevant to REV'),
2612 2672 ),
2613 2673 (b'', b'index', False, _(b'display index of the marker')),
2614 2674 (b'', b'delete', [], _(b'delete markers specified by indices')),
2615 2675 ]
2616 2676 + cmdutil.commitopts2
2617 2677 + cmdutil.formatteropts,
2618 2678 _(b'[OBSOLETED [REPLACEMENT ...]]'),
2619 2679 )
2620 2680 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2621 2681 """create arbitrary obsolete marker
2622 2682
2623 2683 With no arguments, displays the list of obsolescence markers."""
2624 2684
2625 2685 opts = pycompat.byteskwargs(opts)
2626 2686
2627 2687 def parsenodeid(s):
2628 2688 try:
2629 2689 # We do not use revsingle/revrange functions here to accept
2630 2690 # arbitrary node identifiers, possibly not present in the
2631 2691 # local repository.
2632 2692 n = bin(s)
2633 2693 if len(n) != repo.nodeconstants.nodelen:
2634 2694 raise TypeError()
2635 2695 return n
2636 2696 except TypeError:
2637 2697 raise error.InputError(
2638 2698 b'changeset references must be full hexadecimal '
2639 2699 b'node identifiers'
2640 2700 )
2641 2701
2642 2702 if opts.get(b'delete'):
2643 2703 indices = []
2644 2704 for v in opts.get(b'delete'):
2645 2705 try:
2646 2706 indices.append(int(v))
2647 2707 except ValueError:
2648 2708 raise error.InputError(
2649 2709 _(b'invalid index value: %r') % v,
2650 2710 hint=_(b'use integers for indices'),
2651 2711 )
2652 2712
2653 2713 if repo.currenttransaction():
2654 2714 raise error.Abort(
2655 2715 _(b'cannot delete obsmarkers in the middle of transaction.')
2656 2716 )
2657 2717
2658 2718 with repo.lock():
2659 2719 n = repair.deleteobsmarkers(repo.obsstore, indices)
2660 2720 ui.write(_(b'deleted %i obsolescence markers\n') % n)
2661 2721
2662 2722 return
2663 2723
2664 2724 if precursor is not None:
2665 2725 if opts[b'rev']:
2666 2726 raise error.InputError(
2667 2727 b'cannot select revision when creating marker'
2668 2728 )
2669 2729 metadata = {}
2670 2730 metadata[b'user'] = encoding.fromlocal(opts[b'user'] or ui.username())
2671 2731 succs = tuple(parsenodeid(succ) for succ in successors)
2672 2732 l = repo.lock()
2673 2733 try:
2674 2734 tr = repo.transaction(b'debugobsolete')
2675 2735 try:
2676 2736 date = opts.get(b'date')
2677 2737 if date:
2678 2738 date = dateutil.parsedate(date)
2679 2739 else:
2680 2740 date = None
2681 2741 prec = parsenodeid(precursor)
2682 2742 parents = None
2683 2743 if opts[b'record_parents']:
2684 2744 if prec not in repo.unfiltered():
2685 2745 raise error.Abort(
2686 2746 b'cannot used --record-parents on '
2687 2747 b'unknown changesets'
2688 2748 )
2689 2749 parents = repo.unfiltered()[prec].parents()
2690 2750 parents = tuple(p.node() for p in parents)
2691 2751 repo.obsstore.create(
2692 2752 tr,
2693 2753 prec,
2694 2754 succs,
2695 2755 opts[b'flags'],
2696 2756 parents=parents,
2697 2757 date=date,
2698 2758 metadata=metadata,
2699 2759 ui=ui,
2700 2760 )
2701 2761 tr.close()
2702 2762 except ValueError as exc:
2703 2763 raise error.Abort(
2704 2764 _(b'bad obsmarker input: %s') % stringutil.forcebytestr(exc)
2705 2765 )
2706 2766 finally:
2707 2767 tr.release()
2708 2768 finally:
2709 2769 l.release()
2710 2770 else:
2711 2771 if opts[b'rev']:
2712 2772 revs = logcmdutil.revrange(repo, opts[b'rev'])
2713 2773 nodes = [repo[r].node() for r in revs]
2714 2774 markers = list(
2715 2775 obsutil.getmarkers(
2716 2776 repo, nodes=nodes, exclusive=opts[b'exclusive']
2717 2777 )
2718 2778 )
2719 2779 markers.sort(key=lambda x: x._data)
2720 2780 else:
2721 2781 markers = obsutil.getmarkers(repo)
2722 2782
2723 2783 markerstoiter = markers
2724 2784 isrelevant = lambda m: True
2725 2785 if opts.get(b'rev') and opts.get(b'index'):
2726 2786 markerstoiter = obsutil.getmarkers(repo)
2727 2787 markerset = set(markers)
2728 2788 isrelevant = lambda m: m in markerset
2729 2789
2730 2790 fm = ui.formatter(b'debugobsolete', opts)
2731 2791 for i, m in enumerate(markerstoiter):
2732 2792 if not isrelevant(m):
2733 2793 # marker can be irrelevant when we're iterating over a set
2734 2794 # of markers (markerstoiter) which is bigger than the set
2735 2795 # of markers we want to display (markers)
2736 2796 # this can happen if both --index and --rev options are
2737 2797 # provided and thus we need to iterate over all of the markers
2738 2798 # to get the correct indices, but only display the ones that
2739 2799 # are relevant to --rev value
2740 2800 continue
2741 2801 fm.startitem()
2742 2802 ind = i if opts.get(b'index') else None
2743 2803 cmdutil.showmarker(fm, m, index=ind)
2744 2804 fm.end()
2745 2805
2746 2806
2747 2807 @command(
2748 2808 b'debugp1copies',
2749 2809 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
2750 2810 _(b'[-r REV]'),
2751 2811 )
2752 2812 def debugp1copies(ui, repo, **opts):
2753 2813 """dump copy information compared to p1"""
2754 2814
2755 2815 opts = pycompat.byteskwargs(opts)
2756 2816 ctx = scmutil.revsingle(repo, opts.get(b'rev'), default=None)
2757 2817 for dst, src in ctx.p1copies().items():
2758 2818 ui.write(b'%s -> %s\n' % (src, dst))
2759 2819
2760 2820
2761 2821 @command(
2762 2822 b'debugp2copies',
2763 2823 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
2764 2824 _(b'[-r REV]'),
2765 2825 )
2766 2826 def debugp1copies(ui, repo, **opts):
2767 2827 """dump copy information compared to p2"""
2768 2828
2769 2829 opts = pycompat.byteskwargs(opts)
2770 2830 ctx = scmutil.revsingle(repo, opts.get(b'rev'), default=None)
2771 2831 for dst, src in ctx.p2copies().items():
2772 2832 ui.write(b'%s -> %s\n' % (src, dst))
2773 2833
2774 2834
2775 2835 @command(
2776 2836 b'debugpathcomplete',
2777 2837 [
2778 2838 (b'f', b'full', None, _(b'complete an entire path')),
2779 2839 (b'n', b'normal', None, _(b'show only normal files')),
2780 2840 (b'a', b'added', None, _(b'show only added files')),
2781 2841 (b'r', b'removed', None, _(b'show only removed files')),
2782 2842 ],
2783 2843 _(b'FILESPEC...'),
2784 2844 )
2785 2845 def debugpathcomplete(ui, repo, *specs, **opts):
2786 2846 """complete part or all of a tracked path
2787 2847
2788 2848 This command supports shells that offer path name completion. It
2789 2849 currently completes only files already known to the dirstate.
2790 2850
2791 2851 Completion extends only to the next path segment unless
2792 2852 --full is specified, in which case entire paths are used."""
2793 2853
2794 2854 def complete(path, acceptable):
2795 2855 dirstate = repo.dirstate
2796 2856 spec = os.path.normpath(os.path.join(encoding.getcwd(), path))
2797 2857 rootdir = repo.root + pycompat.ossep
2798 2858 if spec != repo.root and not spec.startswith(rootdir):
2799 2859 return [], []
2800 2860 if os.path.isdir(spec):
2801 2861 spec += b'/'
2802 2862 spec = spec[len(rootdir) :]
2803 2863 fixpaths = pycompat.ossep != b'/'
2804 2864 if fixpaths:
2805 2865 spec = spec.replace(pycompat.ossep, b'/')
2806 2866 speclen = len(spec)
2807 2867 fullpaths = opts['full']
2808 2868 files, dirs = set(), set()
2809 2869 adddir, addfile = dirs.add, files.add
2810 2870 for f, st in dirstate.items():
2811 2871 if f.startswith(spec) and st.state in acceptable:
2812 2872 if fixpaths:
2813 2873 f = f.replace(b'/', pycompat.ossep)
2814 2874 if fullpaths:
2815 2875 addfile(f)
2816 2876 continue
2817 2877 s = f.find(pycompat.ossep, speclen)
2818 2878 if s >= 0:
2819 2879 adddir(f[:s])
2820 2880 else:
2821 2881 addfile(f)
2822 2882 return files, dirs
2823 2883
2824 2884 acceptable = b''
2825 2885 if opts['normal']:
2826 2886 acceptable += b'nm'
2827 2887 if opts['added']:
2828 2888 acceptable += b'a'
2829 2889 if opts['removed']:
2830 2890 acceptable += b'r'
2831 2891 cwd = repo.getcwd()
2832 2892 if not specs:
2833 2893 specs = [b'.']
2834 2894
2835 2895 files, dirs = set(), set()
2836 2896 for spec in specs:
2837 2897 f, d = complete(spec, acceptable or b'nmar')
2838 2898 files.update(f)
2839 2899 dirs.update(d)
2840 2900 files.update(dirs)
2841 2901 ui.write(b'\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2842 2902 ui.write(b'\n')
2843 2903
2844 2904
2845 2905 @command(
2846 2906 b'debugpathcopies',
2847 2907 cmdutil.walkopts,
2848 2908 b'hg debugpathcopies REV1 REV2 [FILE]',
2849 2909 inferrepo=True,
2850 2910 )
2851 2911 def debugpathcopies(ui, repo, rev1, rev2, *pats, **opts):
2852 2912 """show copies between two revisions"""
2853 2913 ctx1 = scmutil.revsingle(repo, rev1)
2854 2914 ctx2 = scmutil.revsingle(repo, rev2)
2855 2915 m = scmutil.match(ctx1, pats, opts)
2856 2916 for dst, src in sorted(copies.pathcopies(ctx1, ctx2, m).items()):
2857 2917 ui.write(b'%s -> %s\n' % (src, dst))
2858 2918
2859 2919
2860 2920 @command(b'debugpeer', [], _(b'PATH'), norepo=True)
2861 2921 def debugpeer(ui, path):
2862 2922 """establish a connection to a peer repository"""
2863 2923 # Always enable peer request logging. Requires --debug to display
2864 2924 # though.
2865 2925 overrides = {
2866 2926 (b'devel', b'debug.peer-request'): True,
2867 2927 }
2868 2928
2869 2929 with ui.configoverride(overrides):
2870 2930 peer = hg.peer(ui, {}, path)
2871 2931
2872 2932 try:
2873 2933 local = peer.local() is not None
2874 2934 canpush = peer.canpush()
2875 2935
2876 2936 ui.write(_(b'url: %s\n') % peer.url())
2877 2937 ui.write(_(b'local: %s\n') % (_(b'yes') if local else _(b'no')))
2878 2938 ui.write(
2879 2939 _(b'pushable: %s\n') % (_(b'yes') if canpush else _(b'no'))
2880 2940 )
2881 2941 finally:
2882 2942 peer.close()
2883 2943
2884 2944
2885 2945 @command(
2886 2946 b'debugpickmergetool',
2887 2947 [
2888 2948 (b'r', b'rev', b'', _(b'check for files in this revision'), _(b'REV')),
2889 2949 (b'', b'changedelete', None, _(b'emulate merging change and delete')),
2890 2950 ]
2891 2951 + cmdutil.walkopts
2892 2952 + cmdutil.mergetoolopts,
2893 2953 _(b'[PATTERN]...'),
2894 2954 inferrepo=True,
2895 2955 )
2896 2956 def debugpickmergetool(ui, repo, *pats, **opts):
2897 2957 """examine which merge tool is chosen for specified file
2898 2958
2899 2959 As described in :hg:`help merge-tools`, Mercurial examines
2900 2960 configurations below in this order to decide which merge tool is
2901 2961 chosen for specified file.
2902 2962
2903 2963 1. ``--tool`` option
2904 2964 2. ``HGMERGE`` environment variable
2905 2965 3. configurations in ``merge-patterns`` section
2906 2966 4. configuration of ``ui.merge``
2907 2967 5. configurations in ``merge-tools`` section
2908 2968 6. ``hgmerge`` tool (for historical reason only)
2909 2969 7. default tool for fallback (``:merge`` or ``:prompt``)
2910 2970
2911 2971 This command writes out examination result in the style below::
2912 2972
2913 2973 FILE = MERGETOOL
2914 2974
2915 2975 By default, all files known in the first parent context of the
2916 2976 working directory are examined. Use file patterns and/or -I/-X
2917 2977 options to limit target files. -r/--rev is also useful to examine
2918 2978 files in another context without actual updating to it.
2919 2979
2920 2980 With --debug, this command shows warning messages while matching
2921 2981 against ``merge-patterns`` and so on, too. It is recommended to
2922 2982 use this option with explicit file patterns and/or -I/-X options,
2923 2983 because this option increases amount of output per file according
2924 2984 to configurations in hgrc.
2925 2985
2926 2986 With -v/--verbose, this command shows configurations below at
2927 2987 first (only if specified).
2928 2988
2929 2989 - ``--tool`` option
2930 2990 - ``HGMERGE`` environment variable
2931 2991 - configuration of ``ui.merge``
2932 2992
2933 2993 If merge tool is chosen before matching against
2934 2994 ``merge-patterns``, this command can't show any helpful
2935 2995 information, even with --debug. In such case, information above is
2936 2996 useful to know why a merge tool is chosen.
2937 2997 """
2938 2998 opts = pycompat.byteskwargs(opts)
2939 2999 overrides = {}
2940 3000 if opts[b'tool']:
2941 3001 overrides[(b'ui', b'forcemerge')] = opts[b'tool']
2942 3002 ui.notenoi18n(b'with --tool %r\n' % (pycompat.bytestr(opts[b'tool'])))
2943 3003
2944 3004 with ui.configoverride(overrides, b'debugmergepatterns'):
2945 3005 hgmerge = encoding.environ.get(b"HGMERGE")
2946 3006 if hgmerge is not None:
2947 3007 ui.notenoi18n(b'with HGMERGE=%r\n' % (pycompat.bytestr(hgmerge)))
2948 3008 uimerge = ui.config(b"ui", b"merge")
2949 3009 if uimerge:
2950 3010 ui.notenoi18n(b'with ui.merge=%r\n' % (pycompat.bytestr(uimerge)))
2951 3011
2952 3012 ctx = scmutil.revsingle(repo, opts.get(b'rev'))
2953 3013 m = scmutil.match(ctx, pats, opts)
2954 3014 changedelete = opts[b'changedelete']
2955 3015 for path in ctx.walk(m):
2956 3016 fctx = ctx[path]
2957 3017 with ui.silent(
2958 3018 error=True
2959 3019 ) if not ui.debugflag else util.nullcontextmanager():
2960 3020 tool, toolpath = filemerge._picktool(
2961 3021 repo,
2962 3022 ui,
2963 3023 path,
2964 3024 fctx.isbinary(),
2965 3025 b'l' in fctx.flags(),
2966 3026 changedelete,
2967 3027 )
2968 3028 ui.write(b'%s = %s\n' % (path, tool))
2969 3029
2970 3030
2971 3031 @command(b'debugpushkey', [], _(b'REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2972 3032 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2973 3033 """access the pushkey key/value protocol
2974 3034
2975 3035 With two args, list the keys in the given namespace.
2976 3036
2977 3037 With five args, set a key to new if it currently is set to old.
2978 3038 Reports success or failure.
2979 3039 """
2980 3040
2981 3041 target = hg.peer(ui, {}, repopath)
2982 3042 try:
2983 3043 if keyinfo:
2984 3044 key, old, new = keyinfo
2985 3045 with target.commandexecutor() as e:
2986 3046 r = e.callcommand(
2987 3047 b'pushkey',
2988 3048 {
2989 3049 b'namespace': namespace,
2990 3050 b'key': key,
2991 3051 b'old': old,
2992 3052 b'new': new,
2993 3053 },
2994 3054 ).result()
2995 3055
2996 3056 ui.status(pycompat.bytestr(r) + b'\n')
2997 3057 return not r
2998 3058 else:
2999 3059 for k, v in sorted(target.listkeys(namespace).items()):
3000 3060 ui.write(
3001 3061 b"%s\t%s\n"
3002 3062 % (stringutil.escapestr(k), stringutil.escapestr(v))
3003 3063 )
3004 3064 finally:
3005 3065 target.close()
3006 3066
3007 3067
3008 3068 @command(b'debugpvec', [], _(b'A B'))
3009 3069 def debugpvec(ui, repo, a, b=None):
3010 3070 ca = scmutil.revsingle(repo, a)
3011 3071 cb = scmutil.revsingle(repo, b)
3012 3072 pa = pvec.ctxpvec(ca)
3013 3073 pb = pvec.ctxpvec(cb)
3014 3074 if pa == pb:
3015 3075 rel = b"="
3016 3076 elif pa > pb:
3017 3077 rel = b">"
3018 3078 elif pa < pb:
3019 3079 rel = b"<"
3020 3080 elif pa | pb:
3021 3081 rel = b"|"
3022 3082 ui.write(_(b"a: %s\n") % pa)
3023 3083 ui.write(_(b"b: %s\n") % pb)
3024 3084 ui.write(_(b"depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3025 3085 ui.write(
3026 3086 _(b"delta: %d hdist: %d distance: %d relation: %s\n")
3027 3087 % (
3028 3088 abs(pa._depth - pb._depth),
3029 3089 pvec._hamming(pa._vec, pb._vec),
3030 3090 pa.distance(pb),
3031 3091 rel,
3032 3092 )
3033 3093 )
3034 3094
3035 3095
3036 3096 @command(
3037 3097 b'debugrebuilddirstate|debugrebuildstate',
3038 3098 [
3039 3099 (b'r', b'rev', b'', _(b'revision to rebuild to'), _(b'REV')),
3040 3100 (
3041 3101 b'',
3042 3102 b'minimal',
3043 3103 None,
3044 3104 _(
3045 3105 b'only rebuild files that are inconsistent with '
3046 3106 b'the working copy parent'
3047 3107 ),
3048 3108 ),
3049 3109 ],
3050 3110 _(b'[-r REV]'),
3051 3111 )
3052 3112 def debugrebuilddirstate(ui, repo, rev, **opts):
3053 3113 """rebuild the dirstate as it would look like for the given revision
3054 3114
3055 3115 If no revision is specified the first current parent will be used.
3056 3116
3057 3117 The dirstate will be set to the files of the given revision.
3058 3118 The actual working directory content or existing dirstate
3059 3119 information such as adds or removes is not considered.
3060 3120
3061 3121 ``minimal`` will only rebuild the dirstate status for files that claim to be
3062 3122 tracked but are not in the parent manifest, or that exist in the parent
3063 3123 manifest but are not in the dirstate. It will not change adds, removes, or
3064 3124 modified files that are in the working copy parent.
3065 3125
3066 3126 One use of this command is to make the next :hg:`status` invocation
3067 3127 check the actual file content.
3068 3128 """
3069 3129 ctx = scmutil.revsingle(repo, rev)
3070 3130 with repo.wlock():
3071 3131 dirstate = repo.dirstate
3072 3132 changedfiles = None
3073 3133 # See command doc for what minimal does.
3074 3134 if opts.get('minimal'):
3075 3135 manifestfiles = set(ctx.manifest().keys())
3076 3136 dirstatefiles = set(dirstate)
3077 3137 manifestonly = manifestfiles - dirstatefiles
3078 3138 dsonly = dirstatefiles - manifestfiles
3079 3139 dsnotadded = {f for f in dsonly if not dirstate.get_entry(f).added}
3080 3140 changedfiles = manifestonly | dsnotadded
3081 3141
3082 3142 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3083 3143
3084 3144
3085 3145 @command(
3086 3146 b'debugrebuildfncache',
3087 3147 [
3088 3148 (
3089 3149 b'',
3090 3150 b'only-data',
3091 3151 False,
3092 3152 _(b'only look for wrong .d files (much faster)'),
3093 3153 )
3094 3154 ],
3095 3155 b'',
3096 3156 )
3097 3157 def debugrebuildfncache(ui, repo, **opts):
3098 3158 """rebuild the fncache file"""
3099 3159 opts = pycompat.byteskwargs(opts)
3100 3160 repair.rebuildfncache(ui, repo, opts.get(b"only_data"))
3101 3161
3102 3162
3103 3163 @command(
3104 3164 b'debugrename',
3105 3165 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
3106 3166 _(b'[-r REV] [FILE]...'),
3107 3167 )
3108 3168 def debugrename(ui, repo, *pats, **opts):
3109 3169 """dump rename information"""
3110 3170
3111 3171 opts = pycompat.byteskwargs(opts)
3112 3172 ctx = scmutil.revsingle(repo, opts.get(b'rev'))
3113 3173 m = scmutil.match(ctx, pats, opts)
3114 3174 for abs in ctx.walk(m):
3115 3175 fctx = ctx[abs]
3116 3176 o = fctx.filelog().renamed(fctx.filenode())
3117 3177 rel = repo.pathto(abs)
3118 3178 if o:
3119 3179 ui.write(_(b"%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3120 3180 else:
3121 3181 ui.write(_(b"%s not renamed\n") % rel)
3122 3182
3123 3183
3124 3184 @command(b'debugrequires|debugrequirements', [], b'')
3125 3185 def debugrequirements(ui, repo):
3126 3186 """print the current repo requirements"""
3127 3187 for r in sorted(repo.requirements):
3128 3188 ui.write(b"%s\n" % r)
3129 3189
3130 3190
3131 3191 @command(
3132 3192 b'debugrevlog',
3133 3193 cmdutil.debugrevlogopts + [(b'd', b'dump', False, _(b'dump index data'))],
3134 3194 _(b'-c|-m|FILE'),
3135 3195 optionalrepo=True,
3136 3196 )
3137 3197 def debugrevlog(ui, repo, file_=None, **opts):
3138 3198 """show data and statistics about a revlog"""
3139 3199 opts = pycompat.byteskwargs(opts)
3140 3200 r = cmdutil.openrevlog(repo, b'debugrevlog', file_, opts)
3141 3201
3142 3202 if opts.get(b"dump"):
3143 3203 numrevs = len(r)
3144 3204 ui.write(
3145 3205 (
3146 3206 b"# rev p1rev p2rev start end deltastart base p1 p2"
3147 3207 b" rawsize totalsize compression heads chainlen\n"
3148 3208 )
3149 3209 )
3150 3210 ts = 0
3151 3211 heads = set()
3152 3212
3153 3213 for rev in pycompat.xrange(numrevs):
3154 3214 dbase = r.deltaparent(rev)
3155 3215 if dbase == -1:
3156 3216 dbase = rev
3157 3217 cbase = r.chainbase(rev)
3158 3218 clen = r.chainlen(rev)
3159 3219 p1, p2 = r.parentrevs(rev)
3160 3220 rs = r.rawsize(rev)
3161 3221 ts = ts + rs
3162 3222 heads -= set(r.parentrevs(rev))
3163 3223 heads.add(rev)
3164 3224 try:
3165 3225 compression = ts / r.end(rev)
3166 3226 except ZeroDivisionError:
3167 3227 compression = 0
3168 3228 ui.write(
3169 3229 b"%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3170 3230 b"%11d %5d %8d\n"
3171 3231 % (
3172 3232 rev,
3173 3233 p1,
3174 3234 p2,
3175 3235 r.start(rev),
3176 3236 r.end(rev),
3177 3237 r.start(dbase),
3178 3238 r.start(cbase),
3179 3239 r.start(p1),
3180 3240 r.start(p2),
3181 3241 rs,
3182 3242 ts,
3183 3243 compression,
3184 3244 len(heads),
3185 3245 clen,
3186 3246 )
3187 3247 )
3188 3248 return 0
3189 3249
3190 3250 format = r._format_version
3191 3251 v = r._format_flags
3192 3252 flags = []
3193 3253 gdelta = False
3194 3254 if v & revlog.FLAG_INLINE_DATA:
3195 3255 flags.append(b'inline')
3196 3256 if v & revlog.FLAG_GENERALDELTA:
3197 3257 gdelta = True
3198 3258 flags.append(b'generaldelta')
3199 3259 if not flags:
3200 3260 flags = [b'(none)']
3201 3261
3202 3262 ### tracks merge vs single parent
3203 3263 nummerges = 0
3204 3264
3205 3265 ### tracks ways the "delta" are build
3206 3266 # nodelta
3207 3267 numempty = 0
3208 3268 numemptytext = 0
3209 3269 numemptydelta = 0
3210 3270 # full file content
3211 3271 numfull = 0
3212 3272 # intermediate snapshot against a prior snapshot
3213 3273 numsemi = 0
3214 3274 # snapshot count per depth
3215 3275 numsnapdepth = collections.defaultdict(lambda: 0)
3216 3276 # delta against previous revision
3217 3277 numprev = 0
3218 3278 # delta against first or second parent (not prev)
3219 3279 nump1 = 0
3220 3280 nump2 = 0
3221 3281 # delta against neither prev nor parents
3222 3282 numother = 0
3223 3283 # delta against prev that are also first or second parent
3224 3284 # (details of `numprev`)
3225 3285 nump1prev = 0
3226 3286 nump2prev = 0
3227 3287
3228 3288 # data about delta chain of each revs
3229 3289 chainlengths = []
3230 3290 chainbases = []
3231 3291 chainspans = []
3232 3292
3233 3293 # data about each revision
3234 3294 datasize = [None, 0, 0]
3235 3295 fullsize = [None, 0, 0]
3236 3296 semisize = [None, 0, 0]
3237 3297 # snapshot count per depth
3238 3298 snapsizedepth = collections.defaultdict(lambda: [None, 0, 0])
3239 3299 deltasize = [None, 0, 0]
3240 3300 chunktypecounts = {}
3241 3301 chunktypesizes = {}
3242 3302
3243 3303 def addsize(size, l):
3244 3304 if l[0] is None or size < l[0]:
3245 3305 l[0] = size
3246 3306 if size > l[1]:
3247 3307 l[1] = size
3248 3308 l[2] += size
3249 3309
3250 3310 numrevs = len(r)
3251 3311 for rev in pycompat.xrange(numrevs):
3252 3312 p1, p2 = r.parentrevs(rev)
3253 3313 delta = r.deltaparent(rev)
3254 3314 if format > 0:
3255 3315 addsize(r.rawsize(rev), datasize)
3256 3316 if p2 != nullrev:
3257 3317 nummerges += 1
3258 3318 size = r.length(rev)
3259 3319 if delta == nullrev:
3260 3320 chainlengths.append(0)
3261 3321 chainbases.append(r.start(rev))
3262 3322 chainspans.append(size)
3263 3323 if size == 0:
3264 3324 numempty += 1
3265 3325 numemptytext += 1
3266 3326 else:
3267 3327 numfull += 1
3268 3328 numsnapdepth[0] += 1
3269 3329 addsize(size, fullsize)
3270 3330 addsize(size, snapsizedepth[0])
3271 3331 else:
3272 3332 chainlengths.append(chainlengths[delta] + 1)
3273 3333 baseaddr = chainbases[delta]
3274 3334 revaddr = r.start(rev)
3275 3335 chainbases.append(baseaddr)
3276 3336 chainspans.append((revaddr - baseaddr) + size)
3277 3337 if size == 0:
3278 3338 numempty += 1
3279 3339 numemptydelta += 1
3280 3340 elif r.issnapshot(rev):
3281 3341 addsize(size, semisize)
3282 3342 numsemi += 1
3283 3343 depth = r.snapshotdepth(rev)
3284 3344 numsnapdepth[depth] += 1
3285 3345 addsize(size, snapsizedepth[depth])
3286 3346 else:
3287 3347 addsize(size, deltasize)
3288 3348 if delta == rev - 1:
3289 3349 numprev += 1
3290 3350 if delta == p1:
3291 3351 nump1prev += 1
3292 3352 elif delta == p2:
3293 3353 nump2prev += 1
3294 3354 elif delta == p1:
3295 3355 nump1 += 1
3296 3356 elif delta == p2:
3297 3357 nump2 += 1
3298 3358 elif delta != nullrev:
3299 3359 numother += 1
3300 3360
3301 3361 # Obtain data on the raw chunks in the revlog.
3302 3362 if util.safehasattr(r, b'_getsegmentforrevs'):
3303 3363 segment = r._getsegmentforrevs(rev, rev)[1]
3304 3364 else:
3305 3365 segment = r._revlog._getsegmentforrevs(rev, rev)[1]
3306 3366 if segment:
3307 3367 chunktype = bytes(segment[0:1])
3308 3368 else:
3309 3369 chunktype = b'empty'
3310 3370
3311 3371 if chunktype not in chunktypecounts:
3312 3372 chunktypecounts[chunktype] = 0
3313 3373 chunktypesizes[chunktype] = 0
3314 3374
3315 3375 chunktypecounts[chunktype] += 1
3316 3376 chunktypesizes[chunktype] += size
3317 3377
3318 3378 # Adjust size min value for empty cases
3319 3379 for size in (datasize, fullsize, semisize, deltasize):
3320 3380 if size[0] is None:
3321 3381 size[0] = 0
3322 3382
3323 3383 numdeltas = numrevs - numfull - numempty - numsemi
3324 3384 numoprev = numprev - nump1prev - nump2prev
3325 3385 totalrawsize = datasize[2]
3326 3386 datasize[2] /= numrevs
3327 3387 fulltotal = fullsize[2]
3328 3388 if numfull == 0:
3329 3389 fullsize[2] = 0
3330 3390 else:
3331 3391 fullsize[2] /= numfull
3332 3392 semitotal = semisize[2]
3333 3393 snaptotal = {}
3334 3394 if numsemi > 0:
3335 3395 semisize[2] /= numsemi
3336 3396 for depth in snapsizedepth:
3337 3397 snaptotal[depth] = snapsizedepth[depth][2]
3338 3398 snapsizedepth[depth][2] /= numsnapdepth[depth]
3339 3399
3340 3400 deltatotal = deltasize[2]
3341 3401 if numdeltas > 0:
3342 3402 deltasize[2] /= numdeltas
3343 3403 totalsize = fulltotal + semitotal + deltatotal
3344 3404 avgchainlen = sum(chainlengths) / numrevs
3345 3405 maxchainlen = max(chainlengths)
3346 3406 maxchainspan = max(chainspans)
3347 3407 compratio = 1
3348 3408 if totalsize:
3349 3409 compratio = totalrawsize / totalsize
3350 3410
3351 3411 basedfmtstr = b'%%%dd\n'
3352 3412 basepcfmtstr = b'%%%dd %s(%%5.2f%%%%)\n'
3353 3413
3354 3414 def dfmtstr(max):
3355 3415 return basedfmtstr % len(str(max))
3356 3416
3357 3417 def pcfmtstr(max, padding=0):
3358 3418 return basepcfmtstr % (len(str(max)), b' ' * padding)
3359 3419
3360 3420 def pcfmt(value, total):
3361 3421 if total:
3362 3422 return (value, 100 * float(value) / total)
3363 3423 else:
3364 3424 return value, 100.0
3365 3425
3366 3426 ui.writenoi18n(b'format : %d\n' % format)
3367 3427 ui.writenoi18n(b'flags : %s\n' % b', '.join(flags))
3368 3428
3369 3429 ui.write(b'\n')
3370 3430 fmt = pcfmtstr(totalsize)
3371 3431 fmt2 = dfmtstr(totalsize)
3372 3432 ui.writenoi18n(b'revisions : ' + fmt2 % numrevs)
3373 3433 ui.writenoi18n(b' merges : ' + fmt % pcfmt(nummerges, numrevs))
3374 3434 ui.writenoi18n(
3375 3435 b' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs)
3376 3436 )
3377 3437 ui.writenoi18n(b'revisions : ' + fmt2 % numrevs)
3378 3438 ui.writenoi18n(b' empty : ' + fmt % pcfmt(numempty, numrevs))
3379 3439 ui.writenoi18n(
3380 3440 b' text : '
3381 3441 + fmt % pcfmt(numemptytext, numemptytext + numemptydelta)
3382 3442 )
3383 3443 ui.writenoi18n(
3384 3444 b' delta : '
3385 3445 + fmt % pcfmt(numemptydelta, numemptytext + numemptydelta)
3386 3446 )
3387 3447 ui.writenoi18n(
3388 3448 b' snapshot : ' + fmt % pcfmt(numfull + numsemi, numrevs)
3389 3449 )
3390 3450 for depth in sorted(numsnapdepth):
3391 3451 ui.write(
3392 3452 (b' lvl-%-3d : ' % depth)
3393 3453 + fmt % pcfmt(numsnapdepth[depth], numrevs)
3394 3454 )
3395 3455 ui.writenoi18n(b' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
3396 3456 ui.writenoi18n(b'revision size : ' + fmt2 % totalsize)
3397 3457 ui.writenoi18n(
3398 3458 b' snapshot : ' + fmt % pcfmt(fulltotal + semitotal, totalsize)
3399 3459 )
3400 3460 for depth in sorted(numsnapdepth):
3401 3461 ui.write(
3402 3462 (b' lvl-%-3d : ' % depth)
3403 3463 + fmt % pcfmt(snaptotal[depth], totalsize)
3404 3464 )
3405 3465 ui.writenoi18n(b' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
3406 3466
3407 3467 def fmtchunktype(chunktype):
3408 3468 if chunktype == b'empty':
3409 3469 return b' %s : ' % chunktype
3410 3470 elif chunktype in pycompat.bytestr(string.ascii_letters):
3411 3471 return b' 0x%s (%s) : ' % (hex(chunktype), chunktype)
3412 3472 else:
3413 3473 return b' 0x%s : ' % hex(chunktype)
3414 3474
3415 3475 ui.write(b'\n')
3416 3476 ui.writenoi18n(b'chunks : ' + fmt2 % numrevs)
3417 3477 for chunktype in sorted(chunktypecounts):
3418 3478 ui.write(fmtchunktype(chunktype))
3419 3479 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
3420 3480 ui.writenoi18n(b'chunks size : ' + fmt2 % totalsize)
3421 3481 for chunktype in sorted(chunktypecounts):
3422 3482 ui.write(fmtchunktype(chunktype))
3423 3483 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
3424 3484
3425 3485 ui.write(b'\n')
3426 3486 fmt = dfmtstr(max(avgchainlen, maxchainlen, maxchainspan, compratio))
3427 3487 ui.writenoi18n(b'avg chain length : ' + fmt % avgchainlen)
3428 3488 ui.writenoi18n(b'max chain length : ' + fmt % maxchainlen)
3429 3489 ui.writenoi18n(b'max chain reach : ' + fmt % maxchainspan)
3430 3490 ui.writenoi18n(b'compression ratio : ' + fmt % compratio)
3431 3491
3432 3492 if format > 0:
3433 3493 ui.write(b'\n')
3434 3494 ui.writenoi18n(
3435 3495 b'uncompressed data size (min/max/avg) : %d / %d / %d\n'
3436 3496 % tuple(datasize)
3437 3497 )
3438 3498 ui.writenoi18n(
3439 3499 b'full revision size (min/max/avg) : %d / %d / %d\n'
3440 3500 % tuple(fullsize)
3441 3501 )
3442 3502 ui.writenoi18n(
3443 3503 b'inter-snapshot size (min/max/avg) : %d / %d / %d\n'
3444 3504 % tuple(semisize)
3445 3505 )
3446 3506 for depth in sorted(snapsizedepth):
3447 3507 if depth == 0:
3448 3508 continue
3449 3509 ui.writenoi18n(
3450 3510 b' level-%-3d (min/max/avg) : %d / %d / %d\n'
3451 3511 % ((depth,) + tuple(snapsizedepth[depth]))
3452 3512 )
3453 3513 ui.writenoi18n(
3454 3514 b'delta size (min/max/avg) : %d / %d / %d\n'
3455 3515 % tuple(deltasize)
3456 3516 )
3457 3517
3458 3518 if numdeltas > 0:
3459 3519 ui.write(b'\n')
3460 3520 fmt = pcfmtstr(numdeltas)
3461 3521 fmt2 = pcfmtstr(numdeltas, 4)
3462 3522 ui.writenoi18n(
3463 3523 b'deltas against prev : ' + fmt % pcfmt(numprev, numdeltas)
3464 3524 )
3465 3525 if numprev > 0:
3466 3526 ui.writenoi18n(
3467 3527 b' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev)
3468 3528 )
3469 3529 ui.writenoi18n(
3470 3530 b' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev)
3471 3531 )
3472 3532 ui.writenoi18n(
3473 3533 b' other : ' + fmt2 % pcfmt(numoprev, numprev)
3474 3534 )
3475 3535 if gdelta:
3476 3536 ui.writenoi18n(
3477 3537 b'deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas)
3478 3538 )
3479 3539 ui.writenoi18n(
3480 3540 b'deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas)
3481 3541 )
3482 3542 ui.writenoi18n(
3483 3543 b'deltas against other : ' + fmt % pcfmt(numother, numdeltas)
3484 3544 )
3485 3545
3486 3546
3487 3547 @command(
3488 3548 b'debugrevlogindex',
3489 3549 cmdutil.debugrevlogopts
3490 3550 + [(b'f', b'format', 0, _(b'revlog format'), _(b'FORMAT'))],
3491 3551 _(b'[-f FORMAT] -c|-m|FILE'),
3492 3552 optionalrepo=True,
3493 3553 )
3494 3554 def debugrevlogindex(ui, repo, file_=None, **opts):
3495 3555 """dump the contents of a revlog index"""
3496 3556 opts = pycompat.byteskwargs(opts)
3497 3557 r = cmdutil.openrevlog(repo, b'debugrevlogindex', file_, opts)
3498 3558 format = opts.get(b'format', 0)
3499 3559 if format not in (0, 1):
3500 3560 raise error.Abort(_(b"unknown format %d") % format)
3501 3561
3502 3562 if ui.debugflag:
3503 3563 shortfn = hex
3504 3564 else:
3505 3565 shortfn = short
3506 3566
3507 3567 # There might not be anything in r, so have a sane default
3508 3568 idlen = 12
3509 3569 for i in r:
3510 3570 idlen = len(shortfn(r.node(i)))
3511 3571 break
3512 3572
3513 3573 if format == 0:
3514 3574 if ui.verbose:
3515 3575 ui.writenoi18n(
3516 3576 b" rev offset length linkrev %s %s p2\n"
3517 3577 % (b"nodeid".ljust(idlen), b"p1".ljust(idlen))
3518 3578 )
3519 3579 else:
3520 3580 ui.writenoi18n(
3521 3581 b" rev linkrev %s %s p2\n"
3522 3582 % (b"nodeid".ljust(idlen), b"p1".ljust(idlen))
3523 3583 )
3524 3584 elif format == 1:
3525 3585 if ui.verbose:
3526 3586 ui.writenoi18n(
3527 3587 (
3528 3588 b" rev flag offset length size link p1"
3529 3589 b" p2 %s\n"
3530 3590 )
3531 3591 % b"nodeid".rjust(idlen)
3532 3592 )
3533 3593 else:
3534 3594 ui.writenoi18n(
3535 3595 b" rev flag size link p1 p2 %s\n"
3536 3596 % b"nodeid".rjust(idlen)
3537 3597 )
3538 3598
3539 3599 for i in r:
3540 3600 node = r.node(i)
3541 3601 if format == 0:
3542 3602 try:
3543 3603 pp = r.parents(node)
3544 3604 except Exception:
3545 3605 pp = [repo.nullid, repo.nullid]
3546 3606 if ui.verbose:
3547 3607 ui.write(
3548 3608 b"% 6d % 9d % 7d % 7d %s %s %s\n"
3549 3609 % (
3550 3610 i,
3551 3611 r.start(i),
3552 3612 r.length(i),
3553 3613 r.linkrev(i),
3554 3614 shortfn(node),
3555 3615 shortfn(pp[0]),
3556 3616 shortfn(pp[1]),
3557 3617 )
3558 3618 )
3559 3619 else:
3560 3620 ui.write(
3561 3621 b"% 6d % 7d %s %s %s\n"
3562 3622 % (
3563 3623 i,
3564 3624 r.linkrev(i),
3565 3625 shortfn(node),
3566 3626 shortfn(pp[0]),
3567 3627 shortfn(pp[1]),
3568 3628 )
3569 3629 )
3570 3630 elif format == 1:
3571 3631 pr = r.parentrevs(i)
3572 3632 if ui.verbose:
3573 3633 ui.write(
3574 3634 b"% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d %s\n"
3575 3635 % (
3576 3636 i,
3577 3637 r.flags(i),
3578 3638 r.start(i),
3579 3639 r.length(i),
3580 3640 r.rawsize(i),
3581 3641 r.linkrev(i),
3582 3642 pr[0],
3583 3643 pr[1],
3584 3644 shortfn(node),
3585 3645 )
3586 3646 )
3587 3647 else:
3588 3648 ui.write(
3589 3649 b"% 6d %04x % 8d % 6d % 6d % 6d %s\n"
3590 3650 % (
3591 3651 i,
3592 3652 r.flags(i),
3593 3653 r.rawsize(i),
3594 3654 r.linkrev(i),
3595 3655 pr[0],
3596 3656 pr[1],
3597 3657 shortfn(node),
3598 3658 )
3599 3659 )
3600 3660
3601 3661
3602 3662 @command(
3603 3663 b'debugrevspec',
3604 3664 [
3605 3665 (
3606 3666 b'',
3607 3667 b'optimize',
3608 3668 None,
3609 3669 _(b'print parsed tree after optimizing (DEPRECATED)'),
3610 3670 ),
3611 3671 (
3612 3672 b'',
3613 3673 b'show-revs',
3614 3674 True,
3615 3675 _(b'print list of result revisions (default)'),
3616 3676 ),
3617 3677 (
3618 3678 b's',
3619 3679 b'show-set',
3620 3680 None,
3621 3681 _(b'print internal representation of result set'),
3622 3682 ),
3623 3683 (
3624 3684 b'p',
3625 3685 b'show-stage',
3626 3686 [],
3627 3687 _(b'print parsed tree at the given stage'),
3628 3688 _(b'NAME'),
3629 3689 ),
3630 3690 (b'', b'no-optimized', False, _(b'evaluate tree without optimization')),
3631 3691 (b'', b'verify-optimized', False, _(b'verify optimized result')),
3632 3692 ],
3633 3693 b'REVSPEC',
3634 3694 )
3635 3695 def debugrevspec(ui, repo, expr, **opts):
3636 3696 """parse and apply a revision specification
3637 3697
3638 3698 Use -p/--show-stage option to print the parsed tree at the given stages.
3639 3699 Use -p all to print tree at every stage.
3640 3700
3641 3701 Use --no-show-revs option with -s or -p to print only the set
3642 3702 representation or the parsed tree respectively.
3643 3703
3644 3704 Use --verify-optimized to compare the optimized result with the unoptimized
3645 3705 one. Returns 1 if the optimized result differs.
3646 3706 """
3647 3707 opts = pycompat.byteskwargs(opts)
3648 3708 aliases = ui.configitems(b'revsetalias')
3649 3709 stages = [
3650 3710 (b'parsed', lambda tree: tree),
3651 3711 (
3652 3712 b'expanded',
3653 3713 lambda tree: revsetlang.expandaliases(tree, aliases, ui.warn),
3654 3714 ),
3655 3715 (b'concatenated', revsetlang.foldconcat),
3656 3716 (b'analyzed', revsetlang.analyze),
3657 3717 (b'optimized', revsetlang.optimize),
3658 3718 ]
3659 3719 if opts[b'no_optimized']:
3660 3720 stages = stages[:-1]
3661 3721 if opts[b'verify_optimized'] and opts[b'no_optimized']:
3662 3722 raise error.Abort(
3663 3723 _(b'cannot use --verify-optimized with --no-optimized')
3664 3724 )
3665 3725 stagenames = {n for n, f in stages}
3666 3726
3667 3727 showalways = set()
3668 3728 showchanged = set()
3669 3729 if ui.verbose and not opts[b'show_stage']:
3670 3730 # show parsed tree by --verbose (deprecated)
3671 3731 showalways.add(b'parsed')
3672 3732 showchanged.update([b'expanded', b'concatenated'])
3673 3733 if opts[b'optimize']:
3674 3734 showalways.add(b'optimized')
3675 3735 if opts[b'show_stage'] and opts[b'optimize']:
3676 3736 raise error.Abort(_(b'cannot use --optimize with --show-stage'))
3677 3737 if opts[b'show_stage'] == [b'all']:
3678 3738 showalways.update(stagenames)
3679 3739 else:
3680 3740 for n in opts[b'show_stage']:
3681 3741 if n not in stagenames:
3682 3742 raise error.Abort(_(b'invalid stage name: %s') % n)
3683 3743 showalways.update(opts[b'show_stage'])
3684 3744
3685 3745 treebystage = {}
3686 3746 printedtree = None
3687 3747 tree = revsetlang.parse(expr, lookup=revset.lookupfn(repo))
3688 3748 for n, f in stages:
3689 3749 treebystage[n] = tree = f(tree)
3690 3750 if n in showalways or (n in showchanged and tree != printedtree):
3691 3751 if opts[b'show_stage'] or n != b'parsed':
3692 3752 ui.write(b"* %s:\n" % n)
3693 3753 ui.write(revsetlang.prettyformat(tree), b"\n")
3694 3754 printedtree = tree
3695 3755
3696 3756 if opts[b'verify_optimized']:
3697 3757 arevs = revset.makematcher(treebystage[b'analyzed'])(repo)
3698 3758 brevs = revset.makematcher(treebystage[b'optimized'])(repo)
3699 3759 if opts[b'show_set'] or (opts[b'show_set'] is None and ui.verbose):
3700 3760 ui.writenoi18n(
3701 3761 b"* analyzed set:\n", stringutil.prettyrepr(arevs), b"\n"
3702 3762 )
3703 3763 ui.writenoi18n(
3704 3764 b"* optimized set:\n", stringutil.prettyrepr(brevs), b"\n"
3705 3765 )
3706 3766 arevs = list(arevs)
3707 3767 brevs = list(brevs)
3708 3768 if arevs == brevs:
3709 3769 return 0
3710 3770 ui.writenoi18n(b'--- analyzed\n', label=b'diff.file_a')
3711 3771 ui.writenoi18n(b'+++ optimized\n', label=b'diff.file_b')
3712 3772 sm = difflib.SequenceMatcher(None, arevs, brevs)
3713 3773 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3714 3774 if tag in ('delete', 'replace'):
3715 3775 for c in arevs[alo:ahi]:
3716 3776 ui.write(b'-%d\n' % c, label=b'diff.deleted')
3717 3777 if tag in ('insert', 'replace'):
3718 3778 for c in brevs[blo:bhi]:
3719 3779 ui.write(b'+%d\n' % c, label=b'diff.inserted')
3720 3780 if tag == 'equal':
3721 3781 for c in arevs[alo:ahi]:
3722 3782 ui.write(b' %d\n' % c)
3723 3783 return 1
3724 3784
3725 3785 func = revset.makematcher(tree)
3726 3786 revs = func(repo)
3727 3787 if opts[b'show_set'] or (opts[b'show_set'] is None and ui.verbose):
3728 3788 ui.writenoi18n(b"* set:\n", stringutil.prettyrepr(revs), b"\n")
3729 3789 if not opts[b'show_revs']:
3730 3790 return
3731 3791 for c in revs:
3732 3792 ui.write(b"%d\n" % c)
3733 3793
3734 3794
3735 3795 @command(
3736 3796 b'debugserve',
3737 3797 [
3738 3798 (
3739 3799 b'',
3740 3800 b'sshstdio',
3741 3801 False,
3742 3802 _(b'run an SSH server bound to process handles'),
3743 3803 ),
3744 3804 (b'', b'logiofd', b'', _(b'file descriptor to log server I/O to')),
3745 3805 (b'', b'logiofile', b'', _(b'file to log server I/O to')),
3746 3806 ],
3747 3807 b'',
3748 3808 )
3749 3809 def debugserve(ui, repo, **opts):
3750 3810 """run a server with advanced settings
3751 3811
3752 3812 This command is similar to :hg:`serve`. It exists partially as a
3753 3813 workaround to the fact that ``hg serve --stdio`` must have specific
3754 3814 arguments for security reasons.
3755 3815 """
3756 3816 opts = pycompat.byteskwargs(opts)
3757 3817
3758 3818 if not opts[b'sshstdio']:
3759 3819 raise error.Abort(_(b'only --sshstdio is currently supported'))
3760 3820
3761 3821 logfh = None
3762 3822
3763 3823 if opts[b'logiofd'] and opts[b'logiofile']:
3764 3824 raise error.Abort(_(b'cannot use both --logiofd and --logiofile'))
3765 3825
3766 3826 if opts[b'logiofd']:
3767 3827 # Ideally we would be line buffered. But line buffering in binary
3768 3828 # mode isn't supported and emits a warning in Python 3.8+. Disabling
3769 3829 # buffering could have performance impacts. But since this isn't
3770 3830 # performance critical code, it should be fine.
3771 3831 try:
3772 3832 logfh = os.fdopen(int(opts[b'logiofd']), 'ab', 0)
3773 3833 except OSError as e:
3774 3834 if e.errno != errno.ESPIPE:
3775 3835 raise
3776 3836 # can't seek a pipe, so `ab` mode fails on py3
3777 3837 logfh = os.fdopen(int(opts[b'logiofd']), 'wb', 0)
3778 3838 elif opts[b'logiofile']:
3779 3839 logfh = open(opts[b'logiofile'], b'ab', 0)
3780 3840
3781 3841 s = wireprotoserver.sshserver(ui, repo, logfh=logfh)
3782 3842 s.serve_forever()
3783 3843
3784 3844
3785 3845 @command(b'debugsetparents', [], _(b'REV1 [REV2]'))
3786 3846 def debugsetparents(ui, repo, rev1, rev2=None):
3787 3847 """manually set the parents of the current working directory (DANGEROUS)
3788 3848
3789 3849 This command is not what you are looking for and should not be used. Using
3790 3850 this command will most certainly results in slight corruption of the file
3791 3851 level histories withing your repository. DO NOT USE THIS COMMAND.
3792 3852
3793 3853 The command update the p1 and p2 field in the dirstate, and not touching
3794 3854 anything else. This useful for writing repository conversion tools, but
3795 3855 should be used with extreme care. For example, neither the working
3796 3856 directory nor the dirstate is updated, so file status may be incorrect
3797 3857 after running this command. Only used if you are one of the few people that
3798 3858 deeply unstand both conversion tools and file level histories. If you are
3799 3859 reading this help, you are not one of this people (most of them sailed west
3800 3860 from Mithlond anyway.
3801 3861
3802 3862 So one last time DO NOT USE THIS COMMAND.
3803 3863
3804 3864 Returns 0 on success.
3805 3865 """
3806 3866
3807 3867 node1 = scmutil.revsingle(repo, rev1).node()
3808 3868 node2 = scmutil.revsingle(repo, rev2, b'null').node()
3809 3869
3810 3870 with repo.wlock():
3811 3871 repo.setparents(node1, node2)
3812 3872
3813 3873
3814 3874 @command(b'debugsidedata', cmdutil.debugrevlogopts, _(b'-c|-m|FILE REV'))
3815 3875 def debugsidedata(ui, repo, file_, rev=None, **opts):
3816 3876 """dump the side data for a cl/manifest/file revision
3817 3877
3818 3878 Use --verbose to dump the sidedata content."""
3819 3879 opts = pycompat.byteskwargs(opts)
3820 3880 if opts.get(b'changelog') or opts.get(b'manifest') or opts.get(b'dir'):
3821 3881 if rev is not None:
3822 3882 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
3823 3883 file_, rev = None, file_
3824 3884 elif rev is None:
3825 3885 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
3826 3886 r = cmdutil.openstorage(repo, b'debugdata', file_, opts)
3827 3887 r = getattr(r, '_revlog', r)
3828 3888 try:
3829 3889 sidedata = r.sidedata(r.lookup(rev))
3830 3890 except KeyError:
3831 3891 raise error.Abort(_(b'invalid revision identifier %s') % rev)
3832 3892 if sidedata:
3833 3893 sidedata = list(sidedata.items())
3834 3894 sidedata.sort()
3835 3895 ui.writenoi18n(b'%d sidedata entries\n' % len(sidedata))
3836 3896 for key, value in sidedata:
3837 3897 ui.writenoi18n(b' entry-%04o size %d\n' % (key, len(value)))
3838 3898 if ui.verbose:
3839 3899 ui.writenoi18n(b' %s\n' % stringutil.pprint(value))
3840 3900
3841 3901
3842 3902 @command(b'debugssl', [], b'[SOURCE]', optionalrepo=True)
3843 3903 def debugssl(ui, repo, source=None, **opts):
3844 3904 """test a secure connection to a server
3845 3905
3846 3906 This builds the certificate chain for the server on Windows, installing the
3847 3907 missing intermediates and trusted root via Windows Update if necessary. It
3848 3908 does nothing on other platforms.
3849 3909
3850 3910 If SOURCE is omitted, the 'default' path will be used. If a URL is given,
3851 3911 that server is used. See :hg:`help urls` for more information.
3852 3912
3853 3913 If the update succeeds, retry the original operation. Otherwise, the cause
3854 3914 of the SSL error is likely another issue.
3855 3915 """
3856 3916 if not pycompat.iswindows:
3857 3917 raise error.Abort(
3858 3918 _(b'certificate chain building is only possible on Windows')
3859 3919 )
3860 3920
3861 3921 if not source:
3862 3922 if not repo:
3863 3923 raise error.Abort(
3864 3924 _(
3865 3925 b"there is no Mercurial repository here, and no "
3866 3926 b"server specified"
3867 3927 )
3868 3928 )
3869 3929 source = b"default"
3870 3930
3871 3931 source, branches = urlutil.get_unique_pull_path(
3872 3932 b'debugssl', repo, ui, source
3873 3933 )
3874 3934 url = urlutil.url(source)
3875 3935
3876 3936 defaultport = {b'https': 443, b'ssh': 22}
3877 3937 if url.scheme in defaultport:
3878 3938 try:
3879 3939 addr = (url.host, int(url.port or defaultport[url.scheme]))
3880 3940 except ValueError:
3881 3941 raise error.Abort(_(b"malformed port number in URL"))
3882 3942 else:
3883 3943 raise error.Abort(_(b"only https and ssh connections are supported"))
3884 3944
3885 3945 from . import win32
3886 3946
3887 3947 s = ssl.wrap_socket(
3888 3948 socket.socket(),
3889 3949 ssl_version=ssl.PROTOCOL_TLS,
3890 3950 cert_reqs=ssl.CERT_NONE,
3891 3951 ca_certs=None,
3892 3952 )
3893 3953
3894 3954 try:
3895 3955 s.connect(addr)
3896 3956 cert = s.getpeercert(True)
3897 3957
3898 3958 ui.status(_(b'checking the certificate chain for %s\n') % url.host)
3899 3959
3900 3960 complete = win32.checkcertificatechain(cert, build=False)
3901 3961
3902 3962 if not complete:
3903 3963 ui.status(_(b'certificate chain is incomplete, updating... '))
3904 3964
3905 3965 if not win32.checkcertificatechain(cert):
3906 3966 ui.status(_(b'failed.\n'))
3907 3967 else:
3908 3968 ui.status(_(b'done.\n'))
3909 3969 else:
3910 3970 ui.status(_(b'full certificate chain is available\n'))
3911 3971 finally:
3912 3972 s.close()
3913 3973
3914 3974
3915 3975 @command(
3916 3976 b"debugbackupbundle",
3917 3977 [
3918 3978 (
3919 3979 b"",
3920 3980 b"recover",
3921 3981 b"",
3922 3982 b"brings the specified changeset back into the repository",
3923 3983 )
3924 3984 ]
3925 3985 + cmdutil.logopts,
3926 3986 _(b"hg debugbackupbundle [--recover HASH]"),
3927 3987 )
3928 3988 def debugbackupbundle(ui, repo, *pats, **opts):
3929 3989 """lists the changesets available in backup bundles
3930 3990
3931 3991 Without any arguments, this command prints a list of the changesets in each
3932 3992 backup bundle.
3933 3993
3934 3994 --recover takes a changeset hash and unbundles the first bundle that
3935 3995 contains that hash, which puts that changeset back in your repository.
3936 3996
3937 3997 --verbose will print the entire commit message and the bundle path for that
3938 3998 backup.
3939 3999 """
3940 4000 backups = list(
3941 4001 filter(
3942 4002 os.path.isfile, glob.glob(repo.vfs.join(b"strip-backup") + b"/*.hg")
3943 4003 )
3944 4004 )
3945 4005 backups.sort(key=lambda x: os.path.getmtime(x), reverse=True)
3946 4006
3947 4007 opts = pycompat.byteskwargs(opts)
3948 4008 opts[b"bundle"] = b""
3949 4009 opts[b"force"] = None
3950 4010 limit = logcmdutil.getlimit(opts)
3951 4011
3952 4012 def display(other, chlist, displayer):
3953 4013 if opts.get(b"newest_first"):
3954 4014 chlist.reverse()
3955 4015 count = 0
3956 4016 for n in chlist:
3957 4017 if limit is not None and count >= limit:
3958 4018 break
3959 4019 parents = [
3960 4020 True for p in other.changelog.parents(n) if p != repo.nullid
3961 4021 ]
3962 4022 if opts.get(b"no_merges") and len(parents) == 2:
3963 4023 continue
3964 4024 count += 1
3965 4025 displayer.show(other[n])
3966 4026
3967 4027 recovernode = opts.get(b"recover")
3968 4028 if recovernode:
3969 4029 if scmutil.isrevsymbol(repo, recovernode):
3970 4030 ui.warn(_(b"%s already exists in the repo\n") % recovernode)
3971 4031 return
3972 4032 elif backups:
3973 4033 msg = _(
3974 4034 b"Recover changesets using: hg debugbackupbundle --recover "
3975 4035 b"<changeset hash>\n\nAvailable backup changesets:"
3976 4036 )
3977 4037 ui.status(msg, label=b"status.removed")
3978 4038 else:
3979 4039 ui.status(_(b"no backup changesets found\n"))
3980 4040 return
3981 4041
3982 4042 for backup in backups:
3983 4043 # Much of this is copied from the hg incoming logic
3984 4044 source = os.path.relpath(backup, encoding.getcwd())
3985 4045 source, branches = urlutil.get_unique_pull_path(
3986 4046 b'debugbackupbundle',
3987 4047 repo,
3988 4048 ui,
3989 4049 source,
3990 4050 default_branches=opts.get(b'branch'),
3991 4051 )
3992 4052 try:
3993 4053 other = hg.peer(repo, opts, source)
3994 4054 except error.LookupError as ex:
3995 4055 msg = _(b"\nwarning: unable to open bundle %s") % source
3996 4056 hint = _(b"\n(missing parent rev %s)\n") % short(ex.name)
3997 4057 ui.warn(msg, hint=hint)
3998 4058 continue
3999 4059 revs, checkout = hg.addbranchrevs(
4000 4060 repo, other, branches, opts.get(b"rev")
4001 4061 )
4002 4062
4003 4063 if revs:
4004 4064 revs = [other.lookup(rev) for rev in revs]
4005 4065
4006 4066 with ui.silent():
4007 4067 try:
4008 4068 other, chlist, cleanupfn = bundlerepo.getremotechanges(
4009 4069 ui, repo, other, revs, opts[b"bundle"], opts[b"force"]
4010 4070 )
4011 4071 except error.LookupError:
4012 4072 continue
4013 4073
4014 4074 try:
4015 4075 if not chlist:
4016 4076 continue
4017 4077 if recovernode:
4018 4078 with repo.lock(), repo.transaction(b"unbundle") as tr:
4019 4079 if scmutil.isrevsymbol(other, recovernode):
4020 4080 ui.status(_(b"Unbundling %s\n") % (recovernode))
4021 4081 f = hg.openpath(ui, source)
4022 4082 gen = exchange.readbundle(ui, f, source)
4023 4083 if isinstance(gen, bundle2.unbundle20):
4024 4084 bundle2.applybundle(
4025 4085 repo,
4026 4086 gen,
4027 4087 tr,
4028 4088 source=b"unbundle",
4029 4089 url=b"bundle:" + source,
4030 4090 )
4031 4091 else:
4032 4092 gen.apply(repo, b"unbundle", b"bundle:" + source)
4033 4093 break
4034 4094 else:
4035 4095 backupdate = encoding.strtolocal(
4036 4096 time.strftime(
4037 4097 "%a %H:%M, %Y-%m-%d",
4038 4098 time.localtime(os.path.getmtime(source)),
4039 4099 )
4040 4100 )
4041 4101 ui.status(b"\n%s\n" % (backupdate.ljust(50)))
4042 4102 if ui.verbose:
4043 4103 ui.status(b"%s%s\n" % (b"bundle:".ljust(13), source))
4044 4104 else:
4045 4105 opts[
4046 4106 b"template"
4047 4107 ] = b"{label('status.modified', node|short)} {desc|firstline}\n"
4048 4108 displayer = logcmdutil.changesetdisplayer(
4049 4109 ui, other, opts, False
4050 4110 )
4051 4111 display(other, chlist, displayer)
4052 4112 displayer.close()
4053 4113 finally:
4054 4114 cleanupfn()
4055 4115
4056 4116
4057 4117 @command(
4058 4118 b'debugsub',
4059 4119 [(b'r', b'rev', b'', _(b'revision to check'), _(b'REV'))],
4060 4120 _(b'[-r REV] [REV]'),
4061 4121 )
4062 4122 def debugsub(ui, repo, rev=None):
4063 4123 ctx = scmutil.revsingle(repo, rev, None)
4064 4124 for k, v in sorted(ctx.substate.items()):
4065 4125 ui.writenoi18n(b'path %s\n' % k)
4066 4126 ui.writenoi18n(b' source %s\n' % v[0])
4067 4127 ui.writenoi18n(b' revision %s\n' % v[1])
4068 4128
4069 4129
4070 4130 @command(b'debugshell', optionalrepo=True)
4071 4131 def debugshell(ui, repo):
4072 4132 """run an interactive Python interpreter
4073 4133
4074 4134 The local namespace is provided with a reference to the ui and
4075 4135 the repo instance (if available).
4076 4136 """
4077 4137 import code
4078 4138
4079 4139 imported_objects = {
4080 4140 'ui': ui,
4081 4141 'repo': repo,
4082 4142 }
4083 4143
4084 4144 code.interact(local=imported_objects)
4085 4145
4086 4146
4087 4147 @command(
4088 4148 b'debugsuccessorssets',
4089 4149 [(b'', b'closest', False, _(b'return closest successors sets only'))],
4090 4150 _(b'[REV]'),
4091 4151 )
4092 4152 def debugsuccessorssets(ui, repo, *revs, **opts):
4093 4153 """show set of successors for revision
4094 4154
4095 4155 A successors set of changeset A is a consistent group of revisions that
4096 4156 succeed A. It contains non-obsolete changesets only unless closests
4097 4157 successors set is set.
4098 4158
4099 4159 In most cases a changeset A has a single successors set containing a single
4100 4160 successor (changeset A replaced by A').
4101 4161
4102 4162 A changeset that is made obsolete with no successors are called "pruned".
4103 4163 Such changesets have no successors sets at all.
4104 4164
4105 4165 A changeset that has been "split" will have a successors set containing
4106 4166 more than one successor.
4107 4167
4108 4168 A changeset that has been rewritten in multiple different ways is called
4109 4169 "divergent". Such changesets have multiple successor sets (each of which
4110 4170 may also be split, i.e. have multiple successors).
4111 4171
4112 4172 Results are displayed as follows::
4113 4173
4114 4174 <rev1>
4115 4175 <successors-1A>
4116 4176 <rev2>
4117 4177 <successors-2A>
4118 4178 <successors-2B1> <successors-2B2> <successors-2B3>
4119 4179
4120 4180 Here rev2 has two possible (i.e. divergent) successors sets. The first
4121 4181 holds one element, whereas the second holds three (i.e. the changeset has
4122 4182 been split).
4123 4183 """
4124 4184 # passed to successorssets caching computation from one call to another
4125 4185 cache = {}
4126 4186 ctx2str = bytes
4127 4187 node2str = short
4128 4188 for rev in logcmdutil.revrange(repo, revs):
4129 4189 ctx = repo[rev]
4130 4190 ui.write(b'%s\n' % ctx2str(ctx))
4131 4191 for succsset in obsutil.successorssets(
4132 4192 repo, ctx.node(), closest=opts['closest'], cache=cache
4133 4193 ):
4134 4194 if succsset:
4135 4195 ui.write(b' ')
4136 4196 ui.write(node2str(succsset[0]))
4137 4197 for node in succsset[1:]:
4138 4198 ui.write(b' ')
4139 4199 ui.write(node2str(node))
4140 4200 ui.write(b'\n')
4141 4201
4142 4202
4143 4203 @command(b'debugtagscache', [])
4144 4204 def debugtagscache(ui, repo):
4145 4205 """display the contents of .hg/cache/hgtagsfnodes1"""
4146 4206 cache = tagsmod.hgtagsfnodescache(repo.unfiltered())
4147 4207 flog = repo.file(b'.hgtags')
4148 4208 for r in repo:
4149 4209 node = repo[r].node()
4150 4210 tagsnode = cache.getfnode(node, computemissing=False)
4151 4211 if tagsnode:
4152 4212 tagsnodedisplay = hex(tagsnode)
4153 4213 if not flog.hasnode(tagsnode):
4154 4214 tagsnodedisplay += b' (unknown node)'
4155 4215 elif tagsnode is None:
4156 4216 tagsnodedisplay = b'missing'
4157 4217 else:
4158 4218 tagsnodedisplay = b'invalid'
4159 4219
4160 4220 ui.write(b'%d %s %s\n' % (r, hex(node), tagsnodedisplay))
4161 4221
4162 4222
4163 4223 @command(
4164 4224 b'debugtemplate',
4165 4225 [
4166 4226 (b'r', b'rev', [], _(b'apply template on changesets'), _(b'REV')),
4167 4227 (b'D', b'define', [], _(b'define template keyword'), _(b'KEY=VALUE')),
4168 4228 ],
4169 4229 _(b'[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
4170 4230 optionalrepo=True,
4171 4231 )
4172 4232 def debugtemplate(ui, repo, tmpl, **opts):
4173 4233 """parse and apply a template
4174 4234
4175 4235 If -r/--rev is given, the template is processed as a log template and
4176 4236 applied to the given changesets. Otherwise, it is processed as a generic
4177 4237 template.
4178 4238
4179 4239 Use --verbose to print the parsed tree.
4180 4240 """
4181 4241 revs = None
4182 4242 if opts['rev']:
4183 4243 if repo is None:
4184 4244 raise error.RepoError(
4185 4245 _(b'there is no Mercurial repository here (.hg not found)')
4186 4246 )
4187 4247 revs = logcmdutil.revrange(repo, opts['rev'])
4188 4248
4189 4249 props = {}
4190 4250 for d in opts['define']:
4191 4251 try:
4192 4252 k, v = (e.strip() for e in d.split(b'=', 1))
4193 4253 if not k or k == b'ui':
4194 4254 raise ValueError
4195 4255 props[k] = v
4196 4256 except ValueError:
4197 4257 raise error.Abort(_(b'malformed keyword definition: %s') % d)
4198 4258
4199 4259 if ui.verbose:
4200 4260 aliases = ui.configitems(b'templatealias')
4201 4261 tree = templater.parse(tmpl)
4202 4262 ui.note(templater.prettyformat(tree), b'\n')
4203 4263 newtree = templater.expandaliases(tree, aliases)
4204 4264 if newtree != tree:
4205 4265 ui.notenoi18n(
4206 4266 b"* expanded:\n", templater.prettyformat(newtree), b'\n'
4207 4267 )
4208 4268
4209 4269 if revs is None:
4210 4270 tres = formatter.templateresources(ui, repo)
4211 4271 t = formatter.maketemplater(ui, tmpl, resources=tres)
4212 4272 if ui.verbose:
4213 4273 kwds, funcs = t.symbolsuseddefault()
4214 4274 ui.writenoi18n(b"* keywords: %s\n" % b', '.join(sorted(kwds)))
4215 4275 ui.writenoi18n(b"* functions: %s\n" % b', '.join(sorted(funcs)))
4216 4276 ui.write(t.renderdefault(props))
4217 4277 else:
4218 4278 displayer = logcmdutil.maketemplater(ui, repo, tmpl)
4219 4279 if ui.verbose:
4220 4280 kwds, funcs = displayer.t.symbolsuseddefault()
4221 4281 ui.writenoi18n(b"* keywords: %s\n" % b', '.join(sorted(kwds)))
4222 4282 ui.writenoi18n(b"* functions: %s\n" % b', '.join(sorted(funcs)))
4223 4283 for r in revs:
4224 4284 displayer.show(repo[r], **pycompat.strkwargs(props))
4225 4285 displayer.close()
4226 4286
4227 4287
4228 4288 @command(
4229 4289 b'debuguigetpass',
4230 4290 [
4231 4291 (b'p', b'prompt', b'', _(b'prompt text'), _(b'TEXT')),
4232 4292 ],
4233 4293 _(b'[-p TEXT]'),
4234 4294 norepo=True,
4235 4295 )
4236 4296 def debuguigetpass(ui, prompt=b''):
4237 4297 """show prompt to type password"""
4238 4298 r = ui.getpass(prompt)
4239 4299 if r is None:
4240 4300 r = b"<default response>"
4241 4301 ui.writenoi18n(b'response: %s\n' % r)
4242 4302
4243 4303
4244 4304 @command(
4245 4305 b'debuguiprompt',
4246 4306 [
4247 4307 (b'p', b'prompt', b'', _(b'prompt text'), _(b'TEXT')),
4248 4308 ],
4249 4309 _(b'[-p TEXT]'),
4250 4310 norepo=True,
4251 4311 )
4252 4312 def debuguiprompt(ui, prompt=b''):
4253 4313 """show plain prompt"""
4254 4314 r = ui.prompt(prompt)
4255 4315 ui.writenoi18n(b'response: %s\n' % r)
4256 4316
4257 4317
4258 4318 @command(b'debugupdatecaches', [])
4259 4319 def debugupdatecaches(ui, repo, *pats, **opts):
4260 4320 """warm all known caches in the repository"""
4261 4321 with repo.wlock(), repo.lock():
4262 4322 repo.updatecaches(caches=repository.CACHES_ALL)
4263 4323
4264 4324
4265 4325 @command(
4266 4326 b'debugupgraderepo',
4267 4327 [
4268 4328 (
4269 4329 b'o',
4270 4330 b'optimize',
4271 4331 [],
4272 4332 _(b'extra optimization to perform'),
4273 4333 _(b'NAME'),
4274 4334 ),
4275 4335 (b'', b'run', False, _(b'performs an upgrade')),
4276 4336 (b'', b'backup', True, _(b'keep the old repository content around')),
4277 4337 (b'', b'changelog', None, _(b'select the changelog for upgrade')),
4278 4338 (b'', b'manifest', None, _(b'select the manifest for upgrade')),
4279 4339 (b'', b'filelogs', None, _(b'select all filelogs for upgrade')),
4280 4340 ],
4281 4341 )
4282 4342 def debugupgraderepo(ui, repo, run=False, optimize=None, backup=True, **opts):
4283 4343 """upgrade a repository to use different features
4284 4344
4285 4345 If no arguments are specified, the repository is evaluated for upgrade
4286 4346 and a list of problems and potential optimizations is printed.
4287 4347
4288 4348 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
4289 4349 can be influenced via additional arguments. More details will be provided
4290 4350 by the command output when run without ``--run``.
4291 4351
4292 4352 During the upgrade, the repository will be locked and no writes will be
4293 4353 allowed.
4294 4354
4295 4355 At the end of the upgrade, the repository may not be readable while new
4296 4356 repository data is swapped in. This window will be as long as it takes to
4297 4357 rename some directories inside the ``.hg`` directory. On most machines, this
4298 4358 should complete almost instantaneously and the chances of a consumer being
4299 4359 unable to access the repository should be low.
4300 4360
4301 4361 By default, all revlogs will be upgraded. You can restrict this using flags
4302 4362 such as `--manifest`:
4303 4363
4304 4364 * `--manifest`: only optimize the manifest
4305 4365 * `--no-manifest`: optimize all revlog but the manifest
4306 4366 * `--changelog`: optimize the changelog only
4307 4367 * `--no-changelog --no-manifest`: optimize filelogs only
4308 4368 * `--filelogs`: optimize the filelogs only
4309 4369 * `--no-changelog --no-manifest --no-filelogs`: skip all revlog optimizations
4310 4370 """
4311 4371 return upgrade.upgraderepo(
4312 4372 ui, repo, run=run, optimize=set(optimize), backup=backup, **opts
4313 4373 )
4314 4374
4315 4375
4316 4376 @command(
4317 4377 b'debugwalk', cmdutil.walkopts, _(b'[OPTION]... [FILE]...'), inferrepo=True
4318 4378 )
4319 4379 def debugwalk(ui, repo, *pats, **opts):
4320 4380 """show how files match on given patterns"""
4321 4381 opts = pycompat.byteskwargs(opts)
4322 4382 m = scmutil.match(repo[None], pats, opts)
4323 4383 if ui.verbose:
4324 4384 ui.writenoi18n(b'* matcher:\n', stringutil.prettyrepr(m), b'\n')
4325 4385 items = list(repo[None].walk(m))
4326 4386 if not items:
4327 4387 return
4328 4388 f = lambda fn: fn
4329 4389 if ui.configbool(b'ui', b'slash') and pycompat.ossep != b'/':
4330 4390 f = lambda fn: util.normpath(fn)
4331 4391 fmt = b'f %%-%ds %%-%ds %%s' % (
4332 4392 max([len(abs) for abs in items]),
4333 4393 max([len(repo.pathto(abs)) for abs in items]),
4334 4394 )
4335 4395 for abs in items:
4336 4396 line = fmt % (
4337 4397 abs,
4338 4398 f(repo.pathto(abs)),
4339 4399 m.exact(abs) and b'exact' or b'',
4340 4400 )
4341 4401 ui.write(b"%s\n" % line.rstrip())
4342 4402
4343 4403
4344 4404 @command(b'debugwhyunstable', [], _(b'REV'))
4345 4405 def debugwhyunstable(ui, repo, rev):
4346 4406 """explain instabilities of a changeset"""
4347 4407 for entry in obsutil.whyunstable(repo, scmutil.revsingle(repo, rev)):
4348 4408 dnodes = b''
4349 4409 if entry.get(b'divergentnodes'):
4350 4410 dnodes = (
4351 4411 b' '.join(
4352 4412 b'%s (%s)' % (ctx.hex(), ctx.phasestr())
4353 4413 for ctx in entry[b'divergentnodes']
4354 4414 )
4355 4415 + b' '
4356 4416 )
4357 4417 ui.write(
4358 4418 b'%s: %s%s %s\n'
4359 4419 % (entry[b'instability'], dnodes, entry[b'reason'], entry[b'node'])
4360 4420 )
4361 4421
4362 4422
4363 4423 @command(
4364 4424 b'debugwireargs',
4365 4425 [
4366 4426 (b'', b'three', b'', b'three'),
4367 4427 (b'', b'four', b'', b'four'),
4368 4428 (b'', b'five', b'', b'five'),
4369 4429 ]
4370 4430 + cmdutil.remoteopts,
4371 4431 _(b'REPO [OPTIONS]... [ONE [TWO]]'),
4372 4432 norepo=True,
4373 4433 )
4374 4434 def debugwireargs(ui, repopath, *vals, **opts):
4375 4435 opts = pycompat.byteskwargs(opts)
4376 4436 repo = hg.peer(ui, opts, repopath)
4377 4437 try:
4378 4438 for opt in cmdutil.remoteopts:
4379 4439 del opts[opt[1]]
4380 4440 args = {}
4381 4441 for k, v in opts.items():
4382 4442 if v:
4383 4443 args[k] = v
4384 4444 args = pycompat.strkwargs(args)
4385 4445 # run twice to check that we don't mess up the stream for the next command
4386 4446 res1 = repo.debugwireargs(*vals, **args)
4387 4447 res2 = repo.debugwireargs(*vals, **args)
4388 4448 ui.write(b"%s\n" % res1)
4389 4449 if res1 != res2:
4390 4450 ui.warn(b"%s\n" % res2)
4391 4451 finally:
4392 4452 repo.close()
4393 4453
4394 4454
4395 4455 def _parsewirelangblocks(fh):
4396 4456 activeaction = None
4397 4457 blocklines = []
4398 4458 lastindent = 0
4399 4459
4400 4460 for line in fh:
4401 4461 line = line.rstrip()
4402 4462 if not line:
4403 4463 continue
4404 4464
4405 4465 if line.startswith(b'#'):
4406 4466 continue
4407 4467
4408 4468 if not line.startswith(b' '):
4409 4469 # New block. Flush previous one.
4410 4470 if activeaction:
4411 4471 yield activeaction, blocklines
4412 4472
4413 4473 activeaction = line
4414 4474 blocklines = []
4415 4475 lastindent = 0
4416 4476 continue
4417 4477
4418 4478 # Else we start with an indent.
4419 4479
4420 4480 if not activeaction:
4421 4481 raise error.Abort(_(b'indented line outside of block'))
4422 4482
4423 4483 indent = len(line) - len(line.lstrip())
4424 4484
4425 4485 # If this line is indented more than the last line, concatenate it.
4426 4486 if indent > lastindent and blocklines:
4427 4487 blocklines[-1] += line.lstrip()
4428 4488 else:
4429 4489 blocklines.append(line)
4430 4490 lastindent = indent
4431 4491
4432 4492 # Flush last block.
4433 4493 if activeaction:
4434 4494 yield activeaction, blocklines
4435 4495
4436 4496
4437 4497 @command(
4438 4498 b'debugwireproto',
4439 4499 [
4440 4500 (b'', b'localssh', False, _(b'start an SSH server for this repo')),
4441 4501 (b'', b'peer', b'', _(b'construct a specific version of the peer')),
4442 4502 (
4443 4503 b'',
4444 4504 b'noreadstderr',
4445 4505 False,
4446 4506 _(b'do not read from stderr of the remote'),
4447 4507 ),
4448 4508 (
4449 4509 b'',
4450 4510 b'nologhandshake',
4451 4511 False,
4452 4512 _(b'do not log I/O related to the peer handshake'),
4453 4513 ),
4454 4514 ]
4455 4515 + cmdutil.remoteopts,
4456 4516 _(b'[PATH]'),
4457 4517 optionalrepo=True,
4458 4518 )
4459 4519 def debugwireproto(ui, repo, path=None, **opts):
4460 4520 """send wire protocol commands to a server
4461 4521
4462 4522 This command can be used to issue wire protocol commands to remote
4463 4523 peers and to debug the raw data being exchanged.
4464 4524
4465 4525 ``--localssh`` will start an SSH server against the current repository
4466 4526 and connect to that. By default, the connection will perform a handshake
4467 4527 and establish an appropriate peer instance.
4468 4528
4469 4529 ``--peer`` can be used to bypass the handshake protocol and construct a
4470 4530 peer instance using the specified class type. Valid values are ``raw``,
4471 4531 ``ssh1``. ``raw`` instances only allow sending raw data payloads and
4472 4532 don't support higher-level command actions.
4473 4533
4474 4534 ``--noreadstderr`` can be used to disable automatic reading from stderr
4475 4535 of the peer (for SSH connections only). Disabling automatic reading of
4476 4536 stderr is useful for making output more deterministic.
4477 4537
4478 4538 Commands are issued via a mini language which is specified via stdin.
4479 4539 The language consists of individual actions to perform. An action is
4480 4540 defined by a block. A block is defined as a line with no leading
4481 4541 space followed by 0 or more lines with leading space. Blocks are
4482 4542 effectively a high-level command with additional metadata.
4483 4543
4484 4544 Lines beginning with ``#`` are ignored.
4485 4545
4486 4546 The following sections denote available actions.
4487 4547
4488 4548 raw
4489 4549 ---
4490 4550
4491 4551 Send raw data to the server.
4492 4552
4493 4553 The block payload contains the raw data to send as one atomic send
4494 4554 operation. The data may not actually be delivered in a single system
4495 4555 call: it depends on the abilities of the transport being used.
4496 4556
4497 4557 Each line in the block is de-indented and concatenated. Then, that
4498 4558 value is evaluated as a Python b'' literal. This allows the use of
4499 4559 backslash escaping, etc.
4500 4560
4501 4561 raw+
4502 4562 ----
4503 4563
4504 4564 Behaves like ``raw`` except flushes output afterwards.
4505 4565
4506 4566 command <X>
4507 4567 -----------
4508 4568
4509 4569 Send a request to run a named command, whose name follows the ``command``
4510 4570 string.
4511 4571
4512 4572 Arguments to the command are defined as lines in this block. The format of
4513 4573 each line is ``<key> <value>``. e.g.::
4514 4574
4515 4575 command listkeys
4516 4576 namespace bookmarks
4517 4577
4518 4578 If the value begins with ``eval:``, it will be interpreted as a Python
4519 4579 literal expression. Otherwise values are interpreted as Python b'' literals.
4520 4580 This allows sending complex types and encoding special byte sequences via
4521 4581 backslash escaping.
4522 4582
4523 4583 The following arguments have special meaning:
4524 4584
4525 4585 ``PUSHFILE``
4526 4586 When defined, the *push* mechanism of the peer will be used instead
4527 4587 of the static request-response mechanism and the content of the
4528 4588 file specified in the value of this argument will be sent as the
4529 4589 command payload.
4530 4590
4531 4591 This can be used to submit a local bundle file to the remote.
4532 4592
4533 4593 batchbegin
4534 4594 ----------
4535 4595
4536 4596 Instruct the peer to begin a batched send.
4537 4597
4538 4598 All ``command`` blocks are queued for execution until the next
4539 4599 ``batchsubmit`` block.
4540 4600
4541 4601 batchsubmit
4542 4602 -----------
4543 4603
4544 4604 Submit previously queued ``command`` blocks as a batch request.
4545 4605
4546 4606 This action MUST be paired with a ``batchbegin`` action.
4547 4607
4548 4608 httprequest <method> <path>
4549 4609 ---------------------------
4550 4610
4551 4611 (HTTP peer only)
4552 4612
4553 4613 Send an HTTP request to the peer.
4554 4614
4555 4615 The HTTP request line follows the ``httprequest`` action. e.g. ``GET /foo``.
4556 4616
4557 4617 Arguments of the form ``<key>: <value>`` are interpreted as HTTP request
4558 4618 headers to add to the request. e.g. ``Accept: foo``.
4559 4619
4560 4620 The following arguments are special:
4561 4621
4562 4622 ``BODYFILE``
4563 4623 The content of the file defined as the value to this argument will be
4564 4624 transferred verbatim as the HTTP request body.
4565 4625
4566 4626 ``frame <type> <flags> <payload>``
4567 4627 Send a unified protocol frame as part of the request body.
4568 4628
4569 4629 All frames will be collected and sent as the body to the HTTP
4570 4630 request.
4571 4631
4572 4632 close
4573 4633 -----
4574 4634
4575 4635 Close the connection to the server.
4576 4636
4577 4637 flush
4578 4638 -----
4579 4639
4580 4640 Flush data written to the server.
4581 4641
4582 4642 readavailable
4583 4643 -------------
4584 4644
4585 4645 Close the write end of the connection and read all available data from
4586 4646 the server.
4587 4647
4588 4648 If the connection to the server encompasses multiple pipes, we poll both
4589 4649 pipes and read available data.
4590 4650
4591 4651 readline
4592 4652 --------
4593 4653
4594 4654 Read a line of output from the server. If there are multiple output
4595 4655 pipes, reads only the main pipe.
4596 4656
4597 4657 ereadline
4598 4658 ---------
4599 4659
4600 4660 Like ``readline``, but read from the stderr pipe, if available.
4601 4661
4602 4662 read <X>
4603 4663 --------
4604 4664
4605 4665 ``read()`` N bytes from the server's main output pipe.
4606 4666
4607 4667 eread <X>
4608 4668 ---------
4609 4669
4610 4670 ``read()`` N bytes from the server's stderr pipe, if available.
4611 4671
4612 4672 Specifying Unified Frame-Based Protocol Frames
4613 4673 ----------------------------------------------
4614 4674
4615 4675 It is possible to emit a *Unified Frame-Based Protocol* by using special
4616 4676 syntax.
4617 4677
4618 4678 A frame is composed as a type, flags, and payload. These can be parsed
4619 4679 from a string of the form:
4620 4680
4621 4681 <request-id> <stream-id> <stream-flags> <type> <flags> <payload>
4622 4682
4623 4683 ``request-id`` and ``stream-id`` are integers defining the request and
4624 4684 stream identifiers.
4625 4685
4626 4686 ``type`` can be an integer value for the frame type or the string name
4627 4687 of the type. The strings are defined in ``wireprotoframing.py``. e.g.
4628 4688 ``command-name``.
4629 4689
4630 4690 ``stream-flags`` and ``flags`` are a ``|`` delimited list of flag
4631 4691 components. Each component (and there can be just one) can be an integer
4632 4692 or a flag name for stream flags or frame flags, respectively. Values are
4633 4693 resolved to integers and then bitwise OR'd together.
4634 4694
4635 4695 ``payload`` represents the raw frame payload. If it begins with
4636 4696 ``cbor:``, the following string is evaluated as Python code and the
4637 4697 resulting object is fed into a CBOR encoder. Otherwise it is interpreted
4638 4698 as a Python byte string literal.
4639 4699 """
4640 4700 opts = pycompat.byteskwargs(opts)
4641 4701
4642 4702 if opts[b'localssh'] and not repo:
4643 4703 raise error.Abort(_(b'--localssh requires a repository'))
4644 4704
4645 4705 if opts[b'peer'] and opts[b'peer'] not in (
4646 4706 b'raw',
4647 4707 b'ssh1',
4648 4708 ):
4649 4709 raise error.Abort(
4650 4710 _(b'invalid value for --peer'),
4651 4711 hint=_(b'valid values are "raw" and "ssh1"'),
4652 4712 )
4653 4713
4654 4714 if path and opts[b'localssh']:
4655 4715 raise error.Abort(_(b'cannot specify --localssh with an explicit path'))
4656 4716
4657 4717 if ui.interactive():
4658 4718 ui.write(_(b'(waiting for commands on stdin)\n'))
4659 4719
4660 4720 blocks = list(_parsewirelangblocks(ui.fin))
4661 4721
4662 4722 proc = None
4663 4723 stdin = None
4664 4724 stdout = None
4665 4725 stderr = None
4666 4726 opener = None
4667 4727
4668 4728 if opts[b'localssh']:
4669 4729 # We start the SSH server in its own process so there is process
4670 4730 # separation. This prevents a whole class of potential bugs around
4671 4731 # shared state from interfering with server operation.
4672 4732 args = procutil.hgcmd() + [
4673 4733 b'-R',
4674 4734 repo.root,
4675 4735 b'debugserve',
4676 4736 b'--sshstdio',
4677 4737 ]
4678 4738 proc = subprocess.Popen(
4679 4739 pycompat.rapply(procutil.tonativestr, args),
4680 4740 stdin=subprocess.PIPE,
4681 4741 stdout=subprocess.PIPE,
4682 4742 stderr=subprocess.PIPE,
4683 4743 bufsize=0,
4684 4744 )
4685 4745
4686 4746 stdin = proc.stdin
4687 4747 stdout = proc.stdout
4688 4748 stderr = proc.stderr
4689 4749
4690 4750 # We turn the pipes into observers so we can log I/O.
4691 4751 if ui.verbose or opts[b'peer'] == b'raw':
4692 4752 stdin = util.makeloggingfileobject(
4693 4753 ui, proc.stdin, b'i', logdata=True
4694 4754 )
4695 4755 stdout = util.makeloggingfileobject(
4696 4756 ui, proc.stdout, b'o', logdata=True
4697 4757 )
4698 4758 stderr = util.makeloggingfileobject(
4699 4759 ui, proc.stderr, b'e', logdata=True
4700 4760 )
4701 4761
4702 4762 # --localssh also implies the peer connection settings.
4703 4763
4704 4764 url = b'ssh://localserver'
4705 4765 autoreadstderr = not opts[b'noreadstderr']
4706 4766
4707 4767 if opts[b'peer'] == b'ssh1':
4708 4768 ui.write(_(b'creating ssh peer for wire protocol version 1\n'))
4709 4769 peer = sshpeer.sshv1peer(
4710 4770 ui,
4711 4771 url,
4712 4772 proc,
4713 4773 stdin,
4714 4774 stdout,
4715 4775 stderr,
4716 4776 None,
4717 4777 autoreadstderr=autoreadstderr,
4718 4778 )
4719 4779 elif opts[b'peer'] == b'raw':
4720 4780 ui.write(_(b'using raw connection to peer\n'))
4721 4781 peer = None
4722 4782 else:
4723 4783 ui.write(_(b'creating ssh peer from handshake results\n'))
4724 4784 peer = sshpeer.makepeer(
4725 4785 ui,
4726 4786 url,
4727 4787 proc,
4728 4788 stdin,
4729 4789 stdout,
4730 4790 stderr,
4731 4791 autoreadstderr=autoreadstderr,
4732 4792 )
4733 4793
4734 4794 elif path:
4735 4795 # We bypass hg.peer() so we can proxy the sockets.
4736 4796 # TODO consider not doing this because we skip
4737 4797 # ``hg.wirepeersetupfuncs`` and potentially other useful functionality.
4738 4798 u = urlutil.url(path)
4739 4799 if u.scheme != b'http':
4740 4800 raise error.Abort(_(b'only http:// paths are currently supported'))
4741 4801
4742 4802 url, authinfo = u.authinfo()
4743 4803 openerargs = {
4744 4804 'useragent': b'Mercurial debugwireproto',
4745 4805 }
4746 4806
4747 4807 # Turn pipes/sockets into observers so we can log I/O.
4748 4808 if ui.verbose:
4749 4809 openerargs.update(
4750 4810 {
4751 4811 'loggingfh': ui,
4752 4812 'loggingname': b's',
4753 4813 'loggingopts': {
4754 4814 'logdata': True,
4755 4815 'logdataapis': False,
4756 4816 },
4757 4817 }
4758 4818 )
4759 4819
4760 4820 if ui.debugflag:
4761 4821 openerargs['loggingopts']['logdataapis'] = True
4762 4822
4763 4823 # Don't send default headers when in raw mode. This allows us to
4764 4824 # bypass most of the behavior of our URL handling code so we can
4765 4825 # have near complete control over what's sent on the wire.
4766 4826 if opts[b'peer'] == b'raw':
4767 4827 openerargs['sendaccept'] = False
4768 4828
4769 4829 opener = urlmod.opener(ui, authinfo, **openerargs)
4770 4830
4771 4831 if opts[b'peer'] == b'raw':
4772 4832 ui.write(_(b'using raw connection to peer\n'))
4773 4833 peer = None
4774 4834 elif opts[b'peer']:
4775 4835 raise error.Abort(
4776 4836 _(b'--peer %s not supported with HTTP peers') % opts[b'peer']
4777 4837 )
4778 4838 else:
4779 4839 peer = httppeer.makepeer(ui, path, opener=opener)
4780 4840
4781 4841 # We /could/ populate stdin/stdout with sock.makefile()...
4782 4842 else:
4783 4843 raise error.Abort(_(b'unsupported connection configuration'))
4784 4844
4785 4845 batchedcommands = None
4786 4846
4787 4847 # Now perform actions based on the parsed wire language instructions.
4788 4848 for action, lines in blocks:
4789 4849 if action in (b'raw', b'raw+'):
4790 4850 if not stdin:
4791 4851 raise error.Abort(_(b'cannot call raw/raw+ on this peer'))
4792 4852
4793 4853 # Concatenate the data together.
4794 4854 data = b''.join(l.lstrip() for l in lines)
4795 4855 data = stringutil.unescapestr(data)
4796 4856 stdin.write(data)
4797 4857
4798 4858 if action == b'raw+':
4799 4859 stdin.flush()
4800 4860 elif action == b'flush':
4801 4861 if not stdin:
4802 4862 raise error.Abort(_(b'cannot call flush on this peer'))
4803 4863 stdin.flush()
4804 4864 elif action.startswith(b'command'):
4805 4865 if not peer:
4806 4866 raise error.Abort(
4807 4867 _(
4808 4868 b'cannot send commands unless peer instance '
4809 4869 b'is available'
4810 4870 )
4811 4871 )
4812 4872
4813 4873 command = action.split(b' ', 1)[1]
4814 4874
4815 4875 args = {}
4816 4876 for line in lines:
4817 4877 # We need to allow empty values.
4818 4878 fields = line.lstrip().split(b' ', 1)
4819 4879 if len(fields) == 1:
4820 4880 key = fields[0]
4821 4881 value = b''
4822 4882 else:
4823 4883 key, value = fields
4824 4884
4825 4885 if value.startswith(b'eval:'):
4826 4886 value = stringutil.evalpythonliteral(value[5:])
4827 4887 else:
4828 4888 value = stringutil.unescapestr(value)
4829 4889
4830 4890 args[key] = value
4831 4891
4832 4892 if batchedcommands is not None:
4833 4893 batchedcommands.append((command, args))
4834 4894 continue
4835 4895
4836 4896 ui.status(_(b'sending %s command\n') % command)
4837 4897
4838 4898 if b'PUSHFILE' in args:
4839 4899 with open(args[b'PUSHFILE'], 'rb') as fh:
4840 4900 del args[b'PUSHFILE']
4841 4901 res, output = peer._callpush(
4842 4902 command, fh, **pycompat.strkwargs(args)
4843 4903 )
4844 4904 ui.status(_(b'result: %s\n') % stringutil.escapestr(res))
4845 4905 ui.status(
4846 4906 _(b'remote output: %s\n') % stringutil.escapestr(output)
4847 4907 )
4848 4908 else:
4849 4909 with peer.commandexecutor() as e:
4850 4910 res = e.callcommand(command, args).result()
4851 4911
4852 4912 ui.status(
4853 4913 _(b'response: %s\n')
4854 4914 % stringutil.pprint(res, bprefix=True, indent=2)
4855 4915 )
4856 4916
4857 4917 elif action == b'batchbegin':
4858 4918 if batchedcommands is not None:
4859 4919 raise error.Abort(_(b'nested batchbegin not allowed'))
4860 4920
4861 4921 batchedcommands = []
4862 4922 elif action == b'batchsubmit':
4863 4923 # There is a batching API we could go through. But it would be
4864 4924 # difficult to normalize requests into function calls. It is easier
4865 4925 # to bypass this layer and normalize to commands + args.
4866 4926 ui.status(
4867 4927 _(b'sending batch with %d sub-commands\n')
4868 4928 % len(batchedcommands)
4869 4929 )
4870 4930 assert peer is not None
4871 4931 for i, chunk in enumerate(peer._submitbatch(batchedcommands)):
4872 4932 ui.status(
4873 4933 _(b'response #%d: %s\n') % (i, stringutil.escapestr(chunk))
4874 4934 )
4875 4935
4876 4936 batchedcommands = None
4877 4937
4878 4938 elif action.startswith(b'httprequest '):
4879 4939 if not opener:
4880 4940 raise error.Abort(
4881 4941 _(b'cannot use httprequest without an HTTP peer')
4882 4942 )
4883 4943
4884 4944 request = action.split(b' ', 2)
4885 4945 if len(request) != 3:
4886 4946 raise error.Abort(
4887 4947 _(
4888 4948 b'invalid httprequest: expected format is '
4889 4949 b'"httprequest <method> <path>'
4890 4950 )
4891 4951 )
4892 4952
4893 4953 method, httppath = request[1:]
4894 4954 headers = {}
4895 4955 body = None
4896 4956 frames = []
4897 4957 for line in lines:
4898 4958 line = line.lstrip()
4899 4959 m = re.match(b'^([a-zA-Z0-9_-]+): (.*)$', line)
4900 4960 if m:
4901 4961 # Headers need to use native strings.
4902 4962 key = pycompat.strurl(m.group(1))
4903 4963 value = pycompat.strurl(m.group(2))
4904 4964 headers[key] = value
4905 4965 continue
4906 4966
4907 4967 if line.startswith(b'BODYFILE '):
4908 4968 with open(line.split(b' ', 1), b'rb') as fh:
4909 4969 body = fh.read()
4910 4970 elif line.startswith(b'frame '):
4911 4971 frame = wireprotoframing.makeframefromhumanstring(
4912 4972 line[len(b'frame ') :]
4913 4973 )
4914 4974
4915 4975 frames.append(frame)
4916 4976 else:
4917 4977 raise error.Abort(
4918 4978 _(b'unknown argument to httprequest: %s') % line
4919 4979 )
4920 4980
4921 4981 url = path + httppath
4922 4982
4923 4983 if frames:
4924 4984 body = b''.join(bytes(f) for f in frames)
4925 4985
4926 4986 req = urlmod.urlreq.request(pycompat.strurl(url), body, headers)
4927 4987
4928 4988 # urllib.Request insists on using has_data() as a proxy for
4929 4989 # determining the request method. Override that to use our
4930 4990 # explicitly requested method.
4931 4991 req.get_method = lambda: pycompat.sysstr(method)
4932 4992
4933 4993 try:
4934 4994 res = opener.open(req)
4935 4995 body = res.read()
4936 4996 except util.urlerr.urlerror as e:
4937 4997 # read() method must be called, but only exists in Python 2
4938 4998 getattr(e, 'read', lambda: None)()
4939 4999 continue
4940 5000
4941 5001 ct = res.headers.get('Content-Type')
4942 5002 if ct == 'application/mercurial-cbor':
4943 5003 ui.write(
4944 5004 _(b'cbor> %s\n')
4945 5005 % stringutil.pprint(
4946 5006 cborutil.decodeall(body), bprefix=True, indent=2
4947 5007 )
4948 5008 )
4949 5009
4950 5010 elif action == b'close':
4951 5011 assert peer is not None
4952 5012 peer.close()
4953 5013 elif action == b'readavailable':
4954 5014 if not stdout or not stderr:
4955 5015 raise error.Abort(
4956 5016 _(b'readavailable not available on this peer')
4957 5017 )
4958 5018
4959 5019 stdin.close()
4960 5020 stdout.read()
4961 5021 stderr.read()
4962 5022
4963 5023 elif action == b'readline':
4964 5024 if not stdout:
4965 5025 raise error.Abort(_(b'readline not available on this peer'))
4966 5026 stdout.readline()
4967 5027 elif action == b'ereadline':
4968 5028 if not stderr:
4969 5029 raise error.Abort(_(b'ereadline not available on this peer'))
4970 5030 stderr.readline()
4971 5031 elif action.startswith(b'read '):
4972 5032 count = int(action.split(b' ', 1)[1])
4973 5033 if not stdout:
4974 5034 raise error.Abort(_(b'read not available on this peer'))
4975 5035 stdout.read(count)
4976 5036 elif action.startswith(b'eread '):
4977 5037 count = int(action.split(b' ', 1)[1])
4978 5038 if not stderr:
4979 5039 raise error.Abort(_(b'eread not available on this peer'))
4980 5040 stderr.read(count)
4981 5041 else:
4982 5042 raise error.Abort(_(b'unknown action: %s') % action)
4983 5043
4984 5044 if batchedcommands is not None:
4985 5045 raise error.Abort(_(b'unclosed "batchbegin" request'))
4986 5046
4987 5047 if peer:
4988 5048 peer.close()
4989 5049
4990 5050 if proc:
4991 5051 proc.kill()
@@ -1,1233 +1,1332 b''
1 1 # revlogdeltas.py - Logic around delta computation for revlog
2 2 #
3 3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
4 4 # Copyright 2018 Octobus <contact@octobus.net>
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8 """Helper class to compute deltas stored inside revlogs"""
9 9
10 10
11 11 import collections
12 12 import struct
13 13
14 14 # import stuff from node for others to import from revlog
15 15 from ..node import nullrev
16 16 from ..i18n import _
17 17 from ..pycompat import getattr
18 18
19 19 from .constants import (
20 20 COMP_MODE_DEFAULT,
21 21 COMP_MODE_INLINE,
22 22 COMP_MODE_PLAIN,
23 23 KIND_CHANGELOG,
24 24 KIND_FILELOG,
25 25 KIND_MANIFESTLOG,
26 26 REVIDX_ISCENSORED,
27 27 REVIDX_RAWTEXT_CHANGING_FLAGS,
28 28 )
29 29
30 30 from ..thirdparty import attr
31 31
32 32 from .. import (
33 33 error,
34 34 mdiff,
35 35 util,
36 36 )
37 37
38 38 from . import flagutil
39 39
40 40 # maximum <delta-chain-data>/<revision-text-length> ratio
41 41 LIMIT_DELTA2TEXT = 2
42 42
43 43
44 44 class _testrevlog:
45 45 """minimalist fake revlog to use in doctests"""
46 46
47 47 def __init__(self, data, density=0.5, mingap=0, snapshot=()):
48 48 """data is an list of revision payload boundaries"""
49 49 self._data = data
50 50 self._srdensitythreshold = density
51 51 self._srmingapsize = mingap
52 52 self._snapshot = set(snapshot)
53 53 self.index = None
54 54
55 55 def start(self, rev):
56 56 if rev == nullrev:
57 57 return 0
58 58 if rev == 0:
59 59 return 0
60 60 return self._data[rev - 1]
61 61
62 62 def end(self, rev):
63 63 if rev == nullrev:
64 64 return 0
65 65 return self._data[rev]
66 66
67 67 def length(self, rev):
68 68 return self.end(rev) - self.start(rev)
69 69
70 70 def __len__(self):
71 71 return len(self._data)
72 72
73 73 def issnapshot(self, rev):
74 74 if rev == nullrev:
75 75 return True
76 76 return rev in self._snapshot
77 77
78 78
79 79 def slicechunk(revlog, revs, targetsize=None):
80 80 """slice revs to reduce the amount of unrelated data to be read from disk.
81 81
82 82 ``revs`` is sliced into groups that should be read in one time.
83 83 Assume that revs are sorted.
84 84
85 85 The initial chunk is sliced until the overall density (payload/chunks-span
86 86 ratio) is above `revlog._srdensitythreshold`. No gap smaller than
87 87 `revlog._srmingapsize` is skipped.
88 88
89 89 If `targetsize` is set, no chunk larger than `targetsize` will be yield.
90 90 For consistency with other slicing choice, this limit won't go lower than
91 91 `revlog._srmingapsize`.
92 92
93 93 If individual revisions chunk are larger than this limit, they will still
94 94 be raised individually.
95 95
96 96 >>> data = [
97 97 ... 5, #00 (5)
98 98 ... 10, #01 (5)
99 99 ... 12, #02 (2)
100 100 ... 12, #03 (empty)
101 101 ... 27, #04 (15)
102 102 ... 31, #05 (4)
103 103 ... 31, #06 (empty)
104 104 ... 42, #07 (11)
105 105 ... 47, #08 (5)
106 106 ... 47, #09 (empty)
107 107 ... 48, #10 (1)
108 108 ... 51, #11 (3)
109 109 ... 74, #12 (23)
110 110 ... 85, #13 (11)
111 111 ... 86, #14 (1)
112 112 ... 91, #15 (5)
113 113 ... ]
114 114 >>> revlog = _testrevlog(data, snapshot=range(16))
115 115
116 116 >>> list(slicechunk(revlog, list(range(16))))
117 117 [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]]
118 118 >>> list(slicechunk(revlog, [0, 15]))
119 119 [[0], [15]]
120 120 >>> list(slicechunk(revlog, [0, 11, 15]))
121 121 [[0], [11], [15]]
122 122 >>> list(slicechunk(revlog, [0, 11, 13, 15]))
123 123 [[0], [11, 13, 15]]
124 124 >>> list(slicechunk(revlog, [1, 2, 3, 5, 8, 10, 11, 14]))
125 125 [[1, 2], [5, 8, 10, 11], [14]]
126 126
127 127 Slicing with a maximum chunk size
128 128 >>> list(slicechunk(revlog, [0, 11, 13, 15], targetsize=15))
129 129 [[0], [11], [13], [15]]
130 130 >>> list(slicechunk(revlog, [0, 11, 13, 15], targetsize=20))
131 131 [[0], [11], [13, 15]]
132 132
133 133 Slicing involving nullrev
134 134 >>> list(slicechunk(revlog, [-1, 0, 11, 13, 15], targetsize=20))
135 135 [[-1, 0], [11], [13, 15]]
136 136 >>> list(slicechunk(revlog, [-1, 13, 15], targetsize=5))
137 137 [[-1], [13], [15]]
138 138 """
139 139 if targetsize is not None:
140 140 targetsize = max(targetsize, revlog._srmingapsize)
141 141 # targetsize should not be specified when evaluating delta candidates:
142 142 # * targetsize is used to ensure we stay within specification when reading,
143 143 densityslicing = getattr(revlog.index, 'slicechunktodensity', None)
144 144 if densityslicing is None:
145 145 densityslicing = lambda x, y, z: _slicechunktodensity(revlog, x, y, z)
146 146 for chunk in densityslicing(
147 147 revs, revlog._srdensitythreshold, revlog._srmingapsize
148 148 ):
149 149 for subchunk in _slicechunktosize(revlog, chunk, targetsize):
150 150 yield subchunk
151 151
152 152
153 153 def _slicechunktosize(revlog, revs, targetsize=None):
154 154 """slice revs to match the target size
155 155
156 156 This is intended to be used on chunk that density slicing selected by that
157 157 are still too large compared to the read garantee of revlog. This might
158 158 happens when "minimal gap size" interrupted the slicing or when chain are
159 159 built in a way that create large blocks next to each other.
160 160
161 161 >>> data = [
162 162 ... 3, #0 (3)
163 163 ... 5, #1 (2)
164 164 ... 6, #2 (1)
165 165 ... 8, #3 (2)
166 166 ... 8, #4 (empty)
167 167 ... 11, #5 (3)
168 168 ... 12, #6 (1)
169 169 ... 13, #7 (1)
170 170 ... 14, #8 (1)
171 171 ... ]
172 172
173 173 == All snapshots cases ==
174 174 >>> revlog = _testrevlog(data, snapshot=range(9))
175 175
176 176 Cases where chunk is already small enough
177 177 >>> list(_slicechunktosize(revlog, [0], 3))
178 178 [[0]]
179 179 >>> list(_slicechunktosize(revlog, [6, 7], 3))
180 180 [[6, 7]]
181 181 >>> list(_slicechunktosize(revlog, [0], None))
182 182 [[0]]
183 183 >>> list(_slicechunktosize(revlog, [6, 7], None))
184 184 [[6, 7]]
185 185
186 186 cases where we need actual slicing
187 187 >>> list(_slicechunktosize(revlog, [0, 1], 3))
188 188 [[0], [1]]
189 189 >>> list(_slicechunktosize(revlog, [1, 3], 3))
190 190 [[1], [3]]
191 191 >>> list(_slicechunktosize(revlog, [1, 2, 3], 3))
192 192 [[1, 2], [3]]
193 193 >>> list(_slicechunktosize(revlog, [3, 5], 3))
194 194 [[3], [5]]
195 195 >>> list(_slicechunktosize(revlog, [3, 4, 5], 3))
196 196 [[3], [5]]
197 197 >>> list(_slicechunktosize(revlog, [5, 6, 7, 8], 3))
198 198 [[5], [6, 7, 8]]
199 199 >>> list(_slicechunktosize(revlog, [0, 1, 2, 3, 4, 5, 6, 7, 8], 3))
200 200 [[0], [1, 2], [3], [5], [6, 7, 8]]
201 201
202 202 Case with too large individual chunk (must return valid chunk)
203 203 >>> list(_slicechunktosize(revlog, [0, 1], 2))
204 204 [[0], [1]]
205 205 >>> list(_slicechunktosize(revlog, [1, 3], 1))
206 206 [[1], [3]]
207 207 >>> list(_slicechunktosize(revlog, [3, 4, 5], 2))
208 208 [[3], [5]]
209 209
210 210 == No Snapshot cases ==
211 211 >>> revlog = _testrevlog(data)
212 212
213 213 Cases where chunk is already small enough
214 214 >>> list(_slicechunktosize(revlog, [0], 3))
215 215 [[0]]
216 216 >>> list(_slicechunktosize(revlog, [6, 7], 3))
217 217 [[6, 7]]
218 218 >>> list(_slicechunktosize(revlog, [0], None))
219 219 [[0]]
220 220 >>> list(_slicechunktosize(revlog, [6, 7], None))
221 221 [[6, 7]]
222 222
223 223 cases where we need actual slicing
224 224 >>> list(_slicechunktosize(revlog, [0, 1], 3))
225 225 [[0], [1]]
226 226 >>> list(_slicechunktosize(revlog, [1, 3], 3))
227 227 [[1], [3]]
228 228 >>> list(_slicechunktosize(revlog, [1, 2, 3], 3))
229 229 [[1], [2, 3]]
230 230 >>> list(_slicechunktosize(revlog, [3, 5], 3))
231 231 [[3], [5]]
232 232 >>> list(_slicechunktosize(revlog, [3, 4, 5], 3))
233 233 [[3], [4, 5]]
234 234 >>> list(_slicechunktosize(revlog, [5, 6, 7, 8], 3))
235 235 [[5], [6, 7, 8]]
236 236 >>> list(_slicechunktosize(revlog, [0, 1, 2, 3, 4, 5, 6, 7, 8], 3))
237 237 [[0], [1, 2], [3], [5], [6, 7, 8]]
238 238
239 239 Case with too large individual chunk (must return valid chunk)
240 240 >>> list(_slicechunktosize(revlog, [0, 1], 2))
241 241 [[0], [1]]
242 242 >>> list(_slicechunktosize(revlog, [1, 3], 1))
243 243 [[1], [3]]
244 244 >>> list(_slicechunktosize(revlog, [3, 4, 5], 2))
245 245 [[3], [5]]
246 246
247 247 == mixed case ==
248 248 >>> revlog = _testrevlog(data, snapshot=[0, 1, 2])
249 249 >>> list(_slicechunktosize(revlog, list(range(9)), 5))
250 250 [[0, 1], [2], [3, 4, 5], [6, 7, 8]]
251 251 """
252 252 assert targetsize is None or 0 <= targetsize
253 253 startdata = revlog.start(revs[0])
254 254 enddata = revlog.end(revs[-1])
255 255 fullspan = enddata - startdata
256 256 if targetsize is None or fullspan <= targetsize:
257 257 yield revs
258 258 return
259 259
260 260 startrevidx = 0
261 261 endrevidx = 1
262 262 iterrevs = enumerate(revs)
263 263 next(iterrevs) # skip first rev.
264 264 # first step: get snapshots out of the way
265 265 for idx, r in iterrevs:
266 266 span = revlog.end(r) - startdata
267 267 snapshot = revlog.issnapshot(r)
268 268 if span <= targetsize and snapshot:
269 269 endrevidx = idx + 1
270 270 else:
271 271 chunk = _trimchunk(revlog, revs, startrevidx, endrevidx)
272 272 if chunk:
273 273 yield chunk
274 274 startrevidx = idx
275 275 startdata = revlog.start(r)
276 276 endrevidx = idx + 1
277 277 if not snapshot:
278 278 break
279 279
280 280 # for the others, we use binary slicing to quickly converge toward valid
281 281 # chunks (otherwise, we might end up looking for start/end of many
282 282 # revisions). This logic is not looking for the perfect slicing point, it
283 283 # focuses on quickly converging toward valid chunks.
284 284 nbitem = len(revs)
285 285 while (enddata - startdata) > targetsize:
286 286 endrevidx = nbitem
287 287 if nbitem - startrevidx <= 1:
288 288 break # protect against individual chunk larger than limit
289 289 localenddata = revlog.end(revs[endrevidx - 1])
290 290 span = localenddata - startdata
291 291 while span > targetsize:
292 292 if endrevidx - startrevidx <= 1:
293 293 break # protect against individual chunk larger than limit
294 294 endrevidx -= (endrevidx - startrevidx) // 2
295 295 localenddata = revlog.end(revs[endrevidx - 1])
296 296 span = localenddata - startdata
297 297 chunk = _trimchunk(revlog, revs, startrevidx, endrevidx)
298 298 if chunk:
299 299 yield chunk
300 300 startrevidx = endrevidx
301 301 startdata = revlog.start(revs[startrevidx])
302 302
303 303 chunk = _trimchunk(revlog, revs, startrevidx)
304 304 if chunk:
305 305 yield chunk
306 306
307 307
308 308 def _slicechunktodensity(revlog, revs, targetdensity=0.5, mingapsize=0):
309 309 """slice revs to reduce the amount of unrelated data to be read from disk.
310 310
311 311 ``revs`` is sliced into groups that should be read in one time.
312 312 Assume that revs are sorted.
313 313
314 314 The initial chunk is sliced until the overall density (payload/chunks-span
315 315 ratio) is above `targetdensity`. No gap smaller than `mingapsize` is
316 316 skipped.
317 317
318 318 >>> revlog = _testrevlog([
319 319 ... 5, #00 (5)
320 320 ... 10, #01 (5)
321 321 ... 12, #02 (2)
322 322 ... 12, #03 (empty)
323 323 ... 27, #04 (15)
324 324 ... 31, #05 (4)
325 325 ... 31, #06 (empty)
326 326 ... 42, #07 (11)
327 327 ... 47, #08 (5)
328 328 ... 47, #09 (empty)
329 329 ... 48, #10 (1)
330 330 ... 51, #11 (3)
331 331 ... 74, #12 (23)
332 332 ... 85, #13 (11)
333 333 ... 86, #14 (1)
334 334 ... 91, #15 (5)
335 335 ... ])
336 336
337 337 >>> list(_slicechunktodensity(revlog, list(range(16))))
338 338 [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]]
339 339 >>> list(_slicechunktodensity(revlog, [0, 15]))
340 340 [[0], [15]]
341 341 >>> list(_slicechunktodensity(revlog, [0, 11, 15]))
342 342 [[0], [11], [15]]
343 343 >>> list(_slicechunktodensity(revlog, [0, 11, 13, 15]))
344 344 [[0], [11, 13, 15]]
345 345 >>> list(_slicechunktodensity(revlog, [1, 2, 3, 5, 8, 10, 11, 14]))
346 346 [[1, 2], [5, 8, 10, 11], [14]]
347 347 >>> list(_slicechunktodensity(revlog, [1, 2, 3, 5, 8, 10, 11, 14],
348 348 ... mingapsize=20))
349 349 [[1, 2, 3, 5, 8, 10, 11], [14]]
350 350 >>> list(_slicechunktodensity(revlog, [1, 2, 3, 5, 8, 10, 11, 14],
351 351 ... targetdensity=0.95))
352 352 [[1, 2], [5], [8, 10, 11], [14]]
353 353 >>> list(_slicechunktodensity(revlog, [1, 2, 3, 5, 8, 10, 11, 14],
354 354 ... targetdensity=0.95, mingapsize=12))
355 355 [[1, 2], [5, 8, 10, 11], [14]]
356 356 """
357 357 start = revlog.start
358 358 length = revlog.length
359 359
360 360 if len(revs) <= 1:
361 361 yield revs
362 362 return
363 363
364 364 deltachainspan = segmentspan(revlog, revs)
365 365
366 366 if deltachainspan < mingapsize:
367 367 yield revs
368 368 return
369 369
370 370 readdata = deltachainspan
371 371 chainpayload = sum(length(r) for r in revs)
372 372
373 373 if deltachainspan:
374 374 density = chainpayload / float(deltachainspan)
375 375 else:
376 376 density = 1.0
377 377
378 378 if density >= targetdensity:
379 379 yield revs
380 380 return
381 381
382 382 # Store the gaps in a heap to have them sorted by decreasing size
383 383 gaps = []
384 384 prevend = None
385 385 for i, rev in enumerate(revs):
386 386 revstart = start(rev)
387 387 revlen = length(rev)
388 388
389 389 # Skip empty revisions to form larger holes
390 390 if revlen == 0:
391 391 continue
392 392
393 393 if prevend is not None:
394 394 gapsize = revstart - prevend
395 395 # only consider holes that are large enough
396 396 if gapsize > mingapsize:
397 397 gaps.append((gapsize, i))
398 398
399 399 prevend = revstart + revlen
400 400 # sort the gaps to pop them from largest to small
401 401 gaps.sort()
402 402
403 403 # Collect the indices of the largest holes until the density is acceptable
404 404 selected = []
405 405 while gaps and density < targetdensity:
406 406 gapsize, gapidx = gaps.pop()
407 407
408 408 selected.append(gapidx)
409 409
410 410 # the gap sizes are stored as negatives to be sorted decreasingly
411 411 # by the heap
412 412 readdata -= gapsize
413 413 if readdata > 0:
414 414 density = chainpayload / float(readdata)
415 415 else:
416 416 density = 1.0
417 417 selected.sort()
418 418
419 419 # Cut the revs at collected indices
420 420 previdx = 0
421 421 for idx in selected:
422 422
423 423 chunk = _trimchunk(revlog, revs, previdx, idx)
424 424 if chunk:
425 425 yield chunk
426 426
427 427 previdx = idx
428 428
429 429 chunk = _trimchunk(revlog, revs, previdx)
430 430 if chunk:
431 431 yield chunk
432 432
433 433
434 434 def _trimchunk(revlog, revs, startidx, endidx=None):
435 435 """returns revs[startidx:endidx] without empty trailing revs
436 436
437 437 Doctest Setup
438 438 >>> revlog = _testrevlog([
439 439 ... 5, #0
440 440 ... 10, #1
441 441 ... 12, #2
442 442 ... 12, #3 (empty)
443 443 ... 17, #4
444 444 ... 21, #5
445 445 ... 21, #6 (empty)
446 446 ... ])
447 447
448 448 Contiguous cases:
449 449 >>> _trimchunk(revlog, [0, 1, 2, 3, 4, 5, 6], 0)
450 450 [0, 1, 2, 3, 4, 5]
451 451 >>> _trimchunk(revlog, [0, 1, 2, 3, 4, 5, 6], 0, 5)
452 452 [0, 1, 2, 3, 4]
453 453 >>> _trimchunk(revlog, [0, 1, 2, 3, 4, 5, 6], 0, 4)
454 454 [0, 1, 2]
455 455 >>> _trimchunk(revlog, [0, 1, 2, 3, 4, 5, 6], 2, 4)
456 456 [2]
457 457 >>> _trimchunk(revlog, [0, 1, 2, 3, 4, 5, 6], 3)
458 458 [3, 4, 5]
459 459 >>> _trimchunk(revlog, [0, 1, 2, 3, 4, 5, 6], 3, 5)
460 460 [3, 4]
461 461
462 462 Discontiguous cases:
463 463 >>> _trimchunk(revlog, [1, 3, 5, 6], 0)
464 464 [1, 3, 5]
465 465 >>> _trimchunk(revlog, [1, 3, 5, 6], 0, 2)
466 466 [1]
467 467 >>> _trimchunk(revlog, [1, 3, 5, 6], 1, 3)
468 468 [3, 5]
469 469 >>> _trimchunk(revlog, [1, 3, 5, 6], 1)
470 470 [3, 5]
471 471 """
472 472 length = revlog.length
473 473
474 474 if endidx is None:
475 475 endidx = len(revs)
476 476
477 477 # If we have a non-emtpy delta candidate, there are nothing to trim
478 478 if revs[endidx - 1] < len(revlog):
479 479 # Trim empty revs at the end, except the very first revision of a chain
480 480 while (
481 481 endidx > 1 and endidx > startidx and length(revs[endidx - 1]) == 0
482 482 ):
483 483 endidx -= 1
484 484
485 485 return revs[startidx:endidx]
486 486
487 487
488 488 def segmentspan(revlog, revs):
489 489 """Get the byte span of a segment of revisions
490 490
491 491 revs is a sorted array of revision numbers
492 492
493 493 >>> revlog = _testrevlog([
494 494 ... 5, #0
495 495 ... 10, #1
496 496 ... 12, #2
497 497 ... 12, #3 (empty)
498 498 ... 17, #4
499 499 ... ])
500 500
501 501 >>> segmentspan(revlog, [0, 1, 2, 3, 4])
502 502 17
503 503 >>> segmentspan(revlog, [0, 4])
504 504 17
505 505 >>> segmentspan(revlog, [3, 4])
506 506 5
507 507 >>> segmentspan(revlog, [1, 2, 3,])
508 508 7
509 509 >>> segmentspan(revlog, [1, 3])
510 510 7
511 511 """
512 512 if not revs:
513 513 return 0
514 514 end = revlog.end(revs[-1])
515 515 return end - revlog.start(revs[0])
516 516
517 517
518 518 def _textfromdelta(fh, revlog, baserev, delta, p1, p2, flags, expectednode):
519 519 """build full text from a (base, delta) pair and other metadata"""
520 520 # special case deltas which replace entire base; no need to decode
521 521 # base revision. this neatly avoids censored bases, which throw when
522 522 # they're decoded.
523 523 hlen = struct.calcsize(b">lll")
524 524 if delta[:hlen] == mdiff.replacediffheader(
525 525 revlog.rawsize(baserev), len(delta) - hlen
526 526 ):
527 527 fulltext = delta[hlen:]
528 528 else:
529 529 # deltabase is rawtext before changed by flag processors, which is
530 530 # equivalent to non-raw text
531 531 basetext = revlog.revision(baserev, _df=fh)
532 532 fulltext = mdiff.patch(basetext, delta)
533 533
534 534 try:
535 535 validatehash = flagutil.processflagsraw(revlog, fulltext, flags)
536 536 if validatehash:
537 537 revlog.checkhash(fulltext, expectednode, p1=p1, p2=p2)
538 538 if flags & REVIDX_ISCENSORED:
539 539 raise error.StorageError(
540 540 _(b'node %s is not censored') % expectednode
541 541 )
542 542 except error.CensoredNodeError:
543 543 # must pass the censored index flag to add censored revisions
544 544 if not flags & REVIDX_ISCENSORED:
545 545 raise
546 546 return fulltext
547 547
548 548
549 549 @attr.s(slots=True, frozen=True)
550 550 class _deltainfo:
551 551 distance = attr.ib()
552 552 deltalen = attr.ib()
553 553 data = attr.ib()
554 554 base = attr.ib()
555 555 chainbase = attr.ib()
556 556 chainlen = attr.ib()
557 557 compresseddeltalen = attr.ib()
558 558 snapshotdepth = attr.ib()
559 559
560 560
561 561 def drop_u_compression(delta):
562 562 """turn into a "u" (no-compression) into no-compression without header
563 563
564 564 This is useful for revlog format that has better compression method.
565 565 """
566 566 assert delta.data[0] == b'u', delta.data[0]
567 567 return _deltainfo(
568 568 delta.distance,
569 569 delta.deltalen - 1,
570 570 (b'', delta.data[1]),
571 571 delta.base,
572 572 delta.chainbase,
573 573 delta.chainlen,
574 574 delta.compresseddeltalen,
575 575 delta.snapshotdepth,
576 576 )
577 577
578 578
579 579 def isgooddeltainfo(revlog, deltainfo, revinfo):
580 580 """Returns True if the given delta is good. Good means that it is within
581 581 the disk span, disk size, and chain length bounds that we know to be
582 582 performant."""
583 583 if deltainfo is None:
584 584 return False
585 585
586 586 # - 'deltainfo.distance' is the distance from the base revision --
587 587 # bounding it limits the amount of I/O we need to do.
588 588 # - 'deltainfo.compresseddeltalen' is the sum of the total size of
589 589 # deltas we need to apply -- bounding it limits the amount of CPU
590 590 # we consume.
591 591
592 592 textlen = revinfo.textlen
593 593 defaultmax = textlen * 4
594 594 maxdist = revlog._maxdeltachainspan
595 595 if not maxdist:
596 596 maxdist = deltainfo.distance # ensure the conditional pass
597 597 maxdist = max(maxdist, defaultmax)
598 598
599 599 # Bad delta from read span:
600 600 #
601 601 # If the span of data read is larger than the maximum allowed.
602 602 #
603 603 # In the sparse-revlog case, we rely on the associated "sparse reading"
604 604 # to avoid issue related to the span of data. In theory, it would be
605 605 # possible to build pathological revlog where delta pattern would lead
606 606 # to too many reads. However, they do not happen in practice at all. So
607 607 # we skip the span check entirely.
608 608 if not revlog._sparserevlog and maxdist < deltainfo.distance:
609 609 return False
610 610
611 611 # Bad delta from new delta size:
612 612 #
613 613 # If the delta size is larger than the target text, storing the
614 614 # delta will be inefficient.
615 615 if textlen < deltainfo.deltalen:
616 616 return False
617 617
618 618 # Bad delta from cumulated payload size:
619 619 #
620 620 # If the sum of delta get larger than K * target text length.
621 621 if textlen * LIMIT_DELTA2TEXT < deltainfo.compresseddeltalen:
622 622 return False
623 623
624 624 # Bad delta from chain length:
625 625 #
626 626 # If the number of delta in the chain gets too high.
627 627 if revlog._maxchainlen and revlog._maxchainlen < deltainfo.chainlen:
628 628 return False
629 629
630 630 # bad delta from intermediate snapshot size limit
631 631 #
632 632 # If an intermediate snapshot size is higher than the limit. The
633 633 # limit exist to prevent endless chain of intermediate delta to be
634 634 # created.
635 635 if (
636 636 deltainfo.snapshotdepth is not None
637 637 and (textlen >> deltainfo.snapshotdepth) < deltainfo.deltalen
638 638 ):
639 639 return False
640 640
641 641 # bad delta if new intermediate snapshot is larger than the previous
642 642 # snapshot
643 643 if (
644 644 deltainfo.snapshotdepth
645 645 and revlog.length(deltainfo.base) < deltainfo.deltalen
646 646 ):
647 647 return False
648 648
649 649 return True
650 650
651 651
652 652 # If a revision's full text is that much bigger than a base candidate full
653 653 # text's, it is very unlikely that it will produce a valid delta. We no longer
654 654 # consider these candidates.
655 655 LIMIT_BASE2TEXT = 500
656 656
657 657
658 658 def _candidategroups(revlog, textlen, p1, p2, cachedelta):
659 659 """Provides group of revision to be tested as delta base
660 660
661 661 This top level function focus on emitting groups with unique and worthwhile
662 662 content. See _raw_candidate_groups for details about the group order.
663 663 """
664 664 # should we try to build a delta?
665 665 if not (len(revlog) and revlog._storedeltachains):
666 666 yield None
667 667 return
668 668
669 669 deltalength = revlog.length
670 670 deltaparent = revlog.deltaparent
671 671 sparse = revlog._sparserevlog
672 672 good = None
673 673
674 674 deltas_limit = textlen * LIMIT_DELTA2TEXT
675 675
676 676 tested = {nullrev}
677 677 candidates = _refinedgroups(revlog, p1, p2, cachedelta)
678 678 while True:
679 679 temptative = candidates.send(good)
680 680 if temptative is None:
681 681 break
682 682 group = []
683 683 for rev in temptative:
684 684 # skip over empty delta (no need to include them in a chain)
685 685 while revlog._generaldelta and not (
686 686 rev == nullrev or rev in tested or deltalength(rev)
687 687 ):
688 688 tested.add(rev)
689 689 rev = deltaparent(rev)
690 690 # no need to try a delta against nullrev, this will be done as a
691 691 # last resort.
692 692 if rev == nullrev:
693 693 continue
694 694 # filter out revision we tested already
695 695 if rev in tested:
696 696 continue
697 697 tested.add(rev)
698 698 # filter out delta base that will never produce good delta
699 699 if deltas_limit < revlog.length(rev):
700 700 continue
701 701 if sparse and revlog.rawsize(rev) < (textlen // LIMIT_BASE2TEXT):
702 702 continue
703 703 # no delta for rawtext-changing revs (see "candelta" for why)
704 704 if revlog.flags(rev) & REVIDX_RAWTEXT_CHANGING_FLAGS:
705 705 continue
706 706 # If we reach here, we are about to build and test a delta.
707 707 # The delta building process will compute the chaininfo in all
708 708 # case, since that computation is cached, it is fine to access it
709 709 # here too.
710 710 chainlen, chainsize = revlog._chaininfo(rev)
711 711 # if chain will be too long, skip base
712 712 if revlog._maxchainlen and chainlen >= revlog._maxchainlen:
713 713 continue
714 714 # if chain already have too much data, skip base
715 715 if deltas_limit < chainsize:
716 716 continue
717 717 if sparse and revlog.upperboundcomp is not None:
718 718 maxcomp = revlog.upperboundcomp
719 719 basenotsnap = (p1, p2, nullrev)
720 720 if rev not in basenotsnap and revlog.issnapshot(rev):
721 721 snapshotdepth = revlog.snapshotdepth(rev)
722 722 # If text is significantly larger than the base, we can
723 723 # expect the resulting delta to be proportional to the size
724 724 # difference
725 725 revsize = revlog.rawsize(rev)
726 726 rawsizedistance = max(textlen - revsize, 0)
727 727 # use an estimate of the compression upper bound.
728 728 lowestrealisticdeltalen = rawsizedistance // maxcomp
729 729
730 730 # check the absolute constraint on the delta size
731 731 snapshotlimit = textlen >> snapshotdepth
732 732 if snapshotlimit < lowestrealisticdeltalen:
733 733 # delta lower bound is larger than accepted upper bound
734 734 continue
735 735
736 736 # check the relative constraint on the delta size
737 737 revlength = revlog.length(rev)
738 738 if revlength < lowestrealisticdeltalen:
739 739 # delta probable lower bound is larger than target base
740 740 continue
741 741
742 742 group.append(rev)
743 743 if group:
744 744 # XXX: in the sparse revlog case, group can become large,
745 745 # impacting performances. Some bounding or slicing mecanism
746 746 # would help to reduce this impact.
747 747 good = yield tuple(group)
748 748 yield None
749 749
750 750
751 751 def _findsnapshots(revlog, cache, start_rev):
752 752 """find snapshot from start_rev to tip"""
753 753 if util.safehasattr(revlog.index, b'findsnapshots'):
754 754 revlog.index.findsnapshots(cache, start_rev)
755 755 else:
756 756 deltaparent = revlog.deltaparent
757 757 issnapshot = revlog.issnapshot
758 758 for rev in revlog.revs(start_rev):
759 759 if issnapshot(rev):
760 760 cache[deltaparent(rev)].append(rev)
761 761
762 762
763 763 def _refinedgroups(revlog, p1, p2, cachedelta):
764 764 good = None
765 765 # First we try to reuse a the delta contained in the bundle.
766 766 # (or from the source revlog)
767 767 #
768 768 # This logic only applies to general delta repositories and can be disabled
769 769 # through configuration. Disabling reuse source delta is useful when
770 770 # we want to make sure we recomputed "optimal" deltas.
771 771 if cachedelta and revlog._generaldelta and revlog._lazydeltabase:
772 772 # Assume what we received from the server is a good choice
773 773 # build delta will reuse the cache
774 774 good = yield (cachedelta[0],)
775 775 if good is not None:
776 776 yield None
777 777 return
778 778 snapshots = collections.defaultdict(list)
779 779 for candidates in _rawgroups(revlog, p1, p2, cachedelta, snapshots):
780 780 good = yield candidates
781 781 if good is not None:
782 782 break
783 783
784 784 # If sparse revlog is enabled, we can try to refine the available deltas
785 785 if not revlog._sparserevlog:
786 786 yield None
787 787 return
788 788
789 789 # if we have a refinable value, try to refine it
790 790 if good is not None and good not in (p1, p2) and revlog.issnapshot(good):
791 791 # refine snapshot down
792 792 previous = None
793 793 while previous != good:
794 794 previous = good
795 795 base = revlog.deltaparent(good)
796 796 if base == nullrev:
797 797 break
798 798 good = yield (base,)
799 799 # refine snapshot up
800 800 if not snapshots:
801 801 _findsnapshots(revlog, snapshots, good + 1)
802 802 previous = None
803 803 while good != previous:
804 804 previous = good
805 805 children = tuple(sorted(c for c in snapshots[good]))
806 806 good = yield children
807 807
808 808 # we have found nothing
809 809 yield None
810 810
811 811
812 812 def _rawgroups(revlog, p1, p2, cachedelta, snapshots=None):
813 813 """Provides group of revision to be tested as delta base
814 814
815 815 This lower level function focus on emitting delta theorically interresting
816 816 without looking it any practical details.
817 817
818 818 The group order aims at providing fast or small candidates first.
819 819 """
820 820 gdelta = revlog._generaldelta
821 821 # gate sparse behind general-delta because of issue6056
822 822 sparse = gdelta and revlog._sparserevlog
823 823 curr = len(revlog)
824 824 prev = curr - 1
825 825 deltachain = lambda rev: revlog._deltachain(rev)[0]
826 826
827 827 if gdelta:
828 828 # exclude already lazy tested base if any
829 829 parents = [p for p in (p1, p2) if p != nullrev]
830 830
831 831 if not revlog._deltabothparents and len(parents) == 2:
832 832 parents.sort()
833 833 # To minimize the chance of having to build a fulltext,
834 834 # pick first whichever parent is closest to us (max rev)
835 835 yield (parents[1],)
836 836 # then the other one (min rev) if the first did not fit
837 837 yield (parents[0],)
838 838 elif len(parents) > 0:
839 839 # Test all parents (1 or 2), and keep the best candidate
840 840 yield parents
841 841
842 842 if sparse and parents:
843 843 if snapshots is None:
844 844 # map: base-rev: snapshot-rev
845 845 snapshots = collections.defaultdict(list)
846 846 # See if we can use an existing snapshot in the parent chains to use as
847 847 # a base for a new intermediate-snapshot
848 848 #
849 849 # search for snapshot in parents delta chain
850 850 # map: snapshot-level: snapshot-rev
851 851 parents_snaps = collections.defaultdict(set)
852 852 candidate_chains = [deltachain(p) for p in parents]
853 853 for chain in candidate_chains:
854 854 for idx, s in enumerate(chain):
855 855 if not revlog.issnapshot(s):
856 856 break
857 857 parents_snaps[idx].add(s)
858 858 snapfloor = min(parents_snaps[0]) + 1
859 859 _findsnapshots(revlog, snapshots, snapfloor)
860 860 # search for the highest "unrelated" revision
861 861 #
862 862 # Adding snapshots used by "unrelated" revision increase the odd we
863 863 # reuse an independant, yet better snapshot chain.
864 864 #
865 865 # XXX instead of building a set of revisions, we could lazily enumerate
866 866 # over the chains. That would be more efficient, however we stick to
867 867 # simple code for now.
868 868 all_revs = set()
869 869 for chain in candidate_chains:
870 870 all_revs.update(chain)
871 871 other = None
872 872 for r in revlog.revs(prev, snapfloor):
873 873 if r not in all_revs:
874 874 other = r
875 875 break
876 876 if other is not None:
877 877 # To avoid unfair competition, we won't use unrelated intermediate
878 878 # snapshot that are deeper than the ones from the parent delta
879 879 # chain.
880 880 max_depth = max(parents_snaps.keys())
881 881 chain = deltachain(other)
882 882 for idx, s in enumerate(chain):
883 883 if s < snapfloor:
884 884 continue
885 885 if max_depth < idx:
886 886 break
887 887 if not revlog.issnapshot(s):
888 888 break
889 889 parents_snaps[idx].add(s)
890 890 # Test them as possible intermediate snapshot base
891 891 # We test them from highest to lowest level. High level one are more
892 892 # likely to result in small delta
893 893 floor = None
894 894 for idx, snaps in sorted(parents_snaps.items(), reverse=True):
895 895 siblings = set()
896 896 for s in snaps:
897 897 siblings.update(snapshots[s])
898 898 # Before considering making a new intermediate snapshot, we check
899 899 # if an existing snapshot, children of base we consider, would be
900 900 # suitable.
901 901 #
902 902 # It give a change to reuse a delta chain "unrelated" to the
903 903 # current revision instead of starting our own. Without such
904 904 # re-use, topological branches would keep reopening new chains.
905 905 # Creating more and more snapshot as the repository grow.
906 906
907 907 if floor is not None:
908 908 # We only do this for siblings created after the one in our
909 909 # parent's delta chain. Those created before has less chances
910 910 # to be valid base since our ancestors had to create a new
911 911 # snapshot.
912 912 siblings = [r for r in siblings if floor < r]
913 913 yield tuple(sorted(siblings))
914 914 # then test the base from our parent's delta chain.
915 915 yield tuple(sorted(snaps))
916 916 floor = min(snaps)
917 917 # No suitable base found in the parent chain, search if any full
918 918 # snapshots emitted since parent's base would be a suitable base for an
919 919 # intermediate snapshot.
920 920 #
921 921 # It give a chance to reuse a delta chain unrelated to the current
922 922 # revisions instead of starting our own. Without such re-use,
923 923 # topological branches would keep reopening new full chains. Creating
924 924 # more and more snapshot as the repository grow.
925 925 yield tuple(snapshots[nullrev])
926 926
927 927 if not sparse:
928 928 # other approach failed try against prev to hopefully save us a
929 929 # fulltext.
930 930 yield (prev,)
931 931
932 932
933 933 class deltacomputer:
934 def __init__(self, revlog, write_debug=None):
934 def __init__(self, revlog, write_debug=None, debug_search=False):
935 935 self.revlog = revlog
936 936 self._write_debug = write_debug
937 self._debug_search = debug_search
937 938
938 939 def buildtext(self, revinfo, fh):
939 940 """Builds a fulltext version of a revision
940 941
941 942 revinfo: revisioninfo instance that contains all needed info
942 943 fh: file handle to either the .i or the .d revlog file,
943 944 depending on whether it is inlined or not
944 945 """
945 946 btext = revinfo.btext
946 947 if btext[0] is not None:
947 948 return btext[0]
948 949
949 950 revlog = self.revlog
950 951 cachedelta = revinfo.cachedelta
951 952 baserev = cachedelta[0]
952 953 delta = cachedelta[1]
953 954
954 955 fulltext = btext[0] = _textfromdelta(
955 956 fh,
956 957 revlog,
957 958 baserev,
958 959 delta,
959 960 revinfo.p1,
960 961 revinfo.p2,
961 962 revinfo.flags,
962 963 revinfo.node,
963 964 )
964 965 return fulltext
965 966
966 967 def _builddeltadiff(self, base, revinfo, fh):
967 968 revlog = self.revlog
968 969 t = self.buildtext(revinfo, fh)
969 970 if revlog.iscensored(base):
970 971 # deltas based on a censored revision must replace the
971 972 # full content in one patch, so delta works everywhere
972 973 header = mdiff.replacediffheader(revlog.rawsize(base), len(t))
973 974 delta = header + t
974 975 else:
975 976 ptext = revlog.rawdata(base, _df=fh)
976 977 delta = mdiff.textdiff(ptext, t)
977 978
978 979 return delta
979 980
980 981 def _builddeltainfo(self, revinfo, base, fh):
981 982 # can we use the cached delta?
982 983 revlog = self.revlog
984 debug_search = self._write_debug is not None and self._debug_search
983 985 chainbase = revlog.chainbase(base)
984 986 if revlog._generaldelta:
985 987 deltabase = base
986 988 else:
987 989 deltabase = chainbase
988 990 snapshotdepth = None
989 991 if revlog._sparserevlog and deltabase == nullrev:
990 992 snapshotdepth = 0
991 993 elif revlog._sparserevlog and revlog.issnapshot(deltabase):
992 994 # A delta chain should always be one full snapshot,
993 995 # zero or more semi-snapshots, and zero or more deltas
994 996 p1, p2 = revlog.rev(revinfo.p1), revlog.rev(revinfo.p2)
995 997 if deltabase not in (p1, p2) and revlog.issnapshot(deltabase):
996 998 snapshotdepth = len(revlog._deltachain(deltabase)[0])
997 999 delta = None
998 1000 if revinfo.cachedelta:
999 1001 cachebase, cachediff = revinfo.cachedelta
1000 1002 # check if the diff still apply
1001 1003 currentbase = cachebase
1002 1004 while (
1003 1005 currentbase != nullrev
1004 1006 and currentbase != base
1005 1007 and self.revlog.length(currentbase) == 0
1006 1008 ):
1007 1009 currentbase = self.revlog.deltaparent(currentbase)
1008 1010 if self.revlog._lazydelta and currentbase == base:
1009 1011 delta = revinfo.cachedelta[1]
1010 1012 if delta is None:
1011 1013 delta = self._builddeltadiff(base, revinfo, fh)
1014 if debug_search:
1015 msg = b"DBG-DELTAS-SEARCH: uncompressed-delta-size=%d\n"
1016 msg %= len(delta)
1017 self._write_debug(msg)
1012 1018 # snapshotdept need to be neither None nor 0 level snapshot
1013 1019 if revlog.upperboundcomp is not None and snapshotdepth:
1014 1020 lowestrealisticdeltalen = len(delta) // revlog.upperboundcomp
1015 1021 snapshotlimit = revinfo.textlen >> snapshotdepth
1022 if debug_search:
1023 msg = b"DBG-DELTAS-SEARCH: projected-lower-size=%d\n"
1024 msg %= lowestrealisticdeltalen
1025 self._write_debug(msg)
1016 1026 if snapshotlimit < lowestrealisticdeltalen:
1027 if debug_search:
1028 msg = b"DBG-DELTAS-SEARCH: DISCARDED (snapshot limit)\n"
1029 self._write_debug(msg)
1017 1030 return None
1018 1031 if revlog.length(base) < lowestrealisticdeltalen:
1032 if debug_search:
1033 msg = b"DBG-DELTAS-SEARCH: DISCARDED (prev size)\n"
1034 self._write_debug(msg)
1019 1035 return None
1020 1036 header, data = revlog.compress(delta)
1021 1037 deltalen = len(header) + len(data)
1022 1038 offset = revlog.end(len(revlog) - 1)
1023 1039 dist = deltalen + offset - revlog.start(chainbase)
1024 1040 chainlen, compresseddeltalen = revlog._chaininfo(base)
1025 1041 chainlen += 1
1026 1042 compresseddeltalen += deltalen
1027 1043
1028 1044 return _deltainfo(
1029 1045 dist,
1030 1046 deltalen,
1031 1047 (header, data),
1032 1048 deltabase,
1033 1049 chainbase,
1034 1050 chainlen,
1035 1051 compresseddeltalen,
1036 1052 snapshotdepth,
1037 1053 )
1038 1054
1039 1055 def _fullsnapshotinfo(self, fh, revinfo, curr):
1040 1056 rawtext = self.buildtext(revinfo, fh)
1041 1057 data = self.revlog.compress(rawtext)
1042 1058 compresseddeltalen = deltalen = dist = len(data[1]) + len(data[0])
1043 1059 deltabase = chainbase = curr
1044 1060 snapshotdepth = 0
1045 1061 chainlen = 1
1046 1062
1047 1063 return _deltainfo(
1048 1064 dist,
1049 1065 deltalen,
1050 1066 data,
1051 1067 deltabase,
1052 1068 chainbase,
1053 1069 chainlen,
1054 1070 compresseddeltalen,
1055 1071 snapshotdepth,
1056 1072 )
1057 1073
1058 1074 def finddeltainfo(self, revinfo, fh, excluded_bases=None, target_rev=None):
1059 1075 """Find an acceptable delta against a candidate revision
1060 1076
1061 1077 revinfo: information about the revision (instance of _revisioninfo)
1062 1078 fh: file handle to either the .i or the .d revlog file,
1063 1079 depending on whether it is inlined or not
1064 1080
1065 1081 Returns the first acceptable candidate revision, as ordered by
1066 1082 _candidategroups
1067 1083
1068 1084 If no suitable deltabase is found, we return delta info for a full
1069 1085 snapshot.
1070 1086
1071 1087 `excluded_bases` is an optional set of revision that cannot be used as
1072 1088 a delta base. Use this to recompute delta suitable in censor or strip
1073 1089 context.
1074 1090 """
1075 1091 if target_rev is None:
1076 1092 target_rev = len(self.revlog)
1077 1093
1078 1094 if not revinfo.textlen:
1079 1095 return self._fullsnapshotinfo(fh, revinfo, target_rev)
1080 1096
1081 1097 if excluded_bases is None:
1082 1098 excluded_bases = set()
1083 1099
1084 1100 # no delta for flag processor revision (see "candelta" for why)
1085 1101 # not calling candelta since only one revision needs test, also to
1086 1102 # avoid overhead fetching flags again.
1087 1103 if revinfo.flags & REVIDX_RAWTEXT_CHANGING_FLAGS:
1088 1104 return self._fullsnapshotinfo(fh, revinfo, target_rev)
1089 1105
1090 1106 if self._write_debug is not None:
1091 1107 start = util.timer()
1092 1108
1109 debug_search = self._write_debug is not None and self._debug_search
1110
1093 1111 # count the number of different delta we tried (for debug purpose)
1094 1112 dbg_try_count = 0
1095 1113 # count the number of "search round" we did. (for debug purpose)
1096 1114 dbg_try_rounds = 0
1097 1115 dbg_type = b'unknown'
1098 1116
1099 1117 cachedelta = revinfo.cachedelta
1100 1118 p1 = revinfo.p1
1101 1119 p2 = revinfo.p2
1102 1120 revlog = self.revlog
1103 1121
1104 1122 deltainfo = None
1105 1123 p1r, p2r = revlog.rev(p1), revlog.rev(p2)
1106 1124
1107 1125 if self._write_debug is not None:
1108 1126 if p1r != nullrev:
1109 1127 p1_chain_len = revlog._chaininfo(p1r)[0]
1110 1128 else:
1111 1129 p1_chain_len = -1
1112 1130 if p2r != nullrev:
1113 1131 p2_chain_len = revlog._chaininfo(p2r)[0]
1114 1132 else:
1115 1133 p2_chain_len = -1
1134 if debug_search:
1135 msg = b"DBG-DELTAS-SEARCH: SEARCH rev=%d\n"
1136 msg %= target_rev
1137 self._write_debug(msg)
1116 1138
1117 1139 groups = _candidategroups(
1118 1140 self.revlog, revinfo.textlen, p1r, p2r, cachedelta
1119 1141 )
1120 1142 candidaterevs = next(groups)
1121 1143 while candidaterevs is not None:
1122 1144 dbg_try_rounds += 1
1145 if debug_search:
1146 prev = None
1147 if deltainfo is not None:
1148 prev = deltainfo.base
1149
1150 if p1 in candidaterevs or p2 in candidaterevs:
1151 round_type = b"parents"
1152 elif prev is not None and all(c < prev for c in candidaterevs):
1153 round_type = b"refine-down"
1154 elif prev is not None and all(c > prev for c in candidaterevs):
1155 round_type = b"refine-up"
1156 else:
1157 round_type = b"search-down"
1158 msg = b"DBG-DELTAS-SEARCH: ROUND #%d - %d candidates - %s\n"
1159 msg %= (dbg_try_rounds, len(candidaterevs), round_type)
1160 self._write_debug(msg)
1123 1161 nominateddeltas = []
1124 1162 if deltainfo is not None:
1163 if debug_search:
1164 msg = (
1165 b"DBG-DELTAS-SEARCH: CONTENDER: rev=%d - length=%d\n"
1166 )
1167 msg %= (deltainfo.base, deltainfo.deltalen)
1168 self._write_debug(msg)
1125 1169 # if we already found a good delta,
1126 1170 # challenge it against refined candidates
1127 1171 nominateddeltas.append(deltainfo)
1128 1172 for candidaterev in candidaterevs:
1173 if debug_search:
1174 msg = b"DBG-DELTAS-SEARCH: CANDIDATE: rev=%d\n"
1175 msg %= candidaterev
1176 self._write_debug(msg)
1177 candidate_type = None
1178 if candidaterev == p1:
1179 candidate_type = b"p1"
1180 elif candidaterev == p2:
1181 candidate_type = b"p2"
1182 elif self.revlog.issnapshot(candidaterev):
1183 candidate_type = b"snapshot-%d"
1184 candidate_type %= self.revlog.snapshotdepth(
1185 candidaterev
1186 )
1187
1188 if candidate_type is not None:
1189 msg = b"DBG-DELTAS-SEARCH: type=%s\n"
1190 msg %= candidate_type
1191 self._write_debug(msg)
1192 msg = b"DBG-DELTAS-SEARCH: size=%d\n"
1193 msg %= self.revlog.length(candidaterev)
1194 self._write_debug(msg)
1195 msg = b"DBG-DELTAS-SEARCH: base=%d\n"
1196 msg %= self.revlog.deltaparent(candidaterev)
1197 self._write_debug(msg)
1129 1198 if candidaterev in excluded_bases:
1199 if debug_search:
1200 msg = b"DBG-DELTAS-SEARCH: EXCLUDED\n"
1201 self._write_debug(msg)
1130 1202 continue
1131 1203 if candidaterev >= target_rev:
1204 if debug_search:
1205 msg = b"DBG-DELTAS-SEARCH: TOO-HIGH\n"
1206 self._write_debug(msg)
1132 1207 continue
1133 1208 dbg_try_count += 1
1209
1210 if debug_search:
1211 delta_start = util.timer()
1134 1212 candidatedelta = self._builddeltainfo(revinfo, candidaterev, fh)
1213 if debug_search:
1214 delta_end = util.timer()
1215 msg = b"DBG-DELTAS-SEARCH: delta-search-time=%f\n"
1216 msg %= delta_end - delta_start
1217 self._write_debug(msg)
1135 1218 if candidatedelta is not None:
1136 1219 if isgooddeltainfo(self.revlog, candidatedelta, revinfo):
1220 if debug_search:
1221 msg = b"DBG-DELTAS-SEARCH: DELTA: length=%d (GOOD)\n"
1222 msg %= candidatedelta.deltalen
1223 self._write_debug(msg)
1137 1224 nominateddeltas.append(candidatedelta)
1225 elif debug_search:
1226 msg = b"DBG-DELTAS-SEARCH: DELTA: length=%d (BAD)\n"
1227 msg %= candidatedelta.deltalen
1228 self._write_debug(msg)
1229 elif debug_search:
1230 msg = b"DBG-DELTAS-SEARCH: NO-DELTA\n"
1231 self._write_debug(msg)
1138 1232 if nominateddeltas:
1139 1233 deltainfo = min(nominateddeltas, key=lambda x: x.deltalen)
1140 1234 if deltainfo is not None:
1141 1235 candidaterevs = groups.send(deltainfo.base)
1142 1236 else:
1143 1237 candidaterevs = next(groups)
1144 1238
1145 1239 if deltainfo is None:
1146 1240 dbg_type = b"full"
1147 1241 deltainfo = self._fullsnapshotinfo(fh, revinfo, target_rev)
1148 elif deltainfo.snapshotdepth:
1242 elif deltainfo.snapshotdepth: # pytype: disable=attribute-error
1149 1243 dbg_type = b"snapshot"
1150 1244 else:
1151 1245 dbg_type = b"delta"
1152 1246
1153 1247 if self._write_debug is not None:
1154 1248 end = util.timer()
1155 1249 dbg = {
1156 1250 'duration': end - start,
1157 1251 'revision': target_rev,
1158 1252 'search_round_count': dbg_try_rounds,
1159 1253 'delta_try_count': dbg_try_count,
1160 1254 'type': dbg_type,
1161 1255 'p1-chain-len': p1_chain_len,
1162 1256 'p2-chain-len': p2_chain_len,
1163 1257 }
1164 if deltainfo.snapshotdepth is not None:
1165 dbg['snapshot-depth'] = deltainfo.snapshotdepth
1258 if (
1259 deltainfo.snapshotdepth # pytype: disable=attribute-error
1260 is not None
1261 ):
1262 dbg[
1263 'snapshot-depth'
1264 ] = deltainfo.snapshotdepth # pytype: disable=attribute-error
1166 1265 else:
1167 1266 dbg['snapshot-depth'] = 0
1168 1267 target_revlog = b"UNKNOWN"
1169 1268 target_type = self.revlog.target[0]
1170 1269 target_key = self.revlog.target[1]
1171 1270 if target_type == KIND_CHANGELOG:
1172 1271 target_revlog = b'CHANGELOG:'
1173 1272 elif target_type == KIND_MANIFESTLOG:
1174 1273 target_revlog = b'MANIFESTLOG:'
1175 1274 if target_key:
1176 1275 target_revlog += b'%s:' % target_key
1177 1276 elif target_type == KIND_FILELOG:
1178 1277 target_revlog = b'FILELOG:'
1179 1278 if target_key:
1180 1279 target_revlog += b'%s:' % target_key
1181 1280 dbg['target-revlog'] = target_revlog
1182 1281
1183 1282 msg = (
1184 1283 b"DBG-DELTAS:"
1185 1284 b" %-12s"
1186 1285 b" rev=%d:"
1187 1286 b" search-rounds=%d"
1188 1287 b" try-count=%d"
1189 1288 b" - delta-type=%-6s"
1190 1289 b" snap-depth=%d"
1191 1290 b" - p1-chain-length=%d"
1192 1291 b" p2-chain-length=%d"
1193 1292 b" - duration=%f"
1194 1293 b"\n"
1195 1294 )
1196 1295 msg %= (
1197 1296 dbg["target-revlog"],
1198 1297 dbg["revision"],
1199 1298 dbg["search_round_count"],
1200 1299 dbg["delta_try_count"],
1201 1300 dbg["type"],
1202 1301 dbg["snapshot-depth"],
1203 1302 dbg["p1-chain-len"],
1204 1303 dbg["p2-chain-len"],
1205 1304 dbg["duration"],
1206 1305 )
1207 1306 self._write_debug(msg)
1208 1307 return deltainfo
1209 1308
1210 1309
1211 1310 def delta_compression(default_compression_header, deltainfo):
1212 1311 """return (COMPRESSION_MODE, deltainfo)
1213 1312
1214 1313 used by revlog v2+ format to dispatch between PLAIN and DEFAULT
1215 1314 compression.
1216 1315 """
1217 1316 h, d = deltainfo.data
1218 1317 compression_mode = COMP_MODE_INLINE
1219 1318 if not h and not d:
1220 1319 # not data to store at all... declare them uncompressed
1221 1320 compression_mode = COMP_MODE_PLAIN
1222 1321 elif not h:
1223 1322 t = d[0:1]
1224 1323 if t == b'\0':
1225 1324 compression_mode = COMP_MODE_PLAIN
1226 1325 elif t == default_compression_header:
1227 1326 compression_mode = COMP_MODE_DEFAULT
1228 1327 elif h == b'u':
1229 1328 # we have a more efficient way to declare uncompressed
1230 1329 h = b''
1231 1330 compression_mode = COMP_MODE_PLAIN
1232 1331 deltainfo = drop_u_compression(deltainfo)
1233 1332 return compression_mode, deltainfo
@@ -1,447 +1,449 b''
1 1 Show all commands except debug commands
2 2 $ hg debugcomplete
3 3 abort
4 4 add
5 5 addremove
6 6 annotate
7 7 archive
8 8 backout
9 9 bisect
10 10 bookmarks
11 11 branch
12 12 branches
13 13 bundle
14 14 cat
15 15 clone
16 16 commit
17 17 config
18 18 continue
19 19 copy
20 20 diff
21 21 export
22 22 files
23 23 forget
24 24 graft
25 25 grep
26 26 heads
27 27 help
28 28 identify
29 29 import
30 30 incoming
31 31 init
32 32 locate
33 33 log
34 34 manifest
35 35 merge
36 36 outgoing
37 37 parents
38 38 paths
39 39 phase
40 40 pull
41 41 purge
42 42 push
43 43 recover
44 44 remove
45 45 rename
46 46 resolve
47 47 revert
48 48 rollback
49 49 root
50 50 serve
51 51 shelve
52 52 status
53 53 summary
54 54 tag
55 55 tags
56 56 tip
57 57 unbundle
58 58 unshelve
59 59 update
60 60 verify
61 61 version
62 62
63 63 Show all commands that start with "a"
64 64 $ hg debugcomplete a
65 65 abort
66 66 add
67 67 addremove
68 68 annotate
69 69 archive
70 70
71 71 Do not show debug commands if there are other candidates
72 72 $ hg debugcomplete d
73 73 diff
74 74
75 75 Show debug commands if there are no other candidates
76 76 $ hg debugcomplete debug
77 debug-delta-find
77 78 debug-repair-issue6528
78 79 debugancestor
79 80 debugantivirusrunning
80 81 debugapplystreamclonebundle
81 82 debugbackupbundle
82 83 debugbuilddag
83 84 debugbundle
84 85 debugcapabilities
85 86 debugchangedfiles
86 87 debugcheckstate
87 88 debugcolor
88 89 debugcommands
89 90 debugcomplete
90 91 debugconfig
91 92 debugcreatestreamclonebundle
92 93 debugdag
93 94 debugdata
94 95 debugdate
95 96 debugdeltachain
96 97 debugdirstate
97 98 debugdirstateignorepatternshash
98 99 debugdiscovery
99 100 debugdownload
100 101 debugextensions
101 102 debugfileset
102 103 debugformat
103 104 debugfsinfo
104 105 debuggetbundle
105 106 debugignore
106 107 debugindex
107 108 debugindexdot
108 109 debugindexstats
109 110 debuginstall
110 111 debugknown
111 112 debuglabelcomplete
112 113 debuglocks
113 114 debugmanifestfulltextcache
114 115 debugmergestate
115 116 debugnamecomplete
116 117 debugnodemap
117 118 debugobsolete
118 119 debugp1copies
119 120 debugp2copies
120 121 debugpathcomplete
121 122 debugpathcopies
122 123 debugpeer
123 124 debugpickmergetool
124 125 debugpushkey
125 126 debugpvec
126 127 debugrebuilddirstate
127 128 debugrebuildfncache
128 129 debugrename
129 130 debugrequires
130 131 debugrevlog
131 132 debugrevlogindex
132 133 debugrevspec
133 134 debugserve
134 135 debugsetparents
135 136 debugshell
136 137 debugsidedata
137 138 debugssl
138 139 debugstrip
139 140 debugsub
140 141 debugsuccessorssets
141 142 debugtagscache
142 143 debugtemplate
143 144 debuguigetpass
144 145 debuguiprompt
145 146 debugupdatecaches
146 147 debugupgraderepo
147 148 debugwalk
148 149 debugwhyunstable
149 150 debugwireargs
150 151 debugwireproto
151 152
152 153 Do not show the alias of a debug command if there are other candidates
153 154 (this should hide rawcommit)
154 155 $ hg debugcomplete r
155 156 recover
156 157 remove
157 158 rename
158 159 resolve
159 160 revert
160 161 rollback
161 162 root
162 163 Show the alias of a debug command if there are no other candidates
163 164 $ hg debugcomplete rawc
164 165
165 166
166 167 Show the global options
167 168 $ hg debugcomplete --options | sort
168 169 --color
169 170 --config
170 171 --cwd
171 172 --debug
172 173 --debugger
173 174 --encoding
174 175 --encodingmode
175 176 --help
176 177 --hidden
177 178 --noninteractive
178 179 --pager
179 180 --profile
180 181 --quiet
181 182 --repository
182 183 --time
183 184 --traceback
184 185 --verbose
185 186 --version
186 187 -R
187 188 -h
188 189 -q
189 190 -v
190 191 -y
191 192
192 193 Show the options for the "serve" command
193 194 $ hg debugcomplete --options serve | sort
194 195 --accesslog
195 196 --address
196 197 --certificate
197 198 --cmdserver
198 199 --color
199 200 --config
200 201 --cwd
201 202 --daemon
202 203 --daemon-postexec
203 204 --debug
204 205 --debugger
205 206 --encoding
206 207 --encodingmode
207 208 --errorlog
208 209 --help
209 210 --hidden
210 211 --ipv6
211 212 --name
212 213 --noninteractive
213 214 --pager
214 215 --pid-file
215 216 --port
216 217 --prefix
217 218 --print-url
218 219 --profile
219 220 --quiet
220 221 --repository
221 222 --stdio
222 223 --style
223 224 --subrepos
224 225 --templates
225 226 --time
226 227 --traceback
227 228 --verbose
228 229 --version
229 230 --web-conf
230 231 -6
231 232 -A
232 233 -E
233 234 -R
234 235 -S
235 236 -a
236 237 -d
237 238 -h
238 239 -n
239 240 -p
240 241 -q
241 242 -t
242 243 -v
243 244 -y
244 245
245 246 Show an error if we use --options with an ambiguous abbreviation
246 247 $ hg debugcomplete --options s
247 248 hg: command 's' is ambiguous:
248 249 serve shelve showconfig status summary
249 250 [10]
250 251
251 252 Show all commands + options
252 253 $ hg debugcommands
253 254 abort: dry-run
254 255 add: include, exclude, subrepos, dry-run
255 256 addremove: similarity, subrepos, include, exclude, dry-run
256 257 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, skip, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, include, exclude, template
257 258 archive: no-decode, prefix, rev, type, subrepos, include, exclude
258 259 backout: merge, commit, no-commit, parent, rev, edit, tool, include, exclude, message, logfile, date, user
259 260 bisect: reset, good, bad, skip, extend, command, noupdate
260 261 bookmarks: force, rev, delete, rename, inactive, list, template
261 262 branch: force, clean, rev
262 263 branches: active, closed, rev, template
263 264 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
264 265 cat: output, rev, decode, include, exclude, template
265 266 clone: noupdate, updaterev, rev, branch, pull, uncompressed, stream, ssh, remotecmd, insecure
266 267 commit: addremove, close-branch, amend, secret, edit, force-close-branch, interactive, include, exclude, message, logfile, date, user, subrepos
267 268 config: untrusted, exp-all-known, edit, local, source, shared, non-shared, global, template
268 269 continue: dry-run
269 270 copy: forget, after, at-rev, force, include, exclude, dry-run
271 debug-delta-find: changelog, manifest, dir, template
270 272 debug-repair-issue6528: to-report, from-report, paranoid, dry-run
271 273 debugancestor:
272 274 debugantivirusrunning:
273 275 debugapplystreamclonebundle:
274 276 debugbackupbundle: recover, patch, git, limit, no-merges, stat, graph, style, template
275 277 debugbuilddag: mergeable-file, overwritten-file, new-file, from-existing
276 278 debugbundle: all, part-type, spec
277 279 debugcapabilities:
278 280 debugchangedfiles: compute
279 281 debugcheckstate:
280 282 debugcolor: style
281 283 debugcommands:
282 284 debugcomplete: options
283 285 debugcreatestreamclonebundle:
284 286 debugdag: tags, branches, dots, spaces
285 287 debugdata: changelog, manifest, dir
286 288 debugdate: extended
287 289 debugdeltachain: changelog, manifest, dir, template
288 290 debugdirstateignorepatternshash:
289 291 debugdirstate: nodates, dates, datesort, docket, all
290 292 debugdiscovery: old, nonheads, rev, seed, local-as-revs, remote-as-revs, ssh, remotecmd, insecure, template
291 293 debugdownload: output
292 294 debugextensions: template
293 295 debugfileset: rev, all-files, show-matcher, show-stage
294 296 debugformat: template
295 297 debugfsinfo:
296 298 debuggetbundle: head, common, type
297 299 debugignore:
298 300 debugindex: changelog, manifest, dir, template
299 301 debugindexdot: changelog, manifest, dir
300 302 debugindexstats:
301 303 debuginstall: template
302 304 debugknown:
303 305 debuglabelcomplete:
304 306 debuglocks: force-free-lock, force-free-wlock, set-lock, set-wlock
305 307 debugmanifestfulltextcache: clear, add
306 308 debugmergestate: style, template
307 309 debugnamecomplete:
308 310 debugnodemap: dump-new, dump-disk, check, metadata
309 311 debugobsolete: flags, record-parents, rev, exclusive, index, delete, date, user, template
310 312 debugp1copies: rev
311 313 debugp2copies: rev
312 314 debugpathcomplete: full, normal, added, removed
313 315 debugpathcopies: include, exclude
314 316 debugpeer:
315 317 debugpickmergetool: rev, changedelete, include, exclude, tool
316 318 debugpushkey:
317 319 debugpvec:
318 320 debugrebuilddirstate: rev, minimal
319 321 debugrebuildfncache: only-data
320 322 debugrename: rev
321 323 debugrequires:
322 324 debugrevlog: changelog, manifest, dir, dump
323 325 debugrevlogindex: changelog, manifest, dir, format
324 326 debugrevspec: optimize, show-revs, show-set, show-stage, no-optimized, verify-optimized
325 327 debugserve: sshstdio, logiofd, logiofile
326 328 debugsetparents:
327 329 debugshell:
328 330 debugsidedata: changelog, manifest, dir
329 331 debugssl:
330 332 debugstrip: rev, force, no-backup, nobackup, , keep, bookmark, soft
331 333 debugsub: rev
332 334 debugsuccessorssets: closest
333 335 debugtagscache:
334 336 debugtemplate: rev, define
335 337 debuguigetpass: prompt
336 338 debuguiprompt: prompt
337 339 debugupdatecaches:
338 340 debugupgraderepo: optimize, run, backup, changelog, manifest, filelogs
339 341 debugwalk: include, exclude
340 342 debugwhyunstable:
341 343 debugwireargs: three, four, five, ssh, remotecmd, insecure
342 344 debugwireproto: localssh, peer, noreadstderr, nologhandshake, ssh, remotecmd, insecure
343 345 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
344 346 export: bookmark, output, switch-parent, rev, text, git, binary, nodates, template
345 347 files: rev, print0, include, exclude, template, subrepos
346 348 forget: interactive, include, exclude, dry-run
347 349 graft: rev, base, continue, stop, abort, edit, log, no-commit, force, currentdate, currentuser, date, user, tool, dry-run
348 350 grep: print0, all, diff, text, follow, ignore-case, files-with-matches, line-number, rev, all-files, user, date, template, include, exclude
349 351 heads: rev, topo, active, closed, style, template
350 352 help: extension, command, keyword, system
351 353 identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure, template
352 354 import: strip, base, secret, edit, force, no-commit, bypass, partial, exact, prefix, import-branch, message, logfile, date, user, similarity
353 355 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
354 356 init: ssh, remotecmd, insecure
355 357 locate: rev, print0, fullpath, include, exclude
356 358 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
357 359 manifest: rev, all, template
358 360 merge: force, rev, preview, abort, tool
359 361 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
360 362 parents: rev, style, template
361 363 paths: template
362 364 phase: public, draft, secret, force, rev
363 365 pull: update, force, confirm, rev, bookmark, branch, ssh, remotecmd, insecure
364 366 purge: abort-on-err, all, ignored, dirs, files, print, print0, confirm, include, exclude
365 367 push: force, rev, bookmark, all-bookmarks, branch, new-branch, pushvars, publish, ssh, remotecmd, insecure
366 368 recover: verify
367 369 remove: after, force, subrepos, include, exclude, dry-run
368 370 rename: forget, after, at-rev, force, include, exclude, dry-run
369 371 resolve: all, list, mark, unmark, no-status, re-merge, tool, include, exclude, template
370 372 revert: all, date, rev, no-backup, interactive, include, exclude, dry-run
371 373 rollback: dry-run, force
372 374 root: template
373 375 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
374 376 shelve: addremove, unknown, cleanup, date, delete, edit, keep, list, message, name, patch, interactive, stat, include, exclude
375 377 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, terse, copies, print0, rev, change, include, exclude, subrepos, template
376 378 summary: remote
377 379 tag: force, local, rev, remove, edit, message, date, user
378 380 tags: template
379 381 tip: patch, git, style, template
380 382 unbundle: update
381 383 unshelve: abort, continue, interactive, keep, name, tool, date
382 384 update: clean, check, merge, date, rev, tool
383 385 verify: full
384 386 version: template
385 387
386 388 $ hg init a
387 389 $ cd a
388 390 $ echo fee > fee
389 391 $ hg ci -q -Amfee
390 392 $ hg tag fee
391 393 $ mkdir fie
392 394 $ echo dead > fie/dead
393 395 $ echo live > fie/live
394 396 $ hg bookmark fo
395 397 $ hg branch -q fie
396 398 $ hg ci -q -Amfie
397 399 $ echo fo > fo
398 400 $ hg branch -qf default
399 401 $ hg ci -q -Amfo
400 402 $ echo Fum > Fum
401 403 $ hg ci -q -AmFum
402 404 $ hg bookmark Fum
403 405
404 406 Test debugpathcomplete
405 407
406 408 $ hg debugpathcomplete f
407 409 fee
408 410 fie
409 411 fo
410 412 $ hg debugpathcomplete -f f
411 413 fee
412 414 fie/dead
413 415 fie/live
414 416 fo
415 417
416 418 $ hg rm Fum
417 419 $ hg debugpathcomplete -r F
418 420 Fum
419 421
420 422 Test debugnamecomplete
421 423
422 424 $ hg debugnamecomplete
423 425 Fum
424 426 default
425 427 fee
426 428 fie
427 429 fo
428 430 tip
429 431 $ hg debugnamecomplete f
430 432 fee
431 433 fie
432 434 fo
433 435
434 436 Test debuglabelcomplete, a deprecated name for debugnamecomplete that is still
435 437 used for completions in some shells.
436 438
437 439 $ hg debuglabelcomplete
438 440 Fum
439 441 default
440 442 fee
441 443 fie
442 444 fo
443 445 tip
444 446 $ hg debuglabelcomplete f
445 447 fee
446 448 fie
447 449 fo
@@ -1,4063 +1,4065 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 manifest output the current or given revision of the project manifest
133 133 recover roll back an interrupted transaction
134 134 verify verify the integrity of the repository
135 135
136 136 Help:
137 137
138 138 config show combined config settings from all hgrc files
139 139 help show help for a given topic or a help overview
140 140 version output version and copyright information
141 141
142 142 additional help topics:
143 143
144 144 Mercurial identifiers:
145 145
146 146 filesets Specifying File Sets
147 147 hgignore Syntax for Mercurial Ignore Files
148 148 patterns File Name Patterns
149 149 revisions Specifying Revisions
150 150 urls URL Paths
151 151
152 152 Mercurial output:
153 153
154 154 color Colorizing Outputs
155 155 dates Date Formats
156 156 diffs Diff Formats
157 157 templating Template Usage
158 158
159 159 Mercurial configuration:
160 160
161 161 config Configuration Files
162 162 environment Environment Variables
163 163 extensions Using Additional Features
164 164 flags Command-line flags
165 165 hgweb Configuring hgweb
166 166 merge-tools Merge Tools
167 167 pager Pager Support
168 168 rust Rust in Mercurial
169 169
170 170 Concepts:
171 171
172 172 bundlespec Bundle File Formats
173 173 evolution Safely rewriting history (EXPERIMENTAL)
174 174 glossary Glossary
175 175 phases Working with Phases
176 176 subrepos Subrepositories
177 177
178 178 Miscellaneous:
179 179
180 180 deprecated Deprecated Features
181 181 internals Technical implementation topics
182 182 scripting Using Mercurial from scripts and automation
183 183
184 184 (use 'hg help -v' to show built-in aliases and global options)
185 185
186 186 $ hg -q help
187 187 Repository creation:
188 188
189 189 clone make a copy of an existing repository
190 190 init create a new repository in the given directory
191 191
192 192 Remote repository management:
193 193
194 194 incoming show new changesets found in source
195 195 outgoing show changesets not found in the destination
196 196 paths show aliases for remote repositories
197 197 pull pull changes from the specified source
198 198 push push changes to the specified destination
199 199 serve start stand-alone webserver
200 200
201 201 Change creation:
202 202
203 203 commit commit the specified files or all outstanding changes
204 204
205 205 Change manipulation:
206 206
207 207 backout reverse effect of earlier changeset
208 208 graft copy changes from other branches onto the current branch
209 209 merge merge another revision into working directory
210 210
211 211 Change organization:
212 212
213 213 bookmarks create a new bookmark or list existing bookmarks
214 214 branch set or show the current branch name
215 215 branches list repository named branches
216 216 phase set or show the current phase name
217 217 tag add one or more tags for the current or given revision
218 218 tags list repository tags
219 219
220 220 File content management:
221 221
222 222 annotate show changeset information by line for each file
223 223 cat output the current or given revision of files
224 224 copy mark files as copied for the next commit
225 225 diff diff repository (or selected files)
226 226 grep search for a pattern in specified files
227 227
228 228 Change navigation:
229 229
230 230 bisect subdivision search of changesets
231 231 heads show branch heads
232 232 identify identify the working directory or specified revision
233 233 log show revision history of entire repository or files
234 234
235 235 Working directory management:
236 236
237 237 add add the specified files on the next commit
238 238 addremove add all new files, delete all missing files
239 239 files list tracked files
240 240 forget forget the specified files on the next commit
241 241 purge removes files not tracked by Mercurial
242 242 remove remove the specified files on the next commit
243 243 rename rename files; equivalent of copy + remove
244 244 resolve redo merges or set/view the merge status of files
245 245 revert restore files to their checkout state
246 246 root print the root (top) of the current working directory
247 247 shelve save and set aside changes from the working directory
248 248 status show changed files in the working directory
249 249 summary summarize working directory state
250 250 unshelve restore a shelved change to the working directory
251 251 update update working directory (or switch revisions)
252 252
253 253 Change import/export:
254 254
255 255 archive create an unversioned archive of a repository revision
256 256 bundle create a bundle file
257 257 export dump the header and diffs for one or more changesets
258 258 import import an ordered set of patches
259 259 unbundle apply one or more bundle files
260 260
261 261 Repository maintenance:
262 262
263 263 manifest output the current or given revision of the project manifest
264 264 recover roll back an interrupted transaction
265 265 verify verify the integrity of the repository
266 266
267 267 Help:
268 268
269 269 config show combined config settings from all hgrc files
270 270 help show help for a given topic or a help overview
271 271 version output version and copyright information
272 272
273 273 additional help topics:
274 274
275 275 Mercurial identifiers:
276 276
277 277 filesets Specifying File Sets
278 278 hgignore Syntax for Mercurial Ignore Files
279 279 patterns File Name Patterns
280 280 revisions Specifying Revisions
281 281 urls URL Paths
282 282
283 283 Mercurial output:
284 284
285 285 color Colorizing Outputs
286 286 dates Date Formats
287 287 diffs Diff Formats
288 288 templating Template Usage
289 289
290 290 Mercurial configuration:
291 291
292 292 config Configuration Files
293 293 environment Environment Variables
294 294 extensions Using Additional Features
295 295 flags Command-line flags
296 296 hgweb Configuring hgweb
297 297 merge-tools Merge Tools
298 298 pager Pager Support
299 299 rust Rust in Mercurial
300 300
301 301 Concepts:
302 302
303 303 bundlespec Bundle File Formats
304 304 evolution Safely rewriting history (EXPERIMENTAL)
305 305 glossary Glossary
306 306 phases Working with Phases
307 307 subrepos Subrepositories
308 308
309 309 Miscellaneous:
310 310
311 311 deprecated Deprecated Features
312 312 internals Technical implementation topics
313 313 scripting Using Mercurial from scripts and automation
314 314
315 315 Test extension help:
316 316 $ hg help extensions --config extensions.rebase= --config extensions.children=
317 317 Using Additional Features
318 318 """""""""""""""""""""""""
319 319
320 320 Mercurial has the ability to add new features through the use of
321 321 extensions. Extensions may add new commands, add options to existing
322 322 commands, change the default behavior of commands, or implement hooks.
323 323
324 324 To enable the "foo" extension, either shipped with Mercurial or in the
325 325 Python search path, create an entry for it in your configuration file,
326 326 like this:
327 327
328 328 [extensions]
329 329 foo =
330 330
331 331 You may also specify the full path to an extension:
332 332
333 333 [extensions]
334 334 myfeature = ~/.hgext/myfeature.py
335 335
336 336 See 'hg help config' for more information on configuration files.
337 337
338 338 Extensions are not loaded by default for a variety of reasons: they can
339 339 increase startup overhead; they may be meant for advanced usage only; they
340 340 may provide potentially dangerous abilities (such as letting you destroy
341 341 or modify history); they might not be ready for prime time; or they may
342 342 alter some usual behaviors of stock Mercurial. It is thus up to the user
343 343 to activate extensions as needed.
344 344
345 345 To explicitly disable an extension enabled in a configuration file of
346 346 broader scope, prepend its path with !:
347 347
348 348 [extensions]
349 349 # disabling extension bar residing in /path/to/extension/bar.py
350 350 bar = !/path/to/extension/bar.py
351 351 # ditto, but no path was supplied for extension baz
352 352 baz = !
353 353
354 354 enabled extensions:
355 355
356 356 children command to display child changesets (DEPRECATED)
357 357 rebase command to move sets of revisions to a different ancestor
358 358
359 359 disabled extensions:
360 360
361 361 acl hooks for controlling repository access
362 362 blackbox log repository events to a blackbox for debugging
363 363 bugzilla hooks for integrating with the Bugzilla bug tracker
364 364 censor erase file content at a given revision
365 365 churn command to display statistics about repository history
366 366 clonebundles advertise pre-generated bundles to seed clones
367 367 closehead close arbitrary heads without checking them out first
368 368 convert import revisions from foreign VCS repositories into
369 369 Mercurial
370 370 eol automatically manage newlines in repository files
371 371 extdiff command to allow external programs to compare revisions
372 372 factotum http authentication with factotum
373 373 fastexport export repositories as git fast-import stream
374 374 githelp try mapping git commands to Mercurial commands
375 375 gpg commands to sign and verify changesets
376 376 hgk browse the repository in a graphical way
377 377 highlight syntax highlighting for hgweb (requires Pygments)
378 378 histedit interactive history editing
379 379 keyword expand keywords in tracked files
380 380 largefiles track large binary files
381 381 mq manage a stack of patches
382 382 notify hooks for sending email push notifications
383 383 patchbomb command to send changesets as (a series of) patch emails
384 384 relink recreates hardlinks between repository clones
385 385 schemes extend schemes with shortcuts to repository swarms
386 386 share share a common history between several working directories
387 387 transplant command to transplant changesets from another branch
388 388 win32mbcs allow the use of MBCS paths with problematic encodings
389 389 zeroconf discover and advertise repositories on the local network
390 390
391 391 #endif
392 392
393 393 Verify that deprecated extensions are included if --verbose:
394 394
395 395 $ hg -v help extensions | grep children
396 396 children command to display child changesets (DEPRECATED)
397 397
398 398 Verify that extension keywords appear in help templates
399 399
400 400 $ hg help --config extensions.transplant= templating|grep transplant > /dev/null
401 401
402 402 Test short command list with verbose option
403 403
404 404 $ hg -v help shortlist
405 405 Mercurial Distributed SCM
406 406
407 407 basic commands:
408 408
409 409 abort abort an unfinished operation (EXPERIMENTAL)
410 410 add add the specified files on the next commit
411 411 annotate, blame
412 412 show changeset information by line for each file
413 413 clone make a copy of an existing repository
414 414 commit, ci commit the specified files or all outstanding changes
415 415 continue resumes an interrupted operation (EXPERIMENTAL)
416 416 diff diff repository (or selected files)
417 417 export dump the header and diffs for one or more changesets
418 418 forget forget the specified files on the next commit
419 419 init create a new repository in the given directory
420 420 log, history show revision history of entire repository or files
421 421 merge merge another revision into working directory
422 422 pull pull changes from the specified source
423 423 push push changes to the specified destination
424 424 remove, rm remove the specified files on the next commit
425 425 serve start stand-alone webserver
426 426 status, st show changed files in the working directory
427 427 summary, sum summarize working directory state
428 428 update, up, checkout, co
429 429 update working directory (or switch revisions)
430 430
431 431 global options ([+] can be repeated):
432 432
433 433 -R --repository REPO repository root directory or name of overlay bundle
434 434 file
435 435 --cwd DIR change working directory
436 436 -y --noninteractive do not prompt, automatically pick the first choice for
437 437 all prompts
438 438 -q --quiet suppress output
439 439 -v --verbose enable additional output
440 440 --color TYPE when to colorize (boolean, always, auto, never, or
441 441 debug)
442 442 --config CONFIG [+] set/override config option (use 'section.name=value')
443 443 --debug enable debugging output
444 444 --debugger start debugger
445 445 --encoding ENCODE set the charset encoding (default: ascii)
446 446 --encodingmode MODE set the charset encoding mode (default: strict)
447 447 --traceback always print a traceback on exception
448 448 --time time how long the command takes
449 449 --profile print command execution profile
450 450 --version output version information and exit
451 451 -h --help display help and exit
452 452 --hidden consider hidden changesets
453 453 --pager TYPE when to paginate (boolean, always, auto, or never)
454 454 (default: auto)
455 455
456 456 (use 'hg help' for the full list of commands)
457 457
458 458 $ hg add -h
459 459 hg add [OPTION]... [FILE]...
460 460
461 461 add the specified files on the next commit
462 462
463 463 Schedule files to be version controlled and added to the repository.
464 464
465 465 The files will be added to the repository at the next commit. To undo an
466 466 add before that, see 'hg forget'.
467 467
468 468 If no names are given, add all files to the repository (except files
469 469 matching ".hgignore").
470 470
471 471 Returns 0 if all files are successfully added.
472 472
473 473 options ([+] can be repeated):
474 474
475 475 -I --include PATTERN [+] include names matching the given patterns
476 476 -X --exclude PATTERN [+] exclude names matching the given patterns
477 477 -S --subrepos recurse into subrepositories
478 478 -n --dry-run do not perform actions, just print output
479 479
480 480 (some details hidden, use --verbose to show complete help)
481 481
482 482 Verbose help for add
483 483
484 484 $ hg add -hv
485 485 hg add [OPTION]... [FILE]...
486 486
487 487 add the specified files on the next commit
488 488
489 489 Schedule files to be version controlled and added to the repository.
490 490
491 491 The files will be added to the repository at the next commit. To undo an
492 492 add before that, see 'hg forget'.
493 493
494 494 If no names are given, add all files to the repository (except files
495 495 matching ".hgignore").
496 496
497 497 Examples:
498 498
499 499 - New (unknown) files are added automatically by 'hg add':
500 500
501 501 $ ls
502 502 foo.c
503 503 $ hg status
504 504 ? foo.c
505 505 $ hg add
506 506 adding foo.c
507 507 $ hg status
508 508 A foo.c
509 509
510 510 - Specific files to be added can be specified:
511 511
512 512 $ ls
513 513 bar.c foo.c
514 514 $ hg status
515 515 ? bar.c
516 516 ? foo.c
517 517 $ hg add bar.c
518 518 $ hg status
519 519 A bar.c
520 520 ? foo.c
521 521
522 522 Returns 0 if all files are successfully added.
523 523
524 524 options ([+] can be repeated):
525 525
526 526 -I --include PATTERN [+] include names matching the given patterns
527 527 -X --exclude PATTERN [+] exclude names matching the given patterns
528 528 -S --subrepos recurse into subrepositories
529 529 -n --dry-run do not perform actions, just print output
530 530
531 531 global options ([+] can be repeated):
532 532
533 533 -R --repository REPO repository root directory or name of overlay bundle
534 534 file
535 535 --cwd DIR change working directory
536 536 -y --noninteractive do not prompt, automatically pick the first choice for
537 537 all prompts
538 538 -q --quiet suppress output
539 539 -v --verbose enable additional output
540 540 --color TYPE when to colorize (boolean, always, auto, never, or
541 541 debug)
542 542 --config CONFIG [+] set/override config option (use 'section.name=value')
543 543 --debug enable debugging output
544 544 --debugger start debugger
545 545 --encoding ENCODE set the charset encoding (default: ascii)
546 546 --encodingmode MODE set the charset encoding mode (default: strict)
547 547 --traceback always print a traceback on exception
548 548 --time time how long the command takes
549 549 --profile print command execution profile
550 550 --version output version information and exit
551 551 -h --help display help and exit
552 552 --hidden consider hidden changesets
553 553 --pager TYPE when to paginate (boolean, always, auto, or never)
554 554 (default: auto)
555 555
556 556 Test the textwidth config option
557 557
558 558 $ hg root -h --config ui.textwidth=50
559 559 hg root
560 560
561 561 print the root (top) of the current working
562 562 directory
563 563
564 564 Print the root directory of the current
565 565 repository.
566 566
567 567 Returns 0 on success.
568 568
569 569 options:
570 570
571 571 -T --template TEMPLATE display with template
572 572
573 573 (some details hidden, use --verbose to show
574 574 complete help)
575 575
576 576 Test help option with version option
577 577
578 578 $ hg add -h --version
579 579 Mercurial Distributed SCM (version *) (glob)
580 580 (see https://mercurial-scm.org for more information)
581 581
582 582 Copyright (C) 2005-* Olivia Mackall and others (glob)
583 583 This is free software; see the source for copying conditions. There is NO
584 584 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
585 585
586 586 $ hg add --skjdfks
587 587 hg add: option --skjdfks not recognized
588 588 hg add [OPTION]... [FILE]...
589 589
590 590 add the specified files on the next commit
591 591
592 592 options ([+] can be repeated):
593 593
594 594 -I --include PATTERN [+] include names matching the given patterns
595 595 -X --exclude PATTERN [+] exclude names matching the given patterns
596 596 -S --subrepos recurse into subrepositories
597 597 -n --dry-run do not perform actions, just print output
598 598
599 599 (use 'hg add -h' to show more help)
600 600 [10]
601 601
602 602 Test ambiguous command help
603 603
604 604 $ hg help ad
605 605 list of commands:
606 606
607 607 add add the specified files on the next commit
608 608 addremove add all new files, delete all missing files
609 609
610 610 (use 'hg help -v ad' to show built-in aliases and global options)
611 611
612 612 Test command without options
613 613
614 614 $ hg help verify
615 615 hg verify
616 616
617 617 verify the integrity of the repository
618 618
619 619 Verify the integrity of the current repository.
620 620
621 621 This will perform an extensive check of the repository's integrity,
622 622 validating the hashes and checksums of each entry in the changelog,
623 623 manifest, and tracked files, as well as the integrity of their crosslinks
624 624 and indices.
625 625
626 626 Please see https://mercurial-scm.org/wiki/RepositoryCorruption for more
627 627 information about recovery from corruption of the repository.
628 628
629 629 Returns 0 on success, 1 if errors are encountered.
630 630
631 631 options:
632 632
633 633 (some details hidden, use --verbose to show complete help)
634 634
635 635 $ hg help diff
636 636 hg diff [OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...
637 637
638 638 diff repository (or selected files)
639 639
640 640 Show differences between revisions for the specified files.
641 641
642 642 Differences between files are shown using the unified diff format.
643 643
644 644 Note:
645 645 'hg diff' may generate unexpected results for merges, as it will
646 646 default to comparing against the working directory's first parent
647 647 changeset if no revisions are specified. To diff against the conflict
648 648 regions, you can use '--config diff.merge=yes'.
649 649
650 650 By default, the working directory files are compared to its first parent.
651 651 To see the differences from another revision, use --from. To see the
652 652 difference to another revision, use --to. For example, 'hg diff --from .^'
653 653 will show the differences from the working copy's grandparent to the
654 654 working copy, 'hg diff --to .' will show the diff from the working copy to
655 655 its parent (i.e. the reverse of the default), and 'hg diff --from 1.0 --to
656 656 1.2' will show the diff between those two revisions.
657 657
658 658 Alternatively you can specify -c/--change with a revision to see the
659 659 changes in that changeset relative to its first parent (i.e. 'hg diff -c
660 660 42' is equivalent to 'hg diff --from 42^ --to 42')
661 661
662 662 Without the -a/--text option, diff will avoid generating diffs of files it
663 663 detects as binary. With -a, diff will generate a diff anyway, probably
664 664 with undesirable results.
665 665
666 666 Use the -g/--git option to generate diffs in the git extended diff format.
667 667 For more information, read 'hg help diffs'.
668 668
669 669 Returns 0 on success.
670 670
671 671 options ([+] can be repeated):
672 672
673 673 --from REV1 revision to diff from
674 674 --to REV2 revision to diff to
675 675 -c --change REV change made by revision
676 676 -a --text treat all files as text
677 677 -g --git use git extended diff format
678 678 --binary generate binary diffs in git mode (default)
679 679 --nodates omit dates from diff headers
680 680 --noprefix omit a/ and b/ prefixes from filenames
681 681 -p --show-function show which function each change is in
682 682 --reverse produce a diff that undoes the changes
683 683 -w --ignore-all-space ignore white space when comparing lines
684 684 -b --ignore-space-change ignore changes in the amount of white space
685 685 -B --ignore-blank-lines ignore changes whose lines are all blank
686 686 -Z --ignore-space-at-eol ignore changes in whitespace at EOL
687 687 -U --unified NUM number of lines of context to show
688 688 --stat output diffstat-style summary of changes
689 689 --root DIR produce diffs relative to subdirectory
690 690 -I --include PATTERN [+] include names matching the given patterns
691 691 -X --exclude PATTERN [+] exclude names matching the given patterns
692 692 -S --subrepos recurse into subrepositories
693 693
694 694 (some details hidden, use --verbose to show complete help)
695 695
696 696 $ hg help status
697 697 hg status [OPTION]... [FILE]...
698 698
699 699 aliases: st
700 700
701 701 show changed files in the working directory
702 702
703 703 Show status of files in the repository. If names are given, only files
704 704 that match are shown. Files that are clean or ignored or the source of a
705 705 copy/move operation, are not listed unless -c/--clean, -i/--ignored,
706 706 -C/--copies or -A/--all are given. Unless options described with "show
707 707 only ..." are given, the options -mardu are used.
708 708
709 709 Option -q/--quiet hides untracked (unknown and ignored) files unless
710 710 explicitly requested with -u/--unknown or -i/--ignored.
711 711
712 712 Note:
713 713 'hg status' may appear to disagree with diff if permissions have
714 714 changed or a merge has occurred. The standard diff format does not
715 715 report permission changes and diff only reports changes relative to one
716 716 merge parent.
717 717
718 718 If one revision is given, it is used as the base revision. If two
719 719 revisions are given, the differences between them are shown. The --change
720 720 option can also be used as a shortcut to list the changed files of a
721 721 revision from its first parent.
722 722
723 723 The codes used to show the status of files are:
724 724
725 725 M = modified
726 726 A = added
727 727 R = removed
728 728 C = clean
729 729 ! = missing (deleted by non-hg command, but still tracked)
730 730 ? = not tracked
731 731 I = ignored
732 732 = origin of the previous file (with --copies)
733 733
734 734 Returns 0 on success.
735 735
736 736 options ([+] can be repeated):
737 737
738 738 -A --all show status of all files
739 739 -m --modified show only modified files
740 740 -a --added show only added files
741 741 -r --removed show only removed files
742 742 -d --deleted show only missing files
743 743 -c --clean show only files without changes
744 744 -u --unknown show only unknown (not tracked) files
745 745 -i --ignored show only ignored files
746 746 -n --no-status hide status prefix
747 747 -C --copies show source of copied files
748 748 -0 --print0 end filenames with NUL, for use with xargs
749 749 --rev REV [+] show difference from revision
750 750 --change REV list the changed files of a revision
751 751 -I --include PATTERN [+] include names matching the given patterns
752 752 -X --exclude PATTERN [+] exclude names matching the given patterns
753 753 -S --subrepos recurse into subrepositories
754 754 -T --template TEMPLATE display with template
755 755
756 756 (some details hidden, use --verbose to show complete help)
757 757
758 758 $ hg -q help status
759 759 hg status [OPTION]... [FILE]...
760 760
761 761 show changed files in the working directory
762 762
763 763 $ hg help foo
764 764 abort: no such help topic: foo
765 765 (try 'hg help --keyword foo')
766 766 [10]
767 767
768 768 $ hg skjdfks
769 769 hg: unknown command 'skjdfks'
770 770 (use 'hg help' for a list of commands)
771 771 [10]
772 772
773 773 Typoed command gives suggestion
774 774 $ hg puls
775 775 hg: unknown command 'puls'
776 776 (did you mean one of pull, push?)
777 777 [10]
778 778
779 779 Not enabled extension gets suggested
780 780
781 781 $ hg rebase
782 782 hg: unknown command 'rebase'
783 783 'rebase' is provided by the following extension:
784 784
785 785 rebase command to move sets of revisions to a different ancestor
786 786
787 787 (use 'hg help extensions' for information on enabling extensions)
788 788 [10]
789 789
790 790 Disabled extension gets suggested
791 791 $ hg --config extensions.rebase=! rebase
792 792 hg: unknown command 'rebase'
793 793 'rebase' is provided by the following extension:
794 794
795 795 rebase command to move sets of revisions to a different ancestor
796 796
797 797 (use 'hg help extensions' for information on enabling extensions)
798 798 [10]
799 799
800 800 Checking that help adapts based on the config:
801 801
802 802 $ hg help diff --config ui.tweakdefaults=true | egrep -e '^ *(-g|config)'
803 803 -g --[no-]git use git extended diff format (default: on from
804 804 config)
805 805
806 806 Make sure that we don't run afoul of the help system thinking that
807 807 this is a section and erroring out weirdly.
808 808
809 809 $ hg .log
810 810 hg: unknown command '.log'
811 811 (did you mean log?)
812 812 [10]
813 813
814 814 $ hg log.
815 815 hg: unknown command 'log.'
816 816 (did you mean log?)
817 817 [10]
818 818 $ hg pu.lh
819 819 hg: unknown command 'pu.lh'
820 820 (did you mean one of pull, push?)
821 821 [10]
822 822
823 823 $ cat > helpext.py <<EOF
824 824 > import os
825 825 > from mercurial import commands, fancyopts, registrar
826 826 >
827 827 > def func(arg):
828 828 > return '%sfoo' % arg
829 829 > class customopt(fancyopts.customopt):
830 830 > def newstate(self, oldstate, newparam, abort):
831 831 > return '%sbar' % oldstate
832 832 > cmdtable = {}
833 833 > command = registrar.command(cmdtable)
834 834 >
835 835 > @command(b'nohelp',
836 836 > [(b'', b'longdesc', 3, b'x'*67),
837 837 > (b'n', b'', None, b'normal desc'),
838 838 > (b'', b'newline', b'', b'line1\nline2'),
839 839 > (b'', b'default-off', False, b'enable X'),
840 840 > (b'', b'default-on', True, b'enable Y'),
841 841 > (b'', b'callableopt', func, b'adds foo'),
842 842 > (b'', b'customopt', customopt(''), b'adds bar'),
843 843 > (b'', b'customopt-withdefault', customopt('foo'), b'adds bar')],
844 844 > b'hg nohelp',
845 845 > norepo=True)
846 846 > @command(b'debugoptADV', [(b'', b'aopt', None, b'option is (ADVANCED)')])
847 847 > @command(b'debugoptDEP', [(b'', b'dopt', None, b'option is (DEPRECATED)')])
848 848 > @command(b'debugoptEXP', [(b'', b'eopt', None, b'option is (EXPERIMENTAL)')])
849 849 > def nohelp(ui, *args, **kwargs):
850 850 > pass
851 851 >
852 852 > @command(b'hashelp', [], b'hg hashelp', norepo=True)
853 853 > def hashelp(ui, *args, **kwargs):
854 854 > """Extension command's help"""
855 855 >
856 856 > def uisetup(ui):
857 857 > ui.setconfig(b'alias', b'shellalias', b'!echo hi', b'helpext')
858 858 > ui.setconfig(b'alias', b'hgalias', b'summary', b'helpext')
859 859 > ui.setconfig(b'alias', b'hgalias:doc', b'My doc', b'helpext')
860 860 > ui.setconfig(b'alias', b'hgalias:category', b'navigation', b'helpext')
861 861 > ui.setconfig(b'alias', b'hgaliasnodoc', b'summary', b'helpext')
862 862 >
863 863 > EOF
864 864 $ echo '[extensions]' >> $HGRCPATH
865 865 $ echo "helpext = `pwd`/helpext.py" >> $HGRCPATH
866 866
867 867 Test for aliases
868 868
869 869 $ hg help | grep hgalias
870 870 hgalias My doc
871 871
872 872 $ hg help hgalias
873 873 hg hgalias [--remote]
874 874
875 875 alias for: hg summary
876 876
877 877 My doc
878 878
879 879 defined by: helpext
880 880
881 881 options:
882 882
883 883 --remote check for push and pull
884 884
885 885 (some details hidden, use --verbose to show complete help)
886 886 $ hg help hgaliasnodoc
887 887 hg hgaliasnodoc [--remote]
888 888
889 889 alias for: hg summary
890 890
891 891 summarize working directory state
892 892
893 893 This generates a brief summary of the working directory state, including
894 894 parents, branch, commit status, phase and available updates.
895 895
896 896 With the --remote option, this will check the default paths for incoming
897 897 and outgoing changes. This can be time-consuming.
898 898
899 899 Returns 0 on success.
900 900
901 901 defined by: helpext
902 902
903 903 options:
904 904
905 905 --remote check for push and pull
906 906
907 907 (some details hidden, use --verbose to show complete help)
908 908
909 909 $ hg help shellalias
910 910 hg shellalias
911 911
912 912 shell alias for: echo hi
913 913
914 914 (no help text available)
915 915
916 916 defined by: helpext
917 917
918 918 (some details hidden, use --verbose to show complete help)
919 919
920 920 Test command with no help text
921 921
922 922 $ hg help nohelp
923 923 hg nohelp
924 924
925 925 (no help text available)
926 926
927 927 options:
928 928
929 929 --longdesc VALUE
930 930 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
931 931 xxxxxxxxxxxxxxxxxxxxxxx (default: 3)
932 932 -n -- normal desc
933 933 --newline VALUE line1 line2
934 934 --default-off enable X
935 935 --[no-]default-on enable Y (default: on)
936 936 --callableopt VALUE adds foo
937 937 --customopt VALUE adds bar
938 938 --customopt-withdefault VALUE adds bar (default: foo)
939 939
940 940 (some details hidden, use --verbose to show complete help)
941 941
942 942 Test that default list of commands includes extension commands that have help,
943 943 but not those that don't, except in verbose mode, when a keyword is passed, or
944 944 when help about the extension is requested.
945 945
946 946 #if no-extraextensions
947 947
948 948 $ hg help | grep hashelp
949 949 hashelp Extension command's help
950 950 $ hg help | grep nohelp
951 951 [1]
952 952 $ hg help -v | grep nohelp
953 953 nohelp (no help text available)
954 954
955 955 $ hg help -k nohelp
956 956 Commands:
957 957
958 958 nohelp hg nohelp
959 959
960 960 Extension Commands:
961 961
962 962 nohelp (no help text available)
963 963
964 964 $ hg help helpext
965 965 helpext extension - no help text available
966 966
967 967 list of commands:
968 968
969 969 hashelp Extension command's help
970 970 nohelp (no help text available)
971 971
972 972 (use 'hg help -v helpext' to show built-in aliases and global options)
973 973
974 974 #endif
975 975
976 976 Test list of internal help commands
977 977
978 978 $ hg help debug
979 979 debug commands (internal and unsupported):
980 980
981 debug-delta-find
982 display the computation to get to a valid delta for storing REV
981 983 debug-repair-issue6528
982 984 find affected revisions and repair them. See issue6528 for more
983 985 details.
984 986 debugancestor
985 987 find the ancestor revision of two revisions in a given index
986 988 debugantivirusrunning
987 989 attempt to trigger an antivirus scanner to see if one is active
988 990 debugapplystreamclonebundle
989 991 apply a stream clone bundle file
990 992 debugbackupbundle
991 993 lists the changesets available in backup bundles
992 994 debugbuilddag
993 995 builds a repo with a given DAG from scratch in the current
994 996 empty repo
995 997 debugbundle lists the contents of a bundle
996 998 debugcapabilities
997 999 lists the capabilities of a remote peer
998 1000 debugchangedfiles
999 1001 list the stored files changes for a revision
1000 1002 debugcheckstate
1001 1003 validate the correctness of the current dirstate
1002 1004 debugcolor show available color, effects or style
1003 1005 debugcommands
1004 1006 list all available commands and options
1005 1007 debugcomplete
1006 1008 returns the completion list associated with the given command
1007 1009 debugcreatestreamclonebundle
1008 1010 create a stream clone bundle file
1009 1011 debugdag format the changelog or an index DAG as a concise textual
1010 1012 description
1011 1013 debugdata dump the contents of a data file revision
1012 1014 debugdate parse and display a date
1013 1015 debugdeltachain
1014 1016 dump information about delta chains in a revlog
1015 1017 debugdirstate
1016 1018 show the contents of the current dirstate
1017 1019 debugdirstateignorepatternshash
1018 1020 show the hash of ignore patterns stored in dirstate if v2,
1019 1021 debugdiscovery
1020 1022 runs the changeset discovery protocol in isolation
1021 1023 debugdownload
1022 1024 download a resource using Mercurial logic and config
1023 1025 debugextensions
1024 1026 show information about active extensions
1025 1027 debugfileset parse and apply a fileset specification
1026 1028 debugformat display format information about the current repository
1027 1029 debugfsinfo show information detected about current filesystem
1028 1030 debuggetbundle
1029 1031 retrieves a bundle from a repo
1030 1032 debugignore display the combined ignore pattern and information about
1031 1033 ignored files
1032 1034 debugindex dump index data for a storage primitive
1033 1035 debugindexdot
1034 1036 dump an index DAG as a graphviz dot file
1035 1037 debugindexstats
1036 1038 show stats related to the changelog index
1037 1039 debuginstall test Mercurial installation
1038 1040 debugknown test whether node ids are known to a repo
1039 1041 debuglocks show or modify state of locks
1040 1042 debugmanifestfulltextcache
1041 1043 show, clear or amend the contents of the manifest fulltext
1042 1044 cache
1043 1045 debugmergestate
1044 1046 print merge state
1045 1047 debugnamecomplete
1046 1048 complete "names" - tags, open branch names, bookmark names
1047 1049 debugnodemap write and inspect on disk nodemap
1048 1050 debugobsolete
1049 1051 create arbitrary obsolete marker
1050 1052 debugoptADV (no help text available)
1051 1053 debugoptDEP (no help text available)
1052 1054 debugoptEXP (no help text available)
1053 1055 debugp1copies
1054 1056 dump copy information compared to p1
1055 1057 debugp2copies
1056 1058 dump copy information compared to p2
1057 1059 debugpathcomplete
1058 1060 complete part or all of a tracked path
1059 1061 debugpathcopies
1060 1062 show copies between two revisions
1061 1063 debugpeer establish a connection to a peer repository
1062 1064 debugpickmergetool
1063 1065 examine which merge tool is chosen for specified file
1064 1066 debugpushkey access the pushkey key/value protocol
1065 1067 debugpvec (no help text available)
1066 1068 debugrebuilddirstate
1067 1069 rebuild the dirstate as it would look like for the given
1068 1070 revision
1069 1071 debugrebuildfncache
1070 1072 rebuild the fncache file
1071 1073 debugrename dump rename information
1072 1074 debugrequires
1073 1075 print the current repo requirements
1074 1076 debugrevlog show data and statistics about a revlog
1075 1077 debugrevlogindex
1076 1078 dump the contents of a revlog index
1077 1079 debugrevspec parse and apply a revision specification
1078 1080 debugserve run a server with advanced settings
1079 1081 debugsetparents
1080 1082 manually set the parents of the current working directory
1081 1083 (DANGEROUS)
1082 1084 debugshell run an interactive Python interpreter
1083 1085 debugsidedata
1084 1086 dump the side data for a cl/manifest/file revision
1085 1087 debugssl test a secure connection to a server
1086 1088 debugstrip strip changesets and all their descendants from the repository
1087 1089 debugsub (no help text available)
1088 1090 debugsuccessorssets
1089 1091 show set of successors for revision
1090 1092 debugtagscache
1091 1093 display the contents of .hg/cache/hgtagsfnodes1
1092 1094 debugtemplate
1093 1095 parse and apply a template
1094 1096 debuguigetpass
1095 1097 show prompt to type password
1096 1098 debuguiprompt
1097 1099 show plain prompt
1098 1100 debugupdatecaches
1099 1101 warm all known caches in the repository
1100 1102 debugupgraderepo
1101 1103 upgrade a repository to use different features
1102 1104 debugwalk show how files match on given patterns
1103 1105 debugwhyunstable
1104 1106 explain instabilities of a changeset
1105 1107 debugwireargs
1106 1108 (no help text available)
1107 1109 debugwireproto
1108 1110 send wire protocol commands to a server
1109 1111
1110 1112 (use 'hg help -v debug' to show built-in aliases and global options)
1111 1113
1112 1114 internals topic renders index of available sub-topics
1113 1115
1114 1116 $ hg help internals
1115 1117 Technical implementation topics
1116 1118 """""""""""""""""""""""""""""""
1117 1119
1118 1120 To access a subtopic, use "hg help internals.{subtopic-name}"
1119 1121
1120 1122 bid-merge Bid Merge Algorithm
1121 1123 bundle2 Bundle2
1122 1124 bundles Bundles
1123 1125 cbor CBOR
1124 1126 censor Censor
1125 1127 changegroups Changegroups
1126 1128 config Config Registrar
1127 1129 dirstate-v2 dirstate-v2 file format
1128 1130 extensions Extension API
1129 1131 mergestate Mergestate
1130 1132 requirements Repository Requirements
1131 1133 revlogs Revision Logs
1132 1134 wireprotocol Wire Protocol
1133 1135 wireprotocolrpc
1134 1136 Wire Protocol RPC
1135 1137 wireprotocolv2
1136 1138 Wire Protocol Version 2
1137 1139
1138 1140 sub-topics can be accessed
1139 1141
1140 1142 $ hg help internals.changegroups
1141 1143 Changegroups
1142 1144 """"""""""""
1143 1145
1144 1146 Changegroups are representations of repository revlog data, specifically
1145 1147 the changelog data, root/flat manifest data, treemanifest data, and
1146 1148 filelogs.
1147 1149
1148 1150 There are 4 versions of changegroups: "1", "2", "3" and "4". From a high-
1149 1151 level, versions "1" and "2" are almost exactly the same, with the only
1150 1152 difference being an additional item in the *delta header*. Version "3"
1151 1153 adds support for storage flags in the *delta header* and optionally
1152 1154 exchanging treemanifests (enabled by setting an option on the
1153 1155 "changegroup" part in the bundle2). Version "4" adds support for
1154 1156 exchanging sidedata (additional revision metadata not part of the digest).
1155 1157
1156 1158 Changegroups when not exchanging treemanifests consist of 3 logical
1157 1159 segments:
1158 1160
1159 1161 +---------------------------------+
1160 1162 | | | |
1161 1163 | changeset | manifest | filelogs |
1162 1164 | | | |
1163 1165 | | | |
1164 1166 +---------------------------------+
1165 1167
1166 1168 When exchanging treemanifests, there are 4 logical segments:
1167 1169
1168 1170 +-------------------------------------------------+
1169 1171 | | | | |
1170 1172 | changeset | root | treemanifests | filelogs |
1171 1173 | | manifest | | |
1172 1174 | | | | |
1173 1175 +-------------------------------------------------+
1174 1176
1175 1177 The principle building block of each segment is a *chunk*. A *chunk* is a
1176 1178 framed piece of data:
1177 1179
1178 1180 +---------------------------------------+
1179 1181 | | |
1180 1182 | length | data |
1181 1183 | (4 bytes) | (<length - 4> bytes) |
1182 1184 | | |
1183 1185 +---------------------------------------+
1184 1186
1185 1187 All integers are big-endian signed integers. Each chunk starts with a
1186 1188 32-bit integer indicating the length of the entire chunk (including the
1187 1189 length field itself).
1188 1190
1189 1191 There is a special case chunk that has a value of 0 for the length
1190 1192 ("0x00000000"). We call this an *empty chunk*.
1191 1193
1192 1194 Delta Groups
1193 1195 ============
1194 1196
1195 1197 A *delta group* expresses the content of a revlog as a series of deltas,
1196 1198 or patches against previous revisions.
1197 1199
1198 1200 Delta groups consist of 0 or more *chunks* followed by the *empty chunk*
1199 1201 to signal the end of the delta group:
1200 1202
1201 1203 +------------------------------------------------------------------------+
1202 1204 | | | | | |
1203 1205 | chunk0 length | chunk0 data | chunk1 length | chunk1 data | 0x0 |
1204 1206 | (4 bytes) | (various) | (4 bytes) | (various) | (4 bytes) |
1205 1207 | | | | | |
1206 1208 +------------------------------------------------------------------------+
1207 1209
1208 1210 Each *chunk*'s data consists of the following:
1209 1211
1210 1212 +---------------------------------------+
1211 1213 | | |
1212 1214 | delta header | delta data |
1213 1215 | (various by version) | (various) |
1214 1216 | | |
1215 1217 +---------------------------------------+
1216 1218
1217 1219 The *delta data* is a series of *delta*s that describe a diff from an
1218 1220 existing entry (either that the recipient already has, or previously
1219 1221 specified in the bundle/changegroup).
1220 1222
1221 1223 The *delta header* is different between versions "1", "2", "3" and "4" of
1222 1224 the changegroup format.
1223 1225
1224 1226 Version 1 (headerlen=80):
1225 1227
1226 1228 +------------------------------------------------------+
1227 1229 | | | | |
1228 1230 | node | p1 node | p2 node | link node |
1229 1231 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
1230 1232 | | | | |
1231 1233 +------------------------------------------------------+
1232 1234
1233 1235 Version 2 (headerlen=100):
1234 1236
1235 1237 +------------------------------------------------------------------+
1236 1238 | | | | | |
1237 1239 | node | p1 node | p2 node | base node | link node |
1238 1240 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
1239 1241 | | | | | |
1240 1242 +------------------------------------------------------------------+
1241 1243
1242 1244 Version 3 (headerlen=102):
1243 1245
1244 1246 +------------------------------------------------------------------------------+
1245 1247 | | | | | | |
1246 1248 | node | p1 node | p2 node | base node | link node | flags |
1247 1249 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (2 bytes) |
1248 1250 | | | | | | |
1249 1251 +------------------------------------------------------------------------------+
1250 1252
1251 1253 Version 4 (headerlen=103):
1252 1254
1253 1255 +------------------------------------------------------------------------------+----------+
1254 1256 | | | | | | | |
1255 1257 | node | p1 node | p2 node | base node | link node | flags | pflags |
1256 1258 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (2 bytes) | (1 byte) |
1257 1259 | | | | | | | |
1258 1260 +------------------------------------------------------------------------------+----------+
1259 1261
1260 1262 The *delta data* consists of "chunklen - 4 - headerlen" bytes, which
1261 1263 contain a series of *delta*s, densely packed (no separators). These deltas
1262 1264 describe a diff from an existing entry (either that the recipient already
1263 1265 has, or previously specified in the bundle/changegroup). The format is
1264 1266 described more fully in "hg help internals.bdiff", but briefly:
1265 1267
1266 1268 +---------------------------------------------------------------+
1267 1269 | | | | |
1268 1270 | start offset | end offset | new length | content |
1269 1271 | (4 bytes) | (4 bytes) | (4 bytes) | (<new length> bytes) |
1270 1272 | | | | |
1271 1273 +---------------------------------------------------------------+
1272 1274
1273 1275 Please note that the length field in the delta data does *not* include
1274 1276 itself.
1275 1277
1276 1278 In version 1, the delta is always applied against the previous node from
1277 1279 the changegroup or the first parent if this is the first entry in the
1278 1280 changegroup.
1279 1281
1280 1282 In version 2 and up, the delta base node is encoded in the entry in the
1281 1283 changegroup. This allows the delta to be expressed against any parent,
1282 1284 which can result in smaller deltas and more efficient encoding of data.
1283 1285
1284 1286 The *flags* field holds bitwise flags affecting the processing of revision
1285 1287 data. The following flags are defined:
1286 1288
1287 1289 32768
1288 1290 Censored revision. The revision's fulltext has been replaced by censor
1289 1291 metadata. May only occur on file revisions.
1290 1292
1291 1293 16384
1292 1294 Ellipsis revision. Revision hash does not match data (likely due to
1293 1295 rewritten parents).
1294 1296
1295 1297 8192
1296 1298 Externally stored. The revision fulltext contains "key:value" "\n"
1297 1299 delimited metadata defining an object stored elsewhere. Used by the LFS
1298 1300 extension.
1299 1301
1300 1302 4096
1301 1303 Contains copy information. This revision changes files in a way that
1302 1304 could affect copy tracing. This does *not* affect changegroup handling,
1303 1305 but is relevant for other parts of Mercurial.
1304 1306
1305 1307 For historical reasons, the integer values are identical to revlog version
1306 1308 1 per-revision storage flags and correspond to bits being set in this
1307 1309 2-byte field. Bits were allocated starting from the most-significant bit,
1308 1310 hence the reverse ordering and allocation of these flags.
1309 1311
1310 1312 The *pflags* (protocol flags) field holds bitwise flags affecting the
1311 1313 protocol itself. They are first in the header since they may affect the
1312 1314 handling of the rest of the fields in a future version. They are defined
1313 1315 as such:
1314 1316
1315 1317 1 indicates whether to read a chunk of sidedata (of variable length) right
1316 1318 after the revision flags.
1317 1319
1318 1320 Changeset Segment
1319 1321 =================
1320 1322
1321 1323 The *changeset segment* consists of a single *delta group* holding
1322 1324 changelog data. The *empty chunk* at the end of the *delta group* denotes
1323 1325 the boundary to the *manifest segment*.
1324 1326
1325 1327 Manifest Segment
1326 1328 ================
1327 1329
1328 1330 The *manifest segment* consists of a single *delta group* holding manifest
1329 1331 data. If treemanifests are in use, it contains only the manifest for the
1330 1332 root directory of the repository. Otherwise, it contains the entire
1331 1333 manifest data. The *empty chunk* at the end of the *delta group* denotes
1332 1334 the boundary to the next segment (either the *treemanifests segment* or
1333 1335 the *filelogs segment*, depending on version and the request options).
1334 1336
1335 1337 Treemanifests Segment
1336 1338 ---------------------
1337 1339
1338 1340 The *treemanifests segment* only exists in changegroup version "3" and
1339 1341 "4", and only if the 'treemanifest' param is part of the bundle2
1340 1342 changegroup part (it is not possible to use changegroup version 3 or 4
1341 1343 outside of bundle2). Aside from the filenames in the *treemanifests
1342 1344 segment* containing a trailing "/" character, it behaves identically to
1343 1345 the *filelogs segment* (see below). The final sub-segment is followed by
1344 1346 an *empty chunk* (logically, a sub-segment with filename size 0). This
1345 1347 denotes the boundary to the *filelogs segment*.
1346 1348
1347 1349 Filelogs Segment
1348 1350 ================
1349 1351
1350 1352 The *filelogs segment* consists of multiple sub-segments, each
1351 1353 corresponding to an individual file whose data is being described:
1352 1354
1353 1355 +--------------------------------------------------+
1354 1356 | | | | | |
1355 1357 | filelog0 | filelog1 | filelog2 | ... | 0x0 |
1356 1358 | | | | | (4 bytes) |
1357 1359 | | | | | |
1358 1360 +--------------------------------------------------+
1359 1361
1360 1362 The final filelog sub-segment is followed by an *empty chunk* (logically,
1361 1363 a sub-segment with filename size 0). This denotes the end of the segment
1362 1364 and of the overall changegroup.
1363 1365
1364 1366 Each filelog sub-segment consists of the following:
1365 1367
1366 1368 +------------------------------------------------------+
1367 1369 | | | |
1368 1370 | filename length | filename | delta group |
1369 1371 | (4 bytes) | (<length - 4> bytes) | (various) |
1370 1372 | | | |
1371 1373 +------------------------------------------------------+
1372 1374
1373 1375 That is, a *chunk* consisting of the filename (not terminated or padded)
1374 1376 followed by N chunks constituting the *delta group* for this file. The
1375 1377 *empty chunk* at the end of each *delta group* denotes the boundary to the
1376 1378 next filelog sub-segment.
1377 1379
1378 1380 non-existent subtopics print an error
1379 1381
1380 1382 $ hg help internals.foo
1381 1383 abort: no such help topic: internals.foo
1382 1384 (try 'hg help --keyword foo')
1383 1385 [10]
1384 1386
1385 1387 test advanced, deprecated and experimental options are hidden in command help
1386 1388 $ hg help debugoptADV
1387 1389 hg debugoptADV
1388 1390
1389 1391 (no help text available)
1390 1392
1391 1393 options:
1392 1394
1393 1395 (some details hidden, use --verbose to show complete help)
1394 1396 $ hg help debugoptDEP
1395 1397 hg debugoptDEP
1396 1398
1397 1399 (no help text available)
1398 1400
1399 1401 options:
1400 1402
1401 1403 (some details hidden, use --verbose to show complete help)
1402 1404
1403 1405 $ hg help debugoptEXP
1404 1406 hg debugoptEXP
1405 1407
1406 1408 (no help text available)
1407 1409
1408 1410 options:
1409 1411
1410 1412 (some details hidden, use --verbose to show complete help)
1411 1413
1412 1414 test advanced, deprecated and experimental options are shown with -v
1413 1415 $ hg help -v debugoptADV | grep aopt
1414 1416 --aopt option is (ADVANCED)
1415 1417 $ hg help -v debugoptDEP | grep dopt
1416 1418 --dopt option is (DEPRECATED)
1417 1419 $ hg help -v debugoptEXP | grep eopt
1418 1420 --eopt option is (EXPERIMENTAL)
1419 1421
1420 1422 #if gettext
1421 1423 test deprecated option is hidden with translation with untranslated description
1422 1424 (use many globy for not failing on changed transaction)
1423 1425 $ LANGUAGE=sv hg help debugoptDEP
1424 1426 hg debugoptDEP
1425 1427
1426 1428 (*) (glob)
1427 1429
1428 1430 options:
1429 1431
1430 1432 (some details hidden, use --verbose to show complete help)
1431 1433 #endif
1432 1434
1433 1435 Test commands that collide with topics (issue4240)
1434 1436
1435 1437 $ hg config -hq
1436 1438 hg config [-u] [NAME]...
1437 1439
1438 1440 show combined config settings from all hgrc files
1439 1441 $ hg showconfig -hq
1440 1442 hg config [-u] [NAME]...
1441 1443
1442 1444 show combined config settings from all hgrc files
1443 1445
1444 1446 Test a help topic
1445 1447
1446 1448 $ hg help dates
1447 1449 Date Formats
1448 1450 """"""""""""
1449 1451
1450 1452 Some commands allow the user to specify a date, e.g.:
1451 1453
1452 1454 - backout, commit, import, tag: Specify the commit date.
1453 1455 - log, revert, update: Select revision(s) by date.
1454 1456
1455 1457 Many date formats are valid. Here are some examples:
1456 1458
1457 1459 - "Wed Dec 6 13:18:29 2006" (local timezone assumed)
1458 1460 - "Dec 6 13:18 -0600" (year assumed, time offset provided)
1459 1461 - "Dec 6 13:18 UTC" (UTC and GMT are aliases for +0000)
1460 1462 - "Dec 6" (midnight)
1461 1463 - "13:18" (today assumed)
1462 1464 - "3:39" (3:39AM assumed)
1463 1465 - "3:39pm" (15:39)
1464 1466 - "2006-12-06 13:18:29" (ISO 8601 format)
1465 1467 - "2006-12-6 13:18"
1466 1468 - "2006-12-6"
1467 1469 - "12-6"
1468 1470 - "12/6"
1469 1471 - "12/6/6" (Dec 6 2006)
1470 1472 - "today" (midnight)
1471 1473 - "yesterday" (midnight)
1472 1474 - "now" - right now
1473 1475
1474 1476 Lastly, there is Mercurial's internal format:
1475 1477
1476 1478 - "1165411109 0" (Wed Dec 6 13:18:29 2006 UTC)
1477 1479
1478 1480 This is the internal representation format for dates. The first number is
1479 1481 the number of seconds since the epoch (1970-01-01 00:00 UTC). The second
1480 1482 is the offset of the local timezone, in seconds west of UTC (negative if
1481 1483 the timezone is east of UTC).
1482 1484
1483 1485 The log command also accepts date ranges:
1484 1486
1485 1487 - "<DATE" - at or before a given date/time
1486 1488 - ">DATE" - on or after a given date/time
1487 1489 - "DATE to DATE" - a date range, inclusive
1488 1490 - "-DAYS" - within a given number of days from today
1489 1491
1490 1492 Test repeated config section name
1491 1493
1492 1494 $ hg help config.host
1493 1495 "http_proxy.host"
1494 1496 Host name and (optional) port of the proxy server, for example
1495 1497 "myproxy:8000".
1496 1498
1497 1499 "smtp.host"
1498 1500 Host name of mail server, e.g. "mail.example.com".
1499 1501
1500 1502
1501 1503 Test section name with dot
1502 1504
1503 1505 $ hg help config.ui.username
1504 1506 "ui.username"
1505 1507 The committer of a changeset created when running "commit". Typically
1506 1508 a person's name and email address, e.g. "Fred Widget
1507 1509 <fred@example.com>". Environment variables in the username are
1508 1510 expanded.
1509 1511
1510 1512 (default: "$EMAIL" or "username@hostname". If the username in hgrc is
1511 1513 empty, e.g. if the system admin set "username =" in the system hgrc,
1512 1514 it has to be specified manually or in a different hgrc file)
1513 1515
1514 1516
1515 1517 $ hg help config.annotate.git
1516 1518 abort: help section not found: config.annotate.git
1517 1519 [10]
1518 1520
1519 1521 $ hg help config.update.check
1520 1522 "commands.update.check"
1521 1523 Determines what level of checking 'hg update' will perform before
1522 1524 moving to a destination revision. Valid values are "abort", "none",
1523 1525 "linear", and "noconflict".
1524 1526
1525 1527 - "abort" always fails if the working directory has uncommitted
1526 1528 changes.
1527 1529 - "none" performs no checking, and may result in a merge with
1528 1530 uncommitted changes.
1529 1531 - "linear" allows any update as long as it follows a straight line in
1530 1532 the revision history, and may trigger a merge with uncommitted
1531 1533 changes.
1532 1534 - "noconflict" will allow any update which would not trigger a merge
1533 1535 with uncommitted changes, if any are present.
1534 1536
1535 1537 (default: "linear")
1536 1538
1537 1539
1538 1540 $ hg help config.commands.update.check
1539 1541 "commands.update.check"
1540 1542 Determines what level of checking 'hg update' will perform before
1541 1543 moving to a destination revision. Valid values are "abort", "none",
1542 1544 "linear", and "noconflict".
1543 1545
1544 1546 - "abort" always fails if the working directory has uncommitted
1545 1547 changes.
1546 1548 - "none" performs no checking, and may result in a merge with
1547 1549 uncommitted changes.
1548 1550 - "linear" allows any update as long as it follows a straight line in
1549 1551 the revision history, and may trigger a merge with uncommitted
1550 1552 changes.
1551 1553 - "noconflict" will allow any update which would not trigger a merge
1552 1554 with uncommitted changes, if any are present.
1553 1555
1554 1556 (default: "linear")
1555 1557
1556 1558
1557 1559 $ hg help config.ommands.update.check
1558 1560 abort: help section not found: config.ommands.update.check
1559 1561 [10]
1560 1562
1561 1563 Unrelated trailing paragraphs shouldn't be included
1562 1564
1563 1565 $ hg help config.extramsg | grep '^$'
1564 1566
1565 1567
1566 1568 Test capitalized section name
1567 1569
1568 1570 $ hg help scripting.HGPLAIN > /dev/null
1569 1571
1570 1572 Help subsection:
1571 1573
1572 1574 $ hg help config.charsets |grep "Email example:" > /dev/null
1573 1575 [1]
1574 1576
1575 1577 Show nested definitions
1576 1578 ("profiling.type"[break]"ls"[break]"stat"[break])
1577 1579
1578 1580 $ hg help config.type | egrep '^$'|wc -l
1579 1581 \s*3 (re)
1580 1582
1581 1583 $ hg help config.profiling.type.ls
1582 1584 "profiling.type.ls"
1583 1585 Use Python's built-in instrumenting profiler. This profiler works on
1584 1586 all platforms, but each line number it reports is the first line of
1585 1587 a function. This restriction makes it difficult to identify the
1586 1588 expensive parts of a non-trivial function.
1587 1589
1588 1590
1589 1591 Separate sections from subsections
1590 1592
1591 1593 $ hg help config.format | egrep '^ ("|-)|^\s*$' | uniq
1592 1594 "format"
1593 1595 --------
1594 1596
1595 1597 "usegeneraldelta"
1596 1598
1597 1599 "dotencode"
1598 1600
1599 1601 "usefncache"
1600 1602
1601 1603 "use-dirstate-v2"
1602 1604
1603 1605 "use-dirstate-v2.automatic-upgrade-of-mismatching-repositories"
1604 1606
1605 1607 "use-dirstate-tracked-hint"
1606 1608
1607 1609 "use-dirstate-tracked-hint.automatic-upgrade-of-mismatching-repositories"
1608 1610
1609 1611 "use-persistent-nodemap"
1610 1612
1611 1613 "use-share-safe"
1612 1614
1613 1615 "use-share-safe.automatic-upgrade-of-mismatching-repositories"
1614 1616
1615 1617 "usestore"
1616 1618
1617 1619 "sparse-revlog"
1618 1620
1619 1621 "revlog-compression"
1620 1622
1621 1623 "bookmarks-in-store"
1622 1624
1623 1625 "profiling"
1624 1626 -----------
1625 1627
1626 1628 "format"
1627 1629
1628 1630 "progress"
1629 1631 ----------
1630 1632
1631 1633 "format"
1632 1634
1633 1635
1634 1636 Last item in help config.*:
1635 1637
1636 1638 $ hg help config.`hg help config|grep '^ "'| \
1637 1639 > tail -1|sed 's![ "]*!!g'`| \
1638 1640 > grep 'hg help -c config' > /dev/null
1639 1641 [1]
1640 1642
1641 1643 note to use help -c for general hg help config:
1642 1644
1643 1645 $ hg help config |grep 'hg help -c config' > /dev/null
1644 1646
1645 1647 Test templating help
1646 1648
1647 1649 $ hg help templating | egrep '(desc|diffstat|firstline|nonempty) '
1648 1650 desc String. The text of the changeset description.
1649 1651 diffstat String. Statistics of changes with the following format:
1650 1652 firstline Any text. Returns the first line of text.
1651 1653 nonempty Any text. Returns '(none)' if the string is empty.
1652 1654
1653 1655 Test deprecated items
1654 1656
1655 1657 $ hg help -v templating | grep currentbookmark
1656 1658 currentbookmark
1657 1659 $ hg help templating | (grep currentbookmark || true)
1658 1660
1659 1661 Test help hooks
1660 1662
1661 1663 $ cat > helphook1.py <<EOF
1662 1664 > from mercurial import help
1663 1665 >
1664 1666 > def rewrite(ui, topic, doc):
1665 1667 > return doc + b'\nhelphook1\n'
1666 1668 >
1667 1669 > def extsetup(ui):
1668 1670 > help.addtopichook(b'revisions', rewrite)
1669 1671 > EOF
1670 1672 $ cat > helphook2.py <<EOF
1671 1673 > from mercurial import help
1672 1674 >
1673 1675 > def rewrite(ui, topic, doc):
1674 1676 > return doc + b'\nhelphook2\n'
1675 1677 >
1676 1678 > def extsetup(ui):
1677 1679 > help.addtopichook(b'revisions', rewrite)
1678 1680 > EOF
1679 1681 $ echo '[extensions]' >> $HGRCPATH
1680 1682 $ echo "helphook1 = `pwd`/helphook1.py" >> $HGRCPATH
1681 1683 $ echo "helphook2 = `pwd`/helphook2.py" >> $HGRCPATH
1682 1684 $ hg help revsets | grep helphook
1683 1685 helphook1
1684 1686 helphook2
1685 1687
1686 1688 help -c should only show debug --debug
1687 1689
1688 1690 $ hg help -c --debug|egrep debug|wc -l|egrep '^\s*0\s*$'
1689 1691 [1]
1690 1692
1691 1693 help -c should only show deprecated for -v
1692 1694
1693 1695 $ hg help -c -v|egrep DEPRECATED|wc -l|egrep '^\s*0\s*$'
1694 1696 [1]
1695 1697
1696 1698 Test -s / --system
1697 1699
1698 1700 $ hg help config.files -s windows |grep 'etc/mercurial' | \
1699 1701 > wc -l | sed -e 's/ //g'
1700 1702 0
1701 1703 $ hg help config.files --system unix | grep 'USER' | \
1702 1704 > wc -l | sed -e 's/ //g'
1703 1705 0
1704 1706
1705 1707 Test -e / -c / -k combinations
1706 1708
1707 1709 $ hg help -c|egrep '^[A-Z].*:|^ debug'
1708 1710 Commands:
1709 1711 $ hg help -e|egrep '^[A-Z].*:|^ debug'
1710 1712 Extensions:
1711 1713 $ hg help -k|egrep '^[A-Z].*:|^ debug'
1712 1714 Topics:
1713 1715 Commands:
1714 1716 Extensions:
1715 1717 Extension Commands:
1716 1718 $ hg help -c schemes
1717 1719 abort: no such help topic: schemes
1718 1720 (try 'hg help --keyword schemes')
1719 1721 [10]
1720 1722 $ hg help -e schemes |head -1
1721 1723 schemes extension - extend schemes with shortcuts to repository swarms
1722 1724 $ hg help -c -k dates |egrep '^(Topics|Extensions|Commands):'
1723 1725 Commands:
1724 1726 $ hg help -e -k a |egrep '^(Topics|Extensions|Commands):'
1725 1727 Extensions:
1726 1728 $ hg help -e -c -k date |egrep '^(Topics|Extensions|Commands):'
1727 1729 Extensions:
1728 1730 Commands:
1729 1731 $ hg help -c commit > /dev/null
1730 1732 $ hg help -e -c commit > /dev/null
1731 1733 $ hg help -e commit
1732 1734 abort: no such help topic: commit
1733 1735 (try 'hg help --keyword commit')
1734 1736 [10]
1735 1737
1736 1738 Test keyword search help
1737 1739
1738 1740 $ cat > prefixedname.py <<EOF
1739 1741 > '''matched against word "clone"
1740 1742 > '''
1741 1743 > EOF
1742 1744 $ echo '[extensions]' >> $HGRCPATH
1743 1745 $ echo "dot.dot.prefixedname = `pwd`/prefixedname.py" >> $HGRCPATH
1744 1746 $ hg help -k clone
1745 1747 Topics:
1746 1748
1747 1749 config Configuration Files
1748 1750 extensions Using Additional Features
1749 1751 glossary Glossary
1750 1752 phases Working with Phases
1751 1753 subrepos Subrepositories
1752 1754 urls URL Paths
1753 1755
1754 1756 Commands:
1755 1757
1756 1758 bookmarks create a new bookmark or list existing bookmarks
1757 1759 clone make a copy of an existing repository
1758 1760 paths show aliases for remote repositories
1759 1761 pull pull changes from the specified source
1760 1762 update update working directory (or switch revisions)
1761 1763
1762 1764 Extensions:
1763 1765
1764 1766 clonebundles advertise pre-generated bundles to seed clones
1765 1767 narrow create clones which fetch history data for subset of files
1766 1768 (EXPERIMENTAL)
1767 1769 prefixedname matched against word "clone"
1768 1770 relink recreates hardlinks between repository clones
1769 1771
1770 1772 Extension Commands:
1771 1773
1772 1774 qclone clone main and patch repository at same time
1773 1775
1774 1776 Test unfound topic
1775 1777
1776 1778 $ hg help nonexistingtopicthatwillneverexisteverever
1777 1779 abort: no such help topic: nonexistingtopicthatwillneverexisteverever
1778 1780 (try 'hg help --keyword nonexistingtopicthatwillneverexisteverever')
1779 1781 [10]
1780 1782
1781 1783 Test unfound keyword
1782 1784
1783 1785 $ hg help --keyword nonexistingwordthatwillneverexisteverever
1784 1786 abort: no matches
1785 1787 (try 'hg help' for a list of topics)
1786 1788 [10]
1787 1789
1788 1790 Test omit indicating for help
1789 1791
1790 1792 $ cat > addverboseitems.py <<EOF
1791 1793 > r'''extension to test omit indicating.
1792 1794 >
1793 1795 > This paragraph is never omitted (for extension)
1794 1796 >
1795 1797 > .. container:: verbose
1796 1798 >
1797 1799 > This paragraph is omitted,
1798 1800 > if :hg:\`help\` is invoked without \`\`-v\`\` (for extension)
1799 1801 >
1800 1802 > This paragraph is never omitted, too (for extension)
1801 1803 > '''
1802 1804 > from mercurial import commands, help
1803 1805 > testtopic = br"""This paragraph is never omitted (for topic).
1804 1806 >
1805 1807 > .. container:: verbose
1806 1808 >
1807 1809 > This paragraph is omitted,
1808 1810 > if :hg:\`help\` is invoked without \`\`-v\`\` (for topic)
1809 1811 >
1810 1812 > This paragraph is never omitted, too (for topic)
1811 1813 > """
1812 1814 > def extsetup(ui):
1813 1815 > help.helptable.append(([b"topic-containing-verbose"],
1814 1816 > b"This is the topic to test omit indicating.",
1815 1817 > lambda ui: testtopic))
1816 1818 > EOF
1817 1819 $ echo '[extensions]' >> $HGRCPATH
1818 1820 $ echo "addverboseitems = `pwd`/addverboseitems.py" >> $HGRCPATH
1819 1821 $ hg help addverboseitems
1820 1822 addverboseitems extension - extension to test omit indicating.
1821 1823
1822 1824 This paragraph is never omitted (for extension)
1823 1825
1824 1826 This paragraph is never omitted, too (for extension)
1825 1827
1826 1828 (some details hidden, use --verbose to show complete help)
1827 1829
1828 1830 no commands defined
1829 1831 $ hg help -v addverboseitems
1830 1832 addverboseitems extension - extension to test omit indicating.
1831 1833
1832 1834 This paragraph is never omitted (for extension)
1833 1835
1834 1836 This paragraph is omitted, if 'hg help' is invoked without "-v" (for
1835 1837 extension)
1836 1838
1837 1839 This paragraph is never omitted, too (for extension)
1838 1840
1839 1841 no commands defined
1840 1842 $ hg help topic-containing-verbose
1841 1843 This is the topic to test omit indicating.
1842 1844 """"""""""""""""""""""""""""""""""""""""""
1843 1845
1844 1846 This paragraph is never omitted (for topic).
1845 1847
1846 1848 This paragraph is never omitted, too (for topic)
1847 1849
1848 1850 (some details hidden, use --verbose to show complete help)
1849 1851 $ hg help -v topic-containing-verbose
1850 1852 This is the topic to test omit indicating.
1851 1853 """"""""""""""""""""""""""""""""""""""""""
1852 1854
1853 1855 This paragraph is never omitted (for topic).
1854 1856
1855 1857 This paragraph is omitted, if 'hg help' is invoked without "-v" (for
1856 1858 topic)
1857 1859
1858 1860 This paragraph is never omitted, too (for topic)
1859 1861
1860 1862 Test section lookup
1861 1863
1862 1864 $ hg help revset.merge
1863 1865 "merge()"
1864 1866 Changeset is a merge changeset.
1865 1867
1866 1868 $ hg help glossary.dag
1867 1869 DAG
1868 1870 The repository of changesets of a distributed version control system
1869 1871 (DVCS) can be described as a directed acyclic graph (DAG), consisting
1870 1872 of nodes and edges, where nodes correspond to changesets and edges
1871 1873 imply a parent -> child relation. This graph can be visualized by
1872 1874 graphical tools such as 'hg log --graph'. In Mercurial, the DAG is
1873 1875 limited by the requirement for children to have at most two parents.
1874 1876
1875 1877
1876 1878 $ hg help hgrc.paths
1877 1879 "paths"
1878 1880 -------
1879 1881
1880 1882 Assigns symbolic names and behavior to repositories.
1881 1883
1882 1884 Options are symbolic names defining the URL or directory that is the
1883 1885 location of the repository. Example:
1884 1886
1885 1887 [paths]
1886 1888 my_server = https://example.com/my_repo
1887 1889 local_path = /home/me/repo
1888 1890
1889 1891 These symbolic names can be used from the command line. To pull from
1890 1892 "my_server": 'hg pull my_server'. To push to "local_path": 'hg push
1891 1893 local_path'. You can check 'hg help urls' for details about valid URLs.
1892 1894
1893 1895 Options containing colons (":") denote sub-options that can influence
1894 1896 behavior for that specific path. Example:
1895 1897
1896 1898 [paths]
1897 1899 my_server = https://example.com/my_path
1898 1900 my_server:pushurl = ssh://example.com/my_path
1899 1901
1900 1902 Paths using the 'path://otherpath' scheme will inherit the sub-options
1901 1903 value from the path they point to.
1902 1904
1903 1905 The following sub-options can be defined:
1904 1906
1905 1907 "multi-urls"
1906 1908 A boolean option. When enabled the value of the '[paths]' entry will be
1907 1909 parsed as a list and the alias will resolve to multiple destination. If
1908 1910 some of the list entry use the 'path://' syntax, the suboption will be
1909 1911 inherited individually.
1910 1912
1911 1913 "pushurl"
1912 1914 The URL to use for push operations. If not defined, the location
1913 1915 defined by the path's main entry is used.
1914 1916
1915 1917 "pushrev"
1916 1918 A revset defining which revisions to push by default.
1917 1919
1918 1920 When 'hg push' is executed without a "-r" argument, the revset defined
1919 1921 by this sub-option is evaluated to determine what to push.
1920 1922
1921 1923 For example, a value of "." will push the working directory's revision
1922 1924 by default.
1923 1925
1924 1926 Revsets specifying bookmarks will not result in the bookmark being
1925 1927 pushed.
1926 1928
1927 1929 "bookmarks.mode"
1928 1930 How bookmark will be dealt during the exchange. It support the following
1929 1931 value
1930 1932
1931 1933 - "default": the default behavior, local and remote bookmarks are
1932 1934 "merged" on push/pull.
1933 1935 - "mirror": when pulling, replace local bookmarks by remote bookmarks.
1934 1936 This is useful to replicate a repository, or as an optimization.
1935 1937 - "ignore": ignore bookmarks during exchange. (This currently only
1936 1938 affect pulling)
1937 1939
1938 1940 The following special named paths exist:
1939 1941
1940 1942 "default"
1941 1943 The URL or directory to use when no source or remote is specified.
1942 1944
1943 1945 'hg clone' will automatically define this path to the location the
1944 1946 repository was cloned from.
1945 1947
1946 1948 "default-push"
1947 1949 (deprecated) The URL or directory for the default 'hg push' location.
1948 1950 "default:pushurl" should be used instead.
1949 1951
1950 1952 $ hg help glossary.mcguffin
1951 1953 abort: help section not found: glossary.mcguffin
1952 1954 [10]
1953 1955
1954 1956 $ hg help glossary.mc.guffin
1955 1957 abort: help section not found: glossary.mc.guffin
1956 1958 [10]
1957 1959
1958 1960 $ hg help template.files
1959 1961 files List of strings. All files modified, added, or removed by
1960 1962 this changeset.
1961 1963 files(pattern)
1962 1964 All files of the current changeset matching the pattern. See
1963 1965 'hg help patterns'.
1964 1966
1965 1967 Test section lookup by translated message
1966 1968
1967 1969 str.lower() instead of encoding.lower(str) on translated message might
1968 1970 make message meaningless, because some encoding uses 0x41(A) - 0x5a(Z)
1969 1971 as the second or later byte of multi-byte character.
1970 1972
1971 1973 For example, "\x8bL\x98^" (translation of "record" in ja_JP.cp932)
1972 1974 contains 0x4c (L). str.lower() replaces 0x4c(L) by 0x6c(l) and this
1973 1975 replacement makes message meaningless.
1974 1976
1975 1977 This tests that section lookup by translated string isn't broken by
1976 1978 such str.lower().
1977 1979
1978 1980 $ "$PYTHON" <<EOF
1979 1981 > def escape(s):
1980 1982 > return b''.join(b'\\u%x' % ord(uc) for uc in s.decode('cp932'))
1981 1983 > # translation of "record" in ja_JP.cp932
1982 1984 > upper = b"\x8bL\x98^"
1983 1985 > # str.lower()-ed section name should be treated as different one
1984 1986 > lower = b"\x8bl\x98^"
1985 1987 > with open('ambiguous.py', 'wb') as fp:
1986 1988 > fp.write(b"""# ambiguous section names in ja_JP.cp932
1987 1989 > u'''summary of extension
1988 1990 >
1989 1991 > %s
1990 1992 > ----
1991 1993 >
1992 1994 > Upper name should show only this message
1993 1995 >
1994 1996 > %s
1995 1997 > ----
1996 1998 >
1997 1999 > Lower name should show only this message
1998 2000 >
1999 2001 > subsequent section
2000 2002 > ------------------
2001 2003 >
2002 2004 > This should be hidden at 'hg help ambiguous' with section name.
2003 2005 > '''
2004 2006 > """ % (escape(upper), escape(lower)))
2005 2007 > EOF
2006 2008
2007 2009 $ cat >> $HGRCPATH <<EOF
2008 2010 > [extensions]
2009 2011 > ambiguous = ./ambiguous.py
2010 2012 > EOF
2011 2013
2012 2014 $ "$PYTHON" <<EOF | sh
2013 2015 > from mercurial.utils import procutil
2014 2016 > upper = b"\x8bL\x98^"
2015 2017 > procutil.stdout.write(b"hg --encoding cp932 help -e ambiguous.%s\n" % upper)
2016 2018 > EOF
2017 2019 \x8bL\x98^ (esc)
2018 2020 ----
2019 2021
2020 2022 Upper name should show only this message
2021 2023
2022 2024
2023 2025 $ "$PYTHON" <<EOF | sh
2024 2026 > from mercurial.utils import procutil
2025 2027 > lower = b"\x8bl\x98^"
2026 2028 > procutil.stdout.write(b"hg --encoding cp932 help -e ambiguous.%s\n" % lower)
2027 2029 > EOF
2028 2030 \x8bl\x98^ (esc)
2029 2031 ----
2030 2032
2031 2033 Lower name should show only this message
2032 2034
2033 2035
2034 2036 $ cat >> $HGRCPATH <<EOF
2035 2037 > [extensions]
2036 2038 > ambiguous = !
2037 2039 > EOF
2038 2040
2039 2041 Show help content of disabled extensions
2040 2042
2041 2043 $ cat >> $HGRCPATH <<EOF
2042 2044 > [extensions]
2043 2045 > ambiguous = !./ambiguous.py
2044 2046 > EOF
2045 2047 $ hg help -e ambiguous
2046 2048 ambiguous extension - (no help text available)
2047 2049
2048 2050 (use 'hg help extensions' for information on enabling extensions)
2049 2051
2050 2052 Test dynamic list of merge tools only shows up once
2051 2053 $ hg help merge-tools
2052 2054 Merge Tools
2053 2055 """""""""""
2054 2056
2055 2057 To merge files Mercurial uses merge tools.
2056 2058
2057 2059 A merge tool combines two different versions of a file into a merged file.
2058 2060 Merge tools are given the two files and the greatest common ancestor of
2059 2061 the two file versions, so they can determine the changes made on both
2060 2062 branches.
2061 2063
2062 2064 Merge tools are used both for 'hg resolve', 'hg merge', 'hg update', 'hg
2063 2065 backout' and in several extensions.
2064 2066
2065 2067 Usually, the merge tool tries to automatically reconcile the files by
2066 2068 combining all non-overlapping changes that occurred separately in the two
2067 2069 different evolutions of the same initial base file. Furthermore, some
2068 2070 interactive merge programs make it easier to manually resolve conflicting
2069 2071 merges, either in a graphical way, or by inserting some conflict markers.
2070 2072 Mercurial does not include any interactive merge programs but relies on
2071 2073 external tools for that.
2072 2074
2073 2075 Available merge tools
2074 2076 =====================
2075 2077
2076 2078 External merge tools and their properties are configured in the merge-
2077 2079 tools configuration section - see hgrc(5) - but they can often just be
2078 2080 named by their executable.
2079 2081
2080 2082 A merge tool is generally usable if its executable can be found on the
2081 2083 system and if it can handle the merge. The executable is found if it is an
2082 2084 absolute or relative executable path or the name of an application in the
2083 2085 executable search path. The tool is assumed to be able to handle the merge
2084 2086 if it can handle symlinks if the file is a symlink, if it can handle
2085 2087 binary files if the file is binary, and if a GUI is available if the tool
2086 2088 requires a GUI.
2087 2089
2088 2090 There are some internal merge tools which can be used. The internal merge
2089 2091 tools are:
2090 2092
2091 2093 ":dump"
2092 2094 Creates three versions of the files to merge, containing the contents of
2093 2095 local, other and base. These files can then be used to perform a merge
2094 2096 manually. If the file to be merged is named "a.txt", these files will
2095 2097 accordingly be named "a.txt.local", "a.txt.other" and "a.txt.base" and
2096 2098 they will be placed in the same directory as "a.txt".
2097 2099
2098 2100 This implies premerge. Therefore, files aren't dumped, if premerge runs
2099 2101 successfully. Use :forcedump to forcibly write files out.
2100 2102
2101 2103 (actual capabilities: binary, symlink)
2102 2104
2103 2105 ":fail"
2104 2106 Rather than attempting to merge files that were modified on both
2105 2107 branches, it marks them as unresolved. The resolve command must be used
2106 2108 to resolve these conflicts.
2107 2109
2108 2110 (actual capabilities: binary, symlink)
2109 2111
2110 2112 ":forcedump"
2111 2113 Creates three versions of the files as same as :dump, but omits
2112 2114 premerge.
2113 2115
2114 2116 (actual capabilities: binary, symlink)
2115 2117
2116 2118 ":local"
2117 2119 Uses the local 'p1()' version of files as the merged version.
2118 2120
2119 2121 (actual capabilities: binary, symlink)
2120 2122
2121 2123 ":merge"
2122 2124 Uses the internal non-interactive simple merge algorithm for merging
2123 2125 files. It will fail if there are any conflicts and leave markers in the
2124 2126 partially merged file. Markers will have two sections, one for each side
2125 2127 of merge.
2126 2128
2127 2129 ":merge-local"
2128 2130 Like :merge, but resolve all conflicts non-interactively in favor of the
2129 2131 local 'p1()' changes.
2130 2132
2131 2133 ":merge-other"
2132 2134 Like :merge, but resolve all conflicts non-interactively in favor of the
2133 2135 other 'p2()' changes.
2134 2136
2135 2137 ":merge3"
2136 2138 Uses the internal non-interactive simple merge algorithm for merging
2137 2139 files. It will fail if there are any conflicts and leave markers in the
2138 2140 partially merged file. Marker will have three sections, one from each
2139 2141 side of the merge and one for the base content.
2140 2142
2141 2143 ":mergediff"
2142 2144 Uses the internal non-interactive simple merge algorithm for merging
2143 2145 files. It will fail if there are any conflicts and leave markers in the
2144 2146 partially merged file. The marker will have two sections, one with the
2145 2147 content from one side of the merge, and one with a diff from the base
2146 2148 content to the content on the other side. (experimental)
2147 2149
2148 2150 ":other"
2149 2151 Uses the other 'p2()' version of files as the merged version.
2150 2152
2151 2153 (actual capabilities: binary, symlink)
2152 2154
2153 2155 ":prompt"
2154 2156 Asks the user which of the local 'p1()' or the other 'p2()' version to
2155 2157 keep as the merged version.
2156 2158
2157 2159 (actual capabilities: binary, symlink)
2158 2160
2159 2161 ":tagmerge"
2160 2162 Uses the internal tag merge algorithm (experimental).
2161 2163
2162 2164 ":union"
2163 2165 Uses the internal non-interactive simple merge algorithm for merging
2164 2166 files. It will use both left and right sides for conflict regions. No
2165 2167 markers are inserted.
2166 2168
2167 2169 Internal tools are always available and do not require a GUI but will by
2168 2170 default not handle symlinks or binary files. See next section for detail
2169 2171 about "actual capabilities" described above.
2170 2172
2171 2173 Choosing a merge tool
2172 2174 =====================
2173 2175
2174 2176 Mercurial uses these rules when deciding which merge tool to use:
2175 2177
2176 2178 1. If a tool has been specified with the --tool option to merge or
2177 2179 resolve, it is used. If it is the name of a tool in the merge-tools
2178 2180 configuration, its configuration is used. Otherwise the specified tool
2179 2181 must be executable by the shell.
2180 2182 2. If the "HGMERGE" environment variable is present, its value is used and
2181 2183 must be executable by the shell.
2182 2184 3. If the filename of the file to be merged matches any of the patterns in
2183 2185 the merge-patterns configuration section, the first usable merge tool
2184 2186 corresponding to a matching pattern is used.
2185 2187 4. If ui.merge is set it will be considered next. If the value is not the
2186 2188 name of a configured tool, the specified value is used and must be
2187 2189 executable by the shell. Otherwise the named tool is used if it is
2188 2190 usable.
2189 2191 5. If any usable merge tools are present in the merge-tools configuration
2190 2192 section, the one with the highest priority is used.
2191 2193 6. If a program named "hgmerge" can be found on the system, it is used -
2192 2194 but it will by default not be used for symlinks and binary files.
2193 2195 7. If the file to be merged is not binary and is not a symlink, then
2194 2196 internal ":merge" is used.
2195 2197 8. Otherwise, ":prompt" is used.
2196 2198
2197 2199 For historical reason, Mercurial treats merge tools as below while
2198 2200 examining rules above.
2199 2201
2200 2202 step specified via binary symlink
2201 2203 ----------------------------------
2202 2204 1. --tool o/o o/o
2203 2205 2. HGMERGE o/o o/o
2204 2206 3. merge-patterns o/o(*) x/?(*)
2205 2207 4. ui.merge x/?(*) x/?(*)
2206 2208
2207 2209 Each capability column indicates Mercurial behavior for internal/external
2208 2210 merge tools at examining each rule.
2209 2211
2210 2212 - "o": "assume that a tool has capability"
2211 2213 - "x": "assume that a tool does not have capability"
2212 2214 - "?": "check actual capability of a tool"
2213 2215
2214 2216 If "merge.strict-capability-check" configuration is true, Mercurial checks
2215 2217 capabilities of merge tools strictly in (*) cases above (= each capability
2216 2218 column becomes "?/?"). It is false by default for backward compatibility.
2217 2219
2218 2220 Note:
2219 2221 After selecting a merge program, Mercurial will by default attempt to
2220 2222 merge the files using a simple merge algorithm first. Only if it
2221 2223 doesn't succeed because of conflicting changes will Mercurial actually
2222 2224 execute the merge program. Whether to use the simple merge algorithm
2223 2225 first can be controlled by the premerge setting of the merge tool.
2224 2226 Premerge is enabled by default unless the file is binary or a symlink.
2225 2227
2226 2228 See the merge-tools and ui sections of hgrc(5) for details on the
2227 2229 configuration of merge tools.
2228 2230
2229 2231 Compression engines listed in `hg help bundlespec`
2230 2232
2231 2233 $ hg help bundlespec | grep gzip
2232 2234 "v1" bundles can only use the "gzip", "bzip2", and "none" compression
2233 2235 An algorithm that produces smaller bundles than "gzip".
2234 2236 This engine will likely produce smaller bundles than "gzip" but will be
2235 2237 "gzip"
2236 2238 better compression than "gzip". It also frequently yields better (?)
2237 2239
2238 2240 Test usage of section marks in help documents
2239 2241
2240 2242 $ cd "$TESTDIR"/../doc
2241 2243 $ "$PYTHON" check-seclevel.py
2242 2244 $ cd $TESTTMP
2243 2245
2244 2246 #if serve
2245 2247
2246 2248 Test the help pages in hgweb.
2247 2249
2248 2250 Dish up an empty repo; serve it cold.
2249 2251
2250 2252 $ hg init "$TESTTMP/test"
2251 2253 $ hg serve -R "$TESTTMP/test" -n test -p $HGPORT -d --pid-file=hg.pid
2252 2254 $ cat hg.pid >> $DAEMON_PIDS
2253 2255
2254 2256 $ get-with-headers.py $LOCALIP:$HGPORT "help"
2255 2257 200 Script output follows
2256 2258
2257 2259 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
2258 2260 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
2259 2261 <head>
2260 2262 <link rel="icon" href="/static/hgicon.png" type="image/png" />
2261 2263 <meta name="robots" content="index, nofollow" />
2262 2264 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
2263 2265 <script type="text/javascript" src="/static/mercurial.js"></script>
2264 2266
2265 2267 <title>Help: Index</title>
2266 2268 </head>
2267 2269 <body>
2268 2270
2269 2271 <div class="container">
2270 2272 <div class="menu">
2271 2273 <div class="logo">
2272 2274 <a href="https://mercurial-scm.org/">
2273 2275 <img src="/static/hglogo.png" alt="mercurial" /></a>
2274 2276 </div>
2275 2277 <ul>
2276 2278 <li><a href="/shortlog">log</a></li>
2277 2279 <li><a href="/graph">graph</a></li>
2278 2280 <li><a href="/tags">tags</a></li>
2279 2281 <li><a href="/bookmarks">bookmarks</a></li>
2280 2282 <li><a href="/branches">branches</a></li>
2281 2283 </ul>
2282 2284 <ul>
2283 2285 <li class="active">help</li>
2284 2286 </ul>
2285 2287 </div>
2286 2288
2287 2289 <div class="main">
2288 2290 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
2289 2291
2290 2292 <form class="search" action="/log">
2291 2293
2292 2294 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
2293 2295 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
2294 2296 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
2295 2297 </form>
2296 2298 <table class="bigtable">
2297 2299 <tr><td colspan="2"><h2><a name="topics" href="#topics">Topics</a></h2></td></tr>
2298 2300
2299 2301 <tr><td>
2300 2302 <a href="/help/bundlespec">
2301 2303 bundlespec
2302 2304 </a>
2303 2305 </td><td>
2304 2306 Bundle File Formats
2305 2307 </td></tr>
2306 2308 <tr><td>
2307 2309 <a href="/help/color">
2308 2310 color
2309 2311 </a>
2310 2312 </td><td>
2311 2313 Colorizing Outputs
2312 2314 </td></tr>
2313 2315 <tr><td>
2314 2316 <a href="/help/config">
2315 2317 config
2316 2318 </a>
2317 2319 </td><td>
2318 2320 Configuration Files
2319 2321 </td></tr>
2320 2322 <tr><td>
2321 2323 <a href="/help/dates">
2322 2324 dates
2323 2325 </a>
2324 2326 </td><td>
2325 2327 Date Formats
2326 2328 </td></tr>
2327 2329 <tr><td>
2328 2330 <a href="/help/deprecated">
2329 2331 deprecated
2330 2332 </a>
2331 2333 </td><td>
2332 2334 Deprecated Features
2333 2335 </td></tr>
2334 2336 <tr><td>
2335 2337 <a href="/help/diffs">
2336 2338 diffs
2337 2339 </a>
2338 2340 </td><td>
2339 2341 Diff Formats
2340 2342 </td></tr>
2341 2343 <tr><td>
2342 2344 <a href="/help/environment">
2343 2345 environment
2344 2346 </a>
2345 2347 </td><td>
2346 2348 Environment Variables
2347 2349 </td></tr>
2348 2350 <tr><td>
2349 2351 <a href="/help/evolution">
2350 2352 evolution
2351 2353 </a>
2352 2354 </td><td>
2353 2355 Safely rewriting history (EXPERIMENTAL)
2354 2356 </td></tr>
2355 2357 <tr><td>
2356 2358 <a href="/help/extensions">
2357 2359 extensions
2358 2360 </a>
2359 2361 </td><td>
2360 2362 Using Additional Features
2361 2363 </td></tr>
2362 2364 <tr><td>
2363 2365 <a href="/help/filesets">
2364 2366 filesets
2365 2367 </a>
2366 2368 </td><td>
2367 2369 Specifying File Sets
2368 2370 </td></tr>
2369 2371 <tr><td>
2370 2372 <a href="/help/flags">
2371 2373 flags
2372 2374 </a>
2373 2375 </td><td>
2374 2376 Command-line flags
2375 2377 </td></tr>
2376 2378 <tr><td>
2377 2379 <a href="/help/glossary">
2378 2380 glossary
2379 2381 </a>
2380 2382 </td><td>
2381 2383 Glossary
2382 2384 </td></tr>
2383 2385 <tr><td>
2384 2386 <a href="/help/hgignore">
2385 2387 hgignore
2386 2388 </a>
2387 2389 </td><td>
2388 2390 Syntax for Mercurial Ignore Files
2389 2391 </td></tr>
2390 2392 <tr><td>
2391 2393 <a href="/help/hgweb">
2392 2394 hgweb
2393 2395 </a>
2394 2396 </td><td>
2395 2397 Configuring hgweb
2396 2398 </td></tr>
2397 2399 <tr><td>
2398 2400 <a href="/help/internals">
2399 2401 internals
2400 2402 </a>
2401 2403 </td><td>
2402 2404 Technical implementation topics
2403 2405 </td></tr>
2404 2406 <tr><td>
2405 2407 <a href="/help/merge-tools">
2406 2408 merge-tools
2407 2409 </a>
2408 2410 </td><td>
2409 2411 Merge Tools
2410 2412 </td></tr>
2411 2413 <tr><td>
2412 2414 <a href="/help/pager">
2413 2415 pager
2414 2416 </a>
2415 2417 </td><td>
2416 2418 Pager Support
2417 2419 </td></tr>
2418 2420 <tr><td>
2419 2421 <a href="/help/patterns">
2420 2422 patterns
2421 2423 </a>
2422 2424 </td><td>
2423 2425 File Name Patterns
2424 2426 </td></tr>
2425 2427 <tr><td>
2426 2428 <a href="/help/phases">
2427 2429 phases
2428 2430 </a>
2429 2431 </td><td>
2430 2432 Working with Phases
2431 2433 </td></tr>
2432 2434 <tr><td>
2433 2435 <a href="/help/revisions">
2434 2436 revisions
2435 2437 </a>
2436 2438 </td><td>
2437 2439 Specifying Revisions
2438 2440 </td></tr>
2439 2441 <tr><td>
2440 2442 <a href="/help/rust">
2441 2443 rust
2442 2444 </a>
2443 2445 </td><td>
2444 2446 Rust in Mercurial
2445 2447 </td></tr>
2446 2448 <tr><td>
2447 2449 <a href="/help/scripting">
2448 2450 scripting
2449 2451 </a>
2450 2452 </td><td>
2451 2453 Using Mercurial from scripts and automation
2452 2454 </td></tr>
2453 2455 <tr><td>
2454 2456 <a href="/help/subrepos">
2455 2457 subrepos
2456 2458 </a>
2457 2459 </td><td>
2458 2460 Subrepositories
2459 2461 </td></tr>
2460 2462 <tr><td>
2461 2463 <a href="/help/templating">
2462 2464 templating
2463 2465 </a>
2464 2466 </td><td>
2465 2467 Template Usage
2466 2468 </td></tr>
2467 2469 <tr><td>
2468 2470 <a href="/help/urls">
2469 2471 urls
2470 2472 </a>
2471 2473 </td><td>
2472 2474 URL Paths
2473 2475 </td></tr>
2474 2476 <tr><td>
2475 2477 <a href="/help/topic-containing-verbose">
2476 2478 topic-containing-verbose
2477 2479 </a>
2478 2480 </td><td>
2479 2481 This is the topic to test omit indicating.
2480 2482 </td></tr>
2481 2483
2482 2484
2483 2485 <tr><td colspan="2"><h2><a name="main" href="#main">Main Commands</a></h2></td></tr>
2484 2486
2485 2487 <tr><td>
2486 2488 <a href="/help/abort">
2487 2489 abort
2488 2490 </a>
2489 2491 </td><td>
2490 2492 abort an unfinished operation (EXPERIMENTAL)
2491 2493 </td></tr>
2492 2494 <tr><td>
2493 2495 <a href="/help/add">
2494 2496 add
2495 2497 </a>
2496 2498 </td><td>
2497 2499 add the specified files on the next commit
2498 2500 </td></tr>
2499 2501 <tr><td>
2500 2502 <a href="/help/annotate">
2501 2503 annotate
2502 2504 </a>
2503 2505 </td><td>
2504 2506 show changeset information by line for each file
2505 2507 </td></tr>
2506 2508 <tr><td>
2507 2509 <a href="/help/clone">
2508 2510 clone
2509 2511 </a>
2510 2512 </td><td>
2511 2513 make a copy of an existing repository
2512 2514 </td></tr>
2513 2515 <tr><td>
2514 2516 <a href="/help/commit">
2515 2517 commit
2516 2518 </a>
2517 2519 </td><td>
2518 2520 commit the specified files or all outstanding changes
2519 2521 </td></tr>
2520 2522 <tr><td>
2521 2523 <a href="/help/continue">
2522 2524 continue
2523 2525 </a>
2524 2526 </td><td>
2525 2527 resumes an interrupted operation (EXPERIMENTAL)
2526 2528 </td></tr>
2527 2529 <tr><td>
2528 2530 <a href="/help/diff">
2529 2531 diff
2530 2532 </a>
2531 2533 </td><td>
2532 2534 diff repository (or selected files)
2533 2535 </td></tr>
2534 2536 <tr><td>
2535 2537 <a href="/help/export">
2536 2538 export
2537 2539 </a>
2538 2540 </td><td>
2539 2541 dump the header and diffs for one or more changesets
2540 2542 </td></tr>
2541 2543 <tr><td>
2542 2544 <a href="/help/forget">
2543 2545 forget
2544 2546 </a>
2545 2547 </td><td>
2546 2548 forget the specified files on the next commit
2547 2549 </td></tr>
2548 2550 <tr><td>
2549 2551 <a href="/help/init">
2550 2552 init
2551 2553 </a>
2552 2554 </td><td>
2553 2555 create a new repository in the given directory
2554 2556 </td></tr>
2555 2557 <tr><td>
2556 2558 <a href="/help/log">
2557 2559 log
2558 2560 </a>
2559 2561 </td><td>
2560 2562 show revision history of entire repository or files
2561 2563 </td></tr>
2562 2564 <tr><td>
2563 2565 <a href="/help/merge">
2564 2566 merge
2565 2567 </a>
2566 2568 </td><td>
2567 2569 merge another revision into working directory
2568 2570 </td></tr>
2569 2571 <tr><td>
2570 2572 <a href="/help/pull">
2571 2573 pull
2572 2574 </a>
2573 2575 </td><td>
2574 2576 pull changes from the specified source
2575 2577 </td></tr>
2576 2578 <tr><td>
2577 2579 <a href="/help/push">
2578 2580 push
2579 2581 </a>
2580 2582 </td><td>
2581 2583 push changes to the specified destination
2582 2584 </td></tr>
2583 2585 <tr><td>
2584 2586 <a href="/help/remove">
2585 2587 remove
2586 2588 </a>
2587 2589 </td><td>
2588 2590 remove the specified files on the next commit
2589 2591 </td></tr>
2590 2592 <tr><td>
2591 2593 <a href="/help/serve">
2592 2594 serve
2593 2595 </a>
2594 2596 </td><td>
2595 2597 start stand-alone webserver
2596 2598 </td></tr>
2597 2599 <tr><td>
2598 2600 <a href="/help/status">
2599 2601 status
2600 2602 </a>
2601 2603 </td><td>
2602 2604 show changed files in the working directory
2603 2605 </td></tr>
2604 2606 <tr><td>
2605 2607 <a href="/help/summary">
2606 2608 summary
2607 2609 </a>
2608 2610 </td><td>
2609 2611 summarize working directory state
2610 2612 </td></tr>
2611 2613 <tr><td>
2612 2614 <a href="/help/update">
2613 2615 update
2614 2616 </a>
2615 2617 </td><td>
2616 2618 update working directory (or switch revisions)
2617 2619 </td></tr>
2618 2620
2619 2621
2620 2622
2621 2623 <tr><td colspan="2"><h2><a name="other" href="#other">Other Commands</a></h2></td></tr>
2622 2624
2623 2625 <tr><td>
2624 2626 <a href="/help/addremove">
2625 2627 addremove
2626 2628 </a>
2627 2629 </td><td>
2628 2630 add all new files, delete all missing files
2629 2631 </td></tr>
2630 2632 <tr><td>
2631 2633 <a href="/help/archive">
2632 2634 archive
2633 2635 </a>
2634 2636 </td><td>
2635 2637 create an unversioned archive of a repository revision
2636 2638 </td></tr>
2637 2639 <tr><td>
2638 2640 <a href="/help/backout">
2639 2641 backout
2640 2642 </a>
2641 2643 </td><td>
2642 2644 reverse effect of earlier changeset
2643 2645 </td></tr>
2644 2646 <tr><td>
2645 2647 <a href="/help/bisect">
2646 2648 bisect
2647 2649 </a>
2648 2650 </td><td>
2649 2651 subdivision search of changesets
2650 2652 </td></tr>
2651 2653 <tr><td>
2652 2654 <a href="/help/bookmarks">
2653 2655 bookmarks
2654 2656 </a>
2655 2657 </td><td>
2656 2658 create a new bookmark or list existing bookmarks
2657 2659 </td></tr>
2658 2660 <tr><td>
2659 2661 <a href="/help/branch">
2660 2662 branch
2661 2663 </a>
2662 2664 </td><td>
2663 2665 set or show the current branch name
2664 2666 </td></tr>
2665 2667 <tr><td>
2666 2668 <a href="/help/branches">
2667 2669 branches
2668 2670 </a>
2669 2671 </td><td>
2670 2672 list repository named branches
2671 2673 </td></tr>
2672 2674 <tr><td>
2673 2675 <a href="/help/bundle">
2674 2676 bundle
2675 2677 </a>
2676 2678 </td><td>
2677 2679 create a bundle file
2678 2680 </td></tr>
2679 2681 <tr><td>
2680 2682 <a href="/help/cat">
2681 2683 cat
2682 2684 </a>
2683 2685 </td><td>
2684 2686 output the current or given revision of files
2685 2687 </td></tr>
2686 2688 <tr><td>
2687 2689 <a href="/help/config">
2688 2690 config
2689 2691 </a>
2690 2692 </td><td>
2691 2693 show combined config settings from all hgrc files
2692 2694 </td></tr>
2693 2695 <tr><td>
2694 2696 <a href="/help/copy">
2695 2697 copy
2696 2698 </a>
2697 2699 </td><td>
2698 2700 mark files as copied for the next commit
2699 2701 </td></tr>
2700 2702 <tr><td>
2701 2703 <a href="/help/files">
2702 2704 files
2703 2705 </a>
2704 2706 </td><td>
2705 2707 list tracked files
2706 2708 </td></tr>
2707 2709 <tr><td>
2708 2710 <a href="/help/graft">
2709 2711 graft
2710 2712 </a>
2711 2713 </td><td>
2712 2714 copy changes from other branches onto the current branch
2713 2715 </td></tr>
2714 2716 <tr><td>
2715 2717 <a href="/help/grep">
2716 2718 grep
2717 2719 </a>
2718 2720 </td><td>
2719 2721 search for a pattern in specified files
2720 2722 </td></tr>
2721 2723 <tr><td>
2722 2724 <a href="/help/hashelp">
2723 2725 hashelp
2724 2726 </a>
2725 2727 </td><td>
2726 2728 Extension command's help
2727 2729 </td></tr>
2728 2730 <tr><td>
2729 2731 <a href="/help/heads">
2730 2732 heads
2731 2733 </a>
2732 2734 </td><td>
2733 2735 show branch heads
2734 2736 </td></tr>
2735 2737 <tr><td>
2736 2738 <a href="/help/help">
2737 2739 help
2738 2740 </a>
2739 2741 </td><td>
2740 2742 show help for a given topic or a help overview
2741 2743 </td></tr>
2742 2744 <tr><td>
2743 2745 <a href="/help/hgalias">
2744 2746 hgalias
2745 2747 </a>
2746 2748 </td><td>
2747 2749 My doc
2748 2750 </td></tr>
2749 2751 <tr><td>
2750 2752 <a href="/help/hgaliasnodoc">
2751 2753 hgaliasnodoc
2752 2754 </a>
2753 2755 </td><td>
2754 2756 summarize working directory state
2755 2757 </td></tr>
2756 2758 <tr><td>
2757 2759 <a href="/help/identify">
2758 2760 identify
2759 2761 </a>
2760 2762 </td><td>
2761 2763 identify the working directory or specified revision
2762 2764 </td></tr>
2763 2765 <tr><td>
2764 2766 <a href="/help/import">
2765 2767 import
2766 2768 </a>
2767 2769 </td><td>
2768 2770 import an ordered set of patches
2769 2771 </td></tr>
2770 2772 <tr><td>
2771 2773 <a href="/help/incoming">
2772 2774 incoming
2773 2775 </a>
2774 2776 </td><td>
2775 2777 show new changesets found in source
2776 2778 </td></tr>
2777 2779 <tr><td>
2778 2780 <a href="/help/manifest">
2779 2781 manifest
2780 2782 </a>
2781 2783 </td><td>
2782 2784 output the current or given revision of the project manifest
2783 2785 </td></tr>
2784 2786 <tr><td>
2785 2787 <a href="/help/nohelp">
2786 2788 nohelp
2787 2789 </a>
2788 2790 </td><td>
2789 2791 (no help text available)
2790 2792 </td></tr>
2791 2793 <tr><td>
2792 2794 <a href="/help/outgoing">
2793 2795 outgoing
2794 2796 </a>
2795 2797 </td><td>
2796 2798 show changesets not found in the destination
2797 2799 </td></tr>
2798 2800 <tr><td>
2799 2801 <a href="/help/paths">
2800 2802 paths
2801 2803 </a>
2802 2804 </td><td>
2803 2805 show aliases for remote repositories
2804 2806 </td></tr>
2805 2807 <tr><td>
2806 2808 <a href="/help/phase">
2807 2809 phase
2808 2810 </a>
2809 2811 </td><td>
2810 2812 set or show the current phase name
2811 2813 </td></tr>
2812 2814 <tr><td>
2813 2815 <a href="/help/purge">
2814 2816 purge
2815 2817 </a>
2816 2818 </td><td>
2817 2819 removes files not tracked by Mercurial
2818 2820 </td></tr>
2819 2821 <tr><td>
2820 2822 <a href="/help/recover">
2821 2823 recover
2822 2824 </a>
2823 2825 </td><td>
2824 2826 roll back an interrupted transaction
2825 2827 </td></tr>
2826 2828 <tr><td>
2827 2829 <a href="/help/rename">
2828 2830 rename
2829 2831 </a>
2830 2832 </td><td>
2831 2833 rename files; equivalent of copy + remove
2832 2834 </td></tr>
2833 2835 <tr><td>
2834 2836 <a href="/help/resolve">
2835 2837 resolve
2836 2838 </a>
2837 2839 </td><td>
2838 2840 redo merges or set/view the merge status of files
2839 2841 </td></tr>
2840 2842 <tr><td>
2841 2843 <a href="/help/revert">
2842 2844 revert
2843 2845 </a>
2844 2846 </td><td>
2845 2847 restore files to their checkout state
2846 2848 </td></tr>
2847 2849 <tr><td>
2848 2850 <a href="/help/root">
2849 2851 root
2850 2852 </a>
2851 2853 </td><td>
2852 2854 print the root (top) of the current working directory
2853 2855 </td></tr>
2854 2856 <tr><td>
2855 2857 <a href="/help/shellalias">
2856 2858 shellalias
2857 2859 </a>
2858 2860 </td><td>
2859 2861 (no help text available)
2860 2862 </td></tr>
2861 2863 <tr><td>
2862 2864 <a href="/help/shelve">
2863 2865 shelve
2864 2866 </a>
2865 2867 </td><td>
2866 2868 save and set aside changes from the working directory
2867 2869 </td></tr>
2868 2870 <tr><td>
2869 2871 <a href="/help/tag">
2870 2872 tag
2871 2873 </a>
2872 2874 </td><td>
2873 2875 add one or more tags for the current or given revision
2874 2876 </td></tr>
2875 2877 <tr><td>
2876 2878 <a href="/help/tags">
2877 2879 tags
2878 2880 </a>
2879 2881 </td><td>
2880 2882 list repository tags
2881 2883 </td></tr>
2882 2884 <tr><td>
2883 2885 <a href="/help/unbundle">
2884 2886 unbundle
2885 2887 </a>
2886 2888 </td><td>
2887 2889 apply one or more bundle files
2888 2890 </td></tr>
2889 2891 <tr><td>
2890 2892 <a href="/help/unshelve">
2891 2893 unshelve
2892 2894 </a>
2893 2895 </td><td>
2894 2896 restore a shelved change to the working directory
2895 2897 </td></tr>
2896 2898 <tr><td>
2897 2899 <a href="/help/verify">
2898 2900 verify
2899 2901 </a>
2900 2902 </td><td>
2901 2903 verify the integrity of the repository
2902 2904 </td></tr>
2903 2905 <tr><td>
2904 2906 <a href="/help/version">
2905 2907 version
2906 2908 </a>
2907 2909 </td><td>
2908 2910 output version and copyright information
2909 2911 </td></tr>
2910 2912
2911 2913
2912 2914 </table>
2913 2915 </div>
2914 2916 </div>
2915 2917
2916 2918
2917 2919
2918 2920 </body>
2919 2921 </html>
2920 2922
2921 2923
2922 2924 $ get-with-headers.py $LOCALIP:$HGPORT "help/add"
2923 2925 200 Script output follows
2924 2926
2925 2927 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
2926 2928 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
2927 2929 <head>
2928 2930 <link rel="icon" href="/static/hgicon.png" type="image/png" />
2929 2931 <meta name="robots" content="index, nofollow" />
2930 2932 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
2931 2933 <script type="text/javascript" src="/static/mercurial.js"></script>
2932 2934
2933 2935 <title>Help: add</title>
2934 2936 </head>
2935 2937 <body>
2936 2938
2937 2939 <div class="container">
2938 2940 <div class="menu">
2939 2941 <div class="logo">
2940 2942 <a href="https://mercurial-scm.org/">
2941 2943 <img src="/static/hglogo.png" alt="mercurial" /></a>
2942 2944 </div>
2943 2945 <ul>
2944 2946 <li><a href="/shortlog">log</a></li>
2945 2947 <li><a href="/graph">graph</a></li>
2946 2948 <li><a href="/tags">tags</a></li>
2947 2949 <li><a href="/bookmarks">bookmarks</a></li>
2948 2950 <li><a href="/branches">branches</a></li>
2949 2951 </ul>
2950 2952 <ul>
2951 2953 <li class="active"><a href="/help">help</a></li>
2952 2954 </ul>
2953 2955 </div>
2954 2956
2955 2957 <div class="main">
2956 2958 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
2957 2959 <h3>Help: add</h3>
2958 2960
2959 2961 <form class="search" action="/log">
2960 2962
2961 2963 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
2962 2964 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
2963 2965 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
2964 2966 </form>
2965 2967 <div id="doc">
2966 2968 <p>
2967 2969 hg add [OPTION]... [FILE]...
2968 2970 </p>
2969 2971 <p>
2970 2972 add the specified files on the next commit
2971 2973 </p>
2972 2974 <p>
2973 2975 Schedule files to be version controlled and added to the
2974 2976 repository.
2975 2977 </p>
2976 2978 <p>
2977 2979 The files will be added to the repository at the next commit. To
2978 2980 undo an add before that, see 'hg forget'.
2979 2981 </p>
2980 2982 <p>
2981 2983 If no names are given, add all files to the repository (except
2982 2984 files matching &quot;.hgignore&quot;).
2983 2985 </p>
2984 2986 <p>
2985 2987 Examples:
2986 2988 </p>
2987 2989 <ul>
2988 2990 <li> New (unknown) files are added automatically by 'hg add':
2989 2991 <pre>
2990 2992 \$ ls (re)
2991 2993 foo.c
2992 2994 \$ hg status (re)
2993 2995 ? foo.c
2994 2996 \$ hg add (re)
2995 2997 adding foo.c
2996 2998 \$ hg status (re)
2997 2999 A foo.c
2998 3000 </pre>
2999 3001 <li> Specific files to be added can be specified:
3000 3002 <pre>
3001 3003 \$ ls (re)
3002 3004 bar.c foo.c
3003 3005 \$ hg status (re)
3004 3006 ? bar.c
3005 3007 ? foo.c
3006 3008 \$ hg add bar.c (re)
3007 3009 \$ hg status (re)
3008 3010 A bar.c
3009 3011 ? foo.c
3010 3012 </pre>
3011 3013 </ul>
3012 3014 <p>
3013 3015 Returns 0 if all files are successfully added.
3014 3016 </p>
3015 3017 <p>
3016 3018 options ([+] can be repeated):
3017 3019 </p>
3018 3020 <table>
3019 3021 <tr><td>-I</td>
3020 3022 <td>--include PATTERN [+]</td>
3021 3023 <td>include names matching the given patterns</td></tr>
3022 3024 <tr><td>-X</td>
3023 3025 <td>--exclude PATTERN [+]</td>
3024 3026 <td>exclude names matching the given patterns</td></tr>
3025 3027 <tr><td>-S</td>
3026 3028 <td>--subrepos</td>
3027 3029 <td>recurse into subrepositories</td></tr>
3028 3030 <tr><td>-n</td>
3029 3031 <td>--dry-run</td>
3030 3032 <td>do not perform actions, just print output</td></tr>
3031 3033 </table>
3032 3034 <p>
3033 3035 global options ([+] can be repeated):
3034 3036 </p>
3035 3037 <table>
3036 3038 <tr><td>-R</td>
3037 3039 <td>--repository REPO</td>
3038 3040 <td>repository root directory or name of overlay bundle file</td></tr>
3039 3041 <tr><td></td>
3040 3042 <td>--cwd DIR</td>
3041 3043 <td>change working directory</td></tr>
3042 3044 <tr><td>-y</td>
3043 3045 <td>--noninteractive</td>
3044 3046 <td>do not prompt, automatically pick the first choice for all prompts</td></tr>
3045 3047 <tr><td>-q</td>
3046 3048 <td>--quiet</td>
3047 3049 <td>suppress output</td></tr>
3048 3050 <tr><td>-v</td>
3049 3051 <td>--verbose</td>
3050 3052 <td>enable additional output</td></tr>
3051 3053 <tr><td></td>
3052 3054 <td>--color TYPE</td>
3053 3055 <td>when to colorize (boolean, always, auto, never, or debug)</td></tr>
3054 3056 <tr><td></td>
3055 3057 <td>--config CONFIG [+]</td>
3056 3058 <td>set/override config option (use 'section.name=value')</td></tr>
3057 3059 <tr><td></td>
3058 3060 <td>--debug</td>
3059 3061 <td>enable debugging output</td></tr>
3060 3062 <tr><td></td>
3061 3063 <td>--debugger</td>
3062 3064 <td>start debugger</td></tr>
3063 3065 <tr><td></td>
3064 3066 <td>--encoding ENCODE</td>
3065 3067 <td>set the charset encoding (default: ascii)</td></tr>
3066 3068 <tr><td></td>
3067 3069 <td>--encodingmode MODE</td>
3068 3070 <td>set the charset encoding mode (default: strict)</td></tr>
3069 3071 <tr><td></td>
3070 3072 <td>--traceback</td>
3071 3073 <td>always print a traceback on exception</td></tr>
3072 3074 <tr><td></td>
3073 3075 <td>--time</td>
3074 3076 <td>time how long the command takes</td></tr>
3075 3077 <tr><td></td>
3076 3078 <td>--profile</td>
3077 3079 <td>print command execution profile</td></tr>
3078 3080 <tr><td></td>
3079 3081 <td>--version</td>
3080 3082 <td>output version information and exit</td></tr>
3081 3083 <tr><td>-h</td>
3082 3084 <td>--help</td>
3083 3085 <td>display help and exit</td></tr>
3084 3086 <tr><td></td>
3085 3087 <td>--hidden</td>
3086 3088 <td>consider hidden changesets</td></tr>
3087 3089 <tr><td></td>
3088 3090 <td>--pager TYPE</td>
3089 3091 <td>when to paginate (boolean, always, auto, or never) (default: auto)</td></tr>
3090 3092 </table>
3091 3093
3092 3094 </div>
3093 3095 </div>
3094 3096 </div>
3095 3097
3096 3098
3097 3099
3098 3100 </body>
3099 3101 </html>
3100 3102
3101 3103
3102 3104 $ get-with-headers.py $LOCALIP:$HGPORT "help/remove"
3103 3105 200 Script output follows
3104 3106
3105 3107 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3106 3108 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3107 3109 <head>
3108 3110 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3109 3111 <meta name="robots" content="index, nofollow" />
3110 3112 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3111 3113 <script type="text/javascript" src="/static/mercurial.js"></script>
3112 3114
3113 3115 <title>Help: remove</title>
3114 3116 </head>
3115 3117 <body>
3116 3118
3117 3119 <div class="container">
3118 3120 <div class="menu">
3119 3121 <div class="logo">
3120 3122 <a href="https://mercurial-scm.org/">
3121 3123 <img src="/static/hglogo.png" alt="mercurial" /></a>
3122 3124 </div>
3123 3125 <ul>
3124 3126 <li><a href="/shortlog">log</a></li>
3125 3127 <li><a href="/graph">graph</a></li>
3126 3128 <li><a href="/tags">tags</a></li>
3127 3129 <li><a href="/bookmarks">bookmarks</a></li>
3128 3130 <li><a href="/branches">branches</a></li>
3129 3131 </ul>
3130 3132 <ul>
3131 3133 <li class="active"><a href="/help">help</a></li>
3132 3134 </ul>
3133 3135 </div>
3134 3136
3135 3137 <div class="main">
3136 3138 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3137 3139 <h3>Help: remove</h3>
3138 3140
3139 3141 <form class="search" action="/log">
3140 3142
3141 3143 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3142 3144 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3143 3145 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3144 3146 </form>
3145 3147 <div id="doc">
3146 3148 <p>
3147 3149 hg remove [OPTION]... FILE...
3148 3150 </p>
3149 3151 <p>
3150 3152 aliases: rm
3151 3153 </p>
3152 3154 <p>
3153 3155 remove the specified files on the next commit
3154 3156 </p>
3155 3157 <p>
3156 3158 Schedule the indicated files for removal from the current branch.
3157 3159 </p>
3158 3160 <p>
3159 3161 This command schedules the files to be removed at the next commit.
3160 3162 To undo a remove before that, see 'hg revert'. To undo added
3161 3163 files, see 'hg forget'.
3162 3164 </p>
3163 3165 <p>
3164 3166 -A/--after can be used to remove only files that have already
3165 3167 been deleted, -f/--force can be used to force deletion, and -Af
3166 3168 can be used to remove files from the next revision without
3167 3169 deleting them from the working directory.
3168 3170 </p>
3169 3171 <p>
3170 3172 The following table details the behavior of remove for different
3171 3173 file states (columns) and option combinations (rows). The file
3172 3174 states are Added [A], Clean [C], Modified [M] and Missing [!]
3173 3175 (as reported by 'hg status'). The actions are Warn, Remove
3174 3176 (from branch) and Delete (from disk):
3175 3177 </p>
3176 3178 <table>
3177 3179 <tr><td>opt/state</td>
3178 3180 <td>A</td>
3179 3181 <td>C</td>
3180 3182 <td>M</td>
3181 3183 <td>!</td></tr>
3182 3184 <tr><td>none</td>
3183 3185 <td>W</td>
3184 3186 <td>RD</td>
3185 3187 <td>W</td>
3186 3188 <td>R</td></tr>
3187 3189 <tr><td>-f</td>
3188 3190 <td>R</td>
3189 3191 <td>RD</td>
3190 3192 <td>RD</td>
3191 3193 <td>R</td></tr>
3192 3194 <tr><td>-A</td>
3193 3195 <td>W</td>
3194 3196 <td>W</td>
3195 3197 <td>W</td>
3196 3198 <td>R</td></tr>
3197 3199 <tr><td>-Af</td>
3198 3200 <td>R</td>
3199 3201 <td>R</td>
3200 3202 <td>R</td>
3201 3203 <td>R</td></tr>
3202 3204 </table>
3203 3205 <p>
3204 3206 <b>Note:</b>
3205 3207 </p>
3206 3208 <p>
3207 3209 'hg remove' never deletes files in Added [A] state from the
3208 3210 working directory, not even if &quot;--force&quot; is specified.
3209 3211 </p>
3210 3212 <p>
3211 3213 Returns 0 on success, 1 if any warnings encountered.
3212 3214 </p>
3213 3215 <p>
3214 3216 options ([+] can be repeated):
3215 3217 </p>
3216 3218 <table>
3217 3219 <tr><td>-A</td>
3218 3220 <td>--after</td>
3219 3221 <td>record delete for missing files</td></tr>
3220 3222 <tr><td>-f</td>
3221 3223 <td>--force</td>
3222 3224 <td>forget added files, delete modified files</td></tr>
3223 3225 <tr><td>-S</td>
3224 3226 <td>--subrepos</td>
3225 3227 <td>recurse into subrepositories</td></tr>
3226 3228 <tr><td>-I</td>
3227 3229 <td>--include PATTERN [+]</td>
3228 3230 <td>include names matching the given patterns</td></tr>
3229 3231 <tr><td>-X</td>
3230 3232 <td>--exclude PATTERN [+]</td>
3231 3233 <td>exclude names matching the given patterns</td></tr>
3232 3234 <tr><td>-n</td>
3233 3235 <td>--dry-run</td>
3234 3236 <td>do not perform actions, just print output</td></tr>
3235 3237 </table>
3236 3238 <p>
3237 3239 global options ([+] can be repeated):
3238 3240 </p>
3239 3241 <table>
3240 3242 <tr><td>-R</td>
3241 3243 <td>--repository REPO</td>
3242 3244 <td>repository root directory or name of overlay bundle file</td></tr>
3243 3245 <tr><td></td>
3244 3246 <td>--cwd DIR</td>
3245 3247 <td>change working directory</td></tr>
3246 3248 <tr><td>-y</td>
3247 3249 <td>--noninteractive</td>
3248 3250 <td>do not prompt, automatically pick the first choice for all prompts</td></tr>
3249 3251 <tr><td>-q</td>
3250 3252 <td>--quiet</td>
3251 3253 <td>suppress output</td></tr>
3252 3254 <tr><td>-v</td>
3253 3255 <td>--verbose</td>
3254 3256 <td>enable additional output</td></tr>
3255 3257 <tr><td></td>
3256 3258 <td>--color TYPE</td>
3257 3259 <td>when to colorize (boolean, always, auto, never, or debug)</td></tr>
3258 3260 <tr><td></td>
3259 3261 <td>--config CONFIG [+]</td>
3260 3262 <td>set/override config option (use 'section.name=value')</td></tr>
3261 3263 <tr><td></td>
3262 3264 <td>--debug</td>
3263 3265 <td>enable debugging output</td></tr>
3264 3266 <tr><td></td>
3265 3267 <td>--debugger</td>
3266 3268 <td>start debugger</td></tr>
3267 3269 <tr><td></td>
3268 3270 <td>--encoding ENCODE</td>
3269 3271 <td>set the charset encoding (default: ascii)</td></tr>
3270 3272 <tr><td></td>
3271 3273 <td>--encodingmode MODE</td>
3272 3274 <td>set the charset encoding mode (default: strict)</td></tr>
3273 3275 <tr><td></td>
3274 3276 <td>--traceback</td>
3275 3277 <td>always print a traceback on exception</td></tr>
3276 3278 <tr><td></td>
3277 3279 <td>--time</td>
3278 3280 <td>time how long the command takes</td></tr>
3279 3281 <tr><td></td>
3280 3282 <td>--profile</td>
3281 3283 <td>print command execution profile</td></tr>
3282 3284 <tr><td></td>
3283 3285 <td>--version</td>
3284 3286 <td>output version information and exit</td></tr>
3285 3287 <tr><td>-h</td>
3286 3288 <td>--help</td>
3287 3289 <td>display help and exit</td></tr>
3288 3290 <tr><td></td>
3289 3291 <td>--hidden</td>
3290 3292 <td>consider hidden changesets</td></tr>
3291 3293 <tr><td></td>
3292 3294 <td>--pager TYPE</td>
3293 3295 <td>when to paginate (boolean, always, auto, or never) (default: auto)</td></tr>
3294 3296 </table>
3295 3297
3296 3298 </div>
3297 3299 </div>
3298 3300 </div>
3299 3301
3300 3302
3301 3303
3302 3304 </body>
3303 3305 </html>
3304 3306
3305 3307
3306 3308 $ get-with-headers.py $LOCALIP:$HGPORT "help/dates"
3307 3309 200 Script output follows
3308 3310
3309 3311 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3310 3312 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3311 3313 <head>
3312 3314 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3313 3315 <meta name="robots" content="index, nofollow" />
3314 3316 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3315 3317 <script type="text/javascript" src="/static/mercurial.js"></script>
3316 3318
3317 3319 <title>Help: dates</title>
3318 3320 </head>
3319 3321 <body>
3320 3322
3321 3323 <div class="container">
3322 3324 <div class="menu">
3323 3325 <div class="logo">
3324 3326 <a href="https://mercurial-scm.org/">
3325 3327 <img src="/static/hglogo.png" alt="mercurial" /></a>
3326 3328 </div>
3327 3329 <ul>
3328 3330 <li><a href="/shortlog">log</a></li>
3329 3331 <li><a href="/graph">graph</a></li>
3330 3332 <li><a href="/tags">tags</a></li>
3331 3333 <li><a href="/bookmarks">bookmarks</a></li>
3332 3334 <li><a href="/branches">branches</a></li>
3333 3335 </ul>
3334 3336 <ul>
3335 3337 <li class="active"><a href="/help">help</a></li>
3336 3338 </ul>
3337 3339 </div>
3338 3340
3339 3341 <div class="main">
3340 3342 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3341 3343 <h3>Help: dates</h3>
3342 3344
3343 3345 <form class="search" action="/log">
3344 3346
3345 3347 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3346 3348 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3347 3349 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3348 3350 </form>
3349 3351 <div id="doc">
3350 3352 <h1>Date Formats</h1>
3351 3353 <p>
3352 3354 Some commands allow the user to specify a date, e.g.:
3353 3355 </p>
3354 3356 <ul>
3355 3357 <li> backout, commit, import, tag: Specify the commit date.
3356 3358 <li> log, revert, update: Select revision(s) by date.
3357 3359 </ul>
3358 3360 <p>
3359 3361 Many date formats are valid. Here are some examples:
3360 3362 </p>
3361 3363 <ul>
3362 3364 <li> &quot;Wed Dec 6 13:18:29 2006&quot; (local timezone assumed)
3363 3365 <li> &quot;Dec 6 13:18 -0600&quot; (year assumed, time offset provided)
3364 3366 <li> &quot;Dec 6 13:18 UTC&quot; (UTC and GMT are aliases for +0000)
3365 3367 <li> &quot;Dec 6&quot; (midnight)
3366 3368 <li> &quot;13:18&quot; (today assumed)
3367 3369 <li> &quot;3:39&quot; (3:39AM assumed)
3368 3370 <li> &quot;3:39pm&quot; (15:39)
3369 3371 <li> &quot;2006-12-06 13:18:29&quot; (ISO 8601 format)
3370 3372 <li> &quot;2006-12-6 13:18&quot;
3371 3373 <li> &quot;2006-12-6&quot;
3372 3374 <li> &quot;12-6&quot;
3373 3375 <li> &quot;12/6&quot;
3374 3376 <li> &quot;12/6/6&quot; (Dec 6 2006)
3375 3377 <li> &quot;today&quot; (midnight)
3376 3378 <li> &quot;yesterday&quot; (midnight)
3377 3379 <li> &quot;now&quot; - right now
3378 3380 </ul>
3379 3381 <p>
3380 3382 Lastly, there is Mercurial's internal format:
3381 3383 </p>
3382 3384 <ul>
3383 3385 <li> &quot;1165411109 0&quot; (Wed Dec 6 13:18:29 2006 UTC)
3384 3386 </ul>
3385 3387 <p>
3386 3388 This is the internal representation format for dates. The first number
3387 3389 is the number of seconds since the epoch (1970-01-01 00:00 UTC). The
3388 3390 second is the offset of the local timezone, in seconds west of UTC
3389 3391 (negative if the timezone is east of UTC).
3390 3392 </p>
3391 3393 <p>
3392 3394 The log command also accepts date ranges:
3393 3395 </p>
3394 3396 <ul>
3395 3397 <li> &quot;&lt;DATE&quot; - at or before a given date/time
3396 3398 <li> &quot;&gt;DATE&quot; - on or after a given date/time
3397 3399 <li> &quot;DATE to DATE&quot; - a date range, inclusive
3398 3400 <li> &quot;-DAYS&quot; - within a given number of days from today
3399 3401 </ul>
3400 3402
3401 3403 </div>
3402 3404 </div>
3403 3405 </div>
3404 3406
3405 3407
3406 3408
3407 3409 </body>
3408 3410 </html>
3409 3411
3410 3412
3411 3413 $ get-with-headers.py $LOCALIP:$HGPORT "help/pager"
3412 3414 200 Script output follows
3413 3415
3414 3416 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3415 3417 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3416 3418 <head>
3417 3419 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3418 3420 <meta name="robots" content="index, nofollow" />
3419 3421 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3420 3422 <script type="text/javascript" src="/static/mercurial.js"></script>
3421 3423
3422 3424 <title>Help: pager</title>
3423 3425 </head>
3424 3426 <body>
3425 3427
3426 3428 <div class="container">
3427 3429 <div class="menu">
3428 3430 <div class="logo">
3429 3431 <a href="https://mercurial-scm.org/">
3430 3432 <img src="/static/hglogo.png" alt="mercurial" /></a>
3431 3433 </div>
3432 3434 <ul>
3433 3435 <li><a href="/shortlog">log</a></li>
3434 3436 <li><a href="/graph">graph</a></li>
3435 3437 <li><a href="/tags">tags</a></li>
3436 3438 <li><a href="/bookmarks">bookmarks</a></li>
3437 3439 <li><a href="/branches">branches</a></li>
3438 3440 </ul>
3439 3441 <ul>
3440 3442 <li class="active"><a href="/help">help</a></li>
3441 3443 </ul>
3442 3444 </div>
3443 3445
3444 3446 <div class="main">
3445 3447 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3446 3448 <h3>Help: pager</h3>
3447 3449
3448 3450 <form class="search" action="/log">
3449 3451
3450 3452 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3451 3453 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3452 3454 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3453 3455 </form>
3454 3456 <div id="doc">
3455 3457 <h1>Pager Support</h1>
3456 3458 <p>
3457 3459 Some Mercurial commands can produce a lot of output, and Mercurial will
3458 3460 attempt to use a pager to make those commands more pleasant.
3459 3461 </p>
3460 3462 <p>
3461 3463 To set the pager that should be used, set the application variable:
3462 3464 </p>
3463 3465 <pre>
3464 3466 [pager]
3465 3467 pager = less -FRX
3466 3468 </pre>
3467 3469 <p>
3468 3470 If no pager is set in the user or repository configuration, Mercurial uses the
3469 3471 environment variable $PAGER. If $PAGER is not set, pager.pager from the default
3470 3472 or system configuration is used. If none of these are set, a default pager will
3471 3473 be used, typically 'less' on Unix and 'more' on Windows.
3472 3474 </p>
3473 3475 <p>
3474 3476 You can disable the pager for certain commands by adding them to the
3475 3477 pager.ignore list:
3476 3478 </p>
3477 3479 <pre>
3478 3480 [pager]
3479 3481 ignore = version, help, update
3480 3482 </pre>
3481 3483 <p>
3482 3484 To ignore global commands like 'hg version' or 'hg help', you have
3483 3485 to specify them in your user configuration file.
3484 3486 </p>
3485 3487 <p>
3486 3488 To control whether the pager is used at all for an individual command,
3487 3489 you can use --pager=&lt;value&gt;:
3488 3490 </p>
3489 3491 <ul>
3490 3492 <li> use as needed: 'auto'.
3491 3493 <li> require the pager: 'yes' or 'on'.
3492 3494 <li> suppress the pager: 'no' or 'off' (any unrecognized value will also work).
3493 3495 </ul>
3494 3496 <p>
3495 3497 To globally turn off all attempts to use a pager, set:
3496 3498 </p>
3497 3499 <pre>
3498 3500 [ui]
3499 3501 paginate = never
3500 3502 </pre>
3501 3503 <p>
3502 3504 which will prevent the pager from running.
3503 3505 </p>
3504 3506
3505 3507 </div>
3506 3508 </div>
3507 3509 </div>
3508 3510
3509 3511
3510 3512
3511 3513 </body>
3512 3514 </html>
3513 3515
3514 3516
3515 3517 Sub-topic indexes rendered properly
3516 3518
3517 3519 $ get-with-headers.py $LOCALIP:$HGPORT "help/internals"
3518 3520 200 Script output follows
3519 3521
3520 3522 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3521 3523 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3522 3524 <head>
3523 3525 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3524 3526 <meta name="robots" content="index, nofollow" />
3525 3527 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3526 3528 <script type="text/javascript" src="/static/mercurial.js"></script>
3527 3529
3528 3530 <title>Help: internals</title>
3529 3531 </head>
3530 3532 <body>
3531 3533
3532 3534 <div class="container">
3533 3535 <div class="menu">
3534 3536 <div class="logo">
3535 3537 <a href="https://mercurial-scm.org/">
3536 3538 <img src="/static/hglogo.png" alt="mercurial" /></a>
3537 3539 </div>
3538 3540 <ul>
3539 3541 <li><a href="/shortlog">log</a></li>
3540 3542 <li><a href="/graph">graph</a></li>
3541 3543 <li><a href="/tags">tags</a></li>
3542 3544 <li><a href="/bookmarks">bookmarks</a></li>
3543 3545 <li><a href="/branches">branches</a></li>
3544 3546 </ul>
3545 3547 <ul>
3546 3548 <li><a href="/help">help</a></li>
3547 3549 </ul>
3548 3550 </div>
3549 3551
3550 3552 <div class="main">
3551 3553 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3552 3554
3553 3555 <form class="search" action="/log">
3554 3556
3555 3557 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3556 3558 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3557 3559 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3558 3560 </form>
3559 3561 <table class="bigtable">
3560 3562 <tr><td colspan="2"><h2><a name="topics" href="#topics">Topics</a></h2></td></tr>
3561 3563
3562 3564 <tr><td>
3563 3565 <a href="/help/internals.bid-merge">
3564 3566 bid-merge
3565 3567 </a>
3566 3568 </td><td>
3567 3569 Bid Merge Algorithm
3568 3570 </td></tr>
3569 3571 <tr><td>
3570 3572 <a href="/help/internals.bundle2">
3571 3573 bundle2
3572 3574 </a>
3573 3575 </td><td>
3574 3576 Bundle2
3575 3577 </td></tr>
3576 3578 <tr><td>
3577 3579 <a href="/help/internals.bundles">
3578 3580 bundles
3579 3581 </a>
3580 3582 </td><td>
3581 3583 Bundles
3582 3584 </td></tr>
3583 3585 <tr><td>
3584 3586 <a href="/help/internals.cbor">
3585 3587 cbor
3586 3588 </a>
3587 3589 </td><td>
3588 3590 CBOR
3589 3591 </td></tr>
3590 3592 <tr><td>
3591 3593 <a href="/help/internals.censor">
3592 3594 censor
3593 3595 </a>
3594 3596 </td><td>
3595 3597 Censor
3596 3598 </td></tr>
3597 3599 <tr><td>
3598 3600 <a href="/help/internals.changegroups">
3599 3601 changegroups
3600 3602 </a>
3601 3603 </td><td>
3602 3604 Changegroups
3603 3605 </td></tr>
3604 3606 <tr><td>
3605 3607 <a href="/help/internals.config">
3606 3608 config
3607 3609 </a>
3608 3610 </td><td>
3609 3611 Config Registrar
3610 3612 </td></tr>
3611 3613 <tr><td>
3612 3614 <a href="/help/internals.dirstate-v2">
3613 3615 dirstate-v2
3614 3616 </a>
3615 3617 </td><td>
3616 3618 dirstate-v2 file format
3617 3619 </td></tr>
3618 3620 <tr><td>
3619 3621 <a href="/help/internals.extensions">
3620 3622 extensions
3621 3623 </a>
3622 3624 </td><td>
3623 3625 Extension API
3624 3626 </td></tr>
3625 3627 <tr><td>
3626 3628 <a href="/help/internals.mergestate">
3627 3629 mergestate
3628 3630 </a>
3629 3631 </td><td>
3630 3632 Mergestate
3631 3633 </td></tr>
3632 3634 <tr><td>
3633 3635 <a href="/help/internals.requirements">
3634 3636 requirements
3635 3637 </a>
3636 3638 </td><td>
3637 3639 Repository Requirements
3638 3640 </td></tr>
3639 3641 <tr><td>
3640 3642 <a href="/help/internals.revlogs">
3641 3643 revlogs
3642 3644 </a>
3643 3645 </td><td>
3644 3646 Revision Logs
3645 3647 </td></tr>
3646 3648 <tr><td>
3647 3649 <a href="/help/internals.wireprotocol">
3648 3650 wireprotocol
3649 3651 </a>
3650 3652 </td><td>
3651 3653 Wire Protocol
3652 3654 </td></tr>
3653 3655 <tr><td>
3654 3656 <a href="/help/internals.wireprotocolrpc">
3655 3657 wireprotocolrpc
3656 3658 </a>
3657 3659 </td><td>
3658 3660 Wire Protocol RPC
3659 3661 </td></tr>
3660 3662 <tr><td>
3661 3663 <a href="/help/internals.wireprotocolv2">
3662 3664 wireprotocolv2
3663 3665 </a>
3664 3666 </td><td>
3665 3667 Wire Protocol Version 2
3666 3668 </td></tr>
3667 3669
3668 3670
3669 3671
3670 3672
3671 3673
3672 3674 </table>
3673 3675 </div>
3674 3676 </div>
3675 3677
3676 3678
3677 3679
3678 3680 </body>
3679 3681 </html>
3680 3682
3681 3683
3682 3684 Sub-topic topics rendered properly
3683 3685
3684 3686 $ get-with-headers.py $LOCALIP:$HGPORT "help/internals.changegroups"
3685 3687 200 Script output follows
3686 3688
3687 3689 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3688 3690 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3689 3691 <head>
3690 3692 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3691 3693 <meta name="robots" content="index, nofollow" />
3692 3694 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3693 3695 <script type="text/javascript" src="/static/mercurial.js"></script>
3694 3696
3695 3697 <title>Help: internals.changegroups</title>
3696 3698 </head>
3697 3699 <body>
3698 3700
3699 3701 <div class="container">
3700 3702 <div class="menu">
3701 3703 <div class="logo">
3702 3704 <a href="https://mercurial-scm.org/">
3703 3705 <img src="/static/hglogo.png" alt="mercurial" /></a>
3704 3706 </div>
3705 3707 <ul>
3706 3708 <li><a href="/shortlog">log</a></li>
3707 3709 <li><a href="/graph">graph</a></li>
3708 3710 <li><a href="/tags">tags</a></li>
3709 3711 <li><a href="/bookmarks">bookmarks</a></li>
3710 3712 <li><a href="/branches">branches</a></li>
3711 3713 </ul>
3712 3714 <ul>
3713 3715 <li class="active"><a href="/help">help</a></li>
3714 3716 </ul>
3715 3717 </div>
3716 3718
3717 3719 <div class="main">
3718 3720 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3719 3721 <h3>Help: internals.changegroups</h3>
3720 3722
3721 3723 <form class="search" action="/log">
3722 3724
3723 3725 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3724 3726 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3725 3727 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3726 3728 </form>
3727 3729 <div id="doc">
3728 3730 <h1>Changegroups</h1>
3729 3731 <p>
3730 3732 Changegroups are representations of repository revlog data, specifically
3731 3733 the changelog data, root/flat manifest data, treemanifest data, and
3732 3734 filelogs.
3733 3735 </p>
3734 3736 <p>
3735 3737 There are 4 versions of changegroups: &quot;1&quot;, &quot;2&quot;, &quot;3&quot; and &quot;4&quot;. From a
3736 3738 high-level, versions &quot;1&quot; and &quot;2&quot; are almost exactly the same, with the
3737 3739 only difference being an additional item in the *delta header*. Version
3738 3740 &quot;3&quot; adds support for storage flags in the *delta header* and optionally
3739 3741 exchanging treemanifests (enabled by setting an option on the
3740 3742 &quot;changegroup&quot; part in the bundle2). Version &quot;4&quot; adds support for exchanging
3741 3743 sidedata (additional revision metadata not part of the digest).
3742 3744 </p>
3743 3745 <p>
3744 3746 Changegroups when not exchanging treemanifests consist of 3 logical
3745 3747 segments:
3746 3748 </p>
3747 3749 <pre>
3748 3750 +---------------------------------+
3749 3751 | | | |
3750 3752 | changeset | manifest | filelogs |
3751 3753 | | | |
3752 3754 | | | |
3753 3755 +---------------------------------+
3754 3756 </pre>
3755 3757 <p>
3756 3758 When exchanging treemanifests, there are 4 logical segments:
3757 3759 </p>
3758 3760 <pre>
3759 3761 +-------------------------------------------------+
3760 3762 | | | | |
3761 3763 | changeset | root | treemanifests | filelogs |
3762 3764 | | manifest | | |
3763 3765 | | | | |
3764 3766 +-------------------------------------------------+
3765 3767 </pre>
3766 3768 <p>
3767 3769 The principle building block of each segment is a *chunk*. A *chunk*
3768 3770 is a framed piece of data:
3769 3771 </p>
3770 3772 <pre>
3771 3773 +---------------------------------------+
3772 3774 | | |
3773 3775 | length | data |
3774 3776 | (4 bytes) | (&lt;length - 4&gt; bytes) |
3775 3777 | | |
3776 3778 +---------------------------------------+
3777 3779 </pre>
3778 3780 <p>
3779 3781 All integers are big-endian signed integers. Each chunk starts with a 32-bit
3780 3782 integer indicating the length of the entire chunk (including the length field
3781 3783 itself).
3782 3784 </p>
3783 3785 <p>
3784 3786 There is a special case chunk that has a value of 0 for the length
3785 3787 (&quot;0x00000000&quot;). We call this an *empty chunk*.
3786 3788 </p>
3787 3789 <h2>Delta Groups</h2>
3788 3790 <p>
3789 3791 A *delta group* expresses the content of a revlog as a series of deltas,
3790 3792 or patches against previous revisions.
3791 3793 </p>
3792 3794 <p>
3793 3795 Delta groups consist of 0 or more *chunks* followed by the *empty chunk*
3794 3796 to signal the end of the delta group:
3795 3797 </p>
3796 3798 <pre>
3797 3799 +------------------------------------------------------------------------+
3798 3800 | | | | | |
3799 3801 | chunk0 length | chunk0 data | chunk1 length | chunk1 data | 0x0 |
3800 3802 | (4 bytes) | (various) | (4 bytes) | (various) | (4 bytes) |
3801 3803 | | | | | |
3802 3804 +------------------------------------------------------------------------+
3803 3805 </pre>
3804 3806 <p>
3805 3807 Each *chunk*'s data consists of the following:
3806 3808 </p>
3807 3809 <pre>
3808 3810 +---------------------------------------+
3809 3811 | | |
3810 3812 | delta header | delta data |
3811 3813 | (various by version) | (various) |
3812 3814 | | |
3813 3815 +---------------------------------------+
3814 3816 </pre>
3815 3817 <p>
3816 3818 The *delta data* is a series of *delta*s that describe a diff from an existing
3817 3819 entry (either that the recipient already has, or previously specified in the
3818 3820 bundle/changegroup).
3819 3821 </p>
3820 3822 <p>
3821 3823 The *delta header* is different between versions &quot;1&quot;, &quot;2&quot;, &quot;3&quot; and &quot;4&quot;
3822 3824 of the changegroup format.
3823 3825 </p>
3824 3826 <p>
3825 3827 Version 1 (headerlen=80):
3826 3828 </p>
3827 3829 <pre>
3828 3830 +------------------------------------------------------+
3829 3831 | | | | |
3830 3832 | node | p1 node | p2 node | link node |
3831 3833 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
3832 3834 | | | | |
3833 3835 +------------------------------------------------------+
3834 3836 </pre>
3835 3837 <p>
3836 3838 Version 2 (headerlen=100):
3837 3839 </p>
3838 3840 <pre>
3839 3841 +------------------------------------------------------------------+
3840 3842 | | | | | |
3841 3843 | node | p1 node | p2 node | base node | link node |
3842 3844 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
3843 3845 | | | | | |
3844 3846 +------------------------------------------------------------------+
3845 3847 </pre>
3846 3848 <p>
3847 3849 Version 3 (headerlen=102):
3848 3850 </p>
3849 3851 <pre>
3850 3852 +------------------------------------------------------------------------------+
3851 3853 | | | | | | |
3852 3854 | node | p1 node | p2 node | base node | link node | flags |
3853 3855 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (2 bytes) |
3854 3856 | | | | | | |
3855 3857 +------------------------------------------------------------------------------+
3856 3858 </pre>
3857 3859 <p>
3858 3860 Version 4 (headerlen=103):
3859 3861 </p>
3860 3862 <pre>
3861 3863 +------------------------------------------------------------------------------+----------+
3862 3864 | | | | | | | |
3863 3865 | node | p1 node | p2 node | base node | link node | flags | pflags |
3864 3866 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (2 bytes) | (1 byte) |
3865 3867 | | | | | | | |
3866 3868 +------------------------------------------------------------------------------+----------+
3867 3869 </pre>
3868 3870 <p>
3869 3871 The *delta data* consists of &quot;chunklen - 4 - headerlen&quot; bytes, which contain a
3870 3872 series of *delta*s, densely packed (no separators). These deltas describe a diff
3871 3873 from an existing entry (either that the recipient already has, or previously
3872 3874 specified in the bundle/changegroup). The format is described more fully in
3873 3875 &quot;hg help internals.bdiff&quot;, but briefly:
3874 3876 </p>
3875 3877 <pre>
3876 3878 +---------------------------------------------------------------+
3877 3879 | | | | |
3878 3880 | start offset | end offset | new length | content |
3879 3881 | (4 bytes) | (4 bytes) | (4 bytes) | (&lt;new length&gt; bytes) |
3880 3882 | | | | |
3881 3883 +---------------------------------------------------------------+
3882 3884 </pre>
3883 3885 <p>
3884 3886 Please note that the length field in the delta data does *not* include itself.
3885 3887 </p>
3886 3888 <p>
3887 3889 In version 1, the delta is always applied against the previous node from
3888 3890 the changegroup or the first parent if this is the first entry in the
3889 3891 changegroup.
3890 3892 </p>
3891 3893 <p>
3892 3894 In version 2 and up, the delta base node is encoded in the entry in the
3893 3895 changegroup. This allows the delta to be expressed against any parent,
3894 3896 which can result in smaller deltas and more efficient encoding of data.
3895 3897 </p>
3896 3898 <p>
3897 3899 The *flags* field holds bitwise flags affecting the processing of revision
3898 3900 data. The following flags are defined:
3899 3901 </p>
3900 3902 <dl>
3901 3903 <dt>32768
3902 3904 <dd>Censored revision. The revision's fulltext has been replaced by censor metadata. May only occur on file revisions.
3903 3905 <dt>16384
3904 3906 <dd>Ellipsis revision. Revision hash does not match data (likely due to rewritten parents).
3905 3907 <dt>8192
3906 3908 <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.
3907 3909 <dt>4096
3908 3910 <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.
3909 3911 </dl>
3910 3912 <p>
3911 3913 For historical reasons, the integer values are identical to revlog version 1
3912 3914 per-revision storage flags and correspond to bits being set in this 2-byte
3913 3915 field. Bits were allocated starting from the most-significant bit, hence the
3914 3916 reverse ordering and allocation of these flags.
3915 3917 </p>
3916 3918 <p>
3917 3919 The *pflags* (protocol flags) field holds bitwise flags affecting the protocol
3918 3920 itself. They are first in the header since they may affect the handling of the
3919 3921 rest of the fields in a future version. They are defined as such:
3920 3922 </p>
3921 3923 <dl>
3922 3924 <dt>1 indicates whether to read a chunk of sidedata (of variable length) right
3923 3925 <dd>after the revision flags.
3924 3926 </dl>
3925 3927 <h2>Changeset Segment</h2>
3926 3928 <p>
3927 3929 The *changeset segment* consists of a single *delta group* holding
3928 3930 changelog data. The *empty chunk* at the end of the *delta group* denotes
3929 3931 the boundary to the *manifest segment*.
3930 3932 </p>
3931 3933 <h2>Manifest Segment</h2>
3932 3934 <p>
3933 3935 The *manifest segment* consists of a single *delta group* holding manifest
3934 3936 data. If treemanifests are in use, it contains only the manifest for the
3935 3937 root directory of the repository. Otherwise, it contains the entire
3936 3938 manifest data. The *empty chunk* at the end of the *delta group* denotes
3937 3939 the boundary to the next segment (either the *treemanifests segment* or the
3938 3940 *filelogs segment*, depending on version and the request options).
3939 3941 </p>
3940 3942 <h3>Treemanifests Segment</h3>
3941 3943 <p>
3942 3944 The *treemanifests segment* only exists in changegroup version &quot;3&quot; and &quot;4&quot;,
3943 3945 and only if the 'treemanifest' param is part of the bundle2 changegroup part
3944 3946 (it is not possible to use changegroup version 3 or 4 outside of bundle2).
3945 3947 Aside from the filenames in the *treemanifests segment* containing a
3946 3948 trailing &quot;/&quot; character, it behaves identically to the *filelogs segment*
3947 3949 (see below). The final sub-segment is followed by an *empty chunk* (logically,
3948 3950 a sub-segment with filename size 0). This denotes the boundary to the
3949 3951 *filelogs segment*.
3950 3952 </p>
3951 3953 <h2>Filelogs Segment</h2>
3952 3954 <p>
3953 3955 The *filelogs segment* consists of multiple sub-segments, each
3954 3956 corresponding to an individual file whose data is being described:
3955 3957 </p>
3956 3958 <pre>
3957 3959 +--------------------------------------------------+
3958 3960 | | | | | |
3959 3961 | filelog0 | filelog1 | filelog2 | ... | 0x0 |
3960 3962 | | | | | (4 bytes) |
3961 3963 | | | | | |
3962 3964 +--------------------------------------------------+
3963 3965 </pre>
3964 3966 <p>
3965 3967 The final filelog sub-segment is followed by an *empty chunk* (logically,
3966 3968 a sub-segment with filename size 0). This denotes the end of the segment
3967 3969 and of the overall changegroup.
3968 3970 </p>
3969 3971 <p>
3970 3972 Each filelog sub-segment consists of the following:
3971 3973 </p>
3972 3974 <pre>
3973 3975 +------------------------------------------------------+
3974 3976 | | | |
3975 3977 | filename length | filename | delta group |
3976 3978 | (4 bytes) | (&lt;length - 4&gt; bytes) | (various) |
3977 3979 | | | |
3978 3980 +------------------------------------------------------+
3979 3981 </pre>
3980 3982 <p>
3981 3983 That is, a *chunk* consisting of the filename (not terminated or padded)
3982 3984 followed by N chunks constituting the *delta group* for this file. The
3983 3985 *empty chunk* at the end of each *delta group* denotes the boundary to the
3984 3986 next filelog sub-segment.
3985 3987 </p>
3986 3988
3987 3989 </div>
3988 3990 </div>
3989 3991 </div>
3990 3992
3991 3993
3992 3994
3993 3995 </body>
3994 3996 </html>
3995 3997
3996 3998
3997 3999 $ get-with-headers.py 127.0.0.1:$HGPORT "help/unknowntopic"
3998 4000 404 Not Found
3999 4001
4000 4002 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
4001 4003 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
4002 4004 <head>
4003 4005 <link rel="icon" href="/static/hgicon.png" type="image/png" />
4004 4006 <meta name="robots" content="index, nofollow" />
4005 4007 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
4006 4008 <script type="text/javascript" src="/static/mercurial.js"></script>
4007 4009
4008 4010 <title>test: error</title>
4009 4011 </head>
4010 4012 <body>
4011 4013
4012 4014 <div class="container">
4013 4015 <div class="menu">
4014 4016 <div class="logo">
4015 4017 <a href="https://mercurial-scm.org/">
4016 4018 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
4017 4019 </div>
4018 4020 <ul>
4019 4021 <li><a href="/shortlog">log</a></li>
4020 4022 <li><a href="/graph">graph</a></li>
4021 4023 <li><a href="/tags">tags</a></li>
4022 4024 <li><a href="/bookmarks">bookmarks</a></li>
4023 4025 <li><a href="/branches">branches</a></li>
4024 4026 </ul>
4025 4027 <ul>
4026 4028 <li><a href="/help">help</a></li>
4027 4029 </ul>
4028 4030 </div>
4029 4031
4030 4032 <div class="main">
4031 4033
4032 4034 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
4033 4035 <h3>error</h3>
4034 4036
4035 4037
4036 4038 <form class="search" action="/log">
4037 4039
4038 4040 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
4039 4041 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
4040 4042 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
4041 4043 </form>
4042 4044
4043 4045 <div class="description">
4044 4046 <p>
4045 4047 An error occurred while processing your request:
4046 4048 </p>
4047 4049 <p>
4048 4050 Not Found
4049 4051 </p>
4050 4052 </div>
4051 4053 </div>
4052 4054 </div>
4053 4055
4054 4056
4055 4057
4056 4058 </body>
4057 4059 </html>
4058 4060
4059 4061 [1]
4060 4062
4061 4063 $ killdaemons.py
4062 4064
4063 4065 #endif
@@ -1,152 +1,194 b''
1 1 ====================================
2 2 Test delta choice with sparse revlog
3 3 ====================================
4 4
5 5 Sparse-revlog usually shows the most gain on Manifest. However, it is simpler
6 6 to general an appropriate file, so we test with a single file instead. The
7 7 goal is to observe intermediate snapshot being created.
8 8
9 9 We need a large enough file. Part of the content needs to be replaced
10 10 repeatedly while some of it changes rarely.
11 11
12 12 $ bundlepath="$TESTDIR/artifacts/cache/big-file-churn.hg"
13 13
14 14 $ expectedhash=`cat "$bundlepath".md5`
15 15
16 16 #if slow
17 17
18 18 $ if [ ! -f "$bundlepath" ]; then
19 19 > "$TESTDIR"/artifacts/scripts/generate-churning-bundle.py > /dev/null
20 20 > fi
21 21
22 22 #else
23 23
24 24 $ if [ ! -f "$bundlepath" ]; then
25 25 > echo 'skipped: missing artifact, run "'"$TESTDIR"'/artifacts/scripts/generate-churning-bundle.py"'
26 26 > exit 80
27 27 > fi
28 28
29 29 #endif
30 30
31 31 $ currenthash=`f -M "$bundlepath" | cut -d = -f 2`
32 32 $ if [ "$currenthash" != "$expectedhash" ]; then
33 33 > echo 'skipped: outdated artifact, md5 "'"$currenthash"'" expected "'"$expectedhash"'" run "'"$TESTDIR"'/artifacts/scripts/generate-churning-bundle.py"'
34 34 > exit 80
35 35 > fi
36 36
37 37 $ cat >> $HGRCPATH << EOF
38 38 > [format]
39 39 > sparse-revlog = yes
40 40 > maxchainlen = 15
41 41 > [storage]
42 42 > revlog.optimize-delta-parent-choice = yes
43 43 > revlog.reuse-external-delta = no
44 44 > EOF
45 45 $ hg init sparse-repo
46 46 $ cd sparse-repo
47 47 $ hg unbundle $bundlepath
48 48 adding changesets
49 49 adding manifests
50 50 adding file changes
51 51 added 5001 changesets with 5001 changes to 1 files (+89 heads)
52 52 new changesets 9706f5af64f4:d9032adc8114 (5001 drafts)
53 53 (run 'hg heads' to see heads, 'hg merge' to merge)
54 54 $ hg up
55 55 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
56 56 updated to "d9032adc8114: commit #5000"
57 57 89 other heads for branch "default"
58 58
59 59 $ hg log --stat -r 0:3
60 60 changeset: 0:9706f5af64f4
61 61 user: test
62 62 date: Thu Jan 01 00:00:00 1970 +0000
63 63 summary: initial commit
64 64
65 65 SPARSE-REVLOG-TEST-FILE | 10500 ++++++++++++++++++++++++++++++++++++++++++++++
66 66 1 files changed, 10500 insertions(+), 0 deletions(-)
67 67
68 68 changeset: 1:724907deaa5e
69 69 user: test
70 70 date: Thu Jan 01 00:00:00 1970 +0000
71 71 summary: commit #1
72 72
73 73 SPARSE-REVLOG-TEST-FILE | 1068 +++++++++++++++++++++++-----------------------
74 74 1 files changed, 534 insertions(+), 534 deletions(-)
75 75
76 76 changeset: 2:62c41bce3e5d
77 77 user: test
78 78 date: Thu Jan 01 00:00:00 1970 +0000
79 79 summary: commit #2
80 80
81 81 SPARSE-REVLOG-TEST-FILE | 1068 +++++++++++++++++++++++-----------------------
82 82 1 files changed, 534 insertions(+), 534 deletions(-)
83 83
84 84 changeset: 3:348a9cbd6959
85 85 user: test
86 86 date: Thu Jan 01 00:00:00 1970 +0000
87 87 summary: commit #3
88 88
89 89 SPARSE-REVLOG-TEST-FILE | 1068 +++++++++++++++++++++++-----------------------
90 90 1 files changed, 534 insertions(+), 534 deletions(-)
91 91
92 92
93 93 $ f -s .hg/store/data/*.d
94 94 .hg/store/data/_s_p_a_r_s_e-_r_e_v_l_o_g-_t_e_s_t-_f_i_l_e.d: size=58616973
95 95 $ hg debugrevlog *
96 96 format : 1
97 97 flags : generaldelta
98 98
99 99 revisions : 5001
100 100 merges : 625 (12.50%)
101 101 normal : 4376 (87.50%)
102 102 revisions : 5001
103 103 empty : 0 ( 0.00%)
104 104 text : 0 (100.00%)
105 105 delta : 0 (100.00%)
106 106 snapshot : 383 ( 7.66%)
107 107 lvl-0 : 3 ( 0.06%)
108 108 lvl-1 : 18 ( 0.36%)
109 109 lvl-2 : 62 ( 1.24%)
110 110 lvl-3 : 108 ( 2.16%)
111 111 lvl-4 : 191 ( 3.82%)
112 112 lvl-5 : 1 ( 0.02%)
113 113 deltas : 4618 (92.34%)
114 114 revision size : 58616973
115 115 snapshot : 9247844 (15.78%)
116 116 lvl-0 : 539532 ( 0.92%)
117 117 lvl-1 : 1467743 ( 2.50%)
118 118 lvl-2 : 1873820 ( 3.20%)
119 119 lvl-3 : 2326874 ( 3.97%)
120 120 lvl-4 : 3029118 ( 5.17%)
121 121 lvl-5 : 10757 ( 0.02%)
122 122 deltas : 49369129 (84.22%)
123 123
124 124 chunks : 5001
125 125 0x28 : 5001 (100.00%)
126 126 chunks size : 58616973
127 127 0x28 : 58616973 (100.00%)
128 128
129 129 avg chain length : 9
130 130 max chain length : 15
131 131 max chain reach : 27366701
132 132 compression ratio : 29
133 133
134 134 uncompressed data size (min/max/avg) : 346468 / 346472 / 346471
135 135 full revision size (min/max/avg) : 179288 / 180786 / 179844
136 136 inter-snapshot size (min/max/avg) : 10757 / 169507 / 22916
137 137 level-1 (min/max/avg) : 13905 / 169507 / 81541
138 138 level-2 (min/max/avg) : 10887 / 83873 / 30222
139 139 level-3 (min/max/avg) : 10911 / 43047 / 21545
140 140 level-4 (min/max/avg) : 10838 / 21390 / 15859
141 141 level-5 (min/max/avg) : 10757 / 10757 / 10757
142 142 delta size (min/max/avg) : 9672 / 108072 / 10690
143 143
144 144 deltas against prev : 3906 (84.58%)
145 145 where prev = p1 : 3906 (100.00%)
146 146 where prev = p2 : 0 ( 0.00%)
147 147 other : 0 ( 0.00%)
148 148 deltas against p1 : 649 (14.05%)
149 149 deltas against p2 : 63 ( 1.36%)
150 150 deltas against other : 0 ( 0.00%)
151 151
152
153 Test `debug-delta-find`
154 -----------------------
155
156 $ ls -1
157 SPARSE-REVLOG-TEST-FILE
158 $ hg debugdeltachain SPARSE-REVLOG-TEST-FILE | grep other | tail -1
159 4971 3 5 4930 other 19179 346472 427596 1.23414 15994877 15567281 36.40652 427596 179288 1.00000 5
160 $ hg debug-delta-find SPARSE-REVLOG-TEST-FILE 4971
161 DBG-DELTAS-SEARCH: SEARCH rev=4971
162 DBG-DELTAS-SEARCH: ROUND #1 - 2 candidates - search-down
163 DBG-DELTAS-SEARCH: CANDIDATE: rev=4962
164 DBG-DELTAS-SEARCH: type=snapshot-4
165 DBG-DELTAS-SEARCH: size=18296
166 DBG-DELTAS-SEARCH: base=4930
167 DBG-DELTAS-SEARCH: uncompressed-delta-size=30377
168 DBG-DELTAS-SEARCH: delta-search-time=* (glob)
169 DBG-DELTAS-SEARCH: DELTA: length=16872 (BAD)
170 DBG-DELTAS-SEARCH: CANDIDATE: rev=4971
171 DBG-DELTAS-SEARCH: type=snapshot-4
172 DBG-DELTAS-SEARCH: size=19179
173 DBG-DELTAS-SEARCH: base=4930
174 DBG-DELTAS-SEARCH: TOO-HIGH
175 DBG-DELTAS-SEARCH: ROUND #2 - 1 candidates - search-down
176 DBG-DELTAS-SEARCH: CANDIDATE: rev=4930
177 DBG-DELTAS-SEARCH: type=snapshot-3
178 DBG-DELTAS-SEARCH: size=39228
179 DBG-DELTAS-SEARCH: base=4799
180 DBG-DELTAS-SEARCH: uncompressed-delta-size=33050
181 DBG-DELTAS-SEARCH: delta-search-time=* (glob)
182 DBG-DELTAS-SEARCH: DELTA: length=19179 (GOOD)
183 DBG-DELTAS-SEARCH: ROUND #3 - 1 candidates - refine-down
184 DBG-DELTAS-SEARCH: CONTENDER: rev=4930 - length=19179
185 DBG-DELTAS-SEARCH: CANDIDATE: rev=4799
186 DBG-DELTAS-SEARCH: type=snapshot-2
187 DBG-DELTAS-SEARCH: size=50213
188 DBG-DELTAS-SEARCH: base=4623
189 DBG-DELTAS-SEARCH: uncompressed-delta-size=82661
190 DBG-DELTAS-SEARCH: delta-search-time=* (glob)
191 DBG-DELTAS-SEARCH: DELTA: length=49132 (BAD)
192 DBG-DELTAS: FILELOG:SPARSE-REVLOG-TEST-FILE: rev=4971: search-rounds=3 try-count=3 - delta-type=snapshot snap-depth=4 - p1-chain-length=15 p2-chain-length=-1 - duration=* (glob)
193
152 194 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now