##// END OF EJS Templates
context: introduce p[12]copies() methods and debugp[12]copies commands...
Martin von Zweigbergk -
r41905:456ad0fd default draft
parent child Browse files
Show More
@@ -1,2485 +1,2551 b''
1 1 # context.py - changeset and file context objects for mercurial
2 2 #
3 3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import errno
11 11 import filecmp
12 12 import os
13 13 import stat
14 14
15 15 from .i18n import _
16 16 from .node import (
17 17 addednodeid,
18 18 hex,
19 19 modifiednodeid,
20 20 nullid,
21 21 nullrev,
22 22 short,
23 23 wdirfilenodeids,
24 24 wdirid,
25 25 )
26 26 from . import (
27 27 dagop,
28 28 encoding,
29 29 error,
30 30 fileset,
31 31 match as matchmod,
32 32 obsolete as obsmod,
33 33 patch,
34 34 pathutil,
35 35 phases,
36 36 pycompat,
37 37 repoview,
38 38 scmutil,
39 39 sparse,
40 40 subrepo,
41 41 subrepoutil,
42 42 util,
43 43 )
44 44 from .utils import (
45 45 dateutil,
46 46 stringutil,
47 47 )
48 48
49 49 propertycache = util.propertycache
50 50
51 51 class basectx(object):
52 52 """A basectx object represents the common logic for its children:
53 53 changectx: read-only context that is already present in the repo,
54 54 workingctx: a context that represents the working directory and can
55 55 be committed,
56 56 memctx: a context that represents changes in-memory and can also
57 57 be committed."""
58 58
59 59 def __init__(self, repo):
60 60 self._repo = repo
61 61
62 62 def __bytes__(self):
63 63 return short(self.node())
64 64
65 65 __str__ = encoding.strmethod(__bytes__)
66 66
67 67 def __repr__(self):
68 68 return r"<%s %s>" % (type(self).__name__, str(self))
69 69
70 70 def __eq__(self, other):
71 71 try:
72 72 return type(self) == type(other) and self._rev == other._rev
73 73 except AttributeError:
74 74 return False
75 75
76 76 def __ne__(self, other):
77 77 return not (self == other)
78 78
79 79 def __contains__(self, key):
80 80 return key in self._manifest
81 81
82 82 def __getitem__(self, key):
83 83 return self.filectx(key)
84 84
85 85 def __iter__(self):
86 86 return iter(self._manifest)
87 87
88 88 def _buildstatusmanifest(self, status):
89 89 """Builds a manifest that includes the given status results, if this is
90 90 a working copy context. For non-working copy contexts, it just returns
91 91 the normal manifest."""
92 92 return self.manifest()
93 93
94 94 def _matchstatus(self, other, match):
95 95 """This internal method provides a way for child objects to override the
96 96 match operator.
97 97 """
98 98 return match
99 99
100 100 def _buildstatus(self, other, s, match, listignored, listclean,
101 101 listunknown):
102 102 """build a status with respect to another context"""
103 103 # Load earliest manifest first for caching reasons. More specifically,
104 104 # if you have revisions 1000 and 1001, 1001 is probably stored as a
105 105 # delta against 1000. Thus, if you read 1000 first, we'll reconstruct
106 106 # 1000 and cache it so that when you read 1001, we just need to apply a
107 107 # delta to what's in the cache. So that's one full reconstruction + one
108 108 # delta application.
109 109 mf2 = None
110 110 if self.rev() is not None and self.rev() < other.rev():
111 111 mf2 = self._buildstatusmanifest(s)
112 112 mf1 = other._buildstatusmanifest(s)
113 113 if mf2 is None:
114 114 mf2 = self._buildstatusmanifest(s)
115 115
116 116 modified, added = [], []
117 117 removed = []
118 118 clean = []
119 119 deleted, unknown, ignored = s.deleted, s.unknown, s.ignored
120 120 deletedset = set(deleted)
121 121 d = mf1.diff(mf2, match=match, clean=listclean)
122 122 for fn, value in d.iteritems():
123 123 if fn in deletedset:
124 124 continue
125 125 if value is None:
126 126 clean.append(fn)
127 127 continue
128 128 (node1, flag1), (node2, flag2) = value
129 129 if node1 is None:
130 130 added.append(fn)
131 131 elif node2 is None:
132 132 removed.append(fn)
133 133 elif flag1 != flag2:
134 134 modified.append(fn)
135 135 elif node2 not in wdirfilenodeids:
136 136 # When comparing files between two commits, we save time by
137 137 # not comparing the file contents when the nodeids differ.
138 138 # Note that this means we incorrectly report a reverted change
139 139 # to a file as a modification.
140 140 modified.append(fn)
141 141 elif self[fn].cmp(other[fn]):
142 142 modified.append(fn)
143 143 else:
144 144 clean.append(fn)
145 145
146 146 if removed:
147 147 # need to filter files if they are already reported as removed
148 148 unknown = [fn for fn in unknown if fn not in mf1 and
149 149 (not match or match(fn))]
150 150 ignored = [fn for fn in ignored if fn not in mf1 and
151 151 (not match or match(fn))]
152 152 # if they're deleted, don't report them as removed
153 153 removed = [fn for fn in removed if fn not in deletedset]
154 154
155 155 return scmutil.status(modified, added, removed, deleted, unknown,
156 156 ignored, clean)
157 157
158 158 @propertycache
159 159 def substate(self):
160 160 return subrepoutil.state(self, self._repo.ui)
161 161
162 162 def subrev(self, subpath):
163 163 return self.substate[subpath][1]
164 164
165 165 def rev(self):
166 166 return self._rev
167 167 def node(self):
168 168 return self._node
169 169 def hex(self):
170 170 return hex(self.node())
171 171 def manifest(self):
172 172 return self._manifest
173 173 def manifestctx(self):
174 174 return self._manifestctx
175 175 def repo(self):
176 176 return self._repo
177 177 def phasestr(self):
178 178 return phases.phasenames[self.phase()]
179 179 def mutable(self):
180 180 return self.phase() > phases.public
181 181
182 182 def matchfileset(self, expr, badfn=None):
183 183 return fileset.match(self, expr, badfn=badfn)
184 184
185 185 def obsolete(self):
186 186 """True if the changeset is obsolete"""
187 187 return self.rev() in obsmod.getrevs(self._repo, 'obsolete')
188 188
189 189 def extinct(self):
190 190 """True if the changeset is extinct"""
191 191 return self.rev() in obsmod.getrevs(self._repo, 'extinct')
192 192
193 193 def orphan(self):
194 194 """True if the changeset is not obsolete, but its ancestor is"""
195 195 return self.rev() in obsmod.getrevs(self._repo, 'orphan')
196 196
197 197 def phasedivergent(self):
198 198 """True if the changeset tries to be a successor of a public changeset
199 199
200 200 Only non-public and non-obsolete changesets may be phase-divergent.
201 201 """
202 202 return self.rev() in obsmod.getrevs(self._repo, 'phasedivergent')
203 203
204 204 def contentdivergent(self):
205 205 """Is a successor of a changeset with multiple possible successor sets
206 206
207 207 Only non-public and non-obsolete changesets may be content-divergent.
208 208 """
209 209 return self.rev() in obsmod.getrevs(self._repo, 'contentdivergent')
210 210
211 211 def isunstable(self):
212 212 """True if the changeset is either orphan, phase-divergent or
213 213 content-divergent"""
214 214 return self.orphan() or self.phasedivergent() or self.contentdivergent()
215 215
216 216 def instabilities(self):
217 217 """return the list of instabilities affecting this changeset.
218 218
219 219 Instabilities are returned as strings. possible values are:
220 220 - orphan,
221 221 - phase-divergent,
222 222 - content-divergent.
223 223 """
224 224 instabilities = []
225 225 if self.orphan():
226 226 instabilities.append('orphan')
227 227 if self.phasedivergent():
228 228 instabilities.append('phase-divergent')
229 229 if self.contentdivergent():
230 230 instabilities.append('content-divergent')
231 231 return instabilities
232 232
233 233 def parents(self):
234 234 """return contexts for each parent changeset"""
235 235 return self._parents
236 236
237 237 def p1(self):
238 238 return self._parents[0]
239 239
240 240 def p2(self):
241 241 parents = self._parents
242 242 if len(parents) == 2:
243 243 return parents[1]
244 244 return self._repo[nullrev]
245 245
246 246 def _fileinfo(self, path):
247 247 if r'_manifest' in self.__dict__:
248 248 try:
249 249 return self._manifest[path], self._manifest.flags(path)
250 250 except KeyError:
251 251 raise error.ManifestLookupError(self._node, path,
252 252 _('not found in manifest'))
253 253 if r'_manifestdelta' in self.__dict__ or path in self.files():
254 254 if path in self._manifestdelta:
255 255 return (self._manifestdelta[path],
256 256 self._manifestdelta.flags(path))
257 257 mfl = self._repo.manifestlog
258 258 try:
259 259 node, flag = mfl[self._changeset.manifest].find(path)
260 260 except KeyError:
261 261 raise error.ManifestLookupError(self._node, path,
262 262 _('not found in manifest'))
263 263
264 264 return node, flag
265 265
266 266 def filenode(self, path):
267 267 return self._fileinfo(path)[0]
268 268
269 269 def flags(self, path):
270 270 try:
271 271 return self._fileinfo(path)[1]
272 272 except error.LookupError:
273 273 return ''
274 274
275 275 def sub(self, path, allowcreate=True):
276 276 '''return a subrepo for the stored revision of path, never wdir()'''
277 277 return subrepo.subrepo(self, path, allowcreate=allowcreate)
278 278
279 279 def nullsub(self, path, pctx):
280 280 return subrepo.nullsubrepo(self, path, pctx)
281 281
282 282 def workingsub(self, path):
283 283 '''return a subrepo for the stored revision, or wdir if this is a wdir
284 284 context.
285 285 '''
286 286 return subrepo.subrepo(self, path, allowwdir=True)
287 287
288 288 def match(self, pats=None, include=None, exclude=None, default='glob',
289 289 listsubrepos=False, badfn=None):
290 290 r = self._repo
291 291 return matchmod.match(r.root, r.getcwd(), pats,
292 292 include, exclude, default,
293 293 auditor=r.nofsauditor, ctx=self,
294 294 listsubrepos=listsubrepos, badfn=badfn)
295 295
296 296 def diff(self, ctx2=None, match=None, changes=None, opts=None,
297 297 losedatafn=None, pathfn=None, copy=None,
298 298 copysourcematch=None, hunksfilterfn=None):
299 299 """Returns a diff generator for the given contexts and matcher"""
300 300 if ctx2 is None:
301 301 ctx2 = self.p1()
302 302 if ctx2 is not None:
303 303 ctx2 = self._repo[ctx2]
304 304 return patch.diff(self._repo, ctx2, self, match=match, changes=changes,
305 305 opts=opts, losedatafn=losedatafn, pathfn=pathfn,
306 306 copy=copy, copysourcematch=copysourcematch,
307 307 hunksfilterfn=hunksfilterfn)
308 308
309 309 def dirs(self):
310 310 return self._manifest.dirs()
311 311
312 312 def hasdir(self, dir):
313 313 return self._manifest.hasdir(dir)
314 314
315 315 def status(self, other=None, match=None, listignored=False,
316 316 listclean=False, listunknown=False, listsubrepos=False):
317 317 """return status of files between two nodes or node and working
318 318 directory.
319 319
320 320 If other is None, compare this node with working directory.
321 321
322 322 returns (modified, added, removed, deleted, unknown, ignored, clean)
323 323 """
324 324
325 325 ctx1 = self
326 326 ctx2 = self._repo[other]
327 327
328 328 # This next code block is, admittedly, fragile logic that tests for
329 329 # reversing the contexts and wouldn't need to exist if it weren't for
330 330 # the fast (and common) code path of comparing the working directory
331 331 # with its first parent.
332 332 #
333 333 # What we're aiming for here is the ability to call:
334 334 #
335 335 # workingctx.status(parentctx)
336 336 #
337 337 # If we always built the manifest for each context and compared those,
338 338 # then we'd be done. But the special case of the above call means we
339 339 # just copy the manifest of the parent.
340 340 reversed = False
341 341 if (not isinstance(ctx1, changectx)
342 342 and isinstance(ctx2, changectx)):
343 343 reversed = True
344 344 ctx1, ctx2 = ctx2, ctx1
345 345
346 346 match = self._repo.narrowmatch(match)
347 347 match = ctx2._matchstatus(ctx1, match)
348 348 r = scmutil.status([], [], [], [], [], [], [])
349 349 r = ctx2._buildstatus(ctx1, r, match, listignored, listclean,
350 350 listunknown)
351 351
352 352 if reversed:
353 353 # Reverse added and removed. Clear deleted, unknown and ignored as
354 354 # these make no sense to reverse.
355 355 r = scmutil.status(r.modified, r.removed, r.added, [], [], [],
356 356 r.clean)
357 357
358 358 if listsubrepos:
359 359 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
360 360 try:
361 361 rev2 = ctx2.subrev(subpath)
362 362 except KeyError:
363 363 # A subrepo that existed in node1 was deleted between
364 364 # node1 and node2 (inclusive). Thus, ctx2's substate
365 365 # won't contain that subpath. The best we can do ignore it.
366 366 rev2 = None
367 367 submatch = matchmod.subdirmatcher(subpath, match)
368 368 s = sub.status(rev2, match=submatch, ignored=listignored,
369 369 clean=listclean, unknown=listunknown,
370 370 listsubrepos=True)
371 371 for rfiles, sfiles in zip(r, s):
372 372 rfiles.extend("%s/%s" % (subpath, f) for f in sfiles)
373 373
374 374 for l in r:
375 375 l.sort()
376 376
377 377 return r
378 378
379 379 class changectx(basectx):
380 380 """A changecontext object makes access to data related to a particular
381 381 changeset convenient. It represents a read-only context already present in
382 382 the repo."""
383 383 def __init__(self, repo, rev, node):
384 384 super(changectx, self).__init__(repo)
385 385 self._rev = rev
386 386 self._node = node
387 387
388 388 def __hash__(self):
389 389 try:
390 390 return hash(self._rev)
391 391 except AttributeError:
392 392 return id(self)
393 393
394 394 def __nonzero__(self):
395 395 return self._rev != nullrev
396 396
397 397 __bool__ = __nonzero__
398 398
399 399 @propertycache
400 400 def _changeset(self):
401 401 return self._repo.changelog.changelogrevision(self.rev())
402 402
403 403 @propertycache
404 404 def _manifest(self):
405 405 return self._manifestctx.read()
406 406
407 407 @property
408 408 def _manifestctx(self):
409 409 return self._repo.manifestlog[self._changeset.manifest]
410 410
411 411 @propertycache
412 412 def _manifestdelta(self):
413 413 return self._manifestctx.readdelta()
414 414
415 415 @propertycache
416 416 def _parents(self):
417 417 repo = self._repo
418 418 p1, p2 = repo.changelog.parentrevs(self._rev)
419 419 if p2 == nullrev:
420 420 return [repo[p1]]
421 421 return [repo[p1], repo[p2]]
422 422
423 423 def changeset(self):
424 424 c = self._changeset
425 425 return (
426 426 c.manifest,
427 427 c.user,
428 428 c.date,
429 429 c.files,
430 430 c.description,
431 431 c.extra,
432 432 )
433 433 def manifestnode(self):
434 434 return self._changeset.manifest
435 435
436 436 def user(self):
437 437 return self._changeset.user
438 438 def date(self):
439 439 return self._changeset.date
440 440 def files(self):
441 441 return self._changeset.files
442 @propertycache
443 def _copies(self):
444 p1copies = {}
445 p2copies = {}
446 p1 = self.p1()
447 p2 = self.p2()
448 narrowmatch = self._repo.narrowmatch()
449 for dst in self.files():
450 if not narrowmatch(dst) or dst not in self:
451 continue
452 copied = self[dst].renamed()
453 if not copied:
454 continue
455 src, srcnode = copied
456 if src in p1 and p1[src].filenode() == srcnode:
457 p1copies[dst] = src
458 elif src in p2 and p2[src].filenode() == srcnode:
459 p2copies[dst] = src
460 return p1copies, p2copies
461 def p1copies(self):
462 return self._copies[0]
463 def p2copies(self):
464 return self._copies[1]
442 465 def description(self):
443 466 return self._changeset.description
444 467 def branch(self):
445 468 return encoding.tolocal(self._changeset.extra.get("branch"))
446 469 def closesbranch(self):
447 470 return 'close' in self._changeset.extra
448 471 def extra(self):
449 472 """Return a dict of extra information."""
450 473 return self._changeset.extra
451 474 def tags(self):
452 475 """Return a list of byte tag names"""
453 476 return self._repo.nodetags(self._node)
454 477 def bookmarks(self):
455 478 """Return a list of byte bookmark names."""
456 479 return self._repo.nodebookmarks(self._node)
457 480 def phase(self):
458 481 return self._repo._phasecache.phase(self._repo, self._rev)
459 482 def hidden(self):
460 483 return self._rev in repoview.filterrevs(self._repo, 'visible')
461 484
462 485 def isinmemory(self):
463 486 return False
464 487
465 488 def children(self):
466 489 """return list of changectx contexts for each child changeset.
467 490
468 491 This returns only the immediate child changesets. Use descendants() to
469 492 recursively walk children.
470 493 """
471 494 c = self._repo.changelog.children(self._node)
472 495 return [self._repo[x] for x in c]
473 496
474 497 def ancestors(self):
475 498 for a in self._repo.changelog.ancestors([self._rev]):
476 499 yield self._repo[a]
477 500
478 501 def descendants(self):
479 502 """Recursively yield all children of the changeset.
480 503
481 504 For just the immediate children, use children()
482 505 """
483 506 for d in self._repo.changelog.descendants([self._rev]):
484 507 yield self._repo[d]
485 508
486 509 def filectx(self, path, fileid=None, filelog=None):
487 510 """get a file context from this changeset"""
488 511 if fileid is None:
489 512 fileid = self.filenode(path)
490 513 return filectx(self._repo, path, fileid=fileid,
491 514 changectx=self, filelog=filelog)
492 515
493 516 def ancestor(self, c2, warn=False):
494 517 """return the "best" ancestor context of self and c2
495 518
496 519 If there are multiple candidates, it will show a message and check
497 520 merge.preferancestor configuration before falling back to the
498 521 revlog ancestor."""
499 522 # deal with workingctxs
500 523 n2 = c2._node
501 524 if n2 is None:
502 525 n2 = c2._parents[0]._node
503 526 cahs = self._repo.changelog.commonancestorsheads(self._node, n2)
504 527 if not cahs:
505 528 anc = nullid
506 529 elif len(cahs) == 1:
507 530 anc = cahs[0]
508 531 else:
509 532 # experimental config: merge.preferancestor
510 533 for r in self._repo.ui.configlist('merge', 'preferancestor'):
511 534 try:
512 535 ctx = scmutil.revsymbol(self._repo, r)
513 536 except error.RepoLookupError:
514 537 continue
515 538 anc = ctx.node()
516 539 if anc in cahs:
517 540 break
518 541 else:
519 542 anc = self._repo.changelog.ancestor(self._node, n2)
520 543 if warn:
521 544 self._repo.ui.status(
522 545 (_("note: using %s as ancestor of %s and %s\n") %
523 546 (short(anc), short(self._node), short(n2))) +
524 547 ''.join(_(" alternatively, use --config "
525 548 "merge.preferancestor=%s\n") %
526 549 short(n) for n in sorted(cahs) if n != anc))
527 550 return self._repo[anc]
528 551
529 552 def isancestorof(self, other):
530 553 """True if this changeset is an ancestor of other"""
531 554 return self._repo.changelog.isancestorrev(self._rev, other._rev)
532 555
533 556 def walk(self, match):
534 557 '''Generates matching file names.'''
535 558
536 559 # Wrap match.bad method to have message with nodeid
537 560 def bad(fn, msg):
538 561 # The manifest doesn't know about subrepos, so don't complain about
539 562 # paths into valid subrepos.
540 563 if any(fn == s or fn.startswith(s + '/')
541 564 for s in self.substate):
542 565 return
543 566 match.bad(fn, _('no such file in rev %s') % self)
544 567
545 568 m = matchmod.badmatch(self._repo.narrowmatch(match), bad)
546 569 return self._manifest.walk(m)
547 570
548 571 def matches(self, match):
549 572 return self.walk(match)
550 573
551 574 class basefilectx(object):
552 575 """A filecontext object represents the common logic for its children:
553 576 filectx: read-only access to a filerevision that is already present
554 577 in the repo,
555 578 workingfilectx: a filecontext that represents files from the working
556 579 directory,
557 580 memfilectx: a filecontext that represents files in-memory,
558 581 """
559 582 @propertycache
560 583 def _filelog(self):
561 584 return self._repo.file(self._path)
562 585
563 586 @propertycache
564 587 def _changeid(self):
565 588 if r'_changectx' in self.__dict__:
566 589 return self._changectx.rev()
567 590 elif r'_descendantrev' in self.__dict__:
568 591 # this file context was created from a revision with a known
569 592 # descendant, we can (lazily) correct for linkrev aliases
570 593 return self._adjustlinkrev(self._descendantrev)
571 594 else:
572 595 return self._filelog.linkrev(self._filerev)
573 596
574 597 @propertycache
575 598 def _filenode(self):
576 599 if r'_fileid' in self.__dict__:
577 600 return self._filelog.lookup(self._fileid)
578 601 else:
579 602 return self._changectx.filenode(self._path)
580 603
581 604 @propertycache
582 605 def _filerev(self):
583 606 return self._filelog.rev(self._filenode)
584 607
585 608 @propertycache
586 609 def _repopath(self):
587 610 return self._path
588 611
589 612 def __nonzero__(self):
590 613 try:
591 614 self._filenode
592 615 return True
593 616 except error.LookupError:
594 617 # file is missing
595 618 return False
596 619
597 620 __bool__ = __nonzero__
598 621
599 622 def __bytes__(self):
600 623 try:
601 624 return "%s@%s" % (self.path(), self._changectx)
602 625 except error.LookupError:
603 626 return "%s@???" % self.path()
604 627
605 628 __str__ = encoding.strmethod(__bytes__)
606 629
607 630 def __repr__(self):
608 631 return r"<%s %s>" % (type(self).__name__, str(self))
609 632
610 633 def __hash__(self):
611 634 try:
612 635 return hash((self._path, self._filenode))
613 636 except AttributeError:
614 637 return id(self)
615 638
616 639 def __eq__(self, other):
617 640 try:
618 641 return (type(self) == type(other) and self._path == other._path
619 642 and self._filenode == other._filenode)
620 643 except AttributeError:
621 644 return False
622 645
623 646 def __ne__(self, other):
624 647 return not (self == other)
625 648
626 649 def filerev(self):
627 650 return self._filerev
628 651 def filenode(self):
629 652 return self._filenode
630 653 @propertycache
631 654 def _flags(self):
632 655 return self._changectx.flags(self._path)
633 656 def flags(self):
634 657 return self._flags
635 658 def filelog(self):
636 659 return self._filelog
637 660 def rev(self):
638 661 return self._changeid
639 662 def linkrev(self):
640 663 return self._filelog.linkrev(self._filerev)
641 664 def node(self):
642 665 return self._changectx.node()
643 666 def hex(self):
644 667 return self._changectx.hex()
645 668 def user(self):
646 669 return self._changectx.user()
647 670 def date(self):
648 671 return self._changectx.date()
649 672 def files(self):
650 673 return self._changectx.files()
651 674 def description(self):
652 675 return self._changectx.description()
653 676 def branch(self):
654 677 return self._changectx.branch()
655 678 def extra(self):
656 679 return self._changectx.extra()
657 680 def phase(self):
658 681 return self._changectx.phase()
659 682 def phasestr(self):
660 683 return self._changectx.phasestr()
661 684 def obsolete(self):
662 685 return self._changectx.obsolete()
663 686 def instabilities(self):
664 687 return self._changectx.instabilities()
665 688 def manifest(self):
666 689 return self._changectx.manifest()
667 690 def changectx(self):
668 691 return self._changectx
669 692 def renamed(self):
670 693 return self._copied
671 694 def repo(self):
672 695 return self._repo
673 696 def size(self):
674 697 return len(self.data())
675 698
676 699 def path(self):
677 700 return self._path
678 701
679 702 def isbinary(self):
680 703 try:
681 704 return stringutil.binary(self.data())
682 705 except IOError:
683 706 return False
684 707 def isexec(self):
685 708 return 'x' in self.flags()
686 709 def islink(self):
687 710 return 'l' in self.flags()
688 711
689 712 def isabsent(self):
690 713 """whether this filectx represents a file not in self._changectx
691 714
692 715 This is mainly for merge code to detect change/delete conflicts. This is
693 716 expected to be True for all subclasses of basectx."""
694 717 return False
695 718
696 719 _customcmp = False
697 720 def cmp(self, fctx):
698 721 """compare with other file context
699 722
700 723 returns True if different than fctx.
701 724 """
702 725 if fctx._customcmp:
703 726 return fctx.cmp(self)
704 727
705 728 if self._filenode is None:
706 729 raise error.ProgrammingError(
707 730 'filectx.cmp() must be reimplemented if not backed by revlog')
708 731
709 732 if fctx._filenode is None:
710 733 if self._repo._encodefilterpats:
711 734 # can't rely on size() because wdir content may be decoded
712 735 return self._filelog.cmp(self._filenode, fctx.data())
713 736 if self.size() - 4 == fctx.size():
714 737 # size() can match:
715 738 # if file data starts with '\1\n', empty metadata block is
716 739 # prepended, which adds 4 bytes to filelog.size().
717 740 return self._filelog.cmp(self._filenode, fctx.data())
718 741 if self.size() == fctx.size():
719 742 # size() matches: need to compare content
720 743 return self._filelog.cmp(self._filenode, fctx.data())
721 744
722 745 # size() differs
723 746 return True
724 747
725 748 def _adjustlinkrev(self, srcrev, inclusive=False, stoprev=None):
726 749 """return the first ancestor of <srcrev> introducing <fnode>
727 750
728 751 If the linkrev of the file revision does not point to an ancestor of
729 752 srcrev, we'll walk down the ancestors until we find one introducing
730 753 this file revision.
731 754
732 755 :srcrev: the changeset revision we search ancestors from
733 756 :inclusive: if true, the src revision will also be checked
734 757 :stoprev: an optional revision to stop the walk at. If no introduction
735 758 of this file content could be found before this floor
736 759 revision, the function will returns "None" and stops its
737 760 iteration.
738 761 """
739 762 repo = self._repo
740 763 cl = repo.unfiltered().changelog
741 764 mfl = repo.manifestlog
742 765 # fetch the linkrev
743 766 lkr = self.linkrev()
744 767 if srcrev == lkr:
745 768 return lkr
746 769 # hack to reuse ancestor computation when searching for renames
747 770 memberanc = getattr(self, '_ancestrycontext', None)
748 771 iteranc = None
749 772 if srcrev is None:
750 773 # wctx case, used by workingfilectx during mergecopy
751 774 revs = [p.rev() for p in self._repo[None].parents()]
752 775 inclusive = True # we skipped the real (revless) source
753 776 else:
754 777 revs = [srcrev]
755 778 if memberanc is None:
756 779 memberanc = iteranc = cl.ancestors(revs, lkr,
757 780 inclusive=inclusive)
758 781 # check if this linkrev is an ancestor of srcrev
759 782 if lkr not in memberanc:
760 783 if iteranc is None:
761 784 iteranc = cl.ancestors(revs, lkr, inclusive=inclusive)
762 785 fnode = self._filenode
763 786 path = self._path
764 787 for a in iteranc:
765 788 if stoprev is not None and a < stoprev:
766 789 return None
767 790 ac = cl.read(a) # get changeset data (we avoid object creation)
768 791 if path in ac[3]: # checking the 'files' field.
769 792 # The file has been touched, check if the content is
770 793 # similar to the one we search for.
771 794 if fnode == mfl[ac[0]].readfast().get(path):
772 795 return a
773 796 # In theory, we should never get out of that loop without a result.
774 797 # But if manifest uses a buggy file revision (not children of the
775 798 # one it replaces) we could. Such a buggy situation will likely
776 799 # result is crash somewhere else at to some point.
777 800 return lkr
778 801
779 802 def isintroducedafter(self, changelogrev):
780 803 """True if a filectx has been introduced after a given floor revision
781 804 """
782 805 if self.linkrev() >= changelogrev:
783 806 return True
784 807 introrev = self._introrev(stoprev=changelogrev)
785 808 if introrev is None:
786 809 return False
787 810 return introrev >= changelogrev
788 811
789 812 def introrev(self):
790 813 """return the rev of the changeset which introduced this file revision
791 814
792 815 This method is different from linkrev because it take into account the
793 816 changeset the filectx was created from. It ensures the returned
794 817 revision is one of its ancestors. This prevents bugs from
795 818 'linkrev-shadowing' when a file revision is used by multiple
796 819 changesets.
797 820 """
798 821 return self._introrev()
799 822
800 823 def _introrev(self, stoprev=None):
801 824 """
802 825 Same as `introrev` but, with an extra argument to limit changelog
803 826 iteration range in some internal usecase.
804 827
805 828 If `stoprev` is set, the `introrev` will not be searched past that
806 829 `stoprev` revision and "None" might be returned. This is useful to
807 830 limit the iteration range.
808 831 """
809 832 toprev = None
810 833 attrs = vars(self)
811 834 if r'_changeid' in attrs:
812 835 # We have a cached value already
813 836 toprev = self._changeid
814 837 elif r'_changectx' in attrs:
815 838 # We know which changelog entry we are coming from
816 839 toprev = self._changectx.rev()
817 840
818 841 if toprev is not None:
819 842 return self._adjustlinkrev(toprev, inclusive=True, stoprev=stoprev)
820 843 elif r'_descendantrev' in attrs:
821 844 introrev = self._adjustlinkrev(self._descendantrev, stoprev=stoprev)
822 845 # be nice and cache the result of the computation
823 846 if introrev is not None:
824 847 self._changeid = introrev
825 848 return introrev
826 849 else:
827 850 return self.linkrev()
828 851
829 852 def introfilectx(self):
830 853 """Return filectx having identical contents, but pointing to the
831 854 changeset revision where this filectx was introduced"""
832 855 introrev = self.introrev()
833 856 if self.rev() == introrev:
834 857 return self
835 858 return self.filectx(self.filenode(), changeid=introrev)
836 859
837 860 def _parentfilectx(self, path, fileid, filelog):
838 861 """create parent filectx keeping ancestry info for _adjustlinkrev()"""
839 862 fctx = filectx(self._repo, path, fileid=fileid, filelog=filelog)
840 863 if r'_changeid' in vars(self) or r'_changectx' in vars(self):
841 864 # If self is associated with a changeset (probably explicitly
842 865 # fed), ensure the created filectx is associated with a
843 866 # changeset that is an ancestor of self.changectx.
844 867 # This lets us later use _adjustlinkrev to get a correct link.
845 868 fctx._descendantrev = self.rev()
846 869 fctx._ancestrycontext = getattr(self, '_ancestrycontext', None)
847 870 elif r'_descendantrev' in vars(self):
848 871 # Otherwise propagate _descendantrev if we have one associated.
849 872 fctx._descendantrev = self._descendantrev
850 873 fctx._ancestrycontext = getattr(self, '_ancestrycontext', None)
851 874 return fctx
852 875
853 876 def parents(self):
854 877 _path = self._path
855 878 fl = self._filelog
856 879 parents = self._filelog.parents(self._filenode)
857 880 pl = [(_path, node, fl) for node in parents if node != nullid]
858 881
859 882 r = fl.renamed(self._filenode)
860 883 if r:
861 884 # - In the simple rename case, both parent are nullid, pl is empty.
862 885 # - In case of merge, only one of the parent is null id and should
863 886 # be replaced with the rename information. This parent is -always-
864 887 # the first one.
865 888 #
866 889 # As null id have always been filtered out in the previous list
867 890 # comprehension, inserting to 0 will always result in "replacing
868 891 # first nullid parent with rename information.
869 892 pl.insert(0, (r[0], r[1], self._repo.file(r[0])))
870 893
871 894 return [self._parentfilectx(path, fnode, l) for path, fnode, l in pl]
872 895
873 896 def p1(self):
874 897 return self.parents()[0]
875 898
876 899 def p2(self):
877 900 p = self.parents()
878 901 if len(p) == 2:
879 902 return p[1]
880 903 return filectx(self._repo, self._path, fileid=-1, filelog=self._filelog)
881 904
882 905 def annotate(self, follow=False, skiprevs=None, diffopts=None):
883 906 """Returns a list of annotateline objects for each line in the file
884 907
885 908 - line.fctx is the filectx of the node where that line was last changed
886 909 - line.lineno is the line number at the first appearance in the managed
887 910 file
888 911 - line.text is the data on that line (including newline character)
889 912 """
890 913 getlog = util.lrucachefunc(lambda x: self._repo.file(x))
891 914
892 915 def parents(f):
893 916 # Cut _descendantrev here to mitigate the penalty of lazy linkrev
894 917 # adjustment. Otherwise, p._adjustlinkrev() would walk changelog
895 918 # from the topmost introrev (= srcrev) down to p.linkrev() if it
896 919 # isn't an ancestor of the srcrev.
897 920 f._changeid
898 921 pl = f.parents()
899 922
900 923 # Don't return renamed parents if we aren't following.
901 924 if not follow:
902 925 pl = [p for p in pl if p.path() == f.path()]
903 926
904 927 # renamed filectx won't have a filelog yet, so set it
905 928 # from the cache to save time
906 929 for p in pl:
907 930 if not r'_filelog' in p.__dict__:
908 931 p._filelog = getlog(p.path())
909 932
910 933 return pl
911 934
912 935 # use linkrev to find the first changeset where self appeared
913 936 base = self.introfilectx()
914 937 if getattr(base, '_ancestrycontext', None) is None:
915 938 cl = self._repo.changelog
916 939 if base.rev() is None:
917 940 # wctx is not inclusive, but works because _ancestrycontext
918 941 # is used to test filelog revisions
919 942 ac = cl.ancestors([p.rev() for p in base.parents()],
920 943 inclusive=True)
921 944 else:
922 945 ac = cl.ancestors([base.rev()], inclusive=True)
923 946 base._ancestrycontext = ac
924 947
925 948 return dagop.annotate(base, parents, skiprevs=skiprevs,
926 949 diffopts=diffopts)
927 950
928 951 def ancestors(self, followfirst=False):
929 952 visit = {}
930 953 c = self
931 954 if followfirst:
932 955 cut = 1
933 956 else:
934 957 cut = None
935 958
936 959 while True:
937 960 for parent in c.parents()[:cut]:
938 961 visit[(parent.linkrev(), parent.filenode())] = parent
939 962 if not visit:
940 963 break
941 964 c = visit.pop(max(visit))
942 965 yield c
943 966
944 967 def decodeddata(self):
945 968 """Returns `data()` after running repository decoding filters.
946 969
947 970 This is often equivalent to how the data would be expressed on disk.
948 971 """
949 972 return self._repo.wwritedata(self.path(), self.data())
950 973
951 974 class filectx(basefilectx):
952 975 """A filecontext object makes access to data related to a particular
953 976 filerevision convenient."""
954 977 def __init__(self, repo, path, changeid=None, fileid=None,
955 978 filelog=None, changectx=None):
956 979 """changeid must be a revision number, if specified.
957 980 fileid can be a file revision or node."""
958 981 self._repo = repo
959 982 self._path = path
960 983
961 984 assert (changeid is not None
962 985 or fileid is not None
963 986 or changectx is not None), \
964 987 ("bad args: changeid=%r, fileid=%r, changectx=%r"
965 988 % (changeid, fileid, changectx))
966 989
967 990 if filelog is not None:
968 991 self._filelog = filelog
969 992
970 993 if changeid is not None:
971 994 self._changeid = changeid
972 995 if changectx is not None:
973 996 self._changectx = changectx
974 997 if fileid is not None:
975 998 self._fileid = fileid
976 999
977 1000 @propertycache
978 1001 def _changectx(self):
979 1002 try:
980 1003 return self._repo[self._changeid]
981 1004 except error.FilteredRepoLookupError:
982 1005 # Linkrev may point to any revision in the repository. When the
983 1006 # repository is filtered this may lead to `filectx` trying to build
984 1007 # `changectx` for filtered revision. In such case we fallback to
985 1008 # creating `changectx` on the unfiltered version of the reposition.
986 1009 # This fallback should not be an issue because `changectx` from
987 1010 # `filectx` are not used in complex operations that care about
988 1011 # filtering.
989 1012 #
990 1013 # This fallback is a cheap and dirty fix that prevent several
991 1014 # crashes. It does not ensure the behavior is correct. However the
992 1015 # behavior was not correct before filtering either and "incorrect
993 1016 # behavior" is seen as better as "crash"
994 1017 #
995 1018 # Linkrevs have several serious troubles with filtering that are
996 1019 # complicated to solve. Proper handling of the issue here should be
997 1020 # considered when solving linkrev issue are on the table.
998 1021 return self._repo.unfiltered()[self._changeid]
999 1022
1000 1023 def filectx(self, fileid, changeid=None):
1001 1024 '''opens an arbitrary revision of the file without
1002 1025 opening a new filelog'''
1003 1026 return filectx(self._repo, self._path, fileid=fileid,
1004 1027 filelog=self._filelog, changeid=changeid)
1005 1028
1006 1029 def rawdata(self):
1007 1030 return self._filelog.revision(self._filenode, raw=True)
1008 1031
1009 1032 def rawflags(self):
1010 1033 """low-level revlog flags"""
1011 1034 return self._filelog.flags(self._filerev)
1012 1035
1013 1036 def data(self):
1014 1037 try:
1015 1038 return self._filelog.read(self._filenode)
1016 1039 except error.CensoredNodeError:
1017 1040 if self._repo.ui.config("censor", "policy") == "ignore":
1018 1041 return ""
1019 1042 raise error.Abort(_("censored node: %s") % short(self._filenode),
1020 1043 hint=_("set censor.policy to ignore errors"))
1021 1044
1022 1045 def size(self):
1023 1046 return self._filelog.size(self._filerev)
1024 1047
1025 1048 @propertycache
1026 1049 def _copied(self):
1027 1050 """check if file was actually renamed in this changeset revision
1028 1051
1029 1052 If rename logged in file revision, we report copy for changeset only
1030 1053 if file revisions linkrev points back to the changeset in question
1031 1054 or both changeset parents contain different file revisions.
1032 1055 """
1033 1056
1034 1057 renamed = self._filelog.renamed(self._filenode)
1035 1058 if not renamed:
1036 1059 return None
1037 1060
1038 1061 if self.rev() == self.linkrev():
1039 1062 return renamed
1040 1063
1041 1064 name = self.path()
1042 1065 fnode = self._filenode
1043 1066 for p in self._changectx.parents():
1044 1067 try:
1045 1068 if fnode == p.filenode(name):
1046 1069 return None
1047 1070 except error.LookupError:
1048 1071 pass
1049 1072 return renamed
1050 1073
1051 1074 def children(self):
1052 1075 # hard for renames
1053 1076 c = self._filelog.children(self._filenode)
1054 1077 return [filectx(self._repo, self._path, fileid=x,
1055 1078 filelog=self._filelog) for x in c]
1056 1079
1057 1080 class committablectx(basectx):
1058 1081 """A committablectx object provides common functionality for a context that
1059 1082 wants the ability to commit, e.g. workingctx or memctx."""
1060 1083 def __init__(self, repo, text="", user=None, date=None, extra=None,
1061 1084 changes=None):
1062 1085 super(committablectx, self).__init__(repo)
1063 1086 self._rev = None
1064 1087 self._node = None
1065 1088 self._text = text
1066 1089 if date:
1067 1090 self._date = dateutil.parsedate(date)
1068 1091 if user:
1069 1092 self._user = user
1070 1093 if changes:
1071 1094 self._status = changes
1072 1095
1073 1096 self._extra = {}
1074 1097 if extra:
1075 1098 self._extra = extra.copy()
1076 1099 if 'branch' not in self._extra:
1077 1100 try:
1078 1101 branch = encoding.fromlocal(self._repo.dirstate.branch())
1079 1102 except UnicodeDecodeError:
1080 1103 raise error.Abort(_('branch name not in UTF-8!'))
1081 1104 self._extra['branch'] = branch
1082 1105 if self._extra['branch'] == '':
1083 1106 self._extra['branch'] = 'default'
1084 1107
1085 1108 def __bytes__(self):
1086 1109 return bytes(self._parents[0]) + "+"
1087 1110
1088 1111 __str__ = encoding.strmethod(__bytes__)
1089 1112
1090 1113 def __nonzero__(self):
1091 1114 return True
1092 1115
1093 1116 __bool__ = __nonzero__
1094 1117
1095 1118 def _buildflagfunc(self):
1096 1119 # Create a fallback function for getting file flags when the
1097 1120 # filesystem doesn't support them
1098 1121
1099 1122 copiesget = self._repo.dirstate.copies().get
1100 1123 parents = self.parents()
1101 1124 if len(parents) < 2:
1102 1125 # when we have one parent, it's easy: copy from parent
1103 1126 man = parents[0].manifest()
1104 1127 def func(f):
1105 1128 f = copiesget(f, f)
1106 1129 return man.flags(f)
1107 1130 else:
1108 1131 # merges are tricky: we try to reconstruct the unstored
1109 1132 # result from the merge (issue1802)
1110 1133 p1, p2 = parents
1111 1134 pa = p1.ancestor(p2)
1112 1135 m1, m2, ma = p1.manifest(), p2.manifest(), pa.manifest()
1113 1136
1114 1137 def func(f):
1115 1138 f = copiesget(f, f) # may be wrong for merges with copies
1116 1139 fl1, fl2, fla = m1.flags(f), m2.flags(f), ma.flags(f)
1117 1140 if fl1 == fl2:
1118 1141 return fl1
1119 1142 if fl1 == fla:
1120 1143 return fl2
1121 1144 if fl2 == fla:
1122 1145 return fl1
1123 1146 return '' # punt for conflicts
1124 1147
1125 1148 return func
1126 1149
1127 1150 @propertycache
1128 1151 def _flagfunc(self):
1129 1152 return self._repo.dirstate.flagfunc(self._buildflagfunc)
1130 1153
1131 1154 @propertycache
1132 1155 def _status(self):
1133 1156 return self._repo.status()
1134 1157
1135 1158 @propertycache
1136 1159 def _user(self):
1137 1160 return self._repo.ui.username()
1138 1161
1139 1162 @propertycache
1140 1163 def _date(self):
1141 1164 ui = self._repo.ui
1142 1165 date = ui.configdate('devel', 'default-date')
1143 1166 if date is None:
1144 1167 date = dateutil.makedate()
1145 1168 return date
1146 1169
1147 1170 def subrev(self, subpath):
1148 1171 return None
1149 1172
1150 1173 def manifestnode(self):
1151 1174 return None
1152 1175 def user(self):
1153 1176 return self._user or self._repo.ui.username()
1154 1177 def date(self):
1155 1178 return self._date
1156 1179 def description(self):
1157 1180 return self._text
1158 1181 def files(self):
1159 1182 return sorted(self._status.modified + self._status.added +
1160 1183 self._status.removed)
1161
1184 @propertycache
1185 def _copies(self):
1186 p1copies = {}
1187 p2copies = {}
1188 parents = self._repo.dirstate.parents()
1189 p1manifest = self._repo[parents[0]].manifest()
1190 p2manifest = self._repo[parents[1]].manifest()
1191 narrowmatch = self._repo.narrowmatch()
1192 for dst, src in self._repo.dirstate.copies().items():
1193 if not narrowmatch(dst):
1194 continue
1195 if src in p1manifest:
1196 p1copies[dst] = src
1197 elif src in p2manifest:
1198 p2copies[dst] = src
1199 return p1copies, p2copies
1200 def p1copies(self):
1201 return self._copies[0]
1202 def p2copies(self):
1203 return self._copies[1]
1162 1204 def modified(self):
1163 1205 return self._status.modified
1164 1206 def added(self):
1165 1207 return self._status.added
1166 1208 def removed(self):
1167 1209 return self._status.removed
1168 1210 def deleted(self):
1169 1211 return self._status.deleted
1170 1212 def branch(self):
1171 1213 return encoding.tolocal(self._extra['branch'])
1172 1214 def closesbranch(self):
1173 1215 return 'close' in self._extra
1174 1216 def extra(self):
1175 1217 return self._extra
1176 1218
1177 1219 def isinmemory(self):
1178 1220 return False
1179 1221
1180 1222 def tags(self):
1181 1223 return []
1182 1224
1183 1225 def bookmarks(self):
1184 1226 b = []
1185 1227 for p in self.parents():
1186 1228 b.extend(p.bookmarks())
1187 1229 return b
1188 1230
1189 1231 def phase(self):
1190 1232 phase = phases.draft # default phase to draft
1191 1233 for p in self.parents():
1192 1234 phase = max(phase, p.phase())
1193 1235 return phase
1194 1236
1195 1237 def hidden(self):
1196 1238 return False
1197 1239
1198 1240 def children(self):
1199 1241 return []
1200 1242
1201 1243 def flags(self, path):
1202 1244 if r'_manifest' in self.__dict__:
1203 1245 try:
1204 1246 return self._manifest.flags(path)
1205 1247 except KeyError:
1206 1248 return ''
1207 1249
1208 1250 try:
1209 1251 return self._flagfunc(path)
1210 1252 except OSError:
1211 1253 return ''
1212 1254
1213 1255 def ancestor(self, c2):
1214 1256 """return the "best" ancestor context of self and c2"""
1215 1257 return self._parents[0].ancestor(c2) # punt on two parents for now
1216 1258
1217 1259 def walk(self, match):
1218 1260 '''Generates matching file names.'''
1219 1261 return sorted(self._repo.dirstate.walk(self._repo.narrowmatch(match),
1220 1262 subrepos=sorted(self.substate),
1221 1263 unknown=True, ignored=False))
1222 1264
1223 1265 def matches(self, match):
1224 1266 match = self._repo.narrowmatch(match)
1225 1267 ds = self._repo.dirstate
1226 1268 return sorted(f for f in ds.matches(match) if ds[f] != 'r')
1227 1269
1228 1270 def ancestors(self):
1229 1271 for p in self._parents:
1230 1272 yield p
1231 1273 for a in self._repo.changelog.ancestors(
1232 1274 [p.rev() for p in self._parents]):
1233 1275 yield self._repo[a]
1234 1276
1235 1277 def markcommitted(self, node):
1236 1278 """Perform post-commit cleanup necessary after committing this ctx
1237 1279
1238 1280 Specifically, this updates backing stores this working context
1239 1281 wraps to reflect the fact that the changes reflected by this
1240 1282 workingctx have been committed. For example, it marks
1241 1283 modified and added files as normal in the dirstate.
1242 1284
1243 1285 """
1244 1286
1245 1287 with self._repo.dirstate.parentchange():
1246 1288 for f in self.modified() + self.added():
1247 1289 self._repo.dirstate.normal(f)
1248 1290 for f in self.removed():
1249 1291 self._repo.dirstate.drop(f)
1250 1292 self._repo.dirstate.setparents(node)
1251 1293
1252 1294 # write changes out explicitly, because nesting wlock at
1253 1295 # runtime may prevent 'wlock.release()' in 'repo.commit()'
1254 1296 # from immediately doing so for subsequent changing files
1255 1297 self._repo.dirstate.write(self._repo.currenttransaction())
1256 1298
1257 1299 def dirty(self, missing=False, merge=True, branch=True):
1258 1300 return False
1259 1301
1260 1302 class workingctx(committablectx):
1261 1303 """A workingctx object makes access to data related to
1262 1304 the current working directory convenient.
1263 1305 date - any valid date string or (unixtime, offset), or None.
1264 1306 user - username string, or None.
1265 1307 extra - a dictionary of extra values, or None.
1266 1308 changes - a list of file lists as returned by localrepo.status()
1267 1309 or None to use the repository status.
1268 1310 """
1269 1311 def __init__(self, repo, text="", user=None, date=None, extra=None,
1270 1312 changes=None):
1271 1313 super(workingctx, self).__init__(repo, text, user, date, extra, changes)
1272 1314
1273 1315 def __iter__(self):
1274 1316 d = self._repo.dirstate
1275 1317 for f in d:
1276 1318 if d[f] != 'r':
1277 1319 yield f
1278 1320
1279 1321 def __contains__(self, key):
1280 1322 return self._repo.dirstate[key] not in "?r"
1281 1323
1282 1324 def hex(self):
1283 1325 return hex(wdirid)
1284 1326
1285 1327 @propertycache
1286 1328 def _parents(self):
1287 1329 p = self._repo.dirstate.parents()
1288 1330 if p[1] == nullid:
1289 1331 p = p[:-1]
1290 1332 # use unfiltered repo to delay/avoid loading obsmarkers
1291 1333 unfi = self._repo.unfiltered()
1292 1334 return [changectx(self._repo, unfi.changelog.rev(n), n) for n in p]
1293 1335
1294 1336 def _fileinfo(self, path):
1295 1337 # populate __dict__['_manifest'] as workingctx has no _manifestdelta
1296 1338 self._manifest
1297 1339 return super(workingctx, self)._fileinfo(path)
1298 1340
1299 1341 def filectx(self, path, filelog=None):
1300 1342 """get a file context from the working directory"""
1301 1343 return workingfilectx(self._repo, path, workingctx=self,
1302 1344 filelog=filelog)
1303 1345
1304 1346 def dirty(self, missing=False, merge=True, branch=True):
1305 1347 "check whether a working directory is modified"
1306 1348 # check subrepos first
1307 1349 for s in sorted(self.substate):
1308 1350 if self.sub(s).dirty(missing=missing):
1309 1351 return True
1310 1352 # check current working dir
1311 1353 return ((merge and self.p2()) or
1312 1354 (branch and self.branch() != self.p1().branch()) or
1313 1355 self.modified() or self.added() or self.removed() or
1314 1356 (missing and self.deleted()))
1315 1357
1316 1358 def add(self, list, prefix=""):
1317 1359 with self._repo.wlock():
1318 1360 ui, ds = self._repo.ui, self._repo.dirstate
1319 1361 uipath = lambda f: ds.pathto(pathutil.join(prefix, f))
1320 1362 rejected = []
1321 1363 lstat = self._repo.wvfs.lstat
1322 1364 for f in list:
1323 1365 # ds.pathto() returns an absolute file when this is invoked from
1324 1366 # the keyword extension. That gets flagged as non-portable on
1325 1367 # Windows, since it contains the drive letter and colon.
1326 1368 scmutil.checkportable(ui, os.path.join(prefix, f))
1327 1369 try:
1328 1370 st = lstat(f)
1329 1371 except OSError:
1330 1372 ui.warn(_("%s does not exist!\n") % uipath(f))
1331 1373 rejected.append(f)
1332 1374 continue
1333 1375 limit = ui.configbytes('ui', 'large-file-limit')
1334 1376 if limit != 0 and st.st_size > limit:
1335 1377 ui.warn(_("%s: up to %d MB of RAM may be required "
1336 1378 "to manage this file\n"
1337 1379 "(use 'hg revert %s' to cancel the "
1338 1380 "pending addition)\n")
1339 1381 % (f, 3 * st.st_size // 1000000, uipath(f)))
1340 1382 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
1341 1383 ui.warn(_("%s not added: only files and symlinks "
1342 1384 "supported currently\n") % uipath(f))
1343 1385 rejected.append(f)
1344 1386 elif ds[f] in 'amn':
1345 1387 ui.warn(_("%s already tracked!\n") % uipath(f))
1346 1388 elif ds[f] == 'r':
1347 1389 ds.normallookup(f)
1348 1390 else:
1349 1391 ds.add(f)
1350 1392 return rejected
1351 1393
1352 1394 def forget(self, files, prefix=""):
1353 1395 with self._repo.wlock():
1354 1396 ds = self._repo.dirstate
1355 1397 uipath = lambda f: ds.pathto(pathutil.join(prefix, f))
1356 1398 rejected = []
1357 1399 for f in files:
1358 1400 if f not in ds:
1359 1401 self._repo.ui.warn(_("%s not tracked!\n") % uipath(f))
1360 1402 rejected.append(f)
1361 1403 elif ds[f] != 'a':
1362 1404 ds.remove(f)
1363 1405 else:
1364 1406 ds.drop(f)
1365 1407 return rejected
1366 1408
1367 1409 def copy(self, source, dest):
1368 1410 try:
1369 1411 st = self._repo.wvfs.lstat(dest)
1370 1412 except OSError as err:
1371 1413 if err.errno != errno.ENOENT:
1372 1414 raise
1373 1415 self._repo.ui.warn(_("%s does not exist!\n")
1374 1416 % self._repo.dirstate.pathto(dest))
1375 1417 return
1376 1418 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
1377 1419 self._repo.ui.warn(_("copy failed: %s is not a file or a "
1378 1420 "symbolic link\n")
1379 1421 % self._repo.dirstate.pathto(dest))
1380 1422 else:
1381 1423 with self._repo.wlock():
1382 1424 ds = self._repo.dirstate
1383 1425 if ds[dest] in '?':
1384 1426 ds.add(dest)
1385 1427 elif ds[dest] in 'r':
1386 1428 ds.normallookup(dest)
1387 1429 ds.copy(source, dest)
1388 1430
1389 1431 def match(self, pats=None, include=None, exclude=None, default='glob',
1390 1432 listsubrepos=False, badfn=None):
1391 1433 r = self._repo
1392 1434
1393 1435 # Only a case insensitive filesystem needs magic to translate user input
1394 1436 # to actual case in the filesystem.
1395 1437 icasefs = not util.fscasesensitive(r.root)
1396 1438 return matchmod.match(r.root, r.getcwd(), pats, include, exclude,
1397 1439 default, auditor=r.auditor, ctx=self,
1398 1440 listsubrepos=listsubrepos, badfn=badfn,
1399 1441 icasefs=icasefs)
1400 1442
1401 1443 def _filtersuspectsymlink(self, files):
1402 1444 if not files or self._repo.dirstate._checklink:
1403 1445 return files
1404 1446
1405 1447 # Symlink placeholders may get non-symlink-like contents
1406 1448 # via user error or dereferencing by NFS or Samba servers,
1407 1449 # so we filter out any placeholders that don't look like a
1408 1450 # symlink
1409 1451 sane = []
1410 1452 for f in files:
1411 1453 if self.flags(f) == 'l':
1412 1454 d = self[f].data()
1413 1455 if (d == '' or len(d) >= 1024 or '\n' in d
1414 1456 or stringutil.binary(d)):
1415 1457 self._repo.ui.debug('ignoring suspect symlink placeholder'
1416 1458 ' "%s"\n' % f)
1417 1459 continue
1418 1460 sane.append(f)
1419 1461 return sane
1420 1462
1421 1463 def _checklookup(self, files):
1422 1464 # check for any possibly clean files
1423 1465 if not files:
1424 1466 return [], [], []
1425 1467
1426 1468 modified = []
1427 1469 deleted = []
1428 1470 fixup = []
1429 1471 pctx = self._parents[0]
1430 1472 # do a full compare of any files that might have changed
1431 1473 for f in sorted(files):
1432 1474 try:
1433 1475 # This will return True for a file that got replaced by a
1434 1476 # directory in the interim, but fixing that is pretty hard.
1435 1477 if (f not in pctx or self.flags(f) != pctx.flags(f)
1436 1478 or pctx[f].cmp(self[f])):
1437 1479 modified.append(f)
1438 1480 else:
1439 1481 fixup.append(f)
1440 1482 except (IOError, OSError):
1441 1483 # A file become inaccessible in between? Mark it as deleted,
1442 1484 # matching dirstate behavior (issue5584).
1443 1485 # The dirstate has more complex behavior around whether a
1444 1486 # missing file matches a directory, etc, but we don't need to
1445 1487 # bother with that: if f has made it to this point, we're sure
1446 1488 # it's in the dirstate.
1447 1489 deleted.append(f)
1448 1490
1449 1491 return modified, deleted, fixup
1450 1492
1451 1493 def _poststatusfixup(self, status, fixup):
1452 1494 """update dirstate for files that are actually clean"""
1453 1495 poststatus = self._repo.postdsstatus()
1454 1496 if fixup or poststatus:
1455 1497 try:
1456 1498 oldid = self._repo.dirstate.identity()
1457 1499
1458 1500 # updating the dirstate is optional
1459 1501 # so we don't wait on the lock
1460 1502 # wlock can invalidate the dirstate, so cache normal _after_
1461 1503 # taking the lock
1462 1504 with self._repo.wlock(False):
1463 1505 if self._repo.dirstate.identity() == oldid:
1464 1506 if fixup:
1465 1507 normal = self._repo.dirstate.normal
1466 1508 for f in fixup:
1467 1509 normal(f)
1468 1510 # write changes out explicitly, because nesting
1469 1511 # wlock at runtime may prevent 'wlock.release()'
1470 1512 # after this block from doing so for subsequent
1471 1513 # changing files
1472 1514 tr = self._repo.currenttransaction()
1473 1515 self._repo.dirstate.write(tr)
1474 1516
1475 1517 if poststatus:
1476 1518 for ps in poststatus:
1477 1519 ps(self, status)
1478 1520 else:
1479 1521 # in this case, writing changes out breaks
1480 1522 # consistency, because .hg/dirstate was
1481 1523 # already changed simultaneously after last
1482 1524 # caching (see also issue5584 for detail)
1483 1525 self._repo.ui.debug('skip updating dirstate: '
1484 1526 'identity mismatch\n')
1485 1527 except error.LockError:
1486 1528 pass
1487 1529 finally:
1488 1530 # Even if the wlock couldn't be grabbed, clear out the list.
1489 1531 self._repo.clearpostdsstatus()
1490 1532
1491 1533 def _dirstatestatus(self, match, ignored=False, clean=False, unknown=False):
1492 1534 '''Gets the status from the dirstate -- internal use only.'''
1493 1535 subrepos = []
1494 1536 if '.hgsub' in self:
1495 1537 subrepos = sorted(self.substate)
1496 1538 cmp, s = self._repo.dirstate.status(match, subrepos, ignored=ignored,
1497 1539 clean=clean, unknown=unknown)
1498 1540
1499 1541 # check for any possibly clean files
1500 1542 fixup = []
1501 1543 if cmp:
1502 1544 modified2, deleted2, fixup = self._checklookup(cmp)
1503 1545 s.modified.extend(modified2)
1504 1546 s.deleted.extend(deleted2)
1505 1547
1506 1548 if fixup and clean:
1507 1549 s.clean.extend(fixup)
1508 1550
1509 1551 self._poststatusfixup(s, fixup)
1510 1552
1511 1553 if match.always():
1512 1554 # cache for performance
1513 1555 if s.unknown or s.ignored or s.clean:
1514 1556 # "_status" is cached with list*=False in the normal route
1515 1557 self._status = scmutil.status(s.modified, s.added, s.removed,
1516 1558 s.deleted, [], [], [])
1517 1559 else:
1518 1560 self._status = s
1519 1561
1520 1562 return s
1521 1563
1522 1564 @propertycache
1523 1565 def _manifest(self):
1524 1566 """generate a manifest corresponding to the values in self._status
1525 1567
1526 1568 This reuse the file nodeid from parent, but we use special node
1527 1569 identifiers for added and modified files. This is used by manifests
1528 1570 merge to see that files are different and by update logic to avoid
1529 1571 deleting newly added files.
1530 1572 """
1531 1573 return self._buildstatusmanifest(self._status)
1532 1574
1533 1575 def _buildstatusmanifest(self, status):
1534 1576 """Builds a manifest that includes the given status results."""
1535 1577 parents = self.parents()
1536 1578
1537 1579 man = parents[0].manifest().copy()
1538 1580
1539 1581 ff = self._flagfunc
1540 1582 for i, l in ((addednodeid, status.added),
1541 1583 (modifiednodeid, status.modified)):
1542 1584 for f in l:
1543 1585 man[f] = i
1544 1586 try:
1545 1587 man.setflag(f, ff(f))
1546 1588 except OSError:
1547 1589 pass
1548 1590
1549 1591 for f in status.deleted + status.removed:
1550 1592 if f in man:
1551 1593 del man[f]
1552 1594
1553 1595 return man
1554 1596
1555 1597 def _buildstatus(self, other, s, match, listignored, listclean,
1556 1598 listunknown):
1557 1599 """build a status with respect to another context
1558 1600
1559 1601 This includes logic for maintaining the fast path of status when
1560 1602 comparing the working directory against its parent, which is to skip
1561 1603 building a new manifest if self (working directory) is not comparing
1562 1604 against its parent (repo['.']).
1563 1605 """
1564 1606 s = self._dirstatestatus(match, listignored, listclean, listunknown)
1565 1607 # Filter out symlinks that, in the case of FAT32 and NTFS filesystems,
1566 1608 # might have accidentally ended up with the entire contents of the file
1567 1609 # they are supposed to be linking to.
1568 1610 s.modified[:] = self._filtersuspectsymlink(s.modified)
1569 1611 if other != self._repo['.']:
1570 1612 s = super(workingctx, self)._buildstatus(other, s, match,
1571 1613 listignored, listclean,
1572 1614 listunknown)
1573 1615 return s
1574 1616
1575 1617 def _matchstatus(self, other, match):
1576 1618 """override the match method with a filter for directory patterns
1577 1619
1578 1620 We use inheritance to customize the match.bad method only in cases of
1579 1621 workingctx since it belongs only to the working directory when
1580 1622 comparing against the parent changeset.
1581 1623
1582 1624 If we aren't comparing against the working directory's parent, then we
1583 1625 just use the default match object sent to us.
1584 1626 """
1585 1627 if other != self._repo['.']:
1586 1628 def bad(f, msg):
1587 1629 # 'f' may be a directory pattern from 'match.files()',
1588 1630 # so 'f not in ctx1' is not enough
1589 1631 if f not in other and not other.hasdir(f):
1590 1632 self._repo.ui.warn('%s: %s\n' %
1591 1633 (self._repo.dirstate.pathto(f), msg))
1592 1634 match.bad = bad
1593 1635 return match
1594 1636
1595 1637 def markcommitted(self, node):
1596 1638 super(workingctx, self).markcommitted(node)
1597 1639
1598 1640 sparse.aftercommit(self._repo, node)
1599 1641
1600 1642 class committablefilectx(basefilectx):
1601 1643 """A committablefilectx provides common functionality for a file context
1602 1644 that wants the ability to commit, e.g. workingfilectx or memfilectx."""
1603 1645 def __init__(self, repo, path, filelog=None, ctx=None):
1604 1646 self._repo = repo
1605 1647 self._path = path
1606 1648 self._changeid = None
1607 1649 self._filerev = self._filenode = None
1608 1650
1609 1651 if filelog is not None:
1610 1652 self._filelog = filelog
1611 1653 if ctx:
1612 1654 self._changectx = ctx
1613 1655
1614 1656 def __nonzero__(self):
1615 1657 return True
1616 1658
1617 1659 __bool__ = __nonzero__
1618 1660
1619 1661 def linkrev(self):
1620 1662 # linked to self._changectx no matter if file is modified or not
1621 1663 return self.rev()
1622 1664
1623 1665 def parents(self):
1624 1666 '''return parent filectxs, following copies if necessary'''
1625 1667 def filenode(ctx, path):
1626 1668 return ctx._manifest.get(path, nullid)
1627 1669
1628 1670 path = self._path
1629 1671 fl = self._filelog
1630 1672 pcl = self._changectx._parents
1631 1673 renamed = self.renamed()
1632 1674
1633 1675 if renamed:
1634 1676 pl = [renamed + (None,)]
1635 1677 else:
1636 1678 pl = [(path, filenode(pcl[0], path), fl)]
1637 1679
1638 1680 for pc in pcl[1:]:
1639 1681 pl.append((path, filenode(pc, path), fl))
1640 1682
1641 1683 return [self._parentfilectx(p, fileid=n, filelog=l)
1642 1684 for p, n, l in pl if n != nullid]
1643 1685
1644 1686 def children(self):
1645 1687 return []
1646 1688
1647 1689 class workingfilectx(committablefilectx):
1648 1690 """A workingfilectx object makes access to data related to a particular
1649 1691 file in the working directory convenient."""
1650 1692 def __init__(self, repo, path, filelog=None, workingctx=None):
1651 1693 super(workingfilectx, self).__init__(repo, path, filelog, workingctx)
1652 1694
1653 1695 @propertycache
1654 1696 def _changectx(self):
1655 1697 return workingctx(self._repo)
1656 1698
1657 1699 def data(self):
1658 1700 return self._repo.wread(self._path)
1659 1701 def renamed(self):
1660 1702 rp = self._repo.dirstate.copied(self._path)
1661 1703 if not rp:
1662 1704 return None
1663 1705 return rp, self._changectx._parents[0]._manifest.get(rp, nullid)
1664 1706
1665 1707 def size(self):
1666 1708 return self._repo.wvfs.lstat(self._path).st_size
1667 1709 def date(self):
1668 1710 t, tz = self._changectx.date()
1669 1711 try:
1670 1712 return (self._repo.wvfs.lstat(self._path)[stat.ST_MTIME], tz)
1671 1713 except OSError as err:
1672 1714 if err.errno != errno.ENOENT:
1673 1715 raise
1674 1716 return (t, tz)
1675 1717
1676 1718 def exists(self):
1677 1719 return self._repo.wvfs.exists(self._path)
1678 1720
1679 1721 def lexists(self):
1680 1722 return self._repo.wvfs.lexists(self._path)
1681 1723
1682 1724 def audit(self):
1683 1725 return self._repo.wvfs.audit(self._path)
1684 1726
1685 1727 def cmp(self, fctx):
1686 1728 """compare with other file context
1687 1729
1688 1730 returns True if different than fctx.
1689 1731 """
1690 1732 # fctx should be a filectx (not a workingfilectx)
1691 1733 # invert comparison to reuse the same code path
1692 1734 return fctx.cmp(self)
1693 1735
1694 1736 def remove(self, ignoremissing=False):
1695 1737 """wraps unlink for a repo's working directory"""
1696 1738 rmdir = self._repo.ui.configbool('experimental', 'removeemptydirs')
1697 1739 self._repo.wvfs.unlinkpath(self._path, ignoremissing=ignoremissing,
1698 1740 rmdir=rmdir)
1699 1741
1700 1742 def write(self, data, flags, backgroundclose=False, **kwargs):
1701 1743 """wraps repo.wwrite"""
1702 1744 self._repo.wwrite(self._path, data, flags,
1703 1745 backgroundclose=backgroundclose,
1704 1746 **kwargs)
1705 1747
1706 1748 def markcopied(self, src):
1707 1749 """marks this file a copy of `src`"""
1708 1750 if self._repo.dirstate[self._path] in "nma":
1709 1751 self._repo.dirstate.copy(src, self._path)
1710 1752
1711 1753 def clearunknown(self):
1712 1754 """Removes conflicting items in the working directory so that
1713 1755 ``write()`` can be called successfully.
1714 1756 """
1715 1757 wvfs = self._repo.wvfs
1716 1758 f = self._path
1717 1759 wvfs.audit(f)
1718 1760 if self._repo.ui.configbool('experimental', 'merge.checkpathconflicts'):
1719 1761 # remove files under the directory as they should already be
1720 1762 # warned and backed up
1721 1763 if wvfs.isdir(f) and not wvfs.islink(f):
1722 1764 wvfs.rmtree(f, forcibly=True)
1723 1765 for p in reversed(list(util.finddirs(f))):
1724 1766 if wvfs.isfileorlink(p):
1725 1767 wvfs.unlink(p)
1726 1768 break
1727 1769 else:
1728 1770 # don't remove files if path conflicts are not processed
1729 1771 if wvfs.isdir(f) and not wvfs.islink(f):
1730 1772 wvfs.removedirs(f)
1731 1773
1732 1774 def setflags(self, l, x):
1733 1775 self._repo.wvfs.setflags(self._path, l, x)
1734 1776
1735 1777 class overlayworkingctx(committablectx):
1736 1778 """Wraps another mutable context with a write-back cache that can be
1737 1779 converted into a commit context.
1738 1780
1739 1781 self._cache[path] maps to a dict with keys: {
1740 1782 'exists': bool?
1741 1783 'date': date?
1742 1784 'data': str?
1743 1785 'flags': str?
1744 1786 'copied': str? (path or None)
1745 1787 }
1746 1788 If `exists` is True, `flags` must be non-None and 'date' is non-None. If it
1747 1789 is `False`, the file was deleted.
1748 1790 """
1749 1791
1750 1792 def __init__(self, repo):
1751 1793 super(overlayworkingctx, self).__init__(repo)
1752 1794 self.clean()
1753 1795
1754 1796 def setbase(self, wrappedctx):
1755 1797 self._wrappedctx = wrappedctx
1756 1798 self._parents = [wrappedctx]
1757 1799 # Drop old manifest cache as it is now out of date.
1758 1800 # This is necessary when, e.g., rebasing several nodes with one
1759 1801 # ``overlayworkingctx`` (e.g. with --collapse).
1760 1802 util.clearcachedproperty(self, '_manifest')
1761 1803
1762 1804 def data(self, path):
1763 1805 if self.isdirty(path):
1764 1806 if self._cache[path]['exists']:
1765 1807 if self._cache[path]['data']:
1766 1808 return self._cache[path]['data']
1767 1809 else:
1768 1810 # Must fallback here, too, because we only set flags.
1769 1811 return self._wrappedctx[path].data()
1770 1812 else:
1771 1813 raise error.ProgrammingError("No such file or directory: %s" %
1772 1814 path)
1773 1815 else:
1774 1816 return self._wrappedctx[path].data()
1775 1817
1776 1818 @propertycache
1777 1819 def _manifest(self):
1778 1820 parents = self.parents()
1779 1821 man = parents[0].manifest().copy()
1780 1822
1781 1823 flag = self._flagfunc
1782 1824 for path in self.added():
1783 1825 man[path] = addednodeid
1784 1826 man.setflag(path, flag(path))
1785 1827 for path in self.modified():
1786 1828 man[path] = modifiednodeid
1787 1829 man.setflag(path, flag(path))
1788 1830 for path in self.removed():
1789 1831 del man[path]
1790 1832 return man
1791 1833
1792 1834 @propertycache
1793 1835 def _flagfunc(self):
1794 1836 def f(path):
1795 1837 return self._cache[path]['flags']
1796 1838 return f
1797 1839
1798 1840 def files(self):
1799 1841 return sorted(self.added() + self.modified() + self.removed())
1800 1842
1801 1843 def modified(self):
1802 1844 return [f for f in self._cache.keys() if self._cache[f]['exists'] and
1803 1845 self._existsinparent(f)]
1804 1846
1805 1847 def added(self):
1806 1848 return [f for f in self._cache.keys() if self._cache[f]['exists'] and
1807 1849 not self._existsinparent(f)]
1808 1850
1809 1851 def removed(self):
1810 1852 return [f for f in self._cache.keys() if
1811 1853 not self._cache[f]['exists'] and self._existsinparent(f)]
1812 1854
1855 def p1copies(self):
1856 copies = self._repo._wrappedctx.p1copies().copy()
1857 narrowmatch = self._repo.narrowmatch()
1858 for f in self._cache.keys():
1859 if not narrowmatch(f):
1860 continue
1861 copies.pop(f, None) # delete if it exists
1862 source = self._cache[f]['copied']
1863 if source:
1864 copies[f] = source
1865 return copies
1866
1867 def p2copies(self):
1868 copies = self._repo._wrappedctx.p2copies().copy()
1869 narrowmatch = self._repo.narrowmatch()
1870 for f in self._cache.keys():
1871 if not narrowmatch(f):
1872 continue
1873 copies.pop(f, None) # delete if it exists
1874 source = self._cache[f]['copied']
1875 if source:
1876 copies[f] = source
1877 return copies
1878
1813 1879 def isinmemory(self):
1814 1880 return True
1815 1881
1816 1882 def filedate(self, path):
1817 1883 if self.isdirty(path):
1818 1884 return self._cache[path]['date']
1819 1885 else:
1820 1886 return self._wrappedctx[path].date()
1821 1887
1822 1888 def markcopied(self, path, origin):
1823 1889 if self.isdirty(path):
1824 1890 self._cache[path]['copied'] = origin
1825 1891 else:
1826 1892 raise error.ProgrammingError('markcopied() called on clean context')
1827 1893
1828 1894 def copydata(self, path):
1829 1895 if self.isdirty(path):
1830 1896 return self._cache[path]['copied']
1831 1897 else:
1832 1898 raise error.ProgrammingError('copydata() called on clean context')
1833 1899
1834 1900 def flags(self, path):
1835 1901 if self.isdirty(path):
1836 1902 if self._cache[path]['exists']:
1837 1903 return self._cache[path]['flags']
1838 1904 else:
1839 1905 raise error.ProgrammingError("No such file or directory: %s" %
1840 1906 self._path)
1841 1907 else:
1842 1908 return self._wrappedctx[path].flags()
1843 1909
1844 1910 def __contains__(self, key):
1845 1911 if key in self._cache:
1846 1912 return self._cache[key]['exists']
1847 1913 return key in self.p1()
1848 1914
1849 1915 def _existsinparent(self, path):
1850 1916 try:
1851 1917 # ``commitctx` raises a ``ManifestLookupError`` if a path does not
1852 1918 # exist, unlike ``workingctx``, which returns a ``workingfilectx``
1853 1919 # with an ``exists()`` function.
1854 1920 self._wrappedctx[path]
1855 1921 return True
1856 1922 except error.ManifestLookupError:
1857 1923 return False
1858 1924
1859 1925 def _auditconflicts(self, path):
1860 1926 """Replicates conflict checks done by wvfs.write().
1861 1927
1862 1928 Since we never write to the filesystem and never call `applyupdates` in
1863 1929 IMM, we'll never check that a path is actually writable -- e.g., because
1864 1930 it adds `a/foo`, but `a` is actually a file in the other commit.
1865 1931 """
1866 1932 def fail(path, component):
1867 1933 # p1() is the base and we're receiving "writes" for p2()'s
1868 1934 # files.
1869 1935 if 'l' in self.p1()[component].flags():
1870 1936 raise error.Abort("error: %s conflicts with symlink %s "
1871 1937 "in %d." % (path, component,
1872 1938 self.p1().rev()))
1873 1939 else:
1874 1940 raise error.Abort("error: '%s' conflicts with file '%s' in "
1875 1941 "%d." % (path, component,
1876 1942 self.p1().rev()))
1877 1943
1878 1944 # Test that each new directory to be created to write this path from p2
1879 1945 # is not a file in p1.
1880 1946 components = path.split('/')
1881 1947 for i in pycompat.xrange(len(components)):
1882 1948 component = "/".join(components[0:i])
1883 1949 if component in self:
1884 1950 fail(path, component)
1885 1951
1886 1952 # Test the other direction -- that this path from p2 isn't a directory
1887 1953 # in p1 (test that p1 doesn't have any paths matching `path/*`).
1888 1954 match = self.match(pats=[path + '/'], default=b'path')
1889 1955 matches = self.p1().manifest().matches(match)
1890 1956 mfiles = matches.keys()
1891 1957 if len(mfiles) > 0:
1892 1958 if len(mfiles) == 1 and mfiles[0] == path:
1893 1959 return
1894 1960 # omit the files which are deleted in current IMM wctx
1895 1961 mfiles = [m for m in mfiles if m in self]
1896 1962 if not mfiles:
1897 1963 return
1898 1964 raise error.Abort("error: file '%s' cannot be written because "
1899 1965 " '%s/' is a folder in %s (containing %d "
1900 1966 "entries: %s)"
1901 1967 % (path, path, self.p1(), len(mfiles),
1902 1968 ', '.join(mfiles)))
1903 1969
1904 1970 def write(self, path, data, flags='', **kwargs):
1905 1971 if data is None:
1906 1972 raise error.ProgrammingError("data must be non-None")
1907 1973 self._auditconflicts(path)
1908 1974 self._markdirty(path, exists=True, data=data, date=dateutil.makedate(),
1909 1975 flags=flags)
1910 1976
1911 1977 def setflags(self, path, l, x):
1912 1978 flag = ''
1913 1979 if l:
1914 1980 flag = 'l'
1915 1981 elif x:
1916 1982 flag = 'x'
1917 1983 self._markdirty(path, exists=True, date=dateutil.makedate(),
1918 1984 flags=flag)
1919 1985
1920 1986 def remove(self, path):
1921 1987 self._markdirty(path, exists=False)
1922 1988
1923 1989 def exists(self, path):
1924 1990 """exists behaves like `lexists`, but needs to follow symlinks and
1925 1991 return False if they are broken.
1926 1992 """
1927 1993 if self.isdirty(path):
1928 1994 # If this path exists and is a symlink, "follow" it by calling
1929 1995 # exists on the destination path.
1930 1996 if (self._cache[path]['exists'] and
1931 1997 'l' in self._cache[path]['flags']):
1932 1998 return self.exists(self._cache[path]['data'].strip())
1933 1999 else:
1934 2000 return self._cache[path]['exists']
1935 2001
1936 2002 return self._existsinparent(path)
1937 2003
1938 2004 def lexists(self, path):
1939 2005 """lexists returns True if the path exists"""
1940 2006 if self.isdirty(path):
1941 2007 return self._cache[path]['exists']
1942 2008
1943 2009 return self._existsinparent(path)
1944 2010
1945 2011 def size(self, path):
1946 2012 if self.isdirty(path):
1947 2013 if self._cache[path]['exists']:
1948 2014 return len(self._cache[path]['data'])
1949 2015 else:
1950 2016 raise error.ProgrammingError("No such file or directory: %s" %
1951 2017 self._path)
1952 2018 return self._wrappedctx[path].size()
1953 2019
1954 2020 def tomemctx(self, text, branch=None, extra=None, date=None, parents=None,
1955 2021 user=None, editor=None):
1956 2022 """Converts this ``overlayworkingctx`` into a ``memctx`` ready to be
1957 2023 committed.
1958 2024
1959 2025 ``text`` is the commit message.
1960 2026 ``parents`` (optional) are rev numbers.
1961 2027 """
1962 2028 # Default parents to the wrapped contexts' if not passed.
1963 2029 if parents is None:
1964 2030 parents = self._wrappedctx.parents()
1965 2031 if len(parents) == 1:
1966 2032 parents = (parents[0], None)
1967 2033
1968 2034 # ``parents`` is passed as rev numbers; convert to ``commitctxs``.
1969 2035 if parents[1] is None:
1970 2036 parents = (self._repo[parents[0]], None)
1971 2037 else:
1972 2038 parents = (self._repo[parents[0]], self._repo[parents[1]])
1973 2039
1974 2040 files = self._cache.keys()
1975 2041 def getfile(repo, memctx, path):
1976 2042 if self._cache[path]['exists']:
1977 2043 return memfilectx(repo, memctx, path,
1978 2044 self._cache[path]['data'],
1979 2045 'l' in self._cache[path]['flags'],
1980 2046 'x' in self._cache[path]['flags'],
1981 2047 self._cache[path]['copied'])
1982 2048 else:
1983 2049 # Returning None, but including the path in `files`, is
1984 2050 # necessary for memctx to register a deletion.
1985 2051 return None
1986 2052 return memctx(self._repo, parents, text, files, getfile, date=date,
1987 2053 extra=extra, user=user, branch=branch, editor=editor)
1988 2054
1989 2055 def isdirty(self, path):
1990 2056 return path in self._cache
1991 2057
1992 2058 def isempty(self):
1993 2059 # We need to discard any keys that are actually clean before the empty
1994 2060 # commit check.
1995 2061 self._compact()
1996 2062 return len(self._cache) == 0
1997 2063
1998 2064 def clean(self):
1999 2065 self._cache = {}
2000 2066
2001 2067 def _compact(self):
2002 2068 """Removes keys from the cache that are actually clean, by comparing
2003 2069 them with the underlying context.
2004 2070
2005 2071 This can occur during the merge process, e.g. by passing --tool :local
2006 2072 to resolve a conflict.
2007 2073 """
2008 2074 keys = []
2009 2075 # This won't be perfect, but can help performance significantly when
2010 2076 # using things like remotefilelog.
2011 2077 scmutil.prefetchfiles(
2012 2078 self.repo(), [self.p1().rev()],
2013 2079 scmutil.matchfiles(self.repo(), self._cache.keys()))
2014 2080
2015 2081 for path in self._cache.keys():
2016 2082 cache = self._cache[path]
2017 2083 try:
2018 2084 underlying = self._wrappedctx[path]
2019 2085 if (underlying.data() == cache['data'] and
2020 2086 underlying.flags() == cache['flags']):
2021 2087 keys.append(path)
2022 2088 except error.ManifestLookupError:
2023 2089 # Path not in the underlying manifest (created).
2024 2090 continue
2025 2091
2026 2092 for path in keys:
2027 2093 del self._cache[path]
2028 2094 return keys
2029 2095
2030 2096 def _markdirty(self, path, exists, data=None, date=None, flags=''):
2031 2097 # data not provided, let's see if we already have some; if not, let's
2032 2098 # grab it from our underlying context, so that we always have data if
2033 2099 # the file is marked as existing.
2034 2100 if exists and data is None:
2035 2101 oldentry = self._cache.get(path) or {}
2036 2102 data = oldentry.get('data') or self._wrappedctx[path].data()
2037 2103
2038 2104 self._cache[path] = {
2039 2105 'exists': exists,
2040 2106 'data': data,
2041 2107 'date': date,
2042 2108 'flags': flags,
2043 2109 'copied': None,
2044 2110 }
2045 2111
2046 2112 def filectx(self, path, filelog=None):
2047 2113 return overlayworkingfilectx(self._repo, path, parent=self,
2048 2114 filelog=filelog)
2049 2115
2050 2116 class overlayworkingfilectx(committablefilectx):
2051 2117 """Wrap a ``workingfilectx`` but intercepts all writes into an in-memory
2052 2118 cache, which can be flushed through later by calling ``flush()``."""
2053 2119
2054 2120 def __init__(self, repo, path, filelog=None, parent=None):
2055 2121 super(overlayworkingfilectx, self).__init__(repo, path, filelog,
2056 2122 parent)
2057 2123 self._repo = repo
2058 2124 self._parent = parent
2059 2125 self._path = path
2060 2126
2061 2127 def cmp(self, fctx):
2062 2128 return self.data() != fctx.data()
2063 2129
2064 2130 def changectx(self):
2065 2131 return self._parent
2066 2132
2067 2133 def data(self):
2068 2134 return self._parent.data(self._path)
2069 2135
2070 2136 def date(self):
2071 2137 return self._parent.filedate(self._path)
2072 2138
2073 2139 def exists(self):
2074 2140 return self.lexists()
2075 2141
2076 2142 def lexists(self):
2077 2143 return self._parent.exists(self._path)
2078 2144
2079 2145 def renamed(self):
2080 2146 path = self._parent.copydata(self._path)
2081 2147 if not path:
2082 2148 return None
2083 2149 return path, self._changectx._parents[0]._manifest.get(path, nullid)
2084 2150
2085 2151 def size(self):
2086 2152 return self._parent.size(self._path)
2087 2153
2088 2154 def markcopied(self, origin):
2089 2155 self._parent.markcopied(self._path, origin)
2090 2156
2091 2157 def audit(self):
2092 2158 pass
2093 2159
2094 2160 def flags(self):
2095 2161 return self._parent.flags(self._path)
2096 2162
2097 2163 def setflags(self, islink, isexec):
2098 2164 return self._parent.setflags(self._path, islink, isexec)
2099 2165
2100 2166 def write(self, data, flags, backgroundclose=False, **kwargs):
2101 2167 return self._parent.write(self._path, data, flags, **kwargs)
2102 2168
2103 2169 def remove(self, ignoremissing=False):
2104 2170 return self._parent.remove(self._path)
2105 2171
2106 2172 def clearunknown(self):
2107 2173 pass
2108 2174
2109 2175 class workingcommitctx(workingctx):
2110 2176 """A workingcommitctx object makes access to data related to
2111 2177 the revision being committed convenient.
2112 2178
2113 2179 This hides changes in the working directory, if they aren't
2114 2180 committed in this context.
2115 2181 """
2116 2182 def __init__(self, repo, changes,
2117 2183 text="", user=None, date=None, extra=None):
2118 2184 super(workingcommitctx, self).__init__(repo, text, user, date, extra,
2119 2185 changes)
2120 2186
2121 2187 def _dirstatestatus(self, match, ignored=False, clean=False, unknown=False):
2122 2188 """Return matched files only in ``self._status``
2123 2189
2124 2190 Uncommitted files appear "clean" via this context, even if
2125 2191 they aren't actually so in the working directory.
2126 2192 """
2127 2193 if clean:
2128 2194 clean = [f for f in self._manifest if f not in self._changedset]
2129 2195 else:
2130 2196 clean = []
2131 2197 return scmutil.status([f for f in self._status.modified if match(f)],
2132 2198 [f for f in self._status.added if match(f)],
2133 2199 [f for f in self._status.removed if match(f)],
2134 2200 [], [], [], clean)
2135 2201
2136 2202 @propertycache
2137 2203 def _changedset(self):
2138 2204 """Return the set of files changed in this context
2139 2205 """
2140 2206 changed = set(self._status.modified)
2141 2207 changed.update(self._status.added)
2142 2208 changed.update(self._status.removed)
2143 2209 return changed
2144 2210
2145 2211 def makecachingfilectxfn(func):
2146 2212 """Create a filectxfn that caches based on the path.
2147 2213
2148 2214 We can't use util.cachefunc because it uses all arguments as the cache
2149 2215 key and this creates a cycle since the arguments include the repo and
2150 2216 memctx.
2151 2217 """
2152 2218 cache = {}
2153 2219
2154 2220 def getfilectx(repo, memctx, path):
2155 2221 if path not in cache:
2156 2222 cache[path] = func(repo, memctx, path)
2157 2223 return cache[path]
2158 2224
2159 2225 return getfilectx
2160 2226
2161 2227 def memfilefromctx(ctx):
2162 2228 """Given a context return a memfilectx for ctx[path]
2163 2229
2164 2230 This is a convenience method for building a memctx based on another
2165 2231 context.
2166 2232 """
2167 2233 def getfilectx(repo, memctx, path):
2168 2234 fctx = ctx[path]
2169 2235 copied = fctx.renamed()
2170 2236 if copied:
2171 2237 copied = copied[0]
2172 2238 return memfilectx(repo, memctx, path, fctx.data(),
2173 2239 islink=fctx.islink(), isexec=fctx.isexec(),
2174 2240 copied=copied)
2175 2241
2176 2242 return getfilectx
2177 2243
2178 2244 def memfilefrompatch(patchstore):
2179 2245 """Given a patch (e.g. patchstore object) return a memfilectx
2180 2246
2181 2247 This is a convenience method for building a memctx based on a patchstore.
2182 2248 """
2183 2249 def getfilectx(repo, memctx, path):
2184 2250 data, mode, copied = patchstore.getfile(path)
2185 2251 if data is None:
2186 2252 return None
2187 2253 islink, isexec = mode
2188 2254 return memfilectx(repo, memctx, path, data, islink=islink,
2189 2255 isexec=isexec, copied=copied)
2190 2256
2191 2257 return getfilectx
2192 2258
2193 2259 class memctx(committablectx):
2194 2260 """Use memctx to perform in-memory commits via localrepo.commitctx().
2195 2261
2196 2262 Revision information is supplied at initialization time while
2197 2263 related files data and is made available through a callback
2198 2264 mechanism. 'repo' is the current localrepo, 'parents' is a
2199 2265 sequence of two parent revisions identifiers (pass None for every
2200 2266 missing parent), 'text' is the commit message and 'files' lists
2201 2267 names of files touched by the revision (normalized and relative to
2202 2268 repository root).
2203 2269
2204 2270 filectxfn(repo, memctx, path) is a callable receiving the
2205 2271 repository, the current memctx object and the normalized path of
2206 2272 requested file, relative to repository root. It is fired by the
2207 2273 commit function for every file in 'files', but calls order is
2208 2274 undefined. If the file is available in the revision being
2209 2275 committed (updated or added), filectxfn returns a memfilectx
2210 2276 object. If the file was removed, filectxfn return None for recent
2211 2277 Mercurial. Moved files are represented by marking the source file
2212 2278 removed and the new file added with copy information (see
2213 2279 memfilectx).
2214 2280
2215 2281 user receives the committer name and defaults to current
2216 2282 repository username, date is the commit date in any format
2217 2283 supported by dateutil.parsedate() and defaults to current date, extra
2218 2284 is a dictionary of metadata or is left empty.
2219 2285 """
2220 2286
2221 2287 # Mercurial <= 3.1 expects the filectxfn to raise IOError for missing files.
2222 2288 # Extensions that need to retain compatibility across Mercurial 3.1 can use
2223 2289 # this field to determine what to do in filectxfn.
2224 2290 _returnnoneformissingfiles = True
2225 2291
2226 2292 def __init__(self, repo, parents, text, files, filectxfn, user=None,
2227 2293 date=None, extra=None, branch=None, editor=False):
2228 2294 super(memctx, self).__init__(repo, text, user, date, extra)
2229 2295 self._rev = None
2230 2296 self._node = None
2231 2297 parents = [(p or nullid) for p in parents]
2232 2298 p1, p2 = parents
2233 2299 self._parents = [self._repo[p] for p in (p1, p2)]
2234 2300 files = sorted(set(files))
2235 2301 self._files = files
2236 2302 if branch is not None:
2237 2303 self._extra['branch'] = encoding.fromlocal(branch)
2238 2304 self.substate = {}
2239 2305
2240 2306 if isinstance(filectxfn, patch.filestore):
2241 2307 filectxfn = memfilefrompatch(filectxfn)
2242 2308 elif not callable(filectxfn):
2243 2309 # if store is not callable, wrap it in a function
2244 2310 filectxfn = memfilefromctx(filectxfn)
2245 2311
2246 2312 # memoizing increases performance for e.g. vcs convert scenarios.
2247 2313 self._filectxfn = makecachingfilectxfn(filectxfn)
2248 2314
2249 2315 if editor:
2250 2316 self._text = editor(self._repo, self, [])
2251 2317 self._repo.savecommitmessage(self._text)
2252 2318
2253 2319 def filectx(self, path, filelog=None):
2254 2320 """get a file context from the working directory
2255 2321
2256 2322 Returns None if file doesn't exist and should be removed."""
2257 2323 return self._filectxfn(self._repo, self, path)
2258 2324
2259 2325 def commit(self):
2260 2326 """commit context to the repo"""
2261 2327 return self._repo.commitctx(self)
2262 2328
2263 2329 @propertycache
2264 2330 def _manifest(self):
2265 2331 """generate a manifest based on the return values of filectxfn"""
2266 2332
2267 2333 # keep this simple for now; just worry about p1
2268 2334 pctx = self._parents[0]
2269 2335 man = pctx.manifest().copy()
2270 2336
2271 2337 for f in self._status.modified:
2272 2338 man[f] = modifiednodeid
2273 2339
2274 2340 for f in self._status.added:
2275 2341 man[f] = addednodeid
2276 2342
2277 2343 for f in self._status.removed:
2278 2344 if f in man:
2279 2345 del man[f]
2280 2346
2281 2347 return man
2282 2348
2283 2349 @propertycache
2284 2350 def _status(self):
2285 2351 """Calculate exact status from ``files`` specified at construction
2286 2352 """
2287 2353 man1 = self.p1().manifest()
2288 2354 p2 = self._parents[1]
2289 2355 # "1 < len(self._parents)" can't be used for checking
2290 2356 # existence of the 2nd parent, because "memctx._parents" is
2291 2357 # explicitly initialized by the list, of which length is 2.
2292 2358 if p2.node() != nullid:
2293 2359 man2 = p2.manifest()
2294 2360 managing = lambda f: f in man1 or f in man2
2295 2361 else:
2296 2362 managing = lambda f: f in man1
2297 2363
2298 2364 modified, added, removed = [], [], []
2299 2365 for f in self._files:
2300 2366 if not managing(f):
2301 2367 added.append(f)
2302 2368 elif self[f]:
2303 2369 modified.append(f)
2304 2370 else:
2305 2371 removed.append(f)
2306 2372
2307 2373 return scmutil.status(modified, added, removed, [], [], [], [])
2308 2374
2309 2375 class memfilectx(committablefilectx):
2310 2376 """memfilectx represents an in-memory file to commit.
2311 2377
2312 2378 See memctx and committablefilectx for more details.
2313 2379 """
2314 2380 def __init__(self, repo, changectx, path, data, islink=False,
2315 2381 isexec=False, copied=None):
2316 2382 """
2317 2383 path is the normalized file path relative to repository root.
2318 2384 data is the file content as a string.
2319 2385 islink is True if the file is a symbolic link.
2320 2386 isexec is True if the file is executable.
2321 2387 copied is the source file path if current file was copied in the
2322 2388 revision being committed, or None."""
2323 2389 super(memfilectx, self).__init__(repo, path, None, changectx)
2324 2390 self._data = data
2325 2391 if islink:
2326 2392 self._flags = 'l'
2327 2393 elif isexec:
2328 2394 self._flags = 'x'
2329 2395 else:
2330 2396 self._flags = ''
2331 2397 self._copied = None
2332 2398 if copied:
2333 2399 self._copied = (copied, nullid)
2334 2400
2335 2401 def cmp(self, fctx):
2336 2402 return self.data() != fctx.data()
2337 2403
2338 2404 def data(self):
2339 2405 return self._data
2340 2406
2341 2407 def remove(self, ignoremissing=False):
2342 2408 """wraps unlink for a repo's working directory"""
2343 2409 # need to figure out what to do here
2344 2410 del self._changectx[self._path]
2345 2411
2346 2412 def write(self, data, flags, **kwargs):
2347 2413 """wraps repo.wwrite"""
2348 2414 self._data = data
2349 2415
2350 2416
2351 2417 class metadataonlyctx(committablectx):
2352 2418 """Like memctx but it's reusing the manifest of different commit.
2353 2419 Intended to be used by lightweight operations that are creating
2354 2420 metadata-only changes.
2355 2421
2356 2422 Revision information is supplied at initialization time. 'repo' is the
2357 2423 current localrepo, 'ctx' is original revision which manifest we're reuisng
2358 2424 'parents' is a sequence of two parent revisions identifiers (pass None for
2359 2425 every missing parent), 'text' is the commit.
2360 2426
2361 2427 user receives the committer name and defaults to current repository
2362 2428 username, date is the commit date in any format supported by
2363 2429 dateutil.parsedate() and defaults to current date, extra is a dictionary of
2364 2430 metadata or is left empty.
2365 2431 """
2366 2432 def __init__(self, repo, originalctx, parents=None, text=None, user=None,
2367 2433 date=None, extra=None, editor=False):
2368 2434 if text is None:
2369 2435 text = originalctx.description()
2370 2436 super(metadataonlyctx, self).__init__(repo, text, user, date, extra)
2371 2437 self._rev = None
2372 2438 self._node = None
2373 2439 self._originalctx = originalctx
2374 2440 self._manifestnode = originalctx.manifestnode()
2375 2441 if parents is None:
2376 2442 parents = originalctx.parents()
2377 2443 else:
2378 2444 parents = [repo[p] for p in parents if p is not None]
2379 2445 parents = parents[:]
2380 2446 while len(parents) < 2:
2381 2447 parents.append(repo[nullid])
2382 2448 p1, p2 = self._parents = parents
2383 2449
2384 2450 # sanity check to ensure that the reused manifest parents are
2385 2451 # manifests of our commit parents
2386 2452 mp1, mp2 = self.manifestctx().parents
2387 2453 if p1 != nullid and p1.manifestnode() != mp1:
2388 2454 raise RuntimeError(r"can't reuse the manifest: its p1 "
2389 2455 r"doesn't match the new ctx p1")
2390 2456 if p2 != nullid and p2.manifestnode() != mp2:
2391 2457 raise RuntimeError(r"can't reuse the manifest: "
2392 2458 r"its p2 doesn't match the new ctx p2")
2393 2459
2394 2460 self._files = originalctx.files()
2395 2461 self.substate = {}
2396 2462
2397 2463 if editor:
2398 2464 self._text = editor(self._repo, self, [])
2399 2465 self._repo.savecommitmessage(self._text)
2400 2466
2401 2467 def manifestnode(self):
2402 2468 return self._manifestnode
2403 2469
2404 2470 @property
2405 2471 def _manifestctx(self):
2406 2472 return self._repo.manifestlog[self._manifestnode]
2407 2473
2408 2474 def filectx(self, path, filelog=None):
2409 2475 return self._originalctx.filectx(path, filelog=filelog)
2410 2476
2411 2477 def commit(self):
2412 2478 """commit context to the repo"""
2413 2479 return self._repo.commitctx(self)
2414 2480
2415 2481 @property
2416 2482 def _manifest(self):
2417 2483 return self._originalctx.manifest()
2418 2484
2419 2485 @propertycache
2420 2486 def _status(self):
2421 2487 """Calculate exact status from ``files`` specified in the ``origctx``
2422 2488 and parents manifests.
2423 2489 """
2424 2490 man1 = self.p1().manifest()
2425 2491 p2 = self._parents[1]
2426 2492 # "1 < len(self._parents)" can't be used for checking
2427 2493 # existence of the 2nd parent, because "metadataonlyctx._parents" is
2428 2494 # explicitly initialized by the list, of which length is 2.
2429 2495 if p2.node() != nullid:
2430 2496 man2 = p2.manifest()
2431 2497 managing = lambda f: f in man1 or f in man2
2432 2498 else:
2433 2499 managing = lambda f: f in man1
2434 2500
2435 2501 modified, added, removed = [], [], []
2436 2502 for f in self._files:
2437 2503 if not managing(f):
2438 2504 added.append(f)
2439 2505 elif f in self:
2440 2506 modified.append(f)
2441 2507 else:
2442 2508 removed.append(f)
2443 2509
2444 2510 return scmutil.status(modified, added, removed, [], [], [], [])
2445 2511
2446 2512 class arbitraryfilectx(object):
2447 2513 """Allows you to use filectx-like functions on a file in an arbitrary
2448 2514 location on disk, possibly not in the working directory.
2449 2515 """
2450 2516 def __init__(self, path, repo=None):
2451 2517 # Repo is optional because contrib/simplemerge uses this class.
2452 2518 self._repo = repo
2453 2519 self._path = path
2454 2520
2455 2521 def cmp(self, fctx):
2456 2522 # filecmp follows symlinks whereas `cmp` should not, so skip the fast
2457 2523 # path if either side is a symlink.
2458 2524 symlinks = ('l' in self.flags() or 'l' in fctx.flags())
2459 2525 if not symlinks and isinstance(fctx, workingfilectx) and self._repo:
2460 2526 # Add a fast-path for merge if both sides are disk-backed.
2461 2527 # Note that filecmp uses the opposite return values (True if same)
2462 2528 # from our cmp functions (True if different).
2463 2529 return not filecmp.cmp(self.path(), self._repo.wjoin(fctx.path()))
2464 2530 return self.data() != fctx.data()
2465 2531
2466 2532 def path(self):
2467 2533 return self._path
2468 2534
2469 2535 def flags(self):
2470 2536 return ''
2471 2537
2472 2538 def data(self):
2473 2539 return util.readfile(self._path)
2474 2540
2475 2541 def decodeddata(self):
2476 2542 with open(self._path, "rb") as f:
2477 2543 return f.read()
2478 2544
2479 2545 def remove(self):
2480 2546 util.unlink(self._path)
2481 2547
2482 2548 def write(self, data, flags, **kwargs):
2483 2549 assert not flags
2484 2550 with open(self._path, "wb") as f:
2485 2551 f.write(data)
@@ -1,3398 +1,3420 b''
1 1 # debugcommands.py - command processing for debug* commands
2 2 #
3 3 # Copyright 2005-2016 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import codecs
11 11 import collections
12 12 import difflib
13 13 import errno
14 14 import operator
15 15 import os
16 16 import random
17 17 import re
18 18 import socket
19 19 import ssl
20 20 import stat
21 21 import string
22 22 import subprocess
23 23 import sys
24 24 import time
25 25
26 26 from .i18n import _
27 27 from .node import (
28 28 bin,
29 29 hex,
30 30 nullhex,
31 31 nullid,
32 32 nullrev,
33 33 short,
34 34 )
35 35 from . import (
36 36 bundle2,
37 37 changegroup,
38 38 cmdutil,
39 39 color,
40 40 context,
41 41 copies,
42 42 dagparser,
43 43 encoding,
44 44 error,
45 45 exchange,
46 46 extensions,
47 47 filemerge,
48 48 filesetlang,
49 49 formatter,
50 50 hg,
51 51 httppeer,
52 52 localrepo,
53 53 lock as lockmod,
54 54 logcmdutil,
55 55 merge as mergemod,
56 56 obsolete,
57 57 obsutil,
58 58 phases,
59 59 policy,
60 60 pvec,
61 61 pycompat,
62 62 registrar,
63 63 repair,
64 64 revlog,
65 65 revset,
66 66 revsetlang,
67 67 scmutil,
68 68 setdiscovery,
69 69 simplemerge,
70 70 sshpeer,
71 71 sslutil,
72 72 streamclone,
73 73 templater,
74 74 treediscovery,
75 75 upgrade,
76 76 url as urlmod,
77 77 util,
78 78 vfs as vfsmod,
79 79 wireprotoframing,
80 80 wireprotoserver,
81 81 wireprotov2peer,
82 82 )
83 83 from .utils import (
84 84 cborutil,
85 85 dateutil,
86 86 procutil,
87 87 stringutil,
88 88 )
89 89
90 90 from .revlogutils import (
91 91 deltas as deltautil
92 92 )
93 93
94 94 release = lockmod.release
95 95
96 96 command = registrar.command()
97 97
98 98 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
99 99 def debugancestor(ui, repo, *args):
100 100 """find the ancestor revision of two revisions in a given index"""
101 101 if len(args) == 3:
102 102 index, rev1, rev2 = args
103 103 r = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False), index)
104 104 lookup = r.lookup
105 105 elif len(args) == 2:
106 106 if not repo:
107 107 raise error.Abort(_('there is no Mercurial repository here '
108 108 '(.hg not found)'))
109 109 rev1, rev2 = args
110 110 r = repo.changelog
111 111 lookup = repo.lookup
112 112 else:
113 113 raise error.Abort(_('either two or three arguments required'))
114 114 a = r.ancestor(lookup(rev1), lookup(rev2))
115 115 ui.write('%d:%s\n' % (r.rev(a), hex(a)))
116 116
117 117 @command('debugapplystreamclonebundle', [], 'FILE')
118 118 def debugapplystreamclonebundle(ui, repo, fname):
119 119 """apply a stream clone bundle file"""
120 120 f = hg.openpath(ui, fname)
121 121 gen = exchange.readbundle(ui, f, fname)
122 122 gen.apply(repo)
123 123
124 124 @command('debugbuilddag',
125 125 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
126 126 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
127 127 ('n', 'new-file', None, _('add new file at each rev'))],
128 128 _('[OPTION]... [TEXT]'))
129 129 def debugbuilddag(ui, repo, text=None,
130 130 mergeable_file=False,
131 131 overwritten_file=False,
132 132 new_file=False):
133 133 """builds a repo with a given DAG from scratch in the current empty repo
134 134
135 135 The description of the DAG is read from stdin if not given on the
136 136 command line.
137 137
138 138 Elements:
139 139
140 140 - "+n" is a linear run of n nodes based on the current default parent
141 141 - "." is a single node based on the current default parent
142 142 - "$" resets the default parent to null (implied at the start);
143 143 otherwise the default parent is always the last node created
144 144 - "<p" sets the default parent to the backref p
145 145 - "*p" is a fork at parent p, which is a backref
146 146 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
147 147 - "/p2" is a merge of the preceding node and p2
148 148 - ":tag" defines a local tag for the preceding node
149 149 - "@branch" sets the named branch for subsequent nodes
150 150 - "#...\\n" is a comment up to the end of the line
151 151
152 152 Whitespace between the above elements is ignored.
153 153
154 154 A backref is either
155 155
156 156 - a number n, which references the node curr-n, where curr is the current
157 157 node, or
158 158 - the name of a local tag you placed earlier using ":tag", or
159 159 - empty to denote the default parent.
160 160
161 161 All string valued-elements are either strictly alphanumeric, or must
162 162 be enclosed in double quotes ("..."), with "\\" as escape character.
163 163 """
164 164
165 165 if text is None:
166 166 ui.status(_("reading DAG from stdin\n"))
167 167 text = ui.fin.read()
168 168
169 169 cl = repo.changelog
170 170 if len(cl) > 0:
171 171 raise error.Abort(_('repository is not empty'))
172 172
173 173 # determine number of revs in DAG
174 174 total = 0
175 175 for type, data in dagparser.parsedag(text):
176 176 if type == 'n':
177 177 total += 1
178 178
179 179 if mergeable_file:
180 180 linesperrev = 2
181 181 # make a file with k lines per rev
182 182 initialmergedlines = ['%d' % i
183 183 for i in pycompat.xrange(0, total * linesperrev)]
184 184 initialmergedlines.append("")
185 185
186 186 tags = []
187 187 progress = ui.makeprogress(_('building'), unit=_('revisions'),
188 188 total=total)
189 189 with progress, repo.wlock(), repo.lock(), repo.transaction("builddag"):
190 190 at = -1
191 191 atbranch = 'default'
192 192 nodeids = []
193 193 id = 0
194 194 progress.update(id)
195 195 for type, data in dagparser.parsedag(text):
196 196 if type == 'n':
197 197 ui.note(('node %s\n' % pycompat.bytestr(data)))
198 198 id, ps = data
199 199
200 200 files = []
201 201 filecontent = {}
202 202
203 203 p2 = None
204 204 if mergeable_file:
205 205 fn = "mf"
206 206 p1 = repo[ps[0]]
207 207 if len(ps) > 1:
208 208 p2 = repo[ps[1]]
209 209 pa = p1.ancestor(p2)
210 210 base, local, other = [x[fn].data() for x in (pa, p1,
211 211 p2)]
212 212 m3 = simplemerge.Merge3Text(base, local, other)
213 213 ml = [l.strip() for l in m3.merge_lines()]
214 214 ml.append("")
215 215 elif at > 0:
216 216 ml = p1[fn].data().split("\n")
217 217 else:
218 218 ml = initialmergedlines
219 219 ml[id * linesperrev] += " r%i" % id
220 220 mergedtext = "\n".join(ml)
221 221 files.append(fn)
222 222 filecontent[fn] = mergedtext
223 223
224 224 if overwritten_file:
225 225 fn = "of"
226 226 files.append(fn)
227 227 filecontent[fn] = "r%i\n" % id
228 228
229 229 if new_file:
230 230 fn = "nf%i" % id
231 231 files.append(fn)
232 232 filecontent[fn] = "r%i\n" % id
233 233 if len(ps) > 1:
234 234 if not p2:
235 235 p2 = repo[ps[1]]
236 236 for fn in p2:
237 237 if fn.startswith("nf"):
238 238 files.append(fn)
239 239 filecontent[fn] = p2[fn].data()
240 240
241 241 def fctxfn(repo, cx, path):
242 242 if path in filecontent:
243 243 return context.memfilectx(repo, cx, path,
244 244 filecontent[path])
245 245 return None
246 246
247 247 if len(ps) == 0 or ps[0] < 0:
248 248 pars = [None, None]
249 249 elif len(ps) == 1:
250 250 pars = [nodeids[ps[0]], None]
251 251 else:
252 252 pars = [nodeids[p] for p in ps]
253 253 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
254 254 date=(id, 0),
255 255 user="debugbuilddag",
256 256 extra={'branch': atbranch})
257 257 nodeid = repo.commitctx(cx)
258 258 nodeids.append(nodeid)
259 259 at = id
260 260 elif type == 'l':
261 261 id, name = data
262 262 ui.note(('tag %s\n' % name))
263 263 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
264 264 elif type == 'a':
265 265 ui.note(('branch %s\n' % data))
266 266 atbranch = data
267 267 progress.update(id)
268 268
269 269 if tags:
270 270 repo.vfs.write("localtags", "".join(tags))
271 271
272 272 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
273 273 indent_string = ' ' * indent
274 274 if all:
275 275 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
276 276 % indent_string)
277 277
278 278 def showchunks(named):
279 279 ui.write("\n%s%s\n" % (indent_string, named))
280 280 for deltadata in gen.deltaiter():
281 281 node, p1, p2, cs, deltabase, delta, flags = deltadata
282 282 ui.write("%s%s %s %s %s %s %d\n" %
283 283 (indent_string, hex(node), hex(p1), hex(p2),
284 284 hex(cs), hex(deltabase), len(delta)))
285 285
286 286 chunkdata = gen.changelogheader()
287 287 showchunks("changelog")
288 288 chunkdata = gen.manifestheader()
289 289 showchunks("manifest")
290 290 for chunkdata in iter(gen.filelogheader, {}):
291 291 fname = chunkdata['filename']
292 292 showchunks(fname)
293 293 else:
294 294 if isinstance(gen, bundle2.unbundle20):
295 295 raise error.Abort(_('use debugbundle2 for this file'))
296 296 chunkdata = gen.changelogheader()
297 297 for deltadata in gen.deltaiter():
298 298 node, p1, p2, cs, deltabase, delta, flags = deltadata
299 299 ui.write("%s%s\n" % (indent_string, hex(node)))
300 300
301 301 def _debugobsmarkers(ui, part, indent=0, **opts):
302 302 """display version and markers contained in 'data'"""
303 303 opts = pycompat.byteskwargs(opts)
304 304 data = part.read()
305 305 indent_string = ' ' * indent
306 306 try:
307 307 version, markers = obsolete._readmarkers(data)
308 308 except error.UnknownVersion as exc:
309 309 msg = "%sunsupported version: %s (%d bytes)\n"
310 310 msg %= indent_string, exc.version, len(data)
311 311 ui.write(msg)
312 312 else:
313 313 msg = "%sversion: %d (%d bytes)\n"
314 314 msg %= indent_string, version, len(data)
315 315 ui.write(msg)
316 316 fm = ui.formatter('debugobsolete', opts)
317 317 for rawmarker in sorted(markers):
318 318 m = obsutil.marker(None, rawmarker)
319 319 fm.startitem()
320 320 fm.plain(indent_string)
321 321 cmdutil.showmarker(fm, m)
322 322 fm.end()
323 323
324 324 def _debugphaseheads(ui, data, indent=0):
325 325 """display version and markers contained in 'data'"""
326 326 indent_string = ' ' * indent
327 327 headsbyphase = phases.binarydecode(data)
328 328 for phase in phases.allphases:
329 329 for head in headsbyphase[phase]:
330 330 ui.write(indent_string)
331 331 ui.write('%s %s\n' % (hex(head), phases.phasenames[phase]))
332 332
333 333 def _quasirepr(thing):
334 334 if isinstance(thing, (dict, util.sortdict, collections.OrderedDict)):
335 335 return '{%s}' % (
336 336 b', '.join(b'%s: %s' % (k, thing[k]) for k in sorted(thing)))
337 337 return pycompat.bytestr(repr(thing))
338 338
339 339 def _debugbundle2(ui, gen, all=None, **opts):
340 340 """lists the contents of a bundle2"""
341 341 if not isinstance(gen, bundle2.unbundle20):
342 342 raise error.Abort(_('not a bundle2 file'))
343 343 ui.write(('Stream params: %s\n' % _quasirepr(gen.params)))
344 344 parttypes = opts.get(r'part_type', [])
345 345 for part in gen.iterparts():
346 346 if parttypes and part.type not in parttypes:
347 347 continue
348 348 msg = '%s -- %s (mandatory: %r)\n'
349 349 ui.write((msg % (part.type, _quasirepr(part.params), part.mandatory)))
350 350 if part.type == 'changegroup':
351 351 version = part.params.get('version', '01')
352 352 cg = changegroup.getunbundler(version, part, 'UN')
353 353 if not ui.quiet:
354 354 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
355 355 if part.type == 'obsmarkers':
356 356 if not ui.quiet:
357 357 _debugobsmarkers(ui, part, indent=4, **opts)
358 358 if part.type == 'phase-heads':
359 359 if not ui.quiet:
360 360 _debugphaseheads(ui, part, indent=4)
361 361
362 362 @command('debugbundle',
363 363 [('a', 'all', None, _('show all details')),
364 364 ('', 'part-type', [], _('show only the named part type')),
365 365 ('', 'spec', None, _('print the bundlespec of the bundle'))],
366 366 _('FILE'),
367 367 norepo=True)
368 368 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
369 369 """lists the contents of a bundle"""
370 370 with hg.openpath(ui, bundlepath) as f:
371 371 if spec:
372 372 spec = exchange.getbundlespec(ui, f)
373 373 ui.write('%s\n' % spec)
374 374 return
375 375
376 376 gen = exchange.readbundle(ui, f, bundlepath)
377 377 if isinstance(gen, bundle2.unbundle20):
378 378 return _debugbundle2(ui, gen, all=all, **opts)
379 379 _debugchangegroup(ui, gen, all=all, **opts)
380 380
381 381 @command('debugcapabilities',
382 382 [], _('PATH'),
383 383 norepo=True)
384 384 def debugcapabilities(ui, path, **opts):
385 385 """lists the capabilities of a remote peer"""
386 386 opts = pycompat.byteskwargs(opts)
387 387 peer = hg.peer(ui, opts, path)
388 388 caps = peer.capabilities()
389 389 ui.write(('Main capabilities:\n'))
390 390 for c in sorted(caps):
391 391 ui.write((' %s\n') % c)
392 392 b2caps = bundle2.bundle2caps(peer)
393 393 if b2caps:
394 394 ui.write(('Bundle2 capabilities:\n'))
395 395 for key, values in sorted(b2caps.iteritems()):
396 396 ui.write((' %s\n') % key)
397 397 for v in values:
398 398 ui.write((' %s\n') % v)
399 399
400 400 @command('debugcheckstate', [], '')
401 401 def debugcheckstate(ui, repo):
402 402 """validate the correctness of the current dirstate"""
403 403 parent1, parent2 = repo.dirstate.parents()
404 404 m1 = repo[parent1].manifest()
405 405 m2 = repo[parent2].manifest()
406 406 errors = 0
407 407 for f in repo.dirstate:
408 408 state = repo.dirstate[f]
409 409 if state in "nr" and f not in m1:
410 410 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
411 411 errors += 1
412 412 if state in "a" and f in m1:
413 413 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
414 414 errors += 1
415 415 if state in "m" and f not in m1 and f not in m2:
416 416 ui.warn(_("%s in state %s, but not in either manifest\n") %
417 417 (f, state))
418 418 errors += 1
419 419 for f in m1:
420 420 state = repo.dirstate[f]
421 421 if state not in "nrm":
422 422 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
423 423 errors += 1
424 424 if errors:
425 425 error = _(".hg/dirstate inconsistent with current parent's manifest")
426 426 raise error.Abort(error)
427 427
428 428 @command('debugcolor',
429 429 [('', 'style', None, _('show all configured styles'))],
430 430 'hg debugcolor')
431 431 def debugcolor(ui, repo, **opts):
432 432 """show available color, effects or style"""
433 433 ui.write(('color mode: %s\n') % stringutil.pprint(ui._colormode))
434 434 if opts.get(r'style'):
435 435 return _debugdisplaystyle(ui)
436 436 else:
437 437 return _debugdisplaycolor(ui)
438 438
439 439 def _debugdisplaycolor(ui):
440 440 ui = ui.copy()
441 441 ui._styles.clear()
442 442 for effect in color._activeeffects(ui).keys():
443 443 ui._styles[effect] = effect
444 444 if ui._terminfoparams:
445 445 for k, v in ui.configitems('color'):
446 446 if k.startswith('color.'):
447 447 ui._styles[k] = k[6:]
448 448 elif k.startswith('terminfo.'):
449 449 ui._styles[k] = k[9:]
450 450 ui.write(_('available colors:\n'))
451 451 # sort label with a '_' after the other to group '_background' entry.
452 452 items = sorted(ui._styles.items(),
453 453 key=lambda i: ('_' in i[0], i[0], i[1]))
454 454 for colorname, label in items:
455 455 ui.write(('%s\n') % colorname, label=label)
456 456
457 457 def _debugdisplaystyle(ui):
458 458 ui.write(_('available style:\n'))
459 459 if not ui._styles:
460 460 return
461 461 width = max(len(s) for s in ui._styles)
462 462 for label, effects in sorted(ui._styles.items()):
463 463 ui.write('%s' % label, label=label)
464 464 if effects:
465 465 # 50
466 466 ui.write(': ')
467 467 ui.write(' ' * (max(0, width - len(label))))
468 468 ui.write(', '.join(ui.label(e, e) for e in effects.split()))
469 469 ui.write('\n')
470 470
471 471 @command('debugcreatestreamclonebundle', [], 'FILE')
472 472 def debugcreatestreamclonebundle(ui, repo, fname):
473 473 """create a stream clone bundle file
474 474
475 475 Stream bundles are special bundles that are essentially archives of
476 476 revlog files. They are commonly used for cloning very quickly.
477 477 """
478 478 # TODO we may want to turn this into an abort when this functionality
479 479 # is moved into `hg bundle`.
480 480 if phases.hassecret(repo):
481 481 ui.warn(_('(warning: stream clone bundle will contain secret '
482 482 'revisions)\n'))
483 483
484 484 requirements, gen = streamclone.generatebundlev1(repo)
485 485 changegroup.writechunks(ui, gen, fname)
486 486
487 487 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
488 488
489 489 @command('debugdag',
490 490 [('t', 'tags', None, _('use tags as labels')),
491 491 ('b', 'branches', None, _('annotate with branch names')),
492 492 ('', 'dots', None, _('use dots for runs')),
493 493 ('s', 'spaces', None, _('separate elements by spaces'))],
494 494 _('[OPTION]... [FILE [REV]...]'),
495 495 optionalrepo=True)
496 496 def debugdag(ui, repo, file_=None, *revs, **opts):
497 497 """format the changelog or an index DAG as a concise textual description
498 498
499 499 If you pass a revlog index, the revlog's DAG is emitted. If you list
500 500 revision numbers, they get labeled in the output as rN.
501 501
502 502 Otherwise, the changelog DAG of the current repo is emitted.
503 503 """
504 504 spaces = opts.get(r'spaces')
505 505 dots = opts.get(r'dots')
506 506 if file_:
507 507 rlog = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False),
508 508 file_)
509 509 revs = set((int(r) for r in revs))
510 510 def events():
511 511 for r in rlog:
512 512 yield 'n', (r, list(p for p in rlog.parentrevs(r)
513 513 if p != -1))
514 514 if r in revs:
515 515 yield 'l', (r, "r%i" % r)
516 516 elif repo:
517 517 cl = repo.changelog
518 518 tags = opts.get(r'tags')
519 519 branches = opts.get(r'branches')
520 520 if tags:
521 521 labels = {}
522 522 for l, n in repo.tags().items():
523 523 labels.setdefault(cl.rev(n), []).append(l)
524 524 def events():
525 525 b = "default"
526 526 for r in cl:
527 527 if branches:
528 528 newb = cl.read(cl.node(r))[5]['branch']
529 529 if newb != b:
530 530 yield 'a', newb
531 531 b = newb
532 532 yield 'n', (r, list(p for p in cl.parentrevs(r)
533 533 if p != -1))
534 534 if tags:
535 535 ls = labels.get(r)
536 536 if ls:
537 537 for l in ls:
538 538 yield 'l', (r, l)
539 539 else:
540 540 raise error.Abort(_('need repo for changelog dag'))
541 541
542 542 for line in dagparser.dagtextlines(events(),
543 543 addspaces=spaces,
544 544 wraplabels=True,
545 545 wrapannotations=True,
546 546 wrapnonlinear=dots,
547 547 usedots=dots,
548 548 maxlinewidth=70):
549 549 ui.write(line)
550 550 ui.write("\n")
551 551
552 552 @command('debugdata', cmdutil.debugrevlogopts, _('-c|-m|FILE REV'))
553 553 def debugdata(ui, repo, file_, rev=None, **opts):
554 554 """dump the contents of a data file revision"""
555 555 opts = pycompat.byteskwargs(opts)
556 556 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
557 557 if rev is not None:
558 558 raise error.CommandError('debugdata', _('invalid arguments'))
559 559 file_, rev = None, file_
560 560 elif rev is None:
561 561 raise error.CommandError('debugdata', _('invalid arguments'))
562 562 r = cmdutil.openstorage(repo, 'debugdata', file_, opts)
563 563 try:
564 564 ui.write(r.revision(r.lookup(rev), raw=True))
565 565 except KeyError:
566 566 raise error.Abort(_('invalid revision identifier %s') % rev)
567 567
568 568 @command('debugdate',
569 569 [('e', 'extended', None, _('try extended date formats'))],
570 570 _('[-e] DATE [RANGE]'),
571 571 norepo=True, optionalrepo=True)
572 572 def debugdate(ui, date, range=None, **opts):
573 573 """parse and display a date"""
574 574 if opts[r"extended"]:
575 575 d = dateutil.parsedate(date, util.extendeddateformats)
576 576 else:
577 577 d = dateutil.parsedate(date)
578 578 ui.write(("internal: %d %d\n") % d)
579 579 ui.write(("standard: %s\n") % dateutil.datestr(d))
580 580 if range:
581 581 m = dateutil.matchdate(range)
582 582 ui.write(("match: %s\n") % m(d[0]))
583 583
584 584 @command('debugdeltachain',
585 585 cmdutil.debugrevlogopts + cmdutil.formatteropts,
586 586 _('-c|-m|FILE'),
587 587 optionalrepo=True)
588 588 def debugdeltachain(ui, repo, file_=None, **opts):
589 589 """dump information about delta chains in a revlog
590 590
591 591 Output can be templatized. Available template keywords are:
592 592
593 593 :``rev``: revision number
594 594 :``chainid``: delta chain identifier (numbered by unique base)
595 595 :``chainlen``: delta chain length to this revision
596 596 :``prevrev``: previous revision in delta chain
597 597 :``deltatype``: role of delta / how it was computed
598 598 :``compsize``: compressed size of revision
599 599 :``uncompsize``: uncompressed size of revision
600 600 :``chainsize``: total size of compressed revisions in chain
601 601 :``chainratio``: total chain size divided by uncompressed revision size
602 602 (new delta chains typically start at ratio 2.00)
603 603 :``lindist``: linear distance from base revision in delta chain to end
604 604 of this revision
605 605 :``extradist``: total size of revisions not part of this delta chain from
606 606 base of delta chain to end of this revision; a measurement
607 607 of how much extra data we need to read/seek across to read
608 608 the delta chain for this revision
609 609 :``extraratio``: extradist divided by chainsize; another representation of
610 610 how much unrelated data is needed to load this delta chain
611 611
612 612 If the repository is configured to use the sparse read, additional keywords
613 613 are available:
614 614
615 615 :``readsize``: total size of data read from the disk for a revision
616 616 (sum of the sizes of all the blocks)
617 617 :``largestblock``: size of the largest block of data read from the disk
618 618 :``readdensity``: density of useful bytes in the data read from the disk
619 619 :``srchunks``: in how many data hunks the whole revision would be read
620 620
621 621 The sparse read can be enabled with experimental.sparse-read = True
622 622 """
623 623 opts = pycompat.byteskwargs(opts)
624 624 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
625 625 index = r.index
626 626 start = r.start
627 627 length = r.length
628 628 generaldelta = r.version & revlog.FLAG_GENERALDELTA
629 629 withsparseread = getattr(r, '_withsparseread', False)
630 630
631 631 def revinfo(rev):
632 632 e = index[rev]
633 633 compsize = e[1]
634 634 uncompsize = e[2]
635 635 chainsize = 0
636 636
637 637 if generaldelta:
638 638 if e[3] == e[5]:
639 639 deltatype = 'p1'
640 640 elif e[3] == e[6]:
641 641 deltatype = 'p2'
642 642 elif e[3] == rev - 1:
643 643 deltatype = 'prev'
644 644 elif e[3] == rev:
645 645 deltatype = 'base'
646 646 else:
647 647 deltatype = 'other'
648 648 else:
649 649 if e[3] == rev:
650 650 deltatype = 'base'
651 651 else:
652 652 deltatype = 'prev'
653 653
654 654 chain = r._deltachain(rev)[0]
655 655 for iterrev in chain:
656 656 e = index[iterrev]
657 657 chainsize += e[1]
658 658
659 659 return compsize, uncompsize, deltatype, chain, chainsize
660 660
661 661 fm = ui.formatter('debugdeltachain', opts)
662 662
663 663 fm.plain(' rev chain# chainlen prev delta '
664 664 'size rawsize chainsize ratio lindist extradist '
665 665 'extraratio')
666 666 if withsparseread:
667 667 fm.plain(' readsize largestblk rddensity srchunks')
668 668 fm.plain('\n')
669 669
670 670 chainbases = {}
671 671 for rev in r:
672 672 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
673 673 chainbase = chain[0]
674 674 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
675 675 basestart = start(chainbase)
676 676 revstart = start(rev)
677 677 lineardist = revstart + comp - basestart
678 678 extradist = lineardist - chainsize
679 679 try:
680 680 prevrev = chain[-2]
681 681 except IndexError:
682 682 prevrev = -1
683 683
684 684 if uncomp != 0:
685 685 chainratio = float(chainsize) / float(uncomp)
686 686 else:
687 687 chainratio = chainsize
688 688
689 689 if chainsize != 0:
690 690 extraratio = float(extradist) / float(chainsize)
691 691 else:
692 692 extraratio = extradist
693 693
694 694 fm.startitem()
695 695 fm.write('rev chainid chainlen prevrev deltatype compsize '
696 696 'uncompsize chainsize chainratio lindist extradist '
697 697 'extraratio',
698 698 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f',
699 699 rev, chainid, len(chain), prevrev, deltatype, comp,
700 700 uncomp, chainsize, chainratio, lineardist, extradist,
701 701 extraratio,
702 702 rev=rev, chainid=chainid, chainlen=len(chain),
703 703 prevrev=prevrev, deltatype=deltatype, compsize=comp,
704 704 uncompsize=uncomp, chainsize=chainsize,
705 705 chainratio=chainratio, lindist=lineardist,
706 706 extradist=extradist, extraratio=extraratio)
707 707 if withsparseread:
708 708 readsize = 0
709 709 largestblock = 0
710 710 srchunks = 0
711 711
712 712 for revschunk in deltautil.slicechunk(r, chain):
713 713 srchunks += 1
714 714 blkend = start(revschunk[-1]) + length(revschunk[-1])
715 715 blksize = blkend - start(revschunk[0])
716 716
717 717 readsize += blksize
718 718 if largestblock < blksize:
719 719 largestblock = blksize
720 720
721 721 if readsize:
722 722 readdensity = float(chainsize) / float(readsize)
723 723 else:
724 724 readdensity = 1
725 725
726 726 fm.write('readsize largestblock readdensity srchunks',
727 727 ' %10d %10d %9.5f %8d',
728 728 readsize, largestblock, readdensity, srchunks,
729 729 readsize=readsize, largestblock=largestblock,
730 730 readdensity=readdensity, srchunks=srchunks)
731 731
732 732 fm.plain('\n')
733 733
734 734 fm.end()
735 735
736 736 @command('debugdirstate|debugstate',
737 737 [('', 'nodates', None, _('do not display the saved mtime (DEPRECATED)')),
738 738 ('', 'dates', True, _('display the saved mtime')),
739 739 ('', 'datesort', None, _('sort by saved mtime'))],
740 740 _('[OPTION]...'))
741 741 def debugstate(ui, repo, **opts):
742 742 """show the contents of the current dirstate"""
743 743
744 744 nodates = not opts[r'dates']
745 745 if opts.get(r'nodates') is not None:
746 746 nodates = True
747 747 datesort = opts.get(r'datesort')
748 748
749 749 if datesort:
750 750 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
751 751 else:
752 752 keyfunc = None # sort by filename
753 753 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
754 754 if ent[3] == -1:
755 755 timestr = 'unset '
756 756 elif nodates:
757 757 timestr = 'set '
758 758 else:
759 759 timestr = time.strftime(r"%Y-%m-%d %H:%M:%S ",
760 760 time.localtime(ent[3]))
761 761 timestr = encoding.strtolocal(timestr)
762 762 if ent[1] & 0o20000:
763 763 mode = 'lnk'
764 764 else:
765 765 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
766 766 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
767 767 for f in repo.dirstate.copies():
768 768 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
769 769
770 770 @command('debugdiscovery',
771 771 [('', 'old', None, _('use old-style discovery')),
772 772 ('', 'nonheads', None,
773 773 _('use old-style discovery with non-heads included')),
774 774 ('', 'rev', [], 'restrict discovery to this set of revs'),
775 775 ] + cmdutil.remoteopts,
776 776 _('[--rev REV] [OTHER]'))
777 777 def debugdiscovery(ui, repo, remoteurl="default", **opts):
778 778 """runs the changeset discovery protocol in isolation"""
779 779 opts = pycompat.byteskwargs(opts)
780 780 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl))
781 781 remote = hg.peer(repo, opts, remoteurl)
782 782 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
783 783
784 784 # make sure tests are repeatable
785 785 random.seed(12323)
786 786
787 787 def doit(pushedrevs, remoteheads, remote=remote):
788 788 if opts.get('old'):
789 789 if not util.safehasattr(remote, 'branches'):
790 790 # enable in-client legacy support
791 791 remote = localrepo.locallegacypeer(remote.local())
792 792 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
793 793 force=True)
794 794 common = set(common)
795 795 if not opts.get('nonheads'):
796 796 ui.write(("unpruned common: %s\n") %
797 797 " ".join(sorted(short(n) for n in common)))
798 798
799 799 clnode = repo.changelog.node
800 800 common = repo.revs('heads(::%ln)', common)
801 801 common = {clnode(r) for r in common}
802 802 else:
803 803 nodes = None
804 804 if pushedrevs:
805 805 revs = scmutil.revrange(repo, pushedrevs)
806 806 nodes = [repo[r].node() for r in revs]
807 807 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote,
808 808 ancestorsof=nodes)
809 809 common = set(common)
810 810 rheads = set(hds)
811 811 lheads = set(repo.heads())
812 812 ui.write(("common heads: %s\n") %
813 813 " ".join(sorted(short(n) for n in common)))
814 814 if lheads <= common:
815 815 ui.write(("local is subset\n"))
816 816 elif rheads <= common:
817 817 ui.write(("remote is subset\n"))
818 818
819 819 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches, revs=None)
820 820 localrevs = opts['rev']
821 821 doit(localrevs, remoterevs)
822 822
823 823 _chunksize = 4 << 10
824 824
825 825 @command('debugdownload',
826 826 [
827 827 ('o', 'output', '', _('path')),
828 828 ],
829 829 optionalrepo=True)
830 830 def debugdownload(ui, repo, url, output=None, **opts):
831 831 """download a resource using Mercurial logic and config
832 832 """
833 833 fh = urlmod.open(ui, url, output)
834 834
835 835 dest = ui
836 836 if output:
837 837 dest = open(output, "wb", _chunksize)
838 838 try:
839 839 data = fh.read(_chunksize)
840 840 while data:
841 841 dest.write(data)
842 842 data = fh.read(_chunksize)
843 843 finally:
844 844 if output:
845 845 dest.close()
846 846
847 847 @command('debugextensions', cmdutil.formatteropts, [], optionalrepo=True)
848 848 def debugextensions(ui, repo, **opts):
849 849 '''show information about active extensions'''
850 850 opts = pycompat.byteskwargs(opts)
851 851 exts = extensions.extensions(ui)
852 852 hgver = util.version()
853 853 fm = ui.formatter('debugextensions', opts)
854 854 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
855 855 isinternal = extensions.ismoduleinternal(extmod)
856 856 extsource = pycompat.fsencode(extmod.__file__)
857 857 if isinternal:
858 858 exttestedwith = [] # never expose magic string to users
859 859 else:
860 860 exttestedwith = getattr(extmod, 'testedwith', '').split()
861 861 extbuglink = getattr(extmod, 'buglink', None)
862 862
863 863 fm.startitem()
864 864
865 865 if ui.quiet or ui.verbose:
866 866 fm.write('name', '%s\n', extname)
867 867 else:
868 868 fm.write('name', '%s', extname)
869 869 if isinternal or hgver in exttestedwith:
870 870 fm.plain('\n')
871 871 elif not exttestedwith:
872 872 fm.plain(_(' (untested!)\n'))
873 873 else:
874 874 lasttestedversion = exttestedwith[-1]
875 875 fm.plain(' (%s!)\n' % lasttestedversion)
876 876
877 877 fm.condwrite(ui.verbose and extsource, 'source',
878 878 _(' location: %s\n'), extsource or "")
879 879
880 880 if ui.verbose:
881 881 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
882 882 fm.data(bundled=isinternal)
883 883
884 884 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
885 885 _(' tested with: %s\n'),
886 886 fm.formatlist(exttestedwith, name='ver'))
887 887
888 888 fm.condwrite(ui.verbose and extbuglink, 'buglink',
889 889 _(' bug reporting: %s\n'), extbuglink or "")
890 890
891 891 fm.end()
892 892
893 893 @command('debugfileset',
894 894 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV')),
895 895 ('', 'all-files', False,
896 896 _('test files from all revisions and working directory')),
897 897 ('s', 'show-matcher', None,
898 898 _('print internal representation of matcher')),
899 899 ('p', 'show-stage', [],
900 900 _('print parsed tree at the given stage'), _('NAME'))],
901 901 _('[-r REV] [--all-files] [OPTION]... FILESPEC'))
902 902 def debugfileset(ui, repo, expr, **opts):
903 903 '''parse and apply a fileset specification'''
904 904 from . import fileset
905 905 fileset.symbols # force import of fileset so we have predicates to optimize
906 906 opts = pycompat.byteskwargs(opts)
907 907 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
908 908
909 909 stages = [
910 910 ('parsed', pycompat.identity),
911 911 ('analyzed', filesetlang.analyze),
912 912 ('optimized', filesetlang.optimize),
913 913 ]
914 914 stagenames = set(n for n, f in stages)
915 915
916 916 showalways = set()
917 917 if ui.verbose and not opts['show_stage']:
918 918 # show parsed tree by --verbose (deprecated)
919 919 showalways.add('parsed')
920 920 if opts['show_stage'] == ['all']:
921 921 showalways.update(stagenames)
922 922 else:
923 923 for n in opts['show_stage']:
924 924 if n not in stagenames:
925 925 raise error.Abort(_('invalid stage name: %s') % n)
926 926 showalways.update(opts['show_stage'])
927 927
928 928 tree = filesetlang.parse(expr)
929 929 for n, f in stages:
930 930 tree = f(tree)
931 931 if n in showalways:
932 932 if opts['show_stage'] or n != 'parsed':
933 933 ui.write(("* %s:\n") % n)
934 934 ui.write(filesetlang.prettyformat(tree), "\n")
935 935
936 936 files = set()
937 937 if opts['all_files']:
938 938 for r in repo:
939 939 c = repo[r]
940 940 files.update(c.files())
941 941 files.update(c.substate)
942 942 if opts['all_files'] or ctx.rev() is None:
943 943 wctx = repo[None]
944 944 files.update(repo.dirstate.walk(scmutil.matchall(repo),
945 945 subrepos=list(wctx.substate),
946 946 unknown=True, ignored=True))
947 947 files.update(wctx.substate)
948 948 else:
949 949 files.update(ctx.files())
950 950 files.update(ctx.substate)
951 951
952 952 m = ctx.matchfileset(expr)
953 953 if opts['show_matcher'] or (opts['show_matcher'] is None and ui.verbose):
954 954 ui.write(('* matcher:\n'), stringutil.prettyrepr(m), '\n')
955 955 for f in sorted(files):
956 956 if not m(f):
957 957 continue
958 958 ui.write("%s\n" % f)
959 959
960 960 @command('debugformat',
961 961 [] + cmdutil.formatteropts)
962 962 def debugformat(ui, repo, **opts):
963 963 """display format information about the current repository
964 964
965 965 Use --verbose to get extra information about current config value and
966 966 Mercurial default."""
967 967 opts = pycompat.byteskwargs(opts)
968 968 maxvariantlength = max(len(fv.name) for fv in upgrade.allformatvariant)
969 969 maxvariantlength = max(len('format-variant'), maxvariantlength)
970 970
971 971 def makeformatname(name):
972 972 return '%s:' + (' ' * (maxvariantlength - len(name)))
973 973
974 974 fm = ui.formatter('debugformat', opts)
975 975 if fm.isplain():
976 976 def formatvalue(value):
977 977 if util.safehasattr(value, 'startswith'):
978 978 return value
979 979 if value:
980 980 return 'yes'
981 981 else:
982 982 return 'no'
983 983 else:
984 984 formatvalue = pycompat.identity
985 985
986 986 fm.plain('format-variant')
987 987 fm.plain(' ' * (maxvariantlength - len('format-variant')))
988 988 fm.plain(' repo')
989 989 if ui.verbose:
990 990 fm.plain(' config default')
991 991 fm.plain('\n')
992 992 for fv in upgrade.allformatvariant:
993 993 fm.startitem()
994 994 repovalue = fv.fromrepo(repo)
995 995 configvalue = fv.fromconfig(repo)
996 996
997 997 if repovalue != configvalue:
998 998 namelabel = 'formatvariant.name.mismatchconfig'
999 999 repolabel = 'formatvariant.repo.mismatchconfig'
1000 1000 elif repovalue != fv.default:
1001 1001 namelabel = 'formatvariant.name.mismatchdefault'
1002 1002 repolabel = 'formatvariant.repo.mismatchdefault'
1003 1003 else:
1004 1004 namelabel = 'formatvariant.name.uptodate'
1005 1005 repolabel = 'formatvariant.repo.uptodate'
1006 1006
1007 1007 fm.write('name', makeformatname(fv.name), fv.name,
1008 1008 label=namelabel)
1009 1009 fm.write('repo', ' %3s', formatvalue(repovalue),
1010 1010 label=repolabel)
1011 1011 if fv.default != configvalue:
1012 1012 configlabel = 'formatvariant.config.special'
1013 1013 else:
1014 1014 configlabel = 'formatvariant.config.default'
1015 1015 fm.condwrite(ui.verbose, 'config', ' %6s', formatvalue(configvalue),
1016 1016 label=configlabel)
1017 1017 fm.condwrite(ui.verbose, 'default', ' %7s', formatvalue(fv.default),
1018 1018 label='formatvariant.default')
1019 1019 fm.plain('\n')
1020 1020 fm.end()
1021 1021
1022 1022 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
1023 1023 def debugfsinfo(ui, path="."):
1024 1024 """show information detected about current filesystem"""
1025 1025 ui.write(('path: %s\n') % path)
1026 1026 ui.write(('mounted on: %s\n') % (util.getfsmountpoint(path) or '(unknown)'))
1027 1027 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1028 1028 ui.write(('fstype: %s\n') % (util.getfstype(path) or '(unknown)'))
1029 1029 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1030 1030 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
1031 1031 casesensitive = '(unknown)'
1032 1032 try:
1033 1033 with pycompat.namedtempfile(prefix='.debugfsinfo', dir=path) as f:
1034 1034 casesensitive = util.fscasesensitive(f.name) and 'yes' or 'no'
1035 1035 except OSError:
1036 1036 pass
1037 1037 ui.write(('case-sensitive: %s\n') % casesensitive)
1038 1038
1039 1039 @command('debuggetbundle',
1040 1040 [('H', 'head', [], _('id of head node'), _('ID')),
1041 1041 ('C', 'common', [], _('id of common node'), _('ID')),
1042 1042 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1043 1043 _('REPO FILE [-H|-C ID]...'),
1044 1044 norepo=True)
1045 1045 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1046 1046 """retrieves a bundle from a repo
1047 1047
1048 1048 Every ID must be a full-length hex node id string. Saves the bundle to the
1049 1049 given file.
1050 1050 """
1051 1051 opts = pycompat.byteskwargs(opts)
1052 1052 repo = hg.peer(ui, opts, repopath)
1053 1053 if not repo.capable('getbundle'):
1054 1054 raise error.Abort("getbundle() not supported by target repository")
1055 1055 args = {}
1056 1056 if common:
1057 1057 args[r'common'] = [bin(s) for s in common]
1058 1058 if head:
1059 1059 args[r'heads'] = [bin(s) for s in head]
1060 1060 # TODO: get desired bundlecaps from command line.
1061 1061 args[r'bundlecaps'] = None
1062 1062 bundle = repo.getbundle('debug', **args)
1063 1063
1064 1064 bundletype = opts.get('type', 'bzip2').lower()
1065 1065 btypes = {'none': 'HG10UN',
1066 1066 'bzip2': 'HG10BZ',
1067 1067 'gzip': 'HG10GZ',
1068 1068 'bundle2': 'HG20'}
1069 1069 bundletype = btypes.get(bundletype)
1070 1070 if bundletype not in bundle2.bundletypes:
1071 1071 raise error.Abort(_('unknown bundle type specified with --type'))
1072 1072 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
1073 1073
1074 1074 @command('debugignore', [], '[FILE]')
1075 1075 def debugignore(ui, repo, *files, **opts):
1076 1076 """display the combined ignore pattern and information about ignored files
1077 1077
1078 1078 With no argument display the combined ignore pattern.
1079 1079
1080 1080 Given space separated file names, shows if the given file is ignored and
1081 1081 if so, show the ignore rule (file and line number) that matched it.
1082 1082 """
1083 1083 ignore = repo.dirstate._ignore
1084 1084 if not files:
1085 1085 # Show all the patterns
1086 1086 ui.write("%s\n" % pycompat.byterepr(ignore))
1087 1087 else:
1088 1088 m = scmutil.match(repo[None], pats=files)
1089 1089 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
1090 1090 for f in m.files():
1091 1091 nf = util.normpath(f)
1092 1092 ignored = None
1093 1093 ignoredata = None
1094 1094 if nf != '.':
1095 1095 if ignore(nf):
1096 1096 ignored = nf
1097 1097 ignoredata = repo.dirstate._ignorefileandline(nf)
1098 1098 else:
1099 1099 for p in util.finddirs(nf):
1100 1100 if ignore(p):
1101 1101 ignored = p
1102 1102 ignoredata = repo.dirstate._ignorefileandline(p)
1103 1103 break
1104 1104 if ignored:
1105 1105 if ignored == nf:
1106 1106 ui.write(_("%s is ignored\n") % uipathfn(f))
1107 1107 else:
1108 1108 ui.write(_("%s is ignored because of "
1109 1109 "containing folder %s\n")
1110 1110 % (uipathfn(f), ignored))
1111 1111 ignorefile, lineno, line = ignoredata
1112 1112 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
1113 1113 % (ignorefile, lineno, line))
1114 1114 else:
1115 1115 ui.write(_("%s is not ignored\n") % uipathfn(f))
1116 1116
1117 1117 @command('debugindex', cmdutil.debugrevlogopts + cmdutil.formatteropts,
1118 1118 _('-c|-m|FILE'))
1119 1119 def debugindex(ui, repo, file_=None, **opts):
1120 1120 """dump index data for a storage primitive"""
1121 1121 opts = pycompat.byteskwargs(opts)
1122 1122 store = cmdutil.openstorage(repo, 'debugindex', file_, opts)
1123 1123
1124 1124 if ui.debugflag:
1125 1125 shortfn = hex
1126 1126 else:
1127 1127 shortfn = short
1128 1128
1129 1129 idlen = 12
1130 1130 for i in store:
1131 1131 idlen = len(shortfn(store.node(i)))
1132 1132 break
1133 1133
1134 1134 fm = ui.formatter('debugindex', opts)
1135 1135 fm.plain(b' rev linkrev %s %s p2\n' % (
1136 1136 b'nodeid'.ljust(idlen),
1137 1137 b'p1'.ljust(idlen)))
1138 1138
1139 1139 for rev in store:
1140 1140 node = store.node(rev)
1141 1141 parents = store.parents(node)
1142 1142
1143 1143 fm.startitem()
1144 1144 fm.write(b'rev', b'%6d ', rev)
1145 1145 fm.write(b'linkrev', '%7d ', store.linkrev(rev))
1146 1146 fm.write(b'node', '%s ', shortfn(node))
1147 1147 fm.write(b'p1', '%s ', shortfn(parents[0]))
1148 1148 fm.write(b'p2', '%s', shortfn(parents[1]))
1149 1149 fm.plain(b'\n')
1150 1150
1151 1151 fm.end()
1152 1152
1153 1153 @command('debugindexdot', cmdutil.debugrevlogopts,
1154 1154 _('-c|-m|FILE'), optionalrepo=True)
1155 1155 def debugindexdot(ui, repo, file_=None, **opts):
1156 1156 """dump an index DAG as a graphviz dot file"""
1157 1157 opts = pycompat.byteskwargs(opts)
1158 1158 r = cmdutil.openstorage(repo, 'debugindexdot', file_, opts)
1159 1159 ui.write(("digraph G {\n"))
1160 1160 for i in r:
1161 1161 node = r.node(i)
1162 1162 pp = r.parents(node)
1163 1163 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1164 1164 if pp[1] != nullid:
1165 1165 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1166 1166 ui.write("}\n")
1167 1167
1168 1168 @command('debugindexstats', [])
1169 1169 def debugindexstats(ui, repo):
1170 1170 """show stats related to the changelog index"""
1171 1171 repo.changelog.shortest(nullid, 1)
1172 1172 index = repo.changelog.index
1173 1173 if not util.safehasattr(index, 'stats'):
1174 1174 raise error.Abort(_('debugindexstats only works with native code'))
1175 1175 for k, v in sorted(index.stats().items()):
1176 1176 ui.write('%s: %d\n' % (k, v))
1177 1177
1178 1178 @command('debuginstall', [] + cmdutil.formatteropts, '', norepo=True)
1179 1179 def debuginstall(ui, **opts):
1180 1180 '''test Mercurial installation
1181 1181
1182 1182 Returns 0 on success.
1183 1183 '''
1184 1184 opts = pycompat.byteskwargs(opts)
1185 1185
1186 1186 problems = 0
1187 1187
1188 1188 fm = ui.formatter('debuginstall', opts)
1189 1189 fm.startitem()
1190 1190
1191 1191 # encoding
1192 1192 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
1193 1193 err = None
1194 1194 try:
1195 1195 codecs.lookup(pycompat.sysstr(encoding.encoding))
1196 1196 except LookupError as inst:
1197 1197 err = stringutil.forcebytestr(inst)
1198 1198 problems += 1
1199 1199 fm.condwrite(err, 'encodingerror', _(" %s\n"
1200 1200 " (check that your locale is properly set)\n"), err)
1201 1201
1202 1202 # Python
1203 1203 fm.write('pythonexe', _("checking Python executable (%s)\n"),
1204 1204 pycompat.sysexecutable)
1205 1205 fm.write('pythonver', _("checking Python version (%s)\n"),
1206 1206 ("%d.%d.%d" % sys.version_info[:3]))
1207 1207 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
1208 1208 os.path.dirname(pycompat.fsencode(os.__file__)))
1209 1209
1210 1210 security = set(sslutil.supportedprotocols)
1211 1211 if sslutil.hassni:
1212 1212 security.add('sni')
1213 1213
1214 1214 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
1215 1215 fm.formatlist(sorted(security), name='protocol',
1216 1216 fmt='%s', sep=','))
1217 1217
1218 1218 # These are warnings, not errors. So don't increment problem count. This
1219 1219 # may change in the future.
1220 1220 if 'tls1.2' not in security:
1221 1221 fm.plain(_(' TLS 1.2 not supported by Python install; '
1222 1222 'network connections lack modern security\n'))
1223 1223 if 'sni' not in security:
1224 1224 fm.plain(_(' SNI not supported by Python install; may have '
1225 1225 'connectivity issues with some servers\n'))
1226 1226
1227 1227 # TODO print CA cert info
1228 1228
1229 1229 # hg version
1230 1230 hgver = util.version()
1231 1231 fm.write('hgver', _("checking Mercurial version (%s)\n"),
1232 1232 hgver.split('+')[0])
1233 1233 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
1234 1234 '+'.join(hgver.split('+')[1:]))
1235 1235
1236 1236 # compiled modules
1237 1237 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
1238 1238 policy.policy)
1239 1239 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
1240 1240 os.path.dirname(pycompat.fsencode(__file__)))
1241 1241
1242 1242 if policy.policy in ('c', 'allow'):
1243 1243 err = None
1244 1244 try:
1245 1245 from .cext import (
1246 1246 base85,
1247 1247 bdiff,
1248 1248 mpatch,
1249 1249 osutil,
1250 1250 )
1251 1251 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
1252 1252 except Exception as inst:
1253 1253 err = stringutil.forcebytestr(inst)
1254 1254 problems += 1
1255 1255 fm.condwrite(err, 'extensionserror', " %s\n", err)
1256 1256
1257 1257 compengines = util.compengines._engines.values()
1258 1258 fm.write('compengines', _('checking registered compression engines (%s)\n'),
1259 1259 fm.formatlist(sorted(e.name() for e in compengines),
1260 1260 name='compengine', fmt='%s', sep=', '))
1261 1261 fm.write('compenginesavail', _('checking available compression engines '
1262 1262 '(%s)\n'),
1263 1263 fm.formatlist(sorted(e.name() for e in compengines
1264 1264 if e.available()),
1265 1265 name='compengine', fmt='%s', sep=', '))
1266 1266 wirecompengines = util.compengines.supportedwireengines(util.SERVERROLE)
1267 1267 fm.write('compenginesserver', _('checking available compression engines '
1268 1268 'for wire protocol (%s)\n'),
1269 1269 fm.formatlist([e.name() for e in wirecompengines
1270 1270 if e.wireprotosupport()],
1271 1271 name='compengine', fmt='%s', sep=', '))
1272 1272 re2 = 'missing'
1273 1273 if util._re2:
1274 1274 re2 = 'available'
1275 1275 fm.plain(_('checking "re2" regexp engine (%s)\n') % re2)
1276 1276 fm.data(re2=bool(util._re2))
1277 1277
1278 1278 # templates
1279 1279 p = templater.templatepaths()
1280 1280 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
1281 1281 fm.condwrite(not p, '', _(" no template directories found\n"))
1282 1282 if p:
1283 1283 m = templater.templatepath("map-cmdline.default")
1284 1284 if m:
1285 1285 # template found, check if it is working
1286 1286 err = None
1287 1287 try:
1288 1288 templater.templater.frommapfile(m)
1289 1289 except Exception as inst:
1290 1290 err = stringutil.forcebytestr(inst)
1291 1291 p = None
1292 1292 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
1293 1293 else:
1294 1294 p = None
1295 1295 fm.condwrite(p, 'defaulttemplate',
1296 1296 _("checking default template (%s)\n"), m)
1297 1297 fm.condwrite(not m, 'defaulttemplatenotfound',
1298 1298 _(" template '%s' not found\n"), "default")
1299 1299 if not p:
1300 1300 problems += 1
1301 1301 fm.condwrite(not p, '',
1302 1302 _(" (templates seem to have been installed incorrectly)\n"))
1303 1303
1304 1304 # editor
1305 1305 editor = ui.geteditor()
1306 1306 editor = util.expandpath(editor)
1307 1307 editorbin = procutil.shellsplit(editor)[0]
1308 1308 fm.write('editor', _("checking commit editor... (%s)\n"), editorbin)
1309 1309 cmdpath = procutil.findexe(editorbin)
1310 1310 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
1311 1311 _(" No commit editor set and can't find %s in PATH\n"
1312 1312 " (specify a commit editor in your configuration"
1313 1313 " file)\n"), not cmdpath and editor == 'vi' and editorbin)
1314 1314 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
1315 1315 _(" Can't find editor '%s' in PATH\n"
1316 1316 " (specify a commit editor in your configuration"
1317 1317 " file)\n"), not cmdpath and editorbin)
1318 1318 if not cmdpath and editor != 'vi':
1319 1319 problems += 1
1320 1320
1321 1321 # check username
1322 1322 username = None
1323 1323 err = None
1324 1324 try:
1325 1325 username = ui.username()
1326 1326 except error.Abort as e:
1327 1327 err = stringutil.forcebytestr(e)
1328 1328 problems += 1
1329 1329
1330 1330 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
1331 1331 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
1332 1332 " (specify a username in your configuration file)\n"), err)
1333 1333
1334 1334 fm.condwrite(not problems, '',
1335 1335 _("no problems detected\n"))
1336 1336 if not problems:
1337 1337 fm.data(problems=problems)
1338 1338 fm.condwrite(problems, 'problems',
1339 1339 _("%d problems detected,"
1340 1340 " please check your install!\n"), problems)
1341 1341 fm.end()
1342 1342
1343 1343 return problems
1344 1344
1345 1345 @command('debugknown', [], _('REPO ID...'), norepo=True)
1346 1346 def debugknown(ui, repopath, *ids, **opts):
1347 1347 """test whether node ids are known to a repo
1348 1348
1349 1349 Every ID must be a full-length hex node id string. Returns a list of 0s
1350 1350 and 1s indicating unknown/known.
1351 1351 """
1352 1352 opts = pycompat.byteskwargs(opts)
1353 1353 repo = hg.peer(ui, opts, repopath)
1354 1354 if not repo.capable('known'):
1355 1355 raise error.Abort("known() not supported by target repository")
1356 1356 flags = repo.known([bin(s) for s in ids])
1357 1357 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1358 1358
1359 1359 @command('debuglabelcomplete', [], _('LABEL...'))
1360 1360 def debuglabelcomplete(ui, repo, *args):
1361 1361 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
1362 1362 debugnamecomplete(ui, repo, *args)
1363 1363
1364 1364 @command('debuglocks',
1365 1365 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
1366 1366 ('W', 'force-wlock', None,
1367 1367 _('free the working state lock (DANGEROUS)')),
1368 1368 ('s', 'set-lock', None, _('set the store lock until stopped')),
1369 1369 ('S', 'set-wlock', None,
1370 1370 _('set the working state lock until stopped'))],
1371 1371 _('[OPTION]...'))
1372 1372 def debuglocks(ui, repo, **opts):
1373 1373 """show or modify state of locks
1374 1374
1375 1375 By default, this command will show which locks are held. This
1376 1376 includes the user and process holding the lock, the amount of time
1377 1377 the lock has been held, and the machine name where the process is
1378 1378 running if it's not local.
1379 1379
1380 1380 Locks protect the integrity of Mercurial's data, so should be
1381 1381 treated with care. System crashes or other interruptions may cause
1382 1382 locks to not be properly released, though Mercurial will usually
1383 1383 detect and remove such stale locks automatically.
1384 1384
1385 1385 However, detecting stale locks may not always be possible (for
1386 1386 instance, on a shared filesystem). Removing locks may also be
1387 1387 blocked by filesystem permissions.
1388 1388
1389 1389 Setting a lock will prevent other commands from changing the data.
1390 1390 The command will wait until an interruption (SIGINT, SIGTERM, ...) occurs.
1391 1391 The set locks are removed when the command exits.
1392 1392
1393 1393 Returns 0 if no locks are held.
1394 1394
1395 1395 """
1396 1396
1397 1397 if opts.get(r'force_lock'):
1398 1398 repo.svfs.unlink('lock')
1399 1399 if opts.get(r'force_wlock'):
1400 1400 repo.vfs.unlink('wlock')
1401 1401 if opts.get(r'force_lock') or opts.get(r'force_wlock'):
1402 1402 return 0
1403 1403
1404 1404 locks = []
1405 1405 try:
1406 1406 if opts.get(r'set_wlock'):
1407 1407 try:
1408 1408 locks.append(repo.wlock(False))
1409 1409 except error.LockHeld:
1410 1410 raise error.Abort(_('wlock is already held'))
1411 1411 if opts.get(r'set_lock'):
1412 1412 try:
1413 1413 locks.append(repo.lock(False))
1414 1414 except error.LockHeld:
1415 1415 raise error.Abort(_('lock is already held'))
1416 1416 if len(locks):
1417 1417 ui.promptchoice(_("ready to release the lock (y)? $$ &Yes"))
1418 1418 return 0
1419 1419 finally:
1420 1420 release(*locks)
1421 1421
1422 1422 now = time.time()
1423 1423 held = 0
1424 1424
1425 1425 def report(vfs, name, method):
1426 1426 # this causes stale locks to get reaped for more accurate reporting
1427 1427 try:
1428 1428 l = method(False)
1429 1429 except error.LockHeld:
1430 1430 l = None
1431 1431
1432 1432 if l:
1433 1433 l.release()
1434 1434 else:
1435 1435 try:
1436 1436 st = vfs.lstat(name)
1437 1437 age = now - st[stat.ST_MTIME]
1438 1438 user = util.username(st.st_uid)
1439 1439 locker = vfs.readlock(name)
1440 1440 if ":" in locker:
1441 1441 host, pid = locker.split(':')
1442 1442 if host == socket.gethostname():
1443 1443 locker = 'user %s, process %s' % (user or b'None', pid)
1444 1444 else:
1445 1445 locker = 'user %s, process %s, host %s' \
1446 1446 % (user or b'None', pid, host)
1447 1447 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
1448 1448 return 1
1449 1449 except OSError as e:
1450 1450 if e.errno != errno.ENOENT:
1451 1451 raise
1452 1452
1453 1453 ui.write(("%-6s free\n") % (name + ":"))
1454 1454 return 0
1455 1455
1456 1456 held += report(repo.svfs, "lock", repo.lock)
1457 1457 held += report(repo.vfs, "wlock", repo.wlock)
1458 1458
1459 1459 return held
1460 1460
1461 1461 @command('debugmanifestfulltextcache', [
1462 1462 ('', 'clear', False, _('clear the cache')),
1463 1463 ('a', 'add', '', _('add the given manifest node to the cache'),
1464 1464 _('NODE'))
1465 1465 ], '')
1466 1466 def debugmanifestfulltextcache(ui, repo, add=None, **opts):
1467 1467 """show, clear or amend the contents of the manifest fulltext cache"""
1468 1468 with repo.lock():
1469 1469 r = repo.manifestlog.getstorage(b'')
1470 1470 try:
1471 1471 cache = r._fulltextcache
1472 1472 except AttributeError:
1473 1473 ui.warn(_(
1474 1474 "Current revlog implementation doesn't appear to have a "
1475 1475 'manifest fulltext cache\n'))
1476 1476 return
1477 1477
1478 1478 if opts.get(r'clear'):
1479 1479 cache.clear()
1480 1480
1481 1481 if add:
1482 1482 try:
1483 1483 manifest = repo.manifestlog[r.lookup(add)]
1484 1484 except error.LookupError as e:
1485 1485 raise error.Abort(e, hint="Check your manifest node id")
1486 1486 manifest.read() # stores revisision in cache too
1487 1487
1488 1488 if not len(cache):
1489 1489 ui.write(_('Cache empty'))
1490 1490 else:
1491 1491 ui.write(
1492 1492 _('Cache contains %d manifest entries, in order of most to '
1493 1493 'least recent:\n') % (len(cache),))
1494 1494 totalsize = 0
1495 1495 for nodeid in cache:
1496 1496 # Use cache.get to not update the LRU order
1497 1497 data = cache.get(nodeid)
1498 1498 size = len(data)
1499 1499 totalsize += size + 24 # 20 bytes nodeid, 4 bytes size
1500 1500 ui.write(_('id: %s, size %s\n') % (
1501 1501 hex(nodeid), util.bytecount(size)))
1502 1502 ondisk = cache._opener.stat('manifestfulltextcache').st_size
1503 1503 ui.write(
1504 1504 _('Total cache data size %s, on-disk %s\n') % (
1505 1505 util.bytecount(totalsize), util.bytecount(ondisk))
1506 1506 )
1507 1507
1508 1508 @command('debugmergestate', [], '')
1509 1509 def debugmergestate(ui, repo, *args):
1510 1510 """print merge state
1511 1511
1512 1512 Use --verbose to print out information about whether v1 or v2 merge state
1513 1513 was chosen."""
1514 1514 def _hashornull(h):
1515 1515 if h == nullhex:
1516 1516 return 'null'
1517 1517 else:
1518 1518 return h
1519 1519
1520 1520 def printrecords(version):
1521 1521 ui.write(('* version %d records\n') % version)
1522 1522 if version == 1:
1523 1523 records = v1records
1524 1524 else:
1525 1525 records = v2records
1526 1526
1527 1527 for rtype, record in records:
1528 1528 # pretty print some record types
1529 1529 if rtype == 'L':
1530 1530 ui.write(('local: %s\n') % record)
1531 1531 elif rtype == 'O':
1532 1532 ui.write(('other: %s\n') % record)
1533 1533 elif rtype == 'm':
1534 1534 driver, mdstate = record.split('\0', 1)
1535 1535 ui.write(('merge driver: %s (state "%s")\n')
1536 1536 % (driver, mdstate))
1537 1537 elif rtype in 'FDC':
1538 1538 r = record.split('\0')
1539 1539 f, state, hash, lfile, afile, anode, ofile = r[0:7]
1540 1540 if version == 1:
1541 1541 onode = 'not stored in v1 format'
1542 1542 flags = r[7]
1543 1543 else:
1544 1544 onode, flags = r[7:9]
1545 1545 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
1546 1546 % (f, rtype, state, _hashornull(hash)))
1547 1547 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
1548 1548 ui.write((' ancestor path: %s (node %s)\n')
1549 1549 % (afile, _hashornull(anode)))
1550 1550 ui.write((' other path: %s (node %s)\n')
1551 1551 % (ofile, _hashornull(onode)))
1552 1552 elif rtype == 'f':
1553 1553 filename, rawextras = record.split('\0', 1)
1554 1554 extras = rawextras.split('\0')
1555 1555 i = 0
1556 1556 extrastrings = []
1557 1557 while i < len(extras):
1558 1558 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
1559 1559 i += 2
1560 1560
1561 1561 ui.write(('file extras: %s (%s)\n')
1562 1562 % (filename, ', '.join(extrastrings)))
1563 1563 elif rtype == 'l':
1564 1564 labels = record.split('\0', 2)
1565 1565 labels = [l for l in labels if len(l) > 0]
1566 1566 ui.write(('labels:\n'))
1567 1567 ui.write((' local: %s\n' % labels[0]))
1568 1568 ui.write((' other: %s\n' % labels[1]))
1569 1569 if len(labels) > 2:
1570 1570 ui.write((' base: %s\n' % labels[2]))
1571 1571 else:
1572 1572 ui.write(('unrecognized entry: %s\t%s\n')
1573 1573 % (rtype, record.replace('\0', '\t')))
1574 1574
1575 1575 # Avoid mergestate.read() since it may raise an exception for unsupported
1576 1576 # merge state records. We shouldn't be doing this, but this is OK since this
1577 1577 # command is pretty low-level.
1578 1578 ms = mergemod.mergestate(repo)
1579 1579
1580 1580 # sort so that reasonable information is on top
1581 1581 v1records = ms._readrecordsv1()
1582 1582 v2records = ms._readrecordsv2()
1583 1583 order = 'LOml'
1584 1584 def key(r):
1585 1585 idx = order.find(r[0])
1586 1586 if idx == -1:
1587 1587 return (1, r[1])
1588 1588 else:
1589 1589 return (0, idx)
1590 1590 v1records.sort(key=key)
1591 1591 v2records.sort(key=key)
1592 1592
1593 1593 if not v1records and not v2records:
1594 1594 ui.write(('no merge state found\n'))
1595 1595 elif not v2records:
1596 1596 ui.note(('no version 2 merge state\n'))
1597 1597 printrecords(1)
1598 1598 elif ms._v1v2match(v1records, v2records):
1599 1599 ui.note(('v1 and v2 states match: using v2\n'))
1600 1600 printrecords(2)
1601 1601 else:
1602 1602 ui.note(('v1 and v2 states mismatch: using v1\n'))
1603 1603 printrecords(1)
1604 1604 if ui.verbose:
1605 1605 printrecords(2)
1606 1606
1607 1607 @command('debugnamecomplete', [], _('NAME...'))
1608 1608 def debugnamecomplete(ui, repo, *args):
1609 1609 '''complete "names" - tags, open branch names, bookmark names'''
1610 1610
1611 1611 names = set()
1612 1612 # since we previously only listed open branches, we will handle that
1613 1613 # specially (after this for loop)
1614 1614 for name, ns in repo.names.iteritems():
1615 1615 if name != 'branches':
1616 1616 names.update(ns.listnames(repo))
1617 1617 names.update(tag for (tag, heads, tip, closed)
1618 1618 in repo.branchmap().iterbranches() if not closed)
1619 1619 completions = set()
1620 1620 if not args:
1621 1621 args = ['']
1622 1622 for a in args:
1623 1623 completions.update(n for n in names if n.startswith(a))
1624 1624 ui.write('\n'.join(sorted(completions)))
1625 1625 ui.write('\n')
1626 1626
1627 1627 @command('debugobsolete',
1628 1628 [('', 'flags', 0, _('markers flag')),
1629 1629 ('', 'record-parents', False,
1630 1630 _('record parent information for the precursor')),
1631 1631 ('r', 'rev', [], _('display markers relevant to REV')),
1632 1632 ('', 'exclusive', False, _('restrict display to markers only '
1633 1633 'relevant to REV')),
1634 1634 ('', 'index', False, _('display index of the marker')),
1635 1635 ('', 'delete', [], _('delete markers specified by indices')),
1636 1636 ] + cmdutil.commitopts2 + cmdutil.formatteropts,
1637 1637 _('[OBSOLETED [REPLACEMENT ...]]'))
1638 1638 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
1639 1639 """create arbitrary obsolete marker
1640 1640
1641 1641 With no arguments, displays the list of obsolescence markers."""
1642 1642
1643 1643 opts = pycompat.byteskwargs(opts)
1644 1644
1645 1645 def parsenodeid(s):
1646 1646 try:
1647 1647 # We do not use revsingle/revrange functions here to accept
1648 1648 # arbitrary node identifiers, possibly not present in the
1649 1649 # local repository.
1650 1650 n = bin(s)
1651 1651 if len(n) != len(nullid):
1652 1652 raise TypeError()
1653 1653 return n
1654 1654 except TypeError:
1655 1655 raise error.Abort('changeset references must be full hexadecimal '
1656 1656 'node identifiers')
1657 1657
1658 1658 if opts.get('delete'):
1659 1659 indices = []
1660 1660 for v in opts.get('delete'):
1661 1661 try:
1662 1662 indices.append(int(v))
1663 1663 except ValueError:
1664 1664 raise error.Abort(_('invalid index value: %r') % v,
1665 1665 hint=_('use integers for indices'))
1666 1666
1667 1667 if repo.currenttransaction():
1668 1668 raise error.Abort(_('cannot delete obsmarkers in the middle '
1669 1669 'of transaction.'))
1670 1670
1671 1671 with repo.lock():
1672 1672 n = repair.deleteobsmarkers(repo.obsstore, indices)
1673 1673 ui.write(_('deleted %i obsolescence markers\n') % n)
1674 1674
1675 1675 return
1676 1676
1677 1677 if precursor is not None:
1678 1678 if opts['rev']:
1679 1679 raise error.Abort('cannot select revision when creating marker')
1680 1680 metadata = {}
1681 1681 metadata['user'] = encoding.fromlocal(opts['user'] or ui.username())
1682 1682 succs = tuple(parsenodeid(succ) for succ in successors)
1683 1683 l = repo.lock()
1684 1684 try:
1685 1685 tr = repo.transaction('debugobsolete')
1686 1686 try:
1687 1687 date = opts.get('date')
1688 1688 if date:
1689 1689 date = dateutil.parsedate(date)
1690 1690 else:
1691 1691 date = None
1692 1692 prec = parsenodeid(precursor)
1693 1693 parents = None
1694 1694 if opts['record_parents']:
1695 1695 if prec not in repo.unfiltered():
1696 1696 raise error.Abort('cannot used --record-parents on '
1697 1697 'unknown changesets')
1698 1698 parents = repo.unfiltered()[prec].parents()
1699 1699 parents = tuple(p.node() for p in parents)
1700 1700 repo.obsstore.create(tr, prec, succs, opts['flags'],
1701 1701 parents=parents, date=date,
1702 1702 metadata=metadata, ui=ui)
1703 1703 tr.close()
1704 1704 except ValueError as exc:
1705 1705 raise error.Abort(_('bad obsmarker input: %s') %
1706 1706 pycompat.bytestr(exc))
1707 1707 finally:
1708 1708 tr.release()
1709 1709 finally:
1710 1710 l.release()
1711 1711 else:
1712 1712 if opts['rev']:
1713 1713 revs = scmutil.revrange(repo, opts['rev'])
1714 1714 nodes = [repo[r].node() for r in revs]
1715 1715 markers = list(obsutil.getmarkers(repo, nodes=nodes,
1716 1716 exclusive=opts['exclusive']))
1717 1717 markers.sort(key=lambda x: x._data)
1718 1718 else:
1719 1719 markers = obsutil.getmarkers(repo)
1720 1720
1721 1721 markerstoiter = markers
1722 1722 isrelevant = lambda m: True
1723 1723 if opts.get('rev') and opts.get('index'):
1724 1724 markerstoiter = obsutil.getmarkers(repo)
1725 1725 markerset = set(markers)
1726 1726 isrelevant = lambda m: m in markerset
1727 1727
1728 1728 fm = ui.formatter('debugobsolete', opts)
1729 1729 for i, m in enumerate(markerstoiter):
1730 1730 if not isrelevant(m):
1731 1731 # marker can be irrelevant when we're iterating over a set
1732 1732 # of markers (markerstoiter) which is bigger than the set
1733 1733 # of markers we want to display (markers)
1734 1734 # this can happen if both --index and --rev options are
1735 1735 # provided and thus we need to iterate over all of the markers
1736 1736 # to get the correct indices, but only display the ones that
1737 1737 # are relevant to --rev value
1738 1738 continue
1739 1739 fm.startitem()
1740 1740 ind = i if opts.get('index') else None
1741 1741 cmdutil.showmarker(fm, m, index=ind)
1742 1742 fm.end()
1743 1743
1744 @command('debugp1copies',
1745 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1746 _('[-r REV]'))
1747 def debugp1copies(ui, repo, **opts):
1748 """dump copy information compared to p1"""
1749
1750 opts = pycompat.byteskwargs(opts)
1751 ctx = scmutil.revsingle(repo, opts.get('rev'), default=None)
1752 for dst, src in ctx.p1copies().items():
1753 ui.write('%s -> %s\n' % (src, dst))
1754
1755 @command('debugp2copies',
1756 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1757 _('[-r REV]'))
1758 def debugp1copies(ui, repo, **opts):
1759 """dump copy information compared to p2"""
1760
1761 opts = pycompat.byteskwargs(opts)
1762 ctx = scmutil.revsingle(repo, opts.get('rev'), default=None)
1763 for dst, src in ctx.p2copies().items():
1764 ui.write('%s -> %s\n' % (src, dst))
1765
1744 1766 @command('debugpathcomplete',
1745 1767 [('f', 'full', None, _('complete an entire path')),
1746 1768 ('n', 'normal', None, _('show only normal files')),
1747 1769 ('a', 'added', None, _('show only added files')),
1748 1770 ('r', 'removed', None, _('show only removed files'))],
1749 1771 _('FILESPEC...'))
1750 1772 def debugpathcomplete(ui, repo, *specs, **opts):
1751 1773 '''complete part or all of a tracked path
1752 1774
1753 1775 This command supports shells that offer path name completion. It
1754 1776 currently completes only files already known to the dirstate.
1755 1777
1756 1778 Completion extends only to the next path segment unless
1757 1779 --full is specified, in which case entire paths are used.'''
1758 1780
1759 1781 def complete(path, acceptable):
1760 1782 dirstate = repo.dirstate
1761 1783 spec = os.path.normpath(os.path.join(encoding.getcwd(), path))
1762 1784 rootdir = repo.root + pycompat.ossep
1763 1785 if spec != repo.root and not spec.startswith(rootdir):
1764 1786 return [], []
1765 1787 if os.path.isdir(spec):
1766 1788 spec += '/'
1767 1789 spec = spec[len(rootdir):]
1768 1790 fixpaths = pycompat.ossep != '/'
1769 1791 if fixpaths:
1770 1792 spec = spec.replace(pycompat.ossep, '/')
1771 1793 speclen = len(spec)
1772 1794 fullpaths = opts[r'full']
1773 1795 files, dirs = set(), set()
1774 1796 adddir, addfile = dirs.add, files.add
1775 1797 for f, st in dirstate.iteritems():
1776 1798 if f.startswith(spec) and st[0] in acceptable:
1777 1799 if fixpaths:
1778 1800 f = f.replace('/', pycompat.ossep)
1779 1801 if fullpaths:
1780 1802 addfile(f)
1781 1803 continue
1782 1804 s = f.find(pycompat.ossep, speclen)
1783 1805 if s >= 0:
1784 1806 adddir(f[:s])
1785 1807 else:
1786 1808 addfile(f)
1787 1809 return files, dirs
1788 1810
1789 1811 acceptable = ''
1790 1812 if opts[r'normal']:
1791 1813 acceptable += 'nm'
1792 1814 if opts[r'added']:
1793 1815 acceptable += 'a'
1794 1816 if opts[r'removed']:
1795 1817 acceptable += 'r'
1796 1818 cwd = repo.getcwd()
1797 1819 if not specs:
1798 1820 specs = ['.']
1799 1821
1800 1822 files, dirs = set(), set()
1801 1823 for spec in specs:
1802 1824 f, d = complete(spec, acceptable or 'nmar')
1803 1825 files.update(f)
1804 1826 dirs.update(d)
1805 1827 files.update(dirs)
1806 1828 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
1807 1829 ui.write('\n')
1808 1830
1809 1831 @command('debugpathcopies',
1810 1832 cmdutil.walkopts,
1811 1833 'hg debugpathcopies REV1 REV2 [FILE]',
1812 1834 inferrepo=True)
1813 1835 def debugpathcopies(ui, repo, rev1, rev2, *pats, **opts):
1814 1836 """show copies between two revisions"""
1815 1837 ctx1 = scmutil.revsingle(repo, rev1)
1816 1838 ctx2 = scmutil.revsingle(repo, rev2)
1817 1839 m = scmutil.match(ctx1, pats, opts)
1818 1840 for dst, src in sorted(copies.pathcopies(ctx1, ctx2, m).items()):
1819 1841 ui.write('%s -> %s\n' % (src, dst))
1820 1842
1821 1843 @command('debugpeer', [], _('PATH'), norepo=True)
1822 1844 def debugpeer(ui, path):
1823 1845 """establish a connection to a peer repository"""
1824 1846 # Always enable peer request logging. Requires --debug to display
1825 1847 # though.
1826 1848 overrides = {
1827 1849 ('devel', 'debug.peer-request'): True,
1828 1850 }
1829 1851
1830 1852 with ui.configoverride(overrides):
1831 1853 peer = hg.peer(ui, {}, path)
1832 1854
1833 1855 local = peer.local() is not None
1834 1856 canpush = peer.canpush()
1835 1857
1836 1858 ui.write(_('url: %s\n') % peer.url())
1837 1859 ui.write(_('local: %s\n') % (_('yes') if local else _('no')))
1838 1860 ui.write(_('pushable: %s\n') % (_('yes') if canpush else _('no')))
1839 1861
1840 1862 @command('debugpickmergetool',
1841 1863 [('r', 'rev', '', _('check for files in this revision'), _('REV')),
1842 1864 ('', 'changedelete', None, _('emulate merging change and delete')),
1843 1865 ] + cmdutil.walkopts + cmdutil.mergetoolopts,
1844 1866 _('[PATTERN]...'),
1845 1867 inferrepo=True)
1846 1868 def debugpickmergetool(ui, repo, *pats, **opts):
1847 1869 """examine which merge tool is chosen for specified file
1848 1870
1849 1871 As described in :hg:`help merge-tools`, Mercurial examines
1850 1872 configurations below in this order to decide which merge tool is
1851 1873 chosen for specified file.
1852 1874
1853 1875 1. ``--tool`` option
1854 1876 2. ``HGMERGE`` environment variable
1855 1877 3. configurations in ``merge-patterns`` section
1856 1878 4. configuration of ``ui.merge``
1857 1879 5. configurations in ``merge-tools`` section
1858 1880 6. ``hgmerge`` tool (for historical reason only)
1859 1881 7. default tool for fallback (``:merge`` or ``:prompt``)
1860 1882
1861 1883 This command writes out examination result in the style below::
1862 1884
1863 1885 FILE = MERGETOOL
1864 1886
1865 1887 By default, all files known in the first parent context of the
1866 1888 working directory are examined. Use file patterns and/or -I/-X
1867 1889 options to limit target files. -r/--rev is also useful to examine
1868 1890 files in another context without actual updating to it.
1869 1891
1870 1892 With --debug, this command shows warning messages while matching
1871 1893 against ``merge-patterns`` and so on, too. It is recommended to
1872 1894 use this option with explicit file patterns and/or -I/-X options,
1873 1895 because this option increases amount of output per file according
1874 1896 to configurations in hgrc.
1875 1897
1876 1898 With -v/--verbose, this command shows configurations below at
1877 1899 first (only if specified).
1878 1900
1879 1901 - ``--tool`` option
1880 1902 - ``HGMERGE`` environment variable
1881 1903 - configuration of ``ui.merge``
1882 1904
1883 1905 If merge tool is chosen before matching against
1884 1906 ``merge-patterns``, this command can't show any helpful
1885 1907 information, even with --debug. In such case, information above is
1886 1908 useful to know why a merge tool is chosen.
1887 1909 """
1888 1910 opts = pycompat.byteskwargs(opts)
1889 1911 overrides = {}
1890 1912 if opts['tool']:
1891 1913 overrides[('ui', 'forcemerge')] = opts['tool']
1892 1914 ui.note(('with --tool %r\n') % (pycompat.bytestr(opts['tool'])))
1893 1915
1894 1916 with ui.configoverride(overrides, 'debugmergepatterns'):
1895 1917 hgmerge = encoding.environ.get("HGMERGE")
1896 1918 if hgmerge is not None:
1897 1919 ui.note(('with HGMERGE=%r\n') % (pycompat.bytestr(hgmerge)))
1898 1920 uimerge = ui.config("ui", "merge")
1899 1921 if uimerge:
1900 1922 ui.note(('with ui.merge=%r\n') % (pycompat.bytestr(uimerge)))
1901 1923
1902 1924 ctx = scmutil.revsingle(repo, opts.get('rev'))
1903 1925 m = scmutil.match(ctx, pats, opts)
1904 1926 changedelete = opts['changedelete']
1905 1927 for path in ctx.walk(m):
1906 1928 fctx = ctx[path]
1907 1929 try:
1908 1930 if not ui.debugflag:
1909 1931 ui.pushbuffer(error=True)
1910 1932 tool, toolpath = filemerge._picktool(repo, ui, path,
1911 1933 fctx.isbinary(),
1912 1934 'l' in fctx.flags(),
1913 1935 changedelete)
1914 1936 finally:
1915 1937 if not ui.debugflag:
1916 1938 ui.popbuffer()
1917 1939 ui.write(('%s = %s\n') % (path, tool))
1918 1940
1919 1941 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
1920 1942 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1921 1943 '''access the pushkey key/value protocol
1922 1944
1923 1945 With two args, list the keys in the given namespace.
1924 1946
1925 1947 With five args, set a key to new if it currently is set to old.
1926 1948 Reports success or failure.
1927 1949 '''
1928 1950
1929 1951 target = hg.peer(ui, {}, repopath)
1930 1952 if keyinfo:
1931 1953 key, old, new = keyinfo
1932 1954 with target.commandexecutor() as e:
1933 1955 r = e.callcommand('pushkey', {
1934 1956 'namespace': namespace,
1935 1957 'key': key,
1936 1958 'old': old,
1937 1959 'new': new,
1938 1960 }).result()
1939 1961
1940 1962 ui.status(pycompat.bytestr(r) + '\n')
1941 1963 return not r
1942 1964 else:
1943 1965 for k, v in sorted(target.listkeys(namespace).iteritems()):
1944 1966 ui.write("%s\t%s\n" % (stringutil.escapestr(k),
1945 1967 stringutil.escapestr(v)))
1946 1968
1947 1969 @command('debugpvec', [], _('A B'))
1948 1970 def debugpvec(ui, repo, a, b=None):
1949 1971 ca = scmutil.revsingle(repo, a)
1950 1972 cb = scmutil.revsingle(repo, b)
1951 1973 pa = pvec.ctxpvec(ca)
1952 1974 pb = pvec.ctxpvec(cb)
1953 1975 if pa == pb:
1954 1976 rel = "="
1955 1977 elif pa > pb:
1956 1978 rel = ">"
1957 1979 elif pa < pb:
1958 1980 rel = "<"
1959 1981 elif pa | pb:
1960 1982 rel = "|"
1961 1983 ui.write(_("a: %s\n") % pa)
1962 1984 ui.write(_("b: %s\n") % pb)
1963 1985 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
1964 1986 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
1965 1987 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
1966 1988 pa.distance(pb), rel))
1967 1989
1968 1990 @command('debugrebuilddirstate|debugrebuildstate',
1969 1991 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
1970 1992 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
1971 1993 'the working copy parent')),
1972 1994 ],
1973 1995 _('[-r REV]'))
1974 1996 def debugrebuilddirstate(ui, repo, rev, **opts):
1975 1997 """rebuild the dirstate as it would look like for the given revision
1976 1998
1977 1999 If no revision is specified the first current parent will be used.
1978 2000
1979 2001 The dirstate will be set to the files of the given revision.
1980 2002 The actual working directory content or existing dirstate
1981 2003 information such as adds or removes is not considered.
1982 2004
1983 2005 ``minimal`` will only rebuild the dirstate status for files that claim to be
1984 2006 tracked but are not in the parent manifest, or that exist in the parent
1985 2007 manifest but are not in the dirstate. It will not change adds, removes, or
1986 2008 modified files that are in the working copy parent.
1987 2009
1988 2010 One use of this command is to make the next :hg:`status` invocation
1989 2011 check the actual file content.
1990 2012 """
1991 2013 ctx = scmutil.revsingle(repo, rev)
1992 2014 with repo.wlock():
1993 2015 dirstate = repo.dirstate
1994 2016 changedfiles = None
1995 2017 # See command doc for what minimal does.
1996 2018 if opts.get(r'minimal'):
1997 2019 manifestfiles = set(ctx.manifest().keys())
1998 2020 dirstatefiles = set(dirstate)
1999 2021 manifestonly = manifestfiles - dirstatefiles
2000 2022 dsonly = dirstatefiles - manifestfiles
2001 2023 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
2002 2024 changedfiles = manifestonly | dsnotadded
2003 2025
2004 2026 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
2005 2027
2006 2028 @command('debugrebuildfncache', [], '')
2007 2029 def debugrebuildfncache(ui, repo):
2008 2030 """rebuild the fncache file"""
2009 2031 repair.rebuildfncache(ui, repo)
2010 2032
2011 2033 @command('debugrename',
2012 2034 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2013 2035 _('[-r REV] [FILE]...'))
2014 2036 def debugrename(ui, repo, *pats, **opts):
2015 2037 """dump rename information"""
2016 2038
2017 2039 opts = pycompat.byteskwargs(opts)
2018 2040 ctx = scmutil.revsingle(repo, opts.get('rev'))
2019 2041 m = scmutil.match(ctx, pats, opts)
2020 2042 for abs in ctx.walk(m):
2021 2043 fctx = ctx[abs]
2022 2044 o = fctx.filelog().renamed(fctx.filenode())
2023 2045 rel = repo.pathto(abs)
2024 2046 if o:
2025 2047 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2026 2048 else:
2027 2049 ui.write(_("%s not renamed\n") % rel)
2028 2050
2029 2051 @command('debugrevlog', cmdutil.debugrevlogopts +
2030 2052 [('d', 'dump', False, _('dump index data'))],
2031 2053 _('-c|-m|FILE'),
2032 2054 optionalrepo=True)
2033 2055 def debugrevlog(ui, repo, file_=None, **opts):
2034 2056 """show data and statistics about a revlog"""
2035 2057 opts = pycompat.byteskwargs(opts)
2036 2058 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2037 2059
2038 2060 if opts.get("dump"):
2039 2061 numrevs = len(r)
2040 2062 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
2041 2063 " rawsize totalsize compression heads chainlen\n"))
2042 2064 ts = 0
2043 2065 heads = set()
2044 2066
2045 2067 for rev in pycompat.xrange(numrevs):
2046 2068 dbase = r.deltaparent(rev)
2047 2069 if dbase == -1:
2048 2070 dbase = rev
2049 2071 cbase = r.chainbase(rev)
2050 2072 clen = r.chainlen(rev)
2051 2073 p1, p2 = r.parentrevs(rev)
2052 2074 rs = r.rawsize(rev)
2053 2075 ts = ts + rs
2054 2076 heads -= set(r.parentrevs(rev))
2055 2077 heads.add(rev)
2056 2078 try:
2057 2079 compression = ts / r.end(rev)
2058 2080 except ZeroDivisionError:
2059 2081 compression = 0
2060 2082 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2061 2083 "%11d %5d %8d\n" %
2062 2084 (rev, p1, p2, r.start(rev), r.end(rev),
2063 2085 r.start(dbase), r.start(cbase),
2064 2086 r.start(p1), r.start(p2),
2065 2087 rs, ts, compression, len(heads), clen))
2066 2088 return 0
2067 2089
2068 2090 v = r.version
2069 2091 format = v & 0xFFFF
2070 2092 flags = []
2071 2093 gdelta = False
2072 2094 if v & revlog.FLAG_INLINE_DATA:
2073 2095 flags.append('inline')
2074 2096 if v & revlog.FLAG_GENERALDELTA:
2075 2097 gdelta = True
2076 2098 flags.append('generaldelta')
2077 2099 if not flags:
2078 2100 flags = ['(none)']
2079 2101
2080 2102 ### tracks merge vs single parent
2081 2103 nummerges = 0
2082 2104
2083 2105 ### tracks ways the "delta" are build
2084 2106 # nodelta
2085 2107 numempty = 0
2086 2108 numemptytext = 0
2087 2109 numemptydelta = 0
2088 2110 # full file content
2089 2111 numfull = 0
2090 2112 # intermediate snapshot against a prior snapshot
2091 2113 numsemi = 0
2092 2114 # snapshot count per depth
2093 2115 numsnapdepth = collections.defaultdict(lambda: 0)
2094 2116 # delta against previous revision
2095 2117 numprev = 0
2096 2118 # delta against first or second parent (not prev)
2097 2119 nump1 = 0
2098 2120 nump2 = 0
2099 2121 # delta against neither prev nor parents
2100 2122 numother = 0
2101 2123 # delta against prev that are also first or second parent
2102 2124 # (details of `numprev`)
2103 2125 nump1prev = 0
2104 2126 nump2prev = 0
2105 2127
2106 2128 # data about delta chain of each revs
2107 2129 chainlengths = []
2108 2130 chainbases = []
2109 2131 chainspans = []
2110 2132
2111 2133 # data about each revision
2112 2134 datasize = [None, 0, 0]
2113 2135 fullsize = [None, 0, 0]
2114 2136 semisize = [None, 0, 0]
2115 2137 # snapshot count per depth
2116 2138 snapsizedepth = collections.defaultdict(lambda: [None, 0, 0])
2117 2139 deltasize = [None, 0, 0]
2118 2140 chunktypecounts = {}
2119 2141 chunktypesizes = {}
2120 2142
2121 2143 def addsize(size, l):
2122 2144 if l[0] is None or size < l[0]:
2123 2145 l[0] = size
2124 2146 if size > l[1]:
2125 2147 l[1] = size
2126 2148 l[2] += size
2127 2149
2128 2150 numrevs = len(r)
2129 2151 for rev in pycompat.xrange(numrevs):
2130 2152 p1, p2 = r.parentrevs(rev)
2131 2153 delta = r.deltaparent(rev)
2132 2154 if format > 0:
2133 2155 addsize(r.rawsize(rev), datasize)
2134 2156 if p2 != nullrev:
2135 2157 nummerges += 1
2136 2158 size = r.length(rev)
2137 2159 if delta == nullrev:
2138 2160 chainlengths.append(0)
2139 2161 chainbases.append(r.start(rev))
2140 2162 chainspans.append(size)
2141 2163 if size == 0:
2142 2164 numempty += 1
2143 2165 numemptytext += 1
2144 2166 else:
2145 2167 numfull += 1
2146 2168 numsnapdepth[0] += 1
2147 2169 addsize(size, fullsize)
2148 2170 addsize(size, snapsizedepth[0])
2149 2171 else:
2150 2172 chainlengths.append(chainlengths[delta] + 1)
2151 2173 baseaddr = chainbases[delta]
2152 2174 revaddr = r.start(rev)
2153 2175 chainbases.append(baseaddr)
2154 2176 chainspans.append((revaddr - baseaddr) + size)
2155 2177 if size == 0:
2156 2178 numempty += 1
2157 2179 numemptydelta += 1
2158 2180 elif r.issnapshot(rev):
2159 2181 addsize(size, semisize)
2160 2182 numsemi += 1
2161 2183 depth = r.snapshotdepth(rev)
2162 2184 numsnapdepth[depth] += 1
2163 2185 addsize(size, snapsizedepth[depth])
2164 2186 else:
2165 2187 addsize(size, deltasize)
2166 2188 if delta == rev - 1:
2167 2189 numprev += 1
2168 2190 if delta == p1:
2169 2191 nump1prev += 1
2170 2192 elif delta == p2:
2171 2193 nump2prev += 1
2172 2194 elif delta == p1:
2173 2195 nump1 += 1
2174 2196 elif delta == p2:
2175 2197 nump2 += 1
2176 2198 elif delta != nullrev:
2177 2199 numother += 1
2178 2200
2179 2201 # Obtain data on the raw chunks in the revlog.
2180 2202 if util.safehasattr(r, '_getsegmentforrevs'):
2181 2203 segment = r._getsegmentforrevs(rev, rev)[1]
2182 2204 else:
2183 2205 segment = r._revlog._getsegmentforrevs(rev, rev)[1]
2184 2206 if segment:
2185 2207 chunktype = bytes(segment[0:1])
2186 2208 else:
2187 2209 chunktype = 'empty'
2188 2210
2189 2211 if chunktype not in chunktypecounts:
2190 2212 chunktypecounts[chunktype] = 0
2191 2213 chunktypesizes[chunktype] = 0
2192 2214
2193 2215 chunktypecounts[chunktype] += 1
2194 2216 chunktypesizes[chunktype] += size
2195 2217
2196 2218 # Adjust size min value for empty cases
2197 2219 for size in (datasize, fullsize, semisize, deltasize):
2198 2220 if size[0] is None:
2199 2221 size[0] = 0
2200 2222
2201 2223 numdeltas = numrevs - numfull - numempty - numsemi
2202 2224 numoprev = numprev - nump1prev - nump2prev
2203 2225 totalrawsize = datasize[2]
2204 2226 datasize[2] /= numrevs
2205 2227 fulltotal = fullsize[2]
2206 2228 fullsize[2] /= numfull
2207 2229 semitotal = semisize[2]
2208 2230 snaptotal = {}
2209 2231 if numsemi > 0:
2210 2232 semisize[2] /= numsemi
2211 2233 for depth in snapsizedepth:
2212 2234 snaptotal[depth] = snapsizedepth[depth][2]
2213 2235 snapsizedepth[depth][2] /= numsnapdepth[depth]
2214 2236
2215 2237 deltatotal = deltasize[2]
2216 2238 if numdeltas > 0:
2217 2239 deltasize[2] /= numdeltas
2218 2240 totalsize = fulltotal + semitotal + deltatotal
2219 2241 avgchainlen = sum(chainlengths) / numrevs
2220 2242 maxchainlen = max(chainlengths)
2221 2243 maxchainspan = max(chainspans)
2222 2244 compratio = 1
2223 2245 if totalsize:
2224 2246 compratio = totalrawsize / totalsize
2225 2247
2226 2248 basedfmtstr = '%%%dd\n'
2227 2249 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2228 2250
2229 2251 def dfmtstr(max):
2230 2252 return basedfmtstr % len(str(max))
2231 2253 def pcfmtstr(max, padding=0):
2232 2254 return basepcfmtstr % (len(str(max)), ' ' * padding)
2233 2255
2234 2256 def pcfmt(value, total):
2235 2257 if total:
2236 2258 return (value, 100 * float(value) / total)
2237 2259 else:
2238 2260 return value, 100.0
2239 2261
2240 2262 ui.write(('format : %d\n') % format)
2241 2263 ui.write(('flags : %s\n') % ', '.join(flags))
2242 2264
2243 2265 ui.write('\n')
2244 2266 fmt = pcfmtstr(totalsize)
2245 2267 fmt2 = dfmtstr(totalsize)
2246 2268 ui.write(('revisions : ') + fmt2 % numrevs)
2247 2269 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2248 2270 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2249 2271 ui.write(('revisions : ') + fmt2 % numrevs)
2250 2272 ui.write((' empty : ') + fmt % pcfmt(numempty, numrevs))
2251 2273 ui.write((' text : ')
2252 2274 + fmt % pcfmt(numemptytext, numemptytext + numemptydelta))
2253 2275 ui.write((' delta : ')
2254 2276 + fmt % pcfmt(numemptydelta, numemptytext + numemptydelta))
2255 2277 ui.write((' snapshot : ') + fmt % pcfmt(numfull + numsemi, numrevs))
2256 2278 for depth in sorted(numsnapdepth):
2257 2279 ui.write((' lvl-%-3d : ' % depth)
2258 2280 + fmt % pcfmt(numsnapdepth[depth], numrevs))
2259 2281 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2260 2282 ui.write(('revision size : ') + fmt2 % totalsize)
2261 2283 ui.write((' snapshot : ')
2262 2284 + fmt % pcfmt(fulltotal + semitotal, totalsize))
2263 2285 for depth in sorted(numsnapdepth):
2264 2286 ui.write((' lvl-%-3d : ' % depth)
2265 2287 + fmt % pcfmt(snaptotal[depth], totalsize))
2266 2288 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2267 2289
2268 2290 def fmtchunktype(chunktype):
2269 2291 if chunktype == 'empty':
2270 2292 return ' %s : ' % chunktype
2271 2293 elif chunktype in pycompat.bytestr(string.ascii_letters):
2272 2294 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
2273 2295 else:
2274 2296 return ' 0x%s : ' % hex(chunktype)
2275 2297
2276 2298 ui.write('\n')
2277 2299 ui.write(('chunks : ') + fmt2 % numrevs)
2278 2300 for chunktype in sorted(chunktypecounts):
2279 2301 ui.write(fmtchunktype(chunktype))
2280 2302 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
2281 2303 ui.write(('chunks size : ') + fmt2 % totalsize)
2282 2304 for chunktype in sorted(chunktypecounts):
2283 2305 ui.write(fmtchunktype(chunktype))
2284 2306 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
2285 2307
2286 2308 ui.write('\n')
2287 2309 fmt = dfmtstr(max(avgchainlen, maxchainlen, maxchainspan, compratio))
2288 2310 ui.write(('avg chain length : ') + fmt % avgchainlen)
2289 2311 ui.write(('max chain length : ') + fmt % maxchainlen)
2290 2312 ui.write(('max chain reach : ') + fmt % maxchainspan)
2291 2313 ui.write(('compression ratio : ') + fmt % compratio)
2292 2314
2293 2315 if format > 0:
2294 2316 ui.write('\n')
2295 2317 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2296 2318 % tuple(datasize))
2297 2319 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2298 2320 % tuple(fullsize))
2299 2321 ui.write(('inter-snapshot size (min/max/avg) : %d / %d / %d\n')
2300 2322 % tuple(semisize))
2301 2323 for depth in sorted(snapsizedepth):
2302 2324 if depth == 0:
2303 2325 continue
2304 2326 ui.write((' level-%-3d (min/max/avg) : %d / %d / %d\n')
2305 2327 % ((depth,) + tuple(snapsizedepth[depth])))
2306 2328 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2307 2329 % tuple(deltasize))
2308 2330
2309 2331 if numdeltas > 0:
2310 2332 ui.write('\n')
2311 2333 fmt = pcfmtstr(numdeltas)
2312 2334 fmt2 = pcfmtstr(numdeltas, 4)
2313 2335 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2314 2336 if numprev > 0:
2315 2337 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2316 2338 numprev))
2317 2339 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2318 2340 numprev))
2319 2341 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2320 2342 numprev))
2321 2343 if gdelta:
2322 2344 ui.write(('deltas against p1 : ')
2323 2345 + fmt % pcfmt(nump1, numdeltas))
2324 2346 ui.write(('deltas against p2 : ')
2325 2347 + fmt % pcfmt(nump2, numdeltas))
2326 2348 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2327 2349 numdeltas))
2328 2350
2329 2351 @command('debugrevlogindex', cmdutil.debugrevlogopts +
2330 2352 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2331 2353 _('[-f FORMAT] -c|-m|FILE'),
2332 2354 optionalrepo=True)
2333 2355 def debugrevlogindex(ui, repo, file_=None, **opts):
2334 2356 """dump the contents of a revlog index"""
2335 2357 opts = pycompat.byteskwargs(opts)
2336 2358 r = cmdutil.openrevlog(repo, 'debugrevlogindex', file_, opts)
2337 2359 format = opts.get('format', 0)
2338 2360 if format not in (0, 1):
2339 2361 raise error.Abort(_("unknown format %d") % format)
2340 2362
2341 2363 if ui.debugflag:
2342 2364 shortfn = hex
2343 2365 else:
2344 2366 shortfn = short
2345 2367
2346 2368 # There might not be anything in r, so have a sane default
2347 2369 idlen = 12
2348 2370 for i in r:
2349 2371 idlen = len(shortfn(r.node(i)))
2350 2372 break
2351 2373
2352 2374 if format == 0:
2353 2375 if ui.verbose:
2354 2376 ui.write((" rev offset length linkrev"
2355 2377 " %s %s p2\n") % ("nodeid".ljust(idlen),
2356 2378 "p1".ljust(idlen)))
2357 2379 else:
2358 2380 ui.write((" rev linkrev %s %s p2\n") % (
2359 2381 "nodeid".ljust(idlen), "p1".ljust(idlen)))
2360 2382 elif format == 1:
2361 2383 if ui.verbose:
2362 2384 ui.write((" rev flag offset length size link p1"
2363 2385 " p2 %s\n") % "nodeid".rjust(idlen))
2364 2386 else:
2365 2387 ui.write((" rev flag size link p1 p2 %s\n") %
2366 2388 "nodeid".rjust(idlen))
2367 2389
2368 2390 for i in r:
2369 2391 node = r.node(i)
2370 2392 if format == 0:
2371 2393 try:
2372 2394 pp = r.parents(node)
2373 2395 except Exception:
2374 2396 pp = [nullid, nullid]
2375 2397 if ui.verbose:
2376 2398 ui.write("% 6d % 9d % 7d % 7d %s %s %s\n" % (
2377 2399 i, r.start(i), r.length(i), r.linkrev(i),
2378 2400 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2379 2401 else:
2380 2402 ui.write("% 6d % 7d %s %s %s\n" % (
2381 2403 i, r.linkrev(i), shortfn(node), shortfn(pp[0]),
2382 2404 shortfn(pp[1])))
2383 2405 elif format == 1:
2384 2406 pr = r.parentrevs(i)
2385 2407 if ui.verbose:
2386 2408 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d %s\n" % (
2387 2409 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2388 2410 r.linkrev(i), pr[0], pr[1], shortfn(node)))
2389 2411 else:
2390 2412 ui.write("% 6d %04x % 8d % 6d % 6d % 6d %s\n" % (
2391 2413 i, r.flags(i), r.rawsize(i), r.linkrev(i), pr[0], pr[1],
2392 2414 shortfn(node)))
2393 2415
2394 2416 @command('debugrevspec',
2395 2417 [('', 'optimize', None,
2396 2418 _('print parsed tree after optimizing (DEPRECATED)')),
2397 2419 ('', 'show-revs', True, _('print list of result revisions (default)')),
2398 2420 ('s', 'show-set', None, _('print internal representation of result set')),
2399 2421 ('p', 'show-stage', [],
2400 2422 _('print parsed tree at the given stage'), _('NAME')),
2401 2423 ('', 'no-optimized', False, _('evaluate tree without optimization')),
2402 2424 ('', 'verify-optimized', False, _('verify optimized result')),
2403 2425 ],
2404 2426 ('REVSPEC'))
2405 2427 def debugrevspec(ui, repo, expr, **opts):
2406 2428 """parse and apply a revision specification
2407 2429
2408 2430 Use -p/--show-stage option to print the parsed tree at the given stages.
2409 2431 Use -p all to print tree at every stage.
2410 2432
2411 2433 Use --no-show-revs option with -s or -p to print only the set
2412 2434 representation or the parsed tree respectively.
2413 2435
2414 2436 Use --verify-optimized to compare the optimized result with the unoptimized
2415 2437 one. Returns 1 if the optimized result differs.
2416 2438 """
2417 2439 opts = pycompat.byteskwargs(opts)
2418 2440 aliases = ui.configitems('revsetalias')
2419 2441 stages = [
2420 2442 ('parsed', lambda tree: tree),
2421 2443 ('expanded', lambda tree: revsetlang.expandaliases(tree, aliases,
2422 2444 ui.warn)),
2423 2445 ('concatenated', revsetlang.foldconcat),
2424 2446 ('analyzed', revsetlang.analyze),
2425 2447 ('optimized', revsetlang.optimize),
2426 2448 ]
2427 2449 if opts['no_optimized']:
2428 2450 stages = stages[:-1]
2429 2451 if opts['verify_optimized'] and opts['no_optimized']:
2430 2452 raise error.Abort(_('cannot use --verify-optimized with '
2431 2453 '--no-optimized'))
2432 2454 stagenames = set(n for n, f in stages)
2433 2455
2434 2456 showalways = set()
2435 2457 showchanged = set()
2436 2458 if ui.verbose and not opts['show_stage']:
2437 2459 # show parsed tree by --verbose (deprecated)
2438 2460 showalways.add('parsed')
2439 2461 showchanged.update(['expanded', 'concatenated'])
2440 2462 if opts['optimize']:
2441 2463 showalways.add('optimized')
2442 2464 if opts['show_stage'] and opts['optimize']:
2443 2465 raise error.Abort(_('cannot use --optimize with --show-stage'))
2444 2466 if opts['show_stage'] == ['all']:
2445 2467 showalways.update(stagenames)
2446 2468 else:
2447 2469 for n in opts['show_stage']:
2448 2470 if n not in stagenames:
2449 2471 raise error.Abort(_('invalid stage name: %s') % n)
2450 2472 showalways.update(opts['show_stage'])
2451 2473
2452 2474 treebystage = {}
2453 2475 printedtree = None
2454 2476 tree = revsetlang.parse(expr, lookup=revset.lookupfn(repo))
2455 2477 for n, f in stages:
2456 2478 treebystage[n] = tree = f(tree)
2457 2479 if n in showalways or (n in showchanged and tree != printedtree):
2458 2480 if opts['show_stage'] or n != 'parsed':
2459 2481 ui.write(("* %s:\n") % n)
2460 2482 ui.write(revsetlang.prettyformat(tree), "\n")
2461 2483 printedtree = tree
2462 2484
2463 2485 if opts['verify_optimized']:
2464 2486 arevs = revset.makematcher(treebystage['analyzed'])(repo)
2465 2487 brevs = revset.makematcher(treebystage['optimized'])(repo)
2466 2488 if opts['show_set'] or (opts['show_set'] is None and ui.verbose):
2467 2489 ui.write(("* analyzed set:\n"), stringutil.prettyrepr(arevs), "\n")
2468 2490 ui.write(("* optimized set:\n"), stringutil.prettyrepr(brevs), "\n")
2469 2491 arevs = list(arevs)
2470 2492 brevs = list(brevs)
2471 2493 if arevs == brevs:
2472 2494 return 0
2473 2495 ui.write(('--- analyzed\n'), label='diff.file_a')
2474 2496 ui.write(('+++ optimized\n'), label='diff.file_b')
2475 2497 sm = difflib.SequenceMatcher(None, arevs, brevs)
2476 2498 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2477 2499 if tag in (r'delete', r'replace'):
2478 2500 for c in arevs[alo:ahi]:
2479 2501 ui.write('-%d\n' % c, label='diff.deleted')
2480 2502 if tag in (r'insert', r'replace'):
2481 2503 for c in brevs[blo:bhi]:
2482 2504 ui.write('+%d\n' % c, label='diff.inserted')
2483 2505 if tag == r'equal':
2484 2506 for c in arevs[alo:ahi]:
2485 2507 ui.write(' %d\n' % c)
2486 2508 return 1
2487 2509
2488 2510 func = revset.makematcher(tree)
2489 2511 revs = func(repo)
2490 2512 if opts['show_set'] or (opts['show_set'] is None and ui.verbose):
2491 2513 ui.write(("* set:\n"), stringutil.prettyrepr(revs), "\n")
2492 2514 if not opts['show_revs']:
2493 2515 return
2494 2516 for c in revs:
2495 2517 ui.write("%d\n" % c)
2496 2518
2497 2519 @command('debugserve', [
2498 2520 ('', 'sshstdio', False, _('run an SSH server bound to process handles')),
2499 2521 ('', 'logiofd', '', _('file descriptor to log server I/O to')),
2500 2522 ('', 'logiofile', '', _('file to log server I/O to')),
2501 2523 ], '')
2502 2524 def debugserve(ui, repo, **opts):
2503 2525 """run a server with advanced settings
2504 2526
2505 2527 This command is similar to :hg:`serve`. It exists partially as a
2506 2528 workaround to the fact that ``hg serve --stdio`` must have specific
2507 2529 arguments for security reasons.
2508 2530 """
2509 2531 opts = pycompat.byteskwargs(opts)
2510 2532
2511 2533 if not opts['sshstdio']:
2512 2534 raise error.Abort(_('only --sshstdio is currently supported'))
2513 2535
2514 2536 logfh = None
2515 2537
2516 2538 if opts['logiofd'] and opts['logiofile']:
2517 2539 raise error.Abort(_('cannot use both --logiofd and --logiofile'))
2518 2540
2519 2541 if opts['logiofd']:
2520 2542 # Line buffered because output is line based.
2521 2543 try:
2522 2544 logfh = os.fdopen(int(opts['logiofd']), r'ab', 1)
2523 2545 except OSError as e:
2524 2546 if e.errno != errno.ESPIPE:
2525 2547 raise
2526 2548 # can't seek a pipe, so `ab` mode fails on py3
2527 2549 logfh = os.fdopen(int(opts['logiofd']), r'wb', 1)
2528 2550 elif opts['logiofile']:
2529 2551 logfh = open(opts['logiofile'], 'ab', 1)
2530 2552
2531 2553 s = wireprotoserver.sshserver(ui, repo, logfh=logfh)
2532 2554 s.serve_forever()
2533 2555
2534 2556 @command('debugsetparents', [], _('REV1 [REV2]'))
2535 2557 def debugsetparents(ui, repo, rev1, rev2=None):
2536 2558 """manually set the parents of the current working directory
2537 2559
2538 2560 This is useful for writing repository conversion tools, but should
2539 2561 be used with care. For example, neither the working directory nor the
2540 2562 dirstate is updated, so file status may be incorrect after running this
2541 2563 command.
2542 2564
2543 2565 Returns 0 on success.
2544 2566 """
2545 2567
2546 2568 node1 = scmutil.revsingle(repo, rev1).node()
2547 2569 node2 = scmutil.revsingle(repo, rev2, 'null').node()
2548 2570
2549 2571 with repo.wlock():
2550 2572 repo.setparents(node1, node2)
2551 2573
2552 2574 @command('debugssl', [], '[SOURCE]', optionalrepo=True)
2553 2575 def debugssl(ui, repo, source=None, **opts):
2554 2576 '''test a secure connection to a server
2555 2577
2556 2578 This builds the certificate chain for the server on Windows, installing the
2557 2579 missing intermediates and trusted root via Windows Update if necessary. It
2558 2580 does nothing on other platforms.
2559 2581
2560 2582 If SOURCE is omitted, the 'default' path will be used. If a URL is given,
2561 2583 that server is used. See :hg:`help urls` for more information.
2562 2584
2563 2585 If the update succeeds, retry the original operation. Otherwise, the cause
2564 2586 of the SSL error is likely another issue.
2565 2587 '''
2566 2588 if not pycompat.iswindows:
2567 2589 raise error.Abort(_('certificate chain building is only possible on '
2568 2590 'Windows'))
2569 2591
2570 2592 if not source:
2571 2593 if not repo:
2572 2594 raise error.Abort(_("there is no Mercurial repository here, and no "
2573 2595 "server specified"))
2574 2596 source = "default"
2575 2597
2576 2598 source, branches = hg.parseurl(ui.expandpath(source))
2577 2599 url = util.url(source)
2578 2600
2579 2601 defaultport = {'https': 443, 'ssh': 22}
2580 2602 if url.scheme in defaultport:
2581 2603 try:
2582 2604 addr = (url.host, int(url.port or defaultport[url.scheme]))
2583 2605 except ValueError:
2584 2606 raise error.Abort(_("malformed port number in URL"))
2585 2607 else:
2586 2608 raise error.Abort(_("only https and ssh connections are supported"))
2587 2609
2588 2610 from . import win32
2589 2611
2590 2612 s = ssl.wrap_socket(socket.socket(), ssl_version=ssl.PROTOCOL_TLS,
2591 2613 cert_reqs=ssl.CERT_NONE, ca_certs=None)
2592 2614
2593 2615 try:
2594 2616 s.connect(addr)
2595 2617 cert = s.getpeercert(True)
2596 2618
2597 2619 ui.status(_('checking the certificate chain for %s\n') % url.host)
2598 2620
2599 2621 complete = win32.checkcertificatechain(cert, build=False)
2600 2622
2601 2623 if not complete:
2602 2624 ui.status(_('certificate chain is incomplete, updating... '))
2603 2625
2604 2626 if not win32.checkcertificatechain(cert):
2605 2627 ui.status(_('failed.\n'))
2606 2628 else:
2607 2629 ui.status(_('done.\n'))
2608 2630 else:
2609 2631 ui.status(_('full certificate chain is available\n'))
2610 2632 finally:
2611 2633 s.close()
2612 2634
2613 2635 @command('debugsub',
2614 2636 [('r', 'rev', '',
2615 2637 _('revision to check'), _('REV'))],
2616 2638 _('[-r REV] [REV]'))
2617 2639 def debugsub(ui, repo, rev=None):
2618 2640 ctx = scmutil.revsingle(repo, rev, None)
2619 2641 for k, v in sorted(ctx.substate.items()):
2620 2642 ui.write(('path %s\n') % k)
2621 2643 ui.write((' source %s\n') % v[0])
2622 2644 ui.write((' revision %s\n') % v[1])
2623 2645
2624 2646 @command('debugsuccessorssets',
2625 2647 [('', 'closest', False, _('return closest successors sets only'))],
2626 2648 _('[REV]'))
2627 2649 def debugsuccessorssets(ui, repo, *revs, **opts):
2628 2650 """show set of successors for revision
2629 2651
2630 2652 A successors set of changeset A is a consistent group of revisions that
2631 2653 succeed A. It contains non-obsolete changesets only unless closests
2632 2654 successors set is set.
2633 2655
2634 2656 In most cases a changeset A has a single successors set containing a single
2635 2657 successor (changeset A replaced by A').
2636 2658
2637 2659 A changeset that is made obsolete with no successors are called "pruned".
2638 2660 Such changesets have no successors sets at all.
2639 2661
2640 2662 A changeset that has been "split" will have a successors set containing
2641 2663 more than one successor.
2642 2664
2643 2665 A changeset that has been rewritten in multiple different ways is called
2644 2666 "divergent". Such changesets have multiple successor sets (each of which
2645 2667 may also be split, i.e. have multiple successors).
2646 2668
2647 2669 Results are displayed as follows::
2648 2670
2649 2671 <rev1>
2650 2672 <successors-1A>
2651 2673 <rev2>
2652 2674 <successors-2A>
2653 2675 <successors-2B1> <successors-2B2> <successors-2B3>
2654 2676
2655 2677 Here rev2 has two possible (i.e. divergent) successors sets. The first
2656 2678 holds one element, whereas the second holds three (i.e. the changeset has
2657 2679 been split).
2658 2680 """
2659 2681 # passed to successorssets caching computation from one call to another
2660 2682 cache = {}
2661 2683 ctx2str = bytes
2662 2684 node2str = short
2663 2685 for rev in scmutil.revrange(repo, revs):
2664 2686 ctx = repo[rev]
2665 2687 ui.write('%s\n'% ctx2str(ctx))
2666 2688 for succsset in obsutil.successorssets(repo, ctx.node(),
2667 2689 closest=opts[r'closest'],
2668 2690 cache=cache):
2669 2691 if succsset:
2670 2692 ui.write(' ')
2671 2693 ui.write(node2str(succsset[0]))
2672 2694 for node in succsset[1:]:
2673 2695 ui.write(' ')
2674 2696 ui.write(node2str(node))
2675 2697 ui.write('\n')
2676 2698
2677 2699 @command('debugtemplate',
2678 2700 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
2679 2701 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
2680 2702 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
2681 2703 optionalrepo=True)
2682 2704 def debugtemplate(ui, repo, tmpl, **opts):
2683 2705 """parse and apply a template
2684 2706
2685 2707 If -r/--rev is given, the template is processed as a log template and
2686 2708 applied to the given changesets. Otherwise, it is processed as a generic
2687 2709 template.
2688 2710
2689 2711 Use --verbose to print the parsed tree.
2690 2712 """
2691 2713 revs = None
2692 2714 if opts[r'rev']:
2693 2715 if repo is None:
2694 2716 raise error.RepoError(_('there is no Mercurial repository here '
2695 2717 '(.hg not found)'))
2696 2718 revs = scmutil.revrange(repo, opts[r'rev'])
2697 2719
2698 2720 props = {}
2699 2721 for d in opts[r'define']:
2700 2722 try:
2701 2723 k, v = (e.strip() for e in d.split('=', 1))
2702 2724 if not k or k == 'ui':
2703 2725 raise ValueError
2704 2726 props[k] = v
2705 2727 except ValueError:
2706 2728 raise error.Abort(_('malformed keyword definition: %s') % d)
2707 2729
2708 2730 if ui.verbose:
2709 2731 aliases = ui.configitems('templatealias')
2710 2732 tree = templater.parse(tmpl)
2711 2733 ui.note(templater.prettyformat(tree), '\n')
2712 2734 newtree = templater.expandaliases(tree, aliases)
2713 2735 if newtree != tree:
2714 2736 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
2715 2737
2716 2738 if revs is None:
2717 2739 tres = formatter.templateresources(ui, repo)
2718 2740 t = formatter.maketemplater(ui, tmpl, resources=tres)
2719 2741 if ui.verbose:
2720 2742 kwds, funcs = t.symbolsuseddefault()
2721 2743 ui.write(("* keywords: %s\n") % ', '.join(sorted(kwds)))
2722 2744 ui.write(("* functions: %s\n") % ', '.join(sorted(funcs)))
2723 2745 ui.write(t.renderdefault(props))
2724 2746 else:
2725 2747 displayer = logcmdutil.maketemplater(ui, repo, tmpl)
2726 2748 if ui.verbose:
2727 2749 kwds, funcs = displayer.t.symbolsuseddefault()
2728 2750 ui.write(("* keywords: %s\n") % ', '.join(sorted(kwds)))
2729 2751 ui.write(("* functions: %s\n") % ', '.join(sorted(funcs)))
2730 2752 for r in revs:
2731 2753 displayer.show(repo[r], **pycompat.strkwargs(props))
2732 2754 displayer.close()
2733 2755
2734 2756 @command('debuguigetpass', [
2735 2757 ('p', 'prompt', '', _('prompt text'), _('TEXT')),
2736 2758 ], _('[-p TEXT]'), norepo=True)
2737 2759 def debuguigetpass(ui, prompt=''):
2738 2760 """show prompt to type password"""
2739 2761 r = ui.getpass(prompt)
2740 2762 ui.write(('respose: %s\n') % r)
2741 2763
2742 2764 @command('debuguiprompt', [
2743 2765 ('p', 'prompt', '', _('prompt text'), _('TEXT')),
2744 2766 ], _('[-p TEXT]'), norepo=True)
2745 2767 def debuguiprompt(ui, prompt=''):
2746 2768 """show plain prompt"""
2747 2769 r = ui.prompt(prompt)
2748 2770 ui.write(('response: %s\n') % r)
2749 2771
2750 2772 @command('debugupdatecaches', [])
2751 2773 def debugupdatecaches(ui, repo, *pats, **opts):
2752 2774 """warm all known caches in the repository"""
2753 2775 with repo.wlock(), repo.lock():
2754 2776 repo.updatecaches(full=True)
2755 2777
2756 2778 @command('debugupgraderepo', [
2757 2779 ('o', 'optimize', [], _('extra optimization to perform'), _('NAME')),
2758 2780 ('', 'run', False, _('performs an upgrade')),
2759 2781 ('', 'backup', True, _('keep the old repository content around')),
2760 2782 ])
2761 2783 def debugupgraderepo(ui, repo, run=False, optimize=None, backup=True):
2762 2784 """upgrade a repository to use different features
2763 2785
2764 2786 If no arguments are specified, the repository is evaluated for upgrade
2765 2787 and a list of problems and potential optimizations is printed.
2766 2788
2767 2789 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
2768 2790 can be influenced via additional arguments. More details will be provided
2769 2791 by the command output when run without ``--run``.
2770 2792
2771 2793 During the upgrade, the repository will be locked and no writes will be
2772 2794 allowed.
2773 2795
2774 2796 At the end of the upgrade, the repository may not be readable while new
2775 2797 repository data is swapped in. This window will be as long as it takes to
2776 2798 rename some directories inside the ``.hg`` directory. On most machines, this
2777 2799 should complete almost instantaneously and the chances of a consumer being
2778 2800 unable to access the repository should be low.
2779 2801 """
2780 2802 return upgrade.upgraderepo(ui, repo, run=run, optimize=optimize,
2781 2803 backup=backup)
2782 2804
2783 2805 @command('debugwalk', cmdutil.walkopts, _('[OPTION]... [FILE]...'),
2784 2806 inferrepo=True)
2785 2807 def debugwalk(ui, repo, *pats, **opts):
2786 2808 """show how files match on given patterns"""
2787 2809 opts = pycompat.byteskwargs(opts)
2788 2810 m = scmutil.match(repo[None], pats, opts)
2789 2811 if ui.verbose:
2790 2812 ui.write(('* matcher:\n'), stringutil.prettyrepr(m), '\n')
2791 2813 items = list(repo[None].walk(m))
2792 2814 if not items:
2793 2815 return
2794 2816 f = lambda fn: fn
2795 2817 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
2796 2818 f = lambda fn: util.normpath(fn)
2797 2819 fmt = 'f %%-%ds %%-%ds %%s' % (
2798 2820 max([len(abs) for abs in items]),
2799 2821 max([len(repo.pathto(abs)) for abs in items]))
2800 2822 for abs in items:
2801 2823 line = fmt % (abs, f(repo.pathto(abs)), m.exact(abs) and 'exact' or '')
2802 2824 ui.write("%s\n" % line.rstrip())
2803 2825
2804 2826 @command('debugwhyunstable', [], _('REV'))
2805 2827 def debugwhyunstable(ui, repo, rev):
2806 2828 """explain instabilities of a changeset"""
2807 2829 for entry in obsutil.whyunstable(repo, scmutil.revsingle(repo, rev)):
2808 2830 dnodes = ''
2809 2831 if entry.get('divergentnodes'):
2810 2832 dnodes = ' '.join('%s (%s)' % (ctx.hex(), ctx.phasestr())
2811 2833 for ctx in entry['divergentnodes']) + ' '
2812 2834 ui.write('%s: %s%s %s\n' % (entry['instability'], dnodes,
2813 2835 entry['reason'], entry['node']))
2814 2836
2815 2837 @command('debugwireargs',
2816 2838 [('', 'three', '', 'three'),
2817 2839 ('', 'four', '', 'four'),
2818 2840 ('', 'five', '', 'five'),
2819 2841 ] + cmdutil.remoteopts,
2820 2842 _('REPO [OPTIONS]... [ONE [TWO]]'),
2821 2843 norepo=True)
2822 2844 def debugwireargs(ui, repopath, *vals, **opts):
2823 2845 opts = pycompat.byteskwargs(opts)
2824 2846 repo = hg.peer(ui, opts, repopath)
2825 2847 for opt in cmdutil.remoteopts:
2826 2848 del opts[opt[1]]
2827 2849 args = {}
2828 2850 for k, v in opts.iteritems():
2829 2851 if v:
2830 2852 args[k] = v
2831 2853 args = pycompat.strkwargs(args)
2832 2854 # run twice to check that we don't mess up the stream for the next command
2833 2855 res1 = repo.debugwireargs(*vals, **args)
2834 2856 res2 = repo.debugwireargs(*vals, **args)
2835 2857 ui.write("%s\n" % res1)
2836 2858 if res1 != res2:
2837 2859 ui.warn("%s\n" % res2)
2838 2860
2839 2861 def _parsewirelangblocks(fh):
2840 2862 activeaction = None
2841 2863 blocklines = []
2842 2864 lastindent = 0
2843 2865
2844 2866 for line in fh:
2845 2867 line = line.rstrip()
2846 2868 if not line:
2847 2869 continue
2848 2870
2849 2871 if line.startswith(b'#'):
2850 2872 continue
2851 2873
2852 2874 if not line.startswith(b' '):
2853 2875 # New block. Flush previous one.
2854 2876 if activeaction:
2855 2877 yield activeaction, blocklines
2856 2878
2857 2879 activeaction = line
2858 2880 blocklines = []
2859 2881 lastindent = 0
2860 2882 continue
2861 2883
2862 2884 # Else we start with an indent.
2863 2885
2864 2886 if not activeaction:
2865 2887 raise error.Abort(_('indented line outside of block'))
2866 2888
2867 2889 indent = len(line) - len(line.lstrip())
2868 2890
2869 2891 # If this line is indented more than the last line, concatenate it.
2870 2892 if indent > lastindent and blocklines:
2871 2893 blocklines[-1] += line.lstrip()
2872 2894 else:
2873 2895 blocklines.append(line)
2874 2896 lastindent = indent
2875 2897
2876 2898 # Flush last block.
2877 2899 if activeaction:
2878 2900 yield activeaction, blocklines
2879 2901
2880 2902 @command('debugwireproto',
2881 2903 [
2882 2904 ('', 'localssh', False, _('start an SSH server for this repo')),
2883 2905 ('', 'peer', '', _('construct a specific version of the peer')),
2884 2906 ('', 'noreadstderr', False, _('do not read from stderr of the remote')),
2885 2907 ('', 'nologhandshake', False,
2886 2908 _('do not log I/O related to the peer handshake')),
2887 2909 ] + cmdutil.remoteopts,
2888 2910 _('[PATH]'),
2889 2911 optionalrepo=True)
2890 2912 def debugwireproto(ui, repo, path=None, **opts):
2891 2913 """send wire protocol commands to a server
2892 2914
2893 2915 This command can be used to issue wire protocol commands to remote
2894 2916 peers and to debug the raw data being exchanged.
2895 2917
2896 2918 ``--localssh`` will start an SSH server against the current repository
2897 2919 and connect to that. By default, the connection will perform a handshake
2898 2920 and establish an appropriate peer instance.
2899 2921
2900 2922 ``--peer`` can be used to bypass the handshake protocol and construct a
2901 2923 peer instance using the specified class type. Valid values are ``raw``,
2902 2924 ``http2``, ``ssh1``, and ``ssh2``. ``raw`` instances only allow sending
2903 2925 raw data payloads and don't support higher-level command actions.
2904 2926
2905 2927 ``--noreadstderr`` can be used to disable automatic reading from stderr
2906 2928 of the peer (for SSH connections only). Disabling automatic reading of
2907 2929 stderr is useful for making output more deterministic.
2908 2930
2909 2931 Commands are issued via a mini language which is specified via stdin.
2910 2932 The language consists of individual actions to perform. An action is
2911 2933 defined by a block. A block is defined as a line with no leading
2912 2934 space followed by 0 or more lines with leading space. Blocks are
2913 2935 effectively a high-level command with additional metadata.
2914 2936
2915 2937 Lines beginning with ``#`` are ignored.
2916 2938
2917 2939 The following sections denote available actions.
2918 2940
2919 2941 raw
2920 2942 ---
2921 2943
2922 2944 Send raw data to the server.
2923 2945
2924 2946 The block payload contains the raw data to send as one atomic send
2925 2947 operation. The data may not actually be delivered in a single system
2926 2948 call: it depends on the abilities of the transport being used.
2927 2949
2928 2950 Each line in the block is de-indented and concatenated. Then, that
2929 2951 value is evaluated as a Python b'' literal. This allows the use of
2930 2952 backslash escaping, etc.
2931 2953
2932 2954 raw+
2933 2955 ----
2934 2956
2935 2957 Behaves like ``raw`` except flushes output afterwards.
2936 2958
2937 2959 command <X>
2938 2960 -----------
2939 2961
2940 2962 Send a request to run a named command, whose name follows the ``command``
2941 2963 string.
2942 2964
2943 2965 Arguments to the command are defined as lines in this block. The format of
2944 2966 each line is ``<key> <value>``. e.g.::
2945 2967
2946 2968 command listkeys
2947 2969 namespace bookmarks
2948 2970
2949 2971 If the value begins with ``eval:``, it will be interpreted as a Python
2950 2972 literal expression. Otherwise values are interpreted as Python b'' literals.
2951 2973 This allows sending complex types and encoding special byte sequences via
2952 2974 backslash escaping.
2953 2975
2954 2976 The following arguments have special meaning:
2955 2977
2956 2978 ``PUSHFILE``
2957 2979 When defined, the *push* mechanism of the peer will be used instead
2958 2980 of the static request-response mechanism and the content of the
2959 2981 file specified in the value of this argument will be sent as the
2960 2982 command payload.
2961 2983
2962 2984 This can be used to submit a local bundle file to the remote.
2963 2985
2964 2986 batchbegin
2965 2987 ----------
2966 2988
2967 2989 Instruct the peer to begin a batched send.
2968 2990
2969 2991 All ``command`` blocks are queued for execution until the next
2970 2992 ``batchsubmit`` block.
2971 2993
2972 2994 batchsubmit
2973 2995 -----------
2974 2996
2975 2997 Submit previously queued ``command`` blocks as a batch request.
2976 2998
2977 2999 This action MUST be paired with a ``batchbegin`` action.
2978 3000
2979 3001 httprequest <method> <path>
2980 3002 ---------------------------
2981 3003
2982 3004 (HTTP peer only)
2983 3005
2984 3006 Send an HTTP request to the peer.
2985 3007
2986 3008 The HTTP request line follows the ``httprequest`` action. e.g. ``GET /foo``.
2987 3009
2988 3010 Arguments of the form ``<key>: <value>`` are interpreted as HTTP request
2989 3011 headers to add to the request. e.g. ``Accept: foo``.
2990 3012
2991 3013 The following arguments are special:
2992 3014
2993 3015 ``BODYFILE``
2994 3016 The content of the file defined as the value to this argument will be
2995 3017 transferred verbatim as the HTTP request body.
2996 3018
2997 3019 ``frame <type> <flags> <payload>``
2998 3020 Send a unified protocol frame as part of the request body.
2999 3021
3000 3022 All frames will be collected and sent as the body to the HTTP
3001 3023 request.
3002 3024
3003 3025 close
3004 3026 -----
3005 3027
3006 3028 Close the connection to the server.
3007 3029
3008 3030 flush
3009 3031 -----
3010 3032
3011 3033 Flush data written to the server.
3012 3034
3013 3035 readavailable
3014 3036 -------------
3015 3037
3016 3038 Close the write end of the connection and read all available data from
3017 3039 the server.
3018 3040
3019 3041 If the connection to the server encompasses multiple pipes, we poll both
3020 3042 pipes and read available data.
3021 3043
3022 3044 readline
3023 3045 --------
3024 3046
3025 3047 Read a line of output from the server. If there are multiple output
3026 3048 pipes, reads only the main pipe.
3027 3049
3028 3050 ereadline
3029 3051 ---------
3030 3052
3031 3053 Like ``readline``, but read from the stderr pipe, if available.
3032 3054
3033 3055 read <X>
3034 3056 --------
3035 3057
3036 3058 ``read()`` N bytes from the server's main output pipe.
3037 3059
3038 3060 eread <X>
3039 3061 ---------
3040 3062
3041 3063 ``read()`` N bytes from the server's stderr pipe, if available.
3042 3064
3043 3065 Specifying Unified Frame-Based Protocol Frames
3044 3066 ----------------------------------------------
3045 3067
3046 3068 It is possible to emit a *Unified Frame-Based Protocol* by using special
3047 3069 syntax.
3048 3070
3049 3071 A frame is composed as a type, flags, and payload. These can be parsed
3050 3072 from a string of the form:
3051 3073
3052 3074 <request-id> <stream-id> <stream-flags> <type> <flags> <payload>
3053 3075
3054 3076 ``request-id`` and ``stream-id`` are integers defining the request and
3055 3077 stream identifiers.
3056 3078
3057 3079 ``type`` can be an integer value for the frame type or the string name
3058 3080 of the type. The strings are defined in ``wireprotoframing.py``. e.g.
3059 3081 ``command-name``.
3060 3082
3061 3083 ``stream-flags`` and ``flags`` are a ``|`` delimited list of flag
3062 3084 components. Each component (and there can be just one) can be an integer
3063 3085 or a flag name for stream flags or frame flags, respectively. Values are
3064 3086 resolved to integers and then bitwise OR'd together.
3065 3087
3066 3088 ``payload`` represents the raw frame payload. If it begins with
3067 3089 ``cbor:``, the following string is evaluated as Python code and the
3068 3090 resulting object is fed into a CBOR encoder. Otherwise it is interpreted
3069 3091 as a Python byte string literal.
3070 3092 """
3071 3093 opts = pycompat.byteskwargs(opts)
3072 3094
3073 3095 if opts['localssh'] and not repo:
3074 3096 raise error.Abort(_('--localssh requires a repository'))
3075 3097
3076 3098 if opts['peer'] and opts['peer'] not in ('raw', 'http2', 'ssh1', 'ssh2'):
3077 3099 raise error.Abort(_('invalid value for --peer'),
3078 3100 hint=_('valid values are "raw", "ssh1", and "ssh2"'))
3079 3101
3080 3102 if path and opts['localssh']:
3081 3103 raise error.Abort(_('cannot specify --localssh with an explicit '
3082 3104 'path'))
3083 3105
3084 3106 if ui.interactive():
3085 3107 ui.write(_('(waiting for commands on stdin)\n'))
3086 3108
3087 3109 blocks = list(_parsewirelangblocks(ui.fin))
3088 3110
3089 3111 proc = None
3090 3112 stdin = None
3091 3113 stdout = None
3092 3114 stderr = None
3093 3115 opener = None
3094 3116
3095 3117 if opts['localssh']:
3096 3118 # We start the SSH server in its own process so there is process
3097 3119 # separation. This prevents a whole class of potential bugs around
3098 3120 # shared state from interfering with server operation.
3099 3121 args = procutil.hgcmd() + [
3100 3122 '-R', repo.root,
3101 3123 'debugserve', '--sshstdio',
3102 3124 ]
3103 3125 proc = subprocess.Popen(pycompat.rapply(procutil.tonativestr, args),
3104 3126 stdin=subprocess.PIPE,
3105 3127 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
3106 3128 bufsize=0)
3107 3129
3108 3130 stdin = proc.stdin
3109 3131 stdout = proc.stdout
3110 3132 stderr = proc.stderr
3111 3133
3112 3134 # We turn the pipes into observers so we can log I/O.
3113 3135 if ui.verbose or opts['peer'] == 'raw':
3114 3136 stdin = util.makeloggingfileobject(ui, proc.stdin, b'i',
3115 3137 logdata=True)
3116 3138 stdout = util.makeloggingfileobject(ui, proc.stdout, b'o',
3117 3139 logdata=True)
3118 3140 stderr = util.makeloggingfileobject(ui, proc.stderr, b'e',
3119 3141 logdata=True)
3120 3142
3121 3143 # --localssh also implies the peer connection settings.
3122 3144
3123 3145 url = 'ssh://localserver'
3124 3146 autoreadstderr = not opts['noreadstderr']
3125 3147
3126 3148 if opts['peer'] == 'ssh1':
3127 3149 ui.write(_('creating ssh peer for wire protocol version 1\n'))
3128 3150 peer = sshpeer.sshv1peer(ui, url, proc, stdin, stdout, stderr,
3129 3151 None, autoreadstderr=autoreadstderr)
3130 3152 elif opts['peer'] == 'ssh2':
3131 3153 ui.write(_('creating ssh peer for wire protocol version 2\n'))
3132 3154 peer = sshpeer.sshv2peer(ui, url, proc, stdin, stdout, stderr,
3133 3155 None, autoreadstderr=autoreadstderr)
3134 3156 elif opts['peer'] == 'raw':
3135 3157 ui.write(_('using raw connection to peer\n'))
3136 3158 peer = None
3137 3159 else:
3138 3160 ui.write(_('creating ssh peer from handshake results\n'))
3139 3161 peer = sshpeer.makepeer(ui, url, proc, stdin, stdout, stderr,
3140 3162 autoreadstderr=autoreadstderr)
3141 3163
3142 3164 elif path:
3143 3165 # We bypass hg.peer() so we can proxy the sockets.
3144 3166 # TODO consider not doing this because we skip
3145 3167 # ``hg.wirepeersetupfuncs`` and potentially other useful functionality.
3146 3168 u = util.url(path)
3147 3169 if u.scheme != 'http':
3148 3170 raise error.Abort(_('only http:// paths are currently supported'))
3149 3171
3150 3172 url, authinfo = u.authinfo()
3151 3173 openerargs = {
3152 3174 r'useragent': b'Mercurial debugwireproto',
3153 3175 }
3154 3176
3155 3177 # Turn pipes/sockets into observers so we can log I/O.
3156 3178 if ui.verbose:
3157 3179 openerargs.update({
3158 3180 r'loggingfh': ui,
3159 3181 r'loggingname': b's',
3160 3182 r'loggingopts': {
3161 3183 r'logdata': True,
3162 3184 r'logdataapis': False,
3163 3185 },
3164 3186 })
3165 3187
3166 3188 if ui.debugflag:
3167 3189 openerargs[r'loggingopts'][r'logdataapis'] = True
3168 3190
3169 3191 # Don't send default headers when in raw mode. This allows us to
3170 3192 # bypass most of the behavior of our URL handling code so we can
3171 3193 # have near complete control over what's sent on the wire.
3172 3194 if opts['peer'] == 'raw':
3173 3195 openerargs[r'sendaccept'] = False
3174 3196
3175 3197 opener = urlmod.opener(ui, authinfo, **openerargs)
3176 3198
3177 3199 if opts['peer'] == 'http2':
3178 3200 ui.write(_('creating http peer for wire protocol version 2\n'))
3179 3201 # We go through makepeer() because we need an API descriptor for
3180 3202 # the peer instance to be useful.
3181 3203 with ui.configoverride({
3182 3204 ('experimental', 'httppeer.advertise-v2'): True}):
3183 3205 if opts['nologhandshake']:
3184 3206 ui.pushbuffer()
3185 3207
3186 3208 peer = httppeer.makepeer(ui, path, opener=opener)
3187 3209
3188 3210 if opts['nologhandshake']:
3189 3211 ui.popbuffer()
3190 3212
3191 3213 if not isinstance(peer, httppeer.httpv2peer):
3192 3214 raise error.Abort(_('could not instantiate HTTP peer for '
3193 3215 'wire protocol version 2'),
3194 3216 hint=_('the server may not have the feature '
3195 3217 'enabled or is not allowing this '
3196 3218 'client version'))
3197 3219
3198 3220 elif opts['peer'] == 'raw':
3199 3221 ui.write(_('using raw connection to peer\n'))
3200 3222 peer = None
3201 3223 elif opts['peer']:
3202 3224 raise error.Abort(_('--peer %s not supported with HTTP peers') %
3203 3225 opts['peer'])
3204 3226 else:
3205 3227 peer = httppeer.makepeer(ui, path, opener=opener)
3206 3228
3207 3229 # We /could/ populate stdin/stdout with sock.makefile()...
3208 3230 else:
3209 3231 raise error.Abort(_('unsupported connection configuration'))
3210 3232
3211 3233 batchedcommands = None
3212 3234
3213 3235 # Now perform actions based on the parsed wire language instructions.
3214 3236 for action, lines in blocks:
3215 3237 if action in ('raw', 'raw+'):
3216 3238 if not stdin:
3217 3239 raise error.Abort(_('cannot call raw/raw+ on this peer'))
3218 3240
3219 3241 # Concatenate the data together.
3220 3242 data = ''.join(l.lstrip() for l in lines)
3221 3243 data = stringutil.unescapestr(data)
3222 3244 stdin.write(data)
3223 3245
3224 3246 if action == 'raw+':
3225 3247 stdin.flush()
3226 3248 elif action == 'flush':
3227 3249 if not stdin:
3228 3250 raise error.Abort(_('cannot call flush on this peer'))
3229 3251 stdin.flush()
3230 3252 elif action.startswith('command'):
3231 3253 if not peer:
3232 3254 raise error.Abort(_('cannot send commands unless peer instance '
3233 3255 'is available'))
3234 3256
3235 3257 command = action.split(' ', 1)[1]
3236 3258
3237 3259 args = {}
3238 3260 for line in lines:
3239 3261 # We need to allow empty values.
3240 3262 fields = line.lstrip().split(' ', 1)
3241 3263 if len(fields) == 1:
3242 3264 key = fields[0]
3243 3265 value = ''
3244 3266 else:
3245 3267 key, value = fields
3246 3268
3247 3269 if value.startswith('eval:'):
3248 3270 value = stringutil.evalpythonliteral(value[5:])
3249 3271 else:
3250 3272 value = stringutil.unescapestr(value)
3251 3273
3252 3274 args[key] = value
3253 3275
3254 3276 if batchedcommands is not None:
3255 3277 batchedcommands.append((command, args))
3256 3278 continue
3257 3279
3258 3280 ui.status(_('sending %s command\n') % command)
3259 3281
3260 3282 if 'PUSHFILE' in args:
3261 3283 with open(args['PUSHFILE'], r'rb') as fh:
3262 3284 del args['PUSHFILE']
3263 3285 res, output = peer._callpush(command, fh,
3264 3286 **pycompat.strkwargs(args))
3265 3287 ui.status(_('result: %s\n') % stringutil.escapestr(res))
3266 3288 ui.status(_('remote output: %s\n') %
3267 3289 stringutil.escapestr(output))
3268 3290 else:
3269 3291 with peer.commandexecutor() as e:
3270 3292 res = e.callcommand(command, args).result()
3271 3293
3272 3294 if isinstance(res, wireprotov2peer.commandresponse):
3273 3295 val = res.objects()
3274 3296 ui.status(_('response: %s\n') %
3275 3297 stringutil.pprint(val, bprefix=True, indent=2))
3276 3298 else:
3277 3299 ui.status(_('response: %s\n') %
3278 3300 stringutil.pprint(res, bprefix=True, indent=2))
3279 3301
3280 3302 elif action == 'batchbegin':
3281 3303 if batchedcommands is not None:
3282 3304 raise error.Abort(_('nested batchbegin not allowed'))
3283 3305
3284 3306 batchedcommands = []
3285 3307 elif action == 'batchsubmit':
3286 3308 # There is a batching API we could go through. But it would be
3287 3309 # difficult to normalize requests into function calls. It is easier
3288 3310 # to bypass this layer and normalize to commands + args.
3289 3311 ui.status(_('sending batch with %d sub-commands\n') %
3290 3312 len(batchedcommands))
3291 3313 for i, chunk in enumerate(peer._submitbatch(batchedcommands)):
3292 3314 ui.status(_('response #%d: %s\n') %
3293 3315 (i, stringutil.escapestr(chunk)))
3294 3316
3295 3317 batchedcommands = None
3296 3318
3297 3319 elif action.startswith('httprequest '):
3298 3320 if not opener:
3299 3321 raise error.Abort(_('cannot use httprequest without an HTTP '
3300 3322 'peer'))
3301 3323
3302 3324 request = action.split(' ', 2)
3303 3325 if len(request) != 3:
3304 3326 raise error.Abort(_('invalid httprequest: expected format is '
3305 3327 '"httprequest <method> <path>'))
3306 3328
3307 3329 method, httppath = request[1:]
3308 3330 headers = {}
3309 3331 body = None
3310 3332 frames = []
3311 3333 for line in lines:
3312 3334 line = line.lstrip()
3313 3335 m = re.match(b'^([a-zA-Z0-9_-]+): (.*)$', line)
3314 3336 if m:
3315 3337 # Headers need to use native strings.
3316 3338 key = pycompat.strurl(m.group(1))
3317 3339 value = pycompat.strurl(m.group(2))
3318 3340 headers[key] = value
3319 3341 continue
3320 3342
3321 3343 if line.startswith(b'BODYFILE '):
3322 3344 with open(line.split(b' ', 1), 'rb') as fh:
3323 3345 body = fh.read()
3324 3346 elif line.startswith(b'frame '):
3325 3347 frame = wireprotoframing.makeframefromhumanstring(
3326 3348 line[len(b'frame '):])
3327 3349
3328 3350 frames.append(frame)
3329 3351 else:
3330 3352 raise error.Abort(_('unknown argument to httprequest: %s') %
3331 3353 line)
3332 3354
3333 3355 url = path + httppath
3334 3356
3335 3357 if frames:
3336 3358 body = b''.join(bytes(f) for f in frames)
3337 3359
3338 3360 req = urlmod.urlreq.request(pycompat.strurl(url), body, headers)
3339 3361
3340 3362 # urllib.Request insists on using has_data() as a proxy for
3341 3363 # determining the request method. Override that to use our
3342 3364 # explicitly requested method.
3343 3365 req.get_method = lambda: pycompat.sysstr(method)
3344 3366
3345 3367 try:
3346 3368 res = opener.open(req)
3347 3369 body = res.read()
3348 3370 except util.urlerr.urlerror as e:
3349 3371 # read() method must be called, but only exists in Python 2
3350 3372 getattr(e, 'read', lambda: None)()
3351 3373 continue
3352 3374
3353 3375 ct = res.headers.get(r'Content-Type')
3354 3376 if ct == r'application/mercurial-cbor':
3355 3377 ui.write(_('cbor> %s\n') %
3356 3378 stringutil.pprint(cborutil.decodeall(body),
3357 3379 bprefix=True,
3358 3380 indent=2))
3359 3381
3360 3382 elif action == 'close':
3361 3383 peer.close()
3362 3384 elif action == 'readavailable':
3363 3385 if not stdout or not stderr:
3364 3386 raise error.Abort(_('readavailable not available on this peer'))
3365 3387
3366 3388 stdin.close()
3367 3389 stdout.read()
3368 3390 stderr.read()
3369 3391
3370 3392 elif action == 'readline':
3371 3393 if not stdout:
3372 3394 raise error.Abort(_('readline not available on this peer'))
3373 3395 stdout.readline()
3374 3396 elif action == 'ereadline':
3375 3397 if not stderr:
3376 3398 raise error.Abort(_('ereadline not available on this peer'))
3377 3399 stderr.readline()
3378 3400 elif action.startswith('read '):
3379 3401 count = int(action.split(' ', 1)[1])
3380 3402 if not stdout:
3381 3403 raise error.Abort(_('read not available on this peer'))
3382 3404 stdout.read(count)
3383 3405 elif action.startswith('eread '):
3384 3406 count = int(action.split(' ', 1)[1])
3385 3407 if not stderr:
3386 3408 raise error.Abort(_('eread not available on this peer'))
3387 3409 stderr.read(count)
3388 3410 else:
3389 3411 raise error.Abort(_('unknown action: %s') % action)
3390 3412
3391 3413 if batchedcommands is not None:
3392 3414 raise error.Abort(_('unclosed "batchbegin" request'))
3393 3415
3394 3416 if peer:
3395 3417 peer.close()
3396 3418
3397 3419 if proc:
3398 3420 proc.kill()
@@ -1,410 +1,414 b''
1 1 Show all commands except debug commands
2 2 $ hg debugcomplete
3 3 add
4 4 addremove
5 5 annotate
6 6 archive
7 7 backout
8 8 bisect
9 9 bookmarks
10 10 branch
11 11 branches
12 12 bundle
13 13 cat
14 14 clone
15 15 commit
16 16 config
17 17 copy
18 18 diff
19 19 export
20 20 files
21 21 forget
22 22 graft
23 23 grep
24 24 heads
25 25 help
26 26 identify
27 27 import
28 28 incoming
29 29 init
30 30 locate
31 31 log
32 32 manifest
33 33 merge
34 34 outgoing
35 35 parents
36 36 paths
37 37 phase
38 38 pull
39 39 push
40 40 recover
41 41 remove
42 42 rename
43 43 resolve
44 44 revert
45 45 rollback
46 46 root
47 47 serve
48 48 status
49 49 summary
50 50 tag
51 51 tags
52 52 tip
53 53 unbundle
54 54 update
55 55 verify
56 56 version
57 57
58 58 Show all commands that start with "a"
59 59 $ hg debugcomplete a
60 60 add
61 61 addremove
62 62 annotate
63 63 archive
64 64
65 65 Do not show debug commands if there are other candidates
66 66 $ hg debugcomplete d
67 67 diff
68 68
69 69 Show debug commands if there are no other candidates
70 70 $ hg debugcomplete debug
71 71 debugancestor
72 72 debugapplystreamclonebundle
73 73 debugbuilddag
74 74 debugbundle
75 75 debugcapabilities
76 76 debugcheckstate
77 77 debugcolor
78 78 debugcommands
79 79 debugcomplete
80 80 debugconfig
81 81 debugcreatestreamclonebundle
82 82 debugdag
83 83 debugdata
84 84 debugdate
85 85 debugdeltachain
86 86 debugdirstate
87 87 debugdiscovery
88 88 debugdownload
89 89 debugextensions
90 90 debugfileset
91 91 debugformat
92 92 debugfsinfo
93 93 debuggetbundle
94 94 debugignore
95 95 debugindex
96 96 debugindexdot
97 97 debugindexstats
98 98 debuginstall
99 99 debugknown
100 100 debuglabelcomplete
101 101 debuglocks
102 102 debugmanifestfulltextcache
103 103 debugmergestate
104 104 debugnamecomplete
105 105 debugobsolete
106 debugp1copies
107 debugp2copies
106 108 debugpathcomplete
107 109 debugpathcopies
108 110 debugpeer
109 111 debugpickmergetool
110 112 debugpushkey
111 113 debugpvec
112 114 debugrebuilddirstate
113 115 debugrebuildfncache
114 116 debugrename
115 117 debugrevlog
116 118 debugrevlogindex
117 119 debugrevspec
118 120 debugserve
119 121 debugsetparents
120 122 debugssl
121 123 debugsub
122 124 debugsuccessorssets
123 125 debugtemplate
124 126 debuguigetpass
125 127 debuguiprompt
126 128 debugupdatecaches
127 129 debugupgraderepo
128 130 debugwalk
129 131 debugwhyunstable
130 132 debugwireargs
131 133 debugwireproto
132 134
133 135 Do not show the alias of a debug command if there are other candidates
134 136 (this should hide rawcommit)
135 137 $ hg debugcomplete r
136 138 recover
137 139 remove
138 140 rename
139 141 resolve
140 142 revert
141 143 rollback
142 144 root
143 145 Show the alias of a debug command if there are no other candidates
144 146 $ hg debugcomplete rawc
145 147
146 148
147 149 Show the global options
148 150 $ hg debugcomplete --options | sort
149 151 --color
150 152 --config
151 153 --cwd
152 154 --debug
153 155 --debugger
154 156 --encoding
155 157 --encodingmode
156 158 --help
157 159 --hidden
158 160 --noninteractive
159 161 --pager
160 162 --profile
161 163 --quiet
162 164 --repository
163 165 --time
164 166 --traceback
165 167 --verbose
166 168 --version
167 169 -R
168 170 -h
169 171 -q
170 172 -v
171 173 -y
172 174
173 175 Show the options for the "serve" command
174 176 $ hg debugcomplete --options serve | sort
175 177 --accesslog
176 178 --address
177 179 --certificate
178 180 --cmdserver
179 181 --color
180 182 --config
181 183 --cwd
182 184 --daemon
183 185 --daemon-postexec
184 186 --debug
185 187 --debugger
186 188 --encoding
187 189 --encodingmode
188 190 --errorlog
189 191 --help
190 192 --hidden
191 193 --ipv6
192 194 --name
193 195 --noninteractive
194 196 --pager
195 197 --pid-file
196 198 --port
197 199 --prefix
198 200 --print-url
199 201 --profile
200 202 --quiet
201 203 --repository
202 204 --stdio
203 205 --style
204 206 --subrepos
205 207 --templates
206 208 --time
207 209 --traceback
208 210 --verbose
209 211 --version
210 212 --web-conf
211 213 -6
212 214 -A
213 215 -E
214 216 -R
215 217 -S
216 218 -a
217 219 -d
218 220 -h
219 221 -n
220 222 -p
221 223 -q
222 224 -t
223 225 -v
224 226 -y
225 227
226 228 Show an error if we use --options with an ambiguous abbreviation
227 229 $ hg debugcomplete --options s
228 230 hg: command 's' is ambiguous:
229 231 serve showconfig status summary
230 232 [255]
231 233
232 234 Show all commands + options
233 235 $ hg debugcommands
234 236 add: include, exclude, subrepos, dry-run
235 237 addremove: similarity, subrepos, include, exclude, dry-run
236 238 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
237 239 archive: no-decode, prefix, rev, type, subrepos, include, exclude
238 240 backout: merge, commit, no-commit, parent, rev, edit, tool, include, exclude, message, logfile, date, user
239 241 bisect: reset, good, bad, skip, extend, command, noupdate
240 242 bookmarks: force, rev, delete, rename, inactive, list, template
241 243 branch: force, clean, rev
242 244 branches: active, closed, rev, template
243 245 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
244 246 cat: output, rev, decode, include, exclude, template
245 247 clone: noupdate, updaterev, rev, branch, pull, uncompressed, stream, ssh, remotecmd, insecure
246 248 commit: addremove, close-branch, amend, secret, edit, interactive, include, exclude, message, logfile, date, user, subrepos
247 249 config: untrusted, edit, local, global, template
248 250 copy: after, force, include, exclude, dry-run
249 251 debugancestor:
250 252 debugapplystreamclonebundle:
251 253 debugbuilddag: mergeable-file, overwritten-file, new-file
252 254 debugbundle: all, part-type, spec
253 255 debugcapabilities:
254 256 debugcheckstate:
255 257 debugcolor: style
256 258 debugcommands:
257 259 debugcomplete: options
258 260 debugcreatestreamclonebundle:
259 261 debugdag: tags, branches, dots, spaces
260 262 debugdata: changelog, manifest, dir
261 263 debugdate: extended
262 264 debugdeltachain: changelog, manifest, dir, template
263 265 debugdirstate: nodates, dates, datesort
264 266 debugdiscovery: old, nonheads, rev, ssh, remotecmd, insecure
265 267 debugdownload: output
266 268 debugextensions: template
267 269 debugfileset: rev, all-files, show-matcher, show-stage
268 270 debugformat: template
269 271 debugfsinfo:
270 272 debuggetbundle: head, common, type
271 273 debugignore:
272 274 debugindex: changelog, manifest, dir, template
273 275 debugindexdot: changelog, manifest, dir
274 276 debugindexstats:
275 277 debuginstall: template
276 278 debugknown:
277 279 debuglabelcomplete:
278 280 debuglocks: force-lock, force-wlock, set-lock, set-wlock
279 281 debugmanifestfulltextcache: clear, add
280 282 debugmergestate:
281 283 debugnamecomplete:
282 284 debugobsolete: flags, record-parents, rev, exclusive, index, delete, date, user, template
285 debugp1copies: rev
286 debugp2copies: rev
283 287 debugpathcomplete: full, normal, added, removed
284 288 debugpathcopies: include, exclude
285 289 debugpeer:
286 290 debugpickmergetool: rev, changedelete, include, exclude, tool
287 291 debugpushkey:
288 292 debugpvec:
289 293 debugrebuilddirstate: rev, minimal
290 294 debugrebuildfncache:
291 295 debugrename: rev
292 296 debugrevlog: changelog, manifest, dir, dump
293 297 debugrevlogindex: changelog, manifest, dir, format
294 298 debugrevspec: optimize, show-revs, show-set, show-stage, no-optimized, verify-optimized
295 299 debugserve: sshstdio, logiofd, logiofile
296 300 debugsetparents:
297 301 debugssl:
298 302 debugsub: rev
299 303 debugsuccessorssets: closest
300 304 debugtemplate: rev, define
301 305 debuguigetpass: prompt
302 306 debuguiprompt: prompt
303 307 debugupdatecaches:
304 308 debugupgraderepo: optimize, run, backup
305 309 debugwalk: include, exclude
306 310 debugwhyunstable:
307 311 debugwireargs: three, four, five, ssh, remotecmd, insecure
308 312 debugwireproto: localssh, peer, noreadstderr, nologhandshake, ssh, remotecmd, insecure
309 313 diff: rev, 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
310 314 export: bookmark, output, switch-parent, rev, text, git, binary, nodates, template
311 315 files: rev, print0, include, exclude, template, subrepos
312 316 forget: interactive, include, exclude, dry-run
313 317 graft: rev, base, continue, stop, abort, edit, log, no-commit, force, currentdate, currentuser, date, user, tool, dry-run
314 318 grep: print0, all, diff, text, follow, ignore-case, files-with-matches, line-number, rev, all-files, user, date, template, include, exclude
315 319 heads: rev, topo, active, closed, style, template
316 320 help: extension, command, keyword, system
317 321 identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure, template
318 322 import: strip, base, edit, force, no-commit, bypass, partial, exact, prefix, import-branch, message, logfile, date, user, similarity
319 323 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
320 324 init: ssh, remotecmd, insecure
321 325 locate: rev, print0, fullpath, include, exclude
322 326 log: follow, follow-first, date, copies, keyword, rev, line-range, removed, only-merges, user, only-branch, branch, prune, patch, git, limit, no-merges, stat, graph, style, template, include, exclude
323 327 manifest: rev, all, template
324 328 merge: force, rev, preview, abort, tool
325 329 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
326 330 parents: rev, style, template
327 331 paths: template
328 332 phase: public, draft, secret, force, rev
329 333 pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
330 334 push: force, rev, bookmark, branch, new-branch, pushvars, publish, ssh, remotecmd, insecure
331 335 recover:
332 336 remove: after, force, subrepos, include, exclude, dry-run
333 337 rename: after, force, include, exclude, dry-run
334 338 resolve: all, list, mark, unmark, no-status, re-merge, tool, include, exclude, template
335 339 revert: all, date, rev, no-backup, interactive, include, exclude, dry-run
336 340 rollback: dry-run, force
337 341 root:
338 342 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
339 343 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, terse, copies, print0, rev, change, include, exclude, subrepos, template
340 344 summary: remote
341 345 tag: force, local, rev, remove, edit, message, date, user
342 346 tags: template
343 347 tip: patch, git, style, template
344 348 unbundle: update
345 349 update: clean, check, merge, date, rev, tool
346 350 verify:
347 351 version: template
348 352
349 353 $ hg init a
350 354 $ cd a
351 355 $ echo fee > fee
352 356 $ hg ci -q -Amfee
353 357 $ hg tag fee
354 358 $ mkdir fie
355 359 $ echo dead > fie/dead
356 360 $ echo live > fie/live
357 361 $ hg bookmark fo
358 362 $ hg branch -q fie
359 363 $ hg ci -q -Amfie
360 364 $ echo fo > fo
361 365 $ hg branch -qf default
362 366 $ hg ci -q -Amfo
363 367 $ echo Fum > Fum
364 368 $ hg ci -q -AmFum
365 369 $ hg bookmark Fum
366 370
367 371 Test debugpathcomplete
368 372
369 373 $ hg debugpathcomplete f
370 374 fee
371 375 fie
372 376 fo
373 377 $ hg debugpathcomplete -f f
374 378 fee
375 379 fie/dead
376 380 fie/live
377 381 fo
378 382
379 383 $ hg rm Fum
380 384 $ hg debugpathcomplete -r F
381 385 Fum
382 386
383 387 Test debugnamecomplete
384 388
385 389 $ hg debugnamecomplete
386 390 Fum
387 391 default
388 392 fee
389 393 fie
390 394 fo
391 395 tip
392 396 $ hg debugnamecomplete f
393 397 fee
394 398 fie
395 399 fo
396 400
397 401 Test debuglabelcomplete, a deprecated name for debugnamecomplete that is still
398 402 used for completions in some shells.
399 403
400 404 $ hg debuglabelcomplete
401 405 Fum
402 406 default
403 407 fee
404 408 fie
405 409 fo
406 410 tip
407 411 $ hg debuglabelcomplete f
408 412 fee
409 413 fie
410 414 fo
@@ -1,431 +1,484 b''
1 1
2 2 $ cat >> $HGRCPATH << EOF
3 3 > [alias]
4 4 > l = log -G -T '{rev} {desc}\n{files}\n'
5 5 > EOF
6 6
7 7 $ REPONUM=0
8 8 $ newrepo() {
9 9 > cd $TESTTMP
10 10 > REPONUM=`expr $REPONUM + 1`
11 11 > hg init repo-$REPONUM
12 12 > cd repo-$REPONUM
13 13 > }
14 14
15 15 Simple rename case
16 16 $ newrepo
17 17 $ echo x > x
18 18 $ hg ci -Aqm 'add x'
19 19 $ hg mv x y
20 $ hg debugp1copies
21 x -> y
22 $ hg debugp2copies
20 23 $ hg ci -m 'rename x to y'
21 24 $ hg l
22 25 @ 1 rename x to y
23 26 | x y
24 27 o 0 add x
25 28 x
29 $ hg debugp1copies -r 1
30 x -> y
26 31 $ hg debugpathcopies 0 1
27 32 x -> y
28 33 $ hg debugpathcopies 1 0
29 34 y -> x
30 35 Test filtering copies by path. We do filtering by destination.
31 36 $ hg debugpathcopies 0 1 x
32 37 $ hg debugpathcopies 1 0 x
33 38 y -> x
34 39 $ hg debugpathcopies 0 1 y
35 40 x -> y
36 41 $ hg debugpathcopies 1 0 y
37 42
38 43 Copy a file onto another file
39 44 $ newrepo
40 45 $ echo x > x
41 46 $ echo y > y
42 47 $ hg ci -Aqm 'add x and y'
43 48 $ hg cp -f x y
49 $ hg debugp1copies
50 x -> y
51 $ hg debugp2copies
44 52 $ hg ci -m 'copy x onto y'
45 53 $ hg l
46 54 @ 1 copy x onto y
47 55 | y
48 56 o 0 add x and y
49 57 x y
58 $ hg debugp1copies -r 1
59 x -> y
50 60 Incorrectly doesn't show the rename
51 61 $ hg debugpathcopies 0 1
52 62
53 63 Copy a file onto another file with same content. If metadata is stored in changeset, this does not
54 64 produce a new filelog entry. The changeset's "files" entry should still list the file.
55 65 $ newrepo
56 66 $ echo x > x
57 67 $ echo x > x2
58 68 $ hg ci -Aqm 'add x and x2 with same content'
59 69 $ hg cp -f x x2
60 70 $ hg ci -m 'copy x onto x2'
61 71 $ hg l
62 72 @ 1 copy x onto x2
63 73 | x2
64 74 o 0 add x and x2 with same content
65 75 x x2
76 $ hg debugp1copies -r 1
77 x -> x2
66 78 Incorrectly doesn't show the rename
67 79 $ hg debugpathcopies 0 1
68 80
69 81 Copy a file, then delete destination, then copy again. This does not create a new filelog entry.
70 82 $ newrepo
71 83 $ echo x > x
72 84 $ hg ci -Aqm 'add x'
73 85 $ hg cp x y
74 86 $ hg ci -m 'copy x to y'
75 87 $ hg rm y
76 88 $ hg ci -m 'remove y'
77 89 $ hg cp -f x y
78 90 $ hg ci -m 'copy x onto y (again)'
79 91 $ hg l
80 92 @ 3 copy x onto y (again)
81 93 | y
82 94 o 2 remove y
83 95 | y
84 96 o 1 copy x to y
85 97 | y
86 98 o 0 add x
87 99 x
100 $ hg debugp1copies -r 3
101 x -> y
88 102 $ hg debugpathcopies 0 3
89 103 x -> y
90 104
91 105 Rename file in a loop: x->y->z->x
92 106 $ newrepo
93 107 $ echo x > x
94 108 $ hg ci -Aqm 'add x'
95 109 $ hg mv x y
110 $ hg debugp1copies
111 x -> y
112 $ hg debugp2copies
96 113 $ hg ci -m 'rename x to y'
97 114 $ hg mv y z
98 115 $ hg ci -m 'rename y to z'
99 116 $ hg mv z x
100 117 $ hg ci -m 'rename z to x'
101 118 $ hg l
102 119 @ 3 rename z to x
103 120 | x z
104 121 o 2 rename y to z
105 122 | y z
106 123 o 1 rename x to y
107 124 | x y
108 125 o 0 add x
109 126 x
110 127 $ hg debugpathcopies 0 3
111 128
112 129 Copy x to y, then remove y, then add back y. With copy metadata in the changeset, this could easily
113 130 end up reporting y as copied from x (if we don't unmark it as a copy when it's removed).
114 131 $ newrepo
115 132 $ echo x > x
116 133 $ hg ci -Aqm 'add x'
117 134 $ hg mv x y
118 135 $ hg ci -m 'rename x to y'
119 136 $ hg rm y
120 137 $ hg ci -qm 'remove y'
121 138 $ echo x > y
122 139 $ hg ci -Aqm 'add back y'
123 140 $ hg l
124 141 @ 3 add back y
125 142 | y
126 143 o 2 remove y
127 144 | y
128 145 o 1 rename x to y
129 146 | x y
130 147 o 0 add x
131 148 x
149 $ hg debugp1copies -r 3
132 150 $ hg debugpathcopies 0 3
133 151
134 152 Copy x to z, then remove z, then copy x2 (same content as x) to z. With copy metadata in the
135 153 changeset, the two copies here will have the same filelog entry, so ctx['z'].introrev() might point
136 154 to the first commit that added the file. We should still report the copy as being from x2.
137 155 $ newrepo
138 156 $ echo x > x
139 157 $ echo x > x2
140 158 $ hg ci -Aqm 'add x and x2 with same content'
141 159 $ hg cp x z
142 160 $ hg ci -qm 'copy x to z'
143 161 $ hg rm z
144 162 $ hg ci -m 'remove z'
145 163 $ hg cp x2 z
146 164 $ hg ci -m 'copy x2 to z'
147 165 $ hg l
148 166 @ 3 copy x2 to z
149 167 | z
150 168 o 2 remove z
151 169 | z
152 170 o 1 copy x to z
153 171 | z
154 172 o 0 add x and x2 with same content
155 173 x x2
174 $ hg debugp1copies -r 3
175 x2 -> z
156 176 $ hg debugpathcopies 0 3
157 177 x2 -> z
158 178
159 179 Create x and y, then rename them both to the same name, but on different sides of a fork
160 180 $ newrepo
161 181 $ echo x > x
162 182 $ echo y > y
163 183 $ hg ci -Aqm 'add x and y'
164 184 $ hg mv x z
165 185 $ hg ci -qm 'rename x to z'
166 186 $ hg co -q 0
167 187 $ hg mv y z
168 188 $ hg ci -qm 'rename y to z'
169 189 $ hg l
170 190 @ 2 rename y to z
171 191 | y z
172 192 | o 1 rename x to z
173 193 |/ x z
174 194 o 0 add x and y
175 195 x y
176 196 $ hg debugpathcopies 1 2
177 197 z -> x
178 198 y -> z
179 199
180 200 Fork renames x to y on one side and removes x on the other
181 201 $ newrepo
182 202 $ echo x > x
183 203 $ hg ci -Aqm 'add x'
184 204 $ hg mv x y
185 205 $ hg ci -m 'rename x to y'
186 206 $ hg co -q 0
187 207 $ hg rm x
188 208 $ hg ci -m 'remove x'
189 209 created new head
190 210 $ hg l
191 211 @ 2 remove x
192 212 | x
193 213 | o 1 rename x to y
194 214 |/ x y
195 215 o 0 add x
196 216 x
197 217 $ hg debugpathcopies 1 2
198 218
199 219 Copies via null revision (there shouldn't be any)
200 220 $ newrepo
201 221 $ echo x > x
202 222 $ hg ci -Aqm 'add x'
203 223 $ hg cp x y
204 224 $ hg ci -m 'copy x to y'
205 225 $ hg co -q null
206 226 $ echo x > x
207 227 $ hg ci -Aqm 'add x (again)'
208 228 $ hg l
209 229 @ 2 add x (again)
210 230 x
211 231 o 1 copy x to y
212 232 | y
213 233 o 0 add x
214 234 x
215 235 $ hg debugpathcopies 1 2
216 236 $ hg debugpathcopies 2 1
217 237
218 238 Merge rename from other branch
219 239 $ newrepo
220 240 $ echo x > x
221 241 $ hg ci -Aqm 'add x'
222 242 $ hg mv x y
223 243 $ hg ci -m 'rename x to y'
224 244 $ hg co -q 0
225 245 $ echo z > z
226 246 $ hg ci -Aqm 'add z'
227 247 $ hg merge -q 1
248 $ hg debugp1copies
249 $ hg debugp2copies
228 250 $ hg ci -m 'merge rename from p2'
229 251 $ hg l
230 252 @ 3 merge rename from p2
231 253 |\ x
232 254 | o 2 add z
233 255 | | z
234 256 o | 1 rename x to y
235 257 |/ x y
236 258 o 0 add x
237 259 x
238 260 Perhaps we should indicate the rename here, but `hg status` is documented to be weird during
239 261 merges, so...
262 $ hg debugp1copies -r 3
263 $ hg debugp2copies -r 3
240 264 $ hg debugpathcopies 0 3
241 265 x -> y
242 266 $ hg debugpathcopies 1 2
243 267 y -> x
244 268 $ hg debugpathcopies 1 3
245 269 $ hg debugpathcopies 2 3
246 270 x -> y
247 271
248 272 Copy file from either side in a merge
249 273 $ newrepo
250 274 $ echo x > x
251 275 $ hg ci -Aqm 'add x'
252 276 $ hg co -q null
253 277 $ echo y > y
254 278 $ hg ci -Aqm 'add y'
255 279 $ hg merge -q 0
256 280 $ hg cp y z
281 $ hg debugp1copies
282 y -> z
283 $ hg debugp2copies
257 284 $ hg ci -m 'copy file from p1 in merge'
258 285 $ hg co -q 1
259 286 $ hg merge -q 0
260 287 $ hg cp x z
288 $ hg debugp1copies
289 $ hg debugp2copies
290 x -> z
261 291 $ hg ci -qm 'copy file from p2 in merge'
262 292 $ hg l
263 293 @ 3 copy file from p2 in merge
264 294 |\ z
265 295 +---o 2 copy file from p1 in merge
266 296 | |/ z
267 297 | o 1 add y
268 298 | y
269 299 o 0 add x
270 300 x
301 $ hg debugp1copies -r 2
302 y -> z
303 $ hg debugp2copies -r 2
271 304 $ hg debugpathcopies 1 2
272 305 y -> z
273 306 $ hg debugpathcopies 0 2
307 $ hg debugp1copies -r 3
308 $ hg debugp2copies -r 3
309 x -> z
274 310 $ hg debugpathcopies 1 3
275 311 $ hg debugpathcopies 0 3
276 312 x -> z
277 313
278 314 Copy file that exists on both sides of the merge, same content on both sides
279 315 $ newrepo
280 316 $ echo x > x
281 317 $ hg ci -Aqm 'add x on branch 1'
282 318 $ hg co -q null
283 319 $ echo x > x
284 320 $ hg ci -Aqm 'add x on branch 2'
285 321 $ hg merge -q 0
286 322 $ hg cp x z
323 $ hg debugp1copies
324 x -> z
325 $ hg debugp2copies
287 326 $ hg ci -qm 'merge'
288 327 $ hg l
289 328 @ 2 merge
290 329 |\ z
291 330 | o 1 add x on branch 2
292 331 | x
293 332 o 0 add x on branch 1
294 333 x
334 $ hg debugp1copies -r 2
335 x -> z
336 $ hg debugp2copies -r 2
295 337 It's a little weird that it shows up on both sides
296 338 $ hg debugpathcopies 1 2
297 339 x -> z
298 340 $ hg debugpathcopies 0 2
299 341 x -> z
300 342
301 343 Copy file that exists on both sides of the merge, different content
302 344 $ newrepo
303 345 $ echo branch1 > x
304 346 $ hg ci -Aqm 'add x on branch 1'
305 347 $ hg co -q null
306 348 $ echo branch2 > x
307 349 $ hg ci -Aqm 'add x on branch 2'
308 350 $ hg merge -q 0
309 351 warning: conflicts while merging x! (edit, then use 'hg resolve --mark')
310 352 [1]
311 353 $ echo resolved > x
312 354 $ hg resolve -m x
313 355 (no more unresolved files)
314 356 $ hg cp x z
357 $ hg debugp1copies
358 x -> z
359 $ hg debugp2copies
315 360 $ hg ci -qm 'merge'
316 361 $ hg l
317 362 @ 2 merge
318 363 |\ x z
319 364 | o 1 add x on branch 2
320 365 | x
321 366 o 0 add x on branch 1
322 367 x
368 $ hg debugp1copies -r 2
369 $ hg debugp2copies -r 2
370 x -> z
323 371 $ hg debugpathcopies 1 2
324 372 $ hg debugpathcopies 0 2
325 373 x -> z
326 374
327 375 Copy x->y on one side of merge and copy x->z on the other side. Pathcopies from one parent
328 376 of the merge to the merge should include the copy from the other side.
329 377 $ newrepo
330 378 $ echo x > x
331 379 $ hg ci -Aqm 'add x'
332 380 $ hg cp x y
333 381 $ hg ci -qm 'copy x to y'
334 382 $ hg co -q 0
335 383 $ hg cp x z
336 384 $ hg ci -qm 'copy x to z'
337 385 $ hg merge -q 1
338 386 $ hg ci -m 'merge copy x->y and copy x->z'
339 387 $ hg l
340 388 @ 3 merge copy x->y and copy x->z
341 389 |\
342 390 | o 2 copy x to z
343 391 | | z
344 392 o | 1 copy x to y
345 393 |/ y
346 394 o 0 add x
347 395 x
396 $ hg debugp1copies -r 3
397 $ hg debugp2copies -r 3
348 398 $ hg debugpathcopies 2 3
349 399 x -> y
350 400 $ hg debugpathcopies 1 3
351 401 x -> z
352 402
353 403 Copy x to y on one side of merge, create y and rename to z on the other side. Pathcopies from the
354 404 first side should not include the y->z rename since y didn't exist in the merge base.
355 405 $ newrepo
356 406 $ echo x > x
357 407 $ hg ci -Aqm 'add x'
358 408 $ hg cp x y
359 409 $ hg ci -qm 'copy x to y'
360 410 $ hg co -q 0
361 411 $ echo y > y
362 412 $ hg ci -Aqm 'add y'
363 413 $ hg mv y z
364 414 $ hg ci -m 'rename y to z'
365 415 $ hg merge -q 1
366 416 $ hg ci -m 'merge'
367 417 $ hg l
368 418 @ 4 merge
369 419 |\
370 420 | o 3 rename y to z
371 421 | | y z
372 422 | o 2 add y
373 423 | | y
374 424 o | 1 copy x to y
375 425 |/ y
376 426 o 0 add x
377 427 x
428 $ hg debugp1copies -r 3
429 y -> z
430 $ hg debugp2copies -r 3
378 431 $ hg debugpathcopies 2 3
379 432 y -> z
380 433 $ hg debugpathcopies 1 3
381 434
382 435 Create x and y, then rename x to z on one side of merge, and rename y to z and modify z on the
383 436 other side.
384 437 $ newrepo
385 438 $ echo x > x
386 439 $ echo y > y
387 440 $ hg ci -Aqm 'add x and y'
388 441 $ hg mv x z
389 442 $ hg ci -qm 'rename x to z'
390 443 $ hg co -q 0
391 444 $ hg mv y z
392 445 $ hg ci -qm 'rename y to z'
393 446 $ echo z >> z
394 447 $ hg ci -m 'modify z'
395 448 $ hg merge -q 1
396 449 warning: conflicts while merging z! (edit, then use 'hg resolve --mark')
397 450 [1]
398 451 $ echo z > z
399 452 $ hg resolve -qm z
400 453 $ hg ci -m 'merge 1 into 3'
401 454 Try merging the other direction too
402 455 $ hg co -q 1
403 456 $ hg merge -q 3
404 457 warning: conflicts while merging z! (edit, then use 'hg resolve --mark')
405 458 [1]
406 459 $ echo z > z
407 460 $ hg resolve -qm z
408 461 $ hg ci -m 'merge 3 into 1'
409 462 created new head
410 463 $ hg l
411 464 @ 5 merge 3 into 1
412 465 |\ y z
413 466 +---o 4 merge 1 into 3
414 467 | |/ x z
415 468 | o 3 modify z
416 469 | | z
417 470 | o 2 rename y to z
418 471 | | y z
419 472 o | 1 rename x to z
420 473 |/ x z
421 474 o 0 add x and y
422 475 x y
423 476 $ hg debugpathcopies 1 4
424 477 $ hg debugpathcopies 2 4
425 478 $ hg debugpathcopies 0 4
426 479 x -> z
427 480 $ hg debugpathcopies 1 5
428 481 $ hg debugpathcopies 2 5
429 482 $ hg debugpathcopies 0 5
430 483 x -> z
431 484
@@ -1,3829 +1,3833 b''
1 1 Short help:
2 2
3 3 $ hg
4 4 Mercurial Distributed SCM
5 5
6 6 basic commands:
7 7
8 8 add add the specified files on the next commit
9 9 annotate show changeset information by line for each file
10 10 clone make a copy of an existing repository
11 11 commit commit the specified files or all outstanding changes
12 12 diff diff repository (or selected files)
13 13 export dump the header and diffs for one or more changesets
14 14 forget forget the specified files on the next commit
15 15 init create a new repository in the given directory
16 16 log show revision history of entire repository or files
17 17 merge merge another revision into working directory
18 18 pull pull changes from the specified source
19 19 push push changes to the specified destination
20 20 remove remove the specified files on the next commit
21 21 serve start stand-alone webserver
22 22 status show changed files in the working directory
23 23 summary summarize working directory state
24 24 update update working directory (or switch revisions)
25 25
26 26 (use 'hg help' for the full list of commands or 'hg -v' for details)
27 27
28 28 $ hg -q
29 29 add add the specified files on the next commit
30 30 annotate show changeset information by line for each file
31 31 clone make a copy of an existing repository
32 32 commit commit the specified files or all outstanding changes
33 33 diff diff repository (or selected files)
34 34 export dump the header and diffs for one or more changesets
35 35 forget forget the specified files on the next commit
36 36 init create a new repository in the given directory
37 37 log show revision history of entire repository or files
38 38 merge merge another revision into working directory
39 39 pull pull changes from the specified source
40 40 push push changes to the specified destination
41 41 remove remove the specified files on the next commit
42 42 serve start stand-alone webserver
43 43 status show changed files in the working directory
44 44 summary summarize working directory state
45 45 update update working directory (or switch revisions)
46 46
47 47 Extra extensions will be printed in help output in a non-reliable order since
48 48 the extension is unknown.
49 49 #if no-extraextensions
50 50
51 51 $ hg help
52 52 Mercurial Distributed SCM
53 53
54 54 list of commands:
55 55
56 56 Repository creation:
57 57
58 58 clone make a copy of an existing repository
59 59 init create a new repository in the given directory
60 60
61 61 Remote repository management:
62 62
63 63 incoming show new changesets found in source
64 64 outgoing show changesets not found in the destination
65 65 paths show aliases for remote repositories
66 66 pull pull changes from the specified source
67 67 push push changes to the specified destination
68 68 serve start stand-alone webserver
69 69
70 70 Change creation:
71 71
72 72 commit commit the specified files or all outstanding changes
73 73
74 74 Change manipulation:
75 75
76 76 backout reverse effect of earlier changeset
77 77 graft copy changes from other branches onto the current branch
78 78 merge merge another revision into working directory
79 79
80 80 Change organization:
81 81
82 82 bookmarks create a new bookmark or list existing bookmarks
83 83 branch set or show the current branch name
84 84 branches list repository named branches
85 85 phase set or show the current phase name
86 86 tag add one or more tags for the current or given revision
87 87 tags list repository tags
88 88
89 89 File content management:
90 90
91 91 annotate show changeset information by line for each file
92 92 cat output the current or given revision of files
93 93 copy mark files as copied for the next commit
94 94 diff diff repository (or selected files)
95 95 grep search revision history 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 remove remove the specified files on the next commit
111 111 rename rename files; equivalent of copy + remove
112 112 resolve redo merges or set/view the merge status of files
113 113 revert restore files to their checkout state
114 114 root print the root (top) of the current working directory
115 115 status show changed files in the working directory
116 116 summary summarize working directory state
117 117 update update working directory (or switch revisions)
118 118
119 119 Change import/export:
120 120
121 121 archive create an unversioned archive of a repository revision
122 122 bundle create a bundle file
123 123 export dump the header and diffs for one or more changesets
124 124 import import an ordered set of patches
125 125 unbundle apply one or more bundle files
126 126
127 127 Repository maintenance:
128 128
129 129 manifest output the current or given revision of the project manifest
130 130 recover roll back an interrupted transaction
131 131 verify verify the integrity of the repository
132 132
133 133 Help:
134 134
135 135 config show combined config settings from all hgrc files
136 136 help show help for a given topic or a help overview
137 137 version output version and copyright information
138 138
139 139 additional help topics:
140 140
141 141 Mercurial identifiers:
142 142
143 143 filesets Specifying File Sets
144 144 hgignore Syntax for Mercurial Ignore Files
145 145 patterns File Name Patterns
146 146 revisions Specifying Revisions
147 147 urls URL Paths
148 148
149 149 Mercurial output:
150 150
151 151 color Colorizing Outputs
152 152 dates Date Formats
153 153 diffs Diff Formats
154 154 templating Template Usage
155 155
156 156 Mercurial configuration:
157 157
158 158 config Configuration Files
159 159 environment Environment Variables
160 160 extensions Using Additional Features
161 161 flags Command-line flags
162 162 hgweb Configuring hgweb
163 163 merge-tools Merge Tools
164 164 pager Pager Support
165 165
166 166 Concepts:
167 167
168 168 bundlespec Bundle File Formats
169 169 glossary Glossary
170 170 phases Working with Phases
171 171 subrepos Subrepositories
172 172
173 173 Miscellaneous:
174 174
175 175 deprecated Deprecated Features
176 176 internals Technical implementation topics
177 177 scripting Using Mercurial from scripts and automation
178 178
179 179 (use 'hg help -v' to show built-in aliases and global options)
180 180
181 181 $ hg -q help
182 182 Repository creation:
183 183
184 184 clone make a copy of an existing repository
185 185 init create a new repository in the given directory
186 186
187 187 Remote repository management:
188 188
189 189 incoming show new changesets found in source
190 190 outgoing show changesets not found in the destination
191 191 paths show aliases for remote repositories
192 192 pull pull changes from the specified source
193 193 push push changes to the specified destination
194 194 serve start stand-alone webserver
195 195
196 196 Change creation:
197 197
198 198 commit commit the specified files or all outstanding changes
199 199
200 200 Change manipulation:
201 201
202 202 backout reverse effect of earlier changeset
203 203 graft copy changes from other branches onto the current branch
204 204 merge merge another revision into working directory
205 205
206 206 Change organization:
207 207
208 208 bookmarks create a new bookmark or list existing bookmarks
209 209 branch set or show the current branch name
210 210 branches list repository named branches
211 211 phase set or show the current phase name
212 212 tag add one or more tags for the current or given revision
213 213 tags list repository tags
214 214
215 215 File content management:
216 216
217 217 annotate show changeset information by line for each file
218 218 cat output the current or given revision of files
219 219 copy mark files as copied for the next commit
220 220 diff diff repository (or selected files)
221 221 grep search revision history for a pattern in specified files
222 222
223 223 Change navigation:
224 224
225 225 bisect subdivision search of changesets
226 226 heads show branch heads
227 227 identify identify the working directory or specified revision
228 228 log show revision history of entire repository or files
229 229
230 230 Working directory management:
231 231
232 232 add add the specified files on the next commit
233 233 addremove add all new files, delete all missing files
234 234 files list tracked files
235 235 forget forget the specified files on the next commit
236 236 remove remove the specified files on the next commit
237 237 rename rename files; equivalent of copy + remove
238 238 resolve redo merges or set/view the merge status of files
239 239 revert restore files to their checkout state
240 240 root print the root (top) of the current working directory
241 241 status show changed files in the working directory
242 242 summary summarize working directory state
243 243 update update working directory (or switch revisions)
244 244
245 245 Change import/export:
246 246
247 247 archive create an unversioned archive of a repository revision
248 248 bundle create a bundle file
249 249 export dump the header and diffs for one or more changesets
250 250 import import an ordered set of patches
251 251 unbundle apply one or more bundle files
252 252
253 253 Repository maintenance:
254 254
255 255 manifest output the current or given revision of the project manifest
256 256 recover roll back an interrupted transaction
257 257 verify verify the integrity of the repository
258 258
259 259 Help:
260 260
261 261 config show combined config settings from all hgrc files
262 262 help show help for a given topic or a help overview
263 263 version output version and copyright information
264 264
265 265 additional help topics:
266 266
267 267 Mercurial identifiers:
268 268
269 269 filesets Specifying File Sets
270 270 hgignore Syntax for Mercurial Ignore Files
271 271 patterns File Name Patterns
272 272 revisions Specifying Revisions
273 273 urls URL Paths
274 274
275 275 Mercurial output:
276 276
277 277 color Colorizing Outputs
278 278 dates Date Formats
279 279 diffs Diff Formats
280 280 templating Template Usage
281 281
282 282 Mercurial configuration:
283 283
284 284 config Configuration Files
285 285 environment Environment Variables
286 286 extensions Using Additional Features
287 287 flags Command-line flags
288 288 hgweb Configuring hgweb
289 289 merge-tools Merge Tools
290 290 pager Pager Support
291 291
292 292 Concepts:
293 293
294 294 bundlespec Bundle File Formats
295 295 glossary Glossary
296 296 phases Working with Phases
297 297 subrepos Subrepositories
298 298
299 299 Miscellaneous:
300 300
301 301 deprecated Deprecated Features
302 302 internals Technical implementation topics
303 303 scripting Using Mercurial from scripts and automation
304 304
305 305 Test extension help:
306 306 $ hg help extensions --config extensions.rebase= --config extensions.children=
307 307 Using Additional Features
308 308 """""""""""""""""""""""""
309 309
310 310 Mercurial has the ability to add new features through the use of
311 311 extensions. Extensions may add new commands, add options to existing
312 312 commands, change the default behavior of commands, or implement hooks.
313 313
314 314 To enable the "foo" extension, either shipped with Mercurial or in the
315 315 Python search path, create an entry for it in your configuration file,
316 316 like this:
317 317
318 318 [extensions]
319 319 foo =
320 320
321 321 You may also specify the full path to an extension:
322 322
323 323 [extensions]
324 324 myfeature = ~/.hgext/myfeature.py
325 325
326 326 See 'hg help config' for more information on configuration files.
327 327
328 328 Extensions are not loaded by default for a variety of reasons: they can
329 329 increase startup overhead; they may be meant for advanced usage only; they
330 330 may provide potentially dangerous abilities (such as letting you destroy
331 331 or modify history); they might not be ready for prime time; or they may
332 332 alter some usual behaviors of stock Mercurial. It is thus up to the user
333 333 to activate extensions as needed.
334 334
335 335 To explicitly disable an extension enabled in a configuration file of
336 336 broader scope, prepend its path with !:
337 337
338 338 [extensions]
339 339 # disabling extension bar residing in /path/to/extension/bar.py
340 340 bar = !/path/to/extension/bar.py
341 341 # ditto, but no path was supplied for extension baz
342 342 baz = !
343 343
344 344 enabled extensions:
345 345
346 346 children command to display child changesets (DEPRECATED)
347 347 rebase command to move sets of revisions to a different ancestor
348 348
349 349 disabled extensions:
350 350
351 351 acl hooks for controlling repository access
352 352 blackbox log repository events to a blackbox for debugging
353 353 bugzilla hooks for integrating with the Bugzilla bug tracker
354 354 censor erase file content at a given revision
355 355 churn command to display statistics about repository history
356 356 clonebundles advertise pre-generated bundles to seed clones
357 357 closehead close arbitrary heads without checking them out first
358 358 convert import revisions from foreign VCS repositories into
359 359 Mercurial
360 360 eol automatically manage newlines in repository files
361 361 extdiff command to allow external programs to compare revisions
362 362 factotum http authentication with factotum
363 363 githelp try mapping git commands to Mercurial commands
364 364 gpg commands to sign and verify changesets
365 365 hgk browse the repository in a graphical way
366 366 highlight syntax highlighting for hgweb (requires Pygments)
367 367 histedit interactive history editing
368 368 keyword expand keywords in tracked files
369 369 largefiles track large binary files
370 370 mq manage a stack of patches
371 371 notify hooks for sending email push notifications
372 372 patchbomb command to send changesets as (a series of) patch emails
373 373 purge command to delete untracked files from the working
374 374 directory
375 375 relink recreates hardlinks between repository clones
376 376 schemes extend schemes with shortcuts to repository swarms
377 377 share share a common history between several working directories
378 378 shelve save and restore changes to the working directory
379 379 strip strip changesets and their descendants from history
380 380 transplant command to transplant changesets from another branch
381 381 win32mbcs allow the use of MBCS paths with problematic encodings
382 382 zeroconf discover and advertise repositories on the local network
383 383
384 384 #endif
385 385
386 386 Verify that deprecated extensions are included if --verbose:
387 387
388 388 $ hg -v help extensions | grep children
389 389 children command to display child changesets (DEPRECATED)
390 390
391 391 Verify that extension keywords appear in help templates
392 392
393 393 $ hg help --config extensions.transplant= templating|grep transplant > /dev/null
394 394
395 395 Test short command list with verbose option
396 396
397 397 $ hg -v help shortlist
398 398 Mercurial Distributed SCM
399 399
400 400 basic commands:
401 401
402 402 add add the specified files on the next commit
403 403 annotate, blame
404 404 show changeset information by line for each file
405 405 clone make a copy of an existing repository
406 406 commit, ci commit the specified files or all outstanding changes
407 407 diff diff repository (or selected files)
408 408 export dump the header and diffs for one or more changesets
409 409 forget forget the specified files on the next commit
410 410 init create a new repository in the given directory
411 411 log, history show revision history of entire repository or files
412 412 merge merge another revision into working directory
413 413 pull pull changes from the specified source
414 414 push push changes to the specified destination
415 415 remove, rm remove the specified files on the next commit
416 416 serve start stand-alone webserver
417 417 status, st show changed files in the working directory
418 418 summary, sum summarize working directory state
419 419 update, up, checkout, co
420 420 update working directory (or switch revisions)
421 421
422 422 global options ([+] can be repeated):
423 423
424 424 -R --repository REPO repository root directory or name of overlay bundle
425 425 file
426 426 --cwd DIR change working directory
427 427 -y --noninteractive do not prompt, automatically pick the first choice for
428 428 all prompts
429 429 -q --quiet suppress output
430 430 -v --verbose enable additional output
431 431 --color TYPE when to colorize (boolean, always, auto, never, or
432 432 debug)
433 433 --config CONFIG [+] set/override config option (use 'section.name=value')
434 434 --debug enable debugging output
435 435 --debugger start debugger
436 436 --encoding ENCODE set the charset encoding (default: ascii)
437 437 --encodingmode MODE set the charset encoding mode (default: strict)
438 438 --traceback always print a traceback on exception
439 439 --time time how long the command takes
440 440 --profile print command execution profile
441 441 --version output version information and exit
442 442 -h --help display help and exit
443 443 --hidden consider hidden changesets
444 444 --pager TYPE when to paginate (boolean, always, auto, or never)
445 445 (default: auto)
446 446
447 447 (use 'hg help' for the full list of commands)
448 448
449 449 $ hg add -h
450 450 hg add [OPTION]... [FILE]...
451 451
452 452 add the specified files on the next commit
453 453
454 454 Schedule files to be version controlled and added to the repository.
455 455
456 456 The files will be added to the repository at the next commit. To undo an
457 457 add before that, see 'hg forget'.
458 458
459 459 If no names are given, add all files to the repository (except files
460 460 matching ".hgignore").
461 461
462 462 Returns 0 if all files are successfully added.
463 463
464 464 options ([+] can be repeated):
465 465
466 466 -I --include PATTERN [+] include names matching the given patterns
467 467 -X --exclude PATTERN [+] exclude names matching the given patterns
468 468 -S --subrepos recurse into subrepositories
469 469 -n --dry-run do not perform actions, just print output
470 470
471 471 (some details hidden, use --verbose to show complete help)
472 472
473 473 Verbose help for add
474 474
475 475 $ hg add -hv
476 476 hg add [OPTION]... [FILE]...
477 477
478 478 add the specified files on the next commit
479 479
480 480 Schedule files to be version controlled and added to the repository.
481 481
482 482 The files will be added to the repository at the next commit. To undo an
483 483 add before that, see 'hg forget'.
484 484
485 485 If no names are given, add all files to the repository (except files
486 486 matching ".hgignore").
487 487
488 488 Examples:
489 489
490 490 - New (unknown) files are added automatically by 'hg add':
491 491
492 492 $ ls
493 493 foo.c
494 494 $ hg status
495 495 ? foo.c
496 496 $ hg add
497 497 adding foo.c
498 498 $ hg status
499 499 A foo.c
500 500
501 501 - Specific files to be added can be specified:
502 502
503 503 $ ls
504 504 bar.c foo.c
505 505 $ hg status
506 506 ? bar.c
507 507 ? foo.c
508 508 $ hg add bar.c
509 509 $ hg status
510 510 A bar.c
511 511 ? foo.c
512 512
513 513 Returns 0 if all files are successfully added.
514 514
515 515 options ([+] can be repeated):
516 516
517 517 -I --include PATTERN [+] include names matching the given patterns
518 518 -X --exclude PATTERN [+] exclude names matching the given patterns
519 519 -S --subrepos recurse into subrepositories
520 520 -n --dry-run do not perform actions, just print output
521 521
522 522 global options ([+] can be repeated):
523 523
524 524 -R --repository REPO repository root directory or name of overlay bundle
525 525 file
526 526 --cwd DIR change working directory
527 527 -y --noninteractive do not prompt, automatically pick the first choice for
528 528 all prompts
529 529 -q --quiet suppress output
530 530 -v --verbose enable additional output
531 531 --color TYPE when to colorize (boolean, always, auto, never, or
532 532 debug)
533 533 --config CONFIG [+] set/override config option (use 'section.name=value')
534 534 --debug enable debugging output
535 535 --debugger start debugger
536 536 --encoding ENCODE set the charset encoding (default: ascii)
537 537 --encodingmode MODE set the charset encoding mode (default: strict)
538 538 --traceback always print a traceback on exception
539 539 --time time how long the command takes
540 540 --profile print command execution profile
541 541 --version output version information and exit
542 542 -h --help display help and exit
543 543 --hidden consider hidden changesets
544 544 --pager TYPE when to paginate (boolean, always, auto, or never)
545 545 (default: auto)
546 546
547 547 Test the textwidth config option
548 548
549 549 $ hg root -h --config ui.textwidth=50
550 550 hg root
551 551
552 552 print the root (top) of the current working
553 553 directory
554 554
555 555 Print the root directory of the current
556 556 repository.
557 557
558 558 Returns 0 on success.
559 559
560 560 (some details hidden, use --verbose to show
561 561 complete help)
562 562
563 563 Test help option with version option
564 564
565 565 $ hg add -h --version
566 566 Mercurial Distributed SCM (version *) (glob)
567 567 (see https://mercurial-scm.org for more information)
568 568
569 569 Copyright (C) 2005-* Matt Mackall and others (glob)
570 570 This is free software; see the source for copying conditions. There is NO
571 571 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
572 572
573 573 $ hg add --skjdfks
574 574 hg add: option --skjdfks not recognized
575 575 hg add [OPTION]... [FILE]...
576 576
577 577 add the specified files on the next commit
578 578
579 579 options ([+] can be repeated):
580 580
581 581 -I --include PATTERN [+] include names matching the given patterns
582 582 -X --exclude PATTERN [+] exclude names matching the given patterns
583 583 -S --subrepos recurse into subrepositories
584 584 -n --dry-run do not perform actions, just print output
585 585
586 586 (use 'hg add -h' to show more help)
587 587 [255]
588 588
589 589 Test ambiguous command help
590 590
591 591 $ hg help ad
592 592 list of commands:
593 593
594 594 add add the specified files on the next commit
595 595 addremove add all new files, delete all missing files
596 596
597 597 (use 'hg help -v ad' to show built-in aliases and global options)
598 598
599 599 Test command without options
600 600
601 601 $ hg help verify
602 602 hg verify
603 603
604 604 verify the integrity of the repository
605 605
606 606 Verify the integrity of the current repository.
607 607
608 608 This will perform an extensive check of the repository's integrity,
609 609 validating the hashes and checksums of each entry in the changelog,
610 610 manifest, and tracked files, as well as the integrity of their crosslinks
611 611 and indices.
612 612
613 613 Please see https://mercurial-scm.org/wiki/RepositoryCorruption for more
614 614 information about recovery from corruption of the repository.
615 615
616 616 Returns 0 on success, 1 if errors are encountered.
617 617
618 618 (some details hidden, use --verbose to show complete help)
619 619
620 620 $ hg help diff
621 621 hg diff [OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...
622 622
623 623 diff repository (or selected files)
624 624
625 625 Show differences between revisions for the specified files.
626 626
627 627 Differences between files are shown using the unified diff format.
628 628
629 629 Note:
630 630 'hg diff' may generate unexpected results for merges, as it will
631 631 default to comparing against the working directory's first parent
632 632 changeset if no revisions are specified.
633 633
634 634 When two revision arguments are given, then changes are shown between
635 635 those revisions. If only one revision is specified then that revision is
636 636 compared to the working directory, and, when no revisions are specified,
637 637 the working directory files are compared to its first parent.
638 638
639 639 Alternatively you can specify -c/--change with a revision to see the
640 640 changes in that changeset relative to its first parent.
641 641
642 642 Without the -a/--text option, diff will avoid generating diffs of files it
643 643 detects as binary. With -a, diff will generate a diff anyway, probably
644 644 with undesirable results.
645 645
646 646 Use the -g/--git option to generate diffs in the git extended diff format.
647 647 For more information, read 'hg help diffs'.
648 648
649 649 Returns 0 on success.
650 650
651 651 options ([+] can be repeated):
652 652
653 653 -r --rev REV [+] revision
654 654 -c --change REV change made by revision
655 655 -a --text treat all files as text
656 656 -g --git use git extended diff format
657 657 --binary generate binary diffs in git mode (default)
658 658 --nodates omit dates from diff headers
659 659 --noprefix omit a/ and b/ prefixes from filenames
660 660 -p --show-function show which function each change is in
661 661 --reverse produce a diff that undoes the changes
662 662 -w --ignore-all-space ignore white space when comparing lines
663 663 -b --ignore-space-change ignore changes in the amount of white space
664 664 -B --ignore-blank-lines ignore changes whose lines are all blank
665 665 -Z --ignore-space-at-eol ignore changes in whitespace at EOL
666 666 -U --unified NUM number of lines of context to show
667 667 --stat output diffstat-style summary of changes
668 668 --root DIR produce diffs relative to subdirectory
669 669 -I --include PATTERN [+] include names matching the given patterns
670 670 -X --exclude PATTERN [+] exclude names matching the given patterns
671 671 -S --subrepos recurse into subrepositories
672 672
673 673 (some details hidden, use --verbose to show complete help)
674 674
675 675 $ hg help status
676 676 hg status [OPTION]... [FILE]...
677 677
678 678 aliases: st
679 679
680 680 show changed files in the working directory
681 681
682 682 Show status of files in the repository. If names are given, only files
683 683 that match are shown. Files that are clean or ignored or the source of a
684 684 copy/move operation, are not listed unless -c/--clean, -i/--ignored,
685 685 -C/--copies or -A/--all are given. Unless options described with "show
686 686 only ..." are given, the options -mardu are used.
687 687
688 688 Option -q/--quiet hides untracked (unknown and ignored) files unless
689 689 explicitly requested with -u/--unknown or -i/--ignored.
690 690
691 691 Note:
692 692 'hg status' may appear to disagree with diff if permissions have
693 693 changed or a merge has occurred. The standard diff format does not
694 694 report permission changes and diff only reports changes relative to one
695 695 merge parent.
696 696
697 697 If one revision is given, it is used as the base revision. If two
698 698 revisions are given, the differences between them are shown. The --change
699 699 option can also be used as a shortcut to list the changed files of a
700 700 revision from its first parent.
701 701
702 702 The codes used to show the status of files are:
703 703
704 704 M = modified
705 705 A = added
706 706 R = removed
707 707 C = clean
708 708 ! = missing (deleted by non-hg command, but still tracked)
709 709 ? = not tracked
710 710 I = ignored
711 711 = origin of the previous file (with --copies)
712 712
713 713 Returns 0 on success.
714 714
715 715 options ([+] can be repeated):
716 716
717 717 -A --all show status of all files
718 718 -m --modified show only modified files
719 719 -a --added show only added files
720 720 -r --removed show only removed files
721 721 -d --deleted show only deleted (but tracked) files
722 722 -c --clean show only files without changes
723 723 -u --unknown show only unknown (not tracked) files
724 724 -i --ignored show only ignored files
725 725 -n --no-status hide status prefix
726 726 -C --copies show source of copied files
727 727 -0 --print0 end filenames with NUL, for use with xargs
728 728 --rev REV [+] show difference from revision
729 729 --change REV list the changed files of a revision
730 730 -I --include PATTERN [+] include names matching the given patterns
731 731 -X --exclude PATTERN [+] exclude names matching the given patterns
732 732 -S --subrepos recurse into subrepositories
733 733 -T --template TEMPLATE display with template
734 734
735 735 (some details hidden, use --verbose to show complete help)
736 736
737 737 $ hg -q help status
738 738 hg status [OPTION]... [FILE]...
739 739
740 740 show changed files in the working directory
741 741
742 742 $ hg help foo
743 743 abort: no such help topic: foo
744 744 (try 'hg help --keyword foo')
745 745 [255]
746 746
747 747 $ hg skjdfks
748 748 hg: unknown command 'skjdfks'
749 749 (use 'hg help' for a list of commands)
750 750 [255]
751 751
752 752 Typoed command gives suggestion
753 753 $ hg puls
754 754 hg: unknown command 'puls'
755 755 (did you mean one of pull, push?)
756 756 [255]
757 757
758 758 Not enabled extension gets suggested
759 759
760 760 $ hg rebase
761 761 hg: unknown command 'rebase'
762 762 'rebase' is provided by the following extension:
763 763
764 764 rebase command to move sets of revisions to a different ancestor
765 765
766 766 (use 'hg help extensions' for information on enabling extensions)
767 767 [255]
768 768
769 769 Disabled extension gets suggested
770 770 $ hg --config extensions.rebase=! rebase
771 771 hg: unknown command 'rebase'
772 772 'rebase' is provided by the following extension:
773 773
774 774 rebase command to move sets of revisions to a different ancestor
775 775
776 776 (use 'hg help extensions' for information on enabling extensions)
777 777 [255]
778 778
779 779 Make sure that we don't run afoul of the help system thinking that
780 780 this is a section and erroring out weirdly.
781 781
782 782 $ hg .log
783 783 hg: unknown command '.log'
784 784 (did you mean log?)
785 785 [255]
786 786
787 787 $ hg log.
788 788 hg: unknown command 'log.'
789 789 (did you mean log?)
790 790 [255]
791 791 $ hg pu.lh
792 792 hg: unknown command 'pu.lh'
793 793 (did you mean one of pull, push?)
794 794 [255]
795 795
796 796 $ cat > helpext.py <<EOF
797 797 > import os
798 798 > from mercurial import commands, fancyopts, registrar
799 799 >
800 800 > def func(arg):
801 801 > return '%sfoo' % arg
802 802 > class customopt(fancyopts.customopt):
803 803 > def newstate(self, oldstate, newparam, abort):
804 804 > return '%sbar' % oldstate
805 805 > cmdtable = {}
806 806 > command = registrar.command(cmdtable)
807 807 >
808 808 > @command(b'nohelp',
809 809 > [(b'', b'longdesc', 3, b'x'*67),
810 810 > (b'n', b'', None, b'normal desc'),
811 811 > (b'', b'newline', b'', b'line1\nline2'),
812 812 > (b'', b'default-off', False, b'enable X'),
813 813 > (b'', b'default-on', True, b'enable Y'),
814 814 > (b'', b'callableopt', func, b'adds foo'),
815 815 > (b'', b'customopt', customopt(''), b'adds bar'),
816 816 > (b'', b'customopt-withdefault', customopt('foo'), b'adds bar')],
817 817 > b'hg nohelp',
818 818 > norepo=True)
819 819 > @command(b'debugoptADV', [(b'', b'aopt', None, b'option is (ADVANCED)')])
820 820 > @command(b'debugoptDEP', [(b'', b'dopt', None, b'option is (DEPRECATED)')])
821 821 > @command(b'debugoptEXP', [(b'', b'eopt', None, b'option is (EXPERIMENTAL)')])
822 822 > def nohelp(ui, *args, **kwargs):
823 823 > pass
824 824 >
825 825 > @command(b'hashelp', [], b'hg hashelp', norepo=True)
826 826 > def hashelp(ui, *args, **kwargs):
827 827 > """Extension command's help"""
828 828 >
829 829 > def uisetup(ui):
830 830 > ui.setconfig(b'alias', b'shellalias', b'!echo hi', b'helpext')
831 831 > ui.setconfig(b'alias', b'hgalias', b'summary', b'helpext')
832 832 > ui.setconfig(b'alias', b'hgalias:doc', b'My doc', b'helpext')
833 833 > ui.setconfig(b'alias', b'hgalias:category', b'navigation', b'helpext')
834 834 > ui.setconfig(b'alias', b'hgaliasnodoc', b'summary', b'helpext')
835 835 >
836 836 > EOF
837 837 $ echo '[extensions]' >> $HGRCPATH
838 838 $ echo "helpext = `pwd`/helpext.py" >> $HGRCPATH
839 839
840 840 Test for aliases
841 841
842 842 $ hg help | grep hgalias
843 843 hgalias My doc
844 844
845 845 $ hg help hgalias
846 846 hg hgalias [--remote]
847 847
848 848 alias for: hg summary
849 849
850 850 My doc
851 851
852 852 defined by: helpext
853 853
854 854 options:
855 855
856 856 --remote check for push and pull
857 857
858 858 (some details hidden, use --verbose to show complete help)
859 859 $ hg help hgaliasnodoc
860 860 hg hgaliasnodoc [--remote]
861 861
862 862 alias for: hg summary
863 863
864 864 summarize working directory state
865 865
866 866 This generates a brief summary of the working directory state, including
867 867 parents, branch, commit status, phase and available updates.
868 868
869 869 With the --remote option, this will check the default paths for incoming
870 870 and outgoing changes. This can be time-consuming.
871 871
872 872 Returns 0 on success.
873 873
874 874 defined by: helpext
875 875
876 876 options:
877 877
878 878 --remote check for push and pull
879 879
880 880 (some details hidden, use --verbose to show complete help)
881 881
882 882 $ hg help shellalias
883 883 hg shellalias
884 884
885 885 shell alias for: echo hi
886 886
887 887 (no help text available)
888 888
889 889 defined by: helpext
890 890
891 891 (some details hidden, use --verbose to show complete help)
892 892
893 893 Test command with no help text
894 894
895 895 $ hg help nohelp
896 896 hg nohelp
897 897
898 898 (no help text available)
899 899
900 900 options:
901 901
902 902 --longdesc VALUE
903 903 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
904 904 xxxxxxxxxxxxxxxxxxxxxxx (default: 3)
905 905 -n -- normal desc
906 906 --newline VALUE line1 line2
907 907 --default-off enable X
908 908 --[no-]default-on enable Y (default: on)
909 909 --callableopt VALUE adds foo
910 910 --customopt VALUE adds bar
911 911 --customopt-withdefault VALUE adds bar (default: foo)
912 912
913 913 (some details hidden, use --verbose to show complete help)
914 914
915 915 Test that default list of commands includes extension commands that have help,
916 916 but not those that don't, except in verbose mode, when a keyword is passed, or
917 917 when help about the extension is requested.
918 918
919 919 #if no-extraextensions
920 920
921 921 $ hg help | grep hashelp
922 922 hashelp Extension command's help
923 923 $ hg help | grep nohelp
924 924 [1]
925 925 $ hg help -v | grep nohelp
926 926 nohelp (no help text available)
927 927
928 928 $ hg help -k nohelp
929 929 Commands:
930 930
931 931 nohelp hg nohelp
932 932
933 933 Extension Commands:
934 934
935 935 nohelp (no help text available)
936 936
937 937 $ hg help helpext
938 938 helpext extension - no help text available
939 939
940 940 list of commands:
941 941
942 942 hashelp Extension command's help
943 943 nohelp (no help text available)
944 944
945 945 (use 'hg help -v helpext' to show built-in aliases and global options)
946 946
947 947 #endif
948 948
949 949 Test list of internal help commands
950 950
951 951 $ hg help debug
952 952 debug commands (internal and unsupported):
953 953
954 954 debugancestor
955 955 find the ancestor revision of two revisions in a given index
956 956 debugapplystreamclonebundle
957 957 apply a stream clone bundle file
958 958 debugbuilddag
959 959 builds a repo with a given DAG from scratch in the current
960 960 empty repo
961 961 debugbundle lists the contents of a bundle
962 962 debugcapabilities
963 963 lists the capabilities of a remote peer
964 964 debugcheckstate
965 965 validate the correctness of the current dirstate
966 966 debugcolor show available color, effects or style
967 967 debugcommands
968 968 list all available commands and options
969 969 debugcomplete
970 970 returns the completion list associated with the given command
971 971 debugcreatestreamclonebundle
972 972 create a stream clone bundle file
973 973 debugdag format the changelog or an index DAG as a concise textual
974 974 description
975 975 debugdata dump the contents of a data file revision
976 976 debugdate parse and display a date
977 977 debugdeltachain
978 978 dump information about delta chains in a revlog
979 979 debugdirstate
980 980 show the contents of the current dirstate
981 981 debugdiscovery
982 982 runs the changeset discovery protocol in isolation
983 983 debugdownload
984 984 download a resource using Mercurial logic and config
985 985 debugextensions
986 986 show information about active extensions
987 987 debugfileset parse and apply a fileset specification
988 988 debugformat display format information about the current repository
989 989 debugfsinfo show information detected about current filesystem
990 990 debuggetbundle
991 991 retrieves a bundle from a repo
992 992 debugignore display the combined ignore pattern and information about
993 993 ignored files
994 994 debugindex dump index data for a storage primitive
995 995 debugindexdot
996 996 dump an index DAG as a graphviz dot file
997 997 debugindexstats
998 998 show stats related to the changelog index
999 999 debuginstall test Mercurial installation
1000 1000 debugknown test whether node ids are known to a repo
1001 1001 debuglocks show or modify state of locks
1002 1002 debugmanifestfulltextcache
1003 1003 show, clear or amend the contents of the manifest fulltext
1004 1004 cache
1005 1005 debugmergestate
1006 1006 print merge state
1007 1007 debugnamecomplete
1008 1008 complete "names" - tags, open branch names, bookmark names
1009 1009 debugobsolete
1010 1010 create arbitrary obsolete marker
1011 1011 debugoptADV (no help text available)
1012 1012 debugoptDEP (no help text available)
1013 1013 debugoptEXP (no help text available)
1014 debugp1copies
1015 dump copy information compared to p1
1016 debugp2copies
1017 dump copy information compared to p2
1014 1018 debugpathcomplete
1015 1019 complete part or all of a tracked path
1016 1020 debugpathcopies
1017 1021 show copies between two revisions
1018 1022 debugpeer establish a connection to a peer repository
1019 1023 debugpickmergetool
1020 1024 examine which merge tool is chosen for specified file
1021 1025 debugpushkey access the pushkey key/value protocol
1022 1026 debugpvec (no help text available)
1023 1027 debugrebuilddirstate
1024 1028 rebuild the dirstate as it would look like for the given
1025 1029 revision
1026 1030 debugrebuildfncache
1027 1031 rebuild the fncache file
1028 1032 debugrename dump rename information
1029 1033 debugrevlog show data and statistics about a revlog
1030 1034 debugrevlogindex
1031 1035 dump the contents of a revlog index
1032 1036 debugrevspec parse and apply a revision specification
1033 1037 debugserve run a server with advanced settings
1034 1038 debugsetparents
1035 1039 manually set the parents of the current working directory
1036 1040 debugssl test a secure connection to a server
1037 1041 debugsub (no help text available)
1038 1042 debugsuccessorssets
1039 1043 show set of successors for revision
1040 1044 debugtemplate
1041 1045 parse and apply a template
1042 1046 debuguigetpass
1043 1047 show prompt to type password
1044 1048 debuguiprompt
1045 1049 show plain prompt
1046 1050 debugupdatecaches
1047 1051 warm all known caches in the repository
1048 1052 debugupgraderepo
1049 1053 upgrade a repository to use different features
1050 1054 debugwalk show how files match on given patterns
1051 1055 debugwhyunstable
1052 1056 explain instabilities of a changeset
1053 1057 debugwireargs
1054 1058 (no help text available)
1055 1059 debugwireproto
1056 1060 send wire protocol commands to a server
1057 1061
1058 1062 (use 'hg help -v debug' to show built-in aliases and global options)
1059 1063
1060 1064 internals topic renders index of available sub-topics
1061 1065
1062 1066 $ hg help internals
1063 1067 Technical implementation topics
1064 1068 """""""""""""""""""""""""""""""
1065 1069
1066 1070 To access a subtopic, use "hg help internals.{subtopic-name}"
1067 1071
1068 1072 bundle2 Bundle2
1069 1073 bundles Bundles
1070 1074 cbor CBOR
1071 1075 censor Censor
1072 1076 changegroups Changegroups
1073 1077 config Config Registrar
1074 1078 extensions Extension API
1075 1079 requirements Repository Requirements
1076 1080 revlogs Revision Logs
1077 1081 wireprotocol Wire Protocol
1078 1082 wireprotocolrpc
1079 1083 Wire Protocol RPC
1080 1084 wireprotocolv2
1081 1085 Wire Protocol Version 2
1082 1086
1083 1087 sub-topics can be accessed
1084 1088
1085 1089 $ hg help internals.changegroups
1086 1090 Changegroups
1087 1091 """"""""""""
1088 1092
1089 1093 Changegroups are representations of repository revlog data, specifically
1090 1094 the changelog data, root/flat manifest data, treemanifest data, and
1091 1095 filelogs.
1092 1096
1093 1097 There are 3 versions of changegroups: "1", "2", and "3". From a high-
1094 1098 level, versions "1" and "2" are almost exactly the same, with the only
1095 1099 difference being an additional item in the *delta header*. Version "3"
1096 1100 adds support for storage flags in the *delta header* and optionally
1097 1101 exchanging treemanifests (enabled by setting an option on the
1098 1102 "changegroup" part in the bundle2).
1099 1103
1100 1104 Changegroups when not exchanging treemanifests consist of 3 logical
1101 1105 segments:
1102 1106
1103 1107 +---------------------------------+
1104 1108 | | | |
1105 1109 | changeset | manifest | filelogs |
1106 1110 | | | |
1107 1111 | | | |
1108 1112 +---------------------------------+
1109 1113
1110 1114 When exchanging treemanifests, there are 4 logical segments:
1111 1115
1112 1116 +-------------------------------------------------+
1113 1117 | | | | |
1114 1118 | changeset | root | treemanifests | filelogs |
1115 1119 | | manifest | | |
1116 1120 | | | | |
1117 1121 +-------------------------------------------------+
1118 1122
1119 1123 The principle building block of each segment is a *chunk*. A *chunk* is a
1120 1124 framed piece of data:
1121 1125
1122 1126 +---------------------------------------+
1123 1127 | | |
1124 1128 | length | data |
1125 1129 | (4 bytes) | (<length - 4> bytes) |
1126 1130 | | |
1127 1131 +---------------------------------------+
1128 1132
1129 1133 All integers are big-endian signed integers. Each chunk starts with a
1130 1134 32-bit integer indicating the length of the entire chunk (including the
1131 1135 length field itself).
1132 1136
1133 1137 There is a special case chunk that has a value of 0 for the length
1134 1138 ("0x00000000"). We call this an *empty chunk*.
1135 1139
1136 1140 Delta Groups
1137 1141 ============
1138 1142
1139 1143 A *delta group* expresses the content of a revlog as a series of deltas,
1140 1144 or patches against previous revisions.
1141 1145
1142 1146 Delta groups consist of 0 or more *chunks* followed by the *empty chunk*
1143 1147 to signal the end of the delta group:
1144 1148
1145 1149 +------------------------------------------------------------------------+
1146 1150 | | | | | |
1147 1151 | chunk0 length | chunk0 data | chunk1 length | chunk1 data | 0x0 |
1148 1152 | (4 bytes) | (various) | (4 bytes) | (various) | (4 bytes) |
1149 1153 | | | | | |
1150 1154 +------------------------------------------------------------------------+
1151 1155
1152 1156 Each *chunk*'s data consists of the following:
1153 1157
1154 1158 +---------------------------------------+
1155 1159 | | |
1156 1160 | delta header | delta data |
1157 1161 | (various by version) | (various) |
1158 1162 | | |
1159 1163 +---------------------------------------+
1160 1164
1161 1165 The *delta data* is a series of *delta*s that describe a diff from an
1162 1166 existing entry (either that the recipient already has, or previously
1163 1167 specified in the bundle/changegroup).
1164 1168
1165 1169 The *delta header* is different between versions "1", "2", and "3" of the
1166 1170 changegroup format.
1167 1171
1168 1172 Version 1 (headerlen=80):
1169 1173
1170 1174 +------------------------------------------------------+
1171 1175 | | | | |
1172 1176 | node | p1 node | p2 node | link node |
1173 1177 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
1174 1178 | | | | |
1175 1179 +------------------------------------------------------+
1176 1180
1177 1181 Version 2 (headerlen=100):
1178 1182
1179 1183 +------------------------------------------------------------------+
1180 1184 | | | | | |
1181 1185 | node | p1 node | p2 node | base node | link node |
1182 1186 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
1183 1187 | | | | | |
1184 1188 +------------------------------------------------------------------+
1185 1189
1186 1190 Version 3 (headerlen=102):
1187 1191
1188 1192 +------------------------------------------------------------------------------+
1189 1193 | | | | | | |
1190 1194 | node | p1 node | p2 node | base node | link node | flags |
1191 1195 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (2 bytes) |
1192 1196 | | | | | | |
1193 1197 +------------------------------------------------------------------------------+
1194 1198
1195 1199 The *delta data* consists of "chunklen - 4 - headerlen" bytes, which
1196 1200 contain a series of *delta*s, densely packed (no separators). These deltas
1197 1201 describe a diff from an existing entry (either that the recipient already
1198 1202 has, or previously specified in the bundle/changegroup). The format is
1199 1203 described more fully in "hg help internals.bdiff", but briefly:
1200 1204
1201 1205 +---------------------------------------------------------------+
1202 1206 | | | | |
1203 1207 | start offset | end offset | new length | content |
1204 1208 | (4 bytes) | (4 bytes) | (4 bytes) | (<new length> bytes) |
1205 1209 | | | | |
1206 1210 +---------------------------------------------------------------+
1207 1211
1208 1212 Please note that the length field in the delta data does *not* include
1209 1213 itself.
1210 1214
1211 1215 In version 1, the delta is always applied against the previous node from
1212 1216 the changegroup or the first parent if this is the first entry in the
1213 1217 changegroup.
1214 1218
1215 1219 In version 2 and up, the delta base node is encoded in the entry in the
1216 1220 changegroup. This allows the delta to be expressed against any parent,
1217 1221 which can result in smaller deltas and more efficient encoding of data.
1218 1222
1219 1223 The *flags* field holds bitwise flags affecting the processing of revision
1220 1224 data. The following flags are defined:
1221 1225
1222 1226 32768
1223 1227 Censored revision. The revision's fulltext has been replaced by censor
1224 1228 metadata. May only occur on file revisions.
1225 1229
1226 1230 16384
1227 1231 Ellipsis revision. Revision hash does not match data (likely due to
1228 1232 rewritten parents).
1229 1233
1230 1234 8192
1231 1235 Externally stored. The revision fulltext contains "key:value" "\n"
1232 1236 delimited metadata defining an object stored elsewhere. Used by the LFS
1233 1237 extension.
1234 1238
1235 1239 For historical reasons, the integer values are identical to revlog version
1236 1240 1 per-revision storage flags and correspond to bits being set in this
1237 1241 2-byte field. Bits were allocated starting from the most-significant bit,
1238 1242 hence the reverse ordering and allocation of these flags.
1239 1243
1240 1244 Changeset Segment
1241 1245 =================
1242 1246
1243 1247 The *changeset segment* consists of a single *delta group* holding
1244 1248 changelog data. The *empty chunk* at the end of the *delta group* denotes
1245 1249 the boundary to the *manifest segment*.
1246 1250
1247 1251 Manifest Segment
1248 1252 ================
1249 1253
1250 1254 The *manifest segment* consists of a single *delta group* holding manifest
1251 1255 data. If treemanifests are in use, it contains only the manifest for the
1252 1256 root directory of the repository. Otherwise, it contains the entire
1253 1257 manifest data. The *empty chunk* at the end of the *delta group* denotes
1254 1258 the boundary to the next segment (either the *treemanifests segment* or
1255 1259 the *filelogs segment*, depending on version and the request options).
1256 1260
1257 1261 Treemanifests Segment
1258 1262 ---------------------
1259 1263
1260 1264 The *treemanifests segment* only exists in changegroup version "3", and
1261 1265 only if the 'treemanifest' param is part of the bundle2 changegroup part
1262 1266 (it is not possible to use changegroup version 3 outside of bundle2).
1263 1267 Aside from the filenames in the *treemanifests segment* containing a
1264 1268 trailing "/" character, it behaves identically to the *filelogs segment*
1265 1269 (see below). The final sub-segment is followed by an *empty chunk*
1266 1270 (logically, a sub-segment with filename size 0). This denotes the boundary
1267 1271 to the *filelogs segment*.
1268 1272
1269 1273 Filelogs Segment
1270 1274 ================
1271 1275
1272 1276 The *filelogs segment* consists of multiple sub-segments, each
1273 1277 corresponding to an individual file whose data is being described:
1274 1278
1275 1279 +--------------------------------------------------+
1276 1280 | | | | | |
1277 1281 | filelog0 | filelog1 | filelog2 | ... | 0x0 |
1278 1282 | | | | | (4 bytes) |
1279 1283 | | | | | |
1280 1284 +--------------------------------------------------+
1281 1285
1282 1286 The final filelog sub-segment is followed by an *empty chunk* (logically,
1283 1287 a sub-segment with filename size 0). This denotes the end of the segment
1284 1288 and of the overall changegroup.
1285 1289
1286 1290 Each filelog sub-segment consists of the following:
1287 1291
1288 1292 +------------------------------------------------------+
1289 1293 | | | |
1290 1294 | filename length | filename | delta group |
1291 1295 | (4 bytes) | (<length - 4> bytes) | (various) |
1292 1296 | | | |
1293 1297 +------------------------------------------------------+
1294 1298
1295 1299 That is, a *chunk* consisting of the filename (not terminated or padded)
1296 1300 followed by N chunks constituting the *delta group* for this file. The
1297 1301 *empty chunk* at the end of each *delta group* denotes the boundary to the
1298 1302 next filelog sub-segment.
1299 1303
1300 1304 test advanced, deprecated and experimental options are hidden in command help
1301 1305 $ hg help debugoptADV
1302 1306 hg debugoptADV
1303 1307
1304 1308 (no help text available)
1305 1309
1306 1310 options:
1307 1311
1308 1312 (some details hidden, use --verbose to show complete help)
1309 1313 $ hg help debugoptDEP
1310 1314 hg debugoptDEP
1311 1315
1312 1316 (no help text available)
1313 1317
1314 1318 options:
1315 1319
1316 1320 (some details hidden, use --verbose to show complete help)
1317 1321
1318 1322 $ hg help debugoptEXP
1319 1323 hg debugoptEXP
1320 1324
1321 1325 (no help text available)
1322 1326
1323 1327 options:
1324 1328
1325 1329 (some details hidden, use --verbose to show complete help)
1326 1330
1327 1331 test advanced, deprecated and experimental options are shown with -v
1328 1332 $ hg help -v debugoptADV | grep aopt
1329 1333 --aopt option is (ADVANCED)
1330 1334 $ hg help -v debugoptDEP | grep dopt
1331 1335 --dopt option is (DEPRECATED)
1332 1336 $ hg help -v debugoptEXP | grep eopt
1333 1337 --eopt option is (EXPERIMENTAL)
1334 1338
1335 1339 #if gettext
1336 1340 test deprecated option is hidden with translation with untranslated description
1337 1341 (use many globy for not failing on changed transaction)
1338 1342 $ LANGUAGE=sv hg help debugoptDEP
1339 1343 hg debugoptDEP
1340 1344
1341 1345 (*) (glob)
1342 1346
1343 1347 options:
1344 1348
1345 1349 (some details hidden, use --verbose to show complete help)
1346 1350 #endif
1347 1351
1348 1352 Test commands that collide with topics (issue4240)
1349 1353
1350 1354 $ hg config -hq
1351 1355 hg config [-u] [NAME]...
1352 1356
1353 1357 show combined config settings from all hgrc files
1354 1358 $ hg showconfig -hq
1355 1359 hg config [-u] [NAME]...
1356 1360
1357 1361 show combined config settings from all hgrc files
1358 1362
1359 1363 Test a help topic
1360 1364
1361 1365 $ hg help dates
1362 1366 Date Formats
1363 1367 """"""""""""
1364 1368
1365 1369 Some commands allow the user to specify a date, e.g.:
1366 1370
1367 1371 - backout, commit, import, tag: Specify the commit date.
1368 1372 - log, revert, update: Select revision(s) by date.
1369 1373
1370 1374 Many date formats are valid. Here are some examples:
1371 1375
1372 1376 - "Wed Dec 6 13:18:29 2006" (local timezone assumed)
1373 1377 - "Dec 6 13:18 -0600" (year assumed, time offset provided)
1374 1378 - "Dec 6 13:18 UTC" (UTC and GMT are aliases for +0000)
1375 1379 - "Dec 6" (midnight)
1376 1380 - "13:18" (today assumed)
1377 1381 - "3:39" (3:39AM assumed)
1378 1382 - "3:39pm" (15:39)
1379 1383 - "2006-12-06 13:18:29" (ISO 8601 format)
1380 1384 - "2006-12-6 13:18"
1381 1385 - "2006-12-6"
1382 1386 - "12-6"
1383 1387 - "12/6"
1384 1388 - "12/6/6" (Dec 6 2006)
1385 1389 - "today" (midnight)
1386 1390 - "yesterday" (midnight)
1387 1391 - "now" - right now
1388 1392
1389 1393 Lastly, there is Mercurial's internal format:
1390 1394
1391 1395 - "1165411109 0" (Wed Dec 6 13:18:29 2006 UTC)
1392 1396
1393 1397 This is the internal representation format for dates. The first number is
1394 1398 the number of seconds since the epoch (1970-01-01 00:00 UTC). The second
1395 1399 is the offset of the local timezone, in seconds west of UTC (negative if
1396 1400 the timezone is east of UTC).
1397 1401
1398 1402 The log command also accepts date ranges:
1399 1403
1400 1404 - "<DATE" - at or before a given date/time
1401 1405 - ">DATE" - on or after a given date/time
1402 1406 - "DATE to DATE" - a date range, inclusive
1403 1407 - "-DAYS" - within a given number of days of today
1404 1408
1405 1409 Test repeated config section name
1406 1410
1407 1411 $ hg help config.host
1408 1412 "http_proxy.host"
1409 1413 Host name and (optional) port of the proxy server, for example
1410 1414 "myproxy:8000".
1411 1415
1412 1416 "smtp.host"
1413 1417 Host name of mail server, e.g. "mail.example.com".
1414 1418
1415 1419
1416 1420 Test section name with dot
1417 1421
1418 1422 $ hg help config.ui.username
1419 1423 "ui.username"
1420 1424 The committer of a changeset created when running "commit". Typically
1421 1425 a person's name and email address, e.g. "Fred Widget
1422 1426 <fred@example.com>". Environment variables in the username are
1423 1427 expanded.
1424 1428
1425 1429 (default: "$EMAIL" or "username@hostname". If the username in hgrc is
1426 1430 empty, e.g. if the system admin set "username =" in the system hgrc,
1427 1431 it has to be specified manually or in a different hgrc file)
1428 1432
1429 1433
1430 1434 $ hg help config.annotate.git
1431 1435 abort: help section not found: config.annotate.git
1432 1436 [255]
1433 1437
1434 1438 $ hg help config.update.check
1435 1439 "commands.update.check"
1436 1440 Determines what level of checking 'hg update' will perform before
1437 1441 moving to a destination revision. Valid values are "abort", "none",
1438 1442 "linear", and "noconflict". "abort" always fails if the working
1439 1443 directory has uncommitted changes. "none" performs no checking, and
1440 1444 may result in a merge with uncommitted changes. "linear" allows any
1441 1445 update as long as it follows a straight line in the revision history,
1442 1446 and may trigger a merge with uncommitted changes. "noconflict" will
1443 1447 allow any update which would not trigger a merge with uncommitted
1444 1448 changes, if any are present. (default: "linear")
1445 1449
1446 1450
1447 1451 $ hg help config.commands.update.check
1448 1452 "commands.update.check"
1449 1453 Determines what level of checking 'hg update' will perform before
1450 1454 moving to a destination revision. Valid values are "abort", "none",
1451 1455 "linear", and "noconflict". "abort" always fails if the working
1452 1456 directory has uncommitted changes. "none" performs no checking, and
1453 1457 may result in a merge with uncommitted changes. "linear" allows any
1454 1458 update as long as it follows a straight line in the revision history,
1455 1459 and may trigger a merge with uncommitted changes. "noconflict" will
1456 1460 allow any update which would not trigger a merge with uncommitted
1457 1461 changes, if any are present. (default: "linear")
1458 1462
1459 1463
1460 1464 $ hg help config.ommands.update.check
1461 1465 abort: help section not found: config.ommands.update.check
1462 1466 [255]
1463 1467
1464 1468 Unrelated trailing paragraphs shouldn't be included
1465 1469
1466 1470 $ hg help config.extramsg | grep '^$'
1467 1471
1468 1472
1469 1473 Test capitalized section name
1470 1474
1471 1475 $ hg help scripting.HGPLAIN > /dev/null
1472 1476
1473 1477 Help subsection:
1474 1478
1475 1479 $ hg help config.charsets |grep "Email example:" > /dev/null
1476 1480 [1]
1477 1481
1478 1482 Show nested definitions
1479 1483 ("profiling.type"[break]"ls"[break]"stat"[break])
1480 1484
1481 1485 $ hg help config.type | egrep '^$'|wc -l
1482 1486 \s*3 (re)
1483 1487
1484 1488 $ hg help config.profiling.type.ls
1485 1489 "profiling.type.ls"
1486 1490 Use Python's built-in instrumenting profiler. This profiler works on
1487 1491 all platforms, but each line number it reports is the first line of
1488 1492 a function. This restriction makes it difficult to identify the
1489 1493 expensive parts of a non-trivial function.
1490 1494
1491 1495
1492 1496 Separate sections from subsections
1493 1497
1494 1498 $ hg help config.format | egrep '^ ("|-)|^\s*$' | uniq
1495 1499 "format"
1496 1500 --------
1497 1501
1498 1502 "usegeneraldelta"
1499 1503
1500 1504 "dotencode"
1501 1505
1502 1506 "usefncache"
1503 1507
1504 1508 "usestore"
1505 1509
1506 1510 "sparse-revlog"
1507 1511
1508 1512 "profiling"
1509 1513 -----------
1510 1514
1511 1515 "format"
1512 1516
1513 1517 "progress"
1514 1518 ----------
1515 1519
1516 1520 "format"
1517 1521
1518 1522
1519 1523 Last item in help config.*:
1520 1524
1521 1525 $ hg help config.`hg help config|grep '^ "'| \
1522 1526 > tail -1|sed 's![ "]*!!g'`| \
1523 1527 > grep 'hg help -c config' > /dev/null
1524 1528 [1]
1525 1529
1526 1530 note to use help -c for general hg help config:
1527 1531
1528 1532 $ hg help config |grep 'hg help -c config' > /dev/null
1529 1533
1530 1534 Test templating help
1531 1535
1532 1536 $ hg help templating | egrep '(desc|diffstat|firstline|nonempty) '
1533 1537 desc String. The text of the changeset description.
1534 1538 diffstat String. Statistics of changes with the following format:
1535 1539 firstline Any text. Returns the first line of text.
1536 1540 nonempty Any text. Returns '(none)' if the string is empty.
1537 1541
1538 1542 Test deprecated items
1539 1543
1540 1544 $ hg help -v templating | grep currentbookmark
1541 1545 currentbookmark
1542 1546 $ hg help templating | (grep currentbookmark || true)
1543 1547
1544 1548 Test help hooks
1545 1549
1546 1550 $ cat > helphook1.py <<EOF
1547 1551 > from mercurial import help
1548 1552 >
1549 1553 > def rewrite(ui, topic, doc):
1550 1554 > return doc + b'\nhelphook1\n'
1551 1555 >
1552 1556 > def extsetup(ui):
1553 1557 > help.addtopichook(b'revisions', rewrite)
1554 1558 > EOF
1555 1559 $ cat > helphook2.py <<EOF
1556 1560 > from mercurial import help
1557 1561 >
1558 1562 > def rewrite(ui, topic, doc):
1559 1563 > return doc + b'\nhelphook2\n'
1560 1564 >
1561 1565 > def extsetup(ui):
1562 1566 > help.addtopichook(b'revisions', rewrite)
1563 1567 > EOF
1564 1568 $ echo '[extensions]' >> $HGRCPATH
1565 1569 $ echo "helphook1 = `pwd`/helphook1.py" >> $HGRCPATH
1566 1570 $ echo "helphook2 = `pwd`/helphook2.py" >> $HGRCPATH
1567 1571 $ hg help revsets | grep helphook
1568 1572 helphook1
1569 1573 helphook2
1570 1574
1571 1575 help -c should only show debug --debug
1572 1576
1573 1577 $ hg help -c --debug|egrep debug|wc -l|egrep '^\s*0\s*$'
1574 1578 [1]
1575 1579
1576 1580 help -c should only show deprecated for -v
1577 1581
1578 1582 $ hg help -c -v|egrep DEPRECATED|wc -l|egrep '^\s*0\s*$'
1579 1583 [1]
1580 1584
1581 1585 Test -s / --system
1582 1586
1583 1587 $ hg help config.files -s windows |grep 'etc/mercurial' | \
1584 1588 > wc -l | sed -e 's/ //g'
1585 1589 0
1586 1590 $ hg help config.files --system unix | grep 'USER' | \
1587 1591 > wc -l | sed -e 's/ //g'
1588 1592 0
1589 1593
1590 1594 Test -e / -c / -k combinations
1591 1595
1592 1596 $ hg help -c|egrep '^[A-Z].*:|^ debug'
1593 1597 Commands:
1594 1598 $ hg help -e|egrep '^[A-Z].*:|^ debug'
1595 1599 Extensions:
1596 1600 $ hg help -k|egrep '^[A-Z].*:|^ debug'
1597 1601 Topics:
1598 1602 Commands:
1599 1603 Extensions:
1600 1604 Extension Commands:
1601 1605 $ hg help -c schemes
1602 1606 abort: no such help topic: schemes
1603 1607 (try 'hg help --keyword schemes')
1604 1608 [255]
1605 1609 $ hg help -e schemes |head -1
1606 1610 schemes extension - extend schemes with shortcuts to repository swarms
1607 1611 $ hg help -c -k dates |egrep '^(Topics|Extensions|Commands):'
1608 1612 Commands:
1609 1613 $ hg help -e -k a |egrep '^(Topics|Extensions|Commands):'
1610 1614 Extensions:
1611 1615 $ hg help -e -c -k date |egrep '^(Topics|Extensions|Commands):'
1612 1616 Extensions:
1613 1617 Commands:
1614 1618 $ hg help -c commit > /dev/null
1615 1619 $ hg help -e -c commit > /dev/null
1616 1620 $ hg help -e commit
1617 1621 abort: no such help topic: commit
1618 1622 (try 'hg help --keyword commit')
1619 1623 [255]
1620 1624
1621 1625 Test keyword search help
1622 1626
1623 1627 $ cat > prefixedname.py <<EOF
1624 1628 > '''matched against word "clone"
1625 1629 > '''
1626 1630 > EOF
1627 1631 $ echo '[extensions]' >> $HGRCPATH
1628 1632 $ echo "dot.dot.prefixedname = `pwd`/prefixedname.py" >> $HGRCPATH
1629 1633 $ hg help -k clone
1630 1634 Topics:
1631 1635
1632 1636 config Configuration Files
1633 1637 extensions Using Additional Features
1634 1638 glossary Glossary
1635 1639 phases Working with Phases
1636 1640 subrepos Subrepositories
1637 1641 urls URL Paths
1638 1642
1639 1643 Commands:
1640 1644
1641 1645 bookmarks create a new bookmark or list existing bookmarks
1642 1646 clone make a copy of an existing repository
1643 1647 paths show aliases for remote repositories
1644 1648 pull pull changes from the specified source
1645 1649 update update working directory (or switch revisions)
1646 1650
1647 1651 Extensions:
1648 1652
1649 1653 clonebundles advertise pre-generated bundles to seed clones
1650 1654 narrow create clones which fetch history data for subset of files
1651 1655 (EXPERIMENTAL)
1652 1656 prefixedname matched against word "clone"
1653 1657 relink recreates hardlinks between repository clones
1654 1658
1655 1659 Extension Commands:
1656 1660
1657 1661 qclone clone main and patch repository at same time
1658 1662
1659 1663 Test unfound topic
1660 1664
1661 1665 $ hg help nonexistingtopicthatwillneverexisteverever
1662 1666 abort: no such help topic: nonexistingtopicthatwillneverexisteverever
1663 1667 (try 'hg help --keyword nonexistingtopicthatwillneverexisteverever')
1664 1668 [255]
1665 1669
1666 1670 Test unfound keyword
1667 1671
1668 1672 $ hg help --keyword nonexistingwordthatwillneverexisteverever
1669 1673 abort: no matches
1670 1674 (try 'hg help' for a list of topics)
1671 1675 [255]
1672 1676
1673 1677 Test omit indicating for help
1674 1678
1675 1679 $ cat > addverboseitems.py <<EOF
1676 1680 > r'''extension to test omit indicating.
1677 1681 >
1678 1682 > This paragraph is never omitted (for extension)
1679 1683 >
1680 1684 > .. container:: verbose
1681 1685 >
1682 1686 > This paragraph is omitted,
1683 1687 > if :hg:\`help\` is invoked without \`\`-v\`\` (for extension)
1684 1688 >
1685 1689 > This paragraph is never omitted, too (for extension)
1686 1690 > '''
1687 1691 > from __future__ import absolute_import
1688 1692 > from mercurial import commands, help
1689 1693 > testtopic = br"""This paragraph is never omitted (for topic).
1690 1694 >
1691 1695 > .. container:: verbose
1692 1696 >
1693 1697 > This paragraph is omitted,
1694 1698 > if :hg:\`help\` is invoked without \`\`-v\`\` (for topic)
1695 1699 >
1696 1700 > This paragraph is never omitted, too (for topic)
1697 1701 > """
1698 1702 > def extsetup(ui):
1699 1703 > help.helptable.append(([b"topic-containing-verbose"],
1700 1704 > b"This is the topic to test omit indicating.",
1701 1705 > lambda ui: testtopic))
1702 1706 > EOF
1703 1707 $ echo '[extensions]' >> $HGRCPATH
1704 1708 $ echo "addverboseitems = `pwd`/addverboseitems.py" >> $HGRCPATH
1705 1709 $ hg help addverboseitems
1706 1710 addverboseitems extension - extension to test omit indicating.
1707 1711
1708 1712 This paragraph is never omitted (for extension)
1709 1713
1710 1714 This paragraph is never omitted, too (for extension)
1711 1715
1712 1716 (some details hidden, use --verbose to show complete help)
1713 1717
1714 1718 no commands defined
1715 1719 $ hg help -v addverboseitems
1716 1720 addverboseitems extension - extension to test omit indicating.
1717 1721
1718 1722 This paragraph is never omitted (for extension)
1719 1723
1720 1724 This paragraph is omitted, if 'hg help' is invoked without "-v" (for
1721 1725 extension)
1722 1726
1723 1727 This paragraph is never omitted, too (for extension)
1724 1728
1725 1729 no commands defined
1726 1730 $ hg help topic-containing-verbose
1727 1731 This is the topic to test omit indicating.
1728 1732 """"""""""""""""""""""""""""""""""""""""""
1729 1733
1730 1734 This paragraph is never omitted (for topic).
1731 1735
1732 1736 This paragraph is never omitted, too (for topic)
1733 1737
1734 1738 (some details hidden, use --verbose to show complete help)
1735 1739 $ hg help -v topic-containing-verbose
1736 1740 This is the topic to test omit indicating.
1737 1741 """"""""""""""""""""""""""""""""""""""""""
1738 1742
1739 1743 This paragraph is never omitted (for topic).
1740 1744
1741 1745 This paragraph is omitted, if 'hg help' is invoked without "-v" (for
1742 1746 topic)
1743 1747
1744 1748 This paragraph is never omitted, too (for topic)
1745 1749
1746 1750 Test section lookup
1747 1751
1748 1752 $ hg help revset.merge
1749 1753 "merge()"
1750 1754 Changeset is a merge changeset.
1751 1755
1752 1756 $ hg help glossary.dag
1753 1757 DAG
1754 1758 The repository of changesets of a distributed version control system
1755 1759 (DVCS) can be described as a directed acyclic graph (DAG), consisting
1756 1760 of nodes and edges, where nodes correspond to changesets and edges
1757 1761 imply a parent -> child relation. This graph can be visualized by
1758 1762 graphical tools such as 'hg log --graph'. In Mercurial, the DAG is
1759 1763 limited by the requirement for children to have at most two parents.
1760 1764
1761 1765
1762 1766 $ hg help hgrc.paths
1763 1767 "paths"
1764 1768 -------
1765 1769
1766 1770 Assigns symbolic names and behavior to repositories.
1767 1771
1768 1772 Options are symbolic names defining the URL or directory that is the
1769 1773 location of the repository. Example:
1770 1774
1771 1775 [paths]
1772 1776 my_server = https://example.com/my_repo
1773 1777 local_path = /home/me/repo
1774 1778
1775 1779 These symbolic names can be used from the command line. To pull from
1776 1780 "my_server": 'hg pull my_server'. To push to "local_path": 'hg push
1777 1781 local_path'.
1778 1782
1779 1783 Options containing colons (":") denote sub-options that can influence
1780 1784 behavior for that specific path. Example:
1781 1785
1782 1786 [paths]
1783 1787 my_server = https://example.com/my_path
1784 1788 my_server:pushurl = ssh://example.com/my_path
1785 1789
1786 1790 The following sub-options can be defined:
1787 1791
1788 1792 "pushurl"
1789 1793 The URL to use for push operations. If not defined, the location
1790 1794 defined by the path's main entry is used.
1791 1795
1792 1796 "pushrev"
1793 1797 A revset defining which revisions to push by default.
1794 1798
1795 1799 When 'hg push' is executed without a "-r" argument, the revset defined
1796 1800 by this sub-option is evaluated to determine what to push.
1797 1801
1798 1802 For example, a value of "." will push the working directory's revision
1799 1803 by default.
1800 1804
1801 1805 Revsets specifying bookmarks will not result in the bookmark being
1802 1806 pushed.
1803 1807
1804 1808 The following special named paths exist:
1805 1809
1806 1810 "default"
1807 1811 The URL or directory to use when no source or remote is specified.
1808 1812
1809 1813 'hg clone' will automatically define this path to the location the
1810 1814 repository was cloned from.
1811 1815
1812 1816 "default-push"
1813 1817 (deprecated) The URL or directory for the default 'hg push' location.
1814 1818 "default:pushurl" should be used instead.
1815 1819
1816 1820 $ hg help glossary.mcguffin
1817 1821 abort: help section not found: glossary.mcguffin
1818 1822 [255]
1819 1823
1820 1824 $ hg help glossary.mc.guffin
1821 1825 abort: help section not found: glossary.mc.guffin
1822 1826 [255]
1823 1827
1824 1828 $ hg help template.files
1825 1829 files List of strings. All files modified, added, or removed by
1826 1830 this changeset.
1827 1831 files(pattern)
1828 1832 All files of the current changeset matching the pattern. See
1829 1833 'hg help patterns'.
1830 1834
1831 1835 Test section lookup by translated message
1832 1836
1833 1837 str.lower() instead of encoding.lower(str) on translated message might
1834 1838 make message meaningless, because some encoding uses 0x41(A) - 0x5a(Z)
1835 1839 as the second or later byte of multi-byte character.
1836 1840
1837 1841 For example, "\x8bL\x98^" (translation of "record" in ja_JP.cp932)
1838 1842 contains 0x4c (L). str.lower() replaces 0x4c(L) by 0x6c(l) and this
1839 1843 replacement makes message meaningless.
1840 1844
1841 1845 This tests that section lookup by translated string isn't broken by
1842 1846 such str.lower().
1843 1847
1844 1848 $ "$PYTHON" <<EOF
1845 1849 > def escape(s):
1846 1850 > return b''.join(b'\\u%x' % ord(uc) for uc in s.decode('cp932'))
1847 1851 > # translation of "record" in ja_JP.cp932
1848 1852 > upper = b"\x8bL\x98^"
1849 1853 > # str.lower()-ed section name should be treated as different one
1850 1854 > lower = b"\x8bl\x98^"
1851 1855 > with open('ambiguous.py', 'wb') as fp:
1852 1856 > fp.write(b"""# ambiguous section names in ja_JP.cp932
1853 1857 > u'''summary of extension
1854 1858 >
1855 1859 > %s
1856 1860 > ----
1857 1861 >
1858 1862 > Upper name should show only this message
1859 1863 >
1860 1864 > %s
1861 1865 > ----
1862 1866 >
1863 1867 > Lower name should show only this message
1864 1868 >
1865 1869 > subsequent section
1866 1870 > ------------------
1867 1871 >
1868 1872 > This should be hidden at 'hg help ambiguous' with section name.
1869 1873 > '''
1870 1874 > """ % (escape(upper), escape(lower)))
1871 1875 > EOF
1872 1876
1873 1877 $ cat >> $HGRCPATH <<EOF
1874 1878 > [extensions]
1875 1879 > ambiguous = ./ambiguous.py
1876 1880 > EOF
1877 1881
1878 1882 $ "$PYTHON" <<EOF | sh
1879 1883 > from mercurial import pycompat
1880 1884 > upper = b"\x8bL\x98^"
1881 1885 > pycompat.stdout.write(b"hg --encoding cp932 help -e ambiguous.%s\n" % upper)
1882 1886 > EOF
1883 1887 \x8bL\x98^ (esc)
1884 1888 ----
1885 1889
1886 1890 Upper name should show only this message
1887 1891
1888 1892
1889 1893 $ "$PYTHON" <<EOF | sh
1890 1894 > from mercurial import pycompat
1891 1895 > lower = b"\x8bl\x98^"
1892 1896 > pycompat.stdout.write(b"hg --encoding cp932 help -e ambiguous.%s\n" % lower)
1893 1897 > EOF
1894 1898 \x8bl\x98^ (esc)
1895 1899 ----
1896 1900
1897 1901 Lower name should show only this message
1898 1902
1899 1903
1900 1904 $ cat >> $HGRCPATH <<EOF
1901 1905 > [extensions]
1902 1906 > ambiguous = !
1903 1907 > EOF
1904 1908
1905 1909 Show help content of disabled extensions
1906 1910
1907 1911 $ cat >> $HGRCPATH <<EOF
1908 1912 > [extensions]
1909 1913 > ambiguous = !./ambiguous.py
1910 1914 > EOF
1911 1915 $ hg help -e ambiguous
1912 1916 ambiguous extension - (no help text available)
1913 1917
1914 1918 (use 'hg help extensions' for information on enabling extensions)
1915 1919
1916 1920 Test dynamic list of merge tools only shows up once
1917 1921 $ hg help merge-tools
1918 1922 Merge Tools
1919 1923 """""""""""
1920 1924
1921 1925 To merge files Mercurial uses merge tools.
1922 1926
1923 1927 A merge tool combines two different versions of a file into a merged file.
1924 1928 Merge tools are given the two files and the greatest common ancestor of
1925 1929 the two file versions, so they can determine the changes made on both
1926 1930 branches.
1927 1931
1928 1932 Merge tools are used both for 'hg resolve', 'hg merge', 'hg update', 'hg
1929 1933 backout' and in several extensions.
1930 1934
1931 1935 Usually, the merge tool tries to automatically reconcile the files by
1932 1936 combining all non-overlapping changes that occurred separately in the two
1933 1937 different evolutions of the same initial base file. Furthermore, some
1934 1938 interactive merge programs make it easier to manually resolve conflicting
1935 1939 merges, either in a graphical way, or by inserting some conflict markers.
1936 1940 Mercurial does not include any interactive merge programs but relies on
1937 1941 external tools for that.
1938 1942
1939 1943 Available merge tools
1940 1944 =====================
1941 1945
1942 1946 External merge tools and their properties are configured in the merge-
1943 1947 tools configuration section - see hgrc(5) - but they can often just be
1944 1948 named by their executable.
1945 1949
1946 1950 A merge tool is generally usable if its executable can be found on the
1947 1951 system and if it can handle the merge. The executable is found if it is an
1948 1952 absolute or relative executable path or the name of an application in the
1949 1953 executable search path. The tool is assumed to be able to handle the merge
1950 1954 if it can handle symlinks if the file is a symlink, if it can handle
1951 1955 binary files if the file is binary, and if a GUI is available if the tool
1952 1956 requires a GUI.
1953 1957
1954 1958 There are some internal merge tools which can be used. The internal merge
1955 1959 tools are:
1956 1960
1957 1961 ":dump"
1958 1962 Creates three versions of the files to merge, containing the contents of
1959 1963 local, other and base. These files can then be used to perform a merge
1960 1964 manually. If the file to be merged is named "a.txt", these files will
1961 1965 accordingly be named "a.txt.local", "a.txt.other" and "a.txt.base" and
1962 1966 they will be placed in the same directory as "a.txt".
1963 1967
1964 1968 This implies premerge. Therefore, files aren't dumped, if premerge runs
1965 1969 successfully. Use :forcedump to forcibly write files out.
1966 1970
1967 1971 (actual capabilities: binary, symlink)
1968 1972
1969 1973 ":fail"
1970 1974 Rather than attempting to merge files that were modified on both
1971 1975 branches, it marks them as unresolved. The resolve command must be used
1972 1976 to resolve these conflicts.
1973 1977
1974 1978 (actual capabilities: binary, symlink)
1975 1979
1976 1980 ":forcedump"
1977 1981 Creates three versions of the files as same as :dump, but omits
1978 1982 premerge.
1979 1983
1980 1984 (actual capabilities: binary, symlink)
1981 1985
1982 1986 ":local"
1983 1987 Uses the local 'p1()' version of files as the merged version.
1984 1988
1985 1989 (actual capabilities: binary, symlink)
1986 1990
1987 1991 ":merge"
1988 1992 Uses the internal non-interactive simple merge algorithm for merging
1989 1993 files. It will fail if there are any conflicts and leave markers in the
1990 1994 partially merged file. Markers will have two sections, one for each side
1991 1995 of merge.
1992 1996
1993 1997 ":merge-local"
1994 1998 Like :merge, but resolve all conflicts non-interactively in favor of the
1995 1999 local 'p1()' changes.
1996 2000
1997 2001 ":merge-other"
1998 2002 Like :merge, but resolve all conflicts non-interactively in favor of the
1999 2003 other 'p2()' changes.
2000 2004
2001 2005 ":merge3"
2002 2006 Uses the internal non-interactive simple merge algorithm for merging
2003 2007 files. It will fail if there are any conflicts and leave markers in the
2004 2008 partially merged file. Marker will have three sections, one from each
2005 2009 side of the merge and one for the base content.
2006 2010
2007 2011 ":other"
2008 2012 Uses the other 'p2()' version of files as the merged version.
2009 2013
2010 2014 (actual capabilities: binary, symlink)
2011 2015
2012 2016 ":prompt"
2013 2017 Asks the user which of the local 'p1()' or the other 'p2()' version to
2014 2018 keep as the merged version.
2015 2019
2016 2020 (actual capabilities: binary, symlink)
2017 2021
2018 2022 ":tagmerge"
2019 2023 Uses the internal tag merge algorithm (experimental).
2020 2024
2021 2025 ":union"
2022 2026 Uses the internal non-interactive simple merge algorithm for merging
2023 2027 files. It will use both left and right sides for conflict regions. No
2024 2028 markers are inserted.
2025 2029
2026 2030 Internal tools are always available and do not require a GUI but will by
2027 2031 default not handle symlinks or binary files. See next section for detail
2028 2032 about "actual capabilities" described above.
2029 2033
2030 2034 Choosing a merge tool
2031 2035 =====================
2032 2036
2033 2037 Mercurial uses these rules when deciding which merge tool to use:
2034 2038
2035 2039 1. If a tool has been specified with the --tool option to merge or
2036 2040 resolve, it is used. If it is the name of a tool in the merge-tools
2037 2041 configuration, its configuration is used. Otherwise the specified tool
2038 2042 must be executable by the shell.
2039 2043 2. If the "HGMERGE" environment variable is present, its value is used and
2040 2044 must be executable by the shell.
2041 2045 3. If the filename of the file to be merged matches any of the patterns in
2042 2046 the merge-patterns configuration section, the first usable merge tool
2043 2047 corresponding to a matching pattern is used.
2044 2048 4. If ui.merge is set it will be considered next. If the value is not the
2045 2049 name of a configured tool, the specified value is used and must be
2046 2050 executable by the shell. Otherwise the named tool is used if it is
2047 2051 usable.
2048 2052 5. If any usable merge tools are present in the merge-tools configuration
2049 2053 section, the one with the highest priority is used.
2050 2054 6. If a program named "hgmerge" can be found on the system, it is used -
2051 2055 but it will by default not be used for symlinks and binary files.
2052 2056 7. If the file to be merged is not binary and is not a symlink, then
2053 2057 internal ":merge" is used.
2054 2058 8. Otherwise, ":prompt" is used.
2055 2059
2056 2060 For historical reason, Mercurial treats merge tools as below while
2057 2061 examining rules above.
2058 2062
2059 2063 step specified via binary symlink
2060 2064 ----------------------------------
2061 2065 1. --tool o/o o/o
2062 2066 2. HGMERGE o/o o/o
2063 2067 3. merge-patterns o/o(*) x/?(*)
2064 2068 4. ui.merge x/?(*) x/?(*)
2065 2069
2066 2070 Each capability column indicates Mercurial behavior for internal/external
2067 2071 merge tools at examining each rule.
2068 2072
2069 2073 - "o": "assume that a tool has capability"
2070 2074 - "x": "assume that a tool does not have capability"
2071 2075 - "?": "check actual capability of a tool"
2072 2076
2073 2077 If "merge.strict-capability-check" configuration is true, Mercurial checks
2074 2078 capabilities of merge tools strictly in (*) cases above (= each capability
2075 2079 column becomes "?/?"). It is false by default for backward compatibility.
2076 2080
2077 2081 Note:
2078 2082 After selecting a merge program, Mercurial will by default attempt to
2079 2083 merge the files using a simple merge algorithm first. Only if it
2080 2084 doesn't succeed because of conflicting changes will Mercurial actually
2081 2085 execute the merge program. Whether to use the simple merge algorithm
2082 2086 first can be controlled by the premerge setting of the merge tool.
2083 2087 Premerge is enabled by default unless the file is binary or a symlink.
2084 2088
2085 2089 See the merge-tools and ui sections of hgrc(5) for details on the
2086 2090 configuration of merge tools.
2087 2091
2088 2092 Compression engines listed in `hg help bundlespec`
2089 2093
2090 2094 $ hg help bundlespec | grep gzip
2091 2095 "v1" bundles can only use the "gzip", "bzip2", and "none" compression
2092 2096 An algorithm that produces smaller bundles than "gzip".
2093 2097 This engine will likely produce smaller bundles than "gzip" but will be
2094 2098 "gzip"
2095 2099 better compression than "gzip". It also frequently yields better (?)
2096 2100
2097 2101 Test usage of section marks in help documents
2098 2102
2099 2103 $ cd "$TESTDIR"/../doc
2100 2104 $ "$PYTHON" check-seclevel.py
2101 2105 $ cd $TESTTMP
2102 2106
2103 2107 #if serve
2104 2108
2105 2109 Test the help pages in hgweb.
2106 2110
2107 2111 Dish up an empty repo; serve it cold.
2108 2112
2109 2113 $ hg init "$TESTTMP/test"
2110 2114 $ hg serve -R "$TESTTMP/test" -n test -p $HGPORT -d --pid-file=hg.pid
2111 2115 $ cat hg.pid >> $DAEMON_PIDS
2112 2116
2113 2117 $ get-with-headers.py $LOCALIP:$HGPORT "help"
2114 2118 200 Script output follows
2115 2119
2116 2120 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
2117 2121 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
2118 2122 <head>
2119 2123 <link rel="icon" href="/static/hgicon.png" type="image/png" />
2120 2124 <meta name="robots" content="index, nofollow" />
2121 2125 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
2122 2126 <script type="text/javascript" src="/static/mercurial.js"></script>
2123 2127
2124 2128 <title>Help: Index</title>
2125 2129 </head>
2126 2130 <body>
2127 2131
2128 2132 <div class="container">
2129 2133 <div class="menu">
2130 2134 <div class="logo">
2131 2135 <a href="https://mercurial-scm.org/">
2132 2136 <img src="/static/hglogo.png" alt="mercurial" /></a>
2133 2137 </div>
2134 2138 <ul>
2135 2139 <li><a href="/shortlog">log</a></li>
2136 2140 <li><a href="/graph">graph</a></li>
2137 2141 <li><a href="/tags">tags</a></li>
2138 2142 <li><a href="/bookmarks">bookmarks</a></li>
2139 2143 <li><a href="/branches">branches</a></li>
2140 2144 </ul>
2141 2145 <ul>
2142 2146 <li class="active">help</li>
2143 2147 </ul>
2144 2148 </div>
2145 2149
2146 2150 <div class="main">
2147 2151 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
2148 2152
2149 2153 <form class="search" action="/log">
2150 2154
2151 2155 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
2152 2156 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
2153 2157 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
2154 2158 </form>
2155 2159 <table class="bigtable">
2156 2160 <tr><td colspan="2"><h2><a name="topics" href="#topics">Topics</a></h2></td></tr>
2157 2161
2158 2162 <tr><td>
2159 2163 <a href="/help/bundlespec">
2160 2164 bundlespec
2161 2165 </a>
2162 2166 </td><td>
2163 2167 Bundle File Formats
2164 2168 </td></tr>
2165 2169 <tr><td>
2166 2170 <a href="/help/color">
2167 2171 color
2168 2172 </a>
2169 2173 </td><td>
2170 2174 Colorizing Outputs
2171 2175 </td></tr>
2172 2176 <tr><td>
2173 2177 <a href="/help/config">
2174 2178 config
2175 2179 </a>
2176 2180 </td><td>
2177 2181 Configuration Files
2178 2182 </td></tr>
2179 2183 <tr><td>
2180 2184 <a href="/help/dates">
2181 2185 dates
2182 2186 </a>
2183 2187 </td><td>
2184 2188 Date Formats
2185 2189 </td></tr>
2186 2190 <tr><td>
2187 2191 <a href="/help/deprecated">
2188 2192 deprecated
2189 2193 </a>
2190 2194 </td><td>
2191 2195 Deprecated Features
2192 2196 </td></tr>
2193 2197 <tr><td>
2194 2198 <a href="/help/diffs">
2195 2199 diffs
2196 2200 </a>
2197 2201 </td><td>
2198 2202 Diff Formats
2199 2203 </td></tr>
2200 2204 <tr><td>
2201 2205 <a href="/help/environment">
2202 2206 environment
2203 2207 </a>
2204 2208 </td><td>
2205 2209 Environment Variables
2206 2210 </td></tr>
2207 2211 <tr><td>
2208 2212 <a href="/help/extensions">
2209 2213 extensions
2210 2214 </a>
2211 2215 </td><td>
2212 2216 Using Additional Features
2213 2217 </td></tr>
2214 2218 <tr><td>
2215 2219 <a href="/help/filesets">
2216 2220 filesets
2217 2221 </a>
2218 2222 </td><td>
2219 2223 Specifying File Sets
2220 2224 </td></tr>
2221 2225 <tr><td>
2222 2226 <a href="/help/flags">
2223 2227 flags
2224 2228 </a>
2225 2229 </td><td>
2226 2230 Command-line flags
2227 2231 </td></tr>
2228 2232 <tr><td>
2229 2233 <a href="/help/glossary">
2230 2234 glossary
2231 2235 </a>
2232 2236 </td><td>
2233 2237 Glossary
2234 2238 </td></tr>
2235 2239 <tr><td>
2236 2240 <a href="/help/hgignore">
2237 2241 hgignore
2238 2242 </a>
2239 2243 </td><td>
2240 2244 Syntax for Mercurial Ignore Files
2241 2245 </td></tr>
2242 2246 <tr><td>
2243 2247 <a href="/help/hgweb">
2244 2248 hgweb
2245 2249 </a>
2246 2250 </td><td>
2247 2251 Configuring hgweb
2248 2252 </td></tr>
2249 2253 <tr><td>
2250 2254 <a href="/help/internals">
2251 2255 internals
2252 2256 </a>
2253 2257 </td><td>
2254 2258 Technical implementation topics
2255 2259 </td></tr>
2256 2260 <tr><td>
2257 2261 <a href="/help/merge-tools">
2258 2262 merge-tools
2259 2263 </a>
2260 2264 </td><td>
2261 2265 Merge Tools
2262 2266 </td></tr>
2263 2267 <tr><td>
2264 2268 <a href="/help/pager">
2265 2269 pager
2266 2270 </a>
2267 2271 </td><td>
2268 2272 Pager Support
2269 2273 </td></tr>
2270 2274 <tr><td>
2271 2275 <a href="/help/patterns">
2272 2276 patterns
2273 2277 </a>
2274 2278 </td><td>
2275 2279 File Name Patterns
2276 2280 </td></tr>
2277 2281 <tr><td>
2278 2282 <a href="/help/phases">
2279 2283 phases
2280 2284 </a>
2281 2285 </td><td>
2282 2286 Working with Phases
2283 2287 </td></tr>
2284 2288 <tr><td>
2285 2289 <a href="/help/revisions">
2286 2290 revisions
2287 2291 </a>
2288 2292 </td><td>
2289 2293 Specifying Revisions
2290 2294 </td></tr>
2291 2295 <tr><td>
2292 2296 <a href="/help/scripting">
2293 2297 scripting
2294 2298 </a>
2295 2299 </td><td>
2296 2300 Using Mercurial from scripts and automation
2297 2301 </td></tr>
2298 2302 <tr><td>
2299 2303 <a href="/help/subrepos">
2300 2304 subrepos
2301 2305 </a>
2302 2306 </td><td>
2303 2307 Subrepositories
2304 2308 </td></tr>
2305 2309 <tr><td>
2306 2310 <a href="/help/templating">
2307 2311 templating
2308 2312 </a>
2309 2313 </td><td>
2310 2314 Template Usage
2311 2315 </td></tr>
2312 2316 <tr><td>
2313 2317 <a href="/help/urls">
2314 2318 urls
2315 2319 </a>
2316 2320 </td><td>
2317 2321 URL Paths
2318 2322 </td></tr>
2319 2323 <tr><td>
2320 2324 <a href="/help/topic-containing-verbose">
2321 2325 topic-containing-verbose
2322 2326 </a>
2323 2327 </td><td>
2324 2328 This is the topic to test omit indicating.
2325 2329 </td></tr>
2326 2330
2327 2331
2328 2332 <tr><td colspan="2"><h2><a name="main" href="#main">Main Commands</a></h2></td></tr>
2329 2333
2330 2334 <tr><td>
2331 2335 <a href="/help/add">
2332 2336 add
2333 2337 </a>
2334 2338 </td><td>
2335 2339 add the specified files on the next commit
2336 2340 </td></tr>
2337 2341 <tr><td>
2338 2342 <a href="/help/annotate">
2339 2343 annotate
2340 2344 </a>
2341 2345 </td><td>
2342 2346 show changeset information by line for each file
2343 2347 </td></tr>
2344 2348 <tr><td>
2345 2349 <a href="/help/clone">
2346 2350 clone
2347 2351 </a>
2348 2352 </td><td>
2349 2353 make a copy of an existing repository
2350 2354 </td></tr>
2351 2355 <tr><td>
2352 2356 <a href="/help/commit">
2353 2357 commit
2354 2358 </a>
2355 2359 </td><td>
2356 2360 commit the specified files or all outstanding changes
2357 2361 </td></tr>
2358 2362 <tr><td>
2359 2363 <a href="/help/diff">
2360 2364 diff
2361 2365 </a>
2362 2366 </td><td>
2363 2367 diff repository (or selected files)
2364 2368 </td></tr>
2365 2369 <tr><td>
2366 2370 <a href="/help/export">
2367 2371 export
2368 2372 </a>
2369 2373 </td><td>
2370 2374 dump the header and diffs for one or more changesets
2371 2375 </td></tr>
2372 2376 <tr><td>
2373 2377 <a href="/help/forget">
2374 2378 forget
2375 2379 </a>
2376 2380 </td><td>
2377 2381 forget the specified files on the next commit
2378 2382 </td></tr>
2379 2383 <tr><td>
2380 2384 <a href="/help/init">
2381 2385 init
2382 2386 </a>
2383 2387 </td><td>
2384 2388 create a new repository in the given directory
2385 2389 </td></tr>
2386 2390 <tr><td>
2387 2391 <a href="/help/log">
2388 2392 log
2389 2393 </a>
2390 2394 </td><td>
2391 2395 show revision history of entire repository or files
2392 2396 </td></tr>
2393 2397 <tr><td>
2394 2398 <a href="/help/merge">
2395 2399 merge
2396 2400 </a>
2397 2401 </td><td>
2398 2402 merge another revision into working directory
2399 2403 </td></tr>
2400 2404 <tr><td>
2401 2405 <a href="/help/pull">
2402 2406 pull
2403 2407 </a>
2404 2408 </td><td>
2405 2409 pull changes from the specified source
2406 2410 </td></tr>
2407 2411 <tr><td>
2408 2412 <a href="/help/push">
2409 2413 push
2410 2414 </a>
2411 2415 </td><td>
2412 2416 push changes to the specified destination
2413 2417 </td></tr>
2414 2418 <tr><td>
2415 2419 <a href="/help/remove">
2416 2420 remove
2417 2421 </a>
2418 2422 </td><td>
2419 2423 remove the specified files on the next commit
2420 2424 </td></tr>
2421 2425 <tr><td>
2422 2426 <a href="/help/serve">
2423 2427 serve
2424 2428 </a>
2425 2429 </td><td>
2426 2430 start stand-alone webserver
2427 2431 </td></tr>
2428 2432 <tr><td>
2429 2433 <a href="/help/status">
2430 2434 status
2431 2435 </a>
2432 2436 </td><td>
2433 2437 show changed files in the working directory
2434 2438 </td></tr>
2435 2439 <tr><td>
2436 2440 <a href="/help/summary">
2437 2441 summary
2438 2442 </a>
2439 2443 </td><td>
2440 2444 summarize working directory state
2441 2445 </td></tr>
2442 2446 <tr><td>
2443 2447 <a href="/help/update">
2444 2448 update
2445 2449 </a>
2446 2450 </td><td>
2447 2451 update working directory (or switch revisions)
2448 2452 </td></tr>
2449 2453
2450 2454
2451 2455
2452 2456 <tr><td colspan="2"><h2><a name="other" href="#other">Other Commands</a></h2></td></tr>
2453 2457
2454 2458 <tr><td>
2455 2459 <a href="/help/addremove">
2456 2460 addremove
2457 2461 </a>
2458 2462 </td><td>
2459 2463 add all new files, delete all missing files
2460 2464 </td></tr>
2461 2465 <tr><td>
2462 2466 <a href="/help/archive">
2463 2467 archive
2464 2468 </a>
2465 2469 </td><td>
2466 2470 create an unversioned archive of a repository revision
2467 2471 </td></tr>
2468 2472 <tr><td>
2469 2473 <a href="/help/backout">
2470 2474 backout
2471 2475 </a>
2472 2476 </td><td>
2473 2477 reverse effect of earlier changeset
2474 2478 </td></tr>
2475 2479 <tr><td>
2476 2480 <a href="/help/bisect">
2477 2481 bisect
2478 2482 </a>
2479 2483 </td><td>
2480 2484 subdivision search of changesets
2481 2485 </td></tr>
2482 2486 <tr><td>
2483 2487 <a href="/help/bookmarks">
2484 2488 bookmarks
2485 2489 </a>
2486 2490 </td><td>
2487 2491 create a new bookmark or list existing bookmarks
2488 2492 </td></tr>
2489 2493 <tr><td>
2490 2494 <a href="/help/branch">
2491 2495 branch
2492 2496 </a>
2493 2497 </td><td>
2494 2498 set or show the current branch name
2495 2499 </td></tr>
2496 2500 <tr><td>
2497 2501 <a href="/help/branches">
2498 2502 branches
2499 2503 </a>
2500 2504 </td><td>
2501 2505 list repository named branches
2502 2506 </td></tr>
2503 2507 <tr><td>
2504 2508 <a href="/help/bundle">
2505 2509 bundle
2506 2510 </a>
2507 2511 </td><td>
2508 2512 create a bundle file
2509 2513 </td></tr>
2510 2514 <tr><td>
2511 2515 <a href="/help/cat">
2512 2516 cat
2513 2517 </a>
2514 2518 </td><td>
2515 2519 output the current or given revision of files
2516 2520 </td></tr>
2517 2521 <tr><td>
2518 2522 <a href="/help/config">
2519 2523 config
2520 2524 </a>
2521 2525 </td><td>
2522 2526 show combined config settings from all hgrc files
2523 2527 </td></tr>
2524 2528 <tr><td>
2525 2529 <a href="/help/copy">
2526 2530 copy
2527 2531 </a>
2528 2532 </td><td>
2529 2533 mark files as copied for the next commit
2530 2534 </td></tr>
2531 2535 <tr><td>
2532 2536 <a href="/help/files">
2533 2537 files
2534 2538 </a>
2535 2539 </td><td>
2536 2540 list tracked files
2537 2541 </td></tr>
2538 2542 <tr><td>
2539 2543 <a href="/help/graft">
2540 2544 graft
2541 2545 </a>
2542 2546 </td><td>
2543 2547 copy changes from other branches onto the current branch
2544 2548 </td></tr>
2545 2549 <tr><td>
2546 2550 <a href="/help/grep">
2547 2551 grep
2548 2552 </a>
2549 2553 </td><td>
2550 2554 search revision history for a pattern in specified files
2551 2555 </td></tr>
2552 2556 <tr><td>
2553 2557 <a href="/help/hashelp">
2554 2558 hashelp
2555 2559 </a>
2556 2560 </td><td>
2557 2561 Extension command's help
2558 2562 </td></tr>
2559 2563 <tr><td>
2560 2564 <a href="/help/heads">
2561 2565 heads
2562 2566 </a>
2563 2567 </td><td>
2564 2568 show branch heads
2565 2569 </td></tr>
2566 2570 <tr><td>
2567 2571 <a href="/help/help">
2568 2572 help
2569 2573 </a>
2570 2574 </td><td>
2571 2575 show help for a given topic or a help overview
2572 2576 </td></tr>
2573 2577 <tr><td>
2574 2578 <a href="/help/hgalias">
2575 2579 hgalias
2576 2580 </a>
2577 2581 </td><td>
2578 2582 My doc
2579 2583 </td></tr>
2580 2584 <tr><td>
2581 2585 <a href="/help/hgaliasnodoc">
2582 2586 hgaliasnodoc
2583 2587 </a>
2584 2588 </td><td>
2585 2589 summarize working directory state
2586 2590 </td></tr>
2587 2591 <tr><td>
2588 2592 <a href="/help/identify">
2589 2593 identify
2590 2594 </a>
2591 2595 </td><td>
2592 2596 identify the working directory or specified revision
2593 2597 </td></tr>
2594 2598 <tr><td>
2595 2599 <a href="/help/import">
2596 2600 import
2597 2601 </a>
2598 2602 </td><td>
2599 2603 import an ordered set of patches
2600 2604 </td></tr>
2601 2605 <tr><td>
2602 2606 <a href="/help/incoming">
2603 2607 incoming
2604 2608 </a>
2605 2609 </td><td>
2606 2610 show new changesets found in source
2607 2611 </td></tr>
2608 2612 <tr><td>
2609 2613 <a href="/help/manifest">
2610 2614 manifest
2611 2615 </a>
2612 2616 </td><td>
2613 2617 output the current or given revision of the project manifest
2614 2618 </td></tr>
2615 2619 <tr><td>
2616 2620 <a href="/help/nohelp">
2617 2621 nohelp
2618 2622 </a>
2619 2623 </td><td>
2620 2624 (no help text available)
2621 2625 </td></tr>
2622 2626 <tr><td>
2623 2627 <a href="/help/outgoing">
2624 2628 outgoing
2625 2629 </a>
2626 2630 </td><td>
2627 2631 show changesets not found in the destination
2628 2632 </td></tr>
2629 2633 <tr><td>
2630 2634 <a href="/help/paths">
2631 2635 paths
2632 2636 </a>
2633 2637 </td><td>
2634 2638 show aliases for remote repositories
2635 2639 </td></tr>
2636 2640 <tr><td>
2637 2641 <a href="/help/phase">
2638 2642 phase
2639 2643 </a>
2640 2644 </td><td>
2641 2645 set or show the current phase name
2642 2646 </td></tr>
2643 2647 <tr><td>
2644 2648 <a href="/help/recover">
2645 2649 recover
2646 2650 </a>
2647 2651 </td><td>
2648 2652 roll back an interrupted transaction
2649 2653 </td></tr>
2650 2654 <tr><td>
2651 2655 <a href="/help/rename">
2652 2656 rename
2653 2657 </a>
2654 2658 </td><td>
2655 2659 rename files; equivalent of copy + remove
2656 2660 </td></tr>
2657 2661 <tr><td>
2658 2662 <a href="/help/resolve">
2659 2663 resolve
2660 2664 </a>
2661 2665 </td><td>
2662 2666 redo merges or set/view the merge status of files
2663 2667 </td></tr>
2664 2668 <tr><td>
2665 2669 <a href="/help/revert">
2666 2670 revert
2667 2671 </a>
2668 2672 </td><td>
2669 2673 restore files to their checkout state
2670 2674 </td></tr>
2671 2675 <tr><td>
2672 2676 <a href="/help/root">
2673 2677 root
2674 2678 </a>
2675 2679 </td><td>
2676 2680 print the root (top) of the current working directory
2677 2681 </td></tr>
2678 2682 <tr><td>
2679 2683 <a href="/help/shellalias">
2680 2684 shellalias
2681 2685 </a>
2682 2686 </td><td>
2683 2687 (no help text available)
2684 2688 </td></tr>
2685 2689 <tr><td>
2686 2690 <a href="/help/tag">
2687 2691 tag
2688 2692 </a>
2689 2693 </td><td>
2690 2694 add one or more tags for the current or given revision
2691 2695 </td></tr>
2692 2696 <tr><td>
2693 2697 <a href="/help/tags">
2694 2698 tags
2695 2699 </a>
2696 2700 </td><td>
2697 2701 list repository tags
2698 2702 </td></tr>
2699 2703 <tr><td>
2700 2704 <a href="/help/unbundle">
2701 2705 unbundle
2702 2706 </a>
2703 2707 </td><td>
2704 2708 apply one or more bundle files
2705 2709 </td></tr>
2706 2710 <tr><td>
2707 2711 <a href="/help/verify">
2708 2712 verify
2709 2713 </a>
2710 2714 </td><td>
2711 2715 verify the integrity of the repository
2712 2716 </td></tr>
2713 2717 <tr><td>
2714 2718 <a href="/help/version">
2715 2719 version
2716 2720 </a>
2717 2721 </td><td>
2718 2722 output version and copyright information
2719 2723 </td></tr>
2720 2724
2721 2725
2722 2726 </table>
2723 2727 </div>
2724 2728 </div>
2725 2729
2726 2730
2727 2731
2728 2732 </body>
2729 2733 </html>
2730 2734
2731 2735
2732 2736 $ get-with-headers.py $LOCALIP:$HGPORT "help/add"
2733 2737 200 Script output follows
2734 2738
2735 2739 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
2736 2740 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
2737 2741 <head>
2738 2742 <link rel="icon" href="/static/hgicon.png" type="image/png" />
2739 2743 <meta name="robots" content="index, nofollow" />
2740 2744 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
2741 2745 <script type="text/javascript" src="/static/mercurial.js"></script>
2742 2746
2743 2747 <title>Help: add</title>
2744 2748 </head>
2745 2749 <body>
2746 2750
2747 2751 <div class="container">
2748 2752 <div class="menu">
2749 2753 <div class="logo">
2750 2754 <a href="https://mercurial-scm.org/">
2751 2755 <img src="/static/hglogo.png" alt="mercurial" /></a>
2752 2756 </div>
2753 2757 <ul>
2754 2758 <li><a href="/shortlog">log</a></li>
2755 2759 <li><a href="/graph">graph</a></li>
2756 2760 <li><a href="/tags">tags</a></li>
2757 2761 <li><a href="/bookmarks">bookmarks</a></li>
2758 2762 <li><a href="/branches">branches</a></li>
2759 2763 </ul>
2760 2764 <ul>
2761 2765 <li class="active"><a href="/help">help</a></li>
2762 2766 </ul>
2763 2767 </div>
2764 2768
2765 2769 <div class="main">
2766 2770 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
2767 2771 <h3>Help: add</h3>
2768 2772
2769 2773 <form class="search" action="/log">
2770 2774
2771 2775 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
2772 2776 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
2773 2777 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
2774 2778 </form>
2775 2779 <div id="doc">
2776 2780 <p>
2777 2781 hg add [OPTION]... [FILE]...
2778 2782 </p>
2779 2783 <p>
2780 2784 add the specified files on the next commit
2781 2785 </p>
2782 2786 <p>
2783 2787 Schedule files to be version controlled and added to the
2784 2788 repository.
2785 2789 </p>
2786 2790 <p>
2787 2791 The files will be added to the repository at the next commit. To
2788 2792 undo an add before that, see 'hg forget'.
2789 2793 </p>
2790 2794 <p>
2791 2795 If no names are given, add all files to the repository (except
2792 2796 files matching &quot;.hgignore&quot;).
2793 2797 </p>
2794 2798 <p>
2795 2799 Examples:
2796 2800 </p>
2797 2801 <ul>
2798 2802 <li> New (unknown) files are added automatically by 'hg add':
2799 2803 <pre>
2800 2804 \$ ls (re)
2801 2805 foo.c
2802 2806 \$ hg status (re)
2803 2807 ? foo.c
2804 2808 \$ hg add (re)
2805 2809 adding foo.c
2806 2810 \$ hg status (re)
2807 2811 A foo.c
2808 2812 </pre>
2809 2813 <li> Specific files to be added can be specified:
2810 2814 <pre>
2811 2815 \$ ls (re)
2812 2816 bar.c foo.c
2813 2817 \$ hg status (re)
2814 2818 ? bar.c
2815 2819 ? foo.c
2816 2820 \$ hg add bar.c (re)
2817 2821 \$ hg status (re)
2818 2822 A bar.c
2819 2823 ? foo.c
2820 2824 </pre>
2821 2825 </ul>
2822 2826 <p>
2823 2827 Returns 0 if all files are successfully added.
2824 2828 </p>
2825 2829 <p>
2826 2830 options ([+] can be repeated):
2827 2831 </p>
2828 2832 <table>
2829 2833 <tr><td>-I</td>
2830 2834 <td>--include PATTERN [+]</td>
2831 2835 <td>include names matching the given patterns</td></tr>
2832 2836 <tr><td>-X</td>
2833 2837 <td>--exclude PATTERN [+]</td>
2834 2838 <td>exclude names matching the given patterns</td></tr>
2835 2839 <tr><td>-S</td>
2836 2840 <td>--subrepos</td>
2837 2841 <td>recurse into subrepositories</td></tr>
2838 2842 <tr><td>-n</td>
2839 2843 <td>--dry-run</td>
2840 2844 <td>do not perform actions, just print output</td></tr>
2841 2845 </table>
2842 2846 <p>
2843 2847 global options ([+] can be repeated):
2844 2848 </p>
2845 2849 <table>
2846 2850 <tr><td>-R</td>
2847 2851 <td>--repository REPO</td>
2848 2852 <td>repository root directory or name of overlay bundle file</td></tr>
2849 2853 <tr><td></td>
2850 2854 <td>--cwd DIR</td>
2851 2855 <td>change working directory</td></tr>
2852 2856 <tr><td>-y</td>
2853 2857 <td>--noninteractive</td>
2854 2858 <td>do not prompt, automatically pick the first choice for all prompts</td></tr>
2855 2859 <tr><td>-q</td>
2856 2860 <td>--quiet</td>
2857 2861 <td>suppress output</td></tr>
2858 2862 <tr><td>-v</td>
2859 2863 <td>--verbose</td>
2860 2864 <td>enable additional output</td></tr>
2861 2865 <tr><td></td>
2862 2866 <td>--color TYPE</td>
2863 2867 <td>when to colorize (boolean, always, auto, never, or debug)</td></tr>
2864 2868 <tr><td></td>
2865 2869 <td>--config CONFIG [+]</td>
2866 2870 <td>set/override config option (use 'section.name=value')</td></tr>
2867 2871 <tr><td></td>
2868 2872 <td>--debug</td>
2869 2873 <td>enable debugging output</td></tr>
2870 2874 <tr><td></td>
2871 2875 <td>--debugger</td>
2872 2876 <td>start debugger</td></tr>
2873 2877 <tr><td></td>
2874 2878 <td>--encoding ENCODE</td>
2875 2879 <td>set the charset encoding (default: ascii)</td></tr>
2876 2880 <tr><td></td>
2877 2881 <td>--encodingmode MODE</td>
2878 2882 <td>set the charset encoding mode (default: strict)</td></tr>
2879 2883 <tr><td></td>
2880 2884 <td>--traceback</td>
2881 2885 <td>always print a traceback on exception</td></tr>
2882 2886 <tr><td></td>
2883 2887 <td>--time</td>
2884 2888 <td>time how long the command takes</td></tr>
2885 2889 <tr><td></td>
2886 2890 <td>--profile</td>
2887 2891 <td>print command execution profile</td></tr>
2888 2892 <tr><td></td>
2889 2893 <td>--version</td>
2890 2894 <td>output version information and exit</td></tr>
2891 2895 <tr><td>-h</td>
2892 2896 <td>--help</td>
2893 2897 <td>display help and exit</td></tr>
2894 2898 <tr><td></td>
2895 2899 <td>--hidden</td>
2896 2900 <td>consider hidden changesets</td></tr>
2897 2901 <tr><td></td>
2898 2902 <td>--pager TYPE</td>
2899 2903 <td>when to paginate (boolean, always, auto, or never) (default: auto)</td></tr>
2900 2904 </table>
2901 2905
2902 2906 </div>
2903 2907 </div>
2904 2908 </div>
2905 2909
2906 2910
2907 2911
2908 2912 </body>
2909 2913 </html>
2910 2914
2911 2915
2912 2916 $ get-with-headers.py $LOCALIP:$HGPORT "help/remove"
2913 2917 200 Script output follows
2914 2918
2915 2919 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
2916 2920 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
2917 2921 <head>
2918 2922 <link rel="icon" href="/static/hgicon.png" type="image/png" />
2919 2923 <meta name="robots" content="index, nofollow" />
2920 2924 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
2921 2925 <script type="text/javascript" src="/static/mercurial.js"></script>
2922 2926
2923 2927 <title>Help: remove</title>
2924 2928 </head>
2925 2929 <body>
2926 2930
2927 2931 <div class="container">
2928 2932 <div class="menu">
2929 2933 <div class="logo">
2930 2934 <a href="https://mercurial-scm.org/">
2931 2935 <img src="/static/hglogo.png" alt="mercurial" /></a>
2932 2936 </div>
2933 2937 <ul>
2934 2938 <li><a href="/shortlog">log</a></li>
2935 2939 <li><a href="/graph">graph</a></li>
2936 2940 <li><a href="/tags">tags</a></li>
2937 2941 <li><a href="/bookmarks">bookmarks</a></li>
2938 2942 <li><a href="/branches">branches</a></li>
2939 2943 </ul>
2940 2944 <ul>
2941 2945 <li class="active"><a href="/help">help</a></li>
2942 2946 </ul>
2943 2947 </div>
2944 2948
2945 2949 <div class="main">
2946 2950 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
2947 2951 <h3>Help: remove</h3>
2948 2952
2949 2953 <form class="search" action="/log">
2950 2954
2951 2955 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
2952 2956 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
2953 2957 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
2954 2958 </form>
2955 2959 <div id="doc">
2956 2960 <p>
2957 2961 hg remove [OPTION]... FILE...
2958 2962 </p>
2959 2963 <p>
2960 2964 aliases: rm
2961 2965 </p>
2962 2966 <p>
2963 2967 remove the specified files on the next commit
2964 2968 </p>
2965 2969 <p>
2966 2970 Schedule the indicated files for removal from the current branch.
2967 2971 </p>
2968 2972 <p>
2969 2973 This command schedules the files to be removed at the next commit.
2970 2974 To undo a remove before that, see 'hg revert'. To undo added
2971 2975 files, see 'hg forget'.
2972 2976 </p>
2973 2977 <p>
2974 2978 -A/--after can be used to remove only files that have already
2975 2979 been deleted, -f/--force can be used to force deletion, and -Af
2976 2980 can be used to remove files from the next revision without
2977 2981 deleting them from the working directory.
2978 2982 </p>
2979 2983 <p>
2980 2984 The following table details the behavior of remove for different
2981 2985 file states (columns) and option combinations (rows). The file
2982 2986 states are Added [A], Clean [C], Modified [M] and Missing [!]
2983 2987 (as reported by 'hg status'). The actions are Warn, Remove
2984 2988 (from branch) and Delete (from disk):
2985 2989 </p>
2986 2990 <table>
2987 2991 <tr><td>opt/state</td>
2988 2992 <td>A</td>
2989 2993 <td>C</td>
2990 2994 <td>M</td>
2991 2995 <td>!</td></tr>
2992 2996 <tr><td>none</td>
2993 2997 <td>W</td>
2994 2998 <td>RD</td>
2995 2999 <td>W</td>
2996 3000 <td>R</td></tr>
2997 3001 <tr><td>-f</td>
2998 3002 <td>R</td>
2999 3003 <td>RD</td>
3000 3004 <td>RD</td>
3001 3005 <td>R</td></tr>
3002 3006 <tr><td>-A</td>
3003 3007 <td>W</td>
3004 3008 <td>W</td>
3005 3009 <td>W</td>
3006 3010 <td>R</td></tr>
3007 3011 <tr><td>-Af</td>
3008 3012 <td>R</td>
3009 3013 <td>R</td>
3010 3014 <td>R</td>
3011 3015 <td>R</td></tr>
3012 3016 </table>
3013 3017 <p>
3014 3018 <b>Note:</b>
3015 3019 </p>
3016 3020 <p>
3017 3021 'hg remove' never deletes files in Added [A] state from the
3018 3022 working directory, not even if &quot;--force&quot; is specified.
3019 3023 </p>
3020 3024 <p>
3021 3025 Returns 0 on success, 1 if any warnings encountered.
3022 3026 </p>
3023 3027 <p>
3024 3028 options ([+] can be repeated):
3025 3029 </p>
3026 3030 <table>
3027 3031 <tr><td>-A</td>
3028 3032 <td>--after</td>
3029 3033 <td>record delete for missing files</td></tr>
3030 3034 <tr><td>-f</td>
3031 3035 <td>--force</td>
3032 3036 <td>forget added files, delete modified files</td></tr>
3033 3037 <tr><td>-S</td>
3034 3038 <td>--subrepos</td>
3035 3039 <td>recurse into subrepositories</td></tr>
3036 3040 <tr><td>-I</td>
3037 3041 <td>--include PATTERN [+]</td>
3038 3042 <td>include names matching the given patterns</td></tr>
3039 3043 <tr><td>-X</td>
3040 3044 <td>--exclude PATTERN [+]</td>
3041 3045 <td>exclude names matching the given patterns</td></tr>
3042 3046 <tr><td>-n</td>
3043 3047 <td>--dry-run</td>
3044 3048 <td>do not perform actions, just print output</td></tr>
3045 3049 </table>
3046 3050 <p>
3047 3051 global options ([+] can be repeated):
3048 3052 </p>
3049 3053 <table>
3050 3054 <tr><td>-R</td>
3051 3055 <td>--repository REPO</td>
3052 3056 <td>repository root directory or name of overlay bundle file</td></tr>
3053 3057 <tr><td></td>
3054 3058 <td>--cwd DIR</td>
3055 3059 <td>change working directory</td></tr>
3056 3060 <tr><td>-y</td>
3057 3061 <td>--noninteractive</td>
3058 3062 <td>do not prompt, automatically pick the first choice for all prompts</td></tr>
3059 3063 <tr><td>-q</td>
3060 3064 <td>--quiet</td>
3061 3065 <td>suppress output</td></tr>
3062 3066 <tr><td>-v</td>
3063 3067 <td>--verbose</td>
3064 3068 <td>enable additional output</td></tr>
3065 3069 <tr><td></td>
3066 3070 <td>--color TYPE</td>
3067 3071 <td>when to colorize (boolean, always, auto, never, or debug)</td></tr>
3068 3072 <tr><td></td>
3069 3073 <td>--config CONFIG [+]</td>
3070 3074 <td>set/override config option (use 'section.name=value')</td></tr>
3071 3075 <tr><td></td>
3072 3076 <td>--debug</td>
3073 3077 <td>enable debugging output</td></tr>
3074 3078 <tr><td></td>
3075 3079 <td>--debugger</td>
3076 3080 <td>start debugger</td></tr>
3077 3081 <tr><td></td>
3078 3082 <td>--encoding ENCODE</td>
3079 3083 <td>set the charset encoding (default: ascii)</td></tr>
3080 3084 <tr><td></td>
3081 3085 <td>--encodingmode MODE</td>
3082 3086 <td>set the charset encoding mode (default: strict)</td></tr>
3083 3087 <tr><td></td>
3084 3088 <td>--traceback</td>
3085 3089 <td>always print a traceback on exception</td></tr>
3086 3090 <tr><td></td>
3087 3091 <td>--time</td>
3088 3092 <td>time how long the command takes</td></tr>
3089 3093 <tr><td></td>
3090 3094 <td>--profile</td>
3091 3095 <td>print command execution profile</td></tr>
3092 3096 <tr><td></td>
3093 3097 <td>--version</td>
3094 3098 <td>output version information and exit</td></tr>
3095 3099 <tr><td>-h</td>
3096 3100 <td>--help</td>
3097 3101 <td>display help and exit</td></tr>
3098 3102 <tr><td></td>
3099 3103 <td>--hidden</td>
3100 3104 <td>consider hidden changesets</td></tr>
3101 3105 <tr><td></td>
3102 3106 <td>--pager TYPE</td>
3103 3107 <td>when to paginate (boolean, always, auto, or never) (default: auto)</td></tr>
3104 3108 </table>
3105 3109
3106 3110 </div>
3107 3111 </div>
3108 3112 </div>
3109 3113
3110 3114
3111 3115
3112 3116 </body>
3113 3117 </html>
3114 3118
3115 3119
3116 3120 $ get-with-headers.py $LOCALIP:$HGPORT "help/dates"
3117 3121 200 Script output follows
3118 3122
3119 3123 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3120 3124 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3121 3125 <head>
3122 3126 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3123 3127 <meta name="robots" content="index, nofollow" />
3124 3128 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3125 3129 <script type="text/javascript" src="/static/mercurial.js"></script>
3126 3130
3127 3131 <title>Help: dates</title>
3128 3132 </head>
3129 3133 <body>
3130 3134
3131 3135 <div class="container">
3132 3136 <div class="menu">
3133 3137 <div class="logo">
3134 3138 <a href="https://mercurial-scm.org/">
3135 3139 <img src="/static/hglogo.png" alt="mercurial" /></a>
3136 3140 </div>
3137 3141 <ul>
3138 3142 <li><a href="/shortlog">log</a></li>
3139 3143 <li><a href="/graph">graph</a></li>
3140 3144 <li><a href="/tags">tags</a></li>
3141 3145 <li><a href="/bookmarks">bookmarks</a></li>
3142 3146 <li><a href="/branches">branches</a></li>
3143 3147 </ul>
3144 3148 <ul>
3145 3149 <li class="active"><a href="/help">help</a></li>
3146 3150 </ul>
3147 3151 </div>
3148 3152
3149 3153 <div class="main">
3150 3154 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3151 3155 <h3>Help: dates</h3>
3152 3156
3153 3157 <form class="search" action="/log">
3154 3158
3155 3159 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3156 3160 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3157 3161 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3158 3162 </form>
3159 3163 <div id="doc">
3160 3164 <h1>Date Formats</h1>
3161 3165 <p>
3162 3166 Some commands allow the user to specify a date, e.g.:
3163 3167 </p>
3164 3168 <ul>
3165 3169 <li> backout, commit, import, tag: Specify the commit date.
3166 3170 <li> log, revert, update: Select revision(s) by date.
3167 3171 </ul>
3168 3172 <p>
3169 3173 Many date formats are valid. Here are some examples:
3170 3174 </p>
3171 3175 <ul>
3172 3176 <li> &quot;Wed Dec 6 13:18:29 2006&quot; (local timezone assumed)
3173 3177 <li> &quot;Dec 6 13:18 -0600&quot; (year assumed, time offset provided)
3174 3178 <li> &quot;Dec 6 13:18 UTC&quot; (UTC and GMT are aliases for +0000)
3175 3179 <li> &quot;Dec 6&quot; (midnight)
3176 3180 <li> &quot;13:18&quot; (today assumed)
3177 3181 <li> &quot;3:39&quot; (3:39AM assumed)
3178 3182 <li> &quot;3:39pm&quot; (15:39)
3179 3183 <li> &quot;2006-12-06 13:18:29&quot; (ISO 8601 format)
3180 3184 <li> &quot;2006-12-6 13:18&quot;
3181 3185 <li> &quot;2006-12-6&quot;
3182 3186 <li> &quot;12-6&quot;
3183 3187 <li> &quot;12/6&quot;
3184 3188 <li> &quot;12/6/6&quot; (Dec 6 2006)
3185 3189 <li> &quot;today&quot; (midnight)
3186 3190 <li> &quot;yesterday&quot; (midnight)
3187 3191 <li> &quot;now&quot; - right now
3188 3192 </ul>
3189 3193 <p>
3190 3194 Lastly, there is Mercurial's internal format:
3191 3195 </p>
3192 3196 <ul>
3193 3197 <li> &quot;1165411109 0&quot; (Wed Dec 6 13:18:29 2006 UTC)
3194 3198 </ul>
3195 3199 <p>
3196 3200 This is the internal representation format for dates. The first number
3197 3201 is the number of seconds since the epoch (1970-01-01 00:00 UTC). The
3198 3202 second is the offset of the local timezone, in seconds west of UTC
3199 3203 (negative if the timezone is east of UTC).
3200 3204 </p>
3201 3205 <p>
3202 3206 The log command also accepts date ranges:
3203 3207 </p>
3204 3208 <ul>
3205 3209 <li> &quot;&lt;DATE&quot; - at or before a given date/time
3206 3210 <li> &quot;&gt;DATE&quot; - on or after a given date/time
3207 3211 <li> &quot;DATE to DATE&quot; - a date range, inclusive
3208 3212 <li> &quot;-DAYS&quot; - within a given number of days of today
3209 3213 </ul>
3210 3214
3211 3215 </div>
3212 3216 </div>
3213 3217 </div>
3214 3218
3215 3219
3216 3220
3217 3221 </body>
3218 3222 </html>
3219 3223
3220 3224
3221 3225 $ get-with-headers.py $LOCALIP:$HGPORT "help/pager"
3222 3226 200 Script output follows
3223 3227
3224 3228 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3225 3229 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3226 3230 <head>
3227 3231 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3228 3232 <meta name="robots" content="index, nofollow" />
3229 3233 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3230 3234 <script type="text/javascript" src="/static/mercurial.js"></script>
3231 3235
3232 3236 <title>Help: pager</title>
3233 3237 </head>
3234 3238 <body>
3235 3239
3236 3240 <div class="container">
3237 3241 <div class="menu">
3238 3242 <div class="logo">
3239 3243 <a href="https://mercurial-scm.org/">
3240 3244 <img src="/static/hglogo.png" alt="mercurial" /></a>
3241 3245 </div>
3242 3246 <ul>
3243 3247 <li><a href="/shortlog">log</a></li>
3244 3248 <li><a href="/graph">graph</a></li>
3245 3249 <li><a href="/tags">tags</a></li>
3246 3250 <li><a href="/bookmarks">bookmarks</a></li>
3247 3251 <li><a href="/branches">branches</a></li>
3248 3252 </ul>
3249 3253 <ul>
3250 3254 <li class="active"><a href="/help">help</a></li>
3251 3255 </ul>
3252 3256 </div>
3253 3257
3254 3258 <div class="main">
3255 3259 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3256 3260 <h3>Help: pager</h3>
3257 3261
3258 3262 <form class="search" action="/log">
3259 3263
3260 3264 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3261 3265 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3262 3266 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3263 3267 </form>
3264 3268 <div id="doc">
3265 3269 <h1>Pager Support</h1>
3266 3270 <p>
3267 3271 Some Mercurial commands can produce a lot of output, and Mercurial will
3268 3272 attempt to use a pager to make those commands more pleasant.
3269 3273 </p>
3270 3274 <p>
3271 3275 To set the pager that should be used, set the application variable:
3272 3276 </p>
3273 3277 <pre>
3274 3278 [pager]
3275 3279 pager = less -FRX
3276 3280 </pre>
3277 3281 <p>
3278 3282 If no pager is set in the user or repository configuration, Mercurial uses the
3279 3283 environment variable $PAGER. If $PAGER is not set, pager.pager from the default
3280 3284 or system configuration is used. If none of these are set, a default pager will
3281 3285 be used, typically 'less' on Unix and 'more' on Windows.
3282 3286 </p>
3283 3287 <p>
3284 3288 You can disable the pager for certain commands by adding them to the
3285 3289 pager.ignore list:
3286 3290 </p>
3287 3291 <pre>
3288 3292 [pager]
3289 3293 ignore = version, help, update
3290 3294 </pre>
3291 3295 <p>
3292 3296 To ignore global commands like 'hg version' or 'hg help', you have
3293 3297 to specify them in your user configuration file.
3294 3298 </p>
3295 3299 <p>
3296 3300 To control whether the pager is used at all for an individual command,
3297 3301 you can use --pager=&lt;value&gt;:
3298 3302 </p>
3299 3303 <ul>
3300 3304 <li> use as needed: 'auto'.
3301 3305 <li> require the pager: 'yes' or 'on'.
3302 3306 <li> suppress the pager: 'no' or 'off' (any unrecognized value will also work).
3303 3307 </ul>
3304 3308 <p>
3305 3309 To globally turn off all attempts to use a pager, set:
3306 3310 </p>
3307 3311 <pre>
3308 3312 [ui]
3309 3313 paginate = never
3310 3314 </pre>
3311 3315 <p>
3312 3316 which will prevent the pager from running.
3313 3317 </p>
3314 3318
3315 3319 </div>
3316 3320 </div>
3317 3321 </div>
3318 3322
3319 3323
3320 3324
3321 3325 </body>
3322 3326 </html>
3323 3327
3324 3328
3325 3329 Sub-topic indexes rendered properly
3326 3330
3327 3331 $ get-with-headers.py $LOCALIP:$HGPORT "help/internals"
3328 3332 200 Script output follows
3329 3333
3330 3334 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3331 3335 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3332 3336 <head>
3333 3337 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3334 3338 <meta name="robots" content="index, nofollow" />
3335 3339 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3336 3340 <script type="text/javascript" src="/static/mercurial.js"></script>
3337 3341
3338 3342 <title>Help: internals</title>
3339 3343 </head>
3340 3344 <body>
3341 3345
3342 3346 <div class="container">
3343 3347 <div class="menu">
3344 3348 <div class="logo">
3345 3349 <a href="https://mercurial-scm.org/">
3346 3350 <img src="/static/hglogo.png" alt="mercurial" /></a>
3347 3351 </div>
3348 3352 <ul>
3349 3353 <li><a href="/shortlog">log</a></li>
3350 3354 <li><a href="/graph">graph</a></li>
3351 3355 <li><a href="/tags">tags</a></li>
3352 3356 <li><a href="/bookmarks">bookmarks</a></li>
3353 3357 <li><a href="/branches">branches</a></li>
3354 3358 </ul>
3355 3359 <ul>
3356 3360 <li><a href="/help">help</a></li>
3357 3361 </ul>
3358 3362 </div>
3359 3363
3360 3364 <div class="main">
3361 3365 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3362 3366
3363 3367 <form class="search" action="/log">
3364 3368
3365 3369 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3366 3370 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3367 3371 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3368 3372 </form>
3369 3373 <table class="bigtable">
3370 3374 <tr><td colspan="2"><h2><a name="topics" href="#topics">Topics</a></h2></td></tr>
3371 3375
3372 3376 <tr><td>
3373 3377 <a href="/help/internals.bundle2">
3374 3378 bundle2
3375 3379 </a>
3376 3380 </td><td>
3377 3381 Bundle2
3378 3382 </td></tr>
3379 3383 <tr><td>
3380 3384 <a href="/help/internals.bundles">
3381 3385 bundles
3382 3386 </a>
3383 3387 </td><td>
3384 3388 Bundles
3385 3389 </td></tr>
3386 3390 <tr><td>
3387 3391 <a href="/help/internals.cbor">
3388 3392 cbor
3389 3393 </a>
3390 3394 </td><td>
3391 3395 CBOR
3392 3396 </td></tr>
3393 3397 <tr><td>
3394 3398 <a href="/help/internals.censor">
3395 3399 censor
3396 3400 </a>
3397 3401 </td><td>
3398 3402 Censor
3399 3403 </td></tr>
3400 3404 <tr><td>
3401 3405 <a href="/help/internals.changegroups">
3402 3406 changegroups
3403 3407 </a>
3404 3408 </td><td>
3405 3409 Changegroups
3406 3410 </td></tr>
3407 3411 <tr><td>
3408 3412 <a href="/help/internals.config">
3409 3413 config
3410 3414 </a>
3411 3415 </td><td>
3412 3416 Config Registrar
3413 3417 </td></tr>
3414 3418 <tr><td>
3415 3419 <a href="/help/internals.extensions">
3416 3420 extensions
3417 3421 </a>
3418 3422 </td><td>
3419 3423 Extension API
3420 3424 </td></tr>
3421 3425 <tr><td>
3422 3426 <a href="/help/internals.requirements">
3423 3427 requirements
3424 3428 </a>
3425 3429 </td><td>
3426 3430 Repository Requirements
3427 3431 </td></tr>
3428 3432 <tr><td>
3429 3433 <a href="/help/internals.revlogs">
3430 3434 revlogs
3431 3435 </a>
3432 3436 </td><td>
3433 3437 Revision Logs
3434 3438 </td></tr>
3435 3439 <tr><td>
3436 3440 <a href="/help/internals.wireprotocol">
3437 3441 wireprotocol
3438 3442 </a>
3439 3443 </td><td>
3440 3444 Wire Protocol
3441 3445 </td></tr>
3442 3446 <tr><td>
3443 3447 <a href="/help/internals.wireprotocolrpc">
3444 3448 wireprotocolrpc
3445 3449 </a>
3446 3450 </td><td>
3447 3451 Wire Protocol RPC
3448 3452 </td></tr>
3449 3453 <tr><td>
3450 3454 <a href="/help/internals.wireprotocolv2">
3451 3455 wireprotocolv2
3452 3456 </a>
3453 3457 </td><td>
3454 3458 Wire Protocol Version 2
3455 3459 </td></tr>
3456 3460
3457 3461
3458 3462
3459 3463
3460 3464
3461 3465 </table>
3462 3466 </div>
3463 3467 </div>
3464 3468
3465 3469
3466 3470
3467 3471 </body>
3468 3472 </html>
3469 3473
3470 3474
3471 3475 Sub-topic topics rendered properly
3472 3476
3473 3477 $ get-with-headers.py $LOCALIP:$HGPORT "help/internals.changegroups"
3474 3478 200 Script output follows
3475 3479
3476 3480 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3477 3481 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3478 3482 <head>
3479 3483 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3480 3484 <meta name="robots" content="index, nofollow" />
3481 3485 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3482 3486 <script type="text/javascript" src="/static/mercurial.js"></script>
3483 3487
3484 3488 <title>Help: internals.changegroups</title>
3485 3489 </head>
3486 3490 <body>
3487 3491
3488 3492 <div class="container">
3489 3493 <div class="menu">
3490 3494 <div class="logo">
3491 3495 <a href="https://mercurial-scm.org/">
3492 3496 <img src="/static/hglogo.png" alt="mercurial" /></a>
3493 3497 </div>
3494 3498 <ul>
3495 3499 <li><a href="/shortlog">log</a></li>
3496 3500 <li><a href="/graph">graph</a></li>
3497 3501 <li><a href="/tags">tags</a></li>
3498 3502 <li><a href="/bookmarks">bookmarks</a></li>
3499 3503 <li><a href="/branches">branches</a></li>
3500 3504 </ul>
3501 3505 <ul>
3502 3506 <li class="active"><a href="/help">help</a></li>
3503 3507 </ul>
3504 3508 </div>
3505 3509
3506 3510 <div class="main">
3507 3511 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3508 3512 <h3>Help: internals.changegroups</h3>
3509 3513
3510 3514 <form class="search" action="/log">
3511 3515
3512 3516 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3513 3517 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3514 3518 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3515 3519 </form>
3516 3520 <div id="doc">
3517 3521 <h1>Changegroups</h1>
3518 3522 <p>
3519 3523 Changegroups are representations of repository revlog data, specifically
3520 3524 the changelog data, root/flat manifest data, treemanifest data, and
3521 3525 filelogs.
3522 3526 </p>
3523 3527 <p>
3524 3528 There are 3 versions of changegroups: &quot;1&quot;, &quot;2&quot;, and &quot;3&quot;. From a
3525 3529 high-level, versions &quot;1&quot; and &quot;2&quot; are almost exactly the same, with the
3526 3530 only difference being an additional item in the *delta header*. Version
3527 3531 &quot;3&quot; adds support for storage flags in the *delta header* and optionally
3528 3532 exchanging treemanifests (enabled by setting an option on the
3529 3533 &quot;changegroup&quot; part in the bundle2).
3530 3534 </p>
3531 3535 <p>
3532 3536 Changegroups when not exchanging treemanifests consist of 3 logical
3533 3537 segments:
3534 3538 </p>
3535 3539 <pre>
3536 3540 +---------------------------------+
3537 3541 | | | |
3538 3542 | changeset | manifest | filelogs |
3539 3543 | | | |
3540 3544 | | | |
3541 3545 +---------------------------------+
3542 3546 </pre>
3543 3547 <p>
3544 3548 When exchanging treemanifests, there are 4 logical segments:
3545 3549 </p>
3546 3550 <pre>
3547 3551 +-------------------------------------------------+
3548 3552 | | | | |
3549 3553 | changeset | root | treemanifests | filelogs |
3550 3554 | | manifest | | |
3551 3555 | | | | |
3552 3556 +-------------------------------------------------+
3553 3557 </pre>
3554 3558 <p>
3555 3559 The principle building block of each segment is a *chunk*. A *chunk*
3556 3560 is a framed piece of data:
3557 3561 </p>
3558 3562 <pre>
3559 3563 +---------------------------------------+
3560 3564 | | |
3561 3565 | length | data |
3562 3566 | (4 bytes) | (&lt;length - 4&gt; bytes) |
3563 3567 | | |
3564 3568 +---------------------------------------+
3565 3569 </pre>
3566 3570 <p>
3567 3571 All integers are big-endian signed integers. Each chunk starts with a 32-bit
3568 3572 integer indicating the length of the entire chunk (including the length field
3569 3573 itself).
3570 3574 </p>
3571 3575 <p>
3572 3576 There is a special case chunk that has a value of 0 for the length
3573 3577 (&quot;0x00000000&quot;). We call this an *empty chunk*.
3574 3578 </p>
3575 3579 <h2>Delta Groups</h2>
3576 3580 <p>
3577 3581 A *delta group* expresses the content of a revlog as a series of deltas,
3578 3582 or patches against previous revisions.
3579 3583 </p>
3580 3584 <p>
3581 3585 Delta groups consist of 0 or more *chunks* followed by the *empty chunk*
3582 3586 to signal the end of the delta group:
3583 3587 </p>
3584 3588 <pre>
3585 3589 +------------------------------------------------------------------------+
3586 3590 | | | | | |
3587 3591 | chunk0 length | chunk0 data | chunk1 length | chunk1 data | 0x0 |
3588 3592 | (4 bytes) | (various) | (4 bytes) | (various) | (4 bytes) |
3589 3593 | | | | | |
3590 3594 +------------------------------------------------------------------------+
3591 3595 </pre>
3592 3596 <p>
3593 3597 Each *chunk*'s data consists of the following:
3594 3598 </p>
3595 3599 <pre>
3596 3600 +---------------------------------------+
3597 3601 | | |
3598 3602 | delta header | delta data |
3599 3603 | (various by version) | (various) |
3600 3604 | | |
3601 3605 +---------------------------------------+
3602 3606 </pre>
3603 3607 <p>
3604 3608 The *delta data* is a series of *delta*s that describe a diff from an existing
3605 3609 entry (either that the recipient already has, or previously specified in the
3606 3610 bundle/changegroup).
3607 3611 </p>
3608 3612 <p>
3609 3613 The *delta header* is different between versions &quot;1&quot;, &quot;2&quot;, and
3610 3614 &quot;3&quot; of the changegroup format.
3611 3615 </p>
3612 3616 <p>
3613 3617 Version 1 (headerlen=80):
3614 3618 </p>
3615 3619 <pre>
3616 3620 +------------------------------------------------------+
3617 3621 | | | | |
3618 3622 | node | p1 node | p2 node | link node |
3619 3623 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
3620 3624 | | | | |
3621 3625 +------------------------------------------------------+
3622 3626 </pre>
3623 3627 <p>
3624 3628 Version 2 (headerlen=100):
3625 3629 </p>
3626 3630 <pre>
3627 3631 +------------------------------------------------------------------+
3628 3632 | | | | | |
3629 3633 | node | p1 node | p2 node | base node | link node |
3630 3634 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
3631 3635 | | | | | |
3632 3636 +------------------------------------------------------------------+
3633 3637 </pre>
3634 3638 <p>
3635 3639 Version 3 (headerlen=102):
3636 3640 </p>
3637 3641 <pre>
3638 3642 +------------------------------------------------------------------------------+
3639 3643 | | | | | | |
3640 3644 | node | p1 node | p2 node | base node | link node | flags |
3641 3645 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (2 bytes) |
3642 3646 | | | | | | |
3643 3647 +------------------------------------------------------------------------------+
3644 3648 </pre>
3645 3649 <p>
3646 3650 The *delta data* consists of &quot;chunklen - 4 - headerlen&quot; bytes, which contain a
3647 3651 series of *delta*s, densely packed (no separators). These deltas describe a diff
3648 3652 from an existing entry (either that the recipient already has, or previously
3649 3653 specified in the bundle/changegroup). The format is described more fully in
3650 3654 &quot;hg help internals.bdiff&quot;, but briefly:
3651 3655 </p>
3652 3656 <pre>
3653 3657 +---------------------------------------------------------------+
3654 3658 | | | | |
3655 3659 | start offset | end offset | new length | content |
3656 3660 | (4 bytes) | (4 bytes) | (4 bytes) | (&lt;new length&gt; bytes) |
3657 3661 | | | | |
3658 3662 +---------------------------------------------------------------+
3659 3663 </pre>
3660 3664 <p>
3661 3665 Please note that the length field in the delta data does *not* include itself.
3662 3666 </p>
3663 3667 <p>
3664 3668 In version 1, the delta is always applied against the previous node from
3665 3669 the changegroup or the first parent if this is the first entry in the
3666 3670 changegroup.
3667 3671 </p>
3668 3672 <p>
3669 3673 In version 2 and up, the delta base node is encoded in the entry in the
3670 3674 changegroup. This allows the delta to be expressed against any parent,
3671 3675 which can result in smaller deltas and more efficient encoding of data.
3672 3676 </p>
3673 3677 <p>
3674 3678 The *flags* field holds bitwise flags affecting the processing of revision
3675 3679 data. The following flags are defined:
3676 3680 </p>
3677 3681 <dl>
3678 3682 <dt>32768
3679 3683 <dd>Censored revision. The revision's fulltext has been replaced by censor metadata. May only occur on file revisions.
3680 3684 <dt>16384
3681 3685 <dd>Ellipsis revision. Revision hash does not match data (likely due to rewritten parents).
3682 3686 <dt>8192
3683 3687 <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.
3684 3688 </dl>
3685 3689 <p>
3686 3690 For historical reasons, the integer values are identical to revlog version 1
3687 3691 per-revision storage flags and correspond to bits being set in this 2-byte
3688 3692 field. Bits were allocated starting from the most-significant bit, hence the
3689 3693 reverse ordering and allocation of these flags.
3690 3694 </p>
3691 3695 <h2>Changeset Segment</h2>
3692 3696 <p>
3693 3697 The *changeset segment* consists of a single *delta group* holding
3694 3698 changelog data. The *empty chunk* at the end of the *delta group* denotes
3695 3699 the boundary to the *manifest segment*.
3696 3700 </p>
3697 3701 <h2>Manifest Segment</h2>
3698 3702 <p>
3699 3703 The *manifest segment* consists of a single *delta group* holding manifest
3700 3704 data. If treemanifests are in use, it contains only the manifest for the
3701 3705 root directory of the repository. Otherwise, it contains the entire
3702 3706 manifest data. The *empty chunk* at the end of the *delta group* denotes
3703 3707 the boundary to the next segment (either the *treemanifests segment* or the
3704 3708 *filelogs segment*, depending on version and the request options).
3705 3709 </p>
3706 3710 <h3>Treemanifests Segment</h3>
3707 3711 <p>
3708 3712 The *treemanifests segment* only exists in changegroup version &quot;3&quot;, and
3709 3713 only if the 'treemanifest' param is part of the bundle2 changegroup part
3710 3714 (it is not possible to use changegroup version 3 outside of bundle2).
3711 3715 Aside from the filenames in the *treemanifests segment* containing a
3712 3716 trailing &quot;/&quot; character, it behaves identically to the *filelogs segment*
3713 3717 (see below). The final sub-segment is followed by an *empty chunk* (logically,
3714 3718 a sub-segment with filename size 0). This denotes the boundary to the
3715 3719 *filelogs segment*.
3716 3720 </p>
3717 3721 <h2>Filelogs Segment</h2>
3718 3722 <p>
3719 3723 The *filelogs segment* consists of multiple sub-segments, each
3720 3724 corresponding to an individual file whose data is being described:
3721 3725 </p>
3722 3726 <pre>
3723 3727 +--------------------------------------------------+
3724 3728 | | | | | |
3725 3729 | filelog0 | filelog1 | filelog2 | ... | 0x0 |
3726 3730 | | | | | (4 bytes) |
3727 3731 | | | | | |
3728 3732 +--------------------------------------------------+
3729 3733 </pre>
3730 3734 <p>
3731 3735 The final filelog sub-segment is followed by an *empty chunk* (logically,
3732 3736 a sub-segment with filename size 0). This denotes the end of the segment
3733 3737 and of the overall changegroup.
3734 3738 </p>
3735 3739 <p>
3736 3740 Each filelog sub-segment consists of the following:
3737 3741 </p>
3738 3742 <pre>
3739 3743 +------------------------------------------------------+
3740 3744 | | | |
3741 3745 | filename length | filename | delta group |
3742 3746 | (4 bytes) | (&lt;length - 4&gt; bytes) | (various) |
3743 3747 | | | |
3744 3748 +------------------------------------------------------+
3745 3749 </pre>
3746 3750 <p>
3747 3751 That is, a *chunk* consisting of the filename (not terminated or padded)
3748 3752 followed by N chunks constituting the *delta group* for this file. The
3749 3753 *empty chunk* at the end of each *delta group* denotes the boundary to the
3750 3754 next filelog sub-segment.
3751 3755 </p>
3752 3756
3753 3757 </div>
3754 3758 </div>
3755 3759 </div>
3756 3760
3757 3761
3758 3762
3759 3763 </body>
3760 3764 </html>
3761 3765
3762 3766
3763 3767 $ get-with-headers.py 127.0.0.1:$HGPORT "help/unknowntopic"
3764 3768 404 Not Found
3765 3769
3766 3770 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3767 3771 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3768 3772 <head>
3769 3773 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3770 3774 <meta name="robots" content="index, nofollow" />
3771 3775 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3772 3776 <script type="text/javascript" src="/static/mercurial.js"></script>
3773 3777
3774 3778 <title>test: error</title>
3775 3779 </head>
3776 3780 <body>
3777 3781
3778 3782 <div class="container">
3779 3783 <div class="menu">
3780 3784 <div class="logo">
3781 3785 <a href="https://mercurial-scm.org/">
3782 3786 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
3783 3787 </div>
3784 3788 <ul>
3785 3789 <li><a href="/shortlog">log</a></li>
3786 3790 <li><a href="/graph">graph</a></li>
3787 3791 <li><a href="/tags">tags</a></li>
3788 3792 <li><a href="/bookmarks">bookmarks</a></li>
3789 3793 <li><a href="/branches">branches</a></li>
3790 3794 </ul>
3791 3795 <ul>
3792 3796 <li><a href="/help">help</a></li>
3793 3797 </ul>
3794 3798 </div>
3795 3799
3796 3800 <div class="main">
3797 3801
3798 3802 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3799 3803 <h3>error</h3>
3800 3804
3801 3805
3802 3806 <form class="search" action="/log">
3803 3807
3804 3808 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3805 3809 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3806 3810 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3807 3811 </form>
3808 3812
3809 3813 <div class="description">
3810 3814 <p>
3811 3815 An error occurred while processing your request:
3812 3816 </p>
3813 3817 <p>
3814 3818 Not Found
3815 3819 </p>
3816 3820 </div>
3817 3821 </div>
3818 3822 </div>
3819 3823
3820 3824
3821 3825
3822 3826 </body>
3823 3827 </html>
3824 3828
3825 3829 [1]
3826 3830
3827 3831 $ killdaemons.py
3828 3832
3829 3833 #endif
General Comments 0
You need to be logged in to leave comments. Login now