##// END OF EJS Templates
debugcommands: introduce a debug command to repair repos affected by issue6528...
Raphaël Gomès -
r48623:b30a53ff stable
parent child Browse files
Show More
1 NO CONTENT: new file 100644, binary diff hidden
@@ -1,4856 +1,4915
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 from __future__ import absolute_import
9 9
10 10 import binascii
11 11 import codecs
12 12 import collections
13 13 import contextlib
14 14 import difflib
15 15 import errno
16 16 import glob
17 17 import operator
18 18 import os
19 19 import platform
20 20 import random
21 21 import re
22 22 import socket
23 23 import ssl
24 24 import stat
25 25 import string
26 26 import subprocess
27 27 import sys
28 28 import time
29 29
30 30 from .i18n import _
31 31 from .node import (
32 32 bin,
33 33 hex,
34 34 nullrev,
35 35 short,
36 36 )
37 37 from .pycompat import (
38 38 getattr,
39 39 open,
40 40 )
41 41 from . import (
42 42 bundle2,
43 43 bundlerepo,
44 44 changegroup,
45 45 cmdutil,
46 46 color,
47 47 context,
48 48 copies,
49 49 dagparser,
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 requirements,
74 75 revlog,
75 76 revset,
76 77 revsetlang,
77 78 scmutil,
78 79 setdiscovery,
79 80 simplemerge,
80 81 sshpeer,
81 82 sslutil,
82 83 streamclone,
83 84 strip,
84 85 tags as tagsmod,
85 86 templater,
86 87 treediscovery,
87 88 upgrade,
88 89 url as urlmod,
89 90 util,
90 91 vfs as vfsmod,
91 92 wireprotoframing,
92 93 wireprotoserver,
93 94 wireprotov2peer,
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 deltas as deltautil,
107 108 nodemap,
109 rewrite,
108 110 sidedata,
109 111 )
110 112
111 113 release = lockmod.release
112 114
113 115 table = {}
114 116 table.update(strip.command._table)
115 117 command = registrar.command(table)
116 118
117 119
118 120 @command(b'debugancestor', [], _(b'[INDEX] REV1 REV2'), optionalrepo=True)
119 121 def debugancestor(ui, repo, *args):
120 122 """find the ancestor revision of two revisions in a given index"""
121 123 if len(args) == 3:
122 124 index, rev1, rev2 = args
123 125 r = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False), index)
124 126 lookup = r.lookup
125 127 elif len(args) == 2:
126 128 if not repo:
127 129 raise error.Abort(
128 130 _(b'there is no Mercurial repository here (.hg not found)')
129 131 )
130 132 rev1, rev2 = args
131 133 r = repo.changelog
132 134 lookup = repo.lookup
133 135 else:
134 136 raise error.Abort(_(b'either two or three arguments required'))
135 137 a = r.ancestor(lookup(rev1), lookup(rev2))
136 138 ui.write(b'%d:%s\n' % (r.rev(a), hex(a)))
137 139
138 140
139 141 @command(b'debugantivirusrunning', [])
140 142 def debugantivirusrunning(ui, repo):
141 143 """attempt to trigger an antivirus scanner to see if one is active"""
142 144 with repo.cachevfs.open('eicar-test-file.com', b'wb') as f:
143 145 f.write(
144 146 util.b85decode(
145 147 # This is a base85-armored version of the EICAR test file. See
146 148 # https://en.wikipedia.org/wiki/EICAR_test_file for details.
147 149 b'ST#=}P$fV?P+K%yP+C|uG$>GBDK|qyDK~v2MM*<JQY}+dK~6+LQba95P'
148 150 b'E<)&Nm5l)EmTEQR4qnHOhq9iNGnJx'
149 151 )
150 152 )
151 153 # Give an AV engine time to scan the file.
152 154 time.sleep(2)
153 155 util.unlink(repo.cachevfs.join('eicar-test-file.com'))
154 156
155 157
156 158 @command(b'debugapplystreamclonebundle', [], b'FILE')
157 159 def debugapplystreamclonebundle(ui, repo, fname):
158 160 """apply a stream clone bundle file"""
159 161 f = hg.openpath(ui, fname)
160 162 gen = exchange.readbundle(ui, f, fname)
161 163 gen.apply(repo)
162 164
163 165
164 166 @command(
165 167 b'debugbuilddag',
166 168 [
167 169 (
168 170 b'm',
169 171 b'mergeable-file',
170 172 None,
171 173 _(b'add single file mergeable changes'),
172 174 ),
173 175 (
174 176 b'o',
175 177 b'overwritten-file',
176 178 None,
177 179 _(b'add single file all revs overwrite'),
178 180 ),
179 181 (b'n', b'new-file', None, _(b'add new file at each rev')),
180 182 ],
181 183 _(b'[OPTION]... [TEXT]'),
182 184 )
183 185 def debugbuilddag(
184 186 ui,
185 187 repo,
186 188 text=None,
187 189 mergeable_file=False,
188 190 overwritten_file=False,
189 191 new_file=False,
190 192 ):
191 193 """builds a repo with a given DAG from scratch in the current empty repo
192 194
193 195 The description of the DAG is read from stdin if not given on the
194 196 command line.
195 197
196 198 Elements:
197 199
198 200 - "+n" is a linear run of n nodes based on the current default parent
199 201 - "." is a single node based on the current default parent
200 202 - "$" resets the default parent to null (implied at the start);
201 203 otherwise the default parent is always the last node created
202 204 - "<p" sets the default parent to the backref p
203 205 - "*p" is a fork at parent p, which is a backref
204 206 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
205 207 - "/p2" is a merge of the preceding node and p2
206 208 - ":tag" defines a local tag for the preceding node
207 209 - "@branch" sets the named branch for subsequent nodes
208 210 - "#...\\n" is a comment up to the end of the line
209 211
210 212 Whitespace between the above elements is ignored.
211 213
212 214 A backref is either
213 215
214 216 - a number n, which references the node curr-n, where curr is the current
215 217 node, or
216 218 - the name of a local tag you placed earlier using ":tag", or
217 219 - empty to denote the default parent.
218 220
219 221 All string valued-elements are either strictly alphanumeric, or must
220 222 be enclosed in double quotes ("..."), with "\\" as escape character.
221 223 """
222 224
223 225 if text is None:
224 226 ui.status(_(b"reading DAG from stdin\n"))
225 227 text = ui.fin.read()
226 228
227 229 cl = repo.changelog
228 230 if len(cl) > 0:
229 231 raise error.Abort(_(b'repository is not empty'))
230 232
231 233 # determine number of revs in DAG
232 234 total = 0
233 235 for type, data in dagparser.parsedag(text):
234 236 if type == b'n':
235 237 total += 1
236 238
237 239 if mergeable_file:
238 240 linesperrev = 2
239 241 # make a file with k lines per rev
240 242 initialmergedlines = [
241 243 b'%d' % i for i in pycompat.xrange(0, total * linesperrev)
242 244 ]
243 245 initialmergedlines.append(b"")
244 246
245 247 tags = []
246 248 progress = ui.makeprogress(
247 249 _(b'building'), unit=_(b'revisions'), total=total
248 250 )
249 251 with progress, repo.wlock(), repo.lock(), repo.transaction(b"builddag"):
250 252 at = -1
251 253 atbranch = b'default'
252 254 nodeids = []
253 255 id = 0
254 256 progress.update(id)
255 257 for type, data in dagparser.parsedag(text):
256 258 if type == b'n':
257 259 ui.note((b'node %s\n' % pycompat.bytestr(data)))
258 260 id, ps = data
259 261
260 262 files = []
261 263 filecontent = {}
262 264
263 265 p2 = None
264 266 if mergeable_file:
265 267 fn = b"mf"
266 268 p1 = repo[ps[0]]
267 269 if len(ps) > 1:
268 270 p2 = repo[ps[1]]
269 271 pa = p1.ancestor(p2)
270 272 base, local, other = [
271 273 x[fn].data() for x in (pa, p1, p2)
272 274 ]
273 275 m3 = simplemerge.Merge3Text(base, local, other)
274 276 ml = [l.strip() for l in m3.merge_lines()]
275 277 ml.append(b"")
276 278 elif at > 0:
277 279 ml = p1[fn].data().split(b"\n")
278 280 else:
279 281 ml = initialmergedlines
280 282 ml[id * linesperrev] += b" r%i" % id
281 283 mergedtext = b"\n".join(ml)
282 284 files.append(fn)
283 285 filecontent[fn] = mergedtext
284 286
285 287 if overwritten_file:
286 288 fn = b"of"
287 289 files.append(fn)
288 290 filecontent[fn] = b"r%i\n" % id
289 291
290 292 if new_file:
291 293 fn = b"nf%i" % id
292 294 files.append(fn)
293 295 filecontent[fn] = b"r%i\n" % id
294 296 if len(ps) > 1:
295 297 if not p2:
296 298 p2 = repo[ps[1]]
297 299 for fn in p2:
298 300 if fn.startswith(b"nf"):
299 301 files.append(fn)
300 302 filecontent[fn] = p2[fn].data()
301 303
302 304 def fctxfn(repo, cx, path):
303 305 if path in filecontent:
304 306 return context.memfilectx(
305 307 repo, cx, path, filecontent[path]
306 308 )
307 309 return None
308 310
309 311 if len(ps) == 0 or ps[0] < 0:
310 312 pars = [None, None]
311 313 elif len(ps) == 1:
312 314 pars = [nodeids[ps[0]], None]
313 315 else:
314 316 pars = [nodeids[p] for p in ps]
315 317 cx = context.memctx(
316 318 repo,
317 319 pars,
318 320 b"r%i" % id,
319 321 files,
320 322 fctxfn,
321 323 date=(id, 0),
322 324 user=b"debugbuilddag",
323 325 extra={b'branch': atbranch},
324 326 )
325 327 nodeid = repo.commitctx(cx)
326 328 nodeids.append(nodeid)
327 329 at = id
328 330 elif type == b'l':
329 331 id, name = data
330 332 ui.note((b'tag %s\n' % name))
331 333 tags.append(b"%s %s\n" % (hex(repo.changelog.node(id)), name))
332 334 elif type == b'a':
333 335 ui.note((b'branch %s\n' % data))
334 336 atbranch = data
335 337 progress.update(id)
336 338
337 339 if tags:
338 340 repo.vfs.write(b"localtags", b"".join(tags))
339 341
340 342
341 343 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
342 344 indent_string = b' ' * indent
343 345 if all:
344 346 ui.writenoi18n(
345 347 b"%sformat: id, p1, p2, cset, delta base, len(delta)\n"
346 348 % indent_string
347 349 )
348 350
349 351 def showchunks(named):
350 352 ui.write(b"\n%s%s\n" % (indent_string, named))
351 353 for deltadata in gen.deltaiter():
352 354 node, p1, p2, cs, deltabase, delta, flags, sidedata = deltadata
353 355 ui.write(
354 356 b"%s%s %s %s %s %s %d\n"
355 357 % (
356 358 indent_string,
357 359 hex(node),
358 360 hex(p1),
359 361 hex(p2),
360 362 hex(cs),
361 363 hex(deltabase),
362 364 len(delta),
363 365 )
364 366 )
365 367
366 368 gen.changelogheader()
367 369 showchunks(b"changelog")
368 370 gen.manifestheader()
369 371 showchunks(b"manifest")
370 372 for chunkdata in iter(gen.filelogheader, {}):
371 373 fname = chunkdata[b'filename']
372 374 showchunks(fname)
373 375 else:
374 376 if isinstance(gen, bundle2.unbundle20):
375 377 raise error.Abort(_(b'use debugbundle2 for this file'))
376 378 gen.changelogheader()
377 379 for deltadata in gen.deltaiter():
378 380 node, p1, p2, cs, deltabase, delta, flags, sidedata = deltadata
379 381 ui.write(b"%s%s\n" % (indent_string, hex(node)))
380 382
381 383
382 384 def _debugobsmarkers(ui, part, indent=0, **opts):
383 385 """display version and markers contained in 'data'"""
384 386 opts = pycompat.byteskwargs(opts)
385 387 data = part.read()
386 388 indent_string = b' ' * indent
387 389 try:
388 390 version, markers = obsolete._readmarkers(data)
389 391 except error.UnknownVersion as exc:
390 392 msg = b"%sunsupported version: %s (%d bytes)\n"
391 393 msg %= indent_string, exc.version, len(data)
392 394 ui.write(msg)
393 395 else:
394 396 msg = b"%sversion: %d (%d bytes)\n"
395 397 msg %= indent_string, version, len(data)
396 398 ui.write(msg)
397 399 fm = ui.formatter(b'debugobsolete', opts)
398 400 for rawmarker in sorted(markers):
399 401 m = obsutil.marker(None, rawmarker)
400 402 fm.startitem()
401 403 fm.plain(indent_string)
402 404 cmdutil.showmarker(fm, m)
403 405 fm.end()
404 406
405 407
406 408 def _debugphaseheads(ui, data, indent=0):
407 409 """display version and markers contained in 'data'"""
408 410 indent_string = b' ' * indent
409 411 headsbyphase = phases.binarydecode(data)
410 412 for phase in phases.allphases:
411 413 for head in headsbyphase[phase]:
412 414 ui.write(indent_string)
413 415 ui.write(b'%s %s\n' % (hex(head), phases.phasenames[phase]))
414 416
415 417
416 418 def _quasirepr(thing):
417 419 if isinstance(thing, (dict, util.sortdict, collections.OrderedDict)):
418 420 return b'{%s}' % (
419 421 b', '.join(b'%s: %s' % (k, thing[k]) for k in sorted(thing))
420 422 )
421 423 return pycompat.bytestr(repr(thing))
422 424
423 425
424 426 def _debugbundle2(ui, gen, all=None, **opts):
425 427 """lists the contents of a bundle2"""
426 428 if not isinstance(gen, bundle2.unbundle20):
427 429 raise error.Abort(_(b'not a bundle2 file'))
428 430 ui.write((b'Stream params: %s\n' % _quasirepr(gen.params)))
429 431 parttypes = opts.get('part_type', [])
430 432 for part in gen.iterparts():
431 433 if parttypes and part.type not in parttypes:
432 434 continue
433 435 msg = b'%s -- %s (mandatory: %r)\n'
434 436 ui.write((msg % (part.type, _quasirepr(part.params), part.mandatory)))
435 437 if part.type == b'changegroup':
436 438 version = part.params.get(b'version', b'01')
437 439 cg = changegroup.getunbundler(version, part, b'UN')
438 440 if not ui.quiet:
439 441 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
440 442 if part.type == b'obsmarkers':
441 443 if not ui.quiet:
442 444 _debugobsmarkers(ui, part, indent=4, **opts)
443 445 if part.type == b'phase-heads':
444 446 if not ui.quiet:
445 447 _debugphaseheads(ui, part, indent=4)
446 448
447 449
448 450 @command(
449 451 b'debugbundle',
450 452 [
451 453 (b'a', b'all', None, _(b'show all details')),
452 454 (b'', b'part-type', [], _(b'show only the named part type')),
453 455 (b'', b'spec', None, _(b'print the bundlespec of the bundle')),
454 456 ],
455 457 _(b'FILE'),
456 458 norepo=True,
457 459 )
458 460 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
459 461 """lists the contents of a bundle"""
460 462 with hg.openpath(ui, bundlepath) as f:
461 463 if spec:
462 464 spec = exchange.getbundlespec(ui, f)
463 465 ui.write(b'%s\n' % spec)
464 466 return
465 467
466 468 gen = exchange.readbundle(ui, f, bundlepath)
467 469 if isinstance(gen, bundle2.unbundle20):
468 470 return _debugbundle2(ui, gen, all=all, **opts)
469 471 _debugchangegroup(ui, gen, all=all, **opts)
470 472
471 473
472 474 @command(b'debugcapabilities', [], _(b'PATH'), norepo=True)
473 475 def debugcapabilities(ui, path, **opts):
474 476 """lists the capabilities of a remote peer"""
475 477 opts = pycompat.byteskwargs(opts)
476 478 peer = hg.peer(ui, opts, path)
477 479 try:
478 480 caps = peer.capabilities()
479 481 ui.writenoi18n(b'Main capabilities:\n')
480 482 for c in sorted(caps):
481 483 ui.write(b' %s\n' % c)
482 484 b2caps = bundle2.bundle2caps(peer)
483 485 if b2caps:
484 486 ui.writenoi18n(b'Bundle2 capabilities:\n')
485 487 for key, values in sorted(pycompat.iteritems(b2caps)):
486 488 ui.write(b' %s\n' % key)
487 489 for v in values:
488 490 ui.write(b' %s\n' % v)
489 491 finally:
490 492 peer.close()
491 493
492 494
493 495 @command(
494 496 b'debugchangedfiles',
495 497 [
496 498 (
497 499 b'',
498 500 b'compute',
499 501 False,
500 502 b"compute information instead of reading it from storage",
501 503 ),
502 504 ],
503 505 b'REV',
504 506 )
505 507 def debugchangedfiles(ui, repo, rev, **opts):
506 508 """list the stored files changes for a revision"""
507 509 ctx = scmutil.revsingle(repo, rev, None)
508 510 files = None
509 511
510 512 if opts['compute']:
511 513 files = metadata.compute_all_files_changes(ctx)
512 514 else:
513 515 sd = repo.changelog.sidedata(ctx.rev())
514 516 files_block = sd.get(sidedata.SD_FILES)
515 517 if files_block is not None:
516 518 files = metadata.decode_files_sidedata(sd)
517 519 if files is not None:
518 520 for f in sorted(files.touched):
519 521 if f in files.added:
520 522 action = b"added"
521 523 elif f in files.removed:
522 524 action = b"removed"
523 525 elif f in files.merged:
524 526 action = b"merged"
525 527 elif f in files.salvaged:
526 528 action = b"salvaged"
527 529 else:
528 530 action = b"touched"
529 531
530 532 copy_parent = b""
531 533 copy_source = b""
532 534 if f in files.copied_from_p1:
533 535 copy_parent = b"p1"
534 536 copy_source = files.copied_from_p1[f]
535 537 elif f in files.copied_from_p2:
536 538 copy_parent = b"p2"
537 539 copy_source = files.copied_from_p2[f]
538 540
539 541 data = (action, copy_parent, f, copy_source)
540 542 template = b"%-8s %2s: %s, %s;\n"
541 543 ui.write(template % data)
542 544
543 545
544 546 @command(b'debugcheckstate', [], b'')
545 547 def debugcheckstate(ui, repo):
546 548 """validate the correctness of the current dirstate"""
547 549 parent1, parent2 = repo.dirstate.parents()
548 550 m1 = repo[parent1].manifest()
549 551 m2 = repo[parent2].manifest()
550 552 errors = 0
551 553 for f in repo.dirstate:
552 554 state = repo.dirstate[f]
553 555 if state in b"nr" and f not in m1:
554 556 ui.warn(_(b"%s in state %s, but not in manifest1\n") % (f, state))
555 557 errors += 1
556 558 if state in b"a" and f in m1:
557 559 ui.warn(_(b"%s in state %s, but also in manifest1\n") % (f, state))
558 560 errors += 1
559 561 if state in b"m" and f not in m1 and f not in m2:
560 562 ui.warn(
561 563 _(b"%s in state %s, but not in either manifest\n") % (f, state)
562 564 )
563 565 errors += 1
564 566 for f in m1:
565 567 state = repo.dirstate[f]
566 568 if state not in b"nrm":
567 569 ui.warn(_(b"%s in manifest1, but listed as state %s") % (f, state))
568 570 errors += 1
569 571 if errors:
570 572 errstr = _(b".hg/dirstate inconsistent with current parent's manifest")
571 573 raise error.Abort(errstr)
572 574
573 575
574 576 @command(
575 577 b'debugcolor',
576 578 [(b'', b'style', None, _(b'show all configured styles'))],
577 579 b'hg debugcolor',
578 580 )
579 581 def debugcolor(ui, repo, **opts):
580 582 """show available color, effects or style"""
581 583 ui.writenoi18n(b'color mode: %s\n' % stringutil.pprint(ui._colormode))
582 584 if opts.get('style'):
583 585 return _debugdisplaystyle(ui)
584 586 else:
585 587 return _debugdisplaycolor(ui)
586 588
587 589
588 590 def _debugdisplaycolor(ui):
589 591 ui = ui.copy()
590 592 ui._styles.clear()
591 593 for effect in color._activeeffects(ui).keys():
592 594 ui._styles[effect] = effect
593 595 if ui._terminfoparams:
594 596 for k, v in ui.configitems(b'color'):
595 597 if k.startswith(b'color.'):
596 598 ui._styles[k] = k[6:]
597 599 elif k.startswith(b'terminfo.'):
598 600 ui._styles[k] = k[9:]
599 601 ui.write(_(b'available colors:\n'))
600 602 # sort label with a '_' after the other to group '_background' entry.
601 603 items = sorted(ui._styles.items(), key=lambda i: (b'_' in i[0], i[0], i[1]))
602 604 for colorname, label in items:
603 605 ui.write(b'%s\n' % colorname, label=label)
604 606
605 607
606 608 def _debugdisplaystyle(ui):
607 609 ui.write(_(b'available style:\n'))
608 610 if not ui._styles:
609 611 return
610 612 width = max(len(s) for s in ui._styles)
611 613 for label, effects in sorted(ui._styles.items()):
612 614 ui.write(b'%s' % label, label=label)
613 615 if effects:
614 616 # 50
615 617 ui.write(b': ')
616 618 ui.write(b' ' * (max(0, width - len(label))))
617 619 ui.write(b', '.join(ui.label(e, e) for e in effects.split()))
618 620 ui.write(b'\n')
619 621
620 622
621 623 @command(b'debugcreatestreamclonebundle', [], b'FILE')
622 624 def debugcreatestreamclonebundle(ui, repo, fname):
623 625 """create a stream clone bundle file
624 626
625 627 Stream bundles are special bundles that are essentially archives of
626 628 revlog files. They are commonly used for cloning very quickly.
627 629 """
628 630 # TODO we may want to turn this into an abort when this functionality
629 631 # is moved into `hg bundle`.
630 632 if phases.hassecret(repo):
631 633 ui.warn(
632 634 _(
633 635 b'(warning: stream clone bundle will contain secret '
634 636 b'revisions)\n'
635 637 )
636 638 )
637 639
638 640 requirements, gen = streamclone.generatebundlev1(repo)
639 641 changegroup.writechunks(ui, gen, fname)
640 642
641 643 ui.write(_(b'bundle requirements: %s\n') % b', '.join(sorted(requirements)))
642 644
643 645
644 646 @command(
645 647 b'debugdag',
646 648 [
647 649 (b't', b'tags', None, _(b'use tags as labels')),
648 650 (b'b', b'branches', None, _(b'annotate with branch names')),
649 651 (b'', b'dots', None, _(b'use dots for runs')),
650 652 (b's', b'spaces', None, _(b'separate elements by spaces')),
651 653 ],
652 654 _(b'[OPTION]... [FILE [REV]...]'),
653 655 optionalrepo=True,
654 656 )
655 657 def debugdag(ui, repo, file_=None, *revs, **opts):
656 658 """format the changelog or an index DAG as a concise textual description
657 659
658 660 If you pass a revlog index, the revlog's DAG is emitted. If you list
659 661 revision numbers, they get labeled in the output as rN.
660 662
661 663 Otherwise, the changelog DAG of the current repo is emitted.
662 664 """
663 665 spaces = opts.get('spaces')
664 666 dots = opts.get('dots')
665 667 if file_:
666 668 rlog = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False), file_)
667 669 revs = {int(r) for r in revs}
668 670
669 671 def events():
670 672 for r in rlog:
671 673 yield b'n', (r, list(p for p in rlog.parentrevs(r) if p != -1))
672 674 if r in revs:
673 675 yield b'l', (r, b"r%i" % r)
674 676
675 677 elif repo:
676 678 cl = repo.changelog
677 679 tags = opts.get('tags')
678 680 branches = opts.get('branches')
679 681 if tags:
680 682 labels = {}
681 683 for l, n in repo.tags().items():
682 684 labels.setdefault(cl.rev(n), []).append(l)
683 685
684 686 def events():
685 687 b = b"default"
686 688 for r in cl:
687 689 if branches:
688 690 newb = cl.read(cl.node(r))[5][b'branch']
689 691 if newb != b:
690 692 yield b'a', newb
691 693 b = newb
692 694 yield b'n', (r, list(p for p in cl.parentrevs(r) if p != -1))
693 695 if tags:
694 696 ls = labels.get(r)
695 697 if ls:
696 698 for l in ls:
697 699 yield b'l', (r, l)
698 700
699 701 else:
700 702 raise error.Abort(_(b'need repo for changelog dag'))
701 703
702 704 for line in dagparser.dagtextlines(
703 705 events(),
704 706 addspaces=spaces,
705 707 wraplabels=True,
706 708 wrapannotations=True,
707 709 wrapnonlinear=dots,
708 710 usedots=dots,
709 711 maxlinewidth=70,
710 712 ):
711 713 ui.write(line)
712 714 ui.write(b"\n")
713 715
714 716
715 717 @command(b'debugdata', cmdutil.debugrevlogopts, _(b'-c|-m|FILE REV'))
716 718 def debugdata(ui, repo, file_, rev=None, **opts):
717 719 """dump the contents of a data file revision"""
718 720 opts = pycompat.byteskwargs(opts)
719 721 if opts.get(b'changelog') or opts.get(b'manifest') or opts.get(b'dir'):
720 722 if rev is not None:
721 723 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
722 724 file_, rev = None, file_
723 725 elif rev is None:
724 726 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
725 727 r = cmdutil.openstorage(repo, b'debugdata', file_, opts)
726 728 try:
727 729 ui.write(r.rawdata(r.lookup(rev)))
728 730 except KeyError:
729 731 raise error.Abort(_(b'invalid revision identifier %s') % rev)
730 732
731 733
732 734 @command(
733 735 b'debugdate',
734 736 [(b'e', b'extended', None, _(b'try extended date formats'))],
735 737 _(b'[-e] DATE [RANGE]'),
736 738 norepo=True,
737 739 optionalrepo=True,
738 740 )
739 741 def debugdate(ui, date, range=None, **opts):
740 742 """parse and display a date"""
741 743 if opts["extended"]:
742 744 d = dateutil.parsedate(date, dateutil.extendeddateformats)
743 745 else:
744 746 d = dateutil.parsedate(date)
745 747 ui.writenoi18n(b"internal: %d %d\n" % d)
746 748 ui.writenoi18n(b"standard: %s\n" % dateutil.datestr(d))
747 749 if range:
748 750 m = dateutil.matchdate(range)
749 751 ui.writenoi18n(b"match: %s\n" % m(d[0]))
750 752
751 753
752 754 @command(
753 755 b'debugdeltachain',
754 756 cmdutil.debugrevlogopts + cmdutil.formatteropts,
755 757 _(b'-c|-m|FILE'),
756 758 optionalrepo=True,
757 759 )
758 760 def debugdeltachain(ui, repo, file_=None, **opts):
759 761 """dump information about delta chains in a revlog
760 762
761 763 Output can be templatized. Available template keywords are:
762 764
763 765 :``rev``: revision number
764 766 :``chainid``: delta chain identifier (numbered by unique base)
765 767 :``chainlen``: delta chain length to this revision
766 768 :``prevrev``: previous revision in delta chain
767 769 :``deltatype``: role of delta / how it was computed
768 770 :``compsize``: compressed size of revision
769 771 :``uncompsize``: uncompressed size of revision
770 772 :``chainsize``: total size of compressed revisions in chain
771 773 :``chainratio``: total chain size divided by uncompressed revision size
772 774 (new delta chains typically start at ratio 2.00)
773 775 :``lindist``: linear distance from base revision in delta chain to end
774 776 of this revision
775 777 :``extradist``: total size of revisions not part of this delta chain from
776 778 base of delta chain to end of this revision; a measurement
777 779 of how much extra data we need to read/seek across to read
778 780 the delta chain for this revision
779 781 :``extraratio``: extradist divided by chainsize; another representation of
780 782 how much unrelated data is needed to load this delta chain
781 783
782 784 If the repository is configured to use the sparse read, additional keywords
783 785 are available:
784 786
785 787 :``readsize``: total size of data read from the disk for a revision
786 788 (sum of the sizes of all the blocks)
787 789 :``largestblock``: size of the largest block of data read from the disk
788 790 :``readdensity``: density of useful bytes in the data read from the disk
789 791 :``srchunks``: in how many data hunks the whole revision would be read
790 792
791 793 The sparse read can be enabled with experimental.sparse-read = True
792 794 """
793 795 opts = pycompat.byteskwargs(opts)
794 796 r = cmdutil.openrevlog(repo, b'debugdeltachain', file_, opts)
795 797 index = r.index
796 798 start = r.start
797 799 length = r.length
798 800 generaldelta = r._generaldelta
799 801 withsparseread = getattr(r, '_withsparseread', False)
800 802
801 803 def revinfo(rev):
802 804 e = index[rev]
803 805 compsize = e[1]
804 806 uncompsize = e[2]
805 807 chainsize = 0
806 808
807 809 if generaldelta:
808 810 if e[3] == e[5]:
809 811 deltatype = b'p1'
810 812 elif e[3] == e[6]:
811 813 deltatype = b'p2'
812 814 elif e[3] == rev - 1:
813 815 deltatype = b'prev'
814 816 elif e[3] == rev:
815 817 deltatype = b'base'
816 818 else:
817 819 deltatype = b'other'
818 820 else:
819 821 if e[3] == rev:
820 822 deltatype = b'base'
821 823 else:
822 824 deltatype = b'prev'
823 825
824 826 chain = r._deltachain(rev)[0]
825 827 for iterrev in chain:
826 828 e = index[iterrev]
827 829 chainsize += e[1]
828 830
829 831 return compsize, uncompsize, deltatype, chain, chainsize
830 832
831 833 fm = ui.formatter(b'debugdeltachain', opts)
832 834
833 835 fm.plain(
834 836 b' rev chain# chainlen prev delta '
835 837 b'size rawsize chainsize ratio lindist extradist '
836 838 b'extraratio'
837 839 )
838 840 if withsparseread:
839 841 fm.plain(b' readsize largestblk rddensity srchunks')
840 842 fm.plain(b'\n')
841 843
842 844 chainbases = {}
843 845 for rev in r:
844 846 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
845 847 chainbase = chain[0]
846 848 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
847 849 basestart = start(chainbase)
848 850 revstart = start(rev)
849 851 lineardist = revstart + comp - basestart
850 852 extradist = lineardist - chainsize
851 853 try:
852 854 prevrev = chain[-2]
853 855 except IndexError:
854 856 prevrev = -1
855 857
856 858 if uncomp != 0:
857 859 chainratio = float(chainsize) / float(uncomp)
858 860 else:
859 861 chainratio = chainsize
860 862
861 863 if chainsize != 0:
862 864 extraratio = float(extradist) / float(chainsize)
863 865 else:
864 866 extraratio = extradist
865 867
866 868 fm.startitem()
867 869 fm.write(
868 870 b'rev chainid chainlen prevrev deltatype compsize '
869 871 b'uncompsize chainsize chainratio lindist extradist '
870 872 b'extraratio',
871 873 b'%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f',
872 874 rev,
873 875 chainid,
874 876 len(chain),
875 877 prevrev,
876 878 deltatype,
877 879 comp,
878 880 uncomp,
879 881 chainsize,
880 882 chainratio,
881 883 lineardist,
882 884 extradist,
883 885 extraratio,
884 886 rev=rev,
885 887 chainid=chainid,
886 888 chainlen=len(chain),
887 889 prevrev=prevrev,
888 890 deltatype=deltatype,
889 891 compsize=comp,
890 892 uncompsize=uncomp,
891 893 chainsize=chainsize,
892 894 chainratio=chainratio,
893 895 lindist=lineardist,
894 896 extradist=extradist,
895 897 extraratio=extraratio,
896 898 )
897 899 if withsparseread:
898 900 readsize = 0
899 901 largestblock = 0
900 902 srchunks = 0
901 903
902 904 for revschunk in deltautil.slicechunk(r, chain):
903 905 srchunks += 1
904 906 blkend = start(revschunk[-1]) + length(revschunk[-1])
905 907 blksize = blkend - start(revschunk[0])
906 908
907 909 readsize += blksize
908 910 if largestblock < blksize:
909 911 largestblock = blksize
910 912
911 913 if readsize:
912 914 readdensity = float(chainsize) / float(readsize)
913 915 else:
914 916 readdensity = 1
915 917
916 918 fm.write(
917 919 b'readsize largestblock readdensity srchunks',
918 920 b' %10d %10d %9.5f %8d',
919 921 readsize,
920 922 largestblock,
921 923 readdensity,
922 924 srchunks,
923 925 readsize=readsize,
924 926 largestblock=largestblock,
925 927 readdensity=readdensity,
926 928 srchunks=srchunks,
927 929 )
928 930
929 931 fm.plain(b'\n')
930 932
931 933 fm.end()
932 934
933 935
934 936 @command(
935 937 b'debugdirstate|debugstate',
936 938 [
937 939 (
938 940 b'',
939 941 b'nodates',
940 942 None,
941 943 _(b'do not display the saved mtime (DEPRECATED)'),
942 944 ),
943 945 (b'', b'dates', True, _(b'display the saved mtime')),
944 946 (b'', b'datesort', None, _(b'sort by saved mtime')),
945 947 (
946 948 b'',
947 949 b'all',
948 950 False,
949 951 _(b'display dirstate-v2 tree nodes that would not exist in v1'),
950 952 ),
951 953 ],
952 954 _(b'[OPTION]...'),
953 955 )
954 956 def debugstate(ui, repo, **opts):
955 957 """show the contents of the current dirstate"""
956 958
957 959 nodates = not opts['dates']
958 960 if opts.get('nodates') is not None:
959 961 nodates = True
960 962 datesort = opts.get('datesort')
961 963
962 964 if datesort:
963 965 keyfunc = lambda x: (
964 966 x[1].v1_mtime(),
965 967 x[0],
966 968 ) # sort by mtime, then by filename
967 969 else:
968 970 keyfunc = None # sort by filename
969 971 if opts['all']:
970 972 entries = list(repo.dirstate._map.debug_iter())
971 973 else:
972 974 entries = list(pycompat.iteritems(repo.dirstate))
973 975 entries.sort(key=keyfunc)
974 976 for file_, ent in entries:
975 977 if ent.v1_mtime() == -1:
976 978 timestr = b'unset '
977 979 elif nodates:
978 980 timestr = b'set '
979 981 else:
980 982 timestr = time.strftime(
981 983 "%Y-%m-%d %H:%M:%S ", time.localtime(ent.v1_mtime())
982 984 )
983 985 timestr = encoding.strtolocal(timestr)
984 986 if ent.mode & 0o20000:
985 987 mode = b'lnk'
986 988 else:
987 989 mode = b'%3o' % (ent.v1_mode() & 0o777 & ~util.umask)
988 990 ui.write(
989 991 b"%c %s %10d %s%s\n"
990 992 % (ent.v1_state(), mode, ent.v1_size(), timestr, file_)
991 993 )
992 994 for f in repo.dirstate.copies():
993 995 ui.write(_(b"copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
994 996
995 997
996 998 @command(
997 999 b'debugdirstateignorepatternshash',
998 1000 [],
999 1001 _(b''),
1000 1002 )
1001 1003 def debugdirstateignorepatternshash(ui, repo, **opts):
1002 1004 """show the hash of ignore patterns stored in dirstate if v2,
1003 1005 or nothing for dirstate-v2
1004 1006 """
1005 1007 if repo.dirstate._use_dirstate_v2:
1006 1008 docket = repo.dirstate._map.docket
1007 1009 hash_len = 20 # 160 bits for SHA-1
1008 1010 hash_bytes = docket.tree_metadata[-hash_len:]
1009 1011 ui.write(binascii.hexlify(hash_bytes) + b'\n')
1010 1012
1011 1013
1012 1014 @command(
1013 1015 b'debugdiscovery',
1014 1016 [
1015 1017 (b'', b'old', None, _(b'use old-style discovery')),
1016 1018 (
1017 1019 b'',
1018 1020 b'nonheads',
1019 1021 None,
1020 1022 _(b'use old-style discovery with non-heads included'),
1021 1023 ),
1022 1024 (b'', b'rev', [], b'restrict discovery to this set of revs'),
1023 1025 (b'', b'seed', b'12323', b'specify the random seed use for discovery'),
1024 1026 (
1025 1027 b'',
1026 1028 b'local-as-revs',
1027 1029 b"",
1028 1030 b'treat local has having these revisions only',
1029 1031 ),
1030 1032 (
1031 1033 b'',
1032 1034 b'remote-as-revs',
1033 1035 b"",
1034 1036 b'use local as remote, with only these these revisions',
1035 1037 ),
1036 1038 ]
1037 1039 + cmdutil.remoteopts
1038 1040 + cmdutil.formatteropts,
1039 1041 _(b'[--rev REV] [OTHER]'),
1040 1042 )
1041 1043 def debugdiscovery(ui, repo, remoteurl=b"default", **opts):
1042 1044 """runs the changeset discovery protocol in isolation
1043 1045
1044 1046 The local peer can be "replaced" by a subset of the local repository by
1045 1047 using the `--local-as-revs` flag. Int he same way, usual `remote` peer can
1046 1048 be "replaced" by a subset of the local repository using the
1047 1049 `--local-as-revs` flag. This is useful to efficiently debug pathological
1048 1050 discovery situation.
1049 1051
1050 1052 The following developer oriented config are relevant for people playing with this command:
1051 1053
1052 1054 * devel.discovery.exchange-heads=True
1053 1055
1054 1056 If False, the discovery will not start with
1055 1057 remote head fetching and local head querying.
1056 1058
1057 1059 * devel.discovery.grow-sample=True
1058 1060
1059 1061 If False, the sample size used in set discovery will not be increased
1060 1062 through the process
1061 1063
1062 1064 * devel.discovery.grow-sample.dynamic=True
1063 1065
1064 1066 When discovery.grow-sample.dynamic is True, the default, the sample size is
1065 1067 adapted to the shape of the undecided set (it is set to the max of:
1066 1068 <target-size>, len(roots(undecided)), len(heads(undecided)
1067 1069
1068 1070 * devel.discovery.grow-sample.rate=1.05
1069 1071
1070 1072 the rate at which the sample grow
1071 1073
1072 1074 * devel.discovery.randomize=True
1073 1075
1074 1076 If andom sampling during discovery are deterministic. It is meant for
1075 1077 integration tests.
1076 1078
1077 1079 * devel.discovery.sample-size=200
1078 1080
1079 1081 Control the initial size of the discovery sample
1080 1082
1081 1083 * devel.discovery.sample-size.initial=100
1082 1084
1083 1085 Control the initial size of the discovery for initial change
1084 1086 """
1085 1087 opts = pycompat.byteskwargs(opts)
1086 1088 unfi = repo.unfiltered()
1087 1089
1088 1090 # setup potential extra filtering
1089 1091 local_revs = opts[b"local_as_revs"]
1090 1092 remote_revs = opts[b"remote_as_revs"]
1091 1093
1092 1094 # make sure tests are repeatable
1093 1095 random.seed(int(opts[b'seed']))
1094 1096
1095 1097 if not remote_revs:
1096 1098
1097 1099 remoteurl, branches = urlutil.get_unique_pull_path(
1098 1100 b'debugdiscovery', repo, ui, remoteurl
1099 1101 )
1100 1102 remote = hg.peer(repo, opts, remoteurl)
1101 1103 ui.status(_(b'comparing with %s\n') % urlutil.hidepassword(remoteurl))
1102 1104 else:
1103 1105 branches = (None, [])
1104 1106 remote_filtered_revs = scmutil.revrange(
1105 1107 unfi, [b"not (::(%s))" % remote_revs]
1106 1108 )
1107 1109 remote_filtered_revs = frozenset(remote_filtered_revs)
1108 1110
1109 1111 def remote_func(x):
1110 1112 return remote_filtered_revs
1111 1113
1112 1114 repoview.filtertable[b'debug-discovery-remote-filter'] = remote_func
1113 1115
1114 1116 remote = repo.peer()
1115 1117 remote._repo = remote._repo.filtered(b'debug-discovery-remote-filter')
1116 1118
1117 1119 if local_revs:
1118 1120 local_filtered_revs = scmutil.revrange(
1119 1121 unfi, [b"not (::(%s))" % local_revs]
1120 1122 )
1121 1123 local_filtered_revs = frozenset(local_filtered_revs)
1122 1124
1123 1125 def local_func(x):
1124 1126 return local_filtered_revs
1125 1127
1126 1128 repoview.filtertable[b'debug-discovery-local-filter'] = local_func
1127 1129 repo = repo.filtered(b'debug-discovery-local-filter')
1128 1130
1129 1131 data = {}
1130 1132 if opts.get(b'old'):
1131 1133
1132 1134 def doit(pushedrevs, remoteheads, remote=remote):
1133 1135 if not util.safehasattr(remote, b'branches'):
1134 1136 # enable in-client legacy support
1135 1137 remote = localrepo.locallegacypeer(remote.local())
1136 1138 common, _in, hds = treediscovery.findcommonincoming(
1137 1139 repo, remote, force=True, audit=data
1138 1140 )
1139 1141 common = set(common)
1140 1142 if not opts.get(b'nonheads'):
1141 1143 ui.writenoi18n(
1142 1144 b"unpruned common: %s\n"
1143 1145 % b" ".join(sorted(short(n) for n in common))
1144 1146 )
1145 1147
1146 1148 clnode = repo.changelog.node
1147 1149 common = repo.revs(b'heads(::%ln)', common)
1148 1150 common = {clnode(r) for r in common}
1149 1151 return common, hds
1150 1152
1151 1153 else:
1152 1154
1153 1155 def doit(pushedrevs, remoteheads, remote=remote):
1154 1156 nodes = None
1155 1157 if pushedrevs:
1156 1158 revs = scmutil.revrange(repo, pushedrevs)
1157 1159 nodes = [repo[r].node() for r in revs]
1158 1160 common, any, hds = setdiscovery.findcommonheads(
1159 1161 ui, repo, remote, ancestorsof=nodes, audit=data
1160 1162 )
1161 1163 return common, hds
1162 1164
1163 1165 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches, revs=None)
1164 1166 localrevs = opts[b'rev']
1165 1167
1166 1168 fm = ui.formatter(b'debugdiscovery', opts)
1167 1169 if fm.strict_format:
1168 1170
1169 1171 @contextlib.contextmanager
1170 1172 def may_capture_output():
1171 1173 ui.pushbuffer()
1172 1174 yield
1173 1175 data[b'output'] = ui.popbuffer()
1174 1176
1175 1177 else:
1176 1178 may_capture_output = util.nullcontextmanager
1177 1179 with may_capture_output():
1178 1180 with util.timedcm('debug-discovery') as t:
1179 1181 common, hds = doit(localrevs, remoterevs)
1180 1182
1181 1183 # compute all statistics
1182 1184 heads_common = set(common)
1183 1185 heads_remote = set(hds)
1184 1186 heads_local = set(repo.heads())
1185 1187 # note: they cannot be a local or remote head that is in common and not
1186 1188 # itself a head of common.
1187 1189 heads_common_local = heads_common & heads_local
1188 1190 heads_common_remote = heads_common & heads_remote
1189 1191 heads_common_both = heads_common & heads_remote & heads_local
1190 1192
1191 1193 all = repo.revs(b'all()')
1192 1194 common = repo.revs(b'::%ln', common)
1193 1195 roots_common = repo.revs(b'roots(::%ld)', common)
1194 1196 missing = repo.revs(b'not ::%ld', common)
1195 1197 heads_missing = repo.revs(b'heads(%ld)', missing)
1196 1198 roots_missing = repo.revs(b'roots(%ld)', missing)
1197 1199 assert len(common) + len(missing) == len(all)
1198 1200
1199 1201 initial_undecided = repo.revs(
1200 1202 b'not (::%ln or %ln::)', heads_common_remote, heads_common_local
1201 1203 )
1202 1204 heads_initial_undecided = repo.revs(b'heads(%ld)', initial_undecided)
1203 1205 roots_initial_undecided = repo.revs(b'roots(%ld)', initial_undecided)
1204 1206 common_initial_undecided = initial_undecided & common
1205 1207 missing_initial_undecided = initial_undecided & missing
1206 1208
1207 1209 data[b'elapsed'] = t.elapsed
1208 1210 data[b'nb-common-heads'] = len(heads_common)
1209 1211 data[b'nb-common-heads-local'] = len(heads_common_local)
1210 1212 data[b'nb-common-heads-remote'] = len(heads_common_remote)
1211 1213 data[b'nb-common-heads-both'] = len(heads_common_both)
1212 1214 data[b'nb-common-roots'] = len(roots_common)
1213 1215 data[b'nb-head-local'] = len(heads_local)
1214 1216 data[b'nb-head-local-missing'] = len(heads_local) - len(heads_common_local)
1215 1217 data[b'nb-head-remote'] = len(heads_remote)
1216 1218 data[b'nb-head-remote-unknown'] = len(heads_remote) - len(
1217 1219 heads_common_remote
1218 1220 )
1219 1221 data[b'nb-revs'] = len(all)
1220 1222 data[b'nb-revs-common'] = len(common)
1221 1223 data[b'nb-revs-missing'] = len(missing)
1222 1224 data[b'nb-missing-heads'] = len(heads_missing)
1223 1225 data[b'nb-missing-roots'] = len(roots_missing)
1224 1226 data[b'nb-ini_und'] = len(initial_undecided)
1225 1227 data[b'nb-ini_und-heads'] = len(heads_initial_undecided)
1226 1228 data[b'nb-ini_und-roots'] = len(roots_initial_undecided)
1227 1229 data[b'nb-ini_und-common'] = len(common_initial_undecided)
1228 1230 data[b'nb-ini_und-missing'] = len(missing_initial_undecided)
1229 1231
1230 1232 fm.startitem()
1231 1233 fm.data(**pycompat.strkwargs(data))
1232 1234 # display discovery summary
1233 1235 fm.plain(b"elapsed time: %(elapsed)f seconds\n" % data)
1234 1236 fm.plain(b"round-trips: %(total-roundtrips)9d\n" % data)
1235 1237 fm.plain(b"heads summary:\n")
1236 1238 fm.plain(b" total common heads: %(nb-common-heads)9d\n" % data)
1237 1239 fm.plain(b" also local heads: %(nb-common-heads-local)9d\n" % data)
1238 1240 fm.plain(b" also remote heads: %(nb-common-heads-remote)9d\n" % data)
1239 1241 fm.plain(b" both: %(nb-common-heads-both)9d\n" % data)
1240 1242 fm.plain(b" local heads: %(nb-head-local)9d\n" % data)
1241 1243 fm.plain(b" common: %(nb-common-heads-local)9d\n" % data)
1242 1244 fm.plain(b" missing: %(nb-head-local-missing)9d\n" % data)
1243 1245 fm.plain(b" remote heads: %(nb-head-remote)9d\n" % data)
1244 1246 fm.plain(b" common: %(nb-common-heads-remote)9d\n" % data)
1245 1247 fm.plain(b" unknown: %(nb-head-remote-unknown)9d\n" % data)
1246 1248 fm.plain(b"local changesets: %(nb-revs)9d\n" % data)
1247 1249 fm.plain(b" common: %(nb-revs-common)9d\n" % data)
1248 1250 fm.plain(b" heads: %(nb-common-heads)9d\n" % data)
1249 1251 fm.plain(b" roots: %(nb-common-roots)9d\n" % data)
1250 1252 fm.plain(b" missing: %(nb-revs-missing)9d\n" % data)
1251 1253 fm.plain(b" heads: %(nb-missing-heads)9d\n" % data)
1252 1254 fm.plain(b" roots: %(nb-missing-roots)9d\n" % data)
1253 1255 fm.plain(b" first undecided set: %(nb-ini_und)9d\n" % data)
1254 1256 fm.plain(b" heads: %(nb-ini_und-heads)9d\n" % data)
1255 1257 fm.plain(b" roots: %(nb-ini_und-roots)9d\n" % data)
1256 1258 fm.plain(b" common: %(nb-ini_und-common)9d\n" % data)
1257 1259 fm.plain(b" missing: %(nb-ini_und-missing)9d\n" % data)
1258 1260
1259 1261 if ui.verbose:
1260 1262 fm.plain(
1261 1263 b"common heads: %s\n"
1262 1264 % b" ".join(sorted(short(n) for n in heads_common))
1263 1265 )
1264 1266 fm.end()
1265 1267
1266 1268
1267 1269 _chunksize = 4 << 10
1268 1270
1269 1271
1270 1272 @command(
1271 1273 b'debugdownload',
1272 1274 [
1273 1275 (b'o', b'output', b'', _(b'path')),
1274 1276 ],
1275 1277 optionalrepo=True,
1276 1278 )
1277 1279 def debugdownload(ui, repo, url, output=None, **opts):
1278 1280 """download a resource using Mercurial logic and config"""
1279 1281 fh = urlmod.open(ui, url, output)
1280 1282
1281 1283 dest = ui
1282 1284 if output:
1283 1285 dest = open(output, b"wb", _chunksize)
1284 1286 try:
1285 1287 data = fh.read(_chunksize)
1286 1288 while data:
1287 1289 dest.write(data)
1288 1290 data = fh.read(_chunksize)
1289 1291 finally:
1290 1292 if output:
1291 1293 dest.close()
1292 1294
1293 1295
1294 1296 @command(b'debugextensions', cmdutil.formatteropts, [], optionalrepo=True)
1295 1297 def debugextensions(ui, repo, **opts):
1296 1298 '''show information about active extensions'''
1297 1299 opts = pycompat.byteskwargs(opts)
1298 1300 exts = extensions.extensions(ui)
1299 1301 hgver = util.version()
1300 1302 fm = ui.formatter(b'debugextensions', opts)
1301 1303 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
1302 1304 isinternal = extensions.ismoduleinternal(extmod)
1303 1305 extsource = None
1304 1306
1305 1307 if util.safehasattr(extmod, '__file__'):
1306 1308 extsource = pycompat.fsencode(extmod.__file__)
1307 1309 elif getattr(sys, 'oxidized', False):
1308 1310 extsource = pycompat.sysexecutable
1309 1311 if isinternal:
1310 1312 exttestedwith = [] # never expose magic string to users
1311 1313 else:
1312 1314 exttestedwith = getattr(extmod, 'testedwith', b'').split()
1313 1315 extbuglink = getattr(extmod, 'buglink', None)
1314 1316
1315 1317 fm.startitem()
1316 1318
1317 1319 if ui.quiet or ui.verbose:
1318 1320 fm.write(b'name', b'%s\n', extname)
1319 1321 else:
1320 1322 fm.write(b'name', b'%s', extname)
1321 1323 if isinternal or hgver in exttestedwith:
1322 1324 fm.plain(b'\n')
1323 1325 elif not exttestedwith:
1324 1326 fm.plain(_(b' (untested!)\n'))
1325 1327 else:
1326 1328 lasttestedversion = exttestedwith[-1]
1327 1329 fm.plain(b' (%s!)\n' % lasttestedversion)
1328 1330
1329 1331 fm.condwrite(
1330 1332 ui.verbose and extsource,
1331 1333 b'source',
1332 1334 _(b' location: %s\n'),
1333 1335 extsource or b"",
1334 1336 )
1335 1337
1336 1338 if ui.verbose:
1337 1339 fm.plain(_(b' bundled: %s\n') % [b'no', b'yes'][isinternal])
1338 1340 fm.data(bundled=isinternal)
1339 1341
1340 1342 fm.condwrite(
1341 1343 ui.verbose and exttestedwith,
1342 1344 b'testedwith',
1343 1345 _(b' tested with: %s\n'),
1344 1346 fm.formatlist(exttestedwith, name=b'ver'),
1345 1347 )
1346 1348
1347 1349 fm.condwrite(
1348 1350 ui.verbose and extbuglink,
1349 1351 b'buglink',
1350 1352 _(b' bug reporting: %s\n'),
1351 1353 extbuglink or b"",
1352 1354 )
1353 1355
1354 1356 fm.end()
1355 1357
1356 1358
1357 1359 @command(
1358 1360 b'debugfileset',
1359 1361 [
1360 1362 (
1361 1363 b'r',
1362 1364 b'rev',
1363 1365 b'',
1364 1366 _(b'apply the filespec on this revision'),
1365 1367 _(b'REV'),
1366 1368 ),
1367 1369 (
1368 1370 b'',
1369 1371 b'all-files',
1370 1372 False,
1371 1373 _(b'test files from all revisions and working directory'),
1372 1374 ),
1373 1375 (
1374 1376 b's',
1375 1377 b'show-matcher',
1376 1378 None,
1377 1379 _(b'print internal representation of matcher'),
1378 1380 ),
1379 1381 (
1380 1382 b'p',
1381 1383 b'show-stage',
1382 1384 [],
1383 1385 _(b'print parsed tree at the given stage'),
1384 1386 _(b'NAME'),
1385 1387 ),
1386 1388 ],
1387 1389 _(b'[-r REV] [--all-files] [OPTION]... FILESPEC'),
1388 1390 )
1389 1391 def debugfileset(ui, repo, expr, **opts):
1390 1392 '''parse and apply a fileset specification'''
1391 1393 from . import fileset
1392 1394
1393 1395 fileset.symbols # force import of fileset so we have predicates to optimize
1394 1396 opts = pycompat.byteskwargs(opts)
1395 1397 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
1396 1398
1397 1399 stages = [
1398 1400 (b'parsed', pycompat.identity),
1399 1401 (b'analyzed', filesetlang.analyze),
1400 1402 (b'optimized', filesetlang.optimize),
1401 1403 ]
1402 1404 stagenames = {n for n, f in stages}
1403 1405
1404 1406 showalways = set()
1405 1407 if ui.verbose and not opts[b'show_stage']:
1406 1408 # show parsed tree by --verbose (deprecated)
1407 1409 showalways.add(b'parsed')
1408 1410 if opts[b'show_stage'] == [b'all']:
1409 1411 showalways.update(stagenames)
1410 1412 else:
1411 1413 for n in opts[b'show_stage']:
1412 1414 if n not in stagenames:
1413 1415 raise error.Abort(_(b'invalid stage name: %s') % n)
1414 1416 showalways.update(opts[b'show_stage'])
1415 1417
1416 1418 tree = filesetlang.parse(expr)
1417 1419 for n, f in stages:
1418 1420 tree = f(tree)
1419 1421 if n in showalways:
1420 1422 if opts[b'show_stage'] or n != b'parsed':
1421 1423 ui.write(b"* %s:\n" % n)
1422 1424 ui.write(filesetlang.prettyformat(tree), b"\n")
1423 1425
1424 1426 files = set()
1425 1427 if opts[b'all_files']:
1426 1428 for r in repo:
1427 1429 c = repo[r]
1428 1430 files.update(c.files())
1429 1431 files.update(c.substate)
1430 1432 if opts[b'all_files'] or ctx.rev() is None:
1431 1433 wctx = repo[None]
1432 1434 files.update(
1433 1435 repo.dirstate.walk(
1434 1436 scmutil.matchall(repo),
1435 1437 subrepos=list(wctx.substate),
1436 1438 unknown=True,
1437 1439 ignored=True,
1438 1440 )
1439 1441 )
1440 1442 files.update(wctx.substate)
1441 1443 else:
1442 1444 files.update(ctx.files())
1443 1445 files.update(ctx.substate)
1444 1446
1445 1447 m = ctx.matchfileset(repo.getcwd(), expr)
1446 1448 if opts[b'show_matcher'] or (opts[b'show_matcher'] is None and ui.verbose):
1447 1449 ui.writenoi18n(b'* matcher:\n', stringutil.prettyrepr(m), b'\n')
1448 1450 for f in sorted(files):
1449 1451 if not m(f):
1450 1452 continue
1451 1453 ui.write(b"%s\n" % f)
1452 1454
1453 1455
1456 @command(
1457 b"debug-repair-issue6528",
1458 [
1459 (
1460 b'',
1461 b'to-report',
1462 b'',
1463 _(b'build a report of affected revisions to this file'),
1464 _(b'FILE'),
1465 ),
1466 (
1467 b'',
1468 b'from-report',
1469 b'',
1470 _(b'repair revisions listed in this report file'),
1471 _(b'FILE'),
1472 ),
1473 ]
1474 + cmdutil.dryrunopts,
1475 )
1476 def debug_repair_issue6528(ui, repo, **opts):
1477 """find affected revisions and repair them. See issue6528 for more details.
1478
1479 The `--to-report` and `--from-report` flags allow you to cache and reuse the
1480 computation of affected revisions for a given repository across clones.
1481 The report format is line-based (with empty lines ignored):
1482
1483 ```
1484 <ascii-hex of the affected revision>,... <unencoded filelog index filename>
1485 ```
1486
1487 There can be multiple broken revisions per filelog, they are separated by
1488 a comma with no spaces. The only space is between the revision(s) and the
1489 filename.
1490
1491 Note that this does *not* mean that this repairs future affected revisions,
1492 that needs a separate fix at the exchange level that hasn't been written yet
1493 (as of 5.9rc0).
1494 """
1495 cmdutil.check_incompatible_arguments(
1496 opts, 'to_report', ['from_report', 'dry_run']
1497 )
1498 dry_run = opts.get('dry_run')
1499 to_report = opts.get('to_report')
1500 from_report = opts.get('from_report')
1501 # TODO maybe add filelog pattern and revision pattern parameters to help
1502 # narrow down the search for users that know what they're looking for?
1503
1504 if requirements.REVLOGV1_REQUIREMENT not in repo.requirements:
1505 msg = b"can only repair revlogv1 repositories, v2 is not affected"
1506 raise error.Abort(_(msg))
1507
1508 rewrite.repair_issue6528(
1509 ui, repo, dry_run=dry_run, to_report=to_report, from_report=from_report
1510 )
1511
1512
1454 1513 @command(b'debugformat', [] + cmdutil.formatteropts)
1455 1514 def debugformat(ui, repo, **opts):
1456 1515 """display format information about the current repository
1457 1516
1458 1517 Use --verbose to get extra information about current config value and
1459 1518 Mercurial default."""
1460 1519 opts = pycompat.byteskwargs(opts)
1461 1520 maxvariantlength = max(len(fv.name) for fv in upgrade.allformatvariant)
1462 1521 maxvariantlength = max(len(b'format-variant'), maxvariantlength)
1463 1522
1464 1523 def makeformatname(name):
1465 1524 return b'%s:' + (b' ' * (maxvariantlength - len(name)))
1466 1525
1467 1526 fm = ui.formatter(b'debugformat', opts)
1468 1527 if fm.isplain():
1469 1528
1470 1529 def formatvalue(value):
1471 1530 if util.safehasattr(value, b'startswith'):
1472 1531 return value
1473 1532 if value:
1474 1533 return b'yes'
1475 1534 else:
1476 1535 return b'no'
1477 1536
1478 1537 else:
1479 1538 formatvalue = pycompat.identity
1480 1539
1481 1540 fm.plain(b'format-variant')
1482 1541 fm.plain(b' ' * (maxvariantlength - len(b'format-variant')))
1483 1542 fm.plain(b' repo')
1484 1543 if ui.verbose:
1485 1544 fm.plain(b' config default')
1486 1545 fm.plain(b'\n')
1487 1546 for fv in upgrade.allformatvariant:
1488 1547 fm.startitem()
1489 1548 repovalue = fv.fromrepo(repo)
1490 1549 configvalue = fv.fromconfig(repo)
1491 1550
1492 1551 if repovalue != configvalue:
1493 1552 namelabel = b'formatvariant.name.mismatchconfig'
1494 1553 repolabel = b'formatvariant.repo.mismatchconfig'
1495 1554 elif repovalue != fv.default:
1496 1555 namelabel = b'formatvariant.name.mismatchdefault'
1497 1556 repolabel = b'formatvariant.repo.mismatchdefault'
1498 1557 else:
1499 1558 namelabel = b'formatvariant.name.uptodate'
1500 1559 repolabel = b'formatvariant.repo.uptodate'
1501 1560
1502 1561 fm.write(b'name', makeformatname(fv.name), fv.name, label=namelabel)
1503 1562 fm.write(b'repo', b' %3s', formatvalue(repovalue), label=repolabel)
1504 1563 if fv.default != configvalue:
1505 1564 configlabel = b'formatvariant.config.special'
1506 1565 else:
1507 1566 configlabel = b'formatvariant.config.default'
1508 1567 fm.condwrite(
1509 1568 ui.verbose,
1510 1569 b'config',
1511 1570 b' %6s',
1512 1571 formatvalue(configvalue),
1513 1572 label=configlabel,
1514 1573 )
1515 1574 fm.condwrite(
1516 1575 ui.verbose,
1517 1576 b'default',
1518 1577 b' %7s',
1519 1578 formatvalue(fv.default),
1520 1579 label=b'formatvariant.default',
1521 1580 )
1522 1581 fm.plain(b'\n')
1523 1582 fm.end()
1524 1583
1525 1584
1526 1585 @command(b'debugfsinfo', [], _(b'[PATH]'), norepo=True)
1527 1586 def debugfsinfo(ui, path=b"."):
1528 1587 """show information detected about current filesystem"""
1529 1588 ui.writenoi18n(b'path: %s\n' % path)
1530 1589 ui.writenoi18n(
1531 1590 b'mounted on: %s\n' % (util.getfsmountpoint(path) or b'(unknown)')
1532 1591 )
1533 1592 ui.writenoi18n(b'exec: %s\n' % (util.checkexec(path) and b'yes' or b'no'))
1534 1593 ui.writenoi18n(b'fstype: %s\n' % (util.getfstype(path) or b'(unknown)'))
1535 1594 ui.writenoi18n(
1536 1595 b'symlink: %s\n' % (util.checklink(path) and b'yes' or b'no')
1537 1596 )
1538 1597 ui.writenoi18n(
1539 1598 b'hardlink: %s\n' % (util.checknlink(path) and b'yes' or b'no')
1540 1599 )
1541 1600 casesensitive = b'(unknown)'
1542 1601 try:
1543 1602 with pycompat.namedtempfile(prefix=b'.debugfsinfo', dir=path) as f:
1544 1603 casesensitive = util.fscasesensitive(f.name) and b'yes' or b'no'
1545 1604 except OSError:
1546 1605 pass
1547 1606 ui.writenoi18n(b'case-sensitive: %s\n' % casesensitive)
1548 1607
1549 1608
1550 1609 @command(
1551 1610 b'debuggetbundle',
1552 1611 [
1553 1612 (b'H', b'head', [], _(b'id of head node'), _(b'ID')),
1554 1613 (b'C', b'common', [], _(b'id of common node'), _(b'ID')),
1555 1614 (
1556 1615 b't',
1557 1616 b'type',
1558 1617 b'bzip2',
1559 1618 _(b'bundle compression type to use'),
1560 1619 _(b'TYPE'),
1561 1620 ),
1562 1621 ],
1563 1622 _(b'REPO FILE [-H|-C ID]...'),
1564 1623 norepo=True,
1565 1624 )
1566 1625 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1567 1626 """retrieves a bundle from a repo
1568 1627
1569 1628 Every ID must be a full-length hex node id string. Saves the bundle to the
1570 1629 given file.
1571 1630 """
1572 1631 opts = pycompat.byteskwargs(opts)
1573 1632 repo = hg.peer(ui, opts, repopath)
1574 1633 if not repo.capable(b'getbundle'):
1575 1634 raise error.Abort(b"getbundle() not supported by target repository")
1576 1635 args = {}
1577 1636 if common:
1578 1637 args['common'] = [bin(s) for s in common]
1579 1638 if head:
1580 1639 args['heads'] = [bin(s) for s in head]
1581 1640 # TODO: get desired bundlecaps from command line.
1582 1641 args['bundlecaps'] = None
1583 1642 bundle = repo.getbundle(b'debug', **args)
1584 1643
1585 1644 bundletype = opts.get(b'type', b'bzip2').lower()
1586 1645 btypes = {
1587 1646 b'none': b'HG10UN',
1588 1647 b'bzip2': b'HG10BZ',
1589 1648 b'gzip': b'HG10GZ',
1590 1649 b'bundle2': b'HG20',
1591 1650 }
1592 1651 bundletype = btypes.get(bundletype)
1593 1652 if bundletype not in bundle2.bundletypes:
1594 1653 raise error.Abort(_(b'unknown bundle type specified with --type'))
1595 1654 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
1596 1655
1597 1656
1598 1657 @command(b'debugignore', [], b'[FILE]')
1599 1658 def debugignore(ui, repo, *files, **opts):
1600 1659 """display the combined ignore pattern and information about ignored files
1601 1660
1602 1661 With no argument display the combined ignore pattern.
1603 1662
1604 1663 Given space separated file names, shows if the given file is ignored and
1605 1664 if so, show the ignore rule (file and line number) that matched it.
1606 1665 """
1607 1666 ignore = repo.dirstate._ignore
1608 1667 if not files:
1609 1668 # Show all the patterns
1610 1669 ui.write(b"%s\n" % pycompat.byterepr(ignore))
1611 1670 else:
1612 1671 m = scmutil.match(repo[None], pats=files)
1613 1672 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
1614 1673 for f in m.files():
1615 1674 nf = util.normpath(f)
1616 1675 ignored = None
1617 1676 ignoredata = None
1618 1677 if nf != b'.':
1619 1678 if ignore(nf):
1620 1679 ignored = nf
1621 1680 ignoredata = repo.dirstate._ignorefileandline(nf)
1622 1681 else:
1623 1682 for p in pathutil.finddirs(nf):
1624 1683 if ignore(p):
1625 1684 ignored = p
1626 1685 ignoredata = repo.dirstate._ignorefileandline(p)
1627 1686 break
1628 1687 if ignored:
1629 1688 if ignored == nf:
1630 1689 ui.write(_(b"%s is ignored\n") % uipathfn(f))
1631 1690 else:
1632 1691 ui.write(
1633 1692 _(
1634 1693 b"%s is ignored because of "
1635 1694 b"containing directory %s\n"
1636 1695 )
1637 1696 % (uipathfn(f), ignored)
1638 1697 )
1639 1698 ignorefile, lineno, line = ignoredata
1640 1699 ui.write(
1641 1700 _(b"(ignore rule in %s, line %d: '%s')\n")
1642 1701 % (ignorefile, lineno, line)
1643 1702 )
1644 1703 else:
1645 1704 ui.write(_(b"%s is not ignored\n") % uipathfn(f))
1646 1705
1647 1706
1648 1707 @command(
1649 1708 b'debugindex',
1650 1709 cmdutil.debugrevlogopts + cmdutil.formatteropts,
1651 1710 _(b'-c|-m|FILE'),
1652 1711 )
1653 1712 def debugindex(ui, repo, file_=None, **opts):
1654 1713 """dump index data for a storage primitive"""
1655 1714 opts = pycompat.byteskwargs(opts)
1656 1715 store = cmdutil.openstorage(repo, b'debugindex', file_, opts)
1657 1716
1658 1717 if ui.debugflag:
1659 1718 shortfn = hex
1660 1719 else:
1661 1720 shortfn = short
1662 1721
1663 1722 idlen = 12
1664 1723 for i in store:
1665 1724 idlen = len(shortfn(store.node(i)))
1666 1725 break
1667 1726
1668 1727 fm = ui.formatter(b'debugindex', opts)
1669 1728 fm.plain(
1670 1729 b' rev linkrev %s %s p2\n'
1671 1730 % (b'nodeid'.ljust(idlen), b'p1'.ljust(idlen))
1672 1731 )
1673 1732
1674 1733 for rev in store:
1675 1734 node = store.node(rev)
1676 1735 parents = store.parents(node)
1677 1736
1678 1737 fm.startitem()
1679 1738 fm.write(b'rev', b'%6d ', rev)
1680 1739 fm.write(b'linkrev', b'%7d ', store.linkrev(rev))
1681 1740 fm.write(b'node', b'%s ', shortfn(node))
1682 1741 fm.write(b'p1', b'%s ', shortfn(parents[0]))
1683 1742 fm.write(b'p2', b'%s', shortfn(parents[1]))
1684 1743 fm.plain(b'\n')
1685 1744
1686 1745 fm.end()
1687 1746
1688 1747
1689 1748 @command(
1690 1749 b'debugindexdot',
1691 1750 cmdutil.debugrevlogopts,
1692 1751 _(b'-c|-m|FILE'),
1693 1752 optionalrepo=True,
1694 1753 )
1695 1754 def debugindexdot(ui, repo, file_=None, **opts):
1696 1755 """dump an index DAG as a graphviz dot file"""
1697 1756 opts = pycompat.byteskwargs(opts)
1698 1757 r = cmdutil.openstorage(repo, b'debugindexdot', file_, opts)
1699 1758 ui.writenoi18n(b"digraph G {\n")
1700 1759 for i in r:
1701 1760 node = r.node(i)
1702 1761 pp = r.parents(node)
1703 1762 ui.write(b"\t%d -> %d\n" % (r.rev(pp[0]), i))
1704 1763 if pp[1] != repo.nullid:
1705 1764 ui.write(b"\t%d -> %d\n" % (r.rev(pp[1]), i))
1706 1765 ui.write(b"}\n")
1707 1766
1708 1767
1709 1768 @command(b'debugindexstats', [])
1710 1769 def debugindexstats(ui, repo):
1711 1770 """show stats related to the changelog index"""
1712 1771 repo.changelog.shortest(repo.nullid, 1)
1713 1772 index = repo.changelog.index
1714 1773 if not util.safehasattr(index, b'stats'):
1715 1774 raise error.Abort(_(b'debugindexstats only works with native code'))
1716 1775 for k, v in sorted(index.stats().items()):
1717 1776 ui.write(b'%s: %d\n' % (k, v))
1718 1777
1719 1778
1720 1779 @command(b'debuginstall', [] + cmdutil.formatteropts, b'', norepo=True)
1721 1780 def debuginstall(ui, **opts):
1722 1781 """test Mercurial installation
1723 1782
1724 1783 Returns 0 on success.
1725 1784 """
1726 1785 opts = pycompat.byteskwargs(opts)
1727 1786
1728 1787 problems = 0
1729 1788
1730 1789 fm = ui.formatter(b'debuginstall', opts)
1731 1790 fm.startitem()
1732 1791
1733 1792 # encoding might be unknown or wrong. don't translate these messages.
1734 1793 fm.write(b'encoding', b"checking encoding (%s)...\n", encoding.encoding)
1735 1794 err = None
1736 1795 try:
1737 1796 codecs.lookup(pycompat.sysstr(encoding.encoding))
1738 1797 except LookupError as inst:
1739 1798 err = stringutil.forcebytestr(inst)
1740 1799 problems += 1
1741 1800 fm.condwrite(
1742 1801 err,
1743 1802 b'encodingerror',
1744 1803 b" %s\n (check that your locale is properly set)\n",
1745 1804 err,
1746 1805 )
1747 1806
1748 1807 # Python
1749 1808 pythonlib = None
1750 1809 if util.safehasattr(os, '__file__'):
1751 1810 pythonlib = os.path.dirname(pycompat.fsencode(os.__file__))
1752 1811 elif getattr(sys, 'oxidized', False):
1753 1812 pythonlib = pycompat.sysexecutable
1754 1813
1755 1814 fm.write(
1756 1815 b'pythonexe',
1757 1816 _(b"checking Python executable (%s)\n"),
1758 1817 pycompat.sysexecutable or _(b"unknown"),
1759 1818 )
1760 1819 fm.write(
1761 1820 b'pythonimplementation',
1762 1821 _(b"checking Python implementation (%s)\n"),
1763 1822 pycompat.sysbytes(platform.python_implementation()),
1764 1823 )
1765 1824 fm.write(
1766 1825 b'pythonver',
1767 1826 _(b"checking Python version (%s)\n"),
1768 1827 (b"%d.%d.%d" % sys.version_info[:3]),
1769 1828 )
1770 1829 fm.write(
1771 1830 b'pythonlib',
1772 1831 _(b"checking Python lib (%s)...\n"),
1773 1832 pythonlib or _(b"unknown"),
1774 1833 )
1775 1834
1776 1835 try:
1777 1836 from . import rustext # pytype: disable=import-error
1778 1837
1779 1838 rustext.__doc__ # trigger lazy import
1780 1839 except ImportError:
1781 1840 rustext = None
1782 1841
1783 1842 security = set(sslutil.supportedprotocols)
1784 1843 if sslutil.hassni:
1785 1844 security.add(b'sni')
1786 1845
1787 1846 fm.write(
1788 1847 b'pythonsecurity',
1789 1848 _(b"checking Python security support (%s)\n"),
1790 1849 fm.formatlist(sorted(security), name=b'protocol', fmt=b'%s', sep=b','),
1791 1850 )
1792 1851
1793 1852 # These are warnings, not errors. So don't increment problem count. This
1794 1853 # may change in the future.
1795 1854 if b'tls1.2' not in security:
1796 1855 fm.plain(
1797 1856 _(
1798 1857 b' TLS 1.2 not supported by Python install; '
1799 1858 b'network connections lack modern security\n'
1800 1859 )
1801 1860 )
1802 1861 if b'sni' not in security:
1803 1862 fm.plain(
1804 1863 _(
1805 1864 b' SNI not supported by Python install; may have '
1806 1865 b'connectivity issues with some servers\n'
1807 1866 )
1808 1867 )
1809 1868
1810 1869 fm.plain(
1811 1870 _(
1812 1871 b"checking Rust extensions (%s)\n"
1813 1872 % (b'missing' if rustext is None else b'installed')
1814 1873 ),
1815 1874 )
1816 1875
1817 1876 # TODO print CA cert info
1818 1877
1819 1878 # hg version
1820 1879 hgver = util.version()
1821 1880 fm.write(
1822 1881 b'hgver', _(b"checking Mercurial version (%s)\n"), hgver.split(b'+')[0]
1823 1882 )
1824 1883 fm.write(
1825 1884 b'hgverextra',
1826 1885 _(b"checking Mercurial custom build (%s)\n"),
1827 1886 b'+'.join(hgver.split(b'+')[1:]),
1828 1887 )
1829 1888
1830 1889 # compiled modules
1831 1890 hgmodules = None
1832 1891 if util.safehasattr(sys.modules[__name__], '__file__'):
1833 1892 hgmodules = os.path.dirname(pycompat.fsencode(__file__))
1834 1893 elif getattr(sys, 'oxidized', False):
1835 1894 hgmodules = pycompat.sysexecutable
1836 1895
1837 1896 fm.write(
1838 1897 b'hgmodulepolicy', _(b"checking module policy (%s)\n"), policy.policy
1839 1898 )
1840 1899 fm.write(
1841 1900 b'hgmodules',
1842 1901 _(b"checking installed modules (%s)...\n"),
1843 1902 hgmodules or _(b"unknown"),
1844 1903 )
1845 1904
1846 1905 rustandc = policy.policy in (b'rust+c', b'rust+c-allow')
1847 1906 rustext = rustandc # for now, that's the only case
1848 1907 cext = policy.policy in (b'c', b'allow') or rustandc
1849 1908 nopure = cext or rustext
1850 1909 if nopure:
1851 1910 err = None
1852 1911 try:
1853 1912 if cext:
1854 1913 from .cext import ( # pytype: disable=import-error
1855 1914 base85,
1856 1915 bdiff,
1857 1916 mpatch,
1858 1917 osutil,
1859 1918 )
1860 1919
1861 1920 # quiet pyflakes
1862 1921 dir(bdiff), dir(mpatch), dir(base85), dir(osutil)
1863 1922 if rustext:
1864 1923 from .rustext import ( # pytype: disable=import-error
1865 1924 ancestor,
1866 1925 dirstate,
1867 1926 )
1868 1927
1869 1928 dir(ancestor), dir(dirstate) # quiet pyflakes
1870 1929 except Exception as inst:
1871 1930 err = stringutil.forcebytestr(inst)
1872 1931 problems += 1
1873 1932 fm.condwrite(err, b'extensionserror', b" %s\n", err)
1874 1933
1875 1934 compengines = util.compengines._engines.values()
1876 1935 fm.write(
1877 1936 b'compengines',
1878 1937 _(b'checking registered compression engines (%s)\n'),
1879 1938 fm.formatlist(
1880 1939 sorted(e.name() for e in compengines),
1881 1940 name=b'compengine',
1882 1941 fmt=b'%s',
1883 1942 sep=b', ',
1884 1943 ),
1885 1944 )
1886 1945 fm.write(
1887 1946 b'compenginesavail',
1888 1947 _(b'checking available compression engines (%s)\n'),
1889 1948 fm.formatlist(
1890 1949 sorted(e.name() for e in compengines if e.available()),
1891 1950 name=b'compengine',
1892 1951 fmt=b'%s',
1893 1952 sep=b', ',
1894 1953 ),
1895 1954 )
1896 1955 wirecompengines = compression.compengines.supportedwireengines(
1897 1956 compression.SERVERROLE
1898 1957 )
1899 1958 fm.write(
1900 1959 b'compenginesserver',
1901 1960 _(
1902 1961 b'checking available compression engines '
1903 1962 b'for wire protocol (%s)\n'
1904 1963 ),
1905 1964 fm.formatlist(
1906 1965 [e.name() for e in wirecompengines if e.wireprotosupport()],
1907 1966 name=b'compengine',
1908 1967 fmt=b'%s',
1909 1968 sep=b', ',
1910 1969 ),
1911 1970 )
1912 1971 re2 = b'missing'
1913 1972 if util._re2:
1914 1973 re2 = b'available'
1915 1974 fm.plain(_(b'checking "re2" regexp engine (%s)\n') % re2)
1916 1975 fm.data(re2=bool(util._re2))
1917 1976
1918 1977 # templates
1919 1978 p = templater.templatedir()
1920 1979 fm.write(b'templatedirs', b'checking templates (%s)...\n', p or b'')
1921 1980 fm.condwrite(not p, b'', _(b" no template directories found\n"))
1922 1981 if p:
1923 1982 (m, fp) = templater.try_open_template(b"map-cmdline.default")
1924 1983 if m:
1925 1984 # template found, check if it is working
1926 1985 err = None
1927 1986 try:
1928 1987 templater.templater.frommapfile(m)
1929 1988 except Exception as inst:
1930 1989 err = stringutil.forcebytestr(inst)
1931 1990 p = None
1932 1991 fm.condwrite(err, b'defaulttemplateerror', b" %s\n", err)
1933 1992 else:
1934 1993 p = None
1935 1994 fm.condwrite(
1936 1995 p, b'defaulttemplate', _(b"checking default template (%s)\n"), m
1937 1996 )
1938 1997 fm.condwrite(
1939 1998 not m,
1940 1999 b'defaulttemplatenotfound',
1941 2000 _(b" template '%s' not found\n"),
1942 2001 b"default",
1943 2002 )
1944 2003 if not p:
1945 2004 problems += 1
1946 2005 fm.condwrite(
1947 2006 not p, b'', _(b" (templates seem to have been installed incorrectly)\n")
1948 2007 )
1949 2008
1950 2009 # editor
1951 2010 editor = ui.geteditor()
1952 2011 editor = util.expandpath(editor)
1953 2012 editorbin = procutil.shellsplit(editor)[0]
1954 2013 fm.write(b'editor', _(b"checking commit editor... (%s)\n"), editorbin)
1955 2014 cmdpath = procutil.findexe(editorbin)
1956 2015 fm.condwrite(
1957 2016 not cmdpath and editor == b'vi',
1958 2017 b'vinotfound',
1959 2018 _(
1960 2019 b" No commit editor set and can't find %s in PATH\n"
1961 2020 b" (specify a commit editor in your configuration"
1962 2021 b" file)\n"
1963 2022 ),
1964 2023 not cmdpath and editor == b'vi' and editorbin,
1965 2024 )
1966 2025 fm.condwrite(
1967 2026 not cmdpath and editor != b'vi',
1968 2027 b'editornotfound',
1969 2028 _(
1970 2029 b" Can't find editor '%s' in PATH\n"
1971 2030 b" (specify a commit editor in your configuration"
1972 2031 b" file)\n"
1973 2032 ),
1974 2033 not cmdpath and editorbin,
1975 2034 )
1976 2035 if not cmdpath and editor != b'vi':
1977 2036 problems += 1
1978 2037
1979 2038 # check username
1980 2039 username = None
1981 2040 err = None
1982 2041 try:
1983 2042 username = ui.username()
1984 2043 except error.Abort as e:
1985 2044 err = e.message
1986 2045 problems += 1
1987 2046
1988 2047 fm.condwrite(
1989 2048 username, b'username', _(b"checking username (%s)\n"), username
1990 2049 )
1991 2050 fm.condwrite(
1992 2051 err,
1993 2052 b'usernameerror',
1994 2053 _(
1995 2054 b"checking username...\n %s\n"
1996 2055 b" (specify a username in your configuration file)\n"
1997 2056 ),
1998 2057 err,
1999 2058 )
2000 2059
2001 2060 for name, mod in extensions.extensions():
2002 2061 handler = getattr(mod, 'debuginstall', None)
2003 2062 if handler is not None:
2004 2063 problems += handler(ui, fm)
2005 2064
2006 2065 fm.condwrite(not problems, b'', _(b"no problems detected\n"))
2007 2066 if not problems:
2008 2067 fm.data(problems=problems)
2009 2068 fm.condwrite(
2010 2069 problems,
2011 2070 b'problems',
2012 2071 _(b"%d problems detected, please check your install!\n"),
2013 2072 problems,
2014 2073 )
2015 2074 fm.end()
2016 2075
2017 2076 return problems
2018 2077
2019 2078
2020 2079 @command(b'debugknown', [], _(b'REPO ID...'), norepo=True)
2021 2080 def debugknown(ui, repopath, *ids, **opts):
2022 2081 """test whether node ids are known to a repo
2023 2082
2024 2083 Every ID must be a full-length hex node id string. Returns a list of 0s
2025 2084 and 1s indicating unknown/known.
2026 2085 """
2027 2086 opts = pycompat.byteskwargs(opts)
2028 2087 repo = hg.peer(ui, opts, repopath)
2029 2088 if not repo.capable(b'known'):
2030 2089 raise error.Abort(b"known() not supported by target repository")
2031 2090 flags = repo.known([bin(s) for s in ids])
2032 2091 ui.write(b"%s\n" % (b"".join([f and b"1" or b"0" for f in flags])))
2033 2092
2034 2093
2035 2094 @command(b'debuglabelcomplete', [], _(b'LABEL...'))
2036 2095 def debuglabelcomplete(ui, repo, *args):
2037 2096 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2038 2097 debugnamecomplete(ui, repo, *args)
2039 2098
2040 2099
2041 2100 @command(
2042 2101 b'debuglocks',
2043 2102 [
2044 2103 (b'L', b'force-free-lock', None, _(b'free the store lock (DANGEROUS)')),
2045 2104 (
2046 2105 b'W',
2047 2106 b'force-free-wlock',
2048 2107 None,
2049 2108 _(b'free the working state lock (DANGEROUS)'),
2050 2109 ),
2051 2110 (b's', b'set-lock', None, _(b'set the store lock until stopped')),
2052 2111 (
2053 2112 b'S',
2054 2113 b'set-wlock',
2055 2114 None,
2056 2115 _(b'set the working state lock until stopped'),
2057 2116 ),
2058 2117 ],
2059 2118 _(b'[OPTION]...'),
2060 2119 )
2061 2120 def debuglocks(ui, repo, **opts):
2062 2121 """show or modify state of locks
2063 2122
2064 2123 By default, this command will show which locks are held. This
2065 2124 includes the user and process holding the lock, the amount of time
2066 2125 the lock has been held, and the machine name where the process is
2067 2126 running if it's not local.
2068 2127
2069 2128 Locks protect the integrity of Mercurial's data, so should be
2070 2129 treated with care. System crashes or other interruptions may cause
2071 2130 locks to not be properly released, though Mercurial will usually
2072 2131 detect and remove such stale locks automatically.
2073 2132
2074 2133 However, detecting stale locks may not always be possible (for
2075 2134 instance, on a shared filesystem). Removing locks may also be
2076 2135 blocked by filesystem permissions.
2077 2136
2078 2137 Setting a lock will prevent other commands from changing the data.
2079 2138 The command will wait until an interruption (SIGINT, SIGTERM, ...) occurs.
2080 2139 The set locks are removed when the command exits.
2081 2140
2082 2141 Returns 0 if no locks are held.
2083 2142
2084 2143 """
2085 2144
2086 2145 if opts.get('force_free_lock'):
2087 2146 repo.svfs.unlink(b'lock')
2088 2147 if opts.get('force_free_wlock'):
2089 2148 repo.vfs.unlink(b'wlock')
2090 2149 if opts.get('force_free_lock') or opts.get('force_free_wlock'):
2091 2150 return 0
2092 2151
2093 2152 locks = []
2094 2153 try:
2095 2154 if opts.get('set_wlock'):
2096 2155 try:
2097 2156 locks.append(repo.wlock(False))
2098 2157 except error.LockHeld:
2099 2158 raise error.Abort(_(b'wlock is already held'))
2100 2159 if opts.get('set_lock'):
2101 2160 try:
2102 2161 locks.append(repo.lock(False))
2103 2162 except error.LockHeld:
2104 2163 raise error.Abort(_(b'lock is already held'))
2105 2164 if len(locks):
2106 2165 ui.promptchoice(_(b"ready to release the lock (y)? $$ &Yes"))
2107 2166 return 0
2108 2167 finally:
2109 2168 release(*locks)
2110 2169
2111 2170 now = time.time()
2112 2171 held = 0
2113 2172
2114 2173 def report(vfs, name, method):
2115 2174 # this causes stale locks to get reaped for more accurate reporting
2116 2175 try:
2117 2176 l = method(False)
2118 2177 except error.LockHeld:
2119 2178 l = None
2120 2179
2121 2180 if l:
2122 2181 l.release()
2123 2182 else:
2124 2183 try:
2125 2184 st = vfs.lstat(name)
2126 2185 age = now - st[stat.ST_MTIME]
2127 2186 user = util.username(st.st_uid)
2128 2187 locker = vfs.readlock(name)
2129 2188 if b":" in locker:
2130 2189 host, pid = locker.split(b':')
2131 2190 if host == socket.gethostname():
2132 2191 locker = b'user %s, process %s' % (user or b'None', pid)
2133 2192 else:
2134 2193 locker = b'user %s, process %s, host %s' % (
2135 2194 user or b'None',
2136 2195 pid,
2137 2196 host,
2138 2197 )
2139 2198 ui.writenoi18n(b"%-6s %s (%ds)\n" % (name + b":", locker, age))
2140 2199 return 1
2141 2200 except OSError as e:
2142 2201 if e.errno != errno.ENOENT:
2143 2202 raise
2144 2203
2145 2204 ui.writenoi18n(b"%-6s free\n" % (name + b":"))
2146 2205 return 0
2147 2206
2148 2207 held += report(repo.svfs, b"lock", repo.lock)
2149 2208 held += report(repo.vfs, b"wlock", repo.wlock)
2150 2209
2151 2210 return held
2152 2211
2153 2212
2154 2213 @command(
2155 2214 b'debugmanifestfulltextcache',
2156 2215 [
2157 2216 (b'', b'clear', False, _(b'clear the cache')),
2158 2217 (
2159 2218 b'a',
2160 2219 b'add',
2161 2220 [],
2162 2221 _(b'add the given manifest nodes to the cache'),
2163 2222 _(b'NODE'),
2164 2223 ),
2165 2224 ],
2166 2225 b'',
2167 2226 )
2168 2227 def debugmanifestfulltextcache(ui, repo, add=(), **opts):
2169 2228 """show, clear or amend the contents of the manifest fulltext cache"""
2170 2229
2171 2230 def getcache():
2172 2231 r = repo.manifestlog.getstorage(b'')
2173 2232 try:
2174 2233 return r._fulltextcache
2175 2234 except AttributeError:
2176 2235 msg = _(
2177 2236 b"Current revlog implementation doesn't appear to have a "
2178 2237 b"manifest fulltext cache\n"
2179 2238 )
2180 2239 raise error.Abort(msg)
2181 2240
2182 2241 if opts.get('clear'):
2183 2242 with repo.wlock():
2184 2243 cache = getcache()
2185 2244 cache.clear(clear_persisted_data=True)
2186 2245 return
2187 2246
2188 2247 if add:
2189 2248 with repo.wlock():
2190 2249 m = repo.manifestlog
2191 2250 store = m.getstorage(b'')
2192 2251 for n in add:
2193 2252 try:
2194 2253 manifest = m[store.lookup(n)]
2195 2254 except error.LookupError as e:
2196 2255 raise error.Abort(
2197 2256 bytes(e), hint=b"Check your manifest node id"
2198 2257 )
2199 2258 manifest.read() # stores revisision in cache too
2200 2259 return
2201 2260
2202 2261 cache = getcache()
2203 2262 if not len(cache):
2204 2263 ui.write(_(b'cache empty\n'))
2205 2264 else:
2206 2265 ui.write(
2207 2266 _(
2208 2267 b'cache contains %d manifest entries, in order of most to '
2209 2268 b'least recent:\n'
2210 2269 )
2211 2270 % (len(cache),)
2212 2271 )
2213 2272 totalsize = 0
2214 2273 for nodeid in cache:
2215 2274 # Use cache.get to not update the LRU order
2216 2275 data = cache.peek(nodeid)
2217 2276 size = len(data)
2218 2277 totalsize += size + 24 # 20 bytes nodeid, 4 bytes size
2219 2278 ui.write(
2220 2279 _(b'id: %s, size %s\n') % (hex(nodeid), util.bytecount(size))
2221 2280 )
2222 2281 ondisk = cache._opener.stat(b'manifestfulltextcache').st_size
2223 2282 ui.write(
2224 2283 _(b'total cache data size %s, on-disk %s\n')
2225 2284 % (util.bytecount(totalsize), util.bytecount(ondisk))
2226 2285 )
2227 2286
2228 2287
2229 2288 @command(b'debugmergestate', [] + cmdutil.templateopts, b'')
2230 2289 def debugmergestate(ui, repo, *args, **opts):
2231 2290 """print merge state
2232 2291
2233 2292 Use --verbose to print out information about whether v1 or v2 merge state
2234 2293 was chosen."""
2235 2294
2236 2295 if ui.verbose:
2237 2296 ms = mergestatemod.mergestate(repo)
2238 2297
2239 2298 # sort so that reasonable information is on top
2240 2299 v1records = ms._readrecordsv1()
2241 2300 v2records = ms._readrecordsv2()
2242 2301
2243 2302 if not v1records and not v2records:
2244 2303 pass
2245 2304 elif not v2records:
2246 2305 ui.writenoi18n(b'no version 2 merge state\n')
2247 2306 elif ms._v1v2match(v1records, v2records):
2248 2307 ui.writenoi18n(b'v1 and v2 states match: using v2\n')
2249 2308 else:
2250 2309 ui.writenoi18n(b'v1 and v2 states mismatch: using v1\n')
2251 2310
2252 2311 opts = pycompat.byteskwargs(opts)
2253 2312 if not opts[b'template']:
2254 2313 opts[b'template'] = (
2255 2314 b'{if(commits, "", "no merge state found\n")}'
2256 2315 b'{commits % "{name}{if(label, " ({label})")}: {node}\n"}'
2257 2316 b'{files % "file: {path} (state \\"{state}\\")\n'
2258 2317 b'{if(local_path, "'
2259 2318 b' local path: {local_path} (hash {local_key}, flags \\"{local_flags}\\")\n'
2260 2319 b' ancestor path: {ancestor_path} (node {ancestor_node})\n'
2261 2320 b' other path: {other_path} (node {other_node})\n'
2262 2321 b'")}'
2263 2322 b'{if(rename_side, "'
2264 2323 b' rename side: {rename_side}\n'
2265 2324 b' renamed path: {renamed_path}\n'
2266 2325 b'")}'
2267 2326 b'{extras % " extra: {key} = {value}\n"}'
2268 2327 b'"}'
2269 2328 b'{extras % "extra: {file} ({key} = {value})\n"}'
2270 2329 )
2271 2330
2272 2331 ms = mergestatemod.mergestate.read(repo)
2273 2332
2274 2333 fm = ui.formatter(b'debugmergestate', opts)
2275 2334 fm.startitem()
2276 2335
2277 2336 fm_commits = fm.nested(b'commits')
2278 2337 if ms.active():
2279 2338 for name, node, label_index in (
2280 2339 (b'local', ms.local, 0),
2281 2340 (b'other', ms.other, 1),
2282 2341 ):
2283 2342 fm_commits.startitem()
2284 2343 fm_commits.data(name=name)
2285 2344 fm_commits.data(node=hex(node))
2286 2345 if ms._labels and len(ms._labels) > label_index:
2287 2346 fm_commits.data(label=ms._labels[label_index])
2288 2347 fm_commits.end()
2289 2348
2290 2349 fm_files = fm.nested(b'files')
2291 2350 if ms.active():
2292 2351 for f in ms:
2293 2352 fm_files.startitem()
2294 2353 fm_files.data(path=f)
2295 2354 state = ms._state[f]
2296 2355 fm_files.data(state=state[0])
2297 2356 if state[0] in (
2298 2357 mergestatemod.MERGE_RECORD_UNRESOLVED,
2299 2358 mergestatemod.MERGE_RECORD_RESOLVED,
2300 2359 ):
2301 2360 fm_files.data(local_key=state[1])
2302 2361 fm_files.data(local_path=state[2])
2303 2362 fm_files.data(ancestor_path=state[3])
2304 2363 fm_files.data(ancestor_node=state[4])
2305 2364 fm_files.data(other_path=state[5])
2306 2365 fm_files.data(other_node=state[6])
2307 2366 fm_files.data(local_flags=state[7])
2308 2367 elif state[0] in (
2309 2368 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
2310 2369 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
2311 2370 ):
2312 2371 fm_files.data(renamed_path=state[1])
2313 2372 fm_files.data(rename_side=state[2])
2314 2373 fm_extras = fm_files.nested(b'extras')
2315 2374 for k, v in sorted(ms.extras(f).items()):
2316 2375 fm_extras.startitem()
2317 2376 fm_extras.data(key=k)
2318 2377 fm_extras.data(value=v)
2319 2378 fm_extras.end()
2320 2379
2321 2380 fm_files.end()
2322 2381
2323 2382 fm_extras = fm.nested(b'extras')
2324 2383 for f, d in sorted(pycompat.iteritems(ms.allextras())):
2325 2384 if f in ms:
2326 2385 # If file is in mergestate, we have already processed it's extras
2327 2386 continue
2328 2387 for k, v in pycompat.iteritems(d):
2329 2388 fm_extras.startitem()
2330 2389 fm_extras.data(file=f)
2331 2390 fm_extras.data(key=k)
2332 2391 fm_extras.data(value=v)
2333 2392 fm_extras.end()
2334 2393
2335 2394 fm.end()
2336 2395
2337 2396
2338 2397 @command(b'debugnamecomplete', [], _(b'NAME...'))
2339 2398 def debugnamecomplete(ui, repo, *args):
2340 2399 '''complete "names" - tags, open branch names, bookmark names'''
2341 2400
2342 2401 names = set()
2343 2402 # since we previously only listed open branches, we will handle that
2344 2403 # specially (after this for loop)
2345 2404 for name, ns in pycompat.iteritems(repo.names):
2346 2405 if name != b'branches':
2347 2406 names.update(ns.listnames(repo))
2348 2407 names.update(
2349 2408 tag
2350 2409 for (tag, heads, tip, closed) in repo.branchmap().iterbranches()
2351 2410 if not closed
2352 2411 )
2353 2412 completions = set()
2354 2413 if not args:
2355 2414 args = [b'']
2356 2415 for a in args:
2357 2416 completions.update(n for n in names if n.startswith(a))
2358 2417 ui.write(b'\n'.join(sorted(completions)))
2359 2418 ui.write(b'\n')
2360 2419
2361 2420
2362 2421 @command(
2363 2422 b'debugnodemap',
2364 2423 [
2365 2424 (
2366 2425 b'',
2367 2426 b'dump-new',
2368 2427 False,
2369 2428 _(b'write a (new) persistent binary nodemap on stdout'),
2370 2429 ),
2371 2430 (b'', b'dump-disk', False, _(b'dump on-disk data on stdout')),
2372 2431 (
2373 2432 b'',
2374 2433 b'check',
2375 2434 False,
2376 2435 _(b'check that the data on disk data are correct.'),
2377 2436 ),
2378 2437 (
2379 2438 b'',
2380 2439 b'metadata',
2381 2440 False,
2382 2441 _(b'display the on disk meta data for the nodemap'),
2383 2442 ),
2384 2443 ],
2385 2444 )
2386 2445 def debugnodemap(ui, repo, **opts):
2387 2446 """write and inspect on disk nodemap"""
2388 2447 if opts['dump_new']:
2389 2448 unfi = repo.unfiltered()
2390 2449 cl = unfi.changelog
2391 2450 if util.safehasattr(cl.index, "nodemap_data_all"):
2392 2451 data = cl.index.nodemap_data_all()
2393 2452 else:
2394 2453 data = nodemap.persistent_data(cl.index)
2395 2454 ui.write(data)
2396 2455 elif opts['dump_disk']:
2397 2456 unfi = repo.unfiltered()
2398 2457 cl = unfi.changelog
2399 2458 nm_data = nodemap.persisted_data(cl)
2400 2459 if nm_data is not None:
2401 2460 docket, data = nm_data
2402 2461 ui.write(data[:])
2403 2462 elif opts['check']:
2404 2463 unfi = repo.unfiltered()
2405 2464 cl = unfi.changelog
2406 2465 nm_data = nodemap.persisted_data(cl)
2407 2466 if nm_data is not None:
2408 2467 docket, data = nm_data
2409 2468 return nodemap.check_data(ui, cl.index, data)
2410 2469 elif opts['metadata']:
2411 2470 unfi = repo.unfiltered()
2412 2471 cl = unfi.changelog
2413 2472 nm_data = nodemap.persisted_data(cl)
2414 2473 if nm_data is not None:
2415 2474 docket, data = nm_data
2416 2475 ui.write((b"uid: %s\n") % docket.uid)
2417 2476 ui.write((b"tip-rev: %d\n") % docket.tip_rev)
2418 2477 ui.write((b"tip-node: %s\n") % hex(docket.tip_node))
2419 2478 ui.write((b"data-length: %d\n") % docket.data_length)
2420 2479 ui.write((b"data-unused: %d\n") % docket.data_unused)
2421 2480 unused_perc = docket.data_unused * 100.0 / docket.data_length
2422 2481 ui.write((b"data-unused: %2.3f%%\n") % unused_perc)
2423 2482
2424 2483
2425 2484 @command(
2426 2485 b'debugobsolete',
2427 2486 [
2428 2487 (b'', b'flags', 0, _(b'markers flag')),
2429 2488 (
2430 2489 b'',
2431 2490 b'record-parents',
2432 2491 False,
2433 2492 _(b'record parent information for the precursor'),
2434 2493 ),
2435 2494 (b'r', b'rev', [], _(b'display markers relevant to REV')),
2436 2495 (
2437 2496 b'',
2438 2497 b'exclusive',
2439 2498 False,
2440 2499 _(b'restrict display to markers only relevant to REV'),
2441 2500 ),
2442 2501 (b'', b'index', False, _(b'display index of the marker')),
2443 2502 (b'', b'delete', [], _(b'delete markers specified by indices')),
2444 2503 ]
2445 2504 + cmdutil.commitopts2
2446 2505 + cmdutil.formatteropts,
2447 2506 _(b'[OBSOLETED [REPLACEMENT ...]]'),
2448 2507 )
2449 2508 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2450 2509 """create arbitrary obsolete marker
2451 2510
2452 2511 With no arguments, displays the list of obsolescence markers."""
2453 2512
2454 2513 opts = pycompat.byteskwargs(opts)
2455 2514
2456 2515 def parsenodeid(s):
2457 2516 try:
2458 2517 # We do not use revsingle/revrange functions here to accept
2459 2518 # arbitrary node identifiers, possibly not present in the
2460 2519 # local repository.
2461 2520 n = bin(s)
2462 2521 if len(n) != repo.nodeconstants.nodelen:
2463 2522 raise TypeError()
2464 2523 return n
2465 2524 except TypeError:
2466 2525 raise error.InputError(
2467 2526 b'changeset references must be full hexadecimal '
2468 2527 b'node identifiers'
2469 2528 )
2470 2529
2471 2530 if opts.get(b'delete'):
2472 2531 indices = []
2473 2532 for v in opts.get(b'delete'):
2474 2533 try:
2475 2534 indices.append(int(v))
2476 2535 except ValueError:
2477 2536 raise error.InputError(
2478 2537 _(b'invalid index value: %r') % v,
2479 2538 hint=_(b'use integers for indices'),
2480 2539 )
2481 2540
2482 2541 if repo.currenttransaction():
2483 2542 raise error.Abort(
2484 2543 _(b'cannot delete obsmarkers in the middle of transaction.')
2485 2544 )
2486 2545
2487 2546 with repo.lock():
2488 2547 n = repair.deleteobsmarkers(repo.obsstore, indices)
2489 2548 ui.write(_(b'deleted %i obsolescence markers\n') % n)
2490 2549
2491 2550 return
2492 2551
2493 2552 if precursor is not None:
2494 2553 if opts[b'rev']:
2495 2554 raise error.InputError(
2496 2555 b'cannot select revision when creating marker'
2497 2556 )
2498 2557 metadata = {}
2499 2558 metadata[b'user'] = encoding.fromlocal(opts[b'user'] or ui.username())
2500 2559 succs = tuple(parsenodeid(succ) for succ in successors)
2501 2560 l = repo.lock()
2502 2561 try:
2503 2562 tr = repo.transaction(b'debugobsolete')
2504 2563 try:
2505 2564 date = opts.get(b'date')
2506 2565 if date:
2507 2566 date = dateutil.parsedate(date)
2508 2567 else:
2509 2568 date = None
2510 2569 prec = parsenodeid(precursor)
2511 2570 parents = None
2512 2571 if opts[b'record_parents']:
2513 2572 if prec not in repo.unfiltered():
2514 2573 raise error.Abort(
2515 2574 b'cannot used --record-parents on '
2516 2575 b'unknown changesets'
2517 2576 )
2518 2577 parents = repo.unfiltered()[prec].parents()
2519 2578 parents = tuple(p.node() for p in parents)
2520 2579 repo.obsstore.create(
2521 2580 tr,
2522 2581 prec,
2523 2582 succs,
2524 2583 opts[b'flags'],
2525 2584 parents=parents,
2526 2585 date=date,
2527 2586 metadata=metadata,
2528 2587 ui=ui,
2529 2588 )
2530 2589 tr.close()
2531 2590 except ValueError as exc:
2532 2591 raise error.Abort(
2533 2592 _(b'bad obsmarker input: %s') % stringutil.forcebytestr(exc)
2534 2593 )
2535 2594 finally:
2536 2595 tr.release()
2537 2596 finally:
2538 2597 l.release()
2539 2598 else:
2540 2599 if opts[b'rev']:
2541 2600 revs = scmutil.revrange(repo, opts[b'rev'])
2542 2601 nodes = [repo[r].node() for r in revs]
2543 2602 markers = list(
2544 2603 obsutil.getmarkers(
2545 2604 repo, nodes=nodes, exclusive=opts[b'exclusive']
2546 2605 )
2547 2606 )
2548 2607 markers.sort(key=lambda x: x._data)
2549 2608 else:
2550 2609 markers = obsutil.getmarkers(repo)
2551 2610
2552 2611 markerstoiter = markers
2553 2612 isrelevant = lambda m: True
2554 2613 if opts.get(b'rev') and opts.get(b'index'):
2555 2614 markerstoiter = obsutil.getmarkers(repo)
2556 2615 markerset = set(markers)
2557 2616 isrelevant = lambda m: m in markerset
2558 2617
2559 2618 fm = ui.formatter(b'debugobsolete', opts)
2560 2619 for i, m in enumerate(markerstoiter):
2561 2620 if not isrelevant(m):
2562 2621 # marker can be irrelevant when we're iterating over a set
2563 2622 # of markers (markerstoiter) which is bigger than the set
2564 2623 # of markers we want to display (markers)
2565 2624 # this can happen if both --index and --rev options are
2566 2625 # provided and thus we need to iterate over all of the markers
2567 2626 # to get the correct indices, but only display the ones that
2568 2627 # are relevant to --rev value
2569 2628 continue
2570 2629 fm.startitem()
2571 2630 ind = i if opts.get(b'index') else None
2572 2631 cmdutil.showmarker(fm, m, index=ind)
2573 2632 fm.end()
2574 2633
2575 2634
2576 2635 @command(
2577 2636 b'debugp1copies',
2578 2637 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
2579 2638 _(b'[-r REV]'),
2580 2639 )
2581 2640 def debugp1copies(ui, repo, **opts):
2582 2641 """dump copy information compared to p1"""
2583 2642
2584 2643 opts = pycompat.byteskwargs(opts)
2585 2644 ctx = scmutil.revsingle(repo, opts.get(b'rev'), default=None)
2586 2645 for dst, src in ctx.p1copies().items():
2587 2646 ui.write(b'%s -> %s\n' % (src, dst))
2588 2647
2589 2648
2590 2649 @command(
2591 2650 b'debugp2copies',
2592 2651 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
2593 2652 _(b'[-r REV]'),
2594 2653 )
2595 2654 def debugp1copies(ui, repo, **opts):
2596 2655 """dump copy information compared to p2"""
2597 2656
2598 2657 opts = pycompat.byteskwargs(opts)
2599 2658 ctx = scmutil.revsingle(repo, opts.get(b'rev'), default=None)
2600 2659 for dst, src in ctx.p2copies().items():
2601 2660 ui.write(b'%s -> %s\n' % (src, dst))
2602 2661
2603 2662
2604 2663 @command(
2605 2664 b'debugpathcomplete',
2606 2665 [
2607 2666 (b'f', b'full', None, _(b'complete an entire path')),
2608 2667 (b'n', b'normal', None, _(b'show only normal files')),
2609 2668 (b'a', b'added', None, _(b'show only added files')),
2610 2669 (b'r', b'removed', None, _(b'show only removed files')),
2611 2670 ],
2612 2671 _(b'FILESPEC...'),
2613 2672 )
2614 2673 def debugpathcomplete(ui, repo, *specs, **opts):
2615 2674 """complete part or all of a tracked path
2616 2675
2617 2676 This command supports shells that offer path name completion. It
2618 2677 currently completes only files already known to the dirstate.
2619 2678
2620 2679 Completion extends only to the next path segment unless
2621 2680 --full is specified, in which case entire paths are used."""
2622 2681
2623 2682 def complete(path, acceptable):
2624 2683 dirstate = repo.dirstate
2625 2684 spec = os.path.normpath(os.path.join(encoding.getcwd(), path))
2626 2685 rootdir = repo.root + pycompat.ossep
2627 2686 if spec != repo.root and not spec.startswith(rootdir):
2628 2687 return [], []
2629 2688 if os.path.isdir(spec):
2630 2689 spec += b'/'
2631 2690 spec = spec[len(rootdir) :]
2632 2691 fixpaths = pycompat.ossep != b'/'
2633 2692 if fixpaths:
2634 2693 spec = spec.replace(pycompat.ossep, b'/')
2635 2694 speclen = len(spec)
2636 2695 fullpaths = opts['full']
2637 2696 files, dirs = set(), set()
2638 2697 adddir, addfile = dirs.add, files.add
2639 2698 for f, st in pycompat.iteritems(dirstate):
2640 2699 if f.startswith(spec) and st.state in acceptable:
2641 2700 if fixpaths:
2642 2701 f = f.replace(b'/', pycompat.ossep)
2643 2702 if fullpaths:
2644 2703 addfile(f)
2645 2704 continue
2646 2705 s = f.find(pycompat.ossep, speclen)
2647 2706 if s >= 0:
2648 2707 adddir(f[:s])
2649 2708 else:
2650 2709 addfile(f)
2651 2710 return files, dirs
2652 2711
2653 2712 acceptable = b''
2654 2713 if opts['normal']:
2655 2714 acceptable += b'nm'
2656 2715 if opts['added']:
2657 2716 acceptable += b'a'
2658 2717 if opts['removed']:
2659 2718 acceptable += b'r'
2660 2719 cwd = repo.getcwd()
2661 2720 if not specs:
2662 2721 specs = [b'.']
2663 2722
2664 2723 files, dirs = set(), set()
2665 2724 for spec in specs:
2666 2725 f, d = complete(spec, acceptable or b'nmar')
2667 2726 files.update(f)
2668 2727 dirs.update(d)
2669 2728 files.update(dirs)
2670 2729 ui.write(b'\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2671 2730 ui.write(b'\n')
2672 2731
2673 2732
2674 2733 @command(
2675 2734 b'debugpathcopies',
2676 2735 cmdutil.walkopts,
2677 2736 b'hg debugpathcopies REV1 REV2 [FILE]',
2678 2737 inferrepo=True,
2679 2738 )
2680 2739 def debugpathcopies(ui, repo, rev1, rev2, *pats, **opts):
2681 2740 """show copies between two revisions"""
2682 2741 ctx1 = scmutil.revsingle(repo, rev1)
2683 2742 ctx2 = scmutil.revsingle(repo, rev2)
2684 2743 m = scmutil.match(ctx1, pats, opts)
2685 2744 for dst, src in sorted(copies.pathcopies(ctx1, ctx2, m).items()):
2686 2745 ui.write(b'%s -> %s\n' % (src, dst))
2687 2746
2688 2747
2689 2748 @command(b'debugpeer', [], _(b'PATH'), norepo=True)
2690 2749 def debugpeer(ui, path):
2691 2750 """establish a connection to a peer repository"""
2692 2751 # Always enable peer request logging. Requires --debug to display
2693 2752 # though.
2694 2753 overrides = {
2695 2754 (b'devel', b'debug.peer-request'): True,
2696 2755 }
2697 2756
2698 2757 with ui.configoverride(overrides):
2699 2758 peer = hg.peer(ui, {}, path)
2700 2759
2701 2760 try:
2702 2761 local = peer.local() is not None
2703 2762 canpush = peer.canpush()
2704 2763
2705 2764 ui.write(_(b'url: %s\n') % peer.url())
2706 2765 ui.write(_(b'local: %s\n') % (_(b'yes') if local else _(b'no')))
2707 2766 ui.write(
2708 2767 _(b'pushable: %s\n') % (_(b'yes') if canpush else _(b'no'))
2709 2768 )
2710 2769 finally:
2711 2770 peer.close()
2712 2771
2713 2772
2714 2773 @command(
2715 2774 b'debugpickmergetool',
2716 2775 [
2717 2776 (b'r', b'rev', b'', _(b'check for files in this revision'), _(b'REV')),
2718 2777 (b'', b'changedelete', None, _(b'emulate merging change and delete')),
2719 2778 ]
2720 2779 + cmdutil.walkopts
2721 2780 + cmdutil.mergetoolopts,
2722 2781 _(b'[PATTERN]...'),
2723 2782 inferrepo=True,
2724 2783 )
2725 2784 def debugpickmergetool(ui, repo, *pats, **opts):
2726 2785 """examine which merge tool is chosen for specified file
2727 2786
2728 2787 As described in :hg:`help merge-tools`, Mercurial examines
2729 2788 configurations below in this order to decide which merge tool is
2730 2789 chosen for specified file.
2731 2790
2732 2791 1. ``--tool`` option
2733 2792 2. ``HGMERGE`` environment variable
2734 2793 3. configurations in ``merge-patterns`` section
2735 2794 4. configuration of ``ui.merge``
2736 2795 5. configurations in ``merge-tools`` section
2737 2796 6. ``hgmerge`` tool (for historical reason only)
2738 2797 7. default tool for fallback (``:merge`` or ``:prompt``)
2739 2798
2740 2799 This command writes out examination result in the style below::
2741 2800
2742 2801 FILE = MERGETOOL
2743 2802
2744 2803 By default, all files known in the first parent context of the
2745 2804 working directory are examined. Use file patterns and/or -I/-X
2746 2805 options to limit target files. -r/--rev is also useful to examine
2747 2806 files in another context without actual updating to it.
2748 2807
2749 2808 With --debug, this command shows warning messages while matching
2750 2809 against ``merge-patterns`` and so on, too. It is recommended to
2751 2810 use this option with explicit file patterns and/or -I/-X options,
2752 2811 because this option increases amount of output per file according
2753 2812 to configurations in hgrc.
2754 2813
2755 2814 With -v/--verbose, this command shows configurations below at
2756 2815 first (only if specified).
2757 2816
2758 2817 - ``--tool`` option
2759 2818 - ``HGMERGE`` environment variable
2760 2819 - configuration of ``ui.merge``
2761 2820
2762 2821 If merge tool is chosen before matching against
2763 2822 ``merge-patterns``, this command can't show any helpful
2764 2823 information, even with --debug. In such case, information above is
2765 2824 useful to know why a merge tool is chosen.
2766 2825 """
2767 2826 opts = pycompat.byteskwargs(opts)
2768 2827 overrides = {}
2769 2828 if opts[b'tool']:
2770 2829 overrides[(b'ui', b'forcemerge')] = opts[b'tool']
2771 2830 ui.notenoi18n(b'with --tool %r\n' % (pycompat.bytestr(opts[b'tool'])))
2772 2831
2773 2832 with ui.configoverride(overrides, b'debugmergepatterns'):
2774 2833 hgmerge = encoding.environ.get(b"HGMERGE")
2775 2834 if hgmerge is not None:
2776 2835 ui.notenoi18n(b'with HGMERGE=%r\n' % (pycompat.bytestr(hgmerge)))
2777 2836 uimerge = ui.config(b"ui", b"merge")
2778 2837 if uimerge:
2779 2838 ui.notenoi18n(b'with ui.merge=%r\n' % (pycompat.bytestr(uimerge)))
2780 2839
2781 2840 ctx = scmutil.revsingle(repo, opts.get(b'rev'))
2782 2841 m = scmutil.match(ctx, pats, opts)
2783 2842 changedelete = opts[b'changedelete']
2784 2843 for path in ctx.walk(m):
2785 2844 fctx = ctx[path]
2786 2845 with ui.silent(
2787 2846 error=True
2788 2847 ) if not ui.debugflag else util.nullcontextmanager():
2789 2848 tool, toolpath = filemerge._picktool(
2790 2849 repo,
2791 2850 ui,
2792 2851 path,
2793 2852 fctx.isbinary(),
2794 2853 b'l' in fctx.flags(),
2795 2854 changedelete,
2796 2855 )
2797 2856 ui.write(b'%s = %s\n' % (path, tool))
2798 2857
2799 2858
2800 2859 @command(b'debugpushkey', [], _(b'REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2801 2860 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2802 2861 """access the pushkey key/value protocol
2803 2862
2804 2863 With two args, list the keys in the given namespace.
2805 2864
2806 2865 With five args, set a key to new if it currently is set to old.
2807 2866 Reports success or failure.
2808 2867 """
2809 2868
2810 2869 target = hg.peer(ui, {}, repopath)
2811 2870 try:
2812 2871 if keyinfo:
2813 2872 key, old, new = keyinfo
2814 2873 with target.commandexecutor() as e:
2815 2874 r = e.callcommand(
2816 2875 b'pushkey',
2817 2876 {
2818 2877 b'namespace': namespace,
2819 2878 b'key': key,
2820 2879 b'old': old,
2821 2880 b'new': new,
2822 2881 },
2823 2882 ).result()
2824 2883
2825 2884 ui.status(pycompat.bytestr(r) + b'\n')
2826 2885 return not r
2827 2886 else:
2828 2887 for k, v in sorted(pycompat.iteritems(target.listkeys(namespace))):
2829 2888 ui.write(
2830 2889 b"%s\t%s\n"
2831 2890 % (stringutil.escapestr(k), stringutil.escapestr(v))
2832 2891 )
2833 2892 finally:
2834 2893 target.close()
2835 2894
2836 2895
2837 2896 @command(b'debugpvec', [], _(b'A B'))
2838 2897 def debugpvec(ui, repo, a, b=None):
2839 2898 ca = scmutil.revsingle(repo, a)
2840 2899 cb = scmutil.revsingle(repo, b)
2841 2900 pa = pvec.ctxpvec(ca)
2842 2901 pb = pvec.ctxpvec(cb)
2843 2902 if pa == pb:
2844 2903 rel = b"="
2845 2904 elif pa > pb:
2846 2905 rel = b">"
2847 2906 elif pa < pb:
2848 2907 rel = b"<"
2849 2908 elif pa | pb:
2850 2909 rel = b"|"
2851 2910 ui.write(_(b"a: %s\n") % pa)
2852 2911 ui.write(_(b"b: %s\n") % pb)
2853 2912 ui.write(_(b"depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2854 2913 ui.write(
2855 2914 _(b"delta: %d hdist: %d distance: %d relation: %s\n")
2856 2915 % (
2857 2916 abs(pa._depth - pb._depth),
2858 2917 pvec._hamming(pa._vec, pb._vec),
2859 2918 pa.distance(pb),
2860 2919 rel,
2861 2920 )
2862 2921 )
2863 2922
2864 2923
2865 2924 @command(
2866 2925 b'debugrebuilddirstate|debugrebuildstate',
2867 2926 [
2868 2927 (b'r', b'rev', b'', _(b'revision to rebuild to'), _(b'REV')),
2869 2928 (
2870 2929 b'',
2871 2930 b'minimal',
2872 2931 None,
2873 2932 _(
2874 2933 b'only rebuild files that are inconsistent with '
2875 2934 b'the working copy parent'
2876 2935 ),
2877 2936 ),
2878 2937 ],
2879 2938 _(b'[-r REV]'),
2880 2939 )
2881 2940 def debugrebuilddirstate(ui, repo, rev, **opts):
2882 2941 """rebuild the dirstate as it would look like for the given revision
2883 2942
2884 2943 If no revision is specified the first current parent will be used.
2885 2944
2886 2945 The dirstate will be set to the files of the given revision.
2887 2946 The actual working directory content or existing dirstate
2888 2947 information such as adds or removes is not considered.
2889 2948
2890 2949 ``minimal`` will only rebuild the dirstate status for files that claim to be
2891 2950 tracked but are not in the parent manifest, or that exist in the parent
2892 2951 manifest but are not in the dirstate. It will not change adds, removes, or
2893 2952 modified files that are in the working copy parent.
2894 2953
2895 2954 One use of this command is to make the next :hg:`status` invocation
2896 2955 check the actual file content.
2897 2956 """
2898 2957 ctx = scmutil.revsingle(repo, rev)
2899 2958 with repo.wlock():
2900 2959 dirstate = repo.dirstate
2901 2960 changedfiles = None
2902 2961 # See command doc for what minimal does.
2903 2962 if opts.get('minimal'):
2904 2963 manifestfiles = set(ctx.manifest().keys())
2905 2964 dirstatefiles = set(dirstate)
2906 2965 manifestonly = manifestfiles - dirstatefiles
2907 2966 dsonly = dirstatefiles - manifestfiles
2908 2967 dsnotadded = {f for f in dsonly if dirstate[f] != b'a'}
2909 2968 changedfiles = manifestonly | dsnotadded
2910 2969
2911 2970 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
2912 2971
2913 2972
2914 2973 @command(b'debugrebuildfncache', [], b'')
2915 2974 def debugrebuildfncache(ui, repo):
2916 2975 """rebuild the fncache file"""
2917 2976 repair.rebuildfncache(ui, repo)
2918 2977
2919 2978
2920 2979 @command(
2921 2980 b'debugrename',
2922 2981 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
2923 2982 _(b'[-r REV] [FILE]...'),
2924 2983 )
2925 2984 def debugrename(ui, repo, *pats, **opts):
2926 2985 """dump rename information"""
2927 2986
2928 2987 opts = pycompat.byteskwargs(opts)
2929 2988 ctx = scmutil.revsingle(repo, opts.get(b'rev'))
2930 2989 m = scmutil.match(ctx, pats, opts)
2931 2990 for abs in ctx.walk(m):
2932 2991 fctx = ctx[abs]
2933 2992 o = fctx.filelog().renamed(fctx.filenode())
2934 2993 rel = repo.pathto(abs)
2935 2994 if o:
2936 2995 ui.write(_(b"%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2937 2996 else:
2938 2997 ui.write(_(b"%s not renamed\n") % rel)
2939 2998
2940 2999
2941 3000 @command(b'debugrequires|debugrequirements', [], b'')
2942 3001 def debugrequirements(ui, repo):
2943 3002 """print the current repo requirements"""
2944 3003 for r in sorted(repo.requirements):
2945 3004 ui.write(b"%s\n" % r)
2946 3005
2947 3006
2948 3007 @command(
2949 3008 b'debugrevlog',
2950 3009 cmdutil.debugrevlogopts + [(b'd', b'dump', False, _(b'dump index data'))],
2951 3010 _(b'-c|-m|FILE'),
2952 3011 optionalrepo=True,
2953 3012 )
2954 3013 def debugrevlog(ui, repo, file_=None, **opts):
2955 3014 """show data and statistics about a revlog"""
2956 3015 opts = pycompat.byteskwargs(opts)
2957 3016 r = cmdutil.openrevlog(repo, b'debugrevlog', file_, opts)
2958 3017
2959 3018 if opts.get(b"dump"):
2960 3019 numrevs = len(r)
2961 3020 ui.write(
2962 3021 (
2963 3022 b"# rev p1rev p2rev start end deltastart base p1 p2"
2964 3023 b" rawsize totalsize compression heads chainlen\n"
2965 3024 )
2966 3025 )
2967 3026 ts = 0
2968 3027 heads = set()
2969 3028
2970 3029 for rev in pycompat.xrange(numrevs):
2971 3030 dbase = r.deltaparent(rev)
2972 3031 if dbase == -1:
2973 3032 dbase = rev
2974 3033 cbase = r.chainbase(rev)
2975 3034 clen = r.chainlen(rev)
2976 3035 p1, p2 = r.parentrevs(rev)
2977 3036 rs = r.rawsize(rev)
2978 3037 ts = ts + rs
2979 3038 heads -= set(r.parentrevs(rev))
2980 3039 heads.add(rev)
2981 3040 try:
2982 3041 compression = ts / r.end(rev)
2983 3042 except ZeroDivisionError:
2984 3043 compression = 0
2985 3044 ui.write(
2986 3045 b"%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2987 3046 b"%11d %5d %8d\n"
2988 3047 % (
2989 3048 rev,
2990 3049 p1,
2991 3050 p2,
2992 3051 r.start(rev),
2993 3052 r.end(rev),
2994 3053 r.start(dbase),
2995 3054 r.start(cbase),
2996 3055 r.start(p1),
2997 3056 r.start(p2),
2998 3057 rs,
2999 3058 ts,
3000 3059 compression,
3001 3060 len(heads),
3002 3061 clen,
3003 3062 )
3004 3063 )
3005 3064 return 0
3006 3065
3007 3066 format = r._format_version
3008 3067 v = r._format_flags
3009 3068 flags = []
3010 3069 gdelta = False
3011 3070 if v & revlog.FLAG_INLINE_DATA:
3012 3071 flags.append(b'inline')
3013 3072 if v & revlog.FLAG_GENERALDELTA:
3014 3073 gdelta = True
3015 3074 flags.append(b'generaldelta')
3016 3075 if not flags:
3017 3076 flags = [b'(none)']
3018 3077
3019 3078 ### tracks merge vs single parent
3020 3079 nummerges = 0
3021 3080
3022 3081 ### tracks ways the "delta" are build
3023 3082 # nodelta
3024 3083 numempty = 0
3025 3084 numemptytext = 0
3026 3085 numemptydelta = 0
3027 3086 # full file content
3028 3087 numfull = 0
3029 3088 # intermediate snapshot against a prior snapshot
3030 3089 numsemi = 0
3031 3090 # snapshot count per depth
3032 3091 numsnapdepth = collections.defaultdict(lambda: 0)
3033 3092 # delta against previous revision
3034 3093 numprev = 0
3035 3094 # delta against first or second parent (not prev)
3036 3095 nump1 = 0
3037 3096 nump2 = 0
3038 3097 # delta against neither prev nor parents
3039 3098 numother = 0
3040 3099 # delta against prev that are also first or second parent
3041 3100 # (details of `numprev`)
3042 3101 nump1prev = 0
3043 3102 nump2prev = 0
3044 3103
3045 3104 # data about delta chain of each revs
3046 3105 chainlengths = []
3047 3106 chainbases = []
3048 3107 chainspans = []
3049 3108
3050 3109 # data about each revision
3051 3110 datasize = [None, 0, 0]
3052 3111 fullsize = [None, 0, 0]
3053 3112 semisize = [None, 0, 0]
3054 3113 # snapshot count per depth
3055 3114 snapsizedepth = collections.defaultdict(lambda: [None, 0, 0])
3056 3115 deltasize = [None, 0, 0]
3057 3116 chunktypecounts = {}
3058 3117 chunktypesizes = {}
3059 3118
3060 3119 def addsize(size, l):
3061 3120 if l[0] is None or size < l[0]:
3062 3121 l[0] = size
3063 3122 if size > l[1]:
3064 3123 l[1] = size
3065 3124 l[2] += size
3066 3125
3067 3126 numrevs = len(r)
3068 3127 for rev in pycompat.xrange(numrevs):
3069 3128 p1, p2 = r.parentrevs(rev)
3070 3129 delta = r.deltaparent(rev)
3071 3130 if format > 0:
3072 3131 addsize(r.rawsize(rev), datasize)
3073 3132 if p2 != nullrev:
3074 3133 nummerges += 1
3075 3134 size = r.length(rev)
3076 3135 if delta == nullrev:
3077 3136 chainlengths.append(0)
3078 3137 chainbases.append(r.start(rev))
3079 3138 chainspans.append(size)
3080 3139 if size == 0:
3081 3140 numempty += 1
3082 3141 numemptytext += 1
3083 3142 else:
3084 3143 numfull += 1
3085 3144 numsnapdepth[0] += 1
3086 3145 addsize(size, fullsize)
3087 3146 addsize(size, snapsizedepth[0])
3088 3147 else:
3089 3148 chainlengths.append(chainlengths[delta] + 1)
3090 3149 baseaddr = chainbases[delta]
3091 3150 revaddr = r.start(rev)
3092 3151 chainbases.append(baseaddr)
3093 3152 chainspans.append((revaddr - baseaddr) + size)
3094 3153 if size == 0:
3095 3154 numempty += 1
3096 3155 numemptydelta += 1
3097 3156 elif r.issnapshot(rev):
3098 3157 addsize(size, semisize)
3099 3158 numsemi += 1
3100 3159 depth = r.snapshotdepth(rev)
3101 3160 numsnapdepth[depth] += 1
3102 3161 addsize(size, snapsizedepth[depth])
3103 3162 else:
3104 3163 addsize(size, deltasize)
3105 3164 if delta == rev - 1:
3106 3165 numprev += 1
3107 3166 if delta == p1:
3108 3167 nump1prev += 1
3109 3168 elif delta == p2:
3110 3169 nump2prev += 1
3111 3170 elif delta == p1:
3112 3171 nump1 += 1
3113 3172 elif delta == p2:
3114 3173 nump2 += 1
3115 3174 elif delta != nullrev:
3116 3175 numother += 1
3117 3176
3118 3177 # Obtain data on the raw chunks in the revlog.
3119 3178 if util.safehasattr(r, b'_getsegmentforrevs'):
3120 3179 segment = r._getsegmentforrevs(rev, rev)[1]
3121 3180 else:
3122 3181 segment = r._revlog._getsegmentforrevs(rev, rev)[1]
3123 3182 if segment:
3124 3183 chunktype = bytes(segment[0:1])
3125 3184 else:
3126 3185 chunktype = b'empty'
3127 3186
3128 3187 if chunktype not in chunktypecounts:
3129 3188 chunktypecounts[chunktype] = 0
3130 3189 chunktypesizes[chunktype] = 0
3131 3190
3132 3191 chunktypecounts[chunktype] += 1
3133 3192 chunktypesizes[chunktype] += size
3134 3193
3135 3194 # Adjust size min value for empty cases
3136 3195 for size in (datasize, fullsize, semisize, deltasize):
3137 3196 if size[0] is None:
3138 3197 size[0] = 0
3139 3198
3140 3199 numdeltas = numrevs - numfull - numempty - numsemi
3141 3200 numoprev = numprev - nump1prev - nump2prev
3142 3201 totalrawsize = datasize[2]
3143 3202 datasize[2] /= numrevs
3144 3203 fulltotal = fullsize[2]
3145 3204 if numfull == 0:
3146 3205 fullsize[2] = 0
3147 3206 else:
3148 3207 fullsize[2] /= numfull
3149 3208 semitotal = semisize[2]
3150 3209 snaptotal = {}
3151 3210 if numsemi > 0:
3152 3211 semisize[2] /= numsemi
3153 3212 for depth in snapsizedepth:
3154 3213 snaptotal[depth] = snapsizedepth[depth][2]
3155 3214 snapsizedepth[depth][2] /= numsnapdepth[depth]
3156 3215
3157 3216 deltatotal = deltasize[2]
3158 3217 if numdeltas > 0:
3159 3218 deltasize[2] /= numdeltas
3160 3219 totalsize = fulltotal + semitotal + deltatotal
3161 3220 avgchainlen = sum(chainlengths) / numrevs
3162 3221 maxchainlen = max(chainlengths)
3163 3222 maxchainspan = max(chainspans)
3164 3223 compratio = 1
3165 3224 if totalsize:
3166 3225 compratio = totalrawsize / totalsize
3167 3226
3168 3227 basedfmtstr = b'%%%dd\n'
3169 3228 basepcfmtstr = b'%%%dd %s(%%5.2f%%%%)\n'
3170 3229
3171 3230 def dfmtstr(max):
3172 3231 return basedfmtstr % len(str(max))
3173 3232
3174 3233 def pcfmtstr(max, padding=0):
3175 3234 return basepcfmtstr % (len(str(max)), b' ' * padding)
3176 3235
3177 3236 def pcfmt(value, total):
3178 3237 if total:
3179 3238 return (value, 100 * float(value) / total)
3180 3239 else:
3181 3240 return value, 100.0
3182 3241
3183 3242 ui.writenoi18n(b'format : %d\n' % format)
3184 3243 ui.writenoi18n(b'flags : %s\n' % b', '.join(flags))
3185 3244
3186 3245 ui.write(b'\n')
3187 3246 fmt = pcfmtstr(totalsize)
3188 3247 fmt2 = dfmtstr(totalsize)
3189 3248 ui.writenoi18n(b'revisions : ' + fmt2 % numrevs)
3190 3249 ui.writenoi18n(b' merges : ' + fmt % pcfmt(nummerges, numrevs))
3191 3250 ui.writenoi18n(
3192 3251 b' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs)
3193 3252 )
3194 3253 ui.writenoi18n(b'revisions : ' + fmt2 % numrevs)
3195 3254 ui.writenoi18n(b' empty : ' + fmt % pcfmt(numempty, numrevs))
3196 3255 ui.writenoi18n(
3197 3256 b' text : '
3198 3257 + fmt % pcfmt(numemptytext, numemptytext + numemptydelta)
3199 3258 )
3200 3259 ui.writenoi18n(
3201 3260 b' delta : '
3202 3261 + fmt % pcfmt(numemptydelta, numemptytext + numemptydelta)
3203 3262 )
3204 3263 ui.writenoi18n(
3205 3264 b' snapshot : ' + fmt % pcfmt(numfull + numsemi, numrevs)
3206 3265 )
3207 3266 for depth in sorted(numsnapdepth):
3208 3267 ui.write(
3209 3268 (b' lvl-%-3d : ' % depth)
3210 3269 + fmt % pcfmt(numsnapdepth[depth], numrevs)
3211 3270 )
3212 3271 ui.writenoi18n(b' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
3213 3272 ui.writenoi18n(b'revision size : ' + fmt2 % totalsize)
3214 3273 ui.writenoi18n(
3215 3274 b' snapshot : ' + fmt % pcfmt(fulltotal + semitotal, totalsize)
3216 3275 )
3217 3276 for depth in sorted(numsnapdepth):
3218 3277 ui.write(
3219 3278 (b' lvl-%-3d : ' % depth)
3220 3279 + fmt % pcfmt(snaptotal[depth], totalsize)
3221 3280 )
3222 3281 ui.writenoi18n(b' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
3223 3282
3224 3283 def fmtchunktype(chunktype):
3225 3284 if chunktype == b'empty':
3226 3285 return b' %s : ' % chunktype
3227 3286 elif chunktype in pycompat.bytestr(string.ascii_letters):
3228 3287 return b' 0x%s (%s) : ' % (hex(chunktype), chunktype)
3229 3288 else:
3230 3289 return b' 0x%s : ' % hex(chunktype)
3231 3290
3232 3291 ui.write(b'\n')
3233 3292 ui.writenoi18n(b'chunks : ' + fmt2 % numrevs)
3234 3293 for chunktype in sorted(chunktypecounts):
3235 3294 ui.write(fmtchunktype(chunktype))
3236 3295 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
3237 3296 ui.writenoi18n(b'chunks size : ' + fmt2 % totalsize)
3238 3297 for chunktype in sorted(chunktypecounts):
3239 3298 ui.write(fmtchunktype(chunktype))
3240 3299 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
3241 3300
3242 3301 ui.write(b'\n')
3243 3302 fmt = dfmtstr(max(avgchainlen, maxchainlen, maxchainspan, compratio))
3244 3303 ui.writenoi18n(b'avg chain length : ' + fmt % avgchainlen)
3245 3304 ui.writenoi18n(b'max chain length : ' + fmt % maxchainlen)
3246 3305 ui.writenoi18n(b'max chain reach : ' + fmt % maxchainspan)
3247 3306 ui.writenoi18n(b'compression ratio : ' + fmt % compratio)
3248 3307
3249 3308 if format > 0:
3250 3309 ui.write(b'\n')
3251 3310 ui.writenoi18n(
3252 3311 b'uncompressed data size (min/max/avg) : %d / %d / %d\n'
3253 3312 % tuple(datasize)
3254 3313 )
3255 3314 ui.writenoi18n(
3256 3315 b'full revision size (min/max/avg) : %d / %d / %d\n'
3257 3316 % tuple(fullsize)
3258 3317 )
3259 3318 ui.writenoi18n(
3260 3319 b'inter-snapshot size (min/max/avg) : %d / %d / %d\n'
3261 3320 % tuple(semisize)
3262 3321 )
3263 3322 for depth in sorted(snapsizedepth):
3264 3323 if depth == 0:
3265 3324 continue
3266 3325 ui.writenoi18n(
3267 3326 b' level-%-3d (min/max/avg) : %d / %d / %d\n'
3268 3327 % ((depth,) + tuple(snapsizedepth[depth]))
3269 3328 )
3270 3329 ui.writenoi18n(
3271 3330 b'delta size (min/max/avg) : %d / %d / %d\n'
3272 3331 % tuple(deltasize)
3273 3332 )
3274 3333
3275 3334 if numdeltas > 0:
3276 3335 ui.write(b'\n')
3277 3336 fmt = pcfmtstr(numdeltas)
3278 3337 fmt2 = pcfmtstr(numdeltas, 4)
3279 3338 ui.writenoi18n(
3280 3339 b'deltas against prev : ' + fmt % pcfmt(numprev, numdeltas)
3281 3340 )
3282 3341 if numprev > 0:
3283 3342 ui.writenoi18n(
3284 3343 b' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev)
3285 3344 )
3286 3345 ui.writenoi18n(
3287 3346 b' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev)
3288 3347 )
3289 3348 ui.writenoi18n(
3290 3349 b' other : ' + fmt2 % pcfmt(numoprev, numprev)
3291 3350 )
3292 3351 if gdelta:
3293 3352 ui.writenoi18n(
3294 3353 b'deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas)
3295 3354 )
3296 3355 ui.writenoi18n(
3297 3356 b'deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas)
3298 3357 )
3299 3358 ui.writenoi18n(
3300 3359 b'deltas against other : ' + fmt % pcfmt(numother, numdeltas)
3301 3360 )
3302 3361
3303 3362
3304 3363 @command(
3305 3364 b'debugrevlogindex',
3306 3365 cmdutil.debugrevlogopts
3307 3366 + [(b'f', b'format', 0, _(b'revlog format'), _(b'FORMAT'))],
3308 3367 _(b'[-f FORMAT] -c|-m|FILE'),
3309 3368 optionalrepo=True,
3310 3369 )
3311 3370 def debugrevlogindex(ui, repo, file_=None, **opts):
3312 3371 """dump the contents of a revlog index"""
3313 3372 opts = pycompat.byteskwargs(opts)
3314 3373 r = cmdutil.openrevlog(repo, b'debugrevlogindex', file_, opts)
3315 3374 format = opts.get(b'format', 0)
3316 3375 if format not in (0, 1):
3317 3376 raise error.Abort(_(b"unknown format %d") % format)
3318 3377
3319 3378 if ui.debugflag:
3320 3379 shortfn = hex
3321 3380 else:
3322 3381 shortfn = short
3323 3382
3324 3383 # There might not be anything in r, so have a sane default
3325 3384 idlen = 12
3326 3385 for i in r:
3327 3386 idlen = len(shortfn(r.node(i)))
3328 3387 break
3329 3388
3330 3389 if format == 0:
3331 3390 if ui.verbose:
3332 3391 ui.writenoi18n(
3333 3392 b" rev offset length linkrev %s %s p2\n"
3334 3393 % (b"nodeid".ljust(idlen), b"p1".ljust(idlen))
3335 3394 )
3336 3395 else:
3337 3396 ui.writenoi18n(
3338 3397 b" rev linkrev %s %s p2\n"
3339 3398 % (b"nodeid".ljust(idlen), b"p1".ljust(idlen))
3340 3399 )
3341 3400 elif format == 1:
3342 3401 if ui.verbose:
3343 3402 ui.writenoi18n(
3344 3403 (
3345 3404 b" rev flag offset length size link p1"
3346 3405 b" p2 %s\n"
3347 3406 )
3348 3407 % b"nodeid".rjust(idlen)
3349 3408 )
3350 3409 else:
3351 3410 ui.writenoi18n(
3352 3411 b" rev flag size link p1 p2 %s\n"
3353 3412 % b"nodeid".rjust(idlen)
3354 3413 )
3355 3414
3356 3415 for i in r:
3357 3416 node = r.node(i)
3358 3417 if format == 0:
3359 3418 try:
3360 3419 pp = r.parents(node)
3361 3420 except Exception:
3362 3421 pp = [repo.nullid, repo.nullid]
3363 3422 if ui.verbose:
3364 3423 ui.write(
3365 3424 b"% 6d % 9d % 7d % 7d %s %s %s\n"
3366 3425 % (
3367 3426 i,
3368 3427 r.start(i),
3369 3428 r.length(i),
3370 3429 r.linkrev(i),
3371 3430 shortfn(node),
3372 3431 shortfn(pp[0]),
3373 3432 shortfn(pp[1]),
3374 3433 )
3375 3434 )
3376 3435 else:
3377 3436 ui.write(
3378 3437 b"% 6d % 7d %s %s %s\n"
3379 3438 % (
3380 3439 i,
3381 3440 r.linkrev(i),
3382 3441 shortfn(node),
3383 3442 shortfn(pp[0]),
3384 3443 shortfn(pp[1]),
3385 3444 )
3386 3445 )
3387 3446 elif format == 1:
3388 3447 pr = r.parentrevs(i)
3389 3448 if ui.verbose:
3390 3449 ui.write(
3391 3450 b"% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d %s\n"
3392 3451 % (
3393 3452 i,
3394 3453 r.flags(i),
3395 3454 r.start(i),
3396 3455 r.length(i),
3397 3456 r.rawsize(i),
3398 3457 r.linkrev(i),
3399 3458 pr[0],
3400 3459 pr[1],
3401 3460 shortfn(node),
3402 3461 )
3403 3462 )
3404 3463 else:
3405 3464 ui.write(
3406 3465 b"% 6d %04x % 8d % 6d % 6d % 6d %s\n"
3407 3466 % (
3408 3467 i,
3409 3468 r.flags(i),
3410 3469 r.rawsize(i),
3411 3470 r.linkrev(i),
3412 3471 pr[0],
3413 3472 pr[1],
3414 3473 shortfn(node),
3415 3474 )
3416 3475 )
3417 3476
3418 3477
3419 3478 @command(
3420 3479 b'debugrevspec',
3421 3480 [
3422 3481 (
3423 3482 b'',
3424 3483 b'optimize',
3425 3484 None,
3426 3485 _(b'print parsed tree after optimizing (DEPRECATED)'),
3427 3486 ),
3428 3487 (
3429 3488 b'',
3430 3489 b'show-revs',
3431 3490 True,
3432 3491 _(b'print list of result revisions (default)'),
3433 3492 ),
3434 3493 (
3435 3494 b's',
3436 3495 b'show-set',
3437 3496 None,
3438 3497 _(b'print internal representation of result set'),
3439 3498 ),
3440 3499 (
3441 3500 b'p',
3442 3501 b'show-stage',
3443 3502 [],
3444 3503 _(b'print parsed tree at the given stage'),
3445 3504 _(b'NAME'),
3446 3505 ),
3447 3506 (b'', b'no-optimized', False, _(b'evaluate tree without optimization')),
3448 3507 (b'', b'verify-optimized', False, _(b'verify optimized result')),
3449 3508 ],
3450 3509 b'REVSPEC',
3451 3510 )
3452 3511 def debugrevspec(ui, repo, expr, **opts):
3453 3512 """parse and apply a revision specification
3454 3513
3455 3514 Use -p/--show-stage option to print the parsed tree at the given stages.
3456 3515 Use -p all to print tree at every stage.
3457 3516
3458 3517 Use --no-show-revs option with -s or -p to print only the set
3459 3518 representation or the parsed tree respectively.
3460 3519
3461 3520 Use --verify-optimized to compare the optimized result with the unoptimized
3462 3521 one. Returns 1 if the optimized result differs.
3463 3522 """
3464 3523 opts = pycompat.byteskwargs(opts)
3465 3524 aliases = ui.configitems(b'revsetalias')
3466 3525 stages = [
3467 3526 (b'parsed', lambda tree: tree),
3468 3527 (
3469 3528 b'expanded',
3470 3529 lambda tree: revsetlang.expandaliases(tree, aliases, ui.warn),
3471 3530 ),
3472 3531 (b'concatenated', revsetlang.foldconcat),
3473 3532 (b'analyzed', revsetlang.analyze),
3474 3533 (b'optimized', revsetlang.optimize),
3475 3534 ]
3476 3535 if opts[b'no_optimized']:
3477 3536 stages = stages[:-1]
3478 3537 if opts[b'verify_optimized'] and opts[b'no_optimized']:
3479 3538 raise error.Abort(
3480 3539 _(b'cannot use --verify-optimized with --no-optimized')
3481 3540 )
3482 3541 stagenames = {n for n, f in stages}
3483 3542
3484 3543 showalways = set()
3485 3544 showchanged = set()
3486 3545 if ui.verbose and not opts[b'show_stage']:
3487 3546 # show parsed tree by --verbose (deprecated)
3488 3547 showalways.add(b'parsed')
3489 3548 showchanged.update([b'expanded', b'concatenated'])
3490 3549 if opts[b'optimize']:
3491 3550 showalways.add(b'optimized')
3492 3551 if opts[b'show_stage'] and opts[b'optimize']:
3493 3552 raise error.Abort(_(b'cannot use --optimize with --show-stage'))
3494 3553 if opts[b'show_stage'] == [b'all']:
3495 3554 showalways.update(stagenames)
3496 3555 else:
3497 3556 for n in opts[b'show_stage']:
3498 3557 if n not in stagenames:
3499 3558 raise error.Abort(_(b'invalid stage name: %s') % n)
3500 3559 showalways.update(opts[b'show_stage'])
3501 3560
3502 3561 treebystage = {}
3503 3562 printedtree = None
3504 3563 tree = revsetlang.parse(expr, lookup=revset.lookupfn(repo))
3505 3564 for n, f in stages:
3506 3565 treebystage[n] = tree = f(tree)
3507 3566 if n in showalways or (n in showchanged and tree != printedtree):
3508 3567 if opts[b'show_stage'] or n != b'parsed':
3509 3568 ui.write(b"* %s:\n" % n)
3510 3569 ui.write(revsetlang.prettyformat(tree), b"\n")
3511 3570 printedtree = tree
3512 3571
3513 3572 if opts[b'verify_optimized']:
3514 3573 arevs = revset.makematcher(treebystage[b'analyzed'])(repo)
3515 3574 brevs = revset.makematcher(treebystage[b'optimized'])(repo)
3516 3575 if opts[b'show_set'] or (opts[b'show_set'] is None and ui.verbose):
3517 3576 ui.writenoi18n(
3518 3577 b"* analyzed set:\n", stringutil.prettyrepr(arevs), b"\n"
3519 3578 )
3520 3579 ui.writenoi18n(
3521 3580 b"* optimized set:\n", stringutil.prettyrepr(brevs), b"\n"
3522 3581 )
3523 3582 arevs = list(arevs)
3524 3583 brevs = list(brevs)
3525 3584 if arevs == brevs:
3526 3585 return 0
3527 3586 ui.writenoi18n(b'--- analyzed\n', label=b'diff.file_a')
3528 3587 ui.writenoi18n(b'+++ optimized\n', label=b'diff.file_b')
3529 3588 sm = difflib.SequenceMatcher(None, arevs, brevs)
3530 3589 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3531 3590 if tag in ('delete', 'replace'):
3532 3591 for c in arevs[alo:ahi]:
3533 3592 ui.write(b'-%d\n' % c, label=b'diff.deleted')
3534 3593 if tag in ('insert', 'replace'):
3535 3594 for c in brevs[blo:bhi]:
3536 3595 ui.write(b'+%d\n' % c, label=b'diff.inserted')
3537 3596 if tag == 'equal':
3538 3597 for c in arevs[alo:ahi]:
3539 3598 ui.write(b' %d\n' % c)
3540 3599 return 1
3541 3600
3542 3601 func = revset.makematcher(tree)
3543 3602 revs = func(repo)
3544 3603 if opts[b'show_set'] or (opts[b'show_set'] is None and ui.verbose):
3545 3604 ui.writenoi18n(b"* set:\n", stringutil.prettyrepr(revs), b"\n")
3546 3605 if not opts[b'show_revs']:
3547 3606 return
3548 3607 for c in revs:
3549 3608 ui.write(b"%d\n" % c)
3550 3609
3551 3610
3552 3611 @command(
3553 3612 b'debugserve',
3554 3613 [
3555 3614 (
3556 3615 b'',
3557 3616 b'sshstdio',
3558 3617 False,
3559 3618 _(b'run an SSH server bound to process handles'),
3560 3619 ),
3561 3620 (b'', b'logiofd', b'', _(b'file descriptor to log server I/O to')),
3562 3621 (b'', b'logiofile', b'', _(b'file to log server I/O to')),
3563 3622 ],
3564 3623 b'',
3565 3624 )
3566 3625 def debugserve(ui, repo, **opts):
3567 3626 """run a server with advanced settings
3568 3627
3569 3628 This command is similar to :hg:`serve`. It exists partially as a
3570 3629 workaround to the fact that ``hg serve --stdio`` must have specific
3571 3630 arguments for security reasons.
3572 3631 """
3573 3632 opts = pycompat.byteskwargs(opts)
3574 3633
3575 3634 if not opts[b'sshstdio']:
3576 3635 raise error.Abort(_(b'only --sshstdio is currently supported'))
3577 3636
3578 3637 logfh = None
3579 3638
3580 3639 if opts[b'logiofd'] and opts[b'logiofile']:
3581 3640 raise error.Abort(_(b'cannot use both --logiofd and --logiofile'))
3582 3641
3583 3642 if opts[b'logiofd']:
3584 3643 # Ideally we would be line buffered. But line buffering in binary
3585 3644 # mode isn't supported and emits a warning in Python 3.8+. Disabling
3586 3645 # buffering could have performance impacts. But since this isn't
3587 3646 # performance critical code, it should be fine.
3588 3647 try:
3589 3648 logfh = os.fdopen(int(opts[b'logiofd']), 'ab', 0)
3590 3649 except OSError as e:
3591 3650 if e.errno != errno.ESPIPE:
3592 3651 raise
3593 3652 # can't seek a pipe, so `ab` mode fails on py3
3594 3653 logfh = os.fdopen(int(opts[b'logiofd']), 'wb', 0)
3595 3654 elif opts[b'logiofile']:
3596 3655 logfh = open(opts[b'logiofile'], b'ab', 0)
3597 3656
3598 3657 s = wireprotoserver.sshserver(ui, repo, logfh=logfh)
3599 3658 s.serve_forever()
3600 3659
3601 3660
3602 3661 @command(b'debugsetparents', [], _(b'REV1 [REV2]'))
3603 3662 def debugsetparents(ui, repo, rev1, rev2=None):
3604 3663 """manually set the parents of the current working directory (DANGEROUS)
3605 3664
3606 3665 This command is not what you are looking for and should not be used. Using
3607 3666 this command will most certainly results in slight corruption of the file
3608 3667 level histories withing your repository. DO NOT USE THIS COMMAND.
3609 3668
3610 3669 The command update the p1 and p2 field in the dirstate, and not touching
3611 3670 anything else. This useful for writing repository conversion tools, but
3612 3671 should be used with extreme care. For example, neither the working
3613 3672 directory nor the dirstate is updated, so file status may be incorrect
3614 3673 after running this command. Only used if you are one of the few people that
3615 3674 deeply unstand both conversion tools and file level histories. If you are
3616 3675 reading this help, you are not one of this people (most of them sailed west
3617 3676 from Mithlond anyway.
3618 3677
3619 3678 So one last time DO NOT USE THIS COMMAND.
3620 3679
3621 3680 Returns 0 on success.
3622 3681 """
3623 3682
3624 3683 node1 = scmutil.revsingle(repo, rev1).node()
3625 3684 node2 = scmutil.revsingle(repo, rev2, b'null').node()
3626 3685
3627 3686 with repo.wlock():
3628 3687 repo.setparents(node1, node2)
3629 3688
3630 3689
3631 3690 @command(b'debugsidedata', cmdutil.debugrevlogopts, _(b'-c|-m|FILE REV'))
3632 3691 def debugsidedata(ui, repo, file_, rev=None, **opts):
3633 3692 """dump the side data for a cl/manifest/file revision
3634 3693
3635 3694 Use --verbose to dump the sidedata content."""
3636 3695 opts = pycompat.byteskwargs(opts)
3637 3696 if opts.get(b'changelog') or opts.get(b'manifest') or opts.get(b'dir'):
3638 3697 if rev is not None:
3639 3698 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
3640 3699 file_, rev = None, file_
3641 3700 elif rev is None:
3642 3701 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
3643 3702 r = cmdutil.openstorage(repo, b'debugdata', file_, opts)
3644 3703 r = getattr(r, '_revlog', r)
3645 3704 try:
3646 3705 sidedata = r.sidedata(r.lookup(rev))
3647 3706 except KeyError:
3648 3707 raise error.Abort(_(b'invalid revision identifier %s') % rev)
3649 3708 if sidedata:
3650 3709 sidedata = list(sidedata.items())
3651 3710 sidedata.sort()
3652 3711 ui.writenoi18n(b'%d sidedata entries\n' % len(sidedata))
3653 3712 for key, value in sidedata:
3654 3713 ui.writenoi18n(b' entry-%04o size %d\n' % (key, len(value)))
3655 3714 if ui.verbose:
3656 3715 ui.writenoi18n(b' %s\n' % stringutil.pprint(value))
3657 3716
3658 3717
3659 3718 @command(b'debugssl', [], b'[SOURCE]', optionalrepo=True)
3660 3719 def debugssl(ui, repo, source=None, **opts):
3661 3720 """test a secure connection to a server
3662 3721
3663 3722 This builds the certificate chain for the server on Windows, installing the
3664 3723 missing intermediates and trusted root via Windows Update if necessary. It
3665 3724 does nothing on other platforms.
3666 3725
3667 3726 If SOURCE is omitted, the 'default' path will be used. If a URL is given,
3668 3727 that server is used. See :hg:`help urls` for more information.
3669 3728
3670 3729 If the update succeeds, retry the original operation. Otherwise, the cause
3671 3730 of the SSL error is likely another issue.
3672 3731 """
3673 3732 if not pycompat.iswindows:
3674 3733 raise error.Abort(
3675 3734 _(b'certificate chain building is only possible on Windows')
3676 3735 )
3677 3736
3678 3737 if not source:
3679 3738 if not repo:
3680 3739 raise error.Abort(
3681 3740 _(
3682 3741 b"there is no Mercurial repository here, and no "
3683 3742 b"server specified"
3684 3743 )
3685 3744 )
3686 3745 source = b"default"
3687 3746
3688 3747 source, branches = urlutil.get_unique_pull_path(
3689 3748 b'debugssl', repo, ui, source
3690 3749 )
3691 3750 url = urlutil.url(source)
3692 3751
3693 3752 defaultport = {b'https': 443, b'ssh': 22}
3694 3753 if url.scheme in defaultport:
3695 3754 try:
3696 3755 addr = (url.host, int(url.port or defaultport[url.scheme]))
3697 3756 except ValueError:
3698 3757 raise error.Abort(_(b"malformed port number in URL"))
3699 3758 else:
3700 3759 raise error.Abort(_(b"only https and ssh connections are supported"))
3701 3760
3702 3761 from . import win32
3703 3762
3704 3763 s = ssl.wrap_socket(
3705 3764 socket.socket(),
3706 3765 ssl_version=ssl.PROTOCOL_TLS,
3707 3766 cert_reqs=ssl.CERT_NONE,
3708 3767 ca_certs=None,
3709 3768 )
3710 3769
3711 3770 try:
3712 3771 s.connect(addr)
3713 3772 cert = s.getpeercert(True)
3714 3773
3715 3774 ui.status(_(b'checking the certificate chain for %s\n') % url.host)
3716 3775
3717 3776 complete = win32.checkcertificatechain(cert, build=False)
3718 3777
3719 3778 if not complete:
3720 3779 ui.status(_(b'certificate chain is incomplete, updating... '))
3721 3780
3722 3781 if not win32.checkcertificatechain(cert):
3723 3782 ui.status(_(b'failed.\n'))
3724 3783 else:
3725 3784 ui.status(_(b'done.\n'))
3726 3785 else:
3727 3786 ui.status(_(b'full certificate chain is available\n'))
3728 3787 finally:
3729 3788 s.close()
3730 3789
3731 3790
3732 3791 @command(
3733 3792 b"debugbackupbundle",
3734 3793 [
3735 3794 (
3736 3795 b"",
3737 3796 b"recover",
3738 3797 b"",
3739 3798 b"brings the specified changeset back into the repository",
3740 3799 )
3741 3800 ]
3742 3801 + cmdutil.logopts,
3743 3802 _(b"hg debugbackupbundle [--recover HASH]"),
3744 3803 )
3745 3804 def debugbackupbundle(ui, repo, *pats, **opts):
3746 3805 """lists the changesets available in backup bundles
3747 3806
3748 3807 Without any arguments, this command prints a list of the changesets in each
3749 3808 backup bundle.
3750 3809
3751 3810 --recover takes a changeset hash and unbundles the first bundle that
3752 3811 contains that hash, which puts that changeset back in your repository.
3753 3812
3754 3813 --verbose will print the entire commit message and the bundle path for that
3755 3814 backup.
3756 3815 """
3757 3816 backups = list(
3758 3817 filter(
3759 3818 os.path.isfile, glob.glob(repo.vfs.join(b"strip-backup") + b"/*.hg")
3760 3819 )
3761 3820 )
3762 3821 backups.sort(key=lambda x: os.path.getmtime(x), reverse=True)
3763 3822
3764 3823 opts = pycompat.byteskwargs(opts)
3765 3824 opts[b"bundle"] = b""
3766 3825 opts[b"force"] = None
3767 3826 limit = logcmdutil.getlimit(opts)
3768 3827
3769 3828 def display(other, chlist, displayer):
3770 3829 if opts.get(b"newest_first"):
3771 3830 chlist.reverse()
3772 3831 count = 0
3773 3832 for n in chlist:
3774 3833 if limit is not None and count >= limit:
3775 3834 break
3776 3835 parents = [
3777 3836 True for p in other.changelog.parents(n) if p != repo.nullid
3778 3837 ]
3779 3838 if opts.get(b"no_merges") and len(parents) == 2:
3780 3839 continue
3781 3840 count += 1
3782 3841 displayer.show(other[n])
3783 3842
3784 3843 recovernode = opts.get(b"recover")
3785 3844 if recovernode:
3786 3845 if scmutil.isrevsymbol(repo, recovernode):
3787 3846 ui.warn(_(b"%s already exists in the repo\n") % recovernode)
3788 3847 return
3789 3848 elif backups:
3790 3849 msg = _(
3791 3850 b"Recover changesets using: hg debugbackupbundle --recover "
3792 3851 b"<changeset hash>\n\nAvailable backup changesets:"
3793 3852 )
3794 3853 ui.status(msg, label=b"status.removed")
3795 3854 else:
3796 3855 ui.status(_(b"no backup changesets found\n"))
3797 3856 return
3798 3857
3799 3858 for backup in backups:
3800 3859 # Much of this is copied from the hg incoming logic
3801 3860 source = os.path.relpath(backup, encoding.getcwd())
3802 3861 source, branches = urlutil.get_unique_pull_path(
3803 3862 b'debugbackupbundle',
3804 3863 repo,
3805 3864 ui,
3806 3865 source,
3807 3866 default_branches=opts.get(b'branch'),
3808 3867 )
3809 3868 try:
3810 3869 other = hg.peer(repo, opts, source)
3811 3870 except error.LookupError as ex:
3812 3871 msg = _(b"\nwarning: unable to open bundle %s") % source
3813 3872 hint = _(b"\n(missing parent rev %s)\n") % short(ex.name)
3814 3873 ui.warn(msg, hint=hint)
3815 3874 continue
3816 3875 revs, checkout = hg.addbranchrevs(
3817 3876 repo, other, branches, opts.get(b"rev")
3818 3877 )
3819 3878
3820 3879 if revs:
3821 3880 revs = [other.lookup(rev) for rev in revs]
3822 3881
3823 3882 with ui.silent():
3824 3883 try:
3825 3884 other, chlist, cleanupfn = bundlerepo.getremotechanges(
3826 3885 ui, repo, other, revs, opts[b"bundle"], opts[b"force"]
3827 3886 )
3828 3887 except error.LookupError:
3829 3888 continue
3830 3889
3831 3890 try:
3832 3891 if not chlist:
3833 3892 continue
3834 3893 if recovernode:
3835 3894 with repo.lock(), repo.transaction(b"unbundle") as tr:
3836 3895 if scmutil.isrevsymbol(other, recovernode):
3837 3896 ui.status(_(b"Unbundling %s\n") % (recovernode))
3838 3897 f = hg.openpath(ui, source)
3839 3898 gen = exchange.readbundle(ui, f, source)
3840 3899 if isinstance(gen, bundle2.unbundle20):
3841 3900 bundle2.applybundle(
3842 3901 repo,
3843 3902 gen,
3844 3903 tr,
3845 3904 source=b"unbundle",
3846 3905 url=b"bundle:" + source,
3847 3906 )
3848 3907 else:
3849 3908 gen.apply(repo, b"unbundle", b"bundle:" + source)
3850 3909 break
3851 3910 else:
3852 3911 backupdate = encoding.strtolocal(
3853 3912 time.strftime(
3854 3913 "%a %H:%M, %Y-%m-%d",
3855 3914 time.localtime(os.path.getmtime(source)),
3856 3915 )
3857 3916 )
3858 3917 ui.status(b"\n%s\n" % (backupdate.ljust(50)))
3859 3918 if ui.verbose:
3860 3919 ui.status(b"%s%s\n" % (b"bundle:".ljust(13), source))
3861 3920 else:
3862 3921 opts[
3863 3922 b"template"
3864 3923 ] = b"{label('status.modified', node|short)} {desc|firstline}\n"
3865 3924 displayer = logcmdutil.changesetdisplayer(
3866 3925 ui, other, opts, False
3867 3926 )
3868 3927 display(other, chlist, displayer)
3869 3928 displayer.close()
3870 3929 finally:
3871 3930 cleanupfn()
3872 3931
3873 3932
3874 3933 @command(
3875 3934 b'debugsub',
3876 3935 [(b'r', b'rev', b'', _(b'revision to check'), _(b'REV'))],
3877 3936 _(b'[-r REV] [REV]'),
3878 3937 )
3879 3938 def debugsub(ui, repo, rev=None):
3880 3939 ctx = scmutil.revsingle(repo, rev, None)
3881 3940 for k, v in sorted(ctx.substate.items()):
3882 3941 ui.writenoi18n(b'path %s\n' % k)
3883 3942 ui.writenoi18n(b' source %s\n' % v[0])
3884 3943 ui.writenoi18n(b' revision %s\n' % v[1])
3885 3944
3886 3945
3887 3946 @command(b'debugshell', optionalrepo=True)
3888 3947 def debugshell(ui, repo):
3889 3948 """run an interactive Python interpreter
3890 3949
3891 3950 The local namespace is provided with a reference to the ui and
3892 3951 the repo instance (if available).
3893 3952 """
3894 3953 import code
3895 3954
3896 3955 imported_objects = {
3897 3956 'ui': ui,
3898 3957 'repo': repo,
3899 3958 }
3900 3959
3901 3960 code.interact(local=imported_objects)
3902 3961
3903 3962
3904 3963 @command(
3905 3964 b'debugsuccessorssets',
3906 3965 [(b'', b'closest', False, _(b'return closest successors sets only'))],
3907 3966 _(b'[REV]'),
3908 3967 )
3909 3968 def debugsuccessorssets(ui, repo, *revs, **opts):
3910 3969 """show set of successors for revision
3911 3970
3912 3971 A successors set of changeset A is a consistent group of revisions that
3913 3972 succeed A. It contains non-obsolete changesets only unless closests
3914 3973 successors set is set.
3915 3974
3916 3975 In most cases a changeset A has a single successors set containing a single
3917 3976 successor (changeset A replaced by A').
3918 3977
3919 3978 A changeset that is made obsolete with no successors are called "pruned".
3920 3979 Such changesets have no successors sets at all.
3921 3980
3922 3981 A changeset that has been "split" will have a successors set containing
3923 3982 more than one successor.
3924 3983
3925 3984 A changeset that has been rewritten in multiple different ways is called
3926 3985 "divergent". Such changesets have multiple successor sets (each of which
3927 3986 may also be split, i.e. have multiple successors).
3928 3987
3929 3988 Results are displayed as follows::
3930 3989
3931 3990 <rev1>
3932 3991 <successors-1A>
3933 3992 <rev2>
3934 3993 <successors-2A>
3935 3994 <successors-2B1> <successors-2B2> <successors-2B3>
3936 3995
3937 3996 Here rev2 has two possible (i.e. divergent) successors sets. The first
3938 3997 holds one element, whereas the second holds three (i.e. the changeset has
3939 3998 been split).
3940 3999 """
3941 4000 # passed to successorssets caching computation from one call to another
3942 4001 cache = {}
3943 4002 ctx2str = bytes
3944 4003 node2str = short
3945 4004 for rev in scmutil.revrange(repo, revs):
3946 4005 ctx = repo[rev]
3947 4006 ui.write(b'%s\n' % ctx2str(ctx))
3948 4007 for succsset in obsutil.successorssets(
3949 4008 repo, ctx.node(), closest=opts['closest'], cache=cache
3950 4009 ):
3951 4010 if succsset:
3952 4011 ui.write(b' ')
3953 4012 ui.write(node2str(succsset[0]))
3954 4013 for node in succsset[1:]:
3955 4014 ui.write(b' ')
3956 4015 ui.write(node2str(node))
3957 4016 ui.write(b'\n')
3958 4017
3959 4018
3960 4019 @command(b'debugtagscache', [])
3961 4020 def debugtagscache(ui, repo):
3962 4021 """display the contents of .hg/cache/hgtagsfnodes1"""
3963 4022 cache = tagsmod.hgtagsfnodescache(repo.unfiltered())
3964 4023 flog = repo.file(b'.hgtags')
3965 4024 for r in repo:
3966 4025 node = repo[r].node()
3967 4026 tagsnode = cache.getfnode(node, computemissing=False)
3968 4027 if tagsnode:
3969 4028 tagsnodedisplay = hex(tagsnode)
3970 4029 if not flog.hasnode(tagsnode):
3971 4030 tagsnodedisplay += b' (unknown node)'
3972 4031 elif tagsnode is None:
3973 4032 tagsnodedisplay = b'missing'
3974 4033 else:
3975 4034 tagsnodedisplay = b'invalid'
3976 4035
3977 4036 ui.write(b'%d %s %s\n' % (r, hex(node), tagsnodedisplay))
3978 4037
3979 4038
3980 4039 @command(
3981 4040 b'debugtemplate',
3982 4041 [
3983 4042 (b'r', b'rev', [], _(b'apply template on changesets'), _(b'REV')),
3984 4043 (b'D', b'define', [], _(b'define template keyword'), _(b'KEY=VALUE')),
3985 4044 ],
3986 4045 _(b'[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3987 4046 optionalrepo=True,
3988 4047 )
3989 4048 def debugtemplate(ui, repo, tmpl, **opts):
3990 4049 """parse and apply a template
3991 4050
3992 4051 If -r/--rev is given, the template is processed as a log template and
3993 4052 applied to the given changesets. Otherwise, it is processed as a generic
3994 4053 template.
3995 4054
3996 4055 Use --verbose to print the parsed tree.
3997 4056 """
3998 4057 revs = None
3999 4058 if opts['rev']:
4000 4059 if repo is None:
4001 4060 raise error.RepoError(
4002 4061 _(b'there is no Mercurial repository here (.hg not found)')
4003 4062 )
4004 4063 revs = scmutil.revrange(repo, opts['rev'])
4005 4064
4006 4065 props = {}
4007 4066 for d in opts['define']:
4008 4067 try:
4009 4068 k, v = (e.strip() for e in d.split(b'=', 1))
4010 4069 if not k or k == b'ui':
4011 4070 raise ValueError
4012 4071 props[k] = v
4013 4072 except ValueError:
4014 4073 raise error.Abort(_(b'malformed keyword definition: %s') % d)
4015 4074
4016 4075 if ui.verbose:
4017 4076 aliases = ui.configitems(b'templatealias')
4018 4077 tree = templater.parse(tmpl)
4019 4078 ui.note(templater.prettyformat(tree), b'\n')
4020 4079 newtree = templater.expandaliases(tree, aliases)
4021 4080 if newtree != tree:
4022 4081 ui.notenoi18n(
4023 4082 b"* expanded:\n", templater.prettyformat(newtree), b'\n'
4024 4083 )
4025 4084
4026 4085 if revs is None:
4027 4086 tres = formatter.templateresources(ui, repo)
4028 4087 t = formatter.maketemplater(ui, tmpl, resources=tres)
4029 4088 if ui.verbose:
4030 4089 kwds, funcs = t.symbolsuseddefault()
4031 4090 ui.writenoi18n(b"* keywords: %s\n" % b', '.join(sorted(kwds)))
4032 4091 ui.writenoi18n(b"* functions: %s\n" % b', '.join(sorted(funcs)))
4033 4092 ui.write(t.renderdefault(props))
4034 4093 else:
4035 4094 displayer = logcmdutil.maketemplater(ui, repo, tmpl)
4036 4095 if ui.verbose:
4037 4096 kwds, funcs = displayer.t.symbolsuseddefault()
4038 4097 ui.writenoi18n(b"* keywords: %s\n" % b', '.join(sorted(kwds)))
4039 4098 ui.writenoi18n(b"* functions: %s\n" % b', '.join(sorted(funcs)))
4040 4099 for r in revs:
4041 4100 displayer.show(repo[r], **pycompat.strkwargs(props))
4042 4101 displayer.close()
4043 4102
4044 4103
4045 4104 @command(
4046 4105 b'debuguigetpass',
4047 4106 [
4048 4107 (b'p', b'prompt', b'', _(b'prompt text'), _(b'TEXT')),
4049 4108 ],
4050 4109 _(b'[-p TEXT]'),
4051 4110 norepo=True,
4052 4111 )
4053 4112 def debuguigetpass(ui, prompt=b''):
4054 4113 """show prompt to type password"""
4055 4114 r = ui.getpass(prompt)
4056 4115 if r is None:
4057 4116 r = b"<default response>"
4058 4117 ui.writenoi18n(b'response: %s\n' % r)
4059 4118
4060 4119
4061 4120 @command(
4062 4121 b'debuguiprompt',
4063 4122 [
4064 4123 (b'p', b'prompt', b'', _(b'prompt text'), _(b'TEXT')),
4065 4124 ],
4066 4125 _(b'[-p TEXT]'),
4067 4126 norepo=True,
4068 4127 )
4069 4128 def debuguiprompt(ui, prompt=b''):
4070 4129 """show plain prompt"""
4071 4130 r = ui.prompt(prompt)
4072 4131 ui.writenoi18n(b'response: %s\n' % r)
4073 4132
4074 4133
4075 4134 @command(b'debugupdatecaches', [])
4076 4135 def debugupdatecaches(ui, repo, *pats, **opts):
4077 4136 """warm all known caches in the repository"""
4078 4137 with repo.wlock(), repo.lock():
4079 4138 repo.updatecaches(caches=repository.CACHES_ALL)
4080 4139
4081 4140
4082 4141 @command(
4083 4142 b'debugupgraderepo',
4084 4143 [
4085 4144 (
4086 4145 b'o',
4087 4146 b'optimize',
4088 4147 [],
4089 4148 _(b'extra optimization to perform'),
4090 4149 _(b'NAME'),
4091 4150 ),
4092 4151 (b'', b'run', False, _(b'performs an upgrade')),
4093 4152 (b'', b'backup', True, _(b'keep the old repository content around')),
4094 4153 (b'', b'changelog', None, _(b'select the changelog for upgrade')),
4095 4154 (b'', b'manifest', None, _(b'select the manifest for upgrade')),
4096 4155 (b'', b'filelogs', None, _(b'select all filelogs for upgrade')),
4097 4156 ],
4098 4157 )
4099 4158 def debugupgraderepo(ui, repo, run=False, optimize=None, backup=True, **opts):
4100 4159 """upgrade a repository to use different features
4101 4160
4102 4161 If no arguments are specified, the repository is evaluated for upgrade
4103 4162 and a list of problems and potential optimizations is printed.
4104 4163
4105 4164 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
4106 4165 can be influenced via additional arguments. More details will be provided
4107 4166 by the command output when run without ``--run``.
4108 4167
4109 4168 During the upgrade, the repository will be locked and no writes will be
4110 4169 allowed.
4111 4170
4112 4171 At the end of the upgrade, the repository may not be readable while new
4113 4172 repository data is swapped in. This window will be as long as it takes to
4114 4173 rename some directories inside the ``.hg`` directory. On most machines, this
4115 4174 should complete almost instantaneously and the chances of a consumer being
4116 4175 unable to access the repository should be low.
4117 4176
4118 4177 By default, all revlogs will be upgraded. You can restrict this using flags
4119 4178 such as `--manifest`:
4120 4179
4121 4180 * `--manifest`: only optimize the manifest
4122 4181 * `--no-manifest`: optimize all revlog but the manifest
4123 4182 * `--changelog`: optimize the changelog only
4124 4183 * `--no-changelog --no-manifest`: optimize filelogs only
4125 4184 * `--filelogs`: optimize the filelogs only
4126 4185 * `--no-changelog --no-manifest --no-filelogs`: skip all revlog optimizations
4127 4186 """
4128 4187 return upgrade.upgraderepo(
4129 4188 ui, repo, run=run, optimize=set(optimize), backup=backup, **opts
4130 4189 )
4131 4190
4132 4191
4133 4192 @command(
4134 4193 b'debugwalk', cmdutil.walkopts, _(b'[OPTION]... [FILE]...'), inferrepo=True
4135 4194 )
4136 4195 def debugwalk(ui, repo, *pats, **opts):
4137 4196 """show how files match on given patterns"""
4138 4197 opts = pycompat.byteskwargs(opts)
4139 4198 m = scmutil.match(repo[None], pats, opts)
4140 4199 if ui.verbose:
4141 4200 ui.writenoi18n(b'* matcher:\n', stringutil.prettyrepr(m), b'\n')
4142 4201 items = list(repo[None].walk(m))
4143 4202 if not items:
4144 4203 return
4145 4204 f = lambda fn: fn
4146 4205 if ui.configbool(b'ui', b'slash') and pycompat.ossep != b'/':
4147 4206 f = lambda fn: util.normpath(fn)
4148 4207 fmt = b'f %%-%ds %%-%ds %%s' % (
4149 4208 max([len(abs) for abs in items]),
4150 4209 max([len(repo.pathto(abs)) for abs in items]),
4151 4210 )
4152 4211 for abs in items:
4153 4212 line = fmt % (
4154 4213 abs,
4155 4214 f(repo.pathto(abs)),
4156 4215 m.exact(abs) and b'exact' or b'',
4157 4216 )
4158 4217 ui.write(b"%s\n" % line.rstrip())
4159 4218
4160 4219
4161 4220 @command(b'debugwhyunstable', [], _(b'REV'))
4162 4221 def debugwhyunstable(ui, repo, rev):
4163 4222 """explain instabilities of a changeset"""
4164 4223 for entry in obsutil.whyunstable(repo, scmutil.revsingle(repo, rev)):
4165 4224 dnodes = b''
4166 4225 if entry.get(b'divergentnodes'):
4167 4226 dnodes = (
4168 4227 b' '.join(
4169 4228 b'%s (%s)' % (ctx.hex(), ctx.phasestr())
4170 4229 for ctx in entry[b'divergentnodes']
4171 4230 )
4172 4231 + b' '
4173 4232 )
4174 4233 ui.write(
4175 4234 b'%s: %s%s %s\n'
4176 4235 % (entry[b'instability'], dnodes, entry[b'reason'], entry[b'node'])
4177 4236 )
4178 4237
4179 4238
4180 4239 @command(
4181 4240 b'debugwireargs',
4182 4241 [
4183 4242 (b'', b'three', b'', b'three'),
4184 4243 (b'', b'four', b'', b'four'),
4185 4244 (b'', b'five', b'', b'five'),
4186 4245 ]
4187 4246 + cmdutil.remoteopts,
4188 4247 _(b'REPO [OPTIONS]... [ONE [TWO]]'),
4189 4248 norepo=True,
4190 4249 )
4191 4250 def debugwireargs(ui, repopath, *vals, **opts):
4192 4251 opts = pycompat.byteskwargs(opts)
4193 4252 repo = hg.peer(ui, opts, repopath)
4194 4253 try:
4195 4254 for opt in cmdutil.remoteopts:
4196 4255 del opts[opt[1]]
4197 4256 args = {}
4198 4257 for k, v in pycompat.iteritems(opts):
4199 4258 if v:
4200 4259 args[k] = v
4201 4260 args = pycompat.strkwargs(args)
4202 4261 # run twice to check that we don't mess up the stream for the next command
4203 4262 res1 = repo.debugwireargs(*vals, **args)
4204 4263 res2 = repo.debugwireargs(*vals, **args)
4205 4264 ui.write(b"%s\n" % res1)
4206 4265 if res1 != res2:
4207 4266 ui.warn(b"%s\n" % res2)
4208 4267 finally:
4209 4268 repo.close()
4210 4269
4211 4270
4212 4271 def _parsewirelangblocks(fh):
4213 4272 activeaction = None
4214 4273 blocklines = []
4215 4274 lastindent = 0
4216 4275
4217 4276 for line in fh:
4218 4277 line = line.rstrip()
4219 4278 if not line:
4220 4279 continue
4221 4280
4222 4281 if line.startswith(b'#'):
4223 4282 continue
4224 4283
4225 4284 if not line.startswith(b' '):
4226 4285 # New block. Flush previous one.
4227 4286 if activeaction:
4228 4287 yield activeaction, blocklines
4229 4288
4230 4289 activeaction = line
4231 4290 blocklines = []
4232 4291 lastindent = 0
4233 4292 continue
4234 4293
4235 4294 # Else we start with an indent.
4236 4295
4237 4296 if not activeaction:
4238 4297 raise error.Abort(_(b'indented line outside of block'))
4239 4298
4240 4299 indent = len(line) - len(line.lstrip())
4241 4300
4242 4301 # If this line is indented more than the last line, concatenate it.
4243 4302 if indent > lastindent and blocklines:
4244 4303 blocklines[-1] += line.lstrip()
4245 4304 else:
4246 4305 blocklines.append(line)
4247 4306 lastindent = indent
4248 4307
4249 4308 # Flush last block.
4250 4309 if activeaction:
4251 4310 yield activeaction, blocklines
4252 4311
4253 4312
4254 4313 @command(
4255 4314 b'debugwireproto',
4256 4315 [
4257 4316 (b'', b'localssh', False, _(b'start an SSH server for this repo')),
4258 4317 (b'', b'peer', b'', _(b'construct a specific version of the peer')),
4259 4318 (
4260 4319 b'',
4261 4320 b'noreadstderr',
4262 4321 False,
4263 4322 _(b'do not read from stderr of the remote'),
4264 4323 ),
4265 4324 (
4266 4325 b'',
4267 4326 b'nologhandshake',
4268 4327 False,
4269 4328 _(b'do not log I/O related to the peer handshake'),
4270 4329 ),
4271 4330 ]
4272 4331 + cmdutil.remoteopts,
4273 4332 _(b'[PATH]'),
4274 4333 optionalrepo=True,
4275 4334 )
4276 4335 def debugwireproto(ui, repo, path=None, **opts):
4277 4336 """send wire protocol commands to a server
4278 4337
4279 4338 This command can be used to issue wire protocol commands to remote
4280 4339 peers and to debug the raw data being exchanged.
4281 4340
4282 4341 ``--localssh`` will start an SSH server against the current repository
4283 4342 and connect to that. By default, the connection will perform a handshake
4284 4343 and establish an appropriate peer instance.
4285 4344
4286 4345 ``--peer`` can be used to bypass the handshake protocol and construct a
4287 4346 peer instance using the specified class type. Valid values are ``raw``,
4288 4347 ``http2``, ``ssh1``, and ``ssh2``. ``raw`` instances only allow sending
4289 4348 raw data payloads and don't support higher-level command actions.
4290 4349
4291 4350 ``--noreadstderr`` can be used to disable automatic reading from stderr
4292 4351 of the peer (for SSH connections only). Disabling automatic reading of
4293 4352 stderr is useful for making output more deterministic.
4294 4353
4295 4354 Commands are issued via a mini language which is specified via stdin.
4296 4355 The language consists of individual actions to perform. An action is
4297 4356 defined by a block. A block is defined as a line with no leading
4298 4357 space followed by 0 or more lines with leading space. Blocks are
4299 4358 effectively a high-level command with additional metadata.
4300 4359
4301 4360 Lines beginning with ``#`` are ignored.
4302 4361
4303 4362 The following sections denote available actions.
4304 4363
4305 4364 raw
4306 4365 ---
4307 4366
4308 4367 Send raw data to the server.
4309 4368
4310 4369 The block payload contains the raw data to send as one atomic send
4311 4370 operation. The data may not actually be delivered in a single system
4312 4371 call: it depends on the abilities of the transport being used.
4313 4372
4314 4373 Each line in the block is de-indented and concatenated. Then, that
4315 4374 value is evaluated as a Python b'' literal. This allows the use of
4316 4375 backslash escaping, etc.
4317 4376
4318 4377 raw+
4319 4378 ----
4320 4379
4321 4380 Behaves like ``raw`` except flushes output afterwards.
4322 4381
4323 4382 command <X>
4324 4383 -----------
4325 4384
4326 4385 Send a request to run a named command, whose name follows the ``command``
4327 4386 string.
4328 4387
4329 4388 Arguments to the command are defined as lines in this block. The format of
4330 4389 each line is ``<key> <value>``. e.g.::
4331 4390
4332 4391 command listkeys
4333 4392 namespace bookmarks
4334 4393
4335 4394 If the value begins with ``eval:``, it will be interpreted as a Python
4336 4395 literal expression. Otherwise values are interpreted as Python b'' literals.
4337 4396 This allows sending complex types and encoding special byte sequences via
4338 4397 backslash escaping.
4339 4398
4340 4399 The following arguments have special meaning:
4341 4400
4342 4401 ``PUSHFILE``
4343 4402 When defined, the *push* mechanism of the peer will be used instead
4344 4403 of the static request-response mechanism and the content of the
4345 4404 file specified in the value of this argument will be sent as the
4346 4405 command payload.
4347 4406
4348 4407 This can be used to submit a local bundle file to the remote.
4349 4408
4350 4409 batchbegin
4351 4410 ----------
4352 4411
4353 4412 Instruct the peer to begin a batched send.
4354 4413
4355 4414 All ``command`` blocks are queued for execution until the next
4356 4415 ``batchsubmit`` block.
4357 4416
4358 4417 batchsubmit
4359 4418 -----------
4360 4419
4361 4420 Submit previously queued ``command`` blocks as a batch request.
4362 4421
4363 4422 This action MUST be paired with a ``batchbegin`` action.
4364 4423
4365 4424 httprequest <method> <path>
4366 4425 ---------------------------
4367 4426
4368 4427 (HTTP peer only)
4369 4428
4370 4429 Send an HTTP request to the peer.
4371 4430
4372 4431 The HTTP request line follows the ``httprequest`` action. e.g. ``GET /foo``.
4373 4432
4374 4433 Arguments of the form ``<key>: <value>`` are interpreted as HTTP request
4375 4434 headers to add to the request. e.g. ``Accept: foo``.
4376 4435
4377 4436 The following arguments are special:
4378 4437
4379 4438 ``BODYFILE``
4380 4439 The content of the file defined as the value to this argument will be
4381 4440 transferred verbatim as the HTTP request body.
4382 4441
4383 4442 ``frame <type> <flags> <payload>``
4384 4443 Send a unified protocol frame as part of the request body.
4385 4444
4386 4445 All frames will be collected and sent as the body to the HTTP
4387 4446 request.
4388 4447
4389 4448 close
4390 4449 -----
4391 4450
4392 4451 Close the connection to the server.
4393 4452
4394 4453 flush
4395 4454 -----
4396 4455
4397 4456 Flush data written to the server.
4398 4457
4399 4458 readavailable
4400 4459 -------------
4401 4460
4402 4461 Close the write end of the connection and read all available data from
4403 4462 the server.
4404 4463
4405 4464 If the connection to the server encompasses multiple pipes, we poll both
4406 4465 pipes and read available data.
4407 4466
4408 4467 readline
4409 4468 --------
4410 4469
4411 4470 Read a line of output from the server. If there are multiple output
4412 4471 pipes, reads only the main pipe.
4413 4472
4414 4473 ereadline
4415 4474 ---------
4416 4475
4417 4476 Like ``readline``, but read from the stderr pipe, if available.
4418 4477
4419 4478 read <X>
4420 4479 --------
4421 4480
4422 4481 ``read()`` N bytes from the server's main output pipe.
4423 4482
4424 4483 eread <X>
4425 4484 ---------
4426 4485
4427 4486 ``read()`` N bytes from the server's stderr pipe, if available.
4428 4487
4429 4488 Specifying Unified Frame-Based Protocol Frames
4430 4489 ----------------------------------------------
4431 4490
4432 4491 It is possible to emit a *Unified Frame-Based Protocol* by using special
4433 4492 syntax.
4434 4493
4435 4494 A frame is composed as a type, flags, and payload. These can be parsed
4436 4495 from a string of the form:
4437 4496
4438 4497 <request-id> <stream-id> <stream-flags> <type> <flags> <payload>
4439 4498
4440 4499 ``request-id`` and ``stream-id`` are integers defining the request and
4441 4500 stream identifiers.
4442 4501
4443 4502 ``type`` can be an integer value for the frame type or the string name
4444 4503 of the type. The strings are defined in ``wireprotoframing.py``. e.g.
4445 4504 ``command-name``.
4446 4505
4447 4506 ``stream-flags`` and ``flags`` are a ``|`` delimited list of flag
4448 4507 components. Each component (and there can be just one) can be an integer
4449 4508 or a flag name for stream flags or frame flags, respectively. Values are
4450 4509 resolved to integers and then bitwise OR'd together.
4451 4510
4452 4511 ``payload`` represents the raw frame payload. If it begins with
4453 4512 ``cbor:``, the following string is evaluated as Python code and the
4454 4513 resulting object is fed into a CBOR encoder. Otherwise it is interpreted
4455 4514 as a Python byte string literal.
4456 4515 """
4457 4516 opts = pycompat.byteskwargs(opts)
4458 4517
4459 4518 if opts[b'localssh'] and not repo:
4460 4519 raise error.Abort(_(b'--localssh requires a repository'))
4461 4520
4462 4521 if opts[b'peer'] and opts[b'peer'] not in (
4463 4522 b'raw',
4464 4523 b'http2',
4465 4524 b'ssh1',
4466 4525 b'ssh2',
4467 4526 ):
4468 4527 raise error.Abort(
4469 4528 _(b'invalid value for --peer'),
4470 4529 hint=_(b'valid values are "raw", "ssh1", and "ssh2"'),
4471 4530 )
4472 4531
4473 4532 if path and opts[b'localssh']:
4474 4533 raise error.Abort(_(b'cannot specify --localssh with an explicit path'))
4475 4534
4476 4535 if ui.interactive():
4477 4536 ui.write(_(b'(waiting for commands on stdin)\n'))
4478 4537
4479 4538 blocks = list(_parsewirelangblocks(ui.fin))
4480 4539
4481 4540 proc = None
4482 4541 stdin = None
4483 4542 stdout = None
4484 4543 stderr = None
4485 4544 opener = None
4486 4545
4487 4546 if opts[b'localssh']:
4488 4547 # We start the SSH server in its own process so there is process
4489 4548 # separation. This prevents a whole class of potential bugs around
4490 4549 # shared state from interfering with server operation.
4491 4550 args = procutil.hgcmd() + [
4492 4551 b'-R',
4493 4552 repo.root,
4494 4553 b'debugserve',
4495 4554 b'--sshstdio',
4496 4555 ]
4497 4556 proc = subprocess.Popen(
4498 4557 pycompat.rapply(procutil.tonativestr, args),
4499 4558 stdin=subprocess.PIPE,
4500 4559 stdout=subprocess.PIPE,
4501 4560 stderr=subprocess.PIPE,
4502 4561 bufsize=0,
4503 4562 )
4504 4563
4505 4564 stdin = proc.stdin
4506 4565 stdout = proc.stdout
4507 4566 stderr = proc.stderr
4508 4567
4509 4568 # We turn the pipes into observers so we can log I/O.
4510 4569 if ui.verbose or opts[b'peer'] == b'raw':
4511 4570 stdin = util.makeloggingfileobject(
4512 4571 ui, proc.stdin, b'i', logdata=True
4513 4572 )
4514 4573 stdout = util.makeloggingfileobject(
4515 4574 ui, proc.stdout, b'o', logdata=True
4516 4575 )
4517 4576 stderr = util.makeloggingfileobject(
4518 4577 ui, proc.stderr, b'e', logdata=True
4519 4578 )
4520 4579
4521 4580 # --localssh also implies the peer connection settings.
4522 4581
4523 4582 url = b'ssh://localserver'
4524 4583 autoreadstderr = not opts[b'noreadstderr']
4525 4584
4526 4585 if opts[b'peer'] == b'ssh1':
4527 4586 ui.write(_(b'creating ssh peer for wire protocol version 1\n'))
4528 4587 peer = sshpeer.sshv1peer(
4529 4588 ui,
4530 4589 url,
4531 4590 proc,
4532 4591 stdin,
4533 4592 stdout,
4534 4593 stderr,
4535 4594 None,
4536 4595 autoreadstderr=autoreadstderr,
4537 4596 )
4538 4597 elif opts[b'peer'] == b'ssh2':
4539 4598 ui.write(_(b'creating ssh peer for wire protocol version 2\n'))
4540 4599 peer = sshpeer.sshv2peer(
4541 4600 ui,
4542 4601 url,
4543 4602 proc,
4544 4603 stdin,
4545 4604 stdout,
4546 4605 stderr,
4547 4606 None,
4548 4607 autoreadstderr=autoreadstderr,
4549 4608 )
4550 4609 elif opts[b'peer'] == b'raw':
4551 4610 ui.write(_(b'using raw connection to peer\n'))
4552 4611 peer = None
4553 4612 else:
4554 4613 ui.write(_(b'creating ssh peer from handshake results\n'))
4555 4614 peer = sshpeer.makepeer(
4556 4615 ui,
4557 4616 url,
4558 4617 proc,
4559 4618 stdin,
4560 4619 stdout,
4561 4620 stderr,
4562 4621 autoreadstderr=autoreadstderr,
4563 4622 )
4564 4623
4565 4624 elif path:
4566 4625 # We bypass hg.peer() so we can proxy the sockets.
4567 4626 # TODO consider not doing this because we skip
4568 4627 # ``hg.wirepeersetupfuncs`` and potentially other useful functionality.
4569 4628 u = urlutil.url(path)
4570 4629 if u.scheme != b'http':
4571 4630 raise error.Abort(_(b'only http:// paths are currently supported'))
4572 4631
4573 4632 url, authinfo = u.authinfo()
4574 4633 openerargs = {
4575 4634 'useragent': b'Mercurial debugwireproto',
4576 4635 }
4577 4636
4578 4637 # Turn pipes/sockets into observers so we can log I/O.
4579 4638 if ui.verbose:
4580 4639 openerargs.update(
4581 4640 {
4582 4641 'loggingfh': ui,
4583 4642 'loggingname': b's',
4584 4643 'loggingopts': {
4585 4644 'logdata': True,
4586 4645 'logdataapis': False,
4587 4646 },
4588 4647 }
4589 4648 )
4590 4649
4591 4650 if ui.debugflag:
4592 4651 openerargs['loggingopts']['logdataapis'] = True
4593 4652
4594 4653 # Don't send default headers when in raw mode. This allows us to
4595 4654 # bypass most of the behavior of our URL handling code so we can
4596 4655 # have near complete control over what's sent on the wire.
4597 4656 if opts[b'peer'] == b'raw':
4598 4657 openerargs['sendaccept'] = False
4599 4658
4600 4659 opener = urlmod.opener(ui, authinfo, **openerargs)
4601 4660
4602 4661 if opts[b'peer'] == b'http2':
4603 4662 ui.write(_(b'creating http peer for wire protocol version 2\n'))
4604 4663 # We go through makepeer() because we need an API descriptor for
4605 4664 # the peer instance to be useful.
4606 4665 maybe_silent = (
4607 4666 ui.silent()
4608 4667 if opts[b'nologhandshake']
4609 4668 else util.nullcontextmanager()
4610 4669 )
4611 4670 with maybe_silent, ui.configoverride(
4612 4671 {(b'experimental', b'httppeer.advertise-v2'): True}
4613 4672 ):
4614 4673 peer = httppeer.makepeer(ui, path, opener=opener)
4615 4674
4616 4675 if not isinstance(peer, httppeer.httpv2peer):
4617 4676 raise error.Abort(
4618 4677 _(
4619 4678 b'could not instantiate HTTP peer for '
4620 4679 b'wire protocol version 2'
4621 4680 ),
4622 4681 hint=_(
4623 4682 b'the server may not have the feature '
4624 4683 b'enabled or is not allowing this '
4625 4684 b'client version'
4626 4685 ),
4627 4686 )
4628 4687
4629 4688 elif opts[b'peer'] == b'raw':
4630 4689 ui.write(_(b'using raw connection to peer\n'))
4631 4690 peer = None
4632 4691 elif opts[b'peer']:
4633 4692 raise error.Abort(
4634 4693 _(b'--peer %s not supported with HTTP peers') % opts[b'peer']
4635 4694 )
4636 4695 else:
4637 4696 peer = httppeer.makepeer(ui, path, opener=opener)
4638 4697
4639 4698 # We /could/ populate stdin/stdout with sock.makefile()...
4640 4699 else:
4641 4700 raise error.Abort(_(b'unsupported connection configuration'))
4642 4701
4643 4702 batchedcommands = None
4644 4703
4645 4704 # Now perform actions based on the parsed wire language instructions.
4646 4705 for action, lines in blocks:
4647 4706 if action in (b'raw', b'raw+'):
4648 4707 if not stdin:
4649 4708 raise error.Abort(_(b'cannot call raw/raw+ on this peer'))
4650 4709
4651 4710 # Concatenate the data together.
4652 4711 data = b''.join(l.lstrip() for l in lines)
4653 4712 data = stringutil.unescapestr(data)
4654 4713 stdin.write(data)
4655 4714
4656 4715 if action == b'raw+':
4657 4716 stdin.flush()
4658 4717 elif action == b'flush':
4659 4718 if not stdin:
4660 4719 raise error.Abort(_(b'cannot call flush on this peer'))
4661 4720 stdin.flush()
4662 4721 elif action.startswith(b'command'):
4663 4722 if not peer:
4664 4723 raise error.Abort(
4665 4724 _(
4666 4725 b'cannot send commands unless peer instance '
4667 4726 b'is available'
4668 4727 )
4669 4728 )
4670 4729
4671 4730 command = action.split(b' ', 1)[1]
4672 4731
4673 4732 args = {}
4674 4733 for line in lines:
4675 4734 # We need to allow empty values.
4676 4735 fields = line.lstrip().split(b' ', 1)
4677 4736 if len(fields) == 1:
4678 4737 key = fields[0]
4679 4738 value = b''
4680 4739 else:
4681 4740 key, value = fields
4682 4741
4683 4742 if value.startswith(b'eval:'):
4684 4743 value = stringutil.evalpythonliteral(value[5:])
4685 4744 else:
4686 4745 value = stringutil.unescapestr(value)
4687 4746
4688 4747 args[key] = value
4689 4748
4690 4749 if batchedcommands is not None:
4691 4750 batchedcommands.append((command, args))
4692 4751 continue
4693 4752
4694 4753 ui.status(_(b'sending %s command\n') % command)
4695 4754
4696 4755 if b'PUSHFILE' in args:
4697 4756 with open(args[b'PUSHFILE'], 'rb') as fh:
4698 4757 del args[b'PUSHFILE']
4699 4758 res, output = peer._callpush(
4700 4759 command, fh, **pycompat.strkwargs(args)
4701 4760 )
4702 4761 ui.status(_(b'result: %s\n') % stringutil.escapestr(res))
4703 4762 ui.status(
4704 4763 _(b'remote output: %s\n') % stringutil.escapestr(output)
4705 4764 )
4706 4765 else:
4707 4766 with peer.commandexecutor() as e:
4708 4767 res = e.callcommand(command, args).result()
4709 4768
4710 4769 if isinstance(res, wireprotov2peer.commandresponse):
4711 4770 val = res.objects()
4712 4771 ui.status(
4713 4772 _(b'response: %s\n')
4714 4773 % stringutil.pprint(val, bprefix=True, indent=2)
4715 4774 )
4716 4775 else:
4717 4776 ui.status(
4718 4777 _(b'response: %s\n')
4719 4778 % stringutil.pprint(res, bprefix=True, indent=2)
4720 4779 )
4721 4780
4722 4781 elif action == b'batchbegin':
4723 4782 if batchedcommands is not None:
4724 4783 raise error.Abort(_(b'nested batchbegin not allowed'))
4725 4784
4726 4785 batchedcommands = []
4727 4786 elif action == b'batchsubmit':
4728 4787 # There is a batching API we could go through. But it would be
4729 4788 # difficult to normalize requests into function calls. It is easier
4730 4789 # to bypass this layer and normalize to commands + args.
4731 4790 ui.status(
4732 4791 _(b'sending batch with %d sub-commands\n')
4733 4792 % len(batchedcommands)
4734 4793 )
4735 4794 assert peer is not None
4736 4795 for i, chunk in enumerate(peer._submitbatch(batchedcommands)):
4737 4796 ui.status(
4738 4797 _(b'response #%d: %s\n') % (i, stringutil.escapestr(chunk))
4739 4798 )
4740 4799
4741 4800 batchedcommands = None
4742 4801
4743 4802 elif action.startswith(b'httprequest '):
4744 4803 if not opener:
4745 4804 raise error.Abort(
4746 4805 _(b'cannot use httprequest without an HTTP peer')
4747 4806 )
4748 4807
4749 4808 request = action.split(b' ', 2)
4750 4809 if len(request) != 3:
4751 4810 raise error.Abort(
4752 4811 _(
4753 4812 b'invalid httprequest: expected format is '
4754 4813 b'"httprequest <method> <path>'
4755 4814 )
4756 4815 )
4757 4816
4758 4817 method, httppath = request[1:]
4759 4818 headers = {}
4760 4819 body = None
4761 4820 frames = []
4762 4821 for line in lines:
4763 4822 line = line.lstrip()
4764 4823 m = re.match(b'^([a-zA-Z0-9_-]+): (.*)$', line)
4765 4824 if m:
4766 4825 # Headers need to use native strings.
4767 4826 key = pycompat.strurl(m.group(1))
4768 4827 value = pycompat.strurl(m.group(2))
4769 4828 headers[key] = value
4770 4829 continue
4771 4830
4772 4831 if line.startswith(b'BODYFILE '):
4773 4832 with open(line.split(b' ', 1), b'rb') as fh:
4774 4833 body = fh.read()
4775 4834 elif line.startswith(b'frame '):
4776 4835 frame = wireprotoframing.makeframefromhumanstring(
4777 4836 line[len(b'frame ') :]
4778 4837 )
4779 4838
4780 4839 frames.append(frame)
4781 4840 else:
4782 4841 raise error.Abort(
4783 4842 _(b'unknown argument to httprequest: %s') % line
4784 4843 )
4785 4844
4786 4845 url = path + httppath
4787 4846
4788 4847 if frames:
4789 4848 body = b''.join(bytes(f) for f in frames)
4790 4849
4791 4850 req = urlmod.urlreq.request(pycompat.strurl(url), body, headers)
4792 4851
4793 4852 # urllib.Request insists on using has_data() as a proxy for
4794 4853 # determining the request method. Override that to use our
4795 4854 # explicitly requested method.
4796 4855 req.get_method = lambda: pycompat.sysstr(method)
4797 4856
4798 4857 try:
4799 4858 res = opener.open(req)
4800 4859 body = res.read()
4801 4860 except util.urlerr.urlerror as e:
4802 4861 # read() method must be called, but only exists in Python 2
4803 4862 getattr(e, 'read', lambda: None)()
4804 4863 continue
4805 4864
4806 4865 ct = res.headers.get('Content-Type')
4807 4866 if ct == 'application/mercurial-cbor':
4808 4867 ui.write(
4809 4868 _(b'cbor> %s\n')
4810 4869 % stringutil.pprint(
4811 4870 cborutil.decodeall(body), bprefix=True, indent=2
4812 4871 )
4813 4872 )
4814 4873
4815 4874 elif action == b'close':
4816 4875 assert peer is not None
4817 4876 peer.close()
4818 4877 elif action == b'readavailable':
4819 4878 if not stdout or not stderr:
4820 4879 raise error.Abort(
4821 4880 _(b'readavailable not available on this peer')
4822 4881 )
4823 4882
4824 4883 stdin.close()
4825 4884 stdout.read()
4826 4885 stderr.read()
4827 4886
4828 4887 elif action == b'readline':
4829 4888 if not stdout:
4830 4889 raise error.Abort(_(b'readline not available on this peer'))
4831 4890 stdout.readline()
4832 4891 elif action == b'ereadline':
4833 4892 if not stderr:
4834 4893 raise error.Abort(_(b'ereadline not available on this peer'))
4835 4894 stderr.readline()
4836 4895 elif action.startswith(b'read '):
4837 4896 count = int(action.split(b' ', 1)[1])
4838 4897 if not stdout:
4839 4898 raise error.Abort(_(b'read not available on this peer'))
4840 4899 stdout.read(count)
4841 4900 elif action.startswith(b'eread '):
4842 4901 count = int(action.split(b' ', 1)[1])
4843 4902 if not stderr:
4844 4903 raise error.Abort(_(b'eread not available on this peer'))
4845 4904 stderr.read(count)
4846 4905 else:
4847 4906 raise error.Abort(_(b'unknown action: %s') % action)
4848 4907
4849 4908 if batchedcommands is not None:
4850 4909 raise error.Abort(_(b'unclosed "batchbegin" request'))
4851 4910
4852 4911 if peer:
4853 4912 peer.close()
4854 4913
4855 4914 if proc:
4856 4915 proc.kill()
@@ -1,474 +1,696
1 1 # censor code related to censoring revision
2 2 # coding: utf8
3 3 #
4 4 # Copyright 2021 Pierre-Yves David <pierre-yves.david@octobus.net>
5 5 # Copyright 2015 Google, Inc <martinvonz@google.com>
6 6 #
7 7 # This software may be used and distributed according to the terms of the
8 8 # GNU General Public License version 2 or any later version.
9 9
10 import binascii
10 11 import contextlib
11 12 import os
12 13
13 14 from ..node import (
14 15 nullrev,
15 16 )
16 17 from .constants import (
17 18 COMP_MODE_PLAIN,
18 19 ENTRY_DATA_COMPRESSED_LENGTH,
19 20 ENTRY_DATA_COMPRESSION_MODE,
20 21 ENTRY_DATA_OFFSET,
21 22 ENTRY_DATA_UNCOMPRESSED_LENGTH,
22 23 ENTRY_DELTA_BASE,
23 24 ENTRY_LINK_REV,
24 25 ENTRY_NODE_ID,
25 26 ENTRY_PARENT_1,
26 27 ENTRY_PARENT_2,
27 28 ENTRY_SIDEDATA_COMPRESSED_LENGTH,
28 29 ENTRY_SIDEDATA_COMPRESSION_MODE,
29 30 ENTRY_SIDEDATA_OFFSET,
30 31 REVLOGV0,
31 32 REVLOGV1,
32 33 )
33 34 from ..i18n import _
34 35
35 36 from .. import (
36 37 error,
37 38 pycompat,
38 39 revlogutils,
39 40 util,
40 41 )
41 42 from ..utils import (
42 43 storageutil,
43 44 )
44 45 from . import (
45 46 constants,
46 47 deltas,
47 48 )
48 49
49 50
50 51 def v1_censor(rl, tr, censornode, tombstone=b''):
51 52 """censors a revision in a "version 1" revlog"""
52 53 assert rl._format_version == constants.REVLOGV1, rl._format_version
53 54
54 55 # avoid cycle
55 56 from .. import revlog
56 57
57 58 censorrev = rl.rev(censornode)
58 59 tombstone = storageutil.packmeta({b'censored': tombstone}, b'')
59 60
60 61 # Rewriting the revlog in place is hard. Our strategy for censoring is
61 62 # to create a new revlog, copy all revisions to it, then replace the
62 63 # revlogs on transaction close.
63 64 #
64 65 # This is a bit dangerous. We could easily have a mismatch of state.
65 66 newrl = revlog.revlog(
66 67 rl.opener,
67 68 target=rl.target,
68 69 radix=rl.radix,
69 70 postfix=b'tmpcensored',
70 71 censorable=True,
71 72 )
72 73 newrl._format_version = rl._format_version
73 74 newrl._format_flags = rl._format_flags
74 75 newrl._generaldelta = rl._generaldelta
75 76 newrl._parse_index = rl._parse_index
76 77
77 78 for rev in rl.revs():
78 79 node = rl.node(rev)
79 80 p1, p2 = rl.parents(node)
80 81
81 82 if rev == censorrev:
82 83 newrl.addrawrevision(
83 84 tombstone,
84 85 tr,
85 86 rl.linkrev(censorrev),
86 87 p1,
87 88 p2,
88 89 censornode,
89 90 constants.REVIDX_ISCENSORED,
90 91 )
91 92
92 93 if newrl.deltaparent(rev) != nullrev:
93 94 m = _(b'censored revision stored as delta; cannot censor')
94 95 h = _(
95 96 b'censoring of revlogs is not fully implemented;'
96 97 b' please report this bug'
97 98 )
98 99 raise error.Abort(m, hint=h)
99 100 continue
100 101
101 102 if rl.iscensored(rev):
102 103 if rl.deltaparent(rev) != nullrev:
103 104 m = _(
104 105 b'cannot censor due to censored '
105 106 b'revision having delta stored'
106 107 )
107 108 raise error.Abort(m)
108 109 rawtext = rl._chunk(rev)
109 110 else:
110 111 rawtext = rl.rawdata(rev)
111 112
112 113 newrl.addrawrevision(
113 114 rawtext, tr, rl.linkrev(rev), p1, p2, node, rl.flags(rev)
114 115 )
115 116
116 117 tr.addbackup(rl._indexfile, location=b'store')
117 118 if not rl._inline:
118 119 tr.addbackup(rl._datafile, location=b'store')
119 120
120 121 rl.opener.rename(newrl._indexfile, rl._indexfile)
121 122 if not rl._inline:
122 123 rl.opener.rename(newrl._datafile, rl._datafile)
123 124
124 125 rl.clearcaches()
125 126 rl._loadindex()
126 127
127 128
128 129 def v2_censor(revlog, tr, censornode, tombstone=b''):
129 130 """censors a revision in a "version 2" revlog"""
130 131 assert revlog._format_version != REVLOGV0, revlog._format_version
131 132 assert revlog._format_version != REVLOGV1, revlog._format_version
132 133
133 134 censor_revs = {revlog.rev(censornode)}
134 135 _rewrite_v2(revlog, tr, censor_revs, tombstone)
135 136
136 137
137 138 def _rewrite_v2(revlog, tr, censor_revs, tombstone=b''):
138 139 """rewrite a revlog to censor some of its content
139 140
140 141 General principle
141 142
142 143 We create new revlog files (index/data/sidedata) to copy the content of
143 144 the existing data without the censored data.
144 145
145 146 We need to recompute new delta for any revision that used the censored
146 147 revision as delta base. As the cumulative size of the new delta may be
147 148 large, we store them in a temporary file until they are stored in their
148 149 final destination.
149 150
150 151 All data before the censored data can be blindly copied. The rest needs
151 152 to be copied as we go and the associated index entry needs adjustement.
152 153 """
153 154 assert revlog._format_version != REVLOGV0, revlog._format_version
154 155 assert revlog._format_version != REVLOGV1, revlog._format_version
155 156
156 157 old_index = revlog.index
157 158 docket = revlog._docket
158 159
159 160 tombstone = storageutil.packmeta({b'censored': tombstone}, b'')
160 161
161 162 first_excl_rev = min(censor_revs)
162 163
163 164 first_excl_entry = revlog.index[first_excl_rev]
164 165 index_cutoff = revlog.index.entry_size * first_excl_rev
165 166 data_cutoff = first_excl_entry[ENTRY_DATA_OFFSET] >> 16
166 167 sidedata_cutoff = revlog.sidedata_cut_off(first_excl_rev)
167 168
168 169 with pycompat.unnamedtempfile(mode=b"w+b") as tmp_storage:
169 170 # rev → (new_base, data_start, data_end, compression_mode)
170 171 rewritten_entries = _precompute_rewritten_delta(
171 172 revlog,
172 173 old_index,
173 174 censor_revs,
174 175 tmp_storage,
175 176 )
176 177
177 178 all_files = _setup_new_files(
178 179 revlog,
179 180 index_cutoff,
180 181 data_cutoff,
181 182 sidedata_cutoff,
182 183 )
183 184
184 185 # we dont need to open the old index file since its content already
185 186 # exist in a usable form in `old_index`.
186 187 with all_files() as open_files:
187 188 (
188 189 old_data_file,
189 190 old_sidedata_file,
190 191 new_index_file,
191 192 new_data_file,
192 193 new_sidedata_file,
193 194 ) = open_files
194 195
195 196 # writing the censored revision
196 197
197 198 # Writing all subsequent revisions
198 199 for rev in range(first_excl_rev, len(old_index)):
199 200 if rev in censor_revs:
200 201 _rewrite_censor(
201 202 revlog,
202 203 old_index,
203 204 open_files,
204 205 rev,
205 206 tombstone,
206 207 )
207 208 else:
208 209 _rewrite_simple(
209 210 revlog,
210 211 old_index,
211 212 open_files,
212 213 rev,
213 214 rewritten_entries,
214 215 tmp_storage,
215 216 )
216 217 docket.write(transaction=None, stripping=True)
217 218
218 219
219 220 def _precompute_rewritten_delta(
220 221 revlog,
221 222 old_index,
222 223 excluded_revs,
223 224 tmp_storage,
224 225 ):
225 226 """Compute new delta for revisions whose delta is based on revision that
226 227 will not survive as is.
227 228
228 229 Return a mapping: {rev → (new_base, data_start, data_end, compression_mode)}
229 230 """
230 231 dc = deltas.deltacomputer(revlog)
231 232 rewritten_entries = {}
232 233 first_excl_rev = min(excluded_revs)
233 234 with revlog._segmentfile._open_read() as dfh:
234 235 for rev in range(first_excl_rev, len(old_index)):
235 236 if rev in excluded_revs:
236 237 # this revision will be preserved as is, so we don't need to
237 238 # consider recomputing a delta.
238 239 continue
239 240 entry = old_index[rev]
240 241 if entry[ENTRY_DELTA_BASE] not in excluded_revs:
241 242 continue
242 243 # This is a revision that use the censored revision as the base
243 244 # for its delta. We need a need new deltas
244 245 if entry[ENTRY_DATA_UNCOMPRESSED_LENGTH] == 0:
245 246 # this revision is empty, we can delta against nullrev
246 247 rewritten_entries[rev] = (nullrev, 0, 0, COMP_MODE_PLAIN)
247 248 else:
248 249
249 250 text = revlog.rawdata(rev, _df=dfh)
250 251 info = revlogutils.revisioninfo(
251 252 node=entry[ENTRY_NODE_ID],
252 253 p1=revlog.node(entry[ENTRY_PARENT_1]),
253 254 p2=revlog.node(entry[ENTRY_PARENT_2]),
254 255 btext=[text],
255 256 textlen=len(text),
256 257 cachedelta=None,
257 258 flags=entry[ENTRY_DATA_OFFSET] & 0xFFFF,
258 259 )
259 260 d = dc.finddeltainfo(
260 261 info, dfh, excluded_bases=excluded_revs, target_rev=rev
261 262 )
262 263 default_comp = revlog._docket.default_compression_header
263 264 comp_mode, d = deltas.delta_compression(default_comp, d)
264 265 # using `tell` is a bit lazy, but we are not here for speed
265 266 start = tmp_storage.tell()
266 267 tmp_storage.write(d.data[1])
267 268 end = tmp_storage.tell()
268 269 rewritten_entries[rev] = (d.base, start, end, comp_mode)
269 270 return rewritten_entries
270 271
271 272
272 273 def _setup_new_files(
273 274 revlog,
274 275 index_cutoff,
275 276 data_cutoff,
276 277 sidedata_cutoff,
277 278 ):
278 279 """
279 280
280 281 return a context manager to open all the relevant files:
281 282 - old_data_file,
282 283 - old_sidedata_file,
283 284 - new_index_file,
284 285 - new_data_file,
285 286 - new_sidedata_file,
286 287
287 288 The old_index_file is not here because it is accessed through the
288 289 `old_index` object if the caller function.
289 290 """
290 291 docket = revlog._docket
291 292 old_index_filepath = revlog.opener.join(docket.index_filepath())
292 293 old_data_filepath = revlog.opener.join(docket.data_filepath())
293 294 old_sidedata_filepath = revlog.opener.join(docket.sidedata_filepath())
294 295
295 296 new_index_filepath = revlog.opener.join(docket.new_index_file())
296 297 new_data_filepath = revlog.opener.join(docket.new_data_file())
297 298 new_sidedata_filepath = revlog.opener.join(docket.new_sidedata_file())
298 299
299 300 util.copyfile(old_index_filepath, new_index_filepath, nb_bytes=index_cutoff)
300 301 util.copyfile(old_data_filepath, new_data_filepath, nb_bytes=data_cutoff)
301 302 util.copyfile(
302 303 old_sidedata_filepath,
303 304 new_sidedata_filepath,
304 305 nb_bytes=sidedata_cutoff,
305 306 )
306 307 revlog.opener.register_file(docket.index_filepath())
307 308 revlog.opener.register_file(docket.data_filepath())
308 309 revlog.opener.register_file(docket.sidedata_filepath())
309 310
310 311 docket.index_end = index_cutoff
311 312 docket.data_end = data_cutoff
312 313 docket.sidedata_end = sidedata_cutoff
313 314
314 315 # reload the revlog internal information
315 316 revlog.clearcaches()
316 317 revlog._loadindex(docket=docket)
317 318
318 319 @contextlib.contextmanager
319 320 def all_files_opener():
320 321 # hide opening in an helper function to please check-code, black
321 322 # and various python version at the same time
322 323 with open(old_data_filepath, 'rb') as old_data_file:
323 324 with open(old_sidedata_filepath, 'rb') as old_sidedata_file:
324 325 with open(new_index_filepath, 'r+b') as new_index_file:
325 326 with open(new_data_filepath, 'r+b') as new_data_file:
326 327 with open(
327 328 new_sidedata_filepath, 'r+b'
328 329 ) as new_sidedata_file:
329 330 new_index_file.seek(0, os.SEEK_END)
330 331 assert new_index_file.tell() == index_cutoff
331 332 new_data_file.seek(0, os.SEEK_END)
332 333 assert new_data_file.tell() == data_cutoff
333 334 new_sidedata_file.seek(0, os.SEEK_END)
334 335 assert new_sidedata_file.tell() == sidedata_cutoff
335 336 yield (
336 337 old_data_file,
337 338 old_sidedata_file,
338 339 new_index_file,
339 340 new_data_file,
340 341 new_sidedata_file,
341 342 )
342 343
343 344 return all_files_opener
344 345
345 346
346 347 def _rewrite_simple(
347 348 revlog,
348 349 old_index,
349 350 all_files,
350 351 rev,
351 352 rewritten_entries,
352 353 tmp_storage,
353 354 ):
354 355 """append a normal revision to the index after the rewritten one(s)"""
355 356 (
356 357 old_data_file,
357 358 old_sidedata_file,
358 359 new_index_file,
359 360 new_data_file,
360 361 new_sidedata_file,
361 362 ) = all_files
362 363 entry = old_index[rev]
363 364 flags = entry[ENTRY_DATA_OFFSET] & 0xFFFF
364 365 old_data_offset = entry[ENTRY_DATA_OFFSET] >> 16
365 366
366 367 if rev not in rewritten_entries:
367 368 old_data_file.seek(old_data_offset)
368 369 new_data_size = entry[ENTRY_DATA_COMPRESSED_LENGTH]
369 370 new_data = old_data_file.read(new_data_size)
370 371 data_delta_base = entry[ENTRY_DELTA_BASE]
371 372 d_comp_mode = entry[ENTRY_DATA_COMPRESSION_MODE]
372 373 else:
373 374 (
374 375 data_delta_base,
375 376 start,
376 377 end,
377 378 d_comp_mode,
378 379 ) = rewritten_entries[rev]
379 380 new_data_size = end - start
380 381 tmp_storage.seek(start)
381 382 new_data = tmp_storage.read(new_data_size)
382 383
383 384 # It might be faster to group continuous read/write operation,
384 385 # however, this is censor, an operation that is not focussed
385 386 # around stellar performance. So I have not written this
386 387 # optimisation yet.
387 388 new_data_offset = new_data_file.tell()
388 389 new_data_file.write(new_data)
389 390
390 391 sidedata_size = entry[ENTRY_SIDEDATA_COMPRESSED_LENGTH]
391 392 new_sidedata_offset = new_sidedata_file.tell()
392 393 if 0 < sidedata_size:
393 394 old_sidedata_offset = entry[ENTRY_SIDEDATA_OFFSET]
394 395 old_sidedata_file.seek(old_sidedata_offset)
395 396 new_sidedata = old_sidedata_file.read(sidedata_size)
396 397 new_sidedata_file.write(new_sidedata)
397 398
398 399 data_uncompressed_length = entry[ENTRY_DATA_UNCOMPRESSED_LENGTH]
399 400 sd_com_mode = entry[ENTRY_SIDEDATA_COMPRESSION_MODE]
400 401 assert data_delta_base <= rev, (data_delta_base, rev)
401 402
402 403 new_entry = revlogutils.entry(
403 404 flags=flags,
404 405 data_offset=new_data_offset,
405 406 data_compressed_length=new_data_size,
406 407 data_uncompressed_length=data_uncompressed_length,
407 408 data_delta_base=data_delta_base,
408 409 link_rev=entry[ENTRY_LINK_REV],
409 410 parent_rev_1=entry[ENTRY_PARENT_1],
410 411 parent_rev_2=entry[ENTRY_PARENT_2],
411 412 node_id=entry[ENTRY_NODE_ID],
412 413 sidedata_offset=new_sidedata_offset,
413 414 sidedata_compressed_length=sidedata_size,
414 415 data_compression_mode=d_comp_mode,
415 416 sidedata_compression_mode=sd_com_mode,
416 417 )
417 418 revlog.index.append(new_entry)
418 419 entry_bin = revlog.index.entry_binary(rev)
419 420 new_index_file.write(entry_bin)
420 421
421 422 revlog._docket.index_end = new_index_file.tell()
422 423 revlog._docket.data_end = new_data_file.tell()
423 424 revlog._docket.sidedata_end = new_sidedata_file.tell()
424 425
425 426
426 427 def _rewrite_censor(
427 428 revlog,
428 429 old_index,
429 430 all_files,
430 431 rev,
431 432 tombstone,
432 433 ):
433 434 """rewrite and append a censored revision"""
434 435 (
435 436 old_data_file,
436 437 old_sidedata_file,
437 438 new_index_file,
438 439 new_data_file,
439 440 new_sidedata_file,
440 441 ) = all_files
441 442 entry = old_index[rev]
442 443
443 444 # XXX consider trying the default compression too
444 445 new_data_size = len(tombstone)
445 446 new_data_offset = new_data_file.tell()
446 447 new_data_file.write(tombstone)
447 448
448 449 # we are not adding any sidedata as they might leak info about the censored version
449 450
450 451 link_rev = entry[ENTRY_LINK_REV]
451 452
452 453 p1 = entry[ENTRY_PARENT_1]
453 454 p2 = entry[ENTRY_PARENT_2]
454 455
455 456 new_entry = revlogutils.entry(
456 457 flags=constants.REVIDX_ISCENSORED,
457 458 data_offset=new_data_offset,
458 459 data_compressed_length=new_data_size,
459 460 data_uncompressed_length=new_data_size,
460 461 data_delta_base=rev,
461 462 link_rev=link_rev,
462 463 parent_rev_1=p1,
463 464 parent_rev_2=p2,
464 465 node_id=entry[ENTRY_NODE_ID],
465 466 sidedata_offset=0,
466 467 sidedata_compressed_length=0,
467 468 data_compression_mode=COMP_MODE_PLAIN,
468 469 sidedata_compression_mode=COMP_MODE_PLAIN,
469 470 )
470 471 revlog.index.append(new_entry)
471 472 entry_bin = revlog.index.entry_binary(rev)
472 473 new_index_file.write(entry_bin)
473 474 revlog._docket.index_end = new_index_file.tell()
474 475 revlog._docket.data_end = new_data_file.tell()
476
477
478 def _get_filename_from_filelog_index(path):
479 # Drop the extension and the `data/` prefix
480 path_part = path.rsplit(b'.', 1)[0].split(b'/', 1)
481 if len(path_part) < 2:
482 msg = _(b"cannot recognize filelog from filename: '%s'")
483 msg %= path
484 raise error.Abort(msg)
485
486 return path_part[1]
487
488
489 def _filelog_from_filename(repo, path):
490 """Returns the filelog for the given `path`. Stolen from `engine.py`"""
491
492 from .. import filelog # avoid cycle
493
494 fl = filelog.filelog(repo.svfs, path)
495 return fl
496
497
498 def _write_swapped_parents(repo, rl, rev, offset, fp):
499 """Swaps p1 and p2 and overwrites the revlog entry for `rev` in `fp`"""
500 from ..pure import parsers # avoid cycle
501
502 if repo._currentlock(repo._lockref) is None:
503 # Let's be paranoid about it
504 msg = "repo needs to be locked to rewrite parents"
505 raise error.ProgrammingError(msg)
506
507 index_format = parsers.IndexObject.index_format
508 entry = rl.index[rev]
509 new_entry = list(entry)
510 new_entry[5], new_entry[6] = entry[6], entry[5]
511 packed = index_format.pack(*new_entry[:8])
512 fp.seek(offset)
513 fp.write(packed)
514
515
516 def _reorder_filelog_parents(repo, fl, to_fix):
517 """
518 Swaps p1 and p2 for all `to_fix` revisions of filelog `fl` and writes the
519 new version to disk, overwriting the old one with a rename.
520 """
521 from ..pure import parsers # avoid cycle
522
523 ui = repo.ui
524 assert len(to_fix) > 0
525 rl = fl._revlog
526 if rl._format_version != constants.REVLOGV1:
527 msg = "expected version 1 revlog, got version '%d'" % rl._format_version
528 raise error.ProgrammingError(msg)
529
530 index_file = rl._indexfile
531 new_file_path = index_file + b'.tmp-parents-fix'
532 repaired_msg = _(b"repaired revision %d of 'filelog %s'\n")
533
534 with ui.uninterruptible():
535 try:
536 util.copyfile(
537 rl.opener.join(index_file),
538 rl.opener.join(new_file_path),
539 checkambig=rl._checkambig,
540 )
541
542 with rl.opener(new_file_path, mode=b"r+") as fp:
543 if rl._inline:
544 index = parsers.InlinedIndexObject(fp.read())
545 for rev in fl.revs():
546 if rev in to_fix:
547 offset = index._calculate_index(rev)
548 _write_swapped_parents(repo, rl, rev, offset, fp)
549 ui.write(repaired_msg % (rev, index_file))
550 else:
551 index_format = parsers.IndexObject.index_format
552 for rev in to_fix:
553 offset = rev * index_format.size
554 _write_swapped_parents(repo, rl, rev, offset, fp)
555 ui.write(repaired_msg % (rev, index_file))
556
557 rl.opener.rename(new_file_path, index_file)
558 rl.clearcaches()
559 rl._loadindex()
560 finally:
561 util.tryunlink(new_file_path)
562
563
564 def _is_revision_affected(ui, fl, filerev, path):
565 """Mercurial currently (5.9rc0) uses `p1 == nullrev and p2 != nullrev` as a
566 special meaning compared to the reverse in the context of filelog-based
567 copytracing. issue6528 exists because new code assumed that parent ordering
568 didn't matter, so this detects if the revision contains metadata (since
569 it's only used for filelog-based copytracing) and its parents are in the
570 "wrong" order."""
571 try:
572 raw_text = fl.rawdata(filerev)
573 except error.CensoredNodeError:
574 # We don't care about censored nodes as they never carry metadata
575 return False
576 has_meta = raw_text.startswith(b'\x01\n')
577 if has_meta:
578 (p1, p2) = fl.parentrevs(filerev)
579 if p1 != nullrev and p2 == nullrev:
580 return True
581 return False
582
583
584 def _from_report(ui, repo, context, from_report, dry_run):
585 """
586 Fix the revisions given in the `from_report` file, but still checks if the
587 revisions are indeed affected to prevent an unfortunate cyclic situation
588 where we'd swap well-ordered parents again.
589
590 See the doc for `debug_fix_issue6528` for the format documentation.
591 """
592 ui.write(_(b"loading report file '%s'\n") % from_report)
593
594 with context(), open(from_report, mode='rb') as f:
595 for line in f.read().split(b'\n'):
596 if not line:
597 continue
598 filenodes, filename = line.split(b' ', 1)
599 fl = _filelog_from_filename(repo, filename)
600 to_fix = set(
601 fl.rev(binascii.unhexlify(n)) for n in filenodes.split(b',')
602 )
603 excluded = set()
604
605 for filerev in to_fix:
606 if _is_revision_affected(ui, fl, filerev, filename):
607 msg = b"found affected revision %d for filelog '%s'\n"
608 ui.warn(msg % (filerev, filename))
609 else:
610 msg = _(b"revision %s of file '%s' is not affected\n")
611 msg %= (binascii.hexlify(fl.node(filerev)), filename)
612 ui.warn(msg)
613 excluded.add(filerev)
614
615 to_fix = to_fix - excluded
616 if not to_fix:
617 msg = _(b"no affected revisions were found for '%s'\n")
618 ui.write(msg % filename)
619 continue
620 if not dry_run:
621 _reorder_filelog_parents(repo, fl, sorted(to_fix))
622
623
624 def repair_issue6528(ui, repo, dry_run=False, to_report=None, from_report=None):
625 from .. import store # avoid cycle
626
627 @contextlib.contextmanager
628 def context():
629 if dry_run or to_report: # No need for locking
630 yield
631 else:
632 with repo.wlock(), repo.lock():
633 yield
634
635 if from_report:
636 return _from_report(ui, repo, context, from_report, dry_run)
637
638 report_entries = []
639
640 with context():
641 files = list(
642 (file_type, path)
643 for (file_type, path, _e, _s) in repo.store.datafiles()
644 if path.endswith(b'.i') and file_type & store.FILEFLAGS_FILELOG
645 )
646
647 progress = ui.makeprogress(
648 _(b"looking for affected revisions"),
649 unit=_(b"filelogs"),
650 total=len(files),
651 )
652 found_nothing = True
653
654 for file_type, path in files:
655 if (
656 not path.endswith(b'.i')
657 or not file_type & store.FILEFLAGS_FILELOG
658 ):
659 continue
660 progress.increment()
661 filename = _get_filename_from_filelog_index(path)
662 fl = _filelog_from_filename(repo, filename)
663
664 # Set of filerevs (or hex filenodes if `to_report`) that need fixing
665 to_fix = set()
666 for filerev in fl.revs():
667 # TODO speed up by looking at the start of the delta
668 # If it hasn't changed, it's not worth looking at the other revs
669 # in the same chain
670 affected = _is_revision_affected(ui, fl, filerev, path)
671 if affected:
672 msg = b"found affected revision %d for filelog '%s'\n"
673 ui.warn(msg % (filerev, path))
674 found_nothing = False
675 if not dry_run:
676 if to_report:
677 to_fix.add(binascii.hexlify(fl.node(filerev)))
678 else:
679 to_fix.add(filerev)
680
681 if to_fix:
682 to_fix = sorted(to_fix)
683 if to_report:
684 report_entries.append((filename, to_fix))
685 else:
686 _reorder_filelog_parents(repo, fl, to_fix)
687
688 if found_nothing:
689 ui.write(_(b"no affected revisions were found\n"))
690
691 if to_report and report_entries:
692 with open(to_report, mode="wb") as f:
693 for path, to_fix in report_entries:
694 f.write(b"%s %s\n" % (b",".join(to_fix), path))
695
696 progress.complete()
@@ -1,445 +1,447
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-repair-issue6528
77 78 debugancestor
78 79 debugantivirusrunning
79 80 debugapplystreamclonebundle
80 81 debugbackupbundle
81 82 debugbuilddag
82 83 debugbundle
83 84 debugcapabilities
84 85 debugchangedfiles
85 86 debugcheckstate
86 87 debugcolor
87 88 debugcommands
88 89 debugcomplete
89 90 debugconfig
90 91 debugcreatestreamclonebundle
91 92 debugdag
92 93 debugdata
93 94 debugdate
94 95 debugdeltachain
95 96 debugdirstate
96 97 debugdirstateignorepatternshash
97 98 debugdiscovery
98 99 debugdownload
99 100 debugextensions
100 101 debugfileset
101 102 debugformat
102 103 debugfsinfo
103 104 debuggetbundle
104 105 debugignore
105 106 debugindex
106 107 debugindexdot
107 108 debugindexstats
108 109 debuginstall
109 110 debugknown
110 111 debuglabelcomplete
111 112 debuglocks
112 113 debugmanifestfulltextcache
113 114 debugmergestate
114 115 debugnamecomplete
115 116 debugnodemap
116 117 debugobsolete
117 118 debugp1copies
118 119 debugp2copies
119 120 debugpathcomplete
120 121 debugpathcopies
121 122 debugpeer
122 123 debugpickmergetool
123 124 debugpushkey
124 125 debugpvec
125 126 debugrebuilddirstate
126 127 debugrebuildfncache
127 128 debugrename
128 129 debugrequires
129 130 debugrevlog
130 131 debugrevlogindex
131 132 debugrevspec
132 133 debugserve
133 134 debugsetparents
134 135 debugshell
135 136 debugsidedata
136 137 debugssl
137 138 debugstrip
138 139 debugsub
139 140 debugsuccessorssets
140 141 debugtagscache
141 142 debugtemplate
142 143 debuguigetpass
143 144 debuguiprompt
144 145 debugupdatecaches
145 146 debugupgraderepo
146 147 debugwalk
147 148 debugwhyunstable
148 149 debugwireargs
149 150 debugwireproto
150 151
151 152 Do not show the alias of a debug command if there are other candidates
152 153 (this should hide rawcommit)
153 154 $ hg debugcomplete r
154 155 recover
155 156 remove
156 157 rename
157 158 resolve
158 159 revert
159 160 rollback
160 161 root
161 162 Show the alias of a debug command if there are no other candidates
162 163 $ hg debugcomplete rawc
163 164
164 165
165 166 Show the global options
166 167 $ hg debugcomplete --options | sort
167 168 --color
168 169 --config
169 170 --cwd
170 171 --debug
171 172 --debugger
172 173 --encoding
173 174 --encodingmode
174 175 --help
175 176 --hidden
176 177 --noninteractive
177 178 --pager
178 179 --profile
179 180 --quiet
180 181 --repository
181 182 --time
182 183 --traceback
183 184 --verbose
184 185 --version
185 186 -R
186 187 -h
187 188 -q
188 189 -v
189 190 -y
190 191
191 192 Show the options for the "serve" command
192 193 $ hg debugcomplete --options serve | sort
193 194 --accesslog
194 195 --address
195 196 --certificate
196 197 --cmdserver
197 198 --color
198 199 --config
199 200 --cwd
200 201 --daemon
201 202 --daemon-postexec
202 203 --debug
203 204 --debugger
204 205 --encoding
205 206 --encodingmode
206 207 --errorlog
207 208 --help
208 209 --hidden
209 210 --ipv6
210 211 --name
211 212 --noninteractive
212 213 --pager
213 214 --pid-file
214 215 --port
215 216 --prefix
216 217 --print-url
217 218 --profile
218 219 --quiet
219 220 --repository
220 221 --stdio
221 222 --style
222 223 --subrepos
223 224 --templates
224 225 --time
225 226 --traceback
226 227 --verbose
227 228 --version
228 229 --web-conf
229 230 -6
230 231 -A
231 232 -E
232 233 -R
233 234 -S
234 235 -a
235 236 -d
236 237 -h
237 238 -n
238 239 -p
239 240 -q
240 241 -t
241 242 -v
242 243 -y
243 244
244 245 Show an error if we use --options with an ambiguous abbreviation
245 246 $ hg debugcomplete --options s
246 247 hg: command 's' is ambiguous:
247 248 serve shelve showconfig status summary
248 249 [10]
249 250
250 251 Show all commands + options
251 252 $ hg debugcommands
252 253 abort: dry-run
253 254 add: include, exclude, subrepos, dry-run
254 255 addremove: similarity, subrepos, include, exclude, dry-run
255 256 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
256 257 archive: no-decode, prefix, rev, type, subrepos, include, exclude
257 258 backout: merge, commit, no-commit, parent, rev, edit, tool, include, exclude, message, logfile, date, user
258 259 bisect: reset, good, bad, skip, extend, command, noupdate
259 260 bookmarks: force, rev, delete, rename, inactive, list, template
260 261 branch: force, clean, rev
261 262 branches: active, closed, rev, template
262 263 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
263 264 cat: output, rev, decode, include, exclude, template
264 265 clone: noupdate, updaterev, rev, branch, pull, uncompressed, stream, ssh, remotecmd, insecure
265 266 commit: addremove, close-branch, amend, secret, edit, force-close-branch, interactive, include, exclude, message, logfile, date, user, subrepos
266 267 config: untrusted, exp-all-known, edit, local, source, shared, non-shared, global, template
267 268 continue: dry-run
268 269 copy: forget, after, at-rev, force, include, exclude, dry-run
270 debug-repair-issue6528: to-report, from-report, dry-run
269 271 debugancestor:
270 272 debugantivirusrunning:
271 273 debugapplystreamclonebundle:
272 274 debugbackupbundle: recover, patch, git, limit, no-merges, stat, graph, style, template
273 275 debugbuilddag: mergeable-file, overwritten-file, new-file
274 276 debugbundle: all, part-type, spec
275 277 debugcapabilities:
276 278 debugchangedfiles: compute
277 279 debugcheckstate:
278 280 debugcolor: style
279 281 debugcommands:
280 282 debugcomplete: options
281 283 debugcreatestreamclonebundle:
282 284 debugdag: tags, branches, dots, spaces
283 285 debugdata: changelog, manifest, dir
284 286 debugdate: extended
285 287 debugdeltachain: changelog, manifest, dir, template
286 288 debugdirstateignorepatternshash:
287 289 debugdirstate: nodates, dates, datesort, all
288 290 debugdiscovery: old, nonheads, rev, seed, local-as-revs, remote-as-revs, ssh, remotecmd, insecure, template
289 291 debugdownload: output
290 292 debugextensions: template
291 293 debugfileset: rev, all-files, show-matcher, show-stage
292 294 debugformat: template
293 295 debugfsinfo:
294 296 debuggetbundle: head, common, type
295 297 debugignore:
296 298 debugindex: changelog, manifest, dir, template
297 299 debugindexdot: changelog, manifest, dir
298 300 debugindexstats:
299 301 debuginstall: template
300 302 debugknown:
301 303 debuglabelcomplete:
302 304 debuglocks: force-free-lock, force-free-wlock, set-lock, set-wlock
303 305 debugmanifestfulltextcache: clear, add
304 306 debugmergestate: style, template
305 307 debugnamecomplete:
306 308 debugnodemap: dump-new, dump-disk, check, metadata
307 309 debugobsolete: flags, record-parents, rev, exclusive, index, delete, date, user, template
308 310 debugp1copies: rev
309 311 debugp2copies: rev
310 312 debugpathcomplete: full, normal, added, removed
311 313 debugpathcopies: include, exclude
312 314 debugpeer:
313 315 debugpickmergetool: rev, changedelete, include, exclude, tool
314 316 debugpushkey:
315 317 debugpvec:
316 318 debugrebuilddirstate: rev, minimal
317 319 debugrebuildfncache:
318 320 debugrename: rev
319 321 debugrequires:
320 322 debugrevlog: changelog, manifest, dir, dump
321 323 debugrevlogindex: changelog, manifest, dir, format
322 324 debugrevspec: optimize, show-revs, show-set, show-stage, no-optimized, verify-optimized
323 325 debugserve: sshstdio, logiofd, logiofile
324 326 debugsetparents:
325 327 debugshell:
326 328 debugsidedata: changelog, manifest, dir
327 329 debugssl:
328 330 debugstrip: rev, force, no-backup, nobackup, , keep, bookmark, soft
329 331 debugsub: rev
330 332 debugsuccessorssets: closest
331 333 debugtagscache:
332 334 debugtemplate: rev, define
333 335 debuguigetpass: prompt
334 336 debuguiprompt: prompt
335 337 debugupdatecaches:
336 338 debugupgraderepo: optimize, run, backup, changelog, manifest, filelogs
337 339 debugwalk: include, exclude
338 340 debugwhyunstable:
339 341 debugwireargs: three, four, five, ssh, remotecmd, insecure
340 342 debugwireproto: localssh, peer, noreadstderr, nologhandshake, ssh, remotecmd, insecure
341 343 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
342 344 export: bookmark, output, switch-parent, rev, text, git, binary, nodates, template
343 345 files: rev, print0, include, exclude, template, subrepos
344 346 forget: interactive, include, exclude, dry-run
345 347 graft: rev, base, continue, stop, abort, edit, log, no-commit, force, currentdate, currentuser, date, user, tool, dry-run
346 348 grep: print0, all, diff, text, follow, ignore-case, files-with-matches, line-number, rev, all-files, user, date, template, include, exclude
347 349 heads: rev, topo, active, closed, style, template
348 350 help: extension, command, keyword, system
349 351 identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure, template
350 352 import: strip, base, secret, edit, force, no-commit, bypass, partial, exact, prefix, import-branch, message, logfile, date, user, similarity
351 353 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
352 354 init: ssh, remotecmd, insecure
353 355 locate: rev, print0, fullpath, include, exclude
354 356 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
355 357 manifest: rev, all, template
356 358 merge: force, rev, preview, abort, tool
357 359 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
358 360 parents: rev, style, template
359 361 paths: template
360 362 phase: public, draft, secret, force, rev
361 363 pull: update, force, confirm, rev, bookmark, branch, ssh, remotecmd, insecure
362 364 purge: abort-on-err, all, ignored, dirs, files, print, print0, confirm, include, exclude
363 365 push: force, rev, bookmark, all-bookmarks, branch, new-branch, pushvars, publish, ssh, remotecmd, insecure
364 366 recover: verify
365 367 remove: after, force, subrepos, include, exclude, dry-run
366 368 rename: forget, after, at-rev, force, include, exclude, dry-run
367 369 resolve: all, list, mark, unmark, no-status, re-merge, tool, include, exclude, template
368 370 revert: all, date, rev, no-backup, interactive, include, exclude, dry-run
369 371 rollback: dry-run, force
370 372 root: template
371 373 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
372 374 shelve: addremove, unknown, cleanup, date, delete, edit, keep, list, message, name, patch, interactive, stat, include, exclude
373 375 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, terse, copies, print0, rev, change, include, exclude, subrepos, template
374 376 summary: remote
375 377 tag: force, local, rev, remove, edit, message, date, user
376 378 tags: template
377 379 tip: patch, git, style, template
378 380 unbundle: update
379 381 unshelve: abort, continue, interactive, keep, name, tool, date
380 382 update: clean, check, merge, date, rev, tool
381 383 verify: full
382 384 version: template
383 385
384 386 $ hg init a
385 387 $ cd a
386 388 $ echo fee > fee
387 389 $ hg ci -q -Amfee
388 390 $ hg tag fee
389 391 $ mkdir fie
390 392 $ echo dead > fie/dead
391 393 $ echo live > fie/live
392 394 $ hg bookmark fo
393 395 $ hg branch -q fie
394 396 $ hg ci -q -Amfie
395 397 $ echo fo > fo
396 398 $ hg branch -qf default
397 399 $ hg ci -q -Amfo
398 400 $ echo Fum > Fum
399 401 $ hg ci -q -AmFum
400 402 $ hg bookmark Fum
401 403
402 404 Test debugpathcomplete
403 405
404 406 $ hg debugpathcomplete f
405 407 fee
406 408 fie
407 409 fo
408 410 $ hg debugpathcomplete -f f
409 411 fee
410 412 fie/dead
411 413 fie/live
412 414 fo
413 415
414 416 $ hg rm Fum
415 417 $ hg debugpathcomplete -r F
416 418 Fum
417 419
418 420 Test debugnamecomplete
419 421
420 422 $ hg debugnamecomplete
421 423 Fum
422 424 default
423 425 fee
424 426 fie
425 427 fo
426 428 tip
427 429 $ hg debugnamecomplete f
428 430 fee
429 431 fie
430 432 fo
431 433
432 434 Test debuglabelcomplete, a deprecated name for debugnamecomplete that is still
433 435 used for completions in some shells.
434 436
435 437 $ hg debuglabelcomplete
436 438 Fum
437 439 default
438 440 fee
439 441 fie
440 442 fo
441 443 tip
442 444 $ hg debuglabelcomplete f
443 445 fee
444 446 fie
445 447 fo
@@ -1,4010 +1,4013
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
169 169 Concepts:
170 170
171 171 bundlespec Bundle File Formats
172 172 evolution Safely rewriting history (EXPERIMENTAL)
173 173 glossary Glossary
174 174 phases Working with Phases
175 175 subrepos Subrepositories
176 176
177 177 Miscellaneous:
178 178
179 179 deprecated Deprecated Features
180 180 internals Technical implementation topics
181 181 scripting Using Mercurial from scripts and automation
182 182
183 183 (use 'hg help -v' to show built-in aliases and global options)
184 184
185 185 $ hg -q help
186 186 Repository creation:
187 187
188 188 clone make a copy of an existing repository
189 189 init create a new repository in the given directory
190 190
191 191 Remote repository management:
192 192
193 193 incoming show new changesets found in source
194 194 outgoing show changesets not found in the destination
195 195 paths show aliases for remote repositories
196 196 pull pull changes from the specified source
197 197 push push changes to the specified destination
198 198 serve start stand-alone webserver
199 199
200 200 Change creation:
201 201
202 202 commit commit the specified files or all outstanding changes
203 203
204 204 Change manipulation:
205 205
206 206 backout reverse effect of earlier changeset
207 207 graft copy changes from other branches onto the current branch
208 208 merge merge another revision into working directory
209 209
210 210 Change organization:
211 211
212 212 bookmarks create a new bookmark or list existing bookmarks
213 213 branch set or show the current branch name
214 214 branches list repository named branches
215 215 phase set or show the current phase name
216 216 tag add one or more tags for the current or given revision
217 217 tags list repository tags
218 218
219 219 File content management:
220 220
221 221 annotate show changeset information by line for each file
222 222 cat output the current or given revision of files
223 223 copy mark files as copied for the next commit
224 224 diff diff repository (or selected files)
225 225 grep search for a pattern in specified files
226 226
227 227 Change navigation:
228 228
229 229 bisect subdivision search of changesets
230 230 heads show branch heads
231 231 identify identify the working directory or specified revision
232 232 log show revision history of entire repository or files
233 233
234 234 Working directory management:
235 235
236 236 add add the specified files on the next commit
237 237 addremove add all new files, delete all missing files
238 238 files list tracked files
239 239 forget forget the specified files on the next commit
240 240 purge removes files not tracked by Mercurial
241 241 remove remove the specified files on the next commit
242 242 rename rename files; equivalent of copy + remove
243 243 resolve redo merges or set/view the merge status of files
244 244 revert restore files to their checkout state
245 245 root print the root (top) of the current working directory
246 246 shelve save and set aside changes from the working directory
247 247 status show changed files in the working directory
248 248 summary summarize working directory state
249 249 unshelve restore a shelved change to the working directory
250 250 update update working directory (or switch revisions)
251 251
252 252 Change import/export:
253 253
254 254 archive create an unversioned archive of a repository revision
255 255 bundle create a bundle file
256 256 export dump the header and diffs for one or more changesets
257 257 import import an ordered set of patches
258 258 unbundle apply one or more bundle files
259 259
260 260 Repository maintenance:
261 261
262 262 manifest output the current or given revision of the project manifest
263 263 recover roll back an interrupted transaction
264 264 verify verify the integrity of the repository
265 265
266 266 Help:
267 267
268 268 config show combined config settings from all hgrc files
269 269 help show help for a given topic or a help overview
270 270 version output version and copyright information
271 271
272 272 additional help topics:
273 273
274 274 Mercurial identifiers:
275 275
276 276 filesets Specifying File Sets
277 277 hgignore Syntax for Mercurial Ignore Files
278 278 patterns File Name Patterns
279 279 revisions Specifying Revisions
280 280 urls URL Paths
281 281
282 282 Mercurial output:
283 283
284 284 color Colorizing Outputs
285 285 dates Date Formats
286 286 diffs Diff Formats
287 287 templating Template Usage
288 288
289 289 Mercurial configuration:
290 290
291 291 config Configuration Files
292 292 environment Environment Variables
293 293 extensions Using Additional Features
294 294 flags Command-line flags
295 295 hgweb Configuring hgweb
296 296 merge-tools Merge Tools
297 297 pager Pager Support
298 298
299 299 Concepts:
300 300
301 301 bundlespec Bundle File Formats
302 302 evolution Safely rewriting history (EXPERIMENTAL)
303 303 glossary Glossary
304 304 phases Working with Phases
305 305 subrepos Subrepositories
306 306
307 307 Miscellaneous:
308 308
309 309 deprecated Deprecated Features
310 310 internals Technical implementation topics
311 311 scripting Using Mercurial from scripts and automation
312 312
313 313 Test extension help:
314 314 $ hg help extensions --config extensions.rebase= --config extensions.children=
315 315 Using Additional Features
316 316 """""""""""""""""""""""""
317 317
318 318 Mercurial has the ability to add new features through the use of
319 319 extensions. Extensions may add new commands, add options to existing
320 320 commands, change the default behavior of commands, or implement hooks.
321 321
322 322 To enable the "foo" extension, either shipped with Mercurial or in the
323 323 Python search path, create an entry for it in your configuration file,
324 324 like this:
325 325
326 326 [extensions]
327 327 foo =
328 328
329 329 You may also specify the full path to an extension:
330 330
331 331 [extensions]
332 332 myfeature = ~/.hgext/myfeature.py
333 333
334 334 See 'hg help config' for more information on configuration files.
335 335
336 336 Extensions are not loaded by default for a variety of reasons: they can
337 337 increase startup overhead; they may be meant for advanced usage only; they
338 338 may provide potentially dangerous abilities (such as letting you destroy
339 339 or modify history); they might not be ready for prime time; or they may
340 340 alter some usual behaviors of stock Mercurial. It is thus up to the user
341 341 to activate extensions as needed.
342 342
343 343 To explicitly disable an extension enabled in a configuration file of
344 344 broader scope, prepend its path with !:
345 345
346 346 [extensions]
347 347 # disabling extension bar residing in /path/to/extension/bar.py
348 348 bar = !/path/to/extension/bar.py
349 349 # ditto, but no path was supplied for extension baz
350 350 baz = !
351 351
352 352 enabled extensions:
353 353
354 354 children command to display child changesets (DEPRECATED)
355 355 rebase command to move sets of revisions to a different ancestor
356 356
357 357 disabled extensions:
358 358
359 359 acl hooks for controlling repository access
360 360 blackbox log repository events to a blackbox for debugging
361 361 bugzilla hooks for integrating with the Bugzilla bug tracker
362 362 censor erase file content at a given revision
363 363 churn command to display statistics about repository history
364 364 clonebundles advertise pre-generated bundles to seed clones
365 365 closehead close arbitrary heads without checking them out first
366 366 convert import revisions from foreign VCS repositories into
367 367 Mercurial
368 368 eol automatically manage newlines in repository files
369 369 extdiff command to allow external programs to compare revisions
370 370 factotum http authentication with factotum
371 371 fastexport export repositories as git fast-import stream
372 372 githelp try mapping git commands to Mercurial commands
373 373 gpg commands to sign and verify changesets
374 374 hgk browse the repository in a graphical way
375 375 highlight syntax highlighting for hgweb (requires Pygments)
376 376 histedit interactive history editing
377 377 keyword expand keywords in tracked files
378 378 largefiles track large binary files
379 379 mq manage a stack of patches
380 380 notify hooks for sending email push notifications
381 381 patchbomb command to send changesets as (a series of) patch emails
382 382 relink recreates hardlinks between repository clones
383 383 schemes extend schemes with shortcuts to repository swarms
384 384 share share a common history between several working directories
385 385 transplant command to transplant changesets from another branch
386 386 win32mbcs allow the use of MBCS paths with problematic encodings
387 387 zeroconf discover and advertise repositories on the local network
388 388
389 389 #endif
390 390
391 391 Verify that deprecated extensions are included if --verbose:
392 392
393 393 $ hg -v help extensions | grep children
394 394 children command to display child changesets (DEPRECATED)
395 395
396 396 Verify that extension keywords appear in help templates
397 397
398 398 $ hg help --config extensions.transplant= templating|grep transplant > /dev/null
399 399
400 400 Test short command list with verbose option
401 401
402 402 $ hg -v help shortlist
403 403 Mercurial Distributed SCM
404 404
405 405 basic commands:
406 406
407 407 abort abort an unfinished operation (EXPERIMENTAL)
408 408 add add the specified files on the next commit
409 409 annotate, blame
410 410 show changeset information by line for each file
411 411 clone make a copy of an existing repository
412 412 commit, ci commit the specified files or all outstanding changes
413 413 continue resumes an interrupted operation (EXPERIMENTAL)
414 414 diff diff repository (or selected files)
415 415 export dump the header and diffs for one or more changesets
416 416 forget forget the specified files on the next commit
417 417 init create a new repository in the given directory
418 418 log, history show revision history of entire repository or files
419 419 merge merge another revision into working directory
420 420 pull pull changes from the specified source
421 421 push push changes to the specified destination
422 422 remove, rm remove the specified files on the next commit
423 423 serve start stand-alone webserver
424 424 status, st show changed files in the working directory
425 425 summary, sum summarize working directory state
426 426 update, up, checkout, co
427 427 update working directory (or switch revisions)
428 428
429 429 global options ([+] can be repeated):
430 430
431 431 -R --repository REPO repository root directory or name of overlay bundle
432 432 file
433 433 --cwd DIR change working directory
434 434 -y --noninteractive do not prompt, automatically pick the first choice for
435 435 all prompts
436 436 -q --quiet suppress output
437 437 -v --verbose enable additional output
438 438 --color TYPE when to colorize (boolean, always, auto, never, or
439 439 debug)
440 440 --config CONFIG [+] set/override config option (use 'section.name=value')
441 441 --debug enable debugging output
442 442 --debugger start debugger
443 443 --encoding ENCODE set the charset encoding (default: ascii)
444 444 --encodingmode MODE set the charset encoding mode (default: strict)
445 445 --traceback always print a traceback on exception
446 446 --time time how long the command takes
447 447 --profile print command execution profile
448 448 --version output version information and exit
449 449 -h --help display help and exit
450 450 --hidden consider hidden changesets
451 451 --pager TYPE when to paginate (boolean, always, auto, or never)
452 452 (default: auto)
453 453
454 454 (use 'hg help' for the full list of commands)
455 455
456 456 $ hg add -h
457 457 hg add [OPTION]... [FILE]...
458 458
459 459 add the specified files on the next commit
460 460
461 461 Schedule files to be version controlled and added to the repository.
462 462
463 463 The files will be added to the repository at the next commit. To undo an
464 464 add before that, see 'hg forget'.
465 465
466 466 If no names are given, add all files to the repository (except files
467 467 matching ".hgignore").
468 468
469 469 Returns 0 if all files are successfully added.
470 470
471 471 options ([+] can be repeated):
472 472
473 473 -I --include PATTERN [+] include names matching the given patterns
474 474 -X --exclude PATTERN [+] exclude names matching the given patterns
475 475 -S --subrepos recurse into subrepositories
476 476 -n --dry-run do not perform actions, just print output
477 477
478 478 (some details hidden, use --verbose to show complete help)
479 479
480 480 Verbose help for add
481 481
482 482 $ hg add -hv
483 483 hg add [OPTION]... [FILE]...
484 484
485 485 add the specified files on the next commit
486 486
487 487 Schedule files to be version controlled and added to the repository.
488 488
489 489 The files will be added to the repository at the next commit. To undo an
490 490 add before that, see 'hg forget'.
491 491
492 492 If no names are given, add all files to the repository (except files
493 493 matching ".hgignore").
494 494
495 495 Examples:
496 496
497 497 - New (unknown) files are added automatically by 'hg add':
498 498
499 499 $ ls
500 500 foo.c
501 501 $ hg status
502 502 ? foo.c
503 503 $ hg add
504 504 adding foo.c
505 505 $ hg status
506 506 A foo.c
507 507
508 508 - Specific files to be added can be specified:
509 509
510 510 $ ls
511 511 bar.c foo.c
512 512 $ hg status
513 513 ? bar.c
514 514 ? foo.c
515 515 $ hg add bar.c
516 516 $ hg status
517 517 A bar.c
518 518 ? foo.c
519 519
520 520 Returns 0 if all files are successfully added.
521 521
522 522 options ([+] can be repeated):
523 523
524 524 -I --include PATTERN [+] include names matching the given patterns
525 525 -X --exclude PATTERN [+] exclude names matching the given patterns
526 526 -S --subrepos recurse into subrepositories
527 527 -n --dry-run do not perform actions, just print output
528 528
529 529 global options ([+] can be repeated):
530 530
531 531 -R --repository REPO repository root directory or name of overlay bundle
532 532 file
533 533 --cwd DIR change working directory
534 534 -y --noninteractive do not prompt, automatically pick the first choice for
535 535 all prompts
536 536 -q --quiet suppress output
537 537 -v --verbose enable additional output
538 538 --color TYPE when to colorize (boolean, always, auto, never, or
539 539 debug)
540 540 --config CONFIG [+] set/override config option (use 'section.name=value')
541 541 --debug enable debugging output
542 542 --debugger start debugger
543 543 --encoding ENCODE set the charset encoding (default: ascii)
544 544 --encodingmode MODE set the charset encoding mode (default: strict)
545 545 --traceback always print a traceback on exception
546 546 --time time how long the command takes
547 547 --profile print command execution profile
548 548 --version output version information and exit
549 549 -h --help display help and exit
550 550 --hidden consider hidden changesets
551 551 --pager TYPE when to paginate (boolean, always, auto, or never)
552 552 (default: auto)
553 553
554 554 Test the textwidth config option
555 555
556 556 $ hg root -h --config ui.textwidth=50
557 557 hg root
558 558
559 559 print the root (top) of the current working
560 560 directory
561 561
562 562 Print the root directory of the current
563 563 repository.
564 564
565 565 Returns 0 on success.
566 566
567 567 options:
568 568
569 569 -T --template TEMPLATE display with template
570 570
571 571 (some details hidden, use --verbose to show
572 572 complete help)
573 573
574 574 Test help option with version option
575 575
576 576 $ hg add -h --version
577 577 Mercurial Distributed SCM (version *) (glob)
578 578 (see https://mercurial-scm.org for more information)
579 579
580 580 Copyright (C) 2005-* Olivia Mackall and others (glob)
581 581 This is free software; see the source for copying conditions. There is NO
582 582 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
583 583
584 584 $ hg add --skjdfks
585 585 hg add: option --skjdfks not recognized
586 586 hg add [OPTION]... [FILE]...
587 587
588 588 add the specified files on the next commit
589 589
590 590 options ([+] can be repeated):
591 591
592 592 -I --include PATTERN [+] include names matching the given patterns
593 593 -X --exclude PATTERN [+] exclude names matching the given patterns
594 594 -S --subrepos recurse into subrepositories
595 595 -n --dry-run do not perform actions, just print output
596 596
597 597 (use 'hg add -h' to show more help)
598 598 [10]
599 599
600 600 Test ambiguous command help
601 601
602 602 $ hg help ad
603 603 list of commands:
604 604
605 605 add add the specified files on the next commit
606 606 addremove add all new files, delete all missing files
607 607
608 608 (use 'hg help -v ad' to show built-in aliases and global options)
609 609
610 610 Test command without options
611 611
612 612 $ hg help verify
613 613 hg verify
614 614
615 615 verify the integrity of the repository
616 616
617 617 Verify the integrity of the current repository.
618 618
619 619 This will perform an extensive check of the repository's integrity,
620 620 validating the hashes and checksums of each entry in the changelog,
621 621 manifest, and tracked files, as well as the integrity of their crosslinks
622 622 and indices.
623 623
624 624 Please see https://mercurial-scm.org/wiki/RepositoryCorruption for more
625 625 information about recovery from corruption of the repository.
626 626
627 627 Returns 0 on success, 1 if errors are encountered.
628 628
629 629 options:
630 630
631 631 (some details hidden, use --verbose to show complete help)
632 632
633 633 $ hg help diff
634 634 hg diff [OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...
635 635
636 636 diff repository (or selected files)
637 637
638 638 Show differences between revisions for the specified files.
639 639
640 640 Differences between files are shown using the unified diff format.
641 641
642 642 Note:
643 643 'hg diff' may generate unexpected results for merges, as it will
644 644 default to comparing against the working directory's first parent
645 645 changeset if no revisions are specified.
646 646
647 647 By default, the working directory files are compared to its first parent.
648 648 To see the differences from another revision, use --from. To see the
649 649 difference to another revision, use --to. For example, 'hg diff --from .^'
650 650 will show the differences from the working copy's grandparent to the
651 651 working copy, 'hg diff --to .' will show the diff from the working copy to
652 652 its parent (i.e. the reverse of the default), and 'hg diff --from 1.0 --to
653 653 1.2' will show the diff between those two revisions.
654 654
655 655 Alternatively you can specify -c/--change with a revision to see the
656 656 changes in that changeset relative to its first parent (i.e. 'hg diff -c
657 657 42' is equivalent to 'hg diff --from 42^ --to 42')
658 658
659 659 Without the -a/--text option, diff will avoid generating diffs of files it
660 660 detects as binary. With -a, diff will generate a diff anyway, probably
661 661 with undesirable results.
662 662
663 663 Use the -g/--git option to generate diffs in the git extended diff format.
664 664 For more information, read 'hg help diffs'.
665 665
666 666 Returns 0 on success.
667 667
668 668 options ([+] can be repeated):
669 669
670 670 --from REV1 revision to diff from
671 671 --to REV2 revision to diff to
672 672 -c --change REV change made by revision
673 673 -a --text treat all files as text
674 674 -g --git use git extended diff format
675 675 --binary generate binary diffs in git mode (default)
676 676 --nodates omit dates from diff headers
677 677 --noprefix omit a/ and b/ prefixes from filenames
678 678 -p --show-function show which function each change is in
679 679 --reverse produce a diff that undoes the changes
680 680 -w --ignore-all-space ignore white space when comparing lines
681 681 -b --ignore-space-change ignore changes in the amount of white space
682 682 -B --ignore-blank-lines ignore changes whose lines are all blank
683 683 -Z --ignore-space-at-eol ignore changes in whitespace at EOL
684 684 -U --unified NUM number of lines of context to show
685 685 --stat output diffstat-style summary of changes
686 686 --root DIR produce diffs relative to subdirectory
687 687 -I --include PATTERN [+] include names matching the given patterns
688 688 -X --exclude PATTERN [+] exclude names matching the given patterns
689 689 -S --subrepos recurse into subrepositories
690 690
691 691 (some details hidden, use --verbose to show complete help)
692 692
693 693 $ hg help status
694 694 hg status [OPTION]... [FILE]...
695 695
696 696 aliases: st
697 697
698 698 show changed files in the working directory
699 699
700 700 Show status of files in the repository. If names are given, only files
701 701 that match are shown. Files that are clean or ignored or the source of a
702 702 copy/move operation, are not listed unless -c/--clean, -i/--ignored,
703 703 -C/--copies or -A/--all are given. Unless options described with "show
704 704 only ..." are given, the options -mardu are used.
705 705
706 706 Option -q/--quiet hides untracked (unknown and ignored) files unless
707 707 explicitly requested with -u/--unknown or -i/--ignored.
708 708
709 709 Note:
710 710 'hg status' may appear to disagree with diff if permissions have
711 711 changed or a merge has occurred. The standard diff format does not
712 712 report permission changes and diff only reports changes relative to one
713 713 merge parent.
714 714
715 715 If one revision is given, it is used as the base revision. If two
716 716 revisions are given, the differences between them are shown. The --change
717 717 option can also be used as a shortcut to list the changed files of a
718 718 revision from its first parent.
719 719
720 720 The codes used to show the status of files are:
721 721
722 722 M = modified
723 723 A = added
724 724 R = removed
725 725 C = clean
726 726 ! = missing (deleted by non-hg command, but still tracked)
727 727 ? = not tracked
728 728 I = ignored
729 729 = origin of the previous file (with --copies)
730 730
731 731 Returns 0 on success.
732 732
733 733 options ([+] can be repeated):
734 734
735 735 -A --all show status of all files
736 736 -m --modified show only modified files
737 737 -a --added show only added files
738 738 -r --removed show only removed files
739 739 -d --deleted show only missing files
740 740 -c --clean show only files without changes
741 741 -u --unknown show only unknown (not tracked) files
742 742 -i --ignored show only ignored files
743 743 -n --no-status hide status prefix
744 744 -C --copies show source of copied files
745 745 -0 --print0 end filenames with NUL, for use with xargs
746 746 --rev REV [+] show difference from revision
747 747 --change REV list the changed files of a revision
748 748 -I --include PATTERN [+] include names matching the given patterns
749 749 -X --exclude PATTERN [+] exclude names matching the given patterns
750 750 -S --subrepos recurse into subrepositories
751 751 -T --template TEMPLATE display with template
752 752
753 753 (some details hidden, use --verbose to show complete help)
754 754
755 755 $ hg -q help status
756 756 hg status [OPTION]... [FILE]...
757 757
758 758 show changed files in the working directory
759 759
760 760 $ hg help foo
761 761 abort: no such help topic: foo
762 762 (try 'hg help --keyword foo')
763 763 [10]
764 764
765 765 $ hg skjdfks
766 766 hg: unknown command 'skjdfks'
767 767 (use 'hg help' for a list of commands)
768 768 [10]
769 769
770 770 Typoed command gives suggestion
771 771 $ hg puls
772 772 hg: unknown command 'puls'
773 773 (did you mean one of pull, push?)
774 774 [10]
775 775
776 776 Not enabled extension gets suggested
777 777
778 778 $ hg rebase
779 779 hg: unknown command 'rebase'
780 780 'rebase' is provided by the following extension:
781 781
782 782 rebase command to move sets of revisions to a different ancestor
783 783
784 784 (use 'hg help extensions' for information on enabling extensions)
785 785 [10]
786 786
787 787 Disabled extension gets suggested
788 788 $ hg --config extensions.rebase=! rebase
789 789 hg: unknown command 'rebase'
790 790 'rebase' is provided by the following extension:
791 791
792 792 rebase command to move sets of revisions to a different ancestor
793 793
794 794 (use 'hg help extensions' for information on enabling extensions)
795 795 [10]
796 796
797 797 Checking that help adapts based on the config:
798 798
799 799 $ hg help diff --config ui.tweakdefaults=true | egrep -e '^ *(-g|config)'
800 800 -g --[no-]git use git extended diff format (default: on from
801 801 config)
802 802
803 803 Make sure that we don't run afoul of the help system thinking that
804 804 this is a section and erroring out weirdly.
805 805
806 806 $ hg .log
807 807 hg: unknown command '.log'
808 808 (did you mean log?)
809 809 [10]
810 810
811 811 $ hg log.
812 812 hg: unknown command 'log.'
813 813 (did you mean log?)
814 814 [10]
815 815 $ hg pu.lh
816 816 hg: unknown command 'pu.lh'
817 817 (did you mean one of pull, push?)
818 818 [10]
819 819
820 820 $ cat > helpext.py <<EOF
821 821 > import os
822 822 > from mercurial import commands, fancyopts, registrar
823 823 >
824 824 > def func(arg):
825 825 > return '%sfoo' % arg
826 826 > class customopt(fancyopts.customopt):
827 827 > def newstate(self, oldstate, newparam, abort):
828 828 > return '%sbar' % oldstate
829 829 > cmdtable = {}
830 830 > command = registrar.command(cmdtable)
831 831 >
832 832 > @command(b'nohelp',
833 833 > [(b'', b'longdesc', 3, b'x'*67),
834 834 > (b'n', b'', None, b'normal desc'),
835 835 > (b'', b'newline', b'', b'line1\nline2'),
836 836 > (b'', b'default-off', False, b'enable X'),
837 837 > (b'', b'default-on', True, b'enable Y'),
838 838 > (b'', b'callableopt', func, b'adds foo'),
839 839 > (b'', b'customopt', customopt(''), b'adds bar'),
840 840 > (b'', b'customopt-withdefault', customopt('foo'), b'adds bar')],
841 841 > b'hg nohelp',
842 842 > norepo=True)
843 843 > @command(b'debugoptADV', [(b'', b'aopt', None, b'option is (ADVANCED)')])
844 844 > @command(b'debugoptDEP', [(b'', b'dopt', None, b'option is (DEPRECATED)')])
845 845 > @command(b'debugoptEXP', [(b'', b'eopt', None, b'option is (EXPERIMENTAL)')])
846 846 > def nohelp(ui, *args, **kwargs):
847 847 > pass
848 848 >
849 849 > @command(b'hashelp', [], b'hg hashelp', norepo=True)
850 850 > def hashelp(ui, *args, **kwargs):
851 851 > """Extension command's help"""
852 852 >
853 853 > def uisetup(ui):
854 854 > ui.setconfig(b'alias', b'shellalias', b'!echo hi', b'helpext')
855 855 > ui.setconfig(b'alias', b'hgalias', b'summary', b'helpext')
856 856 > ui.setconfig(b'alias', b'hgalias:doc', b'My doc', b'helpext')
857 857 > ui.setconfig(b'alias', b'hgalias:category', b'navigation', b'helpext')
858 858 > ui.setconfig(b'alias', b'hgaliasnodoc', b'summary', b'helpext')
859 859 >
860 860 > EOF
861 861 $ echo '[extensions]' >> $HGRCPATH
862 862 $ echo "helpext = `pwd`/helpext.py" >> $HGRCPATH
863 863
864 864 Test for aliases
865 865
866 866 $ hg help | grep hgalias
867 867 hgalias My doc
868 868
869 869 $ hg help hgalias
870 870 hg hgalias [--remote]
871 871
872 872 alias for: hg summary
873 873
874 874 My doc
875 875
876 876 defined by: helpext
877 877
878 878 options:
879 879
880 880 --remote check for push and pull
881 881
882 882 (some details hidden, use --verbose to show complete help)
883 883 $ hg help hgaliasnodoc
884 884 hg hgaliasnodoc [--remote]
885 885
886 886 alias for: hg summary
887 887
888 888 summarize working directory state
889 889
890 890 This generates a brief summary of the working directory state, including
891 891 parents, branch, commit status, phase and available updates.
892 892
893 893 With the --remote option, this will check the default paths for incoming
894 894 and outgoing changes. This can be time-consuming.
895 895
896 896 Returns 0 on success.
897 897
898 898 defined by: helpext
899 899
900 900 options:
901 901
902 902 --remote check for push and pull
903 903
904 904 (some details hidden, use --verbose to show complete help)
905 905
906 906 $ hg help shellalias
907 907 hg shellalias
908 908
909 909 shell alias for: echo hi
910 910
911 911 (no help text available)
912 912
913 913 defined by: helpext
914 914
915 915 (some details hidden, use --verbose to show complete help)
916 916
917 917 Test command with no help text
918 918
919 919 $ hg help nohelp
920 920 hg nohelp
921 921
922 922 (no help text available)
923 923
924 924 options:
925 925
926 926 --longdesc VALUE
927 927 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
928 928 xxxxxxxxxxxxxxxxxxxxxxx (default: 3)
929 929 -n -- normal desc
930 930 --newline VALUE line1 line2
931 931 --default-off enable X
932 932 --[no-]default-on enable Y (default: on)
933 933 --callableopt VALUE adds foo
934 934 --customopt VALUE adds bar
935 935 --customopt-withdefault VALUE adds bar (default: foo)
936 936
937 937 (some details hidden, use --verbose to show complete help)
938 938
939 939 Test that default list of commands includes extension commands that have help,
940 940 but not those that don't, except in verbose mode, when a keyword is passed, or
941 941 when help about the extension is requested.
942 942
943 943 #if no-extraextensions
944 944
945 945 $ hg help | grep hashelp
946 946 hashelp Extension command's help
947 947 $ hg help | grep nohelp
948 948 [1]
949 949 $ hg help -v | grep nohelp
950 950 nohelp (no help text available)
951 951
952 952 $ hg help -k nohelp
953 953 Commands:
954 954
955 955 nohelp hg nohelp
956 956
957 957 Extension Commands:
958 958
959 959 nohelp (no help text available)
960 960
961 961 $ hg help helpext
962 962 helpext extension - no help text available
963 963
964 964 list of commands:
965 965
966 966 hashelp Extension command's help
967 967 nohelp (no help text available)
968 968
969 969 (use 'hg help -v helpext' to show built-in aliases and global options)
970 970
971 971 #endif
972 972
973 973 Test list of internal help commands
974 974
975 975 $ hg help debug
976 976 debug commands (internal and unsupported):
977 977
978 debug-repair-issue6528
979 find affected revisions and repair them. See issue6528 for more
980 details.
978 981 debugancestor
979 982 find the ancestor revision of two revisions in a given index
980 983 debugantivirusrunning
981 984 attempt to trigger an antivirus scanner to see if one is active
982 985 debugapplystreamclonebundle
983 986 apply a stream clone bundle file
984 987 debugbackupbundle
985 988 lists the changesets available in backup bundles
986 989 debugbuilddag
987 990 builds a repo with a given DAG from scratch in the current
988 991 empty repo
989 992 debugbundle lists the contents of a bundle
990 993 debugcapabilities
991 994 lists the capabilities of a remote peer
992 995 debugchangedfiles
993 996 list the stored files changes for a revision
994 997 debugcheckstate
995 998 validate the correctness of the current dirstate
996 999 debugcolor show available color, effects or style
997 1000 debugcommands
998 1001 list all available commands and options
999 1002 debugcomplete
1000 1003 returns the completion list associated with the given command
1001 1004 debugcreatestreamclonebundle
1002 1005 create a stream clone bundle file
1003 1006 debugdag format the changelog or an index DAG as a concise textual
1004 1007 description
1005 1008 debugdata dump the contents of a data file revision
1006 1009 debugdate parse and display a date
1007 1010 debugdeltachain
1008 1011 dump information about delta chains in a revlog
1009 1012 debugdirstate
1010 1013 show the contents of the current dirstate
1011 1014 debugdirstateignorepatternshash
1012 1015 show the hash of ignore patterns stored in dirstate if v2,
1013 1016 debugdiscovery
1014 1017 runs the changeset discovery protocol in isolation
1015 1018 debugdownload
1016 1019 download a resource using Mercurial logic and config
1017 1020 debugextensions
1018 1021 show information about active extensions
1019 1022 debugfileset parse and apply a fileset specification
1020 1023 debugformat display format information about the current repository
1021 1024 debugfsinfo show information detected about current filesystem
1022 1025 debuggetbundle
1023 1026 retrieves a bundle from a repo
1024 1027 debugignore display the combined ignore pattern and information about
1025 1028 ignored files
1026 1029 debugindex dump index data for a storage primitive
1027 1030 debugindexdot
1028 1031 dump an index DAG as a graphviz dot file
1029 1032 debugindexstats
1030 1033 show stats related to the changelog index
1031 1034 debuginstall test Mercurial installation
1032 1035 debugknown test whether node ids are known to a repo
1033 1036 debuglocks show or modify state of locks
1034 1037 debugmanifestfulltextcache
1035 1038 show, clear or amend the contents of the manifest fulltext
1036 1039 cache
1037 1040 debugmergestate
1038 1041 print merge state
1039 1042 debugnamecomplete
1040 1043 complete "names" - tags, open branch names, bookmark names
1041 1044 debugnodemap write and inspect on disk nodemap
1042 1045 debugobsolete
1043 1046 create arbitrary obsolete marker
1044 1047 debugoptADV (no help text available)
1045 1048 debugoptDEP (no help text available)
1046 1049 debugoptEXP (no help text available)
1047 1050 debugp1copies
1048 1051 dump copy information compared to p1
1049 1052 debugp2copies
1050 1053 dump copy information compared to p2
1051 1054 debugpathcomplete
1052 1055 complete part or all of a tracked path
1053 1056 debugpathcopies
1054 1057 show copies between two revisions
1055 1058 debugpeer establish a connection to a peer repository
1056 1059 debugpickmergetool
1057 1060 examine which merge tool is chosen for specified file
1058 1061 debugpushkey access the pushkey key/value protocol
1059 1062 debugpvec (no help text available)
1060 1063 debugrebuilddirstate
1061 1064 rebuild the dirstate as it would look like for the given
1062 1065 revision
1063 1066 debugrebuildfncache
1064 1067 rebuild the fncache file
1065 1068 debugrename dump rename information
1066 1069 debugrequires
1067 1070 print the current repo requirements
1068 1071 debugrevlog show data and statistics about a revlog
1069 1072 debugrevlogindex
1070 1073 dump the contents of a revlog index
1071 1074 debugrevspec parse and apply a revision specification
1072 1075 debugserve run a server with advanced settings
1073 1076 debugsetparents
1074 1077 manually set the parents of the current working directory
1075 1078 (DANGEROUS)
1076 1079 debugshell run an interactive Python interpreter
1077 1080 debugsidedata
1078 1081 dump the side data for a cl/manifest/file revision
1079 1082 debugssl test a secure connection to a server
1080 1083 debugstrip strip changesets and all their descendants from the repository
1081 1084 debugsub (no help text available)
1082 1085 debugsuccessorssets
1083 1086 show set of successors for revision
1084 1087 debugtagscache
1085 1088 display the contents of .hg/cache/hgtagsfnodes1
1086 1089 debugtemplate
1087 1090 parse and apply a template
1088 1091 debuguigetpass
1089 1092 show prompt to type password
1090 1093 debuguiprompt
1091 1094 show plain prompt
1092 1095 debugupdatecaches
1093 1096 warm all known caches in the repository
1094 1097 debugupgraderepo
1095 1098 upgrade a repository to use different features
1096 1099 debugwalk show how files match on given patterns
1097 1100 debugwhyunstable
1098 1101 explain instabilities of a changeset
1099 1102 debugwireargs
1100 1103 (no help text available)
1101 1104 debugwireproto
1102 1105 send wire protocol commands to a server
1103 1106
1104 1107 (use 'hg help -v debug' to show built-in aliases and global options)
1105 1108
1106 1109 internals topic renders index of available sub-topics
1107 1110
1108 1111 $ hg help internals
1109 1112 Technical implementation topics
1110 1113 """""""""""""""""""""""""""""""
1111 1114
1112 1115 To access a subtopic, use "hg help internals.{subtopic-name}"
1113 1116
1114 1117 bid-merge Bid Merge Algorithm
1115 1118 bundle2 Bundle2
1116 1119 bundles Bundles
1117 1120 cbor CBOR
1118 1121 censor Censor
1119 1122 changegroups Changegroups
1120 1123 config Config Registrar
1121 1124 extensions Extension API
1122 1125 mergestate Mergestate
1123 1126 requirements Repository Requirements
1124 1127 revlogs Revision Logs
1125 1128 wireprotocol Wire Protocol
1126 1129 wireprotocolrpc
1127 1130 Wire Protocol RPC
1128 1131 wireprotocolv2
1129 1132 Wire Protocol Version 2
1130 1133
1131 1134 sub-topics can be accessed
1132 1135
1133 1136 $ hg help internals.changegroups
1134 1137 Changegroups
1135 1138 """"""""""""
1136 1139
1137 1140 Changegroups are representations of repository revlog data, specifically
1138 1141 the changelog data, root/flat manifest data, treemanifest data, and
1139 1142 filelogs.
1140 1143
1141 1144 There are 4 versions of changegroups: "1", "2", "3" and "4". From a high-
1142 1145 level, versions "1" and "2" are almost exactly the same, with the only
1143 1146 difference being an additional item in the *delta header*. Version "3"
1144 1147 adds support for storage flags in the *delta header* and optionally
1145 1148 exchanging treemanifests (enabled by setting an option on the
1146 1149 "changegroup" part in the bundle2). Version "4" adds support for
1147 1150 exchanging sidedata (additional revision metadata not part of the digest).
1148 1151
1149 1152 Changegroups when not exchanging treemanifests consist of 3 logical
1150 1153 segments:
1151 1154
1152 1155 +---------------------------------+
1153 1156 | | | |
1154 1157 | changeset | manifest | filelogs |
1155 1158 | | | |
1156 1159 | | | |
1157 1160 +---------------------------------+
1158 1161
1159 1162 When exchanging treemanifests, there are 4 logical segments:
1160 1163
1161 1164 +-------------------------------------------------+
1162 1165 | | | | |
1163 1166 | changeset | root | treemanifests | filelogs |
1164 1167 | | manifest | | |
1165 1168 | | | | |
1166 1169 +-------------------------------------------------+
1167 1170
1168 1171 The principle building block of each segment is a *chunk*. A *chunk* is a
1169 1172 framed piece of data:
1170 1173
1171 1174 +---------------------------------------+
1172 1175 | | |
1173 1176 | length | data |
1174 1177 | (4 bytes) | (<length - 4> bytes) |
1175 1178 | | |
1176 1179 +---------------------------------------+
1177 1180
1178 1181 All integers are big-endian signed integers. Each chunk starts with a
1179 1182 32-bit integer indicating the length of the entire chunk (including the
1180 1183 length field itself).
1181 1184
1182 1185 There is a special case chunk that has a value of 0 for the length
1183 1186 ("0x00000000"). We call this an *empty chunk*.
1184 1187
1185 1188 Delta Groups
1186 1189 ============
1187 1190
1188 1191 A *delta group* expresses the content of a revlog as a series of deltas,
1189 1192 or patches against previous revisions.
1190 1193
1191 1194 Delta groups consist of 0 or more *chunks* followed by the *empty chunk*
1192 1195 to signal the end of the delta group:
1193 1196
1194 1197 +------------------------------------------------------------------------+
1195 1198 | | | | | |
1196 1199 | chunk0 length | chunk0 data | chunk1 length | chunk1 data | 0x0 |
1197 1200 | (4 bytes) | (various) | (4 bytes) | (various) | (4 bytes) |
1198 1201 | | | | | |
1199 1202 +------------------------------------------------------------------------+
1200 1203
1201 1204 Each *chunk*'s data consists of the following:
1202 1205
1203 1206 +---------------------------------------+
1204 1207 | | |
1205 1208 | delta header | delta data |
1206 1209 | (various by version) | (various) |
1207 1210 | | |
1208 1211 +---------------------------------------+
1209 1212
1210 1213 The *delta data* is a series of *delta*s that describe a diff from an
1211 1214 existing entry (either that the recipient already has, or previously
1212 1215 specified in the bundle/changegroup).
1213 1216
1214 1217 The *delta header* is different between versions "1", "2", "3" and "4" of
1215 1218 the changegroup format.
1216 1219
1217 1220 Version 1 (headerlen=80):
1218 1221
1219 1222 +------------------------------------------------------+
1220 1223 | | | | |
1221 1224 | node | p1 node | p2 node | link node |
1222 1225 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
1223 1226 | | | | |
1224 1227 +------------------------------------------------------+
1225 1228
1226 1229 Version 2 (headerlen=100):
1227 1230
1228 1231 +------------------------------------------------------------------+
1229 1232 | | | | | |
1230 1233 | node | p1 node | p2 node | base node | link node |
1231 1234 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
1232 1235 | | | | | |
1233 1236 +------------------------------------------------------------------+
1234 1237
1235 1238 Version 3 (headerlen=102):
1236 1239
1237 1240 +------------------------------------------------------------------------------+
1238 1241 | | | | | | |
1239 1242 | node | p1 node | p2 node | base node | link node | flags |
1240 1243 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (2 bytes) |
1241 1244 | | | | | | |
1242 1245 +------------------------------------------------------------------------------+
1243 1246
1244 1247 Version 4 (headerlen=103):
1245 1248
1246 1249 +------------------------------------------------------------------------------+----------+
1247 1250 | | | | | | | |
1248 1251 | node | p1 node | p2 node | base node | link node | flags | pflags |
1249 1252 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (2 bytes) | (1 byte) |
1250 1253 | | | | | | | |
1251 1254 +------------------------------------------------------------------------------+----------+
1252 1255
1253 1256 The *delta data* consists of "chunklen - 4 - headerlen" bytes, which
1254 1257 contain a series of *delta*s, densely packed (no separators). These deltas
1255 1258 describe a diff from an existing entry (either that the recipient already
1256 1259 has, or previously specified in the bundle/changegroup). The format is
1257 1260 described more fully in "hg help internals.bdiff", but briefly:
1258 1261
1259 1262 +---------------------------------------------------------------+
1260 1263 | | | | |
1261 1264 | start offset | end offset | new length | content |
1262 1265 | (4 bytes) | (4 bytes) | (4 bytes) | (<new length> bytes) |
1263 1266 | | | | |
1264 1267 +---------------------------------------------------------------+
1265 1268
1266 1269 Please note that the length field in the delta data does *not* include
1267 1270 itself.
1268 1271
1269 1272 In version 1, the delta is always applied against the previous node from
1270 1273 the changegroup or the first parent if this is the first entry in the
1271 1274 changegroup.
1272 1275
1273 1276 In version 2 and up, the delta base node is encoded in the entry in the
1274 1277 changegroup. This allows the delta to be expressed against any parent,
1275 1278 which can result in smaller deltas and more efficient encoding of data.
1276 1279
1277 1280 The *flags* field holds bitwise flags affecting the processing of revision
1278 1281 data. The following flags are defined:
1279 1282
1280 1283 32768
1281 1284 Censored revision. The revision's fulltext has been replaced by censor
1282 1285 metadata. May only occur on file revisions.
1283 1286
1284 1287 16384
1285 1288 Ellipsis revision. Revision hash does not match data (likely due to
1286 1289 rewritten parents).
1287 1290
1288 1291 8192
1289 1292 Externally stored. The revision fulltext contains "key:value" "\n"
1290 1293 delimited metadata defining an object stored elsewhere. Used by the LFS
1291 1294 extension.
1292 1295
1293 1296 4096
1294 1297 Contains copy information. This revision changes files in a way that
1295 1298 could affect copy tracing. This does *not* affect changegroup handling,
1296 1299 but is relevant for other parts of Mercurial.
1297 1300
1298 1301 For historical reasons, the integer values are identical to revlog version
1299 1302 1 per-revision storage flags and correspond to bits being set in this
1300 1303 2-byte field. Bits were allocated starting from the most-significant bit,
1301 1304 hence the reverse ordering and allocation of these flags.
1302 1305
1303 1306 The *pflags* (protocol flags) field holds bitwise flags affecting the
1304 1307 protocol itself. They are first in the header since they may affect the
1305 1308 handling of the rest of the fields in a future version. They are defined
1306 1309 as such:
1307 1310
1308 1311 1 indicates whether to read a chunk of sidedata (of variable length) right
1309 1312 after the revision flags.
1310 1313
1311 1314 Changeset Segment
1312 1315 =================
1313 1316
1314 1317 The *changeset segment* consists of a single *delta group* holding
1315 1318 changelog data. The *empty chunk* at the end of the *delta group* denotes
1316 1319 the boundary to the *manifest segment*.
1317 1320
1318 1321 Manifest Segment
1319 1322 ================
1320 1323
1321 1324 The *manifest segment* consists of a single *delta group* holding manifest
1322 1325 data. If treemanifests are in use, it contains only the manifest for the
1323 1326 root directory of the repository. Otherwise, it contains the entire
1324 1327 manifest data. The *empty chunk* at the end of the *delta group* denotes
1325 1328 the boundary to the next segment (either the *treemanifests segment* or
1326 1329 the *filelogs segment*, depending on version and the request options).
1327 1330
1328 1331 Treemanifests Segment
1329 1332 ---------------------
1330 1333
1331 1334 The *treemanifests segment* only exists in changegroup version "3" and
1332 1335 "4", and only if the 'treemanifest' param is part of the bundle2
1333 1336 changegroup part (it is not possible to use changegroup version 3 or 4
1334 1337 outside of bundle2). Aside from the filenames in the *treemanifests
1335 1338 segment* containing a trailing "/" character, it behaves identically to
1336 1339 the *filelogs segment* (see below). The final sub-segment is followed by
1337 1340 an *empty chunk* (logically, a sub-segment with filename size 0). This
1338 1341 denotes the boundary to the *filelogs segment*.
1339 1342
1340 1343 Filelogs Segment
1341 1344 ================
1342 1345
1343 1346 The *filelogs segment* consists of multiple sub-segments, each
1344 1347 corresponding to an individual file whose data is being described:
1345 1348
1346 1349 +--------------------------------------------------+
1347 1350 | | | | | |
1348 1351 | filelog0 | filelog1 | filelog2 | ... | 0x0 |
1349 1352 | | | | | (4 bytes) |
1350 1353 | | | | | |
1351 1354 +--------------------------------------------------+
1352 1355
1353 1356 The final filelog sub-segment is followed by an *empty chunk* (logically,
1354 1357 a sub-segment with filename size 0). This denotes the end of the segment
1355 1358 and of the overall changegroup.
1356 1359
1357 1360 Each filelog sub-segment consists of the following:
1358 1361
1359 1362 +------------------------------------------------------+
1360 1363 | | | |
1361 1364 | filename length | filename | delta group |
1362 1365 | (4 bytes) | (<length - 4> bytes) | (various) |
1363 1366 | | | |
1364 1367 +------------------------------------------------------+
1365 1368
1366 1369 That is, a *chunk* consisting of the filename (not terminated or padded)
1367 1370 followed by N chunks constituting the *delta group* for this file. The
1368 1371 *empty chunk* at the end of each *delta group* denotes the boundary to the
1369 1372 next filelog sub-segment.
1370 1373
1371 1374 non-existent subtopics print an error
1372 1375
1373 1376 $ hg help internals.foo
1374 1377 abort: no such help topic: internals.foo
1375 1378 (try 'hg help --keyword foo')
1376 1379 [10]
1377 1380
1378 1381 test advanced, deprecated and experimental options are hidden in command help
1379 1382 $ hg help debugoptADV
1380 1383 hg debugoptADV
1381 1384
1382 1385 (no help text available)
1383 1386
1384 1387 options:
1385 1388
1386 1389 (some details hidden, use --verbose to show complete help)
1387 1390 $ hg help debugoptDEP
1388 1391 hg debugoptDEP
1389 1392
1390 1393 (no help text available)
1391 1394
1392 1395 options:
1393 1396
1394 1397 (some details hidden, use --verbose to show complete help)
1395 1398
1396 1399 $ hg help debugoptEXP
1397 1400 hg debugoptEXP
1398 1401
1399 1402 (no help text available)
1400 1403
1401 1404 options:
1402 1405
1403 1406 (some details hidden, use --verbose to show complete help)
1404 1407
1405 1408 test advanced, deprecated and experimental options are shown with -v
1406 1409 $ hg help -v debugoptADV | grep aopt
1407 1410 --aopt option is (ADVANCED)
1408 1411 $ hg help -v debugoptDEP | grep dopt
1409 1412 --dopt option is (DEPRECATED)
1410 1413 $ hg help -v debugoptEXP | grep eopt
1411 1414 --eopt option is (EXPERIMENTAL)
1412 1415
1413 1416 #if gettext
1414 1417 test deprecated option is hidden with translation with untranslated description
1415 1418 (use many globy for not failing on changed transaction)
1416 1419 $ LANGUAGE=sv hg help debugoptDEP
1417 1420 hg debugoptDEP
1418 1421
1419 1422 (*) (glob)
1420 1423
1421 1424 options:
1422 1425
1423 1426 (some details hidden, use --verbose to show complete help)
1424 1427 #endif
1425 1428
1426 1429 Test commands that collide with topics (issue4240)
1427 1430
1428 1431 $ hg config -hq
1429 1432 hg config [-u] [NAME]...
1430 1433
1431 1434 show combined config settings from all hgrc files
1432 1435 $ hg showconfig -hq
1433 1436 hg config [-u] [NAME]...
1434 1437
1435 1438 show combined config settings from all hgrc files
1436 1439
1437 1440 Test a help topic
1438 1441
1439 1442 $ hg help dates
1440 1443 Date Formats
1441 1444 """"""""""""
1442 1445
1443 1446 Some commands allow the user to specify a date, e.g.:
1444 1447
1445 1448 - backout, commit, import, tag: Specify the commit date.
1446 1449 - log, revert, update: Select revision(s) by date.
1447 1450
1448 1451 Many date formats are valid. Here are some examples:
1449 1452
1450 1453 - "Wed Dec 6 13:18:29 2006" (local timezone assumed)
1451 1454 - "Dec 6 13:18 -0600" (year assumed, time offset provided)
1452 1455 - "Dec 6 13:18 UTC" (UTC and GMT are aliases for +0000)
1453 1456 - "Dec 6" (midnight)
1454 1457 - "13:18" (today assumed)
1455 1458 - "3:39" (3:39AM assumed)
1456 1459 - "3:39pm" (15:39)
1457 1460 - "2006-12-06 13:18:29" (ISO 8601 format)
1458 1461 - "2006-12-6 13:18"
1459 1462 - "2006-12-6"
1460 1463 - "12-6"
1461 1464 - "12/6"
1462 1465 - "12/6/6" (Dec 6 2006)
1463 1466 - "today" (midnight)
1464 1467 - "yesterday" (midnight)
1465 1468 - "now" - right now
1466 1469
1467 1470 Lastly, there is Mercurial's internal format:
1468 1471
1469 1472 - "1165411109 0" (Wed Dec 6 13:18:29 2006 UTC)
1470 1473
1471 1474 This is the internal representation format for dates. The first number is
1472 1475 the number of seconds since the epoch (1970-01-01 00:00 UTC). The second
1473 1476 is the offset of the local timezone, in seconds west of UTC (negative if
1474 1477 the timezone is east of UTC).
1475 1478
1476 1479 The log command also accepts date ranges:
1477 1480
1478 1481 - "<DATE" - at or before a given date/time
1479 1482 - ">DATE" - on or after a given date/time
1480 1483 - "DATE to DATE" - a date range, inclusive
1481 1484 - "-DAYS" - within a given number of days from today
1482 1485
1483 1486 Test repeated config section name
1484 1487
1485 1488 $ hg help config.host
1486 1489 "http_proxy.host"
1487 1490 Host name and (optional) port of the proxy server, for example
1488 1491 "myproxy:8000".
1489 1492
1490 1493 "smtp.host"
1491 1494 Host name of mail server, e.g. "mail.example.com".
1492 1495
1493 1496
1494 1497 Test section name with dot
1495 1498
1496 1499 $ hg help config.ui.username
1497 1500 "ui.username"
1498 1501 The committer of a changeset created when running "commit". Typically
1499 1502 a person's name and email address, e.g. "Fred Widget
1500 1503 <fred@example.com>". Environment variables in the username are
1501 1504 expanded.
1502 1505
1503 1506 (default: "$EMAIL" or "username@hostname". If the username in hgrc is
1504 1507 empty, e.g. if the system admin set "username =" in the system hgrc,
1505 1508 it has to be specified manually or in a different hgrc file)
1506 1509
1507 1510
1508 1511 $ hg help config.annotate.git
1509 1512 abort: help section not found: config.annotate.git
1510 1513 [10]
1511 1514
1512 1515 $ hg help config.update.check
1513 1516 "commands.update.check"
1514 1517 Determines what level of checking 'hg update' will perform before
1515 1518 moving to a destination revision. Valid values are "abort", "none",
1516 1519 "linear", and "noconflict". "abort" always fails if the working
1517 1520 directory has uncommitted changes. "none" performs no checking, and
1518 1521 may result in a merge with uncommitted changes. "linear" allows any
1519 1522 update as long as it follows a straight line in the revision history,
1520 1523 and may trigger a merge with uncommitted changes. "noconflict" will
1521 1524 allow any update which would not trigger a merge with uncommitted
1522 1525 changes, if any are present. (default: "linear")
1523 1526
1524 1527
1525 1528 $ hg help config.commands.update.check
1526 1529 "commands.update.check"
1527 1530 Determines what level of checking 'hg update' will perform before
1528 1531 moving to a destination revision. Valid values are "abort", "none",
1529 1532 "linear", and "noconflict". "abort" always fails if the working
1530 1533 directory has uncommitted changes. "none" performs no checking, and
1531 1534 may result in a merge with uncommitted changes. "linear" allows any
1532 1535 update as long as it follows a straight line in the revision history,
1533 1536 and may trigger a merge with uncommitted changes. "noconflict" will
1534 1537 allow any update which would not trigger a merge with uncommitted
1535 1538 changes, if any are present. (default: "linear")
1536 1539
1537 1540
1538 1541 $ hg help config.ommands.update.check
1539 1542 abort: help section not found: config.ommands.update.check
1540 1543 [10]
1541 1544
1542 1545 Unrelated trailing paragraphs shouldn't be included
1543 1546
1544 1547 $ hg help config.extramsg | grep '^$'
1545 1548
1546 1549
1547 1550 Test capitalized section name
1548 1551
1549 1552 $ hg help scripting.HGPLAIN > /dev/null
1550 1553
1551 1554 Help subsection:
1552 1555
1553 1556 $ hg help config.charsets |grep "Email example:" > /dev/null
1554 1557 [1]
1555 1558
1556 1559 Show nested definitions
1557 1560 ("profiling.type"[break]"ls"[break]"stat"[break])
1558 1561
1559 1562 $ hg help config.type | egrep '^$'|wc -l
1560 1563 \s*3 (re)
1561 1564
1562 1565 $ hg help config.profiling.type.ls
1563 1566 "profiling.type.ls"
1564 1567 Use Python's built-in instrumenting profiler. This profiler works on
1565 1568 all platforms, but each line number it reports is the first line of
1566 1569 a function. This restriction makes it difficult to identify the
1567 1570 expensive parts of a non-trivial function.
1568 1571
1569 1572
1570 1573 Separate sections from subsections
1571 1574
1572 1575 $ hg help config.format | egrep '^ ("|-)|^\s*$' | uniq
1573 1576 "format"
1574 1577 --------
1575 1578
1576 1579 "usegeneraldelta"
1577 1580
1578 1581 "dotencode"
1579 1582
1580 1583 "usefncache"
1581 1584
1582 1585 "use-persistent-nodemap"
1583 1586
1584 1587 "use-share-safe"
1585 1588
1586 1589 "usestore"
1587 1590
1588 1591 "sparse-revlog"
1589 1592
1590 1593 "revlog-compression"
1591 1594
1592 1595 "bookmarks-in-store"
1593 1596
1594 1597 "profiling"
1595 1598 -----------
1596 1599
1597 1600 "format"
1598 1601
1599 1602 "progress"
1600 1603 ----------
1601 1604
1602 1605 "format"
1603 1606
1604 1607
1605 1608 Last item in help config.*:
1606 1609
1607 1610 $ hg help config.`hg help config|grep '^ "'| \
1608 1611 > tail -1|sed 's![ "]*!!g'`| \
1609 1612 > grep 'hg help -c config' > /dev/null
1610 1613 [1]
1611 1614
1612 1615 note to use help -c for general hg help config:
1613 1616
1614 1617 $ hg help config |grep 'hg help -c config' > /dev/null
1615 1618
1616 1619 Test templating help
1617 1620
1618 1621 $ hg help templating | egrep '(desc|diffstat|firstline|nonempty) '
1619 1622 desc String. The text of the changeset description.
1620 1623 diffstat String. Statistics of changes with the following format:
1621 1624 firstline Any text. Returns the first line of text.
1622 1625 nonempty Any text. Returns '(none)' if the string is empty.
1623 1626
1624 1627 Test deprecated items
1625 1628
1626 1629 $ hg help -v templating | grep currentbookmark
1627 1630 currentbookmark
1628 1631 $ hg help templating | (grep currentbookmark || true)
1629 1632
1630 1633 Test help hooks
1631 1634
1632 1635 $ cat > helphook1.py <<EOF
1633 1636 > from mercurial import help
1634 1637 >
1635 1638 > def rewrite(ui, topic, doc):
1636 1639 > return doc + b'\nhelphook1\n'
1637 1640 >
1638 1641 > def extsetup(ui):
1639 1642 > help.addtopichook(b'revisions', rewrite)
1640 1643 > EOF
1641 1644 $ cat > helphook2.py <<EOF
1642 1645 > from mercurial import help
1643 1646 >
1644 1647 > def rewrite(ui, topic, doc):
1645 1648 > return doc + b'\nhelphook2\n'
1646 1649 >
1647 1650 > def extsetup(ui):
1648 1651 > help.addtopichook(b'revisions', rewrite)
1649 1652 > EOF
1650 1653 $ echo '[extensions]' >> $HGRCPATH
1651 1654 $ echo "helphook1 = `pwd`/helphook1.py" >> $HGRCPATH
1652 1655 $ echo "helphook2 = `pwd`/helphook2.py" >> $HGRCPATH
1653 1656 $ hg help revsets | grep helphook
1654 1657 helphook1
1655 1658 helphook2
1656 1659
1657 1660 help -c should only show debug --debug
1658 1661
1659 1662 $ hg help -c --debug|egrep debug|wc -l|egrep '^\s*0\s*$'
1660 1663 [1]
1661 1664
1662 1665 help -c should only show deprecated for -v
1663 1666
1664 1667 $ hg help -c -v|egrep DEPRECATED|wc -l|egrep '^\s*0\s*$'
1665 1668 [1]
1666 1669
1667 1670 Test -s / --system
1668 1671
1669 1672 $ hg help config.files -s windows |grep 'etc/mercurial' | \
1670 1673 > wc -l | sed -e 's/ //g'
1671 1674 0
1672 1675 $ hg help config.files --system unix | grep 'USER' | \
1673 1676 > wc -l | sed -e 's/ //g'
1674 1677 0
1675 1678
1676 1679 Test -e / -c / -k combinations
1677 1680
1678 1681 $ hg help -c|egrep '^[A-Z].*:|^ debug'
1679 1682 Commands:
1680 1683 $ hg help -e|egrep '^[A-Z].*:|^ debug'
1681 1684 Extensions:
1682 1685 $ hg help -k|egrep '^[A-Z].*:|^ debug'
1683 1686 Topics:
1684 1687 Commands:
1685 1688 Extensions:
1686 1689 Extension Commands:
1687 1690 $ hg help -c schemes
1688 1691 abort: no such help topic: schemes
1689 1692 (try 'hg help --keyword schemes')
1690 1693 [10]
1691 1694 $ hg help -e schemes |head -1
1692 1695 schemes extension - extend schemes with shortcuts to repository swarms
1693 1696 $ hg help -c -k dates |egrep '^(Topics|Extensions|Commands):'
1694 1697 Commands:
1695 1698 $ hg help -e -k a |egrep '^(Topics|Extensions|Commands):'
1696 1699 Extensions:
1697 1700 $ hg help -e -c -k date |egrep '^(Topics|Extensions|Commands):'
1698 1701 Extensions:
1699 1702 Commands:
1700 1703 $ hg help -c commit > /dev/null
1701 1704 $ hg help -e -c commit > /dev/null
1702 1705 $ hg help -e commit
1703 1706 abort: no such help topic: commit
1704 1707 (try 'hg help --keyword commit')
1705 1708 [10]
1706 1709
1707 1710 Test keyword search help
1708 1711
1709 1712 $ cat > prefixedname.py <<EOF
1710 1713 > '''matched against word "clone"
1711 1714 > '''
1712 1715 > EOF
1713 1716 $ echo '[extensions]' >> $HGRCPATH
1714 1717 $ echo "dot.dot.prefixedname = `pwd`/prefixedname.py" >> $HGRCPATH
1715 1718 $ hg help -k clone
1716 1719 Topics:
1717 1720
1718 1721 config Configuration Files
1719 1722 extensions Using Additional Features
1720 1723 glossary Glossary
1721 1724 phases Working with Phases
1722 1725 subrepos Subrepositories
1723 1726 urls URL Paths
1724 1727
1725 1728 Commands:
1726 1729
1727 1730 bookmarks create a new bookmark or list existing bookmarks
1728 1731 clone make a copy of an existing repository
1729 1732 paths show aliases for remote repositories
1730 1733 pull pull changes from the specified source
1731 1734 update update working directory (or switch revisions)
1732 1735
1733 1736 Extensions:
1734 1737
1735 1738 clonebundles advertise pre-generated bundles to seed clones
1736 1739 narrow create clones which fetch history data for subset of files
1737 1740 (EXPERIMENTAL)
1738 1741 prefixedname matched against word "clone"
1739 1742 relink recreates hardlinks between repository clones
1740 1743
1741 1744 Extension Commands:
1742 1745
1743 1746 qclone clone main and patch repository at same time
1744 1747
1745 1748 Test unfound topic
1746 1749
1747 1750 $ hg help nonexistingtopicthatwillneverexisteverever
1748 1751 abort: no such help topic: nonexistingtopicthatwillneverexisteverever
1749 1752 (try 'hg help --keyword nonexistingtopicthatwillneverexisteverever')
1750 1753 [10]
1751 1754
1752 1755 Test unfound keyword
1753 1756
1754 1757 $ hg help --keyword nonexistingwordthatwillneverexisteverever
1755 1758 abort: no matches
1756 1759 (try 'hg help' for a list of topics)
1757 1760 [10]
1758 1761
1759 1762 Test omit indicating for help
1760 1763
1761 1764 $ cat > addverboseitems.py <<EOF
1762 1765 > r'''extension to test omit indicating.
1763 1766 >
1764 1767 > This paragraph is never omitted (for extension)
1765 1768 >
1766 1769 > .. container:: verbose
1767 1770 >
1768 1771 > This paragraph is omitted,
1769 1772 > if :hg:\`help\` is invoked without \`\`-v\`\` (for extension)
1770 1773 >
1771 1774 > This paragraph is never omitted, too (for extension)
1772 1775 > '''
1773 1776 > from __future__ import absolute_import
1774 1777 > from mercurial import commands, help
1775 1778 > testtopic = br"""This paragraph is never omitted (for topic).
1776 1779 >
1777 1780 > .. container:: verbose
1778 1781 >
1779 1782 > This paragraph is omitted,
1780 1783 > if :hg:\`help\` is invoked without \`\`-v\`\` (for topic)
1781 1784 >
1782 1785 > This paragraph is never omitted, too (for topic)
1783 1786 > """
1784 1787 > def extsetup(ui):
1785 1788 > help.helptable.append(([b"topic-containing-verbose"],
1786 1789 > b"This is the topic to test omit indicating.",
1787 1790 > lambda ui: testtopic))
1788 1791 > EOF
1789 1792 $ echo '[extensions]' >> $HGRCPATH
1790 1793 $ echo "addverboseitems = `pwd`/addverboseitems.py" >> $HGRCPATH
1791 1794 $ hg help addverboseitems
1792 1795 addverboseitems extension - extension to test omit indicating.
1793 1796
1794 1797 This paragraph is never omitted (for extension)
1795 1798
1796 1799 This paragraph is never omitted, too (for extension)
1797 1800
1798 1801 (some details hidden, use --verbose to show complete help)
1799 1802
1800 1803 no commands defined
1801 1804 $ hg help -v addverboseitems
1802 1805 addverboseitems extension - extension to test omit indicating.
1803 1806
1804 1807 This paragraph is never omitted (for extension)
1805 1808
1806 1809 This paragraph is omitted, if 'hg help' is invoked without "-v" (for
1807 1810 extension)
1808 1811
1809 1812 This paragraph is never omitted, too (for extension)
1810 1813
1811 1814 no commands defined
1812 1815 $ hg help topic-containing-verbose
1813 1816 This is the topic to test omit indicating.
1814 1817 """"""""""""""""""""""""""""""""""""""""""
1815 1818
1816 1819 This paragraph is never omitted (for topic).
1817 1820
1818 1821 This paragraph is never omitted, too (for topic)
1819 1822
1820 1823 (some details hidden, use --verbose to show complete help)
1821 1824 $ hg help -v topic-containing-verbose
1822 1825 This is the topic to test omit indicating.
1823 1826 """"""""""""""""""""""""""""""""""""""""""
1824 1827
1825 1828 This paragraph is never omitted (for topic).
1826 1829
1827 1830 This paragraph is omitted, if 'hg help' is invoked without "-v" (for
1828 1831 topic)
1829 1832
1830 1833 This paragraph is never omitted, too (for topic)
1831 1834
1832 1835 Test section lookup
1833 1836
1834 1837 $ hg help revset.merge
1835 1838 "merge()"
1836 1839 Changeset is a merge changeset.
1837 1840
1838 1841 $ hg help glossary.dag
1839 1842 DAG
1840 1843 The repository of changesets of a distributed version control system
1841 1844 (DVCS) can be described as a directed acyclic graph (DAG), consisting
1842 1845 of nodes and edges, where nodes correspond to changesets and edges
1843 1846 imply a parent -> child relation. This graph can be visualized by
1844 1847 graphical tools such as 'hg log --graph'. In Mercurial, the DAG is
1845 1848 limited by the requirement for children to have at most two parents.
1846 1849
1847 1850
1848 1851 $ hg help hgrc.paths
1849 1852 "paths"
1850 1853 -------
1851 1854
1852 1855 Assigns symbolic names and behavior to repositories.
1853 1856
1854 1857 Options are symbolic names defining the URL or directory that is the
1855 1858 location of the repository. Example:
1856 1859
1857 1860 [paths]
1858 1861 my_server = https://example.com/my_repo
1859 1862 local_path = /home/me/repo
1860 1863
1861 1864 These symbolic names can be used from the command line. To pull from
1862 1865 "my_server": 'hg pull my_server'. To push to "local_path": 'hg push
1863 1866 local_path'. You can check 'hg help urls' for details about valid URLs.
1864 1867
1865 1868 Options containing colons (":") denote sub-options that can influence
1866 1869 behavior for that specific path. Example:
1867 1870
1868 1871 [paths]
1869 1872 my_server = https://example.com/my_path
1870 1873 my_server:pushurl = ssh://example.com/my_path
1871 1874
1872 1875 Paths using the 'path://otherpath' scheme will inherit the sub-options
1873 1876 value from the path they point to.
1874 1877
1875 1878 The following sub-options can be defined:
1876 1879
1877 1880 "multi-urls"
1878 1881 A boolean option. When enabled the value of the '[paths]' entry will be
1879 1882 parsed as a list and the alias will resolve to multiple destination. If
1880 1883 some of the list entry use the 'path://' syntax, the suboption will be
1881 1884 inherited individually.
1882 1885
1883 1886 "pushurl"
1884 1887 The URL to use for push operations. If not defined, the location
1885 1888 defined by the path's main entry is used.
1886 1889
1887 1890 "pushrev"
1888 1891 A revset defining which revisions to push by default.
1889 1892
1890 1893 When 'hg push' is executed without a "-r" argument, the revset defined
1891 1894 by this sub-option is evaluated to determine what to push.
1892 1895
1893 1896 For example, a value of "." will push the working directory's revision
1894 1897 by default.
1895 1898
1896 1899 Revsets specifying bookmarks will not result in the bookmark being
1897 1900 pushed.
1898 1901
1899 1902 The following special named paths exist:
1900 1903
1901 1904 "default"
1902 1905 The URL or directory to use when no source or remote is specified.
1903 1906
1904 1907 'hg clone' will automatically define this path to the location the
1905 1908 repository was cloned from.
1906 1909
1907 1910 "default-push"
1908 1911 (deprecated) The URL or directory for the default 'hg push' location.
1909 1912 "default:pushurl" should be used instead.
1910 1913
1911 1914 $ hg help glossary.mcguffin
1912 1915 abort: help section not found: glossary.mcguffin
1913 1916 [10]
1914 1917
1915 1918 $ hg help glossary.mc.guffin
1916 1919 abort: help section not found: glossary.mc.guffin
1917 1920 [10]
1918 1921
1919 1922 $ hg help template.files
1920 1923 files List of strings. All files modified, added, or removed by
1921 1924 this changeset.
1922 1925 files(pattern)
1923 1926 All files of the current changeset matching the pattern. See
1924 1927 'hg help patterns'.
1925 1928
1926 1929 Test section lookup by translated message
1927 1930
1928 1931 str.lower() instead of encoding.lower(str) on translated message might
1929 1932 make message meaningless, because some encoding uses 0x41(A) - 0x5a(Z)
1930 1933 as the second or later byte of multi-byte character.
1931 1934
1932 1935 For example, "\x8bL\x98^" (translation of "record" in ja_JP.cp932)
1933 1936 contains 0x4c (L). str.lower() replaces 0x4c(L) by 0x6c(l) and this
1934 1937 replacement makes message meaningless.
1935 1938
1936 1939 This tests that section lookup by translated string isn't broken by
1937 1940 such str.lower().
1938 1941
1939 1942 $ "$PYTHON" <<EOF
1940 1943 > def escape(s):
1941 1944 > return b''.join(b'\\u%x' % ord(uc) for uc in s.decode('cp932'))
1942 1945 > # translation of "record" in ja_JP.cp932
1943 1946 > upper = b"\x8bL\x98^"
1944 1947 > # str.lower()-ed section name should be treated as different one
1945 1948 > lower = b"\x8bl\x98^"
1946 1949 > with open('ambiguous.py', 'wb') as fp:
1947 1950 > fp.write(b"""# ambiguous section names in ja_JP.cp932
1948 1951 > u'''summary of extension
1949 1952 >
1950 1953 > %s
1951 1954 > ----
1952 1955 >
1953 1956 > Upper name should show only this message
1954 1957 >
1955 1958 > %s
1956 1959 > ----
1957 1960 >
1958 1961 > Lower name should show only this message
1959 1962 >
1960 1963 > subsequent section
1961 1964 > ------------------
1962 1965 >
1963 1966 > This should be hidden at 'hg help ambiguous' with section name.
1964 1967 > '''
1965 1968 > """ % (escape(upper), escape(lower)))
1966 1969 > EOF
1967 1970
1968 1971 $ cat >> $HGRCPATH <<EOF
1969 1972 > [extensions]
1970 1973 > ambiguous = ./ambiguous.py
1971 1974 > EOF
1972 1975
1973 1976 $ "$PYTHON" <<EOF | sh
1974 1977 > from mercurial.utils import procutil
1975 1978 > upper = b"\x8bL\x98^"
1976 1979 > procutil.stdout.write(b"hg --encoding cp932 help -e ambiguous.%s\n" % upper)
1977 1980 > EOF
1978 1981 \x8bL\x98^ (esc)
1979 1982 ----
1980 1983
1981 1984 Upper name should show only this message
1982 1985
1983 1986
1984 1987 $ "$PYTHON" <<EOF | sh
1985 1988 > from mercurial.utils import procutil
1986 1989 > lower = b"\x8bl\x98^"
1987 1990 > procutil.stdout.write(b"hg --encoding cp932 help -e ambiguous.%s\n" % lower)
1988 1991 > EOF
1989 1992 \x8bl\x98^ (esc)
1990 1993 ----
1991 1994
1992 1995 Lower name should show only this message
1993 1996
1994 1997
1995 1998 $ cat >> $HGRCPATH <<EOF
1996 1999 > [extensions]
1997 2000 > ambiguous = !
1998 2001 > EOF
1999 2002
2000 2003 Show help content of disabled extensions
2001 2004
2002 2005 $ cat >> $HGRCPATH <<EOF
2003 2006 > [extensions]
2004 2007 > ambiguous = !./ambiguous.py
2005 2008 > EOF
2006 2009 $ hg help -e ambiguous
2007 2010 ambiguous extension - (no help text available)
2008 2011
2009 2012 (use 'hg help extensions' for information on enabling extensions)
2010 2013
2011 2014 Test dynamic list of merge tools only shows up once
2012 2015 $ hg help merge-tools
2013 2016 Merge Tools
2014 2017 """""""""""
2015 2018
2016 2019 To merge files Mercurial uses merge tools.
2017 2020
2018 2021 A merge tool combines two different versions of a file into a merged file.
2019 2022 Merge tools are given the two files and the greatest common ancestor of
2020 2023 the two file versions, so they can determine the changes made on both
2021 2024 branches.
2022 2025
2023 2026 Merge tools are used both for 'hg resolve', 'hg merge', 'hg update', 'hg
2024 2027 backout' and in several extensions.
2025 2028
2026 2029 Usually, the merge tool tries to automatically reconcile the files by
2027 2030 combining all non-overlapping changes that occurred separately in the two
2028 2031 different evolutions of the same initial base file. Furthermore, some
2029 2032 interactive merge programs make it easier to manually resolve conflicting
2030 2033 merges, either in a graphical way, or by inserting some conflict markers.
2031 2034 Mercurial does not include any interactive merge programs but relies on
2032 2035 external tools for that.
2033 2036
2034 2037 Available merge tools
2035 2038 =====================
2036 2039
2037 2040 External merge tools and their properties are configured in the merge-
2038 2041 tools configuration section - see hgrc(5) - but they can often just be
2039 2042 named by their executable.
2040 2043
2041 2044 A merge tool is generally usable if its executable can be found on the
2042 2045 system and if it can handle the merge. The executable is found if it is an
2043 2046 absolute or relative executable path or the name of an application in the
2044 2047 executable search path. The tool is assumed to be able to handle the merge
2045 2048 if it can handle symlinks if the file is a symlink, if it can handle
2046 2049 binary files if the file is binary, and if a GUI is available if the tool
2047 2050 requires a GUI.
2048 2051
2049 2052 There are some internal merge tools which can be used. The internal merge
2050 2053 tools are:
2051 2054
2052 2055 ":dump"
2053 2056 Creates three versions of the files to merge, containing the contents of
2054 2057 local, other and base. These files can then be used to perform a merge
2055 2058 manually. If the file to be merged is named "a.txt", these files will
2056 2059 accordingly be named "a.txt.local", "a.txt.other" and "a.txt.base" and
2057 2060 they will be placed in the same directory as "a.txt".
2058 2061
2059 2062 This implies premerge. Therefore, files aren't dumped, if premerge runs
2060 2063 successfully. Use :forcedump to forcibly write files out.
2061 2064
2062 2065 (actual capabilities: binary, symlink)
2063 2066
2064 2067 ":fail"
2065 2068 Rather than attempting to merge files that were modified on both
2066 2069 branches, it marks them as unresolved. The resolve command must be used
2067 2070 to resolve these conflicts.
2068 2071
2069 2072 (actual capabilities: binary, symlink)
2070 2073
2071 2074 ":forcedump"
2072 2075 Creates three versions of the files as same as :dump, but omits
2073 2076 premerge.
2074 2077
2075 2078 (actual capabilities: binary, symlink)
2076 2079
2077 2080 ":local"
2078 2081 Uses the local 'p1()' version of files as the merged version.
2079 2082
2080 2083 (actual capabilities: binary, symlink)
2081 2084
2082 2085 ":merge"
2083 2086 Uses the internal non-interactive simple merge algorithm for merging
2084 2087 files. It will fail if there are any conflicts and leave markers in the
2085 2088 partially merged file. Markers will have two sections, one for each side
2086 2089 of merge.
2087 2090
2088 2091 ":merge-local"
2089 2092 Like :merge, but resolve all conflicts non-interactively in favor of the
2090 2093 local 'p1()' changes.
2091 2094
2092 2095 ":merge-other"
2093 2096 Like :merge, but resolve all conflicts non-interactively in favor of the
2094 2097 other 'p2()' changes.
2095 2098
2096 2099 ":merge3"
2097 2100 Uses the internal non-interactive simple merge algorithm for merging
2098 2101 files. It will fail if there are any conflicts and leave markers in the
2099 2102 partially merged file. Marker will have three sections, one from each
2100 2103 side of the merge and one for the base content.
2101 2104
2102 2105 ":mergediff"
2103 2106 Uses the internal non-interactive simple merge algorithm for merging
2104 2107 files. It will fail if there are any conflicts and leave markers in the
2105 2108 partially merged file. The marker will have two sections, one with the
2106 2109 content from one side of the merge, and one with a diff from the base
2107 2110 content to the content on the other side. (experimental)
2108 2111
2109 2112 ":other"
2110 2113 Uses the other 'p2()' version of files as the merged version.
2111 2114
2112 2115 (actual capabilities: binary, symlink)
2113 2116
2114 2117 ":prompt"
2115 2118 Asks the user which of the local 'p1()' or the other 'p2()' version to
2116 2119 keep as the merged version.
2117 2120
2118 2121 (actual capabilities: binary, symlink)
2119 2122
2120 2123 ":tagmerge"
2121 2124 Uses the internal tag merge algorithm (experimental).
2122 2125
2123 2126 ":union"
2124 2127 Uses the internal non-interactive simple merge algorithm for merging
2125 2128 files. It will use both left and right sides for conflict regions. No
2126 2129 markers are inserted.
2127 2130
2128 2131 Internal tools are always available and do not require a GUI but will by
2129 2132 default not handle symlinks or binary files. See next section for detail
2130 2133 about "actual capabilities" described above.
2131 2134
2132 2135 Choosing a merge tool
2133 2136 =====================
2134 2137
2135 2138 Mercurial uses these rules when deciding which merge tool to use:
2136 2139
2137 2140 1. If a tool has been specified with the --tool option to merge or
2138 2141 resolve, it is used. If it is the name of a tool in the merge-tools
2139 2142 configuration, its configuration is used. Otherwise the specified tool
2140 2143 must be executable by the shell.
2141 2144 2. If the "HGMERGE" environment variable is present, its value is used and
2142 2145 must be executable by the shell.
2143 2146 3. If the filename of the file to be merged matches any of the patterns in
2144 2147 the merge-patterns configuration section, the first usable merge tool
2145 2148 corresponding to a matching pattern is used.
2146 2149 4. If ui.merge is set it will be considered next. If the value is not the
2147 2150 name of a configured tool, the specified value is used and must be
2148 2151 executable by the shell. Otherwise the named tool is used if it is
2149 2152 usable.
2150 2153 5. If any usable merge tools are present in the merge-tools configuration
2151 2154 section, the one with the highest priority is used.
2152 2155 6. If a program named "hgmerge" can be found on the system, it is used -
2153 2156 but it will by default not be used for symlinks and binary files.
2154 2157 7. If the file to be merged is not binary and is not a symlink, then
2155 2158 internal ":merge" is used.
2156 2159 8. Otherwise, ":prompt" is used.
2157 2160
2158 2161 For historical reason, Mercurial treats merge tools as below while
2159 2162 examining rules above.
2160 2163
2161 2164 step specified via binary symlink
2162 2165 ----------------------------------
2163 2166 1. --tool o/o o/o
2164 2167 2. HGMERGE o/o o/o
2165 2168 3. merge-patterns o/o(*) x/?(*)
2166 2169 4. ui.merge x/?(*) x/?(*)
2167 2170
2168 2171 Each capability column indicates Mercurial behavior for internal/external
2169 2172 merge tools at examining each rule.
2170 2173
2171 2174 - "o": "assume that a tool has capability"
2172 2175 - "x": "assume that a tool does not have capability"
2173 2176 - "?": "check actual capability of a tool"
2174 2177
2175 2178 If "merge.strict-capability-check" configuration is true, Mercurial checks
2176 2179 capabilities of merge tools strictly in (*) cases above (= each capability
2177 2180 column becomes "?/?"). It is false by default for backward compatibility.
2178 2181
2179 2182 Note:
2180 2183 After selecting a merge program, Mercurial will by default attempt to
2181 2184 merge the files using a simple merge algorithm first. Only if it
2182 2185 doesn't succeed because of conflicting changes will Mercurial actually
2183 2186 execute the merge program. Whether to use the simple merge algorithm
2184 2187 first can be controlled by the premerge setting of the merge tool.
2185 2188 Premerge is enabled by default unless the file is binary or a symlink.
2186 2189
2187 2190 See the merge-tools and ui sections of hgrc(5) for details on the
2188 2191 configuration of merge tools.
2189 2192
2190 2193 Compression engines listed in `hg help bundlespec`
2191 2194
2192 2195 $ hg help bundlespec | grep gzip
2193 2196 "v1" bundles can only use the "gzip", "bzip2", and "none" compression
2194 2197 An algorithm that produces smaller bundles than "gzip".
2195 2198 This engine will likely produce smaller bundles than "gzip" but will be
2196 2199 "gzip"
2197 2200 better compression than "gzip". It also frequently yields better (?)
2198 2201
2199 2202 Test usage of section marks in help documents
2200 2203
2201 2204 $ cd "$TESTDIR"/../doc
2202 2205 $ "$PYTHON" check-seclevel.py
2203 2206 $ cd $TESTTMP
2204 2207
2205 2208 #if serve
2206 2209
2207 2210 Test the help pages in hgweb.
2208 2211
2209 2212 Dish up an empty repo; serve it cold.
2210 2213
2211 2214 $ hg init "$TESTTMP/test"
2212 2215 $ hg serve -R "$TESTTMP/test" -n test -p $HGPORT -d --pid-file=hg.pid
2213 2216 $ cat hg.pid >> $DAEMON_PIDS
2214 2217
2215 2218 $ get-with-headers.py $LOCALIP:$HGPORT "help"
2216 2219 200 Script output follows
2217 2220
2218 2221 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
2219 2222 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
2220 2223 <head>
2221 2224 <link rel="icon" href="/static/hgicon.png" type="image/png" />
2222 2225 <meta name="robots" content="index, nofollow" />
2223 2226 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
2224 2227 <script type="text/javascript" src="/static/mercurial.js"></script>
2225 2228
2226 2229 <title>Help: Index</title>
2227 2230 </head>
2228 2231 <body>
2229 2232
2230 2233 <div class="container">
2231 2234 <div class="menu">
2232 2235 <div class="logo">
2233 2236 <a href="https://mercurial-scm.org/">
2234 2237 <img src="/static/hglogo.png" alt="mercurial" /></a>
2235 2238 </div>
2236 2239 <ul>
2237 2240 <li><a href="/shortlog">log</a></li>
2238 2241 <li><a href="/graph">graph</a></li>
2239 2242 <li><a href="/tags">tags</a></li>
2240 2243 <li><a href="/bookmarks">bookmarks</a></li>
2241 2244 <li><a href="/branches">branches</a></li>
2242 2245 </ul>
2243 2246 <ul>
2244 2247 <li class="active">help</li>
2245 2248 </ul>
2246 2249 </div>
2247 2250
2248 2251 <div class="main">
2249 2252 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
2250 2253
2251 2254 <form class="search" action="/log">
2252 2255
2253 2256 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
2254 2257 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
2255 2258 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
2256 2259 </form>
2257 2260 <table class="bigtable">
2258 2261 <tr><td colspan="2"><h2><a name="topics" href="#topics">Topics</a></h2></td></tr>
2259 2262
2260 2263 <tr><td>
2261 2264 <a href="/help/bundlespec">
2262 2265 bundlespec
2263 2266 </a>
2264 2267 </td><td>
2265 2268 Bundle File Formats
2266 2269 </td></tr>
2267 2270 <tr><td>
2268 2271 <a href="/help/color">
2269 2272 color
2270 2273 </a>
2271 2274 </td><td>
2272 2275 Colorizing Outputs
2273 2276 </td></tr>
2274 2277 <tr><td>
2275 2278 <a href="/help/config">
2276 2279 config
2277 2280 </a>
2278 2281 </td><td>
2279 2282 Configuration Files
2280 2283 </td></tr>
2281 2284 <tr><td>
2282 2285 <a href="/help/dates">
2283 2286 dates
2284 2287 </a>
2285 2288 </td><td>
2286 2289 Date Formats
2287 2290 </td></tr>
2288 2291 <tr><td>
2289 2292 <a href="/help/deprecated">
2290 2293 deprecated
2291 2294 </a>
2292 2295 </td><td>
2293 2296 Deprecated Features
2294 2297 </td></tr>
2295 2298 <tr><td>
2296 2299 <a href="/help/diffs">
2297 2300 diffs
2298 2301 </a>
2299 2302 </td><td>
2300 2303 Diff Formats
2301 2304 </td></tr>
2302 2305 <tr><td>
2303 2306 <a href="/help/environment">
2304 2307 environment
2305 2308 </a>
2306 2309 </td><td>
2307 2310 Environment Variables
2308 2311 </td></tr>
2309 2312 <tr><td>
2310 2313 <a href="/help/evolution">
2311 2314 evolution
2312 2315 </a>
2313 2316 </td><td>
2314 2317 Safely rewriting history (EXPERIMENTAL)
2315 2318 </td></tr>
2316 2319 <tr><td>
2317 2320 <a href="/help/extensions">
2318 2321 extensions
2319 2322 </a>
2320 2323 </td><td>
2321 2324 Using Additional Features
2322 2325 </td></tr>
2323 2326 <tr><td>
2324 2327 <a href="/help/filesets">
2325 2328 filesets
2326 2329 </a>
2327 2330 </td><td>
2328 2331 Specifying File Sets
2329 2332 </td></tr>
2330 2333 <tr><td>
2331 2334 <a href="/help/flags">
2332 2335 flags
2333 2336 </a>
2334 2337 </td><td>
2335 2338 Command-line flags
2336 2339 </td></tr>
2337 2340 <tr><td>
2338 2341 <a href="/help/glossary">
2339 2342 glossary
2340 2343 </a>
2341 2344 </td><td>
2342 2345 Glossary
2343 2346 </td></tr>
2344 2347 <tr><td>
2345 2348 <a href="/help/hgignore">
2346 2349 hgignore
2347 2350 </a>
2348 2351 </td><td>
2349 2352 Syntax for Mercurial Ignore Files
2350 2353 </td></tr>
2351 2354 <tr><td>
2352 2355 <a href="/help/hgweb">
2353 2356 hgweb
2354 2357 </a>
2355 2358 </td><td>
2356 2359 Configuring hgweb
2357 2360 </td></tr>
2358 2361 <tr><td>
2359 2362 <a href="/help/internals">
2360 2363 internals
2361 2364 </a>
2362 2365 </td><td>
2363 2366 Technical implementation topics
2364 2367 </td></tr>
2365 2368 <tr><td>
2366 2369 <a href="/help/merge-tools">
2367 2370 merge-tools
2368 2371 </a>
2369 2372 </td><td>
2370 2373 Merge Tools
2371 2374 </td></tr>
2372 2375 <tr><td>
2373 2376 <a href="/help/pager">
2374 2377 pager
2375 2378 </a>
2376 2379 </td><td>
2377 2380 Pager Support
2378 2381 </td></tr>
2379 2382 <tr><td>
2380 2383 <a href="/help/patterns">
2381 2384 patterns
2382 2385 </a>
2383 2386 </td><td>
2384 2387 File Name Patterns
2385 2388 </td></tr>
2386 2389 <tr><td>
2387 2390 <a href="/help/phases">
2388 2391 phases
2389 2392 </a>
2390 2393 </td><td>
2391 2394 Working with Phases
2392 2395 </td></tr>
2393 2396 <tr><td>
2394 2397 <a href="/help/revisions">
2395 2398 revisions
2396 2399 </a>
2397 2400 </td><td>
2398 2401 Specifying Revisions
2399 2402 </td></tr>
2400 2403 <tr><td>
2401 2404 <a href="/help/scripting">
2402 2405 scripting
2403 2406 </a>
2404 2407 </td><td>
2405 2408 Using Mercurial from scripts and automation
2406 2409 </td></tr>
2407 2410 <tr><td>
2408 2411 <a href="/help/subrepos">
2409 2412 subrepos
2410 2413 </a>
2411 2414 </td><td>
2412 2415 Subrepositories
2413 2416 </td></tr>
2414 2417 <tr><td>
2415 2418 <a href="/help/templating">
2416 2419 templating
2417 2420 </a>
2418 2421 </td><td>
2419 2422 Template Usage
2420 2423 </td></tr>
2421 2424 <tr><td>
2422 2425 <a href="/help/urls">
2423 2426 urls
2424 2427 </a>
2425 2428 </td><td>
2426 2429 URL Paths
2427 2430 </td></tr>
2428 2431 <tr><td>
2429 2432 <a href="/help/topic-containing-verbose">
2430 2433 topic-containing-verbose
2431 2434 </a>
2432 2435 </td><td>
2433 2436 This is the topic to test omit indicating.
2434 2437 </td></tr>
2435 2438
2436 2439
2437 2440 <tr><td colspan="2"><h2><a name="main" href="#main">Main Commands</a></h2></td></tr>
2438 2441
2439 2442 <tr><td>
2440 2443 <a href="/help/abort">
2441 2444 abort
2442 2445 </a>
2443 2446 </td><td>
2444 2447 abort an unfinished operation (EXPERIMENTAL)
2445 2448 </td></tr>
2446 2449 <tr><td>
2447 2450 <a href="/help/add">
2448 2451 add
2449 2452 </a>
2450 2453 </td><td>
2451 2454 add the specified files on the next commit
2452 2455 </td></tr>
2453 2456 <tr><td>
2454 2457 <a href="/help/annotate">
2455 2458 annotate
2456 2459 </a>
2457 2460 </td><td>
2458 2461 show changeset information by line for each file
2459 2462 </td></tr>
2460 2463 <tr><td>
2461 2464 <a href="/help/clone">
2462 2465 clone
2463 2466 </a>
2464 2467 </td><td>
2465 2468 make a copy of an existing repository
2466 2469 </td></tr>
2467 2470 <tr><td>
2468 2471 <a href="/help/commit">
2469 2472 commit
2470 2473 </a>
2471 2474 </td><td>
2472 2475 commit the specified files or all outstanding changes
2473 2476 </td></tr>
2474 2477 <tr><td>
2475 2478 <a href="/help/continue">
2476 2479 continue
2477 2480 </a>
2478 2481 </td><td>
2479 2482 resumes an interrupted operation (EXPERIMENTAL)
2480 2483 </td></tr>
2481 2484 <tr><td>
2482 2485 <a href="/help/diff">
2483 2486 diff
2484 2487 </a>
2485 2488 </td><td>
2486 2489 diff repository (or selected files)
2487 2490 </td></tr>
2488 2491 <tr><td>
2489 2492 <a href="/help/export">
2490 2493 export
2491 2494 </a>
2492 2495 </td><td>
2493 2496 dump the header and diffs for one or more changesets
2494 2497 </td></tr>
2495 2498 <tr><td>
2496 2499 <a href="/help/forget">
2497 2500 forget
2498 2501 </a>
2499 2502 </td><td>
2500 2503 forget the specified files on the next commit
2501 2504 </td></tr>
2502 2505 <tr><td>
2503 2506 <a href="/help/init">
2504 2507 init
2505 2508 </a>
2506 2509 </td><td>
2507 2510 create a new repository in the given directory
2508 2511 </td></tr>
2509 2512 <tr><td>
2510 2513 <a href="/help/log">
2511 2514 log
2512 2515 </a>
2513 2516 </td><td>
2514 2517 show revision history of entire repository or files
2515 2518 </td></tr>
2516 2519 <tr><td>
2517 2520 <a href="/help/merge">
2518 2521 merge
2519 2522 </a>
2520 2523 </td><td>
2521 2524 merge another revision into working directory
2522 2525 </td></tr>
2523 2526 <tr><td>
2524 2527 <a href="/help/pull">
2525 2528 pull
2526 2529 </a>
2527 2530 </td><td>
2528 2531 pull changes from the specified source
2529 2532 </td></tr>
2530 2533 <tr><td>
2531 2534 <a href="/help/push">
2532 2535 push
2533 2536 </a>
2534 2537 </td><td>
2535 2538 push changes to the specified destination
2536 2539 </td></tr>
2537 2540 <tr><td>
2538 2541 <a href="/help/remove">
2539 2542 remove
2540 2543 </a>
2541 2544 </td><td>
2542 2545 remove the specified files on the next commit
2543 2546 </td></tr>
2544 2547 <tr><td>
2545 2548 <a href="/help/serve">
2546 2549 serve
2547 2550 </a>
2548 2551 </td><td>
2549 2552 start stand-alone webserver
2550 2553 </td></tr>
2551 2554 <tr><td>
2552 2555 <a href="/help/status">
2553 2556 status
2554 2557 </a>
2555 2558 </td><td>
2556 2559 show changed files in the working directory
2557 2560 </td></tr>
2558 2561 <tr><td>
2559 2562 <a href="/help/summary">
2560 2563 summary
2561 2564 </a>
2562 2565 </td><td>
2563 2566 summarize working directory state
2564 2567 </td></tr>
2565 2568 <tr><td>
2566 2569 <a href="/help/update">
2567 2570 update
2568 2571 </a>
2569 2572 </td><td>
2570 2573 update working directory (or switch revisions)
2571 2574 </td></tr>
2572 2575
2573 2576
2574 2577
2575 2578 <tr><td colspan="2"><h2><a name="other" href="#other">Other Commands</a></h2></td></tr>
2576 2579
2577 2580 <tr><td>
2578 2581 <a href="/help/addremove">
2579 2582 addremove
2580 2583 </a>
2581 2584 </td><td>
2582 2585 add all new files, delete all missing files
2583 2586 </td></tr>
2584 2587 <tr><td>
2585 2588 <a href="/help/archive">
2586 2589 archive
2587 2590 </a>
2588 2591 </td><td>
2589 2592 create an unversioned archive of a repository revision
2590 2593 </td></tr>
2591 2594 <tr><td>
2592 2595 <a href="/help/backout">
2593 2596 backout
2594 2597 </a>
2595 2598 </td><td>
2596 2599 reverse effect of earlier changeset
2597 2600 </td></tr>
2598 2601 <tr><td>
2599 2602 <a href="/help/bisect">
2600 2603 bisect
2601 2604 </a>
2602 2605 </td><td>
2603 2606 subdivision search of changesets
2604 2607 </td></tr>
2605 2608 <tr><td>
2606 2609 <a href="/help/bookmarks">
2607 2610 bookmarks
2608 2611 </a>
2609 2612 </td><td>
2610 2613 create a new bookmark or list existing bookmarks
2611 2614 </td></tr>
2612 2615 <tr><td>
2613 2616 <a href="/help/branch">
2614 2617 branch
2615 2618 </a>
2616 2619 </td><td>
2617 2620 set or show the current branch name
2618 2621 </td></tr>
2619 2622 <tr><td>
2620 2623 <a href="/help/branches">
2621 2624 branches
2622 2625 </a>
2623 2626 </td><td>
2624 2627 list repository named branches
2625 2628 </td></tr>
2626 2629 <tr><td>
2627 2630 <a href="/help/bundle">
2628 2631 bundle
2629 2632 </a>
2630 2633 </td><td>
2631 2634 create a bundle file
2632 2635 </td></tr>
2633 2636 <tr><td>
2634 2637 <a href="/help/cat">
2635 2638 cat
2636 2639 </a>
2637 2640 </td><td>
2638 2641 output the current or given revision of files
2639 2642 </td></tr>
2640 2643 <tr><td>
2641 2644 <a href="/help/config">
2642 2645 config
2643 2646 </a>
2644 2647 </td><td>
2645 2648 show combined config settings from all hgrc files
2646 2649 </td></tr>
2647 2650 <tr><td>
2648 2651 <a href="/help/copy">
2649 2652 copy
2650 2653 </a>
2651 2654 </td><td>
2652 2655 mark files as copied for the next commit
2653 2656 </td></tr>
2654 2657 <tr><td>
2655 2658 <a href="/help/files">
2656 2659 files
2657 2660 </a>
2658 2661 </td><td>
2659 2662 list tracked files
2660 2663 </td></tr>
2661 2664 <tr><td>
2662 2665 <a href="/help/graft">
2663 2666 graft
2664 2667 </a>
2665 2668 </td><td>
2666 2669 copy changes from other branches onto the current branch
2667 2670 </td></tr>
2668 2671 <tr><td>
2669 2672 <a href="/help/grep">
2670 2673 grep
2671 2674 </a>
2672 2675 </td><td>
2673 2676 search for a pattern in specified files
2674 2677 </td></tr>
2675 2678 <tr><td>
2676 2679 <a href="/help/hashelp">
2677 2680 hashelp
2678 2681 </a>
2679 2682 </td><td>
2680 2683 Extension command's help
2681 2684 </td></tr>
2682 2685 <tr><td>
2683 2686 <a href="/help/heads">
2684 2687 heads
2685 2688 </a>
2686 2689 </td><td>
2687 2690 show branch heads
2688 2691 </td></tr>
2689 2692 <tr><td>
2690 2693 <a href="/help/help">
2691 2694 help
2692 2695 </a>
2693 2696 </td><td>
2694 2697 show help for a given topic or a help overview
2695 2698 </td></tr>
2696 2699 <tr><td>
2697 2700 <a href="/help/hgalias">
2698 2701 hgalias
2699 2702 </a>
2700 2703 </td><td>
2701 2704 My doc
2702 2705 </td></tr>
2703 2706 <tr><td>
2704 2707 <a href="/help/hgaliasnodoc">
2705 2708 hgaliasnodoc
2706 2709 </a>
2707 2710 </td><td>
2708 2711 summarize working directory state
2709 2712 </td></tr>
2710 2713 <tr><td>
2711 2714 <a href="/help/identify">
2712 2715 identify
2713 2716 </a>
2714 2717 </td><td>
2715 2718 identify the working directory or specified revision
2716 2719 </td></tr>
2717 2720 <tr><td>
2718 2721 <a href="/help/import">
2719 2722 import
2720 2723 </a>
2721 2724 </td><td>
2722 2725 import an ordered set of patches
2723 2726 </td></tr>
2724 2727 <tr><td>
2725 2728 <a href="/help/incoming">
2726 2729 incoming
2727 2730 </a>
2728 2731 </td><td>
2729 2732 show new changesets found in source
2730 2733 </td></tr>
2731 2734 <tr><td>
2732 2735 <a href="/help/manifest">
2733 2736 manifest
2734 2737 </a>
2735 2738 </td><td>
2736 2739 output the current or given revision of the project manifest
2737 2740 </td></tr>
2738 2741 <tr><td>
2739 2742 <a href="/help/nohelp">
2740 2743 nohelp
2741 2744 </a>
2742 2745 </td><td>
2743 2746 (no help text available)
2744 2747 </td></tr>
2745 2748 <tr><td>
2746 2749 <a href="/help/outgoing">
2747 2750 outgoing
2748 2751 </a>
2749 2752 </td><td>
2750 2753 show changesets not found in the destination
2751 2754 </td></tr>
2752 2755 <tr><td>
2753 2756 <a href="/help/paths">
2754 2757 paths
2755 2758 </a>
2756 2759 </td><td>
2757 2760 show aliases for remote repositories
2758 2761 </td></tr>
2759 2762 <tr><td>
2760 2763 <a href="/help/phase">
2761 2764 phase
2762 2765 </a>
2763 2766 </td><td>
2764 2767 set or show the current phase name
2765 2768 </td></tr>
2766 2769 <tr><td>
2767 2770 <a href="/help/purge">
2768 2771 purge
2769 2772 </a>
2770 2773 </td><td>
2771 2774 removes files not tracked by Mercurial
2772 2775 </td></tr>
2773 2776 <tr><td>
2774 2777 <a href="/help/recover">
2775 2778 recover
2776 2779 </a>
2777 2780 </td><td>
2778 2781 roll back an interrupted transaction
2779 2782 </td></tr>
2780 2783 <tr><td>
2781 2784 <a href="/help/rename">
2782 2785 rename
2783 2786 </a>
2784 2787 </td><td>
2785 2788 rename files; equivalent of copy + remove
2786 2789 </td></tr>
2787 2790 <tr><td>
2788 2791 <a href="/help/resolve">
2789 2792 resolve
2790 2793 </a>
2791 2794 </td><td>
2792 2795 redo merges or set/view the merge status of files
2793 2796 </td></tr>
2794 2797 <tr><td>
2795 2798 <a href="/help/revert">
2796 2799 revert
2797 2800 </a>
2798 2801 </td><td>
2799 2802 restore files to their checkout state
2800 2803 </td></tr>
2801 2804 <tr><td>
2802 2805 <a href="/help/root">
2803 2806 root
2804 2807 </a>
2805 2808 </td><td>
2806 2809 print the root (top) of the current working directory
2807 2810 </td></tr>
2808 2811 <tr><td>
2809 2812 <a href="/help/shellalias">
2810 2813 shellalias
2811 2814 </a>
2812 2815 </td><td>
2813 2816 (no help text available)
2814 2817 </td></tr>
2815 2818 <tr><td>
2816 2819 <a href="/help/shelve">
2817 2820 shelve
2818 2821 </a>
2819 2822 </td><td>
2820 2823 save and set aside changes from the working directory
2821 2824 </td></tr>
2822 2825 <tr><td>
2823 2826 <a href="/help/tag">
2824 2827 tag
2825 2828 </a>
2826 2829 </td><td>
2827 2830 add one or more tags for the current or given revision
2828 2831 </td></tr>
2829 2832 <tr><td>
2830 2833 <a href="/help/tags">
2831 2834 tags
2832 2835 </a>
2833 2836 </td><td>
2834 2837 list repository tags
2835 2838 </td></tr>
2836 2839 <tr><td>
2837 2840 <a href="/help/unbundle">
2838 2841 unbundle
2839 2842 </a>
2840 2843 </td><td>
2841 2844 apply one or more bundle files
2842 2845 </td></tr>
2843 2846 <tr><td>
2844 2847 <a href="/help/unshelve">
2845 2848 unshelve
2846 2849 </a>
2847 2850 </td><td>
2848 2851 restore a shelved change to the working directory
2849 2852 </td></tr>
2850 2853 <tr><td>
2851 2854 <a href="/help/verify">
2852 2855 verify
2853 2856 </a>
2854 2857 </td><td>
2855 2858 verify the integrity of the repository
2856 2859 </td></tr>
2857 2860 <tr><td>
2858 2861 <a href="/help/version">
2859 2862 version
2860 2863 </a>
2861 2864 </td><td>
2862 2865 output version and copyright information
2863 2866 </td></tr>
2864 2867
2865 2868
2866 2869 </table>
2867 2870 </div>
2868 2871 </div>
2869 2872
2870 2873
2871 2874
2872 2875 </body>
2873 2876 </html>
2874 2877
2875 2878
2876 2879 $ get-with-headers.py $LOCALIP:$HGPORT "help/add"
2877 2880 200 Script output follows
2878 2881
2879 2882 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
2880 2883 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
2881 2884 <head>
2882 2885 <link rel="icon" href="/static/hgicon.png" type="image/png" />
2883 2886 <meta name="robots" content="index, nofollow" />
2884 2887 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
2885 2888 <script type="text/javascript" src="/static/mercurial.js"></script>
2886 2889
2887 2890 <title>Help: add</title>
2888 2891 </head>
2889 2892 <body>
2890 2893
2891 2894 <div class="container">
2892 2895 <div class="menu">
2893 2896 <div class="logo">
2894 2897 <a href="https://mercurial-scm.org/">
2895 2898 <img src="/static/hglogo.png" alt="mercurial" /></a>
2896 2899 </div>
2897 2900 <ul>
2898 2901 <li><a href="/shortlog">log</a></li>
2899 2902 <li><a href="/graph">graph</a></li>
2900 2903 <li><a href="/tags">tags</a></li>
2901 2904 <li><a href="/bookmarks">bookmarks</a></li>
2902 2905 <li><a href="/branches">branches</a></li>
2903 2906 </ul>
2904 2907 <ul>
2905 2908 <li class="active"><a href="/help">help</a></li>
2906 2909 </ul>
2907 2910 </div>
2908 2911
2909 2912 <div class="main">
2910 2913 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
2911 2914 <h3>Help: add</h3>
2912 2915
2913 2916 <form class="search" action="/log">
2914 2917
2915 2918 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
2916 2919 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
2917 2920 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
2918 2921 </form>
2919 2922 <div id="doc">
2920 2923 <p>
2921 2924 hg add [OPTION]... [FILE]...
2922 2925 </p>
2923 2926 <p>
2924 2927 add the specified files on the next commit
2925 2928 </p>
2926 2929 <p>
2927 2930 Schedule files to be version controlled and added to the
2928 2931 repository.
2929 2932 </p>
2930 2933 <p>
2931 2934 The files will be added to the repository at the next commit. To
2932 2935 undo an add before that, see 'hg forget'.
2933 2936 </p>
2934 2937 <p>
2935 2938 If no names are given, add all files to the repository (except
2936 2939 files matching &quot;.hgignore&quot;).
2937 2940 </p>
2938 2941 <p>
2939 2942 Examples:
2940 2943 </p>
2941 2944 <ul>
2942 2945 <li> New (unknown) files are added automatically by 'hg add':
2943 2946 <pre>
2944 2947 \$ ls (re)
2945 2948 foo.c
2946 2949 \$ hg status (re)
2947 2950 ? foo.c
2948 2951 \$ hg add (re)
2949 2952 adding foo.c
2950 2953 \$ hg status (re)
2951 2954 A foo.c
2952 2955 </pre>
2953 2956 <li> Specific files to be added can be specified:
2954 2957 <pre>
2955 2958 \$ ls (re)
2956 2959 bar.c foo.c
2957 2960 \$ hg status (re)
2958 2961 ? bar.c
2959 2962 ? foo.c
2960 2963 \$ hg add bar.c (re)
2961 2964 \$ hg status (re)
2962 2965 A bar.c
2963 2966 ? foo.c
2964 2967 </pre>
2965 2968 </ul>
2966 2969 <p>
2967 2970 Returns 0 if all files are successfully added.
2968 2971 </p>
2969 2972 <p>
2970 2973 options ([+] can be repeated):
2971 2974 </p>
2972 2975 <table>
2973 2976 <tr><td>-I</td>
2974 2977 <td>--include PATTERN [+]</td>
2975 2978 <td>include names matching the given patterns</td></tr>
2976 2979 <tr><td>-X</td>
2977 2980 <td>--exclude PATTERN [+]</td>
2978 2981 <td>exclude names matching the given patterns</td></tr>
2979 2982 <tr><td>-S</td>
2980 2983 <td>--subrepos</td>
2981 2984 <td>recurse into subrepositories</td></tr>
2982 2985 <tr><td>-n</td>
2983 2986 <td>--dry-run</td>
2984 2987 <td>do not perform actions, just print output</td></tr>
2985 2988 </table>
2986 2989 <p>
2987 2990 global options ([+] can be repeated):
2988 2991 </p>
2989 2992 <table>
2990 2993 <tr><td>-R</td>
2991 2994 <td>--repository REPO</td>
2992 2995 <td>repository root directory or name of overlay bundle file</td></tr>
2993 2996 <tr><td></td>
2994 2997 <td>--cwd DIR</td>
2995 2998 <td>change working directory</td></tr>
2996 2999 <tr><td>-y</td>
2997 3000 <td>--noninteractive</td>
2998 3001 <td>do not prompt, automatically pick the first choice for all prompts</td></tr>
2999 3002 <tr><td>-q</td>
3000 3003 <td>--quiet</td>
3001 3004 <td>suppress output</td></tr>
3002 3005 <tr><td>-v</td>
3003 3006 <td>--verbose</td>
3004 3007 <td>enable additional output</td></tr>
3005 3008 <tr><td></td>
3006 3009 <td>--color TYPE</td>
3007 3010 <td>when to colorize (boolean, always, auto, never, or debug)</td></tr>
3008 3011 <tr><td></td>
3009 3012 <td>--config CONFIG [+]</td>
3010 3013 <td>set/override config option (use 'section.name=value')</td></tr>
3011 3014 <tr><td></td>
3012 3015 <td>--debug</td>
3013 3016 <td>enable debugging output</td></tr>
3014 3017 <tr><td></td>
3015 3018 <td>--debugger</td>
3016 3019 <td>start debugger</td></tr>
3017 3020 <tr><td></td>
3018 3021 <td>--encoding ENCODE</td>
3019 3022 <td>set the charset encoding (default: ascii)</td></tr>
3020 3023 <tr><td></td>
3021 3024 <td>--encodingmode MODE</td>
3022 3025 <td>set the charset encoding mode (default: strict)</td></tr>
3023 3026 <tr><td></td>
3024 3027 <td>--traceback</td>
3025 3028 <td>always print a traceback on exception</td></tr>
3026 3029 <tr><td></td>
3027 3030 <td>--time</td>
3028 3031 <td>time how long the command takes</td></tr>
3029 3032 <tr><td></td>
3030 3033 <td>--profile</td>
3031 3034 <td>print command execution profile</td></tr>
3032 3035 <tr><td></td>
3033 3036 <td>--version</td>
3034 3037 <td>output version information and exit</td></tr>
3035 3038 <tr><td>-h</td>
3036 3039 <td>--help</td>
3037 3040 <td>display help and exit</td></tr>
3038 3041 <tr><td></td>
3039 3042 <td>--hidden</td>
3040 3043 <td>consider hidden changesets</td></tr>
3041 3044 <tr><td></td>
3042 3045 <td>--pager TYPE</td>
3043 3046 <td>when to paginate (boolean, always, auto, or never) (default: auto)</td></tr>
3044 3047 </table>
3045 3048
3046 3049 </div>
3047 3050 </div>
3048 3051 </div>
3049 3052
3050 3053
3051 3054
3052 3055 </body>
3053 3056 </html>
3054 3057
3055 3058
3056 3059 $ get-with-headers.py $LOCALIP:$HGPORT "help/remove"
3057 3060 200 Script output follows
3058 3061
3059 3062 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3060 3063 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3061 3064 <head>
3062 3065 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3063 3066 <meta name="robots" content="index, nofollow" />
3064 3067 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3065 3068 <script type="text/javascript" src="/static/mercurial.js"></script>
3066 3069
3067 3070 <title>Help: remove</title>
3068 3071 </head>
3069 3072 <body>
3070 3073
3071 3074 <div class="container">
3072 3075 <div class="menu">
3073 3076 <div class="logo">
3074 3077 <a href="https://mercurial-scm.org/">
3075 3078 <img src="/static/hglogo.png" alt="mercurial" /></a>
3076 3079 </div>
3077 3080 <ul>
3078 3081 <li><a href="/shortlog">log</a></li>
3079 3082 <li><a href="/graph">graph</a></li>
3080 3083 <li><a href="/tags">tags</a></li>
3081 3084 <li><a href="/bookmarks">bookmarks</a></li>
3082 3085 <li><a href="/branches">branches</a></li>
3083 3086 </ul>
3084 3087 <ul>
3085 3088 <li class="active"><a href="/help">help</a></li>
3086 3089 </ul>
3087 3090 </div>
3088 3091
3089 3092 <div class="main">
3090 3093 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3091 3094 <h3>Help: remove</h3>
3092 3095
3093 3096 <form class="search" action="/log">
3094 3097
3095 3098 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3096 3099 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3097 3100 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3098 3101 </form>
3099 3102 <div id="doc">
3100 3103 <p>
3101 3104 hg remove [OPTION]... FILE...
3102 3105 </p>
3103 3106 <p>
3104 3107 aliases: rm
3105 3108 </p>
3106 3109 <p>
3107 3110 remove the specified files on the next commit
3108 3111 </p>
3109 3112 <p>
3110 3113 Schedule the indicated files for removal from the current branch.
3111 3114 </p>
3112 3115 <p>
3113 3116 This command schedules the files to be removed at the next commit.
3114 3117 To undo a remove before that, see 'hg revert'. To undo added
3115 3118 files, see 'hg forget'.
3116 3119 </p>
3117 3120 <p>
3118 3121 -A/--after can be used to remove only files that have already
3119 3122 been deleted, -f/--force can be used to force deletion, and -Af
3120 3123 can be used to remove files from the next revision without
3121 3124 deleting them from the working directory.
3122 3125 </p>
3123 3126 <p>
3124 3127 The following table details the behavior of remove for different
3125 3128 file states (columns) and option combinations (rows). The file
3126 3129 states are Added [A], Clean [C], Modified [M] and Missing [!]
3127 3130 (as reported by 'hg status'). The actions are Warn, Remove
3128 3131 (from branch) and Delete (from disk):
3129 3132 </p>
3130 3133 <table>
3131 3134 <tr><td>opt/state</td>
3132 3135 <td>A</td>
3133 3136 <td>C</td>
3134 3137 <td>M</td>
3135 3138 <td>!</td></tr>
3136 3139 <tr><td>none</td>
3137 3140 <td>W</td>
3138 3141 <td>RD</td>
3139 3142 <td>W</td>
3140 3143 <td>R</td></tr>
3141 3144 <tr><td>-f</td>
3142 3145 <td>R</td>
3143 3146 <td>RD</td>
3144 3147 <td>RD</td>
3145 3148 <td>R</td></tr>
3146 3149 <tr><td>-A</td>
3147 3150 <td>W</td>
3148 3151 <td>W</td>
3149 3152 <td>W</td>
3150 3153 <td>R</td></tr>
3151 3154 <tr><td>-Af</td>
3152 3155 <td>R</td>
3153 3156 <td>R</td>
3154 3157 <td>R</td>
3155 3158 <td>R</td></tr>
3156 3159 </table>
3157 3160 <p>
3158 3161 <b>Note:</b>
3159 3162 </p>
3160 3163 <p>
3161 3164 'hg remove' never deletes files in Added [A] state from the
3162 3165 working directory, not even if &quot;--force&quot; is specified.
3163 3166 </p>
3164 3167 <p>
3165 3168 Returns 0 on success, 1 if any warnings encountered.
3166 3169 </p>
3167 3170 <p>
3168 3171 options ([+] can be repeated):
3169 3172 </p>
3170 3173 <table>
3171 3174 <tr><td>-A</td>
3172 3175 <td>--after</td>
3173 3176 <td>record delete for missing files</td></tr>
3174 3177 <tr><td>-f</td>
3175 3178 <td>--force</td>
3176 3179 <td>forget added files, delete modified files</td></tr>
3177 3180 <tr><td>-S</td>
3178 3181 <td>--subrepos</td>
3179 3182 <td>recurse into subrepositories</td></tr>
3180 3183 <tr><td>-I</td>
3181 3184 <td>--include PATTERN [+]</td>
3182 3185 <td>include names matching the given patterns</td></tr>
3183 3186 <tr><td>-X</td>
3184 3187 <td>--exclude PATTERN [+]</td>
3185 3188 <td>exclude names matching the given patterns</td></tr>
3186 3189 <tr><td>-n</td>
3187 3190 <td>--dry-run</td>
3188 3191 <td>do not perform actions, just print output</td></tr>
3189 3192 </table>
3190 3193 <p>
3191 3194 global options ([+] can be repeated):
3192 3195 </p>
3193 3196 <table>
3194 3197 <tr><td>-R</td>
3195 3198 <td>--repository REPO</td>
3196 3199 <td>repository root directory or name of overlay bundle file</td></tr>
3197 3200 <tr><td></td>
3198 3201 <td>--cwd DIR</td>
3199 3202 <td>change working directory</td></tr>
3200 3203 <tr><td>-y</td>
3201 3204 <td>--noninteractive</td>
3202 3205 <td>do not prompt, automatically pick the first choice for all prompts</td></tr>
3203 3206 <tr><td>-q</td>
3204 3207 <td>--quiet</td>
3205 3208 <td>suppress output</td></tr>
3206 3209 <tr><td>-v</td>
3207 3210 <td>--verbose</td>
3208 3211 <td>enable additional output</td></tr>
3209 3212 <tr><td></td>
3210 3213 <td>--color TYPE</td>
3211 3214 <td>when to colorize (boolean, always, auto, never, or debug)</td></tr>
3212 3215 <tr><td></td>
3213 3216 <td>--config CONFIG [+]</td>
3214 3217 <td>set/override config option (use 'section.name=value')</td></tr>
3215 3218 <tr><td></td>
3216 3219 <td>--debug</td>
3217 3220 <td>enable debugging output</td></tr>
3218 3221 <tr><td></td>
3219 3222 <td>--debugger</td>
3220 3223 <td>start debugger</td></tr>
3221 3224 <tr><td></td>
3222 3225 <td>--encoding ENCODE</td>
3223 3226 <td>set the charset encoding (default: ascii)</td></tr>
3224 3227 <tr><td></td>
3225 3228 <td>--encodingmode MODE</td>
3226 3229 <td>set the charset encoding mode (default: strict)</td></tr>
3227 3230 <tr><td></td>
3228 3231 <td>--traceback</td>
3229 3232 <td>always print a traceback on exception</td></tr>
3230 3233 <tr><td></td>
3231 3234 <td>--time</td>
3232 3235 <td>time how long the command takes</td></tr>
3233 3236 <tr><td></td>
3234 3237 <td>--profile</td>
3235 3238 <td>print command execution profile</td></tr>
3236 3239 <tr><td></td>
3237 3240 <td>--version</td>
3238 3241 <td>output version information and exit</td></tr>
3239 3242 <tr><td>-h</td>
3240 3243 <td>--help</td>
3241 3244 <td>display help and exit</td></tr>
3242 3245 <tr><td></td>
3243 3246 <td>--hidden</td>
3244 3247 <td>consider hidden changesets</td></tr>
3245 3248 <tr><td></td>
3246 3249 <td>--pager TYPE</td>
3247 3250 <td>when to paginate (boolean, always, auto, or never) (default: auto)</td></tr>
3248 3251 </table>
3249 3252
3250 3253 </div>
3251 3254 </div>
3252 3255 </div>
3253 3256
3254 3257
3255 3258
3256 3259 </body>
3257 3260 </html>
3258 3261
3259 3262
3260 3263 $ get-with-headers.py $LOCALIP:$HGPORT "help/dates"
3261 3264 200 Script output follows
3262 3265
3263 3266 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3264 3267 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3265 3268 <head>
3266 3269 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3267 3270 <meta name="robots" content="index, nofollow" />
3268 3271 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3269 3272 <script type="text/javascript" src="/static/mercurial.js"></script>
3270 3273
3271 3274 <title>Help: dates</title>
3272 3275 </head>
3273 3276 <body>
3274 3277
3275 3278 <div class="container">
3276 3279 <div class="menu">
3277 3280 <div class="logo">
3278 3281 <a href="https://mercurial-scm.org/">
3279 3282 <img src="/static/hglogo.png" alt="mercurial" /></a>
3280 3283 </div>
3281 3284 <ul>
3282 3285 <li><a href="/shortlog">log</a></li>
3283 3286 <li><a href="/graph">graph</a></li>
3284 3287 <li><a href="/tags">tags</a></li>
3285 3288 <li><a href="/bookmarks">bookmarks</a></li>
3286 3289 <li><a href="/branches">branches</a></li>
3287 3290 </ul>
3288 3291 <ul>
3289 3292 <li class="active"><a href="/help">help</a></li>
3290 3293 </ul>
3291 3294 </div>
3292 3295
3293 3296 <div class="main">
3294 3297 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3295 3298 <h3>Help: dates</h3>
3296 3299
3297 3300 <form class="search" action="/log">
3298 3301
3299 3302 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3300 3303 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3301 3304 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3302 3305 </form>
3303 3306 <div id="doc">
3304 3307 <h1>Date Formats</h1>
3305 3308 <p>
3306 3309 Some commands allow the user to specify a date, e.g.:
3307 3310 </p>
3308 3311 <ul>
3309 3312 <li> backout, commit, import, tag: Specify the commit date.
3310 3313 <li> log, revert, update: Select revision(s) by date.
3311 3314 </ul>
3312 3315 <p>
3313 3316 Many date formats are valid. Here are some examples:
3314 3317 </p>
3315 3318 <ul>
3316 3319 <li> &quot;Wed Dec 6 13:18:29 2006&quot; (local timezone assumed)
3317 3320 <li> &quot;Dec 6 13:18 -0600&quot; (year assumed, time offset provided)
3318 3321 <li> &quot;Dec 6 13:18 UTC&quot; (UTC and GMT are aliases for +0000)
3319 3322 <li> &quot;Dec 6&quot; (midnight)
3320 3323 <li> &quot;13:18&quot; (today assumed)
3321 3324 <li> &quot;3:39&quot; (3:39AM assumed)
3322 3325 <li> &quot;3:39pm&quot; (15:39)
3323 3326 <li> &quot;2006-12-06 13:18:29&quot; (ISO 8601 format)
3324 3327 <li> &quot;2006-12-6 13:18&quot;
3325 3328 <li> &quot;2006-12-6&quot;
3326 3329 <li> &quot;12-6&quot;
3327 3330 <li> &quot;12/6&quot;
3328 3331 <li> &quot;12/6/6&quot; (Dec 6 2006)
3329 3332 <li> &quot;today&quot; (midnight)
3330 3333 <li> &quot;yesterday&quot; (midnight)
3331 3334 <li> &quot;now&quot; - right now
3332 3335 </ul>
3333 3336 <p>
3334 3337 Lastly, there is Mercurial's internal format:
3335 3338 </p>
3336 3339 <ul>
3337 3340 <li> &quot;1165411109 0&quot; (Wed Dec 6 13:18:29 2006 UTC)
3338 3341 </ul>
3339 3342 <p>
3340 3343 This is the internal representation format for dates. The first number
3341 3344 is the number of seconds since the epoch (1970-01-01 00:00 UTC). The
3342 3345 second is the offset of the local timezone, in seconds west of UTC
3343 3346 (negative if the timezone is east of UTC).
3344 3347 </p>
3345 3348 <p>
3346 3349 The log command also accepts date ranges:
3347 3350 </p>
3348 3351 <ul>
3349 3352 <li> &quot;&lt;DATE&quot; - at or before a given date/time
3350 3353 <li> &quot;&gt;DATE&quot; - on or after a given date/time
3351 3354 <li> &quot;DATE to DATE&quot; - a date range, inclusive
3352 3355 <li> &quot;-DAYS&quot; - within a given number of days from today
3353 3356 </ul>
3354 3357
3355 3358 </div>
3356 3359 </div>
3357 3360 </div>
3358 3361
3359 3362
3360 3363
3361 3364 </body>
3362 3365 </html>
3363 3366
3364 3367
3365 3368 $ get-with-headers.py $LOCALIP:$HGPORT "help/pager"
3366 3369 200 Script output follows
3367 3370
3368 3371 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3369 3372 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3370 3373 <head>
3371 3374 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3372 3375 <meta name="robots" content="index, nofollow" />
3373 3376 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3374 3377 <script type="text/javascript" src="/static/mercurial.js"></script>
3375 3378
3376 3379 <title>Help: pager</title>
3377 3380 </head>
3378 3381 <body>
3379 3382
3380 3383 <div class="container">
3381 3384 <div class="menu">
3382 3385 <div class="logo">
3383 3386 <a href="https://mercurial-scm.org/">
3384 3387 <img src="/static/hglogo.png" alt="mercurial" /></a>
3385 3388 </div>
3386 3389 <ul>
3387 3390 <li><a href="/shortlog">log</a></li>
3388 3391 <li><a href="/graph">graph</a></li>
3389 3392 <li><a href="/tags">tags</a></li>
3390 3393 <li><a href="/bookmarks">bookmarks</a></li>
3391 3394 <li><a href="/branches">branches</a></li>
3392 3395 </ul>
3393 3396 <ul>
3394 3397 <li class="active"><a href="/help">help</a></li>
3395 3398 </ul>
3396 3399 </div>
3397 3400
3398 3401 <div class="main">
3399 3402 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3400 3403 <h3>Help: pager</h3>
3401 3404
3402 3405 <form class="search" action="/log">
3403 3406
3404 3407 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3405 3408 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3406 3409 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3407 3410 </form>
3408 3411 <div id="doc">
3409 3412 <h1>Pager Support</h1>
3410 3413 <p>
3411 3414 Some Mercurial commands can produce a lot of output, and Mercurial will
3412 3415 attempt to use a pager to make those commands more pleasant.
3413 3416 </p>
3414 3417 <p>
3415 3418 To set the pager that should be used, set the application variable:
3416 3419 </p>
3417 3420 <pre>
3418 3421 [pager]
3419 3422 pager = less -FRX
3420 3423 </pre>
3421 3424 <p>
3422 3425 If no pager is set in the user or repository configuration, Mercurial uses the
3423 3426 environment variable $PAGER. If $PAGER is not set, pager.pager from the default
3424 3427 or system configuration is used. If none of these are set, a default pager will
3425 3428 be used, typically 'less' on Unix and 'more' on Windows.
3426 3429 </p>
3427 3430 <p>
3428 3431 You can disable the pager for certain commands by adding them to the
3429 3432 pager.ignore list:
3430 3433 </p>
3431 3434 <pre>
3432 3435 [pager]
3433 3436 ignore = version, help, update
3434 3437 </pre>
3435 3438 <p>
3436 3439 To ignore global commands like 'hg version' or 'hg help', you have
3437 3440 to specify them in your user configuration file.
3438 3441 </p>
3439 3442 <p>
3440 3443 To control whether the pager is used at all for an individual command,
3441 3444 you can use --pager=&lt;value&gt;:
3442 3445 </p>
3443 3446 <ul>
3444 3447 <li> use as needed: 'auto'.
3445 3448 <li> require the pager: 'yes' or 'on'.
3446 3449 <li> suppress the pager: 'no' or 'off' (any unrecognized value will also work).
3447 3450 </ul>
3448 3451 <p>
3449 3452 To globally turn off all attempts to use a pager, set:
3450 3453 </p>
3451 3454 <pre>
3452 3455 [ui]
3453 3456 paginate = never
3454 3457 </pre>
3455 3458 <p>
3456 3459 which will prevent the pager from running.
3457 3460 </p>
3458 3461
3459 3462 </div>
3460 3463 </div>
3461 3464 </div>
3462 3465
3463 3466
3464 3467
3465 3468 </body>
3466 3469 </html>
3467 3470
3468 3471
3469 3472 Sub-topic indexes rendered properly
3470 3473
3471 3474 $ get-with-headers.py $LOCALIP:$HGPORT "help/internals"
3472 3475 200 Script output follows
3473 3476
3474 3477 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3475 3478 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3476 3479 <head>
3477 3480 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3478 3481 <meta name="robots" content="index, nofollow" />
3479 3482 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3480 3483 <script type="text/javascript" src="/static/mercurial.js"></script>
3481 3484
3482 3485 <title>Help: internals</title>
3483 3486 </head>
3484 3487 <body>
3485 3488
3486 3489 <div class="container">
3487 3490 <div class="menu">
3488 3491 <div class="logo">
3489 3492 <a href="https://mercurial-scm.org/">
3490 3493 <img src="/static/hglogo.png" alt="mercurial" /></a>
3491 3494 </div>
3492 3495 <ul>
3493 3496 <li><a href="/shortlog">log</a></li>
3494 3497 <li><a href="/graph">graph</a></li>
3495 3498 <li><a href="/tags">tags</a></li>
3496 3499 <li><a href="/bookmarks">bookmarks</a></li>
3497 3500 <li><a href="/branches">branches</a></li>
3498 3501 </ul>
3499 3502 <ul>
3500 3503 <li><a href="/help">help</a></li>
3501 3504 </ul>
3502 3505 </div>
3503 3506
3504 3507 <div class="main">
3505 3508 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3506 3509
3507 3510 <form class="search" action="/log">
3508 3511
3509 3512 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3510 3513 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3511 3514 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3512 3515 </form>
3513 3516 <table class="bigtable">
3514 3517 <tr><td colspan="2"><h2><a name="topics" href="#topics">Topics</a></h2></td></tr>
3515 3518
3516 3519 <tr><td>
3517 3520 <a href="/help/internals.bid-merge">
3518 3521 bid-merge
3519 3522 </a>
3520 3523 </td><td>
3521 3524 Bid Merge Algorithm
3522 3525 </td></tr>
3523 3526 <tr><td>
3524 3527 <a href="/help/internals.bundle2">
3525 3528 bundle2
3526 3529 </a>
3527 3530 </td><td>
3528 3531 Bundle2
3529 3532 </td></tr>
3530 3533 <tr><td>
3531 3534 <a href="/help/internals.bundles">
3532 3535 bundles
3533 3536 </a>
3534 3537 </td><td>
3535 3538 Bundles
3536 3539 </td></tr>
3537 3540 <tr><td>
3538 3541 <a href="/help/internals.cbor">
3539 3542 cbor
3540 3543 </a>
3541 3544 </td><td>
3542 3545 CBOR
3543 3546 </td></tr>
3544 3547 <tr><td>
3545 3548 <a href="/help/internals.censor">
3546 3549 censor
3547 3550 </a>
3548 3551 </td><td>
3549 3552 Censor
3550 3553 </td></tr>
3551 3554 <tr><td>
3552 3555 <a href="/help/internals.changegroups">
3553 3556 changegroups
3554 3557 </a>
3555 3558 </td><td>
3556 3559 Changegroups
3557 3560 </td></tr>
3558 3561 <tr><td>
3559 3562 <a href="/help/internals.config">
3560 3563 config
3561 3564 </a>
3562 3565 </td><td>
3563 3566 Config Registrar
3564 3567 </td></tr>
3565 3568 <tr><td>
3566 3569 <a href="/help/internals.extensions">
3567 3570 extensions
3568 3571 </a>
3569 3572 </td><td>
3570 3573 Extension API
3571 3574 </td></tr>
3572 3575 <tr><td>
3573 3576 <a href="/help/internals.mergestate">
3574 3577 mergestate
3575 3578 </a>
3576 3579 </td><td>
3577 3580 Mergestate
3578 3581 </td></tr>
3579 3582 <tr><td>
3580 3583 <a href="/help/internals.requirements">
3581 3584 requirements
3582 3585 </a>
3583 3586 </td><td>
3584 3587 Repository Requirements
3585 3588 </td></tr>
3586 3589 <tr><td>
3587 3590 <a href="/help/internals.revlogs">
3588 3591 revlogs
3589 3592 </a>
3590 3593 </td><td>
3591 3594 Revision Logs
3592 3595 </td></tr>
3593 3596 <tr><td>
3594 3597 <a href="/help/internals.wireprotocol">
3595 3598 wireprotocol
3596 3599 </a>
3597 3600 </td><td>
3598 3601 Wire Protocol
3599 3602 </td></tr>
3600 3603 <tr><td>
3601 3604 <a href="/help/internals.wireprotocolrpc">
3602 3605 wireprotocolrpc
3603 3606 </a>
3604 3607 </td><td>
3605 3608 Wire Protocol RPC
3606 3609 </td></tr>
3607 3610 <tr><td>
3608 3611 <a href="/help/internals.wireprotocolv2">
3609 3612 wireprotocolv2
3610 3613 </a>
3611 3614 </td><td>
3612 3615 Wire Protocol Version 2
3613 3616 </td></tr>
3614 3617
3615 3618
3616 3619
3617 3620
3618 3621
3619 3622 </table>
3620 3623 </div>
3621 3624 </div>
3622 3625
3623 3626
3624 3627
3625 3628 </body>
3626 3629 </html>
3627 3630
3628 3631
3629 3632 Sub-topic topics rendered properly
3630 3633
3631 3634 $ get-with-headers.py $LOCALIP:$HGPORT "help/internals.changegroups"
3632 3635 200 Script output follows
3633 3636
3634 3637 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3635 3638 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3636 3639 <head>
3637 3640 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3638 3641 <meta name="robots" content="index, nofollow" />
3639 3642 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3640 3643 <script type="text/javascript" src="/static/mercurial.js"></script>
3641 3644
3642 3645 <title>Help: internals.changegroups</title>
3643 3646 </head>
3644 3647 <body>
3645 3648
3646 3649 <div class="container">
3647 3650 <div class="menu">
3648 3651 <div class="logo">
3649 3652 <a href="https://mercurial-scm.org/">
3650 3653 <img src="/static/hglogo.png" alt="mercurial" /></a>
3651 3654 </div>
3652 3655 <ul>
3653 3656 <li><a href="/shortlog">log</a></li>
3654 3657 <li><a href="/graph">graph</a></li>
3655 3658 <li><a href="/tags">tags</a></li>
3656 3659 <li><a href="/bookmarks">bookmarks</a></li>
3657 3660 <li><a href="/branches">branches</a></li>
3658 3661 </ul>
3659 3662 <ul>
3660 3663 <li class="active"><a href="/help">help</a></li>
3661 3664 </ul>
3662 3665 </div>
3663 3666
3664 3667 <div class="main">
3665 3668 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3666 3669 <h3>Help: internals.changegroups</h3>
3667 3670
3668 3671 <form class="search" action="/log">
3669 3672
3670 3673 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3671 3674 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3672 3675 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3673 3676 </form>
3674 3677 <div id="doc">
3675 3678 <h1>Changegroups</h1>
3676 3679 <p>
3677 3680 Changegroups are representations of repository revlog data, specifically
3678 3681 the changelog data, root/flat manifest data, treemanifest data, and
3679 3682 filelogs.
3680 3683 </p>
3681 3684 <p>
3682 3685 There are 4 versions of changegroups: &quot;1&quot;, &quot;2&quot;, &quot;3&quot; and &quot;4&quot;. From a
3683 3686 high-level, versions &quot;1&quot; and &quot;2&quot; are almost exactly the same, with the
3684 3687 only difference being an additional item in the *delta header*. Version
3685 3688 &quot;3&quot; adds support for storage flags in the *delta header* and optionally
3686 3689 exchanging treemanifests (enabled by setting an option on the
3687 3690 &quot;changegroup&quot; part in the bundle2). Version &quot;4&quot; adds support for exchanging
3688 3691 sidedata (additional revision metadata not part of the digest).
3689 3692 </p>
3690 3693 <p>
3691 3694 Changegroups when not exchanging treemanifests consist of 3 logical
3692 3695 segments:
3693 3696 </p>
3694 3697 <pre>
3695 3698 +---------------------------------+
3696 3699 | | | |
3697 3700 | changeset | manifest | filelogs |
3698 3701 | | | |
3699 3702 | | | |
3700 3703 +---------------------------------+
3701 3704 </pre>
3702 3705 <p>
3703 3706 When exchanging treemanifests, there are 4 logical segments:
3704 3707 </p>
3705 3708 <pre>
3706 3709 +-------------------------------------------------+
3707 3710 | | | | |
3708 3711 | changeset | root | treemanifests | filelogs |
3709 3712 | | manifest | | |
3710 3713 | | | | |
3711 3714 +-------------------------------------------------+
3712 3715 </pre>
3713 3716 <p>
3714 3717 The principle building block of each segment is a *chunk*. A *chunk*
3715 3718 is a framed piece of data:
3716 3719 </p>
3717 3720 <pre>
3718 3721 +---------------------------------------+
3719 3722 | | |
3720 3723 | length | data |
3721 3724 | (4 bytes) | (&lt;length - 4&gt; bytes) |
3722 3725 | | |
3723 3726 +---------------------------------------+
3724 3727 </pre>
3725 3728 <p>
3726 3729 All integers are big-endian signed integers. Each chunk starts with a 32-bit
3727 3730 integer indicating the length of the entire chunk (including the length field
3728 3731 itself).
3729 3732 </p>
3730 3733 <p>
3731 3734 There is a special case chunk that has a value of 0 for the length
3732 3735 (&quot;0x00000000&quot;). We call this an *empty chunk*.
3733 3736 </p>
3734 3737 <h2>Delta Groups</h2>
3735 3738 <p>
3736 3739 A *delta group* expresses the content of a revlog as a series of deltas,
3737 3740 or patches against previous revisions.
3738 3741 </p>
3739 3742 <p>
3740 3743 Delta groups consist of 0 or more *chunks* followed by the *empty chunk*
3741 3744 to signal the end of the delta group:
3742 3745 </p>
3743 3746 <pre>
3744 3747 +------------------------------------------------------------------------+
3745 3748 | | | | | |
3746 3749 | chunk0 length | chunk0 data | chunk1 length | chunk1 data | 0x0 |
3747 3750 | (4 bytes) | (various) | (4 bytes) | (various) | (4 bytes) |
3748 3751 | | | | | |
3749 3752 +------------------------------------------------------------------------+
3750 3753 </pre>
3751 3754 <p>
3752 3755 Each *chunk*'s data consists of the following:
3753 3756 </p>
3754 3757 <pre>
3755 3758 +---------------------------------------+
3756 3759 | | |
3757 3760 | delta header | delta data |
3758 3761 | (various by version) | (various) |
3759 3762 | | |
3760 3763 +---------------------------------------+
3761 3764 </pre>
3762 3765 <p>
3763 3766 The *delta data* is a series of *delta*s that describe a diff from an existing
3764 3767 entry (either that the recipient already has, or previously specified in the
3765 3768 bundle/changegroup).
3766 3769 </p>
3767 3770 <p>
3768 3771 The *delta header* is different between versions &quot;1&quot;, &quot;2&quot;, &quot;3&quot; and &quot;4&quot;
3769 3772 of the changegroup format.
3770 3773 </p>
3771 3774 <p>
3772 3775 Version 1 (headerlen=80):
3773 3776 </p>
3774 3777 <pre>
3775 3778 +------------------------------------------------------+
3776 3779 | | | | |
3777 3780 | node | p1 node | p2 node | link node |
3778 3781 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
3779 3782 | | | | |
3780 3783 +------------------------------------------------------+
3781 3784 </pre>
3782 3785 <p>
3783 3786 Version 2 (headerlen=100):
3784 3787 </p>
3785 3788 <pre>
3786 3789 +------------------------------------------------------------------+
3787 3790 | | | | | |
3788 3791 | node | p1 node | p2 node | base node | link node |
3789 3792 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
3790 3793 | | | | | |
3791 3794 +------------------------------------------------------------------+
3792 3795 </pre>
3793 3796 <p>
3794 3797 Version 3 (headerlen=102):
3795 3798 </p>
3796 3799 <pre>
3797 3800 +------------------------------------------------------------------------------+
3798 3801 | | | | | | |
3799 3802 | node | p1 node | p2 node | base node | link node | flags |
3800 3803 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (2 bytes) |
3801 3804 | | | | | | |
3802 3805 +------------------------------------------------------------------------------+
3803 3806 </pre>
3804 3807 <p>
3805 3808 Version 4 (headerlen=103):
3806 3809 </p>
3807 3810 <pre>
3808 3811 +------------------------------------------------------------------------------+----------+
3809 3812 | | | | | | | |
3810 3813 | node | p1 node | p2 node | base node | link node | flags | pflags |
3811 3814 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (2 bytes) | (1 byte) |
3812 3815 | | | | | | | |
3813 3816 +------------------------------------------------------------------------------+----------+
3814 3817 </pre>
3815 3818 <p>
3816 3819 The *delta data* consists of &quot;chunklen - 4 - headerlen&quot; bytes, which contain a
3817 3820 series of *delta*s, densely packed (no separators). These deltas describe a diff
3818 3821 from an existing entry (either that the recipient already has, or previously
3819 3822 specified in the bundle/changegroup). The format is described more fully in
3820 3823 &quot;hg help internals.bdiff&quot;, but briefly:
3821 3824 </p>
3822 3825 <pre>
3823 3826 +---------------------------------------------------------------+
3824 3827 | | | | |
3825 3828 | start offset | end offset | new length | content |
3826 3829 | (4 bytes) | (4 bytes) | (4 bytes) | (&lt;new length&gt; bytes) |
3827 3830 | | | | |
3828 3831 +---------------------------------------------------------------+
3829 3832 </pre>
3830 3833 <p>
3831 3834 Please note that the length field in the delta data does *not* include itself.
3832 3835 </p>
3833 3836 <p>
3834 3837 In version 1, the delta is always applied against the previous node from
3835 3838 the changegroup or the first parent if this is the first entry in the
3836 3839 changegroup.
3837 3840 </p>
3838 3841 <p>
3839 3842 In version 2 and up, the delta base node is encoded in the entry in the
3840 3843 changegroup. This allows the delta to be expressed against any parent,
3841 3844 which can result in smaller deltas and more efficient encoding of data.
3842 3845 </p>
3843 3846 <p>
3844 3847 The *flags* field holds bitwise flags affecting the processing of revision
3845 3848 data. The following flags are defined:
3846 3849 </p>
3847 3850 <dl>
3848 3851 <dt>32768
3849 3852 <dd>Censored revision. The revision's fulltext has been replaced by censor metadata. May only occur on file revisions.
3850 3853 <dt>16384
3851 3854 <dd>Ellipsis revision. Revision hash does not match data (likely due to rewritten parents).
3852 3855 <dt>8192
3853 3856 <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.
3854 3857 <dt>4096
3855 3858 <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.
3856 3859 </dl>
3857 3860 <p>
3858 3861 For historical reasons, the integer values are identical to revlog version 1
3859 3862 per-revision storage flags and correspond to bits being set in this 2-byte
3860 3863 field. Bits were allocated starting from the most-significant bit, hence the
3861 3864 reverse ordering and allocation of these flags.
3862 3865 </p>
3863 3866 <p>
3864 3867 The *pflags* (protocol flags) field holds bitwise flags affecting the protocol
3865 3868 itself. They are first in the header since they may affect the handling of the
3866 3869 rest of the fields in a future version. They are defined as such:
3867 3870 </p>
3868 3871 <dl>
3869 3872 <dt>1 indicates whether to read a chunk of sidedata (of variable length) right
3870 3873 <dd>after the revision flags.
3871 3874 </dl>
3872 3875 <h2>Changeset Segment</h2>
3873 3876 <p>
3874 3877 The *changeset segment* consists of a single *delta group* holding
3875 3878 changelog data. The *empty chunk* at the end of the *delta group* denotes
3876 3879 the boundary to the *manifest segment*.
3877 3880 </p>
3878 3881 <h2>Manifest Segment</h2>
3879 3882 <p>
3880 3883 The *manifest segment* consists of a single *delta group* holding manifest
3881 3884 data. If treemanifests are in use, it contains only the manifest for the
3882 3885 root directory of the repository. Otherwise, it contains the entire
3883 3886 manifest data. The *empty chunk* at the end of the *delta group* denotes
3884 3887 the boundary to the next segment (either the *treemanifests segment* or the
3885 3888 *filelogs segment*, depending on version and the request options).
3886 3889 </p>
3887 3890 <h3>Treemanifests Segment</h3>
3888 3891 <p>
3889 3892 The *treemanifests segment* only exists in changegroup version &quot;3&quot; and &quot;4&quot;,
3890 3893 and only if the 'treemanifest' param is part of the bundle2 changegroup part
3891 3894 (it is not possible to use changegroup version 3 or 4 outside of bundle2).
3892 3895 Aside from the filenames in the *treemanifests segment* containing a
3893 3896 trailing &quot;/&quot; character, it behaves identically to the *filelogs segment*
3894 3897 (see below). The final sub-segment is followed by an *empty chunk* (logically,
3895 3898 a sub-segment with filename size 0). This denotes the boundary to the
3896 3899 *filelogs segment*.
3897 3900 </p>
3898 3901 <h2>Filelogs Segment</h2>
3899 3902 <p>
3900 3903 The *filelogs segment* consists of multiple sub-segments, each
3901 3904 corresponding to an individual file whose data is being described:
3902 3905 </p>
3903 3906 <pre>
3904 3907 +--------------------------------------------------+
3905 3908 | | | | | |
3906 3909 | filelog0 | filelog1 | filelog2 | ... | 0x0 |
3907 3910 | | | | | (4 bytes) |
3908 3911 | | | | | |
3909 3912 +--------------------------------------------------+
3910 3913 </pre>
3911 3914 <p>
3912 3915 The final filelog sub-segment is followed by an *empty chunk* (logically,
3913 3916 a sub-segment with filename size 0). This denotes the end of the segment
3914 3917 and of the overall changegroup.
3915 3918 </p>
3916 3919 <p>
3917 3920 Each filelog sub-segment consists of the following:
3918 3921 </p>
3919 3922 <pre>
3920 3923 +------------------------------------------------------+
3921 3924 | | | |
3922 3925 | filename length | filename | delta group |
3923 3926 | (4 bytes) | (&lt;length - 4&gt; bytes) | (various) |
3924 3927 | | | |
3925 3928 +------------------------------------------------------+
3926 3929 </pre>
3927 3930 <p>
3928 3931 That is, a *chunk* consisting of the filename (not terminated or padded)
3929 3932 followed by N chunks constituting the *delta group* for this file. The
3930 3933 *empty chunk* at the end of each *delta group* denotes the boundary to the
3931 3934 next filelog sub-segment.
3932 3935 </p>
3933 3936
3934 3937 </div>
3935 3938 </div>
3936 3939 </div>
3937 3940
3938 3941
3939 3942
3940 3943 </body>
3941 3944 </html>
3942 3945
3943 3946
3944 3947 $ get-with-headers.py 127.0.0.1:$HGPORT "help/unknowntopic"
3945 3948 404 Not Found
3946 3949
3947 3950 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3948 3951 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3949 3952 <head>
3950 3953 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3951 3954 <meta name="robots" content="index, nofollow" />
3952 3955 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3953 3956 <script type="text/javascript" src="/static/mercurial.js"></script>
3954 3957
3955 3958 <title>test: error</title>
3956 3959 </head>
3957 3960 <body>
3958 3961
3959 3962 <div class="container">
3960 3963 <div class="menu">
3961 3964 <div class="logo">
3962 3965 <a href="https://mercurial-scm.org/">
3963 3966 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
3964 3967 </div>
3965 3968 <ul>
3966 3969 <li><a href="/shortlog">log</a></li>
3967 3970 <li><a href="/graph">graph</a></li>
3968 3971 <li><a href="/tags">tags</a></li>
3969 3972 <li><a href="/bookmarks">bookmarks</a></li>
3970 3973 <li><a href="/branches">branches</a></li>
3971 3974 </ul>
3972 3975 <ul>
3973 3976 <li><a href="/help">help</a></li>
3974 3977 </ul>
3975 3978 </div>
3976 3979
3977 3980 <div class="main">
3978 3981
3979 3982 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3980 3983 <h3>error</h3>
3981 3984
3982 3985
3983 3986 <form class="search" action="/log">
3984 3987
3985 3988 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3986 3989 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3987 3990 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3988 3991 </form>
3989 3992
3990 3993 <div class="description">
3991 3994 <p>
3992 3995 An error occurred while processing your request:
3993 3996 </p>
3994 3997 <p>
3995 3998 Not Found
3996 3999 </p>
3997 4000 </div>
3998 4001 </div>
3999 4002 </div>
4000 4003
4001 4004
4002 4005
4003 4006 </body>
4004 4007 </html>
4005 4008
4006 4009 [1]
4007 4010
4008 4011 $ killdaemons.py
4009 4012
4010 4013 #endif
@@ -1,168 +1,414
1 1 ===============================================================
2 2 Test non-regression on the corruption associated with issue6528
3 3 ===============================================================
4 4
5 5 Setup
6 -----
6 =====
7 7
8 8 $ hg init base-repo
9 9 $ cd base-repo
10 10
11 11 $ cat <<EOF > a.txt
12 12 > 1
13 13 > 2
14 14 > 3
15 15 > 4
16 16 > 5
17 17 > 6
18 18 > EOF
19 19
20 20 $ hg add a.txt
21 21 $ hg commit -m 'c_base_c - create a.txt'
22 22
23 23 Modify a.txt
24 24
25 25 $ sed -e 's/1/foo/' a.txt > a.tmp; mv a.tmp a.txt
26 26 $ hg commit -m 'c_modify_c - modify a.txt'
27 27
28 28 Modify and rename a.txt to b.txt
29 29
30 30 $ hg up -r "desc('c_base_c')"
31 31 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
32 32 $ sed -e 's/6/bar/' a.txt > a.tmp; mv a.tmp a.txt
33 33 $ hg mv a.txt b.txt
34 34 $ hg commit -m 'c_rename_c - rename and modify a.txt to b.txt'
35 35 created new head
36 36
37 37 Merge each branch
38 38
39 39 $ hg merge -r "desc('c_modify_c')"
40 40 merging b.txt and a.txt to b.txt
41 41 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
42 42 (branch merge, don't forget to commit)
43 43 $ hg commit -m 'c_merge_c: commit merge'
44 44
45 45 $ hg debugrevlogindex b.txt
46 46 rev linkrev nodeid p1 p2
47 47 0 2 05b806ebe5ea 000000000000 000000000000
48 48 1 3 a58b36ad6b65 000000000000 05b806ebe5ea
49 49
50 50 Check commit Graph
51 51
52 52 $ hg log -G
53 53 @ changeset: 3:a1cc2bdca0aa
54 54 |\ tag: tip
55 55 | | parent: 2:615c6ccefd15
56 56 | | parent: 1:373d507f4667
57 57 | | user: test
58 58 | | date: Thu Jan 01 00:00:00 1970 +0000
59 59 | | summary: c_merge_c: commit merge
60 60 | |
61 61 | o changeset: 2:615c6ccefd15
62 62 | | parent: 0:f5a5a568022f
63 63 | | user: test
64 64 | | date: Thu Jan 01 00:00:00 1970 +0000
65 65 | | summary: c_rename_c - rename and modify a.txt to b.txt
66 66 | |
67 67 o | changeset: 1:373d507f4667
68 68 |/ user: test
69 69 | date: Thu Jan 01 00:00:00 1970 +0000
70 70 | summary: c_modify_c - modify a.txt
71 71 |
72 72 o changeset: 0:f5a5a568022f
73 73 user: test
74 74 date: Thu Jan 01 00:00:00 1970 +0000
75 75 summary: c_base_c - create a.txt
76 76
77 77
78 78 $ hg cat -r . b.txt
79 79 foo
80 80 2
81 81 3
82 82 4
83 83 5
84 84 bar
85 85 $ cat b.txt
86 86 foo
87 87 2
88 88 3
89 89 4
90 90 5
91 91 bar
92 92 $ cd ..
93 93
94 94
95 95 Check the lack of corruption
96 ----------------------------
96 ============================
97 97
98 98 $ hg clone --pull base-repo cloned
99 99 requesting all changes
100 100 adding changesets
101 101 adding manifests
102 102 adding file changes
103 103 added 4 changesets with 4 changes to 2 files
104 104 new changesets f5a5a568022f:a1cc2bdca0aa
105 105 updating to branch default
106 106 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
107 107 $ cd cloned
108 108 $ hg up -r "desc('c_merge_c')"
109 109 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
110 110
111 111
112 112 Status is buggy, even with debugrebuilddirstate
113 113
114 114 $ hg cat -r . b.txt
115 115 foo
116 116 2
117 117 3
118 118 4
119 119 5
120 120 bar
121 121 $ cat b.txt
122 122 foo
123 123 2
124 124 3
125 125 4
126 126 5
127 127 bar
128 128 $ hg status
129 129 $ hg debugrebuilddirstate
130 130 $ hg status
131 131
132 132 the history was altered
133 133
134 134 in theory p1/p2 order does not matter but in practice p1 == nullid is used as a
135 135 marker that some metadata are present and should be fetched.
136 136
137 137 $ hg debugrevlogindex b.txt
138 138 rev linkrev nodeid p1 p2
139 139 0 2 05b806ebe5ea 000000000000 000000000000
140 140 1 3 a58b36ad6b65 000000000000 05b806ebe5ea
141 141
142 142 Check commit Graph
143 143
144 144 $ hg log -G
145 145 @ changeset: 3:a1cc2bdca0aa
146 146 |\ tag: tip
147 147 | | parent: 2:615c6ccefd15
148 148 | | parent: 1:373d507f4667
149 149 | | user: test
150 150 | | date: Thu Jan 01 00:00:00 1970 +0000
151 151 | | summary: c_merge_c: commit merge
152 152 | |
153 153 | o changeset: 2:615c6ccefd15
154 154 | | parent: 0:f5a5a568022f
155 155 | | user: test
156 156 | | date: Thu Jan 01 00:00:00 1970 +0000
157 157 | | summary: c_rename_c - rename and modify a.txt to b.txt
158 158 | |
159 159 o | changeset: 1:373d507f4667
160 160 |/ user: test
161 161 | date: Thu Jan 01 00:00:00 1970 +0000
162 162 | summary: c_modify_c - modify a.txt
163 163 |
164 164 o changeset: 0:f5a5a568022f
165 165 user: test
166 166 date: Thu Jan 01 00:00:00 1970 +0000
167 167 summary: c_base_c - create a.txt
168 168
169
170 Test the command that fixes the issue
171 =====================================
172
173 Restore a broken repository with multiple broken revisions and a filename that
174 would get encoded to test the `report` options.
175 It's a tarball because unbundle might magically fix the issue later.
176
177 $ cd ..
178 $ mkdir repo-to-fix
179 $ cd repo-to-fix
180 #if windows
181 tar interprets `:` in paths (like `C:`) as being remote, force local on Windows
182 only since some versions of tar don't have this flag.
183
184 $ tar --force-local -xf $TESTDIR/bundles/issue6528.tar
185 #else
186 $ tar xf $TESTDIR/bundles/issue6528.tar
187 #endif
188
189 Check that the issue is present
190 $ hg st
191 M D.txt
192 M b.txt
193 $ hg debugrevlogindex b.txt
194 rev linkrev nodeid p1 p2
195 0 2 05b806ebe5ea 000000000000 000000000000
196 1 3 a58b36ad6b65 05b806ebe5ea 000000000000
197 2 6 216a5fe8b8ed 000000000000 000000000000
198 3 7 ea4f2f2463cc 216a5fe8b8ed 000000000000
199 $ hg debugrevlogindex D.txt
200 rev linkrev nodeid p1 p2
201 0 6 2a8d3833f2fb 000000000000 000000000000
202 1 7 2a80419dfc31 2a8d3833f2fb 000000000000
203
204 Dry-run the fix
205 $ hg debug-repair-issue6528 --dry-run
206 found affected revision 1 for filelog 'data/D.txt.i'
207 found affected revision 1 for filelog 'data/b.txt.i'
208 found affected revision 3 for filelog 'data/b.txt.i'
209 $ hg st
210 M D.txt
211 M b.txt
212 $ hg debugrevlogindex b.txt
213 rev linkrev nodeid p1 p2
214 0 2 05b806ebe5ea 000000000000 000000000000
215 1 3 a58b36ad6b65 05b806ebe5ea 000000000000
216 2 6 216a5fe8b8ed 000000000000 000000000000
217 3 7 ea4f2f2463cc 216a5fe8b8ed 000000000000
218 $ hg debugrevlogindex D.txt
219 rev linkrev nodeid p1 p2
220 0 6 2a8d3833f2fb 000000000000 000000000000
221 1 7 2a80419dfc31 2a8d3833f2fb 000000000000
222
223 Run the fix
224 $ hg debug-repair-issue6528
225 found affected revision 1 for filelog 'data/D.txt.i'
226 repaired revision 1 of 'filelog data/D.txt.i'
227 found affected revision 1 for filelog 'data/b.txt.i'
228 found affected revision 3 for filelog 'data/b.txt.i'
229 repaired revision 1 of 'filelog data/b.txt.i'
230 repaired revision 3 of 'filelog data/b.txt.i'
231
232 Check that the fix worked and that running it twice does nothing
233 $ hg st
234 $ hg debugrevlogindex b.txt
235 rev linkrev nodeid p1 p2
236 0 2 05b806ebe5ea 000000000000 000000000000
237 1 3 a58b36ad6b65 000000000000 05b806ebe5ea
238 2 6 216a5fe8b8ed 000000000000 000000000000
239 3 7 ea4f2f2463cc 000000000000 216a5fe8b8ed
240 $ hg debugrevlogindex D.txt
241 rev linkrev nodeid p1 p2
242 0 6 2a8d3833f2fb 000000000000 000000000000
243 1 7 2a80419dfc31 000000000000 2a8d3833f2fb
244 $ hg debug-repair-issue6528
245 no affected revisions were found
246 $ hg st
247 $ hg debugrevlogindex b.txt
248 rev linkrev nodeid p1 p2
249 0 2 05b806ebe5ea 000000000000 000000000000
250 1 3 a58b36ad6b65 000000000000 05b806ebe5ea
251 2 6 216a5fe8b8ed 000000000000 000000000000
252 3 7 ea4f2f2463cc 000000000000 216a5fe8b8ed
253 $ hg debugrevlogindex D.txt
254 rev linkrev nodeid p1 p2
255 0 6 2a8d3833f2fb 000000000000 000000000000
256 1 7 2a80419dfc31 000000000000 2a8d3833f2fb
257
258 Try the using the report options
259 --------------------------------
260
261 $ cd ..
262 $ mkdir repo-to-fix-report
263 $ cd repo-to-fix
264 #if windows
265 tar interprets `:` in paths (like `C:`) as being remote, force local on Windows
266 only since some versions of tar don't have this flag.
267
268 $ tar --force-local -xf $TESTDIR/bundles/issue6528.tar
269 #else
270 $ tar xf $TESTDIR/bundles/issue6528.tar
271 #endif
272
273 $ hg debug-repair-issue6528 --to-report $TESTTMP/report.txt
274 found affected revision 1 for filelog 'data/D.txt.i'
275 found affected revision 1 for filelog 'data/b.txt.i'
276 found affected revision 3 for filelog 'data/b.txt.i'
277 $ cat $TESTTMP/report.txt
278 2a80419dfc31d7dfb308ac40f3f138282de7d73b D.txt
279 a58b36ad6b6545195952793099613c2116f3563b,ea4f2f2463cca5b29ddf3461012b8ce5c6dac175 b.txt
280
281 $ hg debug-repair-issue6528 --from-report $TESTTMP/report.txt --dry-run
282 loading report file '$TESTTMP/report.txt'
283 found affected revision 1 for filelog 'D.txt'
284 found affected revision 1 for filelog 'b.txt'
285 found affected revision 3 for filelog 'b.txt'
286 $ hg st
287 M D.txt
288 M b.txt
289 $ hg debugrevlogindex b.txt
290 rev linkrev nodeid p1 p2
291 0 2 05b806ebe5ea 000000000000 000000000000
292 1 3 a58b36ad6b65 05b806ebe5ea 000000000000
293 2 6 216a5fe8b8ed 000000000000 000000000000
294 3 7 ea4f2f2463cc 216a5fe8b8ed 000000000000
295 $ hg debugrevlogindex D.txt
296 rev linkrev nodeid p1 p2
297 0 6 2a8d3833f2fb 000000000000 000000000000
298 1 7 2a80419dfc31 2a8d3833f2fb 000000000000
299
300 $ hg debug-repair-issue6528 --from-report $TESTTMP/report.txt
301 loading report file '$TESTTMP/report.txt'
302 found affected revision 1 for filelog 'D.txt'
303 repaired revision 1 of 'filelog data/D.txt.i'
304 found affected revision 1 for filelog 'b.txt'
305 found affected revision 3 for filelog 'b.txt'
306 repaired revision 1 of 'filelog data/b.txt.i'
307 repaired revision 3 of 'filelog data/b.txt.i'
308 $ hg st
309 $ hg debugrevlogindex b.txt
310 rev linkrev nodeid p1 p2
311 0 2 05b806ebe5ea 000000000000 000000000000
312 1 3 a58b36ad6b65 000000000000 05b806ebe5ea
313 2 6 216a5fe8b8ed 000000000000 000000000000
314 3 7 ea4f2f2463cc 000000000000 216a5fe8b8ed
315 $ hg debugrevlogindex D.txt
316 rev linkrev nodeid p1 p2
317 0 6 2a8d3833f2fb 000000000000 000000000000
318 1 7 2a80419dfc31 000000000000 2a8d3833f2fb
319
320 Check that the revision is not "fixed" again
321
322 $ hg debug-repair-issue6528 --from-report $TESTTMP/report.txt
323 loading report file '$TESTTMP/report.txt'
324 revision 2a80419dfc31d7dfb308ac40f3f138282de7d73b of file 'D.txt' is not affected
325 no affected revisions were found for 'D.txt'
326 revision a58b36ad6b6545195952793099613c2116f3563b of file 'b.txt' is not affected
327 revision ea4f2f2463cca5b29ddf3461012b8ce5c6dac175 of file 'b.txt' is not affected
328 no affected revisions were found for 'b.txt'
329 $ hg st
330 $ hg debugrevlogindex b.txt
331 rev linkrev nodeid p1 p2
332 0 2 05b806ebe5ea 000000000000 000000000000
333 1 3 a58b36ad6b65 000000000000 05b806ebe5ea
334 2 6 216a5fe8b8ed 000000000000 000000000000
335 3 7 ea4f2f2463cc 000000000000 216a5fe8b8ed
336 $ hg debugrevlogindex D.txt
337 rev linkrev nodeid p1 p2
338 0 6 2a8d3833f2fb 000000000000 000000000000
339 1 7 2a80419dfc31 000000000000 2a8d3833f2fb
340
341 Try it with a non-inline revlog
342 -------------------------------
343
344 $ cd ..
345 $ mkdir $TESTTMP/ext
346 $ cat << EOF > $TESTTMP/ext/small_inline.py
347 > from mercurial import revlog
348 > revlog._maxinline = 8
349 > EOF
350
351 $ cat << EOF >> $HGRCPATH
352 > [extensions]
353 > small_inline=$TESTTMP/ext/small_inline.py
354 > EOF
355
356 $ mkdir repo-to-fix-not-inline
357 $ cd repo-to-fix-not-inline
358 #if windows
359 tar interprets `:` in paths (like `C:`) as being remote, force local on Windows
360 only since some versions of tar don't have this flag.
361
362 $ tar --force-local -xf $TESTDIR/bundles/issue6528.tar
363 #else
364 $ tar xf $TESTDIR/bundles/issue6528.tar
365 #endif
366 $ echo b >> b.txt
367 $ hg commit -qm "inline -> separate"
368 $ find .hg -name *b.txt.d
369 .hg/store/data/b.txt.d
370
371 Status is correct, but the problem is still there, in the earlier revision
372 $ hg st
373 $ hg up 3
374 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
375 $ hg st
376 M b.txt
377 $ hg debugrevlogindex b.txt
378 rev linkrev nodeid p1 p2
379 0 2 05b806ebe5ea 000000000000 000000000000
380 1 3 a58b36ad6b65 05b806ebe5ea 000000000000
381 2 6 216a5fe8b8ed 000000000000 000000000000
382 3 7 ea4f2f2463cc 216a5fe8b8ed 000000000000
383 4 8 db234885e2fe ea4f2f2463cc 000000000000
384 $ hg debugrevlogindex D.txt
385 rev linkrev nodeid p1 p2
386 0 6 2a8d3833f2fb 000000000000 000000000000
387 1 7 2a80419dfc31 2a8d3833f2fb 000000000000
388 2 8 65aecc89bb5d 2a80419dfc31 000000000000
389
390 Run the fix on the non-inline revlog
391 $ hg debug-repair-issue6528
392 found affected revision 1 for filelog 'data/D.txt.i'
393 repaired revision 1 of 'filelog data/D.txt.i'
394 found affected revision 1 for filelog 'data/b.txt.i'
395 found affected revision 3 for filelog 'data/b.txt.i'
396 repaired revision 1 of 'filelog data/b.txt.i'
397 repaired revision 3 of 'filelog data/b.txt.i'
398
399 Check that it worked
400 $ hg debugrevlogindex b.txt
401 rev linkrev nodeid p1 p2
402 0 2 05b806ebe5ea 000000000000 000000000000
403 1 3 a58b36ad6b65 000000000000 05b806ebe5ea
404 2 6 216a5fe8b8ed 000000000000 000000000000
405 3 7 ea4f2f2463cc 000000000000 216a5fe8b8ed
406 4 8 db234885e2fe ea4f2f2463cc 000000000000
407 $ hg debugrevlogindex D.txt
408 rev linkrev nodeid p1 p2
409 0 6 2a8d3833f2fb 000000000000 000000000000
410 1 7 2a80419dfc31 000000000000 2a8d3833f2fb
411 2 8 65aecc89bb5d 2a80419dfc31 000000000000
412 $ hg debug-repair-issue6528
413 no affected revisions were found
414 $ hg st
General Comments 0
You need to be logged in to leave comments. Login now