##// END OF EJS Templates
stringutil: promote smartset.prettyformat() to utility function...
Yuya Nishihara -
r38280:f3033692 default
parent child Browse files
Show More
@@ -1,3138 +1,3137 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 .thirdparty import (
36 36 cbor,
37 37 )
38 38 from . import (
39 39 bundle2,
40 40 changegroup,
41 41 cmdutil,
42 42 color,
43 43 context,
44 44 dagparser,
45 45 dagutil,
46 46 encoding,
47 47 error,
48 48 exchange,
49 49 extensions,
50 50 filemerge,
51 51 fileset,
52 52 formatter,
53 53 hg,
54 54 httppeer,
55 55 localrepo,
56 56 lock as lockmod,
57 57 logcmdutil,
58 58 merge as mergemod,
59 59 obsolete,
60 60 obsutil,
61 61 phases,
62 62 policy,
63 63 pvec,
64 64 pycompat,
65 65 registrar,
66 66 repair,
67 67 revlog,
68 68 revset,
69 69 revsetlang,
70 70 scmutil,
71 71 setdiscovery,
72 72 simplemerge,
73 smartset,
74 73 sshpeer,
75 74 sslutil,
76 75 streamclone,
77 76 templater,
78 77 treediscovery,
79 78 upgrade,
80 79 url as urlmod,
81 80 util,
82 81 vfs as vfsmod,
83 82 wireprotoframing,
84 83 wireprotoserver,
85 84 wireprotov2peer,
86 85 )
87 86 from .utils import (
88 87 dateutil,
89 88 procutil,
90 89 stringutil,
91 90 )
92 91
93 92 release = lockmod.release
94 93
95 94 command = registrar.command()
96 95
97 96 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
98 97 def debugancestor(ui, repo, *args):
99 98 """find the ancestor revision of two revisions in a given index"""
100 99 if len(args) == 3:
101 100 index, rev1, rev2 = args
102 101 r = revlog.revlog(vfsmod.vfs(pycompat.getcwd(), audit=False), index)
103 102 lookup = r.lookup
104 103 elif len(args) == 2:
105 104 if not repo:
106 105 raise error.Abort(_('there is no Mercurial repository here '
107 106 '(.hg not found)'))
108 107 rev1, rev2 = args
109 108 r = repo.changelog
110 109 lookup = repo.lookup
111 110 else:
112 111 raise error.Abort(_('either two or three arguments required'))
113 112 a = r.ancestor(lookup(rev1), lookup(rev2))
114 113 ui.write('%d:%s\n' % (r.rev(a), hex(a)))
115 114
116 115 @command('debugapplystreamclonebundle', [], 'FILE')
117 116 def debugapplystreamclonebundle(ui, repo, fname):
118 117 """apply a stream clone bundle file"""
119 118 f = hg.openpath(ui, fname)
120 119 gen = exchange.readbundle(ui, f, fname)
121 120 gen.apply(repo)
122 121
123 122 @command('debugbuilddag',
124 123 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
125 124 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
126 125 ('n', 'new-file', None, _('add new file at each rev'))],
127 126 _('[OPTION]... [TEXT]'))
128 127 def debugbuilddag(ui, repo, text=None,
129 128 mergeable_file=False,
130 129 overwritten_file=False,
131 130 new_file=False):
132 131 """builds a repo with a given DAG from scratch in the current empty repo
133 132
134 133 The description of the DAG is read from stdin if not given on the
135 134 command line.
136 135
137 136 Elements:
138 137
139 138 - "+n" is a linear run of n nodes based on the current default parent
140 139 - "." is a single node based on the current default parent
141 140 - "$" resets the default parent to null (implied at the start);
142 141 otherwise the default parent is always the last node created
143 142 - "<p" sets the default parent to the backref p
144 143 - "*p" is a fork at parent p, which is a backref
145 144 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
146 145 - "/p2" is a merge of the preceding node and p2
147 146 - ":tag" defines a local tag for the preceding node
148 147 - "@branch" sets the named branch for subsequent nodes
149 148 - "#...\\n" is a comment up to the end of the line
150 149
151 150 Whitespace between the above elements is ignored.
152 151
153 152 A backref is either
154 153
155 154 - a number n, which references the node curr-n, where curr is the current
156 155 node, or
157 156 - the name of a local tag you placed earlier using ":tag", or
158 157 - empty to denote the default parent.
159 158
160 159 All string valued-elements are either strictly alphanumeric, or must
161 160 be enclosed in double quotes ("..."), with "\\" as escape character.
162 161 """
163 162
164 163 if text is None:
165 164 ui.status(_("reading DAG from stdin\n"))
166 165 text = ui.fin.read()
167 166
168 167 cl = repo.changelog
169 168 if len(cl) > 0:
170 169 raise error.Abort(_('repository is not empty'))
171 170
172 171 # determine number of revs in DAG
173 172 total = 0
174 173 for type, data in dagparser.parsedag(text):
175 174 if type == 'n':
176 175 total += 1
177 176
178 177 if mergeable_file:
179 178 linesperrev = 2
180 179 # make a file with k lines per rev
181 180 initialmergedlines = ['%d' % i for i in xrange(0, total * linesperrev)]
182 181 initialmergedlines.append("")
183 182
184 183 tags = []
185 184
186 185 wlock = lock = tr = None
187 186 try:
188 187 wlock = repo.wlock()
189 188 lock = repo.lock()
190 189 tr = repo.transaction("builddag")
191 190
192 191 at = -1
193 192 atbranch = 'default'
194 193 nodeids = []
195 194 id = 0
196 195 ui.progress(_('building'), id, unit=_('revisions'), total=total)
197 196 for type, data in dagparser.parsedag(text):
198 197 if type == 'n':
199 198 ui.note(('node %s\n' % pycompat.bytestr(data)))
200 199 id, ps = data
201 200
202 201 files = []
203 202 filecontent = {}
204 203
205 204 p2 = None
206 205 if mergeable_file:
207 206 fn = "mf"
208 207 p1 = repo[ps[0]]
209 208 if len(ps) > 1:
210 209 p2 = repo[ps[1]]
211 210 pa = p1.ancestor(p2)
212 211 base, local, other = [x[fn].data() for x in (pa, p1,
213 212 p2)]
214 213 m3 = simplemerge.Merge3Text(base, local, other)
215 214 ml = [l.strip() for l in m3.merge_lines()]
216 215 ml.append("")
217 216 elif at > 0:
218 217 ml = p1[fn].data().split("\n")
219 218 else:
220 219 ml = initialmergedlines
221 220 ml[id * linesperrev] += " r%i" % id
222 221 mergedtext = "\n".join(ml)
223 222 files.append(fn)
224 223 filecontent[fn] = mergedtext
225 224
226 225 if overwritten_file:
227 226 fn = "of"
228 227 files.append(fn)
229 228 filecontent[fn] = "r%i\n" % id
230 229
231 230 if new_file:
232 231 fn = "nf%i" % id
233 232 files.append(fn)
234 233 filecontent[fn] = "r%i\n" % id
235 234 if len(ps) > 1:
236 235 if not p2:
237 236 p2 = repo[ps[1]]
238 237 for fn in p2:
239 238 if fn.startswith("nf"):
240 239 files.append(fn)
241 240 filecontent[fn] = p2[fn].data()
242 241
243 242 def fctxfn(repo, cx, path):
244 243 if path in filecontent:
245 244 return context.memfilectx(repo, cx, path,
246 245 filecontent[path])
247 246 return None
248 247
249 248 if len(ps) == 0 or ps[0] < 0:
250 249 pars = [None, None]
251 250 elif len(ps) == 1:
252 251 pars = [nodeids[ps[0]], None]
253 252 else:
254 253 pars = [nodeids[p] for p in ps]
255 254 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
256 255 date=(id, 0),
257 256 user="debugbuilddag",
258 257 extra={'branch': atbranch})
259 258 nodeid = repo.commitctx(cx)
260 259 nodeids.append(nodeid)
261 260 at = id
262 261 elif type == 'l':
263 262 id, name = data
264 263 ui.note(('tag %s\n' % name))
265 264 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
266 265 elif type == 'a':
267 266 ui.note(('branch %s\n' % data))
268 267 atbranch = data
269 268 ui.progress(_('building'), id, unit=_('revisions'), total=total)
270 269 tr.close()
271 270
272 271 if tags:
273 272 repo.vfs.write("localtags", "".join(tags))
274 273 finally:
275 274 ui.progress(_('building'), None)
276 275 release(tr, lock, wlock)
277 276
278 277 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
279 278 indent_string = ' ' * indent
280 279 if all:
281 280 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
282 281 % indent_string)
283 282
284 283 def showchunks(named):
285 284 ui.write("\n%s%s\n" % (indent_string, named))
286 285 for deltadata in gen.deltaiter():
287 286 node, p1, p2, cs, deltabase, delta, flags = deltadata
288 287 ui.write("%s%s %s %s %s %s %d\n" %
289 288 (indent_string, hex(node), hex(p1), hex(p2),
290 289 hex(cs), hex(deltabase), len(delta)))
291 290
292 291 chunkdata = gen.changelogheader()
293 292 showchunks("changelog")
294 293 chunkdata = gen.manifestheader()
295 294 showchunks("manifest")
296 295 for chunkdata in iter(gen.filelogheader, {}):
297 296 fname = chunkdata['filename']
298 297 showchunks(fname)
299 298 else:
300 299 if isinstance(gen, bundle2.unbundle20):
301 300 raise error.Abort(_('use debugbundle2 for this file'))
302 301 chunkdata = gen.changelogheader()
303 302 for deltadata in gen.deltaiter():
304 303 node, p1, p2, cs, deltabase, delta, flags = deltadata
305 304 ui.write("%s%s\n" % (indent_string, hex(node)))
306 305
307 306 def _debugobsmarkers(ui, part, indent=0, **opts):
308 307 """display version and markers contained in 'data'"""
309 308 opts = pycompat.byteskwargs(opts)
310 309 data = part.read()
311 310 indent_string = ' ' * indent
312 311 try:
313 312 version, markers = obsolete._readmarkers(data)
314 313 except error.UnknownVersion as exc:
315 314 msg = "%sunsupported version: %s (%d bytes)\n"
316 315 msg %= indent_string, exc.version, len(data)
317 316 ui.write(msg)
318 317 else:
319 318 msg = "%sversion: %d (%d bytes)\n"
320 319 msg %= indent_string, version, len(data)
321 320 ui.write(msg)
322 321 fm = ui.formatter('debugobsolete', opts)
323 322 for rawmarker in sorted(markers):
324 323 m = obsutil.marker(None, rawmarker)
325 324 fm.startitem()
326 325 fm.plain(indent_string)
327 326 cmdutil.showmarker(fm, m)
328 327 fm.end()
329 328
330 329 def _debugphaseheads(ui, data, indent=0):
331 330 """display version and markers contained in 'data'"""
332 331 indent_string = ' ' * indent
333 332 headsbyphase = phases.binarydecode(data)
334 333 for phase in phases.allphases:
335 334 for head in headsbyphase[phase]:
336 335 ui.write(indent_string)
337 336 ui.write('%s %s\n' % (hex(head), phases.phasenames[phase]))
338 337
339 338 def _quasirepr(thing):
340 339 if isinstance(thing, (dict, util.sortdict, collections.OrderedDict)):
341 340 return '{%s}' % (
342 341 b', '.join(b'%s: %s' % (k, thing[k]) for k in sorted(thing)))
343 342 return pycompat.bytestr(repr(thing))
344 343
345 344 def _debugbundle2(ui, gen, all=None, **opts):
346 345 """lists the contents of a bundle2"""
347 346 if not isinstance(gen, bundle2.unbundle20):
348 347 raise error.Abort(_('not a bundle2 file'))
349 348 ui.write(('Stream params: %s\n' % _quasirepr(gen.params)))
350 349 parttypes = opts.get(r'part_type', [])
351 350 for part in gen.iterparts():
352 351 if parttypes and part.type not in parttypes:
353 352 continue
354 353 msg = '%s -- %s (mandatory: %r)\n'
355 354 ui.write((msg % (part.type, _quasirepr(part.params), part.mandatory)))
356 355 if part.type == 'changegroup':
357 356 version = part.params.get('version', '01')
358 357 cg = changegroup.getunbundler(version, part, 'UN')
359 358 if not ui.quiet:
360 359 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
361 360 if part.type == 'obsmarkers':
362 361 if not ui.quiet:
363 362 _debugobsmarkers(ui, part, indent=4, **opts)
364 363 if part.type == 'phase-heads':
365 364 if not ui.quiet:
366 365 _debugphaseheads(ui, part, indent=4)
367 366
368 367 @command('debugbundle',
369 368 [('a', 'all', None, _('show all details')),
370 369 ('', 'part-type', [], _('show only the named part type')),
371 370 ('', 'spec', None, _('print the bundlespec of the bundle'))],
372 371 _('FILE'),
373 372 norepo=True)
374 373 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
375 374 """lists the contents of a bundle"""
376 375 with hg.openpath(ui, bundlepath) as f:
377 376 if spec:
378 377 spec = exchange.getbundlespec(ui, f)
379 378 ui.write('%s\n' % spec)
380 379 return
381 380
382 381 gen = exchange.readbundle(ui, f, bundlepath)
383 382 if isinstance(gen, bundle2.unbundle20):
384 383 return _debugbundle2(ui, gen, all=all, **opts)
385 384 _debugchangegroup(ui, gen, all=all, **opts)
386 385
387 386 @command('debugcapabilities',
388 387 [], _('PATH'),
389 388 norepo=True)
390 389 def debugcapabilities(ui, path, **opts):
391 390 """lists the capabilities of a remote peer"""
392 391 opts = pycompat.byteskwargs(opts)
393 392 peer = hg.peer(ui, opts, path)
394 393 caps = peer.capabilities()
395 394 ui.write(('Main capabilities:\n'))
396 395 for c in sorted(caps):
397 396 ui.write((' %s\n') % c)
398 397 b2caps = bundle2.bundle2caps(peer)
399 398 if b2caps:
400 399 ui.write(('Bundle2 capabilities:\n'))
401 400 for key, values in sorted(b2caps.iteritems()):
402 401 ui.write((' %s\n') % key)
403 402 for v in values:
404 403 ui.write((' %s\n') % v)
405 404
406 405 @command('debugcheckstate', [], '')
407 406 def debugcheckstate(ui, repo):
408 407 """validate the correctness of the current dirstate"""
409 408 parent1, parent2 = repo.dirstate.parents()
410 409 m1 = repo[parent1].manifest()
411 410 m2 = repo[parent2].manifest()
412 411 errors = 0
413 412 for f in repo.dirstate:
414 413 state = repo.dirstate[f]
415 414 if state in "nr" and f not in m1:
416 415 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
417 416 errors += 1
418 417 if state in "a" and f in m1:
419 418 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
420 419 errors += 1
421 420 if state in "m" and f not in m1 and f not in m2:
422 421 ui.warn(_("%s in state %s, but not in either manifest\n") %
423 422 (f, state))
424 423 errors += 1
425 424 for f in m1:
426 425 state = repo.dirstate[f]
427 426 if state not in "nrm":
428 427 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
429 428 errors += 1
430 429 if errors:
431 430 error = _(".hg/dirstate inconsistent with current parent's manifest")
432 431 raise error.Abort(error)
433 432
434 433 @command('debugcolor',
435 434 [('', 'style', None, _('show all configured styles'))],
436 435 'hg debugcolor')
437 436 def debugcolor(ui, repo, **opts):
438 437 """show available color, effects or style"""
439 438 ui.write(('color mode: %s\n') % ui._colormode)
440 439 if opts.get(r'style'):
441 440 return _debugdisplaystyle(ui)
442 441 else:
443 442 return _debugdisplaycolor(ui)
444 443
445 444 def _debugdisplaycolor(ui):
446 445 ui = ui.copy()
447 446 ui._styles.clear()
448 447 for effect in color._activeeffects(ui).keys():
449 448 ui._styles[effect] = effect
450 449 if ui._terminfoparams:
451 450 for k, v in ui.configitems('color'):
452 451 if k.startswith('color.'):
453 452 ui._styles[k] = k[6:]
454 453 elif k.startswith('terminfo.'):
455 454 ui._styles[k] = k[9:]
456 455 ui.write(_('available colors:\n'))
457 456 # sort label with a '_' after the other to group '_background' entry.
458 457 items = sorted(ui._styles.items(),
459 458 key=lambda i: ('_' in i[0], i[0], i[1]))
460 459 for colorname, label in items:
461 460 ui.write(('%s\n') % colorname, label=label)
462 461
463 462 def _debugdisplaystyle(ui):
464 463 ui.write(_('available style:\n'))
465 464 if not ui._styles:
466 465 return
467 466 width = max(len(s) for s in ui._styles)
468 467 for label, effects in sorted(ui._styles.items()):
469 468 ui.write('%s' % label, label=label)
470 469 if effects:
471 470 # 50
472 471 ui.write(': ')
473 472 ui.write(' ' * (max(0, width - len(label))))
474 473 ui.write(', '.join(ui.label(e, e) for e in effects.split()))
475 474 ui.write('\n')
476 475
477 476 @command('debugcreatestreamclonebundle', [], 'FILE')
478 477 def debugcreatestreamclonebundle(ui, repo, fname):
479 478 """create a stream clone bundle file
480 479
481 480 Stream bundles are special bundles that are essentially archives of
482 481 revlog files. They are commonly used for cloning very quickly.
483 482 """
484 483 # TODO we may want to turn this into an abort when this functionality
485 484 # is moved into `hg bundle`.
486 485 if phases.hassecret(repo):
487 486 ui.warn(_('(warning: stream clone bundle will contain secret '
488 487 'revisions)\n'))
489 488
490 489 requirements, gen = streamclone.generatebundlev1(repo)
491 490 changegroup.writechunks(ui, gen, fname)
492 491
493 492 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
494 493
495 494 @command('debugdag',
496 495 [('t', 'tags', None, _('use tags as labels')),
497 496 ('b', 'branches', None, _('annotate with branch names')),
498 497 ('', 'dots', None, _('use dots for runs')),
499 498 ('s', 'spaces', None, _('separate elements by spaces'))],
500 499 _('[OPTION]... [FILE [REV]...]'),
501 500 optionalrepo=True)
502 501 def debugdag(ui, repo, file_=None, *revs, **opts):
503 502 """format the changelog or an index DAG as a concise textual description
504 503
505 504 If you pass a revlog index, the revlog's DAG is emitted. If you list
506 505 revision numbers, they get labeled in the output as rN.
507 506
508 507 Otherwise, the changelog DAG of the current repo is emitted.
509 508 """
510 509 spaces = opts.get(r'spaces')
511 510 dots = opts.get(r'dots')
512 511 if file_:
513 512 rlog = revlog.revlog(vfsmod.vfs(pycompat.getcwd(), audit=False),
514 513 file_)
515 514 revs = set((int(r) for r in revs))
516 515 def events():
517 516 for r in rlog:
518 517 yield 'n', (r, list(p for p in rlog.parentrevs(r)
519 518 if p != -1))
520 519 if r in revs:
521 520 yield 'l', (r, "r%i" % r)
522 521 elif repo:
523 522 cl = repo.changelog
524 523 tags = opts.get(r'tags')
525 524 branches = opts.get(r'branches')
526 525 if tags:
527 526 labels = {}
528 527 for l, n in repo.tags().items():
529 528 labels.setdefault(cl.rev(n), []).append(l)
530 529 def events():
531 530 b = "default"
532 531 for r in cl:
533 532 if branches:
534 533 newb = cl.read(cl.node(r))[5]['branch']
535 534 if newb != b:
536 535 yield 'a', newb
537 536 b = newb
538 537 yield 'n', (r, list(p for p in cl.parentrevs(r)
539 538 if p != -1))
540 539 if tags:
541 540 ls = labels.get(r)
542 541 if ls:
543 542 for l in ls:
544 543 yield 'l', (r, l)
545 544 else:
546 545 raise error.Abort(_('need repo for changelog dag'))
547 546
548 547 for line in dagparser.dagtextlines(events(),
549 548 addspaces=spaces,
550 549 wraplabels=True,
551 550 wrapannotations=True,
552 551 wrapnonlinear=dots,
553 552 usedots=dots,
554 553 maxlinewidth=70):
555 554 ui.write(line)
556 555 ui.write("\n")
557 556
558 557 @command('debugdata', cmdutil.debugrevlogopts, _('-c|-m|FILE REV'))
559 558 def debugdata(ui, repo, file_, rev=None, **opts):
560 559 """dump the contents of a data file revision"""
561 560 opts = pycompat.byteskwargs(opts)
562 561 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
563 562 if rev is not None:
564 563 raise error.CommandError('debugdata', _('invalid arguments'))
565 564 file_, rev = None, file_
566 565 elif rev is None:
567 566 raise error.CommandError('debugdata', _('invalid arguments'))
568 567 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
569 568 try:
570 569 ui.write(r.revision(r.lookup(rev), raw=True))
571 570 except KeyError:
572 571 raise error.Abort(_('invalid revision identifier %s') % rev)
573 572
574 573 @command('debugdate',
575 574 [('e', 'extended', None, _('try extended date formats'))],
576 575 _('[-e] DATE [RANGE]'),
577 576 norepo=True, optionalrepo=True)
578 577 def debugdate(ui, date, range=None, **opts):
579 578 """parse and display a date"""
580 579 if opts[r"extended"]:
581 580 d = dateutil.parsedate(date, util.extendeddateformats)
582 581 else:
583 582 d = dateutil.parsedate(date)
584 583 ui.write(("internal: %d %d\n") % d)
585 584 ui.write(("standard: %s\n") % dateutil.datestr(d))
586 585 if range:
587 586 m = dateutil.matchdate(range)
588 587 ui.write(("match: %s\n") % m(d[0]))
589 588
590 589 @command('debugdeltachain',
591 590 cmdutil.debugrevlogopts + cmdutil.formatteropts,
592 591 _('-c|-m|FILE'),
593 592 optionalrepo=True)
594 593 def debugdeltachain(ui, repo, file_=None, **opts):
595 594 """dump information about delta chains in a revlog
596 595
597 596 Output can be templatized. Available template keywords are:
598 597
599 598 :``rev``: revision number
600 599 :``chainid``: delta chain identifier (numbered by unique base)
601 600 :``chainlen``: delta chain length to this revision
602 601 :``prevrev``: previous revision in delta chain
603 602 :``deltatype``: role of delta / how it was computed
604 603 :``compsize``: compressed size of revision
605 604 :``uncompsize``: uncompressed size of revision
606 605 :``chainsize``: total size of compressed revisions in chain
607 606 :``chainratio``: total chain size divided by uncompressed revision size
608 607 (new delta chains typically start at ratio 2.00)
609 608 :``lindist``: linear distance from base revision in delta chain to end
610 609 of this revision
611 610 :``extradist``: total size of revisions not part of this delta chain from
612 611 base of delta chain to end of this revision; a measurement
613 612 of how much extra data we need to read/seek across to read
614 613 the delta chain for this revision
615 614 :``extraratio``: extradist divided by chainsize; another representation of
616 615 how much unrelated data is needed to load this delta chain
617 616
618 617 If the repository is configured to use the sparse read, additional keywords
619 618 are available:
620 619
621 620 :``readsize``: total size of data read from the disk for a revision
622 621 (sum of the sizes of all the blocks)
623 622 :``largestblock``: size of the largest block of data read from the disk
624 623 :``readdensity``: density of useful bytes in the data read from the disk
625 624 :``srchunks``: in how many data hunks the whole revision would be read
626 625
627 626 The sparse read can be enabled with experimental.sparse-read = True
628 627 """
629 628 opts = pycompat.byteskwargs(opts)
630 629 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
631 630 index = r.index
632 631 start = r.start
633 632 length = r.length
634 633 generaldelta = r.version & revlog.FLAG_GENERALDELTA
635 634 withsparseread = getattr(r, '_withsparseread', False)
636 635
637 636 def revinfo(rev):
638 637 e = index[rev]
639 638 compsize = e[1]
640 639 uncompsize = e[2]
641 640 chainsize = 0
642 641
643 642 if generaldelta:
644 643 if e[3] == e[5]:
645 644 deltatype = 'p1'
646 645 elif e[3] == e[6]:
647 646 deltatype = 'p2'
648 647 elif e[3] == rev - 1:
649 648 deltatype = 'prev'
650 649 elif e[3] == rev:
651 650 deltatype = 'base'
652 651 else:
653 652 deltatype = 'other'
654 653 else:
655 654 if e[3] == rev:
656 655 deltatype = 'base'
657 656 else:
658 657 deltatype = 'prev'
659 658
660 659 chain = r._deltachain(rev)[0]
661 660 for iterrev in chain:
662 661 e = index[iterrev]
663 662 chainsize += e[1]
664 663
665 664 return compsize, uncompsize, deltatype, chain, chainsize
666 665
667 666 fm = ui.formatter('debugdeltachain', opts)
668 667
669 668 fm.plain(' rev chain# chainlen prev delta '
670 669 'size rawsize chainsize ratio lindist extradist '
671 670 'extraratio')
672 671 if withsparseread:
673 672 fm.plain(' readsize largestblk rddensity srchunks')
674 673 fm.plain('\n')
675 674
676 675 chainbases = {}
677 676 for rev in r:
678 677 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
679 678 chainbase = chain[0]
680 679 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
681 680 basestart = start(chainbase)
682 681 revstart = start(rev)
683 682 lineardist = revstart + comp - basestart
684 683 extradist = lineardist - chainsize
685 684 try:
686 685 prevrev = chain[-2]
687 686 except IndexError:
688 687 prevrev = -1
689 688
690 689 chainratio = float(chainsize) / float(uncomp)
691 690 extraratio = float(extradist) / float(chainsize)
692 691
693 692 fm.startitem()
694 693 fm.write('rev chainid chainlen prevrev deltatype compsize '
695 694 'uncompsize chainsize chainratio lindist extradist '
696 695 'extraratio',
697 696 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f',
698 697 rev, chainid, len(chain), prevrev, deltatype, comp,
699 698 uncomp, chainsize, chainratio, lineardist, extradist,
700 699 extraratio,
701 700 rev=rev, chainid=chainid, chainlen=len(chain),
702 701 prevrev=prevrev, deltatype=deltatype, compsize=comp,
703 702 uncompsize=uncomp, chainsize=chainsize,
704 703 chainratio=chainratio, lindist=lineardist,
705 704 extradist=extradist, extraratio=extraratio)
706 705 if withsparseread:
707 706 readsize = 0
708 707 largestblock = 0
709 708 srchunks = 0
710 709
711 710 for revschunk in revlog._slicechunk(r, chain):
712 711 srchunks += 1
713 712 blkend = start(revschunk[-1]) + length(revschunk[-1])
714 713 blksize = blkend - start(revschunk[0])
715 714
716 715 readsize += blksize
717 716 if largestblock < blksize:
718 717 largestblock = blksize
719 718
720 719 readdensity = float(chainsize) / float(readsize)
721 720
722 721 fm.write('readsize largestblock readdensity srchunks',
723 722 ' %10d %10d %9.5f %8d',
724 723 readsize, largestblock, readdensity, srchunks,
725 724 readsize=readsize, largestblock=largestblock,
726 725 readdensity=readdensity, srchunks=srchunks)
727 726
728 727 fm.plain('\n')
729 728
730 729 fm.end()
731 730
732 731 @command('debugdirstate|debugstate',
733 732 [('', 'nodates', None, _('do not display the saved mtime')),
734 733 ('', 'datesort', None, _('sort by saved mtime'))],
735 734 _('[OPTION]...'))
736 735 def debugstate(ui, repo, **opts):
737 736 """show the contents of the current dirstate"""
738 737
739 738 nodates = opts.get(r'nodates')
740 739 datesort = opts.get(r'datesort')
741 740
742 741 timestr = ""
743 742 if datesort:
744 743 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
745 744 else:
746 745 keyfunc = None # sort by filename
747 746 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
748 747 if ent[3] == -1:
749 748 timestr = 'unset '
750 749 elif nodates:
751 750 timestr = 'set '
752 751 else:
753 752 timestr = time.strftime(r"%Y-%m-%d %H:%M:%S ",
754 753 time.localtime(ent[3]))
755 754 timestr = encoding.strtolocal(timestr)
756 755 if ent[1] & 0o20000:
757 756 mode = 'lnk'
758 757 else:
759 758 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
760 759 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
761 760 for f in repo.dirstate.copies():
762 761 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
763 762
764 763 @command('debugdiscovery',
765 764 [('', 'old', None, _('use old-style discovery')),
766 765 ('', 'nonheads', None,
767 766 _('use old-style discovery with non-heads included')),
768 767 ('', 'rev', [], 'restrict discovery to this set of revs'),
769 768 ] + cmdutil.remoteopts,
770 769 _('[--rev REV] [OTHER]'))
771 770 def debugdiscovery(ui, repo, remoteurl="default", **opts):
772 771 """runs the changeset discovery protocol in isolation"""
773 772 opts = pycompat.byteskwargs(opts)
774 773 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl))
775 774 remote = hg.peer(repo, opts, remoteurl)
776 775 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
777 776
778 777 # make sure tests are repeatable
779 778 random.seed(12323)
780 779
781 780 def doit(pushedrevs, remoteheads, remote=remote):
782 781 if opts.get('old'):
783 782 if not util.safehasattr(remote, 'branches'):
784 783 # enable in-client legacy support
785 784 remote = localrepo.locallegacypeer(remote.local())
786 785 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
787 786 force=True)
788 787 common = set(common)
789 788 if not opts.get('nonheads'):
790 789 ui.write(("unpruned common: %s\n") %
791 790 " ".join(sorted(short(n) for n in common)))
792 791 dag = dagutil.revlogdag(repo.changelog)
793 792 all = dag.ancestorset(dag.internalizeall(common))
794 793 common = dag.externalizeall(dag.headsetofconnecteds(all))
795 794 else:
796 795 nodes = None
797 796 if pushedrevs:
798 797 revs = scmutil.revrange(repo, pushedrevs)
799 798 nodes = [repo[r].node() for r in revs]
800 799 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote,
801 800 ancestorsof=nodes)
802 801 common = set(common)
803 802 rheads = set(hds)
804 803 lheads = set(repo.heads())
805 804 ui.write(("common heads: %s\n") %
806 805 " ".join(sorted(short(n) for n in common)))
807 806 if lheads <= common:
808 807 ui.write(("local is subset\n"))
809 808 elif rheads <= common:
810 809 ui.write(("remote is subset\n"))
811 810
812 811 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches, revs=None)
813 812 localrevs = opts['rev']
814 813 doit(localrevs, remoterevs)
815 814
816 815 _chunksize = 4 << 10
817 816
818 817 @command('debugdownload',
819 818 [
820 819 ('o', 'output', '', _('path')),
821 820 ],
822 821 optionalrepo=True)
823 822 def debugdownload(ui, repo, url, output=None, **opts):
824 823 """download a resource using Mercurial logic and config
825 824 """
826 825 fh = urlmod.open(ui, url, output)
827 826
828 827 dest = ui
829 828 if output:
830 829 dest = open(output, "wb", _chunksize)
831 830 try:
832 831 data = fh.read(_chunksize)
833 832 while data:
834 833 dest.write(data)
835 834 data = fh.read(_chunksize)
836 835 finally:
837 836 if output:
838 837 dest.close()
839 838
840 839 @command('debugextensions', cmdutil.formatteropts, [], optionalrepo=True)
841 840 def debugextensions(ui, repo, **opts):
842 841 '''show information about active extensions'''
843 842 opts = pycompat.byteskwargs(opts)
844 843 exts = extensions.extensions(ui)
845 844 hgver = util.version()
846 845 fm = ui.formatter('debugextensions', opts)
847 846 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
848 847 isinternal = extensions.ismoduleinternal(extmod)
849 848 extsource = pycompat.fsencode(extmod.__file__)
850 849 if isinternal:
851 850 exttestedwith = [] # never expose magic string to users
852 851 else:
853 852 exttestedwith = getattr(extmod, 'testedwith', '').split()
854 853 extbuglink = getattr(extmod, 'buglink', None)
855 854
856 855 fm.startitem()
857 856
858 857 if ui.quiet or ui.verbose:
859 858 fm.write('name', '%s\n', extname)
860 859 else:
861 860 fm.write('name', '%s', extname)
862 861 if isinternal or hgver in exttestedwith:
863 862 fm.plain('\n')
864 863 elif not exttestedwith:
865 864 fm.plain(_(' (untested!)\n'))
866 865 else:
867 866 lasttestedversion = exttestedwith[-1]
868 867 fm.plain(' (%s!)\n' % lasttestedversion)
869 868
870 869 fm.condwrite(ui.verbose and extsource, 'source',
871 870 _(' location: %s\n'), extsource or "")
872 871
873 872 if ui.verbose:
874 873 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
875 874 fm.data(bundled=isinternal)
876 875
877 876 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
878 877 _(' tested with: %s\n'),
879 878 fm.formatlist(exttestedwith, name='ver'))
880 879
881 880 fm.condwrite(ui.verbose and extbuglink, 'buglink',
882 881 _(' bug reporting: %s\n'), extbuglink or "")
883 882
884 883 fm.end()
885 884
886 885 @command('debugfileset',
887 886 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
888 887 _('[-r REV] FILESPEC'))
889 888 def debugfileset(ui, repo, expr, **opts):
890 889 '''parse and apply a fileset specification'''
891 890 ctx = scmutil.revsingle(repo, opts.get(r'rev'), None)
892 891 if ui.verbose:
893 892 tree = fileset.parse(expr)
894 893 ui.note(fileset.prettyformat(tree), "\n")
895 894
896 895 for f in ctx.getfileset(expr):
897 896 ui.write("%s\n" % f)
898 897
899 898 @command('debugformat',
900 899 [] + cmdutil.formatteropts,
901 900 _(''))
902 901 def debugformat(ui, repo, **opts):
903 902 """display format information about the current repository
904 903
905 904 Use --verbose to get extra information about current config value and
906 905 Mercurial default."""
907 906 opts = pycompat.byteskwargs(opts)
908 907 maxvariantlength = max(len(fv.name) for fv in upgrade.allformatvariant)
909 908 maxvariantlength = max(len('format-variant'), maxvariantlength)
910 909
911 910 def makeformatname(name):
912 911 return '%s:' + (' ' * (maxvariantlength - len(name)))
913 912
914 913 fm = ui.formatter('debugformat', opts)
915 914 if fm.isplain():
916 915 def formatvalue(value):
917 916 if util.safehasattr(value, 'startswith'):
918 917 return value
919 918 if value:
920 919 return 'yes'
921 920 else:
922 921 return 'no'
923 922 else:
924 923 formatvalue = pycompat.identity
925 924
926 925 fm.plain('format-variant')
927 926 fm.plain(' ' * (maxvariantlength - len('format-variant')))
928 927 fm.plain(' repo')
929 928 if ui.verbose:
930 929 fm.plain(' config default')
931 930 fm.plain('\n')
932 931 for fv in upgrade.allformatvariant:
933 932 fm.startitem()
934 933 repovalue = fv.fromrepo(repo)
935 934 configvalue = fv.fromconfig(repo)
936 935
937 936 if repovalue != configvalue:
938 937 namelabel = 'formatvariant.name.mismatchconfig'
939 938 repolabel = 'formatvariant.repo.mismatchconfig'
940 939 elif repovalue != fv.default:
941 940 namelabel = 'formatvariant.name.mismatchdefault'
942 941 repolabel = 'formatvariant.repo.mismatchdefault'
943 942 else:
944 943 namelabel = 'formatvariant.name.uptodate'
945 944 repolabel = 'formatvariant.repo.uptodate'
946 945
947 946 fm.write('name', makeformatname(fv.name), fv.name,
948 947 label=namelabel)
949 948 fm.write('repo', ' %3s', formatvalue(repovalue),
950 949 label=repolabel)
951 950 if fv.default != configvalue:
952 951 configlabel = 'formatvariant.config.special'
953 952 else:
954 953 configlabel = 'formatvariant.config.default'
955 954 fm.condwrite(ui.verbose, 'config', ' %6s', formatvalue(configvalue),
956 955 label=configlabel)
957 956 fm.condwrite(ui.verbose, 'default', ' %7s', formatvalue(fv.default),
958 957 label='formatvariant.default')
959 958 fm.plain('\n')
960 959 fm.end()
961 960
962 961 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
963 962 def debugfsinfo(ui, path="."):
964 963 """show information detected about current filesystem"""
965 964 ui.write(('path: %s\n') % path)
966 965 ui.write(('mounted on: %s\n') % (util.getfsmountpoint(path) or '(unknown)'))
967 966 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
968 967 ui.write(('fstype: %s\n') % (util.getfstype(path) or '(unknown)'))
969 968 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
970 969 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
971 970 casesensitive = '(unknown)'
972 971 try:
973 972 with pycompat.namedtempfile(prefix='.debugfsinfo', dir=path) as f:
974 973 casesensitive = util.fscasesensitive(f.name) and 'yes' or 'no'
975 974 except OSError:
976 975 pass
977 976 ui.write(('case-sensitive: %s\n') % casesensitive)
978 977
979 978 @command('debuggetbundle',
980 979 [('H', 'head', [], _('id of head node'), _('ID')),
981 980 ('C', 'common', [], _('id of common node'), _('ID')),
982 981 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
983 982 _('REPO FILE [-H|-C ID]...'),
984 983 norepo=True)
985 984 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
986 985 """retrieves a bundle from a repo
987 986
988 987 Every ID must be a full-length hex node id string. Saves the bundle to the
989 988 given file.
990 989 """
991 990 opts = pycompat.byteskwargs(opts)
992 991 repo = hg.peer(ui, opts, repopath)
993 992 if not repo.capable('getbundle'):
994 993 raise error.Abort("getbundle() not supported by target repository")
995 994 args = {}
996 995 if common:
997 996 args[r'common'] = [bin(s) for s in common]
998 997 if head:
999 998 args[r'heads'] = [bin(s) for s in head]
1000 999 # TODO: get desired bundlecaps from command line.
1001 1000 args[r'bundlecaps'] = None
1002 1001 bundle = repo.getbundle('debug', **args)
1003 1002
1004 1003 bundletype = opts.get('type', 'bzip2').lower()
1005 1004 btypes = {'none': 'HG10UN',
1006 1005 'bzip2': 'HG10BZ',
1007 1006 'gzip': 'HG10GZ',
1008 1007 'bundle2': 'HG20'}
1009 1008 bundletype = btypes.get(bundletype)
1010 1009 if bundletype not in bundle2.bundletypes:
1011 1010 raise error.Abort(_('unknown bundle type specified with --type'))
1012 1011 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
1013 1012
1014 1013 @command('debugignore', [], '[FILE]')
1015 1014 def debugignore(ui, repo, *files, **opts):
1016 1015 """display the combined ignore pattern and information about ignored files
1017 1016
1018 1017 With no argument display the combined ignore pattern.
1019 1018
1020 1019 Given space separated file names, shows if the given file is ignored and
1021 1020 if so, show the ignore rule (file and line number) that matched it.
1022 1021 """
1023 1022 ignore = repo.dirstate._ignore
1024 1023 if not files:
1025 1024 # Show all the patterns
1026 1025 ui.write("%s\n" % pycompat.byterepr(ignore))
1027 1026 else:
1028 1027 m = scmutil.match(repo[None], pats=files)
1029 1028 for f in m.files():
1030 1029 nf = util.normpath(f)
1031 1030 ignored = None
1032 1031 ignoredata = None
1033 1032 if nf != '.':
1034 1033 if ignore(nf):
1035 1034 ignored = nf
1036 1035 ignoredata = repo.dirstate._ignorefileandline(nf)
1037 1036 else:
1038 1037 for p in util.finddirs(nf):
1039 1038 if ignore(p):
1040 1039 ignored = p
1041 1040 ignoredata = repo.dirstate._ignorefileandline(p)
1042 1041 break
1043 1042 if ignored:
1044 1043 if ignored == nf:
1045 1044 ui.write(_("%s is ignored\n") % m.uipath(f))
1046 1045 else:
1047 1046 ui.write(_("%s is ignored because of "
1048 1047 "containing folder %s\n")
1049 1048 % (m.uipath(f), ignored))
1050 1049 ignorefile, lineno, line = ignoredata
1051 1050 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
1052 1051 % (ignorefile, lineno, line))
1053 1052 else:
1054 1053 ui.write(_("%s is not ignored\n") % m.uipath(f))
1055 1054
1056 1055 @command('debugindex', cmdutil.debugrevlogopts +
1057 1056 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1058 1057 _('[-f FORMAT] -c|-m|FILE'),
1059 1058 optionalrepo=True)
1060 1059 def debugindex(ui, repo, file_=None, **opts):
1061 1060 """dump the contents of an index file"""
1062 1061 opts = pycompat.byteskwargs(opts)
1063 1062 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1064 1063 format = opts.get('format', 0)
1065 1064 if format not in (0, 1):
1066 1065 raise error.Abort(_("unknown format %d") % format)
1067 1066
1068 1067 if ui.debugflag:
1069 1068 shortfn = hex
1070 1069 else:
1071 1070 shortfn = short
1072 1071
1073 1072 # There might not be anything in r, so have a sane default
1074 1073 idlen = 12
1075 1074 for i in r:
1076 1075 idlen = len(shortfn(r.node(i)))
1077 1076 break
1078 1077
1079 1078 if format == 0:
1080 1079 if ui.verbose:
1081 1080 ui.write((" rev offset length linkrev"
1082 1081 " %s %s p2\n") % ("nodeid".ljust(idlen),
1083 1082 "p1".ljust(idlen)))
1084 1083 else:
1085 1084 ui.write((" rev linkrev %s %s p2\n") % (
1086 1085 "nodeid".ljust(idlen), "p1".ljust(idlen)))
1087 1086 elif format == 1:
1088 1087 if ui.verbose:
1089 1088 ui.write((" rev flag offset length size link p1"
1090 1089 " p2 %s\n") % "nodeid".rjust(idlen))
1091 1090 else:
1092 1091 ui.write((" rev flag size link p1 p2 %s\n") %
1093 1092 "nodeid".rjust(idlen))
1094 1093
1095 1094 for i in r:
1096 1095 node = r.node(i)
1097 1096 if format == 0:
1098 1097 try:
1099 1098 pp = r.parents(node)
1100 1099 except Exception:
1101 1100 pp = [nullid, nullid]
1102 1101 if ui.verbose:
1103 1102 ui.write("% 6d % 9d % 7d % 7d %s %s %s\n" % (
1104 1103 i, r.start(i), r.length(i), r.linkrev(i),
1105 1104 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
1106 1105 else:
1107 1106 ui.write("% 6d % 7d %s %s %s\n" % (
1108 1107 i, r.linkrev(i), shortfn(node), shortfn(pp[0]),
1109 1108 shortfn(pp[1])))
1110 1109 elif format == 1:
1111 1110 pr = r.parentrevs(i)
1112 1111 if ui.verbose:
1113 1112 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d %s\n" % (
1114 1113 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1115 1114 r.linkrev(i), pr[0], pr[1], shortfn(node)))
1116 1115 else:
1117 1116 ui.write("% 6d %04x % 8d % 6d % 6d % 6d %s\n" % (
1118 1117 i, r.flags(i), r.rawsize(i), r.linkrev(i), pr[0], pr[1],
1119 1118 shortfn(node)))
1120 1119
1121 1120 @command('debugindexdot', cmdutil.debugrevlogopts,
1122 1121 _('-c|-m|FILE'), optionalrepo=True)
1123 1122 def debugindexdot(ui, repo, file_=None, **opts):
1124 1123 """dump an index DAG as a graphviz dot file"""
1125 1124 opts = pycompat.byteskwargs(opts)
1126 1125 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
1127 1126 ui.write(("digraph G {\n"))
1128 1127 for i in r:
1129 1128 node = r.node(i)
1130 1129 pp = r.parents(node)
1131 1130 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1132 1131 if pp[1] != nullid:
1133 1132 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1134 1133 ui.write("}\n")
1135 1134
1136 1135 @command('debuginstall', [] + cmdutil.formatteropts, '', norepo=True)
1137 1136 def debuginstall(ui, **opts):
1138 1137 '''test Mercurial installation
1139 1138
1140 1139 Returns 0 on success.
1141 1140 '''
1142 1141 opts = pycompat.byteskwargs(opts)
1143 1142
1144 1143 def writetemp(contents):
1145 1144 (fd, name) = pycompat.mkstemp(prefix="hg-debuginstall-")
1146 1145 f = os.fdopen(fd, r"wb")
1147 1146 f.write(contents)
1148 1147 f.close()
1149 1148 return name
1150 1149
1151 1150 problems = 0
1152 1151
1153 1152 fm = ui.formatter('debuginstall', opts)
1154 1153 fm.startitem()
1155 1154
1156 1155 # encoding
1157 1156 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
1158 1157 err = None
1159 1158 try:
1160 1159 codecs.lookup(pycompat.sysstr(encoding.encoding))
1161 1160 except LookupError as inst:
1162 1161 err = stringutil.forcebytestr(inst)
1163 1162 problems += 1
1164 1163 fm.condwrite(err, 'encodingerror', _(" %s\n"
1165 1164 " (check that your locale is properly set)\n"), err)
1166 1165
1167 1166 # Python
1168 1167 fm.write('pythonexe', _("checking Python executable (%s)\n"),
1169 1168 pycompat.sysexecutable)
1170 1169 fm.write('pythonver', _("checking Python version (%s)\n"),
1171 1170 ("%d.%d.%d" % sys.version_info[:3]))
1172 1171 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
1173 1172 os.path.dirname(pycompat.fsencode(os.__file__)))
1174 1173
1175 1174 security = set(sslutil.supportedprotocols)
1176 1175 if sslutil.hassni:
1177 1176 security.add('sni')
1178 1177
1179 1178 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
1180 1179 fm.formatlist(sorted(security), name='protocol',
1181 1180 fmt='%s', sep=','))
1182 1181
1183 1182 # These are warnings, not errors. So don't increment problem count. This
1184 1183 # may change in the future.
1185 1184 if 'tls1.2' not in security:
1186 1185 fm.plain(_(' TLS 1.2 not supported by Python install; '
1187 1186 'network connections lack modern security\n'))
1188 1187 if 'sni' not in security:
1189 1188 fm.plain(_(' SNI not supported by Python install; may have '
1190 1189 'connectivity issues with some servers\n'))
1191 1190
1192 1191 # TODO print CA cert info
1193 1192
1194 1193 # hg version
1195 1194 hgver = util.version()
1196 1195 fm.write('hgver', _("checking Mercurial version (%s)\n"),
1197 1196 hgver.split('+')[0])
1198 1197 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
1199 1198 '+'.join(hgver.split('+')[1:]))
1200 1199
1201 1200 # compiled modules
1202 1201 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
1203 1202 policy.policy)
1204 1203 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
1205 1204 os.path.dirname(pycompat.fsencode(__file__)))
1206 1205
1207 1206 if policy.policy in ('c', 'allow'):
1208 1207 err = None
1209 1208 try:
1210 1209 from .cext import (
1211 1210 base85,
1212 1211 bdiff,
1213 1212 mpatch,
1214 1213 osutil,
1215 1214 )
1216 1215 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
1217 1216 except Exception as inst:
1218 1217 err = stringutil.forcebytestr(inst)
1219 1218 problems += 1
1220 1219 fm.condwrite(err, 'extensionserror', " %s\n", err)
1221 1220
1222 1221 compengines = util.compengines._engines.values()
1223 1222 fm.write('compengines', _('checking registered compression engines (%s)\n'),
1224 1223 fm.formatlist(sorted(e.name() for e in compengines),
1225 1224 name='compengine', fmt='%s', sep=', '))
1226 1225 fm.write('compenginesavail', _('checking available compression engines '
1227 1226 '(%s)\n'),
1228 1227 fm.formatlist(sorted(e.name() for e in compengines
1229 1228 if e.available()),
1230 1229 name='compengine', fmt='%s', sep=', '))
1231 1230 wirecompengines = util.compengines.supportedwireengines(util.SERVERROLE)
1232 1231 fm.write('compenginesserver', _('checking available compression engines '
1233 1232 'for wire protocol (%s)\n'),
1234 1233 fm.formatlist([e.name() for e in wirecompengines
1235 1234 if e.wireprotosupport()],
1236 1235 name='compengine', fmt='%s', sep=', '))
1237 1236 re2 = 'missing'
1238 1237 if util._re2:
1239 1238 re2 = 'available'
1240 1239 fm.plain(_('checking "re2" regexp engine (%s)\n') % re2)
1241 1240 fm.data(re2=bool(util._re2))
1242 1241
1243 1242 # templates
1244 1243 p = templater.templatepaths()
1245 1244 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
1246 1245 fm.condwrite(not p, '', _(" no template directories found\n"))
1247 1246 if p:
1248 1247 m = templater.templatepath("map-cmdline.default")
1249 1248 if m:
1250 1249 # template found, check if it is working
1251 1250 err = None
1252 1251 try:
1253 1252 templater.templater.frommapfile(m)
1254 1253 except Exception as inst:
1255 1254 err = stringutil.forcebytestr(inst)
1256 1255 p = None
1257 1256 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
1258 1257 else:
1259 1258 p = None
1260 1259 fm.condwrite(p, 'defaulttemplate',
1261 1260 _("checking default template (%s)\n"), m)
1262 1261 fm.condwrite(not m, 'defaulttemplatenotfound',
1263 1262 _(" template '%s' not found\n"), "default")
1264 1263 if not p:
1265 1264 problems += 1
1266 1265 fm.condwrite(not p, '',
1267 1266 _(" (templates seem to have been installed incorrectly)\n"))
1268 1267
1269 1268 # editor
1270 1269 editor = ui.geteditor()
1271 1270 editor = util.expandpath(editor)
1272 1271 editorbin = procutil.shellsplit(editor)[0]
1273 1272 fm.write('editor', _("checking commit editor... (%s)\n"), editorbin)
1274 1273 cmdpath = procutil.findexe(editorbin)
1275 1274 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
1276 1275 _(" No commit editor set and can't find %s in PATH\n"
1277 1276 " (specify a commit editor in your configuration"
1278 1277 " file)\n"), not cmdpath and editor == 'vi' and editorbin)
1279 1278 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
1280 1279 _(" Can't find editor '%s' in PATH\n"
1281 1280 " (specify a commit editor in your configuration"
1282 1281 " file)\n"), not cmdpath and editorbin)
1283 1282 if not cmdpath and editor != 'vi':
1284 1283 problems += 1
1285 1284
1286 1285 # check username
1287 1286 username = None
1288 1287 err = None
1289 1288 try:
1290 1289 username = ui.username()
1291 1290 except error.Abort as e:
1292 1291 err = stringutil.forcebytestr(e)
1293 1292 problems += 1
1294 1293
1295 1294 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
1296 1295 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
1297 1296 " (specify a username in your configuration file)\n"), err)
1298 1297
1299 1298 fm.condwrite(not problems, '',
1300 1299 _("no problems detected\n"))
1301 1300 if not problems:
1302 1301 fm.data(problems=problems)
1303 1302 fm.condwrite(problems, 'problems',
1304 1303 _("%d problems detected,"
1305 1304 " please check your install!\n"), problems)
1306 1305 fm.end()
1307 1306
1308 1307 return problems
1309 1308
1310 1309 @command('debugknown', [], _('REPO ID...'), norepo=True)
1311 1310 def debugknown(ui, repopath, *ids, **opts):
1312 1311 """test whether node ids are known to a repo
1313 1312
1314 1313 Every ID must be a full-length hex node id string. Returns a list of 0s
1315 1314 and 1s indicating unknown/known.
1316 1315 """
1317 1316 opts = pycompat.byteskwargs(opts)
1318 1317 repo = hg.peer(ui, opts, repopath)
1319 1318 if not repo.capable('known'):
1320 1319 raise error.Abort("known() not supported by target repository")
1321 1320 flags = repo.known([bin(s) for s in ids])
1322 1321 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1323 1322
1324 1323 @command('debuglabelcomplete', [], _('LABEL...'))
1325 1324 def debuglabelcomplete(ui, repo, *args):
1326 1325 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
1327 1326 debugnamecomplete(ui, repo, *args)
1328 1327
1329 1328 @command('debuglocks',
1330 1329 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
1331 1330 ('W', 'force-wlock', None,
1332 1331 _('free the working state lock (DANGEROUS)')),
1333 1332 ('s', 'set-lock', None, _('set the store lock until stopped')),
1334 1333 ('S', 'set-wlock', None,
1335 1334 _('set the working state lock until stopped'))],
1336 1335 _('[OPTION]...'))
1337 1336 def debuglocks(ui, repo, **opts):
1338 1337 """show or modify state of locks
1339 1338
1340 1339 By default, this command will show which locks are held. This
1341 1340 includes the user and process holding the lock, the amount of time
1342 1341 the lock has been held, and the machine name where the process is
1343 1342 running if it's not local.
1344 1343
1345 1344 Locks protect the integrity of Mercurial's data, so should be
1346 1345 treated with care. System crashes or other interruptions may cause
1347 1346 locks to not be properly released, though Mercurial will usually
1348 1347 detect and remove such stale locks automatically.
1349 1348
1350 1349 However, detecting stale locks may not always be possible (for
1351 1350 instance, on a shared filesystem). Removing locks may also be
1352 1351 blocked by filesystem permissions.
1353 1352
1354 1353 Setting a lock will prevent other commands from changing the data.
1355 1354 The command will wait until an interruption (SIGINT, SIGTERM, ...) occurs.
1356 1355 The set locks are removed when the command exits.
1357 1356
1358 1357 Returns 0 if no locks are held.
1359 1358
1360 1359 """
1361 1360
1362 1361 if opts.get(r'force_lock'):
1363 1362 repo.svfs.unlink('lock')
1364 1363 if opts.get(r'force_wlock'):
1365 1364 repo.vfs.unlink('wlock')
1366 1365 if opts.get(r'force_lock') or opts.get(r'force_wlock'):
1367 1366 return 0
1368 1367
1369 1368 locks = []
1370 1369 try:
1371 1370 if opts.get(r'set_wlock'):
1372 1371 try:
1373 1372 locks.append(repo.wlock(False))
1374 1373 except error.LockHeld:
1375 1374 raise error.Abort(_('wlock is already held'))
1376 1375 if opts.get(r'set_lock'):
1377 1376 try:
1378 1377 locks.append(repo.lock(False))
1379 1378 except error.LockHeld:
1380 1379 raise error.Abort(_('lock is already held'))
1381 1380 if len(locks):
1382 1381 ui.promptchoice(_("ready to release the lock (y)? $$ &Yes"))
1383 1382 return 0
1384 1383 finally:
1385 1384 release(*locks)
1386 1385
1387 1386 now = time.time()
1388 1387 held = 0
1389 1388
1390 1389 def report(vfs, name, method):
1391 1390 # this causes stale locks to get reaped for more accurate reporting
1392 1391 try:
1393 1392 l = method(False)
1394 1393 except error.LockHeld:
1395 1394 l = None
1396 1395
1397 1396 if l:
1398 1397 l.release()
1399 1398 else:
1400 1399 try:
1401 1400 st = vfs.lstat(name)
1402 1401 age = now - st[stat.ST_MTIME]
1403 1402 user = util.username(st.st_uid)
1404 1403 locker = vfs.readlock(name)
1405 1404 if ":" in locker:
1406 1405 host, pid = locker.split(':')
1407 1406 if host == socket.gethostname():
1408 1407 locker = 'user %s, process %s' % (user, pid)
1409 1408 else:
1410 1409 locker = 'user %s, process %s, host %s' \
1411 1410 % (user, pid, host)
1412 1411 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
1413 1412 return 1
1414 1413 except OSError as e:
1415 1414 if e.errno != errno.ENOENT:
1416 1415 raise
1417 1416
1418 1417 ui.write(("%-6s free\n") % (name + ":"))
1419 1418 return 0
1420 1419
1421 1420 held += report(repo.svfs, "lock", repo.lock)
1422 1421 held += report(repo.vfs, "wlock", repo.wlock)
1423 1422
1424 1423 return held
1425 1424
1426 1425 @command('debugmergestate', [], '')
1427 1426 def debugmergestate(ui, repo, *args):
1428 1427 """print merge state
1429 1428
1430 1429 Use --verbose to print out information about whether v1 or v2 merge state
1431 1430 was chosen."""
1432 1431 def _hashornull(h):
1433 1432 if h == nullhex:
1434 1433 return 'null'
1435 1434 else:
1436 1435 return h
1437 1436
1438 1437 def printrecords(version):
1439 1438 ui.write(('* version %d records\n') % version)
1440 1439 if version == 1:
1441 1440 records = v1records
1442 1441 else:
1443 1442 records = v2records
1444 1443
1445 1444 for rtype, record in records:
1446 1445 # pretty print some record types
1447 1446 if rtype == 'L':
1448 1447 ui.write(('local: %s\n') % record)
1449 1448 elif rtype == 'O':
1450 1449 ui.write(('other: %s\n') % record)
1451 1450 elif rtype == 'm':
1452 1451 driver, mdstate = record.split('\0', 1)
1453 1452 ui.write(('merge driver: %s (state "%s")\n')
1454 1453 % (driver, mdstate))
1455 1454 elif rtype in 'FDC':
1456 1455 r = record.split('\0')
1457 1456 f, state, hash, lfile, afile, anode, ofile = r[0:7]
1458 1457 if version == 1:
1459 1458 onode = 'not stored in v1 format'
1460 1459 flags = r[7]
1461 1460 else:
1462 1461 onode, flags = r[7:9]
1463 1462 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
1464 1463 % (f, rtype, state, _hashornull(hash)))
1465 1464 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
1466 1465 ui.write((' ancestor path: %s (node %s)\n')
1467 1466 % (afile, _hashornull(anode)))
1468 1467 ui.write((' other path: %s (node %s)\n')
1469 1468 % (ofile, _hashornull(onode)))
1470 1469 elif rtype == 'f':
1471 1470 filename, rawextras = record.split('\0', 1)
1472 1471 extras = rawextras.split('\0')
1473 1472 i = 0
1474 1473 extrastrings = []
1475 1474 while i < len(extras):
1476 1475 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
1477 1476 i += 2
1478 1477
1479 1478 ui.write(('file extras: %s (%s)\n')
1480 1479 % (filename, ', '.join(extrastrings)))
1481 1480 elif rtype == 'l':
1482 1481 labels = record.split('\0', 2)
1483 1482 labels = [l for l in labels if len(l) > 0]
1484 1483 ui.write(('labels:\n'))
1485 1484 ui.write((' local: %s\n' % labels[0]))
1486 1485 ui.write((' other: %s\n' % labels[1]))
1487 1486 if len(labels) > 2:
1488 1487 ui.write((' base: %s\n' % labels[2]))
1489 1488 else:
1490 1489 ui.write(('unrecognized entry: %s\t%s\n')
1491 1490 % (rtype, record.replace('\0', '\t')))
1492 1491
1493 1492 # Avoid mergestate.read() since it may raise an exception for unsupported
1494 1493 # merge state records. We shouldn't be doing this, but this is OK since this
1495 1494 # command is pretty low-level.
1496 1495 ms = mergemod.mergestate(repo)
1497 1496
1498 1497 # sort so that reasonable information is on top
1499 1498 v1records = ms._readrecordsv1()
1500 1499 v2records = ms._readrecordsv2()
1501 1500 order = 'LOml'
1502 1501 def key(r):
1503 1502 idx = order.find(r[0])
1504 1503 if idx == -1:
1505 1504 return (1, r[1])
1506 1505 else:
1507 1506 return (0, idx)
1508 1507 v1records.sort(key=key)
1509 1508 v2records.sort(key=key)
1510 1509
1511 1510 if not v1records and not v2records:
1512 1511 ui.write(('no merge state found\n'))
1513 1512 elif not v2records:
1514 1513 ui.note(('no version 2 merge state\n'))
1515 1514 printrecords(1)
1516 1515 elif ms._v1v2match(v1records, v2records):
1517 1516 ui.note(('v1 and v2 states match: using v2\n'))
1518 1517 printrecords(2)
1519 1518 else:
1520 1519 ui.note(('v1 and v2 states mismatch: using v1\n'))
1521 1520 printrecords(1)
1522 1521 if ui.verbose:
1523 1522 printrecords(2)
1524 1523
1525 1524 @command('debugnamecomplete', [], _('NAME...'))
1526 1525 def debugnamecomplete(ui, repo, *args):
1527 1526 '''complete "names" - tags, open branch names, bookmark names'''
1528 1527
1529 1528 names = set()
1530 1529 # since we previously only listed open branches, we will handle that
1531 1530 # specially (after this for loop)
1532 1531 for name, ns in repo.names.iteritems():
1533 1532 if name != 'branches':
1534 1533 names.update(ns.listnames(repo))
1535 1534 names.update(tag for (tag, heads, tip, closed)
1536 1535 in repo.branchmap().iterbranches() if not closed)
1537 1536 completions = set()
1538 1537 if not args:
1539 1538 args = ['']
1540 1539 for a in args:
1541 1540 completions.update(n for n in names if n.startswith(a))
1542 1541 ui.write('\n'.join(sorted(completions)))
1543 1542 ui.write('\n')
1544 1543
1545 1544 @command('debugobsolete',
1546 1545 [('', 'flags', 0, _('markers flag')),
1547 1546 ('', 'record-parents', False,
1548 1547 _('record parent information for the precursor')),
1549 1548 ('r', 'rev', [], _('display markers relevant to REV')),
1550 1549 ('', 'exclusive', False, _('restrict display to markers only '
1551 1550 'relevant to REV')),
1552 1551 ('', 'index', False, _('display index of the marker')),
1553 1552 ('', 'delete', [], _('delete markers specified by indices')),
1554 1553 ] + cmdutil.commitopts2 + cmdutil.formatteropts,
1555 1554 _('[OBSOLETED [REPLACEMENT ...]]'))
1556 1555 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
1557 1556 """create arbitrary obsolete marker
1558 1557
1559 1558 With no arguments, displays the list of obsolescence markers."""
1560 1559
1561 1560 opts = pycompat.byteskwargs(opts)
1562 1561
1563 1562 def parsenodeid(s):
1564 1563 try:
1565 1564 # We do not use revsingle/revrange functions here to accept
1566 1565 # arbitrary node identifiers, possibly not present in the
1567 1566 # local repository.
1568 1567 n = bin(s)
1569 1568 if len(n) != len(nullid):
1570 1569 raise TypeError()
1571 1570 return n
1572 1571 except TypeError:
1573 1572 raise error.Abort('changeset references must be full hexadecimal '
1574 1573 'node identifiers')
1575 1574
1576 1575 if opts.get('delete'):
1577 1576 indices = []
1578 1577 for v in opts.get('delete'):
1579 1578 try:
1580 1579 indices.append(int(v))
1581 1580 except ValueError:
1582 1581 raise error.Abort(_('invalid index value: %r') % v,
1583 1582 hint=_('use integers for indices'))
1584 1583
1585 1584 if repo.currenttransaction():
1586 1585 raise error.Abort(_('cannot delete obsmarkers in the middle '
1587 1586 'of transaction.'))
1588 1587
1589 1588 with repo.lock():
1590 1589 n = repair.deleteobsmarkers(repo.obsstore, indices)
1591 1590 ui.write(_('deleted %i obsolescence markers\n') % n)
1592 1591
1593 1592 return
1594 1593
1595 1594 if precursor is not None:
1596 1595 if opts['rev']:
1597 1596 raise error.Abort('cannot select revision when creating marker')
1598 1597 metadata = {}
1599 1598 metadata['user'] = opts['user'] or ui.username()
1600 1599 succs = tuple(parsenodeid(succ) for succ in successors)
1601 1600 l = repo.lock()
1602 1601 try:
1603 1602 tr = repo.transaction('debugobsolete')
1604 1603 try:
1605 1604 date = opts.get('date')
1606 1605 if date:
1607 1606 date = dateutil.parsedate(date)
1608 1607 else:
1609 1608 date = None
1610 1609 prec = parsenodeid(precursor)
1611 1610 parents = None
1612 1611 if opts['record_parents']:
1613 1612 if prec not in repo.unfiltered():
1614 1613 raise error.Abort('cannot used --record-parents on '
1615 1614 'unknown changesets')
1616 1615 parents = repo.unfiltered()[prec].parents()
1617 1616 parents = tuple(p.node() for p in parents)
1618 1617 repo.obsstore.create(tr, prec, succs, opts['flags'],
1619 1618 parents=parents, date=date,
1620 1619 metadata=metadata, ui=ui)
1621 1620 tr.close()
1622 1621 except ValueError as exc:
1623 1622 raise error.Abort(_('bad obsmarker input: %s') %
1624 1623 pycompat.bytestr(exc))
1625 1624 finally:
1626 1625 tr.release()
1627 1626 finally:
1628 1627 l.release()
1629 1628 else:
1630 1629 if opts['rev']:
1631 1630 revs = scmutil.revrange(repo, opts['rev'])
1632 1631 nodes = [repo[r].node() for r in revs]
1633 1632 markers = list(obsutil.getmarkers(repo, nodes=nodes,
1634 1633 exclusive=opts['exclusive']))
1635 1634 markers.sort(key=lambda x: x._data)
1636 1635 else:
1637 1636 markers = obsutil.getmarkers(repo)
1638 1637
1639 1638 markerstoiter = markers
1640 1639 isrelevant = lambda m: True
1641 1640 if opts.get('rev') and opts.get('index'):
1642 1641 markerstoiter = obsutil.getmarkers(repo)
1643 1642 markerset = set(markers)
1644 1643 isrelevant = lambda m: m in markerset
1645 1644
1646 1645 fm = ui.formatter('debugobsolete', opts)
1647 1646 for i, m in enumerate(markerstoiter):
1648 1647 if not isrelevant(m):
1649 1648 # marker can be irrelevant when we're iterating over a set
1650 1649 # of markers (markerstoiter) which is bigger than the set
1651 1650 # of markers we want to display (markers)
1652 1651 # this can happen if both --index and --rev options are
1653 1652 # provided and thus we need to iterate over all of the markers
1654 1653 # to get the correct indices, but only display the ones that
1655 1654 # are relevant to --rev value
1656 1655 continue
1657 1656 fm.startitem()
1658 1657 ind = i if opts.get('index') else None
1659 1658 cmdutil.showmarker(fm, m, index=ind)
1660 1659 fm.end()
1661 1660
1662 1661 @command('debugpathcomplete',
1663 1662 [('f', 'full', None, _('complete an entire path')),
1664 1663 ('n', 'normal', None, _('show only normal files')),
1665 1664 ('a', 'added', None, _('show only added files')),
1666 1665 ('r', 'removed', None, _('show only removed files'))],
1667 1666 _('FILESPEC...'))
1668 1667 def debugpathcomplete(ui, repo, *specs, **opts):
1669 1668 '''complete part or all of a tracked path
1670 1669
1671 1670 This command supports shells that offer path name completion. It
1672 1671 currently completes only files already known to the dirstate.
1673 1672
1674 1673 Completion extends only to the next path segment unless
1675 1674 --full is specified, in which case entire paths are used.'''
1676 1675
1677 1676 def complete(path, acceptable):
1678 1677 dirstate = repo.dirstate
1679 1678 spec = os.path.normpath(os.path.join(pycompat.getcwd(), path))
1680 1679 rootdir = repo.root + pycompat.ossep
1681 1680 if spec != repo.root and not spec.startswith(rootdir):
1682 1681 return [], []
1683 1682 if os.path.isdir(spec):
1684 1683 spec += '/'
1685 1684 spec = spec[len(rootdir):]
1686 1685 fixpaths = pycompat.ossep != '/'
1687 1686 if fixpaths:
1688 1687 spec = spec.replace(pycompat.ossep, '/')
1689 1688 speclen = len(spec)
1690 1689 fullpaths = opts[r'full']
1691 1690 files, dirs = set(), set()
1692 1691 adddir, addfile = dirs.add, files.add
1693 1692 for f, st in dirstate.iteritems():
1694 1693 if f.startswith(spec) and st[0] in acceptable:
1695 1694 if fixpaths:
1696 1695 f = f.replace('/', pycompat.ossep)
1697 1696 if fullpaths:
1698 1697 addfile(f)
1699 1698 continue
1700 1699 s = f.find(pycompat.ossep, speclen)
1701 1700 if s >= 0:
1702 1701 adddir(f[:s])
1703 1702 else:
1704 1703 addfile(f)
1705 1704 return files, dirs
1706 1705
1707 1706 acceptable = ''
1708 1707 if opts[r'normal']:
1709 1708 acceptable += 'nm'
1710 1709 if opts[r'added']:
1711 1710 acceptable += 'a'
1712 1711 if opts[r'removed']:
1713 1712 acceptable += 'r'
1714 1713 cwd = repo.getcwd()
1715 1714 if not specs:
1716 1715 specs = ['.']
1717 1716
1718 1717 files, dirs = set(), set()
1719 1718 for spec in specs:
1720 1719 f, d = complete(spec, acceptable or 'nmar')
1721 1720 files.update(f)
1722 1721 dirs.update(d)
1723 1722 files.update(dirs)
1724 1723 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
1725 1724 ui.write('\n')
1726 1725
1727 1726 @command('debugpeer', [], _('PATH'), norepo=True)
1728 1727 def debugpeer(ui, path):
1729 1728 """establish a connection to a peer repository"""
1730 1729 # Always enable peer request logging. Requires --debug to display
1731 1730 # though.
1732 1731 overrides = {
1733 1732 ('devel', 'debug.peer-request'): True,
1734 1733 }
1735 1734
1736 1735 with ui.configoverride(overrides):
1737 1736 peer = hg.peer(ui, {}, path)
1738 1737
1739 1738 local = peer.local() is not None
1740 1739 canpush = peer.canpush()
1741 1740
1742 1741 ui.write(_('url: %s\n') % peer.url())
1743 1742 ui.write(_('local: %s\n') % (_('yes') if local else _('no')))
1744 1743 ui.write(_('pushable: %s\n') % (_('yes') if canpush else _('no')))
1745 1744
1746 1745 @command('debugpickmergetool',
1747 1746 [('r', 'rev', '', _('check for files in this revision'), _('REV')),
1748 1747 ('', 'changedelete', None, _('emulate merging change and delete')),
1749 1748 ] + cmdutil.walkopts + cmdutil.mergetoolopts,
1750 1749 _('[PATTERN]...'),
1751 1750 inferrepo=True)
1752 1751 def debugpickmergetool(ui, repo, *pats, **opts):
1753 1752 """examine which merge tool is chosen for specified file
1754 1753
1755 1754 As described in :hg:`help merge-tools`, Mercurial examines
1756 1755 configurations below in this order to decide which merge tool is
1757 1756 chosen for specified file.
1758 1757
1759 1758 1. ``--tool`` option
1760 1759 2. ``HGMERGE`` environment variable
1761 1760 3. configurations in ``merge-patterns`` section
1762 1761 4. configuration of ``ui.merge``
1763 1762 5. configurations in ``merge-tools`` section
1764 1763 6. ``hgmerge`` tool (for historical reason only)
1765 1764 7. default tool for fallback (``:merge`` or ``:prompt``)
1766 1765
1767 1766 This command writes out examination result in the style below::
1768 1767
1769 1768 FILE = MERGETOOL
1770 1769
1771 1770 By default, all files known in the first parent context of the
1772 1771 working directory are examined. Use file patterns and/or -I/-X
1773 1772 options to limit target files. -r/--rev is also useful to examine
1774 1773 files in another context without actual updating to it.
1775 1774
1776 1775 With --debug, this command shows warning messages while matching
1777 1776 against ``merge-patterns`` and so on, too. It is recommended to
1778 1777 use this option with explicit file patterns and/or -I/-X options,
1779 1778 because this option increases amount of output per file according
1780 1779 to configurations in hgrc.
1781 1780
1782 1781 With -v/--verbose, this command shows configurations below at
1783 1782 first (only if specified).
1784 1783
1785 1784 - ``--tool`` option
1786 1785 - ``HGMERGE`` environment variable
1787 1786 - configuration of ``ui.merge``
1788 1787
1789 1788 If merge tool is chosen before matching against
1790 1789 ``merge-patterns``, this command can't show any helpful
1791 1790 information, even with --debug. In such case, information above is
1792 1791 useful to know why a merge tool is chosen.
1793 1792 """
1794 1793 opts = pycompat.byteskwargs(opts)
1795 1794 overrides = {}
1796 1795 if opts['tool']:
1797 1796 overrides[('ui', 'forcemerge')] = opts['tool']
1798 1797 ui.note(('with --tool %r\n') % (pycompat.bytestr(opts['tool'])))
1799 1798
1800 1799 with ui.configoverride(overrides, 'debugmergepatterns'):
1801 1800 hgmerge = encoding.environ.get("HGMERGE")
1802 1801 if hgmerge is not None:
1803 1802 ui.note(('with HGMERGE=%r\n') % (pycompat.bytestr(hgmerge)))
1804 1803 uimerge = ui.config("ui", "merge")
1805 1804 if uimerge:
1806 1805 ui.note(('with ui.merge=%r\n') % (pycompat.bytestr(uimerge)))
1807 1806
1808 1807 ctx = scmutil.revsingle(repo, opts.get('rev'))
1809 1808 m = scmutil.match(ctx, pats, opts)
1810 1809 changedelete = opts['changedelete']
1811 1810 for path in ctx.walk(m):
1812 1811 fctx = ctx[path]
1813 1812 try:
1814 1813 if not ui.debugflag:
1815 1814 ui.pushbuffer(error=True)
1816 1815 tool, toolpath = filemerge._picktool(repo, ui, path,
1817 1816 fctx.isbinary(),
1818 1817 'l' in fctx.flags(),
1819 1818 changedelete)
1820 1819 finally:
1821 1820 if not ui.debugflag:
1822 1821 ui.popbuffer()
1823 1822 ui.write(('%s = %s\n') % (path, tool))
1824 1823
1825 1824 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
1826 1825 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1827 1826 '''access the pushkey key/value protocol
1828 1827
1829 1828 With two args, list the keys in the given namespace.
1830 1829
1831 1830 With five args, set a key to new if it currently is set to old.
1832 1831 Reports success or failure.
1833 1832 '''
1834 1833
1835 1834 target = hg.peer(ui, {}, repopath)
1836 1835 if keyinfo:
1837 1836 key, old, new = keyinfo
1838 1837 with target.commandexecutor() as e:
1839 1838 r = e.callcommand('pushkey', {
1840 1839 'namespace': namespace,
1841 1840 'key': key,
1842 1841 'old': old,
1843 1842 'new': new,
1844 1843 }).result()
1845 1844
1846 1845 ui.status(pycompat.bytestr(r) + '\n')
1847 1846 return not r
1848 1847 else:
1849 1848 for k, v in sorted(target.listkeys(namespace).iteritems()):
1850 1849 ui.write("%s\t%s\n" % (stringutil.escapestr(k),
1851 1850 stringutil.escapestr(v)))
1852 1851
1853 1852 @command('debugpvec', [], _('A B'))
1854 1853 def debugpvec(ui, repo, a, b=None):
1855 1854 ca = scmutil.revsingle(repo, a)
1856 1855 cb = scmutil.revsingle(repo, b)
1857 1856 pa = pvec.ctxpvec(ca)
1858 1857 pb = pvec.ctxpvec(cb)
1859 1858 if pa == pb:
1860 1859 rel = "="
1861 1860 elif pa > pb:
1862 1861 rel = ">"
1863 1862 elif pa < pb:
1864 1863 rel = "<"
1865 1864 elif pa | pb:
1866 1865 rel = "|"
1867 1866 ui.write(_("a: %s\n") % pa)
1868 1867 ui.write(_("b: %s\n") % pb)
1869 1868 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
1870 1869 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
1871 1870 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
1872 1871 pa.distance(pb), rel))
1873 1872
1874 1873 @command('debugrebuilddirstate|debugrebuildstate',
1875 1874 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
1876 1875 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
1877 1876 'the working copy parent')),
1878 1877 ],
1879 1878 _('[-r REV]'))
1880 1879 def debugrebuilddirstate(ui, repo, rev, **opts):
1881 1880 """rebuild the dirstate as it would look like for the given revision
1882 1881
1883 1882 If no revision is specified the first current parent will be used.
1884 1883
1885 1884 The dirstate will be set to the files of the given revision.
1886 1885 The actual working directory content or existing dirstate
1887 1886 information such as adds or removes is not considered.
1888 1887
1889 1888 ``minimal`` will only rebuild the dirstate status for files that claim to be
1890 1889 tracked but are not in the parent manifest, or that exist in the parent
1891 1890 manifest but are not in the dirstate. It will not change adds, removes, or
1892 1891 modified files that are in the working copy parent.
1893 1892
1894 1893 One use of this command is to make the next :hg:`status` invocation
1895 1894 check the actual file content.
1896 1895 """
1897 1896 ctx = scmutil.revsingle(repo, rev)
1898 1897 with repo.wlock():
1899 1898 dirstate = repo.dirstate
1900 1899 changedfiles = None
1901 1900 # See command doc for what minimal does.
1902 1901 if opts.get(r'minimal'):
1903 1902 manifestfiles = set(ctx.manifest().keys())
1904 1903 dirstatefiles = set(dirstate)
1905 1904 manifestonly = manifestfiles - dirstatefiles
1906 1905 dsonly = dirstatefiles - manifestfiles
1907 1906 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
1908 1907 changedfiles = manifestonly | dsnotadded
1909 1908
1910 1909 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
1911 1910
1912 1911 @command('debugrebuildfncache', [], '')
1913 1912 def debugrebuildfncache(ui, repo):
1914 1913 """rebuild the fncache file"""
1915 1914 repair.rebuildfncache(ui, repo)
1916 1915
1917 1916 @command('debugrename',
1918 1917 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1919 1918 _('[-r REV] FILE'))
1920 1919 def debugrename(ui, repo, file1, *pats, **opts):
1921 1920 """dump rename information"""
1922 1921
1923 1922 opts = pycompat.byteskwargs(opts)
1924 1923 ctx = scmutil.revsingle(repo, opts.get('rev'))
1925 1924 m = scmutil.match(ctx, (file1,) + pats, opts)
1926 1925 for abs in ctx.walk(m):
1927 1926 fctx = ctx[abs]
1928 1927 o = fctx.filelog().renamed(fctx.filenode())
1929 1928 rel = m.rel(abs)
1930 1929 if o:
1931 1930 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1932 1931 else:
1933 1932 ui.write(_("%s not renamed\n") % rel)
1934 1933
1935 1934 @command('debugrevlog', cmdutil.debugrevlogopts +
1936 1935 [('d', 'dump', False, _('dump index data'))],
1937 1936 _('-c|-m|FILE'),
1938 1937 optionalrepo=True)
1939 1938 def debugrevlog(ui, repo, file_=None, **opts):
1940 1939 """show data and statistics about a revlog"""
1941 1940 opts = pycompat.byteskwargs(opts)
1942 1941 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1943 1942
1944 1943 if opts.get("dump"):
1945 1944 numrevs = len(r)
1946 1945 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
1947 1946 " rawsize totalsize compression heads chainlen\n"))
1948 1947 ts = 0
1949 1948 heads = set()
1950 1949
1951 1950 for rev in xrange(numrevs):
1952 1951 dbase = r.deltaparent(rev)
1953 1952 if dbase == -1:
1954 1953 dbase = rev
1955 1954 cbase = r.chainbase(rev)
1956 1955 clen = r.chainlen(rev)
1957 1956 p1, p2 = r.parentrevs(rev)
1958 1957 rs = r.rawsize(rev)
1959 1958 ts = ts + rs
1960 1959 heads -= set(r.parentrevs(rev))
1961 1960 heads.add(rev)
1962 1961 try:
1963 1962 compression = ts / r.end(rev)
1964 1963 except ZeroDivisionError:
1965 1964 compression = 0
1966 1965 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
1967 1966 "%11d %5d %8d\n" %
1968 1967 (rev, p1, p2, r.start(rev), r.end(rev),
1969 1968 r.start(dbase), r.start(cbase),
1970 1969 r.start(p1), r.start(p2),
1971 1970 rs, ts, compression, len(heads), clen))
1972 1971 return 0
1973 1972
1974 1973 v = r.version
1975 1974 format = v & 0xFFFF
1976 1975 flags = []
1977 1976 gdelta = False
1978 1977 if v & revlog.FLAG_INLINE_DATA:
1979 1978 flags.append('inline')
1980 1979 if v & revlog.FLAG_GENERALDELTA:
1981 1980 gdelta = True
1982 1981 flags.append('generaldelta')
1983 1982 if not flags:
1984 1983 flags = ['(none)']
1985 1984
1986 1985 nummerges = 0
1987 1986 numfull = 0
1988 1987 numprev = 0
1989 1988 nump1 = 0
1990 1989 nump2 = 0
1991 1990 numother = 0
1992 1991 nump1prev = 0
1993 1992 nump2prev = 0
1994 1993 chainlengths = []
1995 1994 chainbases = []
1996 1995 chainspans = []
1997 1996
1998 1997 datasize = [None, 0, 0]
1999 1998 fullsize = [None, 0, 0]
2000 1999 deltasize = [None, 0, 0]
2001 2000 chunktypecounts = {}
2002 2001 chunktypesizes = {}
2003 2002
2004 2003 def addsize(size, l):
2005 2004 if l[0] is None or size < l[0]:
2006 2005 l[0] = size
2007 2006 if size > l[1]:
2008 2007 l[1] = size
2009 2008 l[2] += size
2010 2009
2011 2010 numrevs = len(r)
2012 2011 for rev in xrange(numrevs):
2013 2012 p1, p2 = r.parentrevs(rev)
2014 2013 delta = r.deltaparent(rev)
2015 2014 if format > 0:
2016 2015 addsize(r.rawsize(rev), datasize)
2017 2016 if p2 != nullrev:
2018 2017 nummerges += 1
2019 2018 size = r.length(rev)
2020 2019 if delta == nullrev:
2021 2020 chainlengths.append(0)
2022 2021 chainbases.append(r.start(rev))
2023 2022 chainspans.append(size)
2024 2023 numfull += 1
2025 2024 addsize(size, fullsize)
2026 2025 else:
2027 2026 chainlengths.append(chainlengths[delta] + 1)
2028 2027 baseaddr = chainbases[delta]
2029 2028 revaddr = r.start(rev)
2030 2029 chainbases.append(baseaddr)
2031 2030 chainspans.append((revaddr - baseaddr) + size)
2032 2031 addsize(size, deltasize)
2033 2032 if delta == rev - 1:
2034 2033 numprev += 1
2035 2034 if delta == p1:
2036 2035 nump1prev += 1
2037 2036 elif delta == p2:
2038 2037 nump2prev += 1
2039 2038 elif delta == p1:
2040 2039 nump1 += 1
2041 2040 elif delta == p2:
2042 2041 nump2 += 1
2043 2042 elif delta != nullrev:
2044 2043 numother += 1
2045 2044
2046 2045 # Obtain data on the raw chunks in the revlog.
2047 2046 segment = r._getsegmentforrevs(rev, rev)[1]
2048 2047 if segment:
2049 2048 chunktype = bytes(segment[0:1])
2050 2049 else:
2051 2050 chunktype = 'empty'
2052 2051
2053 2052 if chunktype not in chunktypecounts:
2054 2053 chunktypecounts[chunktype] = 0
2055 2054 chunktypesizes[chunktype] = 0
2056 2055
2057 2056 chunktypecounts[chunktype] += 1
2058 2057 chunktypesizes[chunktype] += size
2059 2058
2060 2059 # Adjust size min value for empty cases
2061 2060 for size in (datasize, fullsize, deltasize):
2062 2061 if size[0] is None:
2063 2062 size[0] = 0
2064 2063
2065 2064 numdeltas = numrevs - numfull
2066 2065 numoprev = numprev - nump1prev - nump2prev
2067 2066 totalrawsize = datasize[2]
2068 2067 datasize[2] /= numrevs
2069 2068 fulltotal = fullsize[2]
2070 2069 fullsize[2] /= numfull
2071 2070 deltatotal = deltasize[2]
2072 2071 if numrevs - numfull > 0:
2073 2072 deltasize[2] /= numrevs - numfull
2074 2073 totalsize = fulltotal + deltatotal
2075 2074 avgchainlen = sum(chainlengths) / numrevs
2076 2075 maxchainlen = max(chainlengths)
2077 2076 maxchainspan = max(chainspans)
2078 2077 compratio = 1
2079 2078 if totalsize:
2080 2079 compratio = totalrawsize / totalsize
2081 2080
2082 2081 basedfmtstr = '%%%dd\n'
2083 2082 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2084 2083
2085 2084 def dfmtstr(max):
2086 2085 return basedfmtstr % len(str(max))
2087 2086 def pcfmtstr(max, padding=0):
2088 2087 return basepcfmtstr % (len(str(max)), ' ' * padding)
2089 2088
2090 2089 def pcfmt(value, total):
2091 2090 if total:
2092 2091 return (value, 100 * float(value) / total)
2093 2092 else:
2094 2093 return value, 100.0
2095 2094
2096 2095 ui.write(('format : %d\n') % format)
2097 2096 ui.write(('flags : %s\n') % ', '.join(flags))
2098 2097
2099 2098 ui.write('\n')
2100 2099 fmt = pcfmtstr(totalsize)
2101 2100 fmt2 = dfmtstr(totalsize)
2102 2101 ui.write(('revisions : ') + fmt2 % numrevs)
2103 2102 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2104 2103 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2105 2104 ui.write(('revisions : ') + fmt2 % numrevs)
2106 2105 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2107 2106 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2108 2107 ui.write(('revision size : ') + fmt2 % totalsize)
2109 2108 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2110 2109 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2111 2110
2112 2111 def fmtchunktype(chunktype):
2113 2112 if chunktype == 'empty':
2114 2113 return ' %s : ' % chunktype
2115 2114 elif chunktype in pycompat.bytestr(string.ascii_letters):
2116 2115 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
2117 2116 else:
2118 2117 return ' 0x%s : ' % hex(chunktype)
2119 2118
2120 2119 ui.write('\n')
2121 2120 ui.write(('chunks : ') + fmt2 % numrevs)
2122 2121 for chunktype in sorted(chunktypecounts):
2123 2122 ui.write(fmtchunktype(chunktype))
2124 2123 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
2125 2124 ui.write(('chunks size : ') + fmt2 % totalsize)
2126 2125 for chunktype in sorted(chunktypecounts):
2127 2126 ui.write(fmtchunktype(chunktype))
2128 2127 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
2129 2128
2130 2129 ui.write('\n')
2131 2130 fmt = dfmtstr(max(avgchainlen, maxchainlen, maxchainspan, compratio))
2132 2131 ui.write(('avg chain length : ') + fmt % avgchainlen)
2133 2132 ui.write(('max chain length : ') + fmt % maxchainlen)
2134 2133 ui.write(('max chain reach : ') + fmt % maxchainspan)
2135 2134 ui.write(('compression ratio : ') + fmt % compratio)
2136 2135
2137 2136 if format > 0:
2138 2137 ui.write('\n')
2139 2138 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2140 2139 % tuple(datasize))
2141 2140 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2142 2141 % tuple(fullsize))
2143 2142 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2144 2143 % tuple(deltasize))
2145 2144
2146 2145 if numdeltas > 0:
2147 2146 ui.write('\n')
2148 2147 fmt = pcfmtstr(numdeltas)
2149 2148 fmt2 = pcfmtstr(numdeltas, 4)
2150 2149 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2151 2150 if numprev > 0:
2152 2151 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2153 2152 numprev))
2154 2153 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2155 2154 numprev))
2156 2155 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2157 2156 numprev))
2158 2157 if gdelta:
2159 2158 ui.write(('deltas against p1 : ')
2160 2159 + fmt % pcfmt(nump1, numdeltas))
2161 2160 ui.write(('deltas against p2 : ')
2162 2161 + fmt % pcfmt(nump2, numdeltas))
2163 2162 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2164 2163 numdeltas))
2165 2164
2166 2165 @command('debugrevspec',
2167 2166 [('', 'optimize', None,
2168 2167 _('print parsed tree after optimizing (DEPRECATED)')),
2169 2168 ('', 'show-revs', True, _('print list of result revisions (default)')),
2170 2169 ('s', 'show-set', None, _('print internal representation of result set')),
2171 2170 ('p', 'show-stage', [],
2172 2171 _('print parsed tree at the given stage'), _('NAME')),
2173 2172 ('', 'no-optimized', False, _('evaluate tree without optimization')),
2174 2173 ('', 'verify-optimized', False, _('verify optimized result')),
2175 2174 ],
2176 2175 ('REVSPEC'))
2177 2176 def debugrevspec(ui, repo, expr, **opts):
2178 2177 """parse and apply a revision specification
2179 2178
2180 2179 Use -p/--show-stage option to print the parsed tree at the given stages.
2181 2180 Use -p all to print tree at every stage.
2182 2181
2183 2182 Use --no-show-revs option with -s or -p to print only the set
2184 2183 representation or the parsed tree respectively.
2185 2184
2186 2185 Use --verify-optimized to compare the optimized result with the unoptimized
2187 2186 one. Returns 1 if the optimized result differs.
2188 2187 """
2189 2188 opts = pycompat.byteskwargs(opts)
2190 2189 aliases = ui.configitems('revsetalias')
2191 2190 stages = [
2192 2191 ('parsed', lambda tree: tree),
2193 2192 ('expanded', lambda tree: revsetlang.expandaliases(tree, aliases,
2194 2193 ui.warn)),
2195 2194 ('concatenated', revsetlang.foldconcat),
2196 2195 ('analyzed', revsetlang.analyze),
2197 2196 ('optimized', revsetlang.optimize),
2198 2197 ]
2199 2198 if opts['no_optimized']:
2200 2199 stages = stages[:-1]
2201 2200 if opts['verify_optimized'] and opts['no_optimized']:
2202 2201 raise error.Abort(_('cannot use --verify-optimized with '
2203 2202 '--no-optimized'))
2204 2203 stagenames = set(n for n, f in stages)
2205 2204
2206 2205 showalways = set()
2207 2206 showchanged = set()
2208 2207 if ui.verbose and not opts['show_stage']:
2209 2208 # show parsed tree by --verbose (deprecated)
2210 2209 showalways.add('parsed')
2211 2210 showchanged.update(['expanded', 'concatenated'])
2212 2211 if opts['optimize']:
2213 2212 showalways.add('optimized')
2214 2213 if opts['show_stage'] and opts['optimize']:
2215 2214 raise error.Abort(_('cannot use --optimize with --show-stage'))
2216 2215 if opts['show_stage'] == ['all']:
2217 2216 showalways.update(stagenames)
2218 2217 else:
2219 2218 for n in opts['show_stage']:
2220 2219 if n not in stagenames:
2221 2220 raise error.Abort(_('invalid stage name: %s') % n)
2222 2221 showalways.update(opts['show_stage'])
2223 2222
2224 2223 treebystage = {}
2225 2224 printedtree = None
2226 2225 tree = revsetlang.parse(expr, lookup=revset.lookupfn(repo))
2227 2226 for n, f in stages:
2228 2227 treebystage[n] = tree = f(tree)
2229 2228 if n in showalways or (n in showchanged and tree != printedtree):
2230 2229 if opts['show_stage'] or n != 'parsed':
2231 2230 ui.write(("* %s:\n") % n)
2232 2231 ui.write(revsetlang.prettyformat(tree), "\n")
2233 2232 printedtree = tree
2234 2233
2235 2234 if opts['verify_optimized']:
2236 2235 arevs = revset.makematcher(treebystage['analyzed'])(repo)
2237 2236 brevs = revset.makematcher(treebystage['optimized'])(repo)
2238 2237 if opts['show_set'] or (opts['show_set'] is None and ui.verbose):
2239 ui.write(("* analyzed set:\n"), smartset.prettyformat(arevs), "\n")
2240 ui.write(("* optimized set:\n"), smartset.prettyformat(brevs), "\n")
2238 ui.write(("* analyzed set:\n"), stringutil.prettyrepr(arevs), "\n")
2239 ui.write(("* optimized set:\n"), stringutil.prettyrepr(brevs), "\n")
2241 2240 arevs = list(arevs)
2242 2241 brevs = list(brevs)
2243 2242 if arevs == brevs:
2244 2243 return 0
2245 2244 ui.write(('--- analyzed\n'), label='diff.file_a')
2246 2245 ui.write(('+++ optimized\n'), label='diff.file_b')
2247 2246 sm = difflib.SequenceMatcher(None, arevs, brevs)
2248 2247 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2249 2248 if tag in ('delete', 'replace'):
2250 2249 for c in arevs[alo:ahi]:
2251 2250 ui.write('-%s\n' % c, label='diff.deleted')
2252 2251 if tag in ('insert', 'replace'):
2253 2252 for c in brevs[blo:bhi]:
2254 2253 ui.write('+%s\n' % c, label='diff.inserted')
2255 2254 if tag == 'equal':
2256 2255 for c in arevs[alo:ahi]:
2257 2256 ui.write(' %s\n' % c)
2258 2257 return 1
2259 2258
2260 2259 func = revset.makematcher(tree)
2261 2260 revs = func(repo)
2262 2261 if opts['show_set'] or (opts['show_set'] is None and ui.verbose):
2263 ui.write(("* set:\n"), smartset.prettyformat(revs), "\n")
2262 ui.write(("* set:\n"), stringutil.prettyrepr(revs), "\n")
2264 2263 if not opts['show_revs']:
2265 2264 return
2266 2265 for c in revs:
2267 2266 ui.write("%d\n" % c)
2268 2267
2269 2268 @command('debugserve', [
2270 2269 ('', 'sshstdio', False, _('run an SSH server bound to process handles')),
2271 2270 ('', 'logiofd', '', _('file descriptor to log server I/O to')),
2272 2271 ('', 'logiofile', '', _('file to log server I/O to')),
2273 2272 ], '')
2274 2273 def debugserve(ui, repo, **opts):
2275 2274 """run a server with advanced settings
2276 2275
2277 2276 This command is similar to :hg:`serve`. It exists partially as a
2278 2277 workaround to the fact that ``hg serve --stdio`` must have specific
2279 2278 arguments for security reasons.
2280 2279 """
2281 2280 opts = pycompat.byteskwargs(opts)
2282 2281
2283 2282 if not opts['sshstdio']:
2284 2283 raise error.Abort(_('only --sshstdio is currently supported'))
2285 2284
2286 2285 logfh = None
2287 2286
2288 2287 if opts['logiofd'] and opts['logiofile']:
2289 2288 raise error.Abort(_('cannot use both --logiofd and --logiofile'))
2290 2289
2291 2290 if opts['logiofd']:
2292 2291 # Line buffered because output is line based.
2293 2292 logfh = os.fdopen(int(opts['logiofd']), r'ab', 1)
2294 2293 elif opts['logiofile']:
2295 2294 logfh = open(opts['logiofile'], 'ab', 1)
2296 2295
2297 2296 s = wireprotoserver.sshserver(ui, repo, logfh=logfh)
2298 2297 s.serve_forever()
2299 2298
2300 2299 @command('debugsetparents', [], _('REV1 [REV2]'))
2301 2300 def debugsetparents(ui, repo, rev1, rev2=None):
2302 2301 """manually set the parents of the current working directory
2303 2302
2304 2303 This is useful for writing repository conversion tools, but should
2305 2304 be used with care. For example, neither the working directory nor the
2306 2305 dirstate is updated, so file status may be incorrect after running this
2307 2306 command.
2308 2307
2309 2308 Returns 0 on success.
2310 2309 """
2311 2310
2312 2311 node1 = scmutil.revsingle(repo, rev1).node()
2313 2312 node2 = scmutil.revsingle(repo, rev2, 'null').node()
2314 2313
2315 2314 with repo.wlock():
2316 2315 repo.setparents(node1, node2)
2317 2316
2318 2317 @command('debugssl', [], '[SOURCE]', optionalrepo=True)
2319 2318 def debugssl(ui, repo, source=None, **opts):
2320 2319 '''test a secure connection to a server
2321 2320
2322 2321 This builds the certificate chain for the server on Windows, installing the
2323 2322 missing intermediates and trusted root via Windows Update if necessary. It
2324 2323 does nothing on other platforms.
2325 2324
2326 2325 If SOURCE is omitted, the 'default' path will be used. If a URL is given,
2327 2326 that server is used. See :hg:`help urls` for more information.
2328 2327
2329 2328 If the update succeeds, retry the original operation. Otherwise, the cause
2330 2329 of the SSL error is likely another issue.
2331 2330 '''
2332 2331 if not pycompat.iswindows:
2333 2332 raise error.Abort(_('certificate chain building is only possible on '
2334 2333 'Windows'))
2335 2334
2336 2335 if not source:
2337 2336 if not repo:
2338 2337 raise error.Abort(_("there is no Mercurial repository here, and no "
2339 2338 "server specified"))
2340 2339 source = "default"
2341 2340
2342 2341 source, branches = hg.parseurl(ui.expandpath(source))
2343 2342 url = util.url(source)
2344 2343 addr = None
2345 2344
2346 2345 defaultport = {'https': 443, 'ssh': 22}
2347 2346 if url.scheme in defaultport:
2348 2347 try:
2349 2348 addr = (url.host, int(url.port or defaultport[url.scheme]))
2350 2349 except ValueError:
2351 2350 raise error.Abort(_("malformed port number in URL"))
2352 2351 else:
2353 2352 raise error.Abort(_("only https and ssh connections are supported"))
2354 2353
2355 2354 from . import win32
2356 2355
2357 2356 s = ssl.wrap_socket(socket.socket(), ssl_version=ssl.PROTOCOL_TLS,
2358 2357 cert_reqs=ssl.CERT_NONE, ca_certs=None)
2359 2358
2360 2359 try:
2361 2360 s.connect(addr)
2362 2361 cert = s.getpeercert(True)
2363 2362
2364 2363 ui.status(_('checking the certificate chain for %s\n') % url.host)
2365 2364
2366 2365 complete = win32.checkcertificatechain(cert, build=False)
2367 2366
2368 2367 if not complete:
2369 2368 ui.status(_('certificate chain is incomplete, updating... '))
2370 2369
2371 2370 if not win32.checkcertificatechain(cert):
2372 2371 ui.status(_('failed.\n'))
2373 2372 else:
2374 2373 ui.status(_('done.\n'))
2375 2374 else:
2376 2375 ui.status(_('full certificate chain is available\n'))
2377 2376 finally:
2378 2377 s.close()
2379 2378
2380 2379 @command('debugsub',
2381 2380 [('r', 'rev', '',
2382 2381 _('revision to check'), _('REV'))],
2383 2382 _('[-r REV] [REV]'))
2384 2383 def debugsub(ui, repo, rev=None):
2385 2384 ctx = scmutil.revsingle(repo, rev, None)
2386 2385 for k, v in sorted(ctx.substate.items()):
2387 2386 ui.write(('path %s\n') % k)
2388 2387 ui.write((' source %s\n') % v[0])
2389 2388 ui.write((' revision %s\n') % v[1])
2390 2389
2391 2390 @command('debugsuccessorssets',
2392 2391 [('', 'closest', False, _('return closest successors sets only'))],
2393 2392 _('[REV]'))
2394 2393 def debugsuccessorssets(ui, repo, *revs, **opts):
2395 2394 """show set of successors for revision
2396 2395
2397 2396 A successors set of changeset A is a consistent group of revisions that
2398 2397 succeed A. It contains non-obsolete changesets only unless closests
2399 2398 successors set is set.
2400 2399
2401 2400 In most cases a changeset A has a single successors set containing a single
2402 2401 successor (changeset A replaced by A').
2403 2402
2404 2403 A changeset that is made obsolete with no successors are called "pruned".
2405 2404 Such changesets have no successors sets at all.
2406 2405
2407 2406 A changeset that has been "split" will have a successors set containing
2408 2407 more than one successor.
2409 2408
2410 2409 A changeset that has been rewritten in multiple different ways is called
2411 2410 "divergent". Such changesets have multiple successor sets (each of which
2412 2411 may also be split, i.e. have multiple successors).
2413 2412
2414 2413 Results are displayed as follows::
2415 2414
2416 2415 <rev1>
2417 2416 <successors-1A>
2418 2417 <rev2>
2419 2418 <successors-2A>
2420 2419 <successors-2B1> <successors-2B2> <successors-2B3>
2421 2420
2422 2421 Here rev2 has two possible (i.e. divergent) successors sets. The first
2423 2422 holds one element, whereas the second holds three (i.e. the changeset has
2424 2423 been split).
2425 2424 """
2426 2425 # passed to successorssets caching computation from one call to another
2427 2426 cache = {}
2428 2427 ctx2str = bytes
2429 2428 node2str = short
2430 2429 for rev in scmutil.revrange(repo, revs):
2431 2430 ctx = repo[rev]
2432 2431 ui.write('%s\n'% ctx2str(ctx))
2433 2432 for succsset in obsutil.successorssets(repo, ctx.node(),
2434 2433 closest=opts[r'closest'],
2435 2434 cache=cache):
2436 2435 if succsset:
2437 2436 ui.write(' ')
2438 2437 ui.write(node2str(succsset[0]))
2439 2438 for node in succsset[1:]:
2440 2439 ui.write(' ')
2441 2440 ui.write(node2str(node))
2442 2441 ui.write('\n')
2443 2442
2444 2443 @command('debugtemplate',
2445 2444 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
2446 2445 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
2447 2446 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
2448 2447 optionalrepo=True)
2449 2448 def debugtemplate(ui, repo, tmpl, **opts):
2450 2449 """parse and apply a template
2451 2450
2452 2451 If -r/--rev is given, the template is processed as a log template and
2453 2452 applied to the given changesets. Otherwise, it is processed as a generic
2454 2453 template.
2455 2454
2456 2455 Use --verbose to print the parsed tree.
2457 2456 """
2458 2457 revs = None
2459 2458 if opts[r'rev']:
2460 2459 if repo is None:
2461 2460 raise error.RepoError(_('there is no Mercurial repository here '
2462 2461 '(.hg not found)'))
2463 2462 revs = scmutil.revrange(repo, opts[r'rev'])
2464 2463
2465 2464 props = {}
2466 2465 for d in opts[r'define']:
2467 2466 try:
2468 2467 k, v = (e.strip() for e in d.split('=', 1))
2469 2468 if not k or k == 'ui':
2470 2469 raise ValueError
2471 2470 props[k] = v
2472 2471 except ValueError:
2473 2472 raise error.Abort(_('malformed keyword definition: %s') % d)
2474 2473
2475 2474 if ui.verbose:
2476 2475 aliases = ui.configitems('templatealias')
2477 2476 tree = templater.parse(tmpl)
2478 2477 ui.note(templater.prettyformat(tree), '\n')
2479 2478 newtree = templater.expandaliases(tree, aliases)
2480 2479 if newtree != tree:
2481 2480 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
2482 2481
2483 2482 if revs is None:
2484 2483 tres = formatter.templateresources(ui, repo)
2485 2484 t = formatter.maketemplater(ui, tmpl, resources=tres)
2486 2485 ui.write(t.renderdefault(props))
2487 2486 else:
2488 2487 displayer = logcmdutil.maketemplater(ui, repo, tmpl)
2489 2488 for r in revs:
2490 2489 displayer.show(repo[r], **pycompat.strkwargs(props))
2491 2490 displayer.close()
2492 2491
2493 2492 @command('debuguigetpass', [
2494 2493 ('p', 'prompt', '', _('prompt text'), _('TEXT')),
2495 2494 ], _('[-p TEXT]'), norepo=True)
2496 2495 def debuguigetpass(ui, prompt=''):
2497 2496 """show prompt to type password"""
2498 2497 r = ui.getpass(prompt)
2499 2498 ui.write(('respose: %s\n') % r)
2500 2499
2501 2500 @command('debuguiprompt', [
2502 2501 ('p', 'prompt', '', _('prompt text'), _('TEXT')),
2503 2502 ], _('[-p TEXT]'), norepo=True)
2504 2503 def debuguiprompt(ui, prompt=''):
2505 2504 """show plain prompt"""
2506 2505 r = ui.prompt(prompt)
2507 2506 ui.write(('response: %s\n') % r)
2508 2507
2509 2508 @command('debugupdatecaches', [])
2510 2509 def debugupdatecaches(ui, repo, *pats, **opts):
2511 2510 """warm all known caches in the repository"""
2512 2511 with repo.wlock(), repo.lock():
2513 2512 repo.updatecaches(full=True)
2514 2513
2515 2514 @command('debugupgraderepo', [
2516 2515 ('o', 'optimize', [], _('extra optimization to perform'), _('NAME')),
2517 2516 ('', 'run', False, _('performs an upgrade')),
2518 2517 ])
2519 2518 def debugupgraderepo(ui, repo, run=False, optimize=None):
2520 2519 """upgrade a repository to use different features
2521 2520
2522 2521 If no arguments are specified, the repository is evaluated for upgrade
2523 2522 and a list of problems and potential optimizations is printed.
2524 2523
2525 2524 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
2526 2525 can be influenced via additional arguments. More details will be provided
2527 2526 by the command output when run without ``--run``.
2528 2527
2529 2528 During the upgrade, the repository will be locked and no writes will be
2530 2529 allowed.
2531 2530
2532 2531 At the end of the upgrade, the repository may not be readable while new
2533 2532 repository data is swapped in. This window will be as long as it takes to
2534 2533 rename some directories inside the ``.hg`` directory. On most machines, this
2535 2534 should complete almost instantaneously and the chances of a consumer being
2536 2535 unable to access the repository should be low.
2537 2536 """
2538 2537 return upgrade.upgraderepo(ui, repo, run=run, optimize=optimize)
2539 2538
2540 2539 @command('debugwalk', cmdutil.walkopts, _('[OPTION]... [FILE]...'),
2541 2540 inferrepo=True)
2542 2541 def debugwalk(ui, repo, *pats, **opts):
2543 2542 """show how files match on given patterns"""
2544 2543 opts = pycompat.byteskwargs(opts)
2545 2544 m = scmutil.match(repo[None], pats, opts)
2546 2545 ui.write(('matcher: %r\n' % m))
2547 2546 items = list(repo[None].walk(m))
2548 2547 if not items:
2549 2548 return
2550 2549 f = lambda fn: fn
2551 2550 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
2552 2551 f = lambda fn: util.normpath(fn)
2553 2552 fmt = 'f %%-%ds %%-%ds %%s' % (
2554 2553 max([len(abs) for abs in items]),
2555 2554 max([len(m.rel(abs)) for abs in items]))
2556 2555 for abs in items:
2557 2556 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2558 2557 ui.write("%s\n" % line.rstrip())
2559 2558
2560 2559 @command('debugwhyunstable', [], _('REV'))
2561 2560 def debugwhyunstable(ui, repo, rev):
2562 2561 """explain instabilities of a changeset"""
2563 2562 for entry in obsutil.whyunstable(repo, scmutil.revsingle(repo, rev)):
2564 2563 dnodes = ''
2565 2564 if entry.get('divergentnodes'):
2566 2565 dnodes = ' '.join('%s (%s)' % (ctx.hex(), ctx.phasestr())
2567 2566 for ctx in entry['divergentnodes']) + ' '
2568 2567 ui.write('%s: %s%s %s\n' % (entry['instability'], dnodes,
2569 2568 entry['reason'], entry['node']))
2570 2569
2571 2570 @command('debugwireargs',
2572 2571 [('', 'three', '', 'three'),
2573 2572 ('', 'four', '', 'four'),
2574 2573 ('', 'five', '', 'five'),
2575 2574 ] + cmdutil.remoteopts,
2576 2575 _('REPO [OPTIONS]... [ONE [TWO]]'),
2577 2576 norepo=True)
2578 2577 def debugwireargs(ui, repopath, *vals, **opts):
2579 2578 opts = pycompat.byteskwargs(opts)
2580 2579 repo = hg.peer(ui, opts, repopath)
2581 2580 for opt in cmdutil.remoteopts:
2582 2581 del opts[opt[1]]
2583 2582 args = {}
2584 2583 for k, v in opts.iteritems():
2585 2584 if v:
2586 2585 args[k] = v
2587 2586 args = pycompat.strkwargs(args)
2588 2587 # run twice to check that we don't mess up the stream for the next command
2589 2588 res1 = repo.debugwireargs(*vals, **args)
2590 2589 res2 = repo.debugwireargs(*vals, **args)
2591 2590 ui.write("%s\n" % res1)
2592 2591 if res1 != res2:
2593 2592 ui.warn("%s\n" % res2)
2594 2593
2595 2594 def _parsewirelangblocks(fh):
2596 2595 activeaction = None
2597 2596 blocklines = []
2598 2597
2599 2598 for line in fh:
2600 2599 line = line.rstrip()
2601 2600 if not line:
2602 2601 continue
2603 2602
2604 2603 if line.startswith(b'#'):
2605 2604 continue
2606 2605
2607 2606 if not line.startswith(' '):
2608 2607 # New block. Flush previous one.
2609 2608 if activeaction:
2610 2609 yield activeaction, blocklines
2611 2610
2612 2611 activeaction = line
2613 2612 blocklines = []
2614 2613 continue
2615 2614
2616 2615 # Else we start with an indent.
2617 2616
2618 2617 if not activeaction:
2619 2618 raise error.Abort(_('indented line outside of block'))
2620 2619
2621 2620 blocklines.append(line)
2622 2621
2623 2622 # Flush last block.
2624 2623 if activeaction:
2625 2624 yield activeaction, blocklines
2626 2625
2627 2626 @command('debugwireproto',
2628 2627 [
2629 2628 ('', 'localssh', False, _('start an SSH server for this repo')),
2630 2629 ('', 'peer', '', _('construct a specific version of the peer')),
2631 2630 ('', 'noreadstderr', False, _('do not read from stderr of the remote')),
2632 2631 ('', 'nologhandshake', False,
2633 2632 _('do not log I/O related to the peer handshake')),
2634 2633 ] + cmdutil.remoteopts,
2635 2634 _('[PATH]'),
2636 2635 optionalrepo=True)
2637 2636 def debugwireproto(ui, repo, path=None, **opts):
2638 2637 """send wire protocol commands to a server
2639 2638
2640 2639 This command can be used to issue wire protocol commands to remote
2641 2640 peers and to debug the raw data being exchanged.
2642 2641
2643 2642 ``--localssh`` will start an SSH server against the current repository
2644 2643 and connect to that. By default, the connection will perform a handshake
2645 2644 and establish an appropriate peer instance.
2646 2645
2647 2646 ``--peer`` can be used to bypass the handshake protocol and construct a
2648 2647 peer instance using the specified class type. Valid values are ``raw``,
2649 2648 ``http2``, ``ssh1``, and ``ssh2``. ``raw`` instances only allow sending
2650 2649 raw data payloads and don't support higher-level command actions.
2651 2650
2652 2651 ``--noreadstderr`` can be used to disable automatic reading from stderr
2653 2652 of the peer (for SSH connections only). Disabling automatic reading of
2654 2653 stderr is useful for making output more deterministic.
2655 2654
2656 2655 Commands are issued via a mini language which is specified via stdin.
2657 2656 The language consists of individual actions to perform. An action is
2658 2657 defined by a block. A block is defined as a line with no leading
2659 2658 space followed by 0 or more lines with leading space. Blocks are
2660 2659 effectively a high-level command with additional metadata.
2661 2660
2662 2661 Lines beginning with ``#`` are ignored.
2663 2662
2664 2663 The following sections denote available actions.
2665 2664
2666 2665 raw
2667 2666 ---
2668 2667
2669 2668 Send raw data to the server.
2670 2669
2671 2670 The block payload contains the raw data to send as one atomic send
2672 2671 operation. The data may not actually be delivered in a single system
2673 2672 call: it depends on the abilities of the transport being used.
2674 2673
2675 2674 Each line in the block is de-indented and concatenated. Then, that
2676 2675 value is evaluated as a Python b'' literal. This allows the use of
2677 2676 backslash escaping, etc.
2678 2677
2679 2678 raw+
2680 2679 ----
2681 2680
2682 2681 Behaves like ``raw`` except flushes output afterwards.
2683 2682
2684 2683 command <X>
2685 2684 -----------
2686 2685
2687 2686 Send a request to run a named command, whose name follows the ``command``
2688 2687 string.
2689 2688
2690 2689 Arguments to the command are defined as lines in this block. The format of
2691 2690 each line is ``<key> <value>``. e.g.::
2692 2691
2693 2692 command listkeys
2694 2693 namespace bookmarks
2695 2694
2696 2695 If the value begins with ``eval:``, it will be interpreted as a Python
2697 2696 literal expression. Otherwise values are interpreted as Python b'' literals.
2698 2697 This allows sending complex types and encoding special byte sequences via
2699 2698 backslash escaping.
2700 2699
2701 2700 The following arguments have special meaning:
2702 2701
2703 2702 ``PUSHFILE``
2704 2703 When defined, the *push* mechanism of the peer will be used instead
2705 2704 of the static request-response mechanism and the content of the
2706 2705 file specified in the value of this argument will be sent as the
2707 2706 command payload.
2708 2707
2709 2708 This can be used to submit a local bundle file to the remote.
2710 2709
2711 2710 batchbegin
2712 2711 ----------
2713 2712
2714 2713 Instruct the peer to begin a batched send.
2715 2714
2716 2715 All ``command`` blocks are queued for execution until the next
2717 2716 ``batchsubmit`` block.
2718 2717
2719 2718 batchsubmit
2720 2719 -----------
2721 2720
2722 2721 Submit previously queued ``command`` blocks as a batch request.
2723 2722
2724 2723 This action MUST be paired with a ``batchbegin`` action.
2725 2724
2726 2725 httprequest <method> <path>
2727 2726 ---------------------------
2728 2727
2729 2728 (HTTP peer only)
2730 2729
2731 2730 Send an HTTP request to the peer.
2732 2731
2733 2732 The HTTP request line follows the ``httprequest`` action. e.g. ``GET /foo``.
2734 2733
2735 2734 Arguments of the form ``<key>: <value>`` are interpreted as HTTP request
2736 2735 headers to add to the request. e.g. ``Accept: foo``.
2737 2736
2738 2737 The following arguments are special:
2739 2738
2740 2739 ``BODYFILE``
2741 2740 The content of the file defined as the value to this argument will be
2742 2741 transferred verbatim as the HTTP request body.
2743 2742
2744 2743 ``frame <type> <flags> <payload>``
2745 2744 Send a unified protocol frame as part of the request body.
2746 2745
2747 2746 All frames will be collected and sent as the body to the HTTP
2748 2747 request.
2749 2748
2750 2749 close
2751 2750 -----
2752 2751
2753 2752 Close the connection to the server.
2754 2753
2755 2754 flush
2756 2755 -----
2757 2756
2758 2757 Flush data written to the server.
2759 2758
2760 2759 readavailable
2761 2760 -------------
2762 2761
2763 2762 Close the write end of the connection and read all available data from
2764 2763 the server.
2765 2764
2766 2765 If the connection to the server encompasses multiple pipes, we poll both
2767 2766 pipes and read available data.
2768 2767
2769 2768 readline
2770 2769 --------
2771 2770
2772 2771 Read a line of output from the server. If there are multiple output
2773 2772 pipes, reads only the main pipe.
2774 2773
2775 2774 ereadline
2776 2775 ---------
2777 2776
2778 2777 Like ``readline``, but read from the stderr pipe, if available.
2779 2778
2780 2779 read <X>
2781 2780 --------
2782 2781
2783 2782 ``read()`` N bytes from the server's main output pipe.
2784 2783
2785 2784 eread <X>
2786 2785 ---------
2787 2786
2788 2787 ``read()`` N bytes from the server's stderr pipe, if available.
2789 2788
2790 2789 Specifying Unified Frame-Based Protocol Frames
2791 2790 ----------------------------------------------
2792 2791
2793 2792 It is possible to emit a *Unified Frame-Based Protocol* by using special
2794 2793 syntax.
2795 2794
2796 2795 A frame is composed as a type, flags, and payload. These can be parsed
2797 2796 from a string of the form:
2798 2797
2799 2798 <request-id> <stream-id> <stream-flags> <type> <flags> <payload>
2800 2799
2801 2800 ``request-id`` and ``stream-id`` are integers defining the request and
2802 2801 stream identifiers.
2803 2802
2804 2803 ``type`` can be an integer value for the frame type or the string name
2805 2804 of the type. The strings are defined in ``wireprotoframing.py``. e.g.
2806 2805 ``command-name``.
2807 2806
2808 2807 ``stream-flags`` and ``flags`` are a ``|`` delimited list of flag
2809 2808 components. Each component (and there can be just one) can be an integer
2810 2809 or a flag name for stream flags or frame flags, respectively. Values are
2811 2810 resolved to integers and then bitwise OR'd together.
2812 2811
2813 2812 ``payload`` represents the raw frame payload. If it begins with
2814 2813 ``cbor:``, the following string is evaluated as Python code and the
2815 2814 resulting object is fed into a CBOR encoder. Otherwise it is interpreted
2816 2815 as a Python byte string literal.
2817 2816 """
2818 2817 opts = pycompat.byteskwargs(opts)
2819 2818
2820 2819 if opts['localssh'] and not repo:
2821 2820 raise error.Abort(_('--localssh requires a repository'))
2822 2821
2823 2822 if opts['peer'] and opts['peer'] not in ('raw', 'http2', 'ssh1', 'ssh2'):
2824 2823 raise error.Abort(_('invalid value for --peer'),
2825 2824 hint=_('valid values are "raw", "ssh1", and "ssh2"'))
2826 2825
2827 2826 if path and opts['localssh']:
2828 2827 raise error.Abort(_('cannot specify --localssh with an explicit '
2829 2828 'path'))
2830 2829
2831 2830 if ui.interactive():
2832 2831 ui.write(_('(waiting for commands on stdin)\n'))
2833 2832
2834 2833 blocks = list(_parsewirelangblocks(ui.fin))
2835 2834
2836 2835 proc = None
2837 2836 stdin = None
2838 2837 stdout = None
2839 2838 stderr = None
2840 2839 opener = None
2841 2840
2842 2841 if opts['localssh']:
2843 2842 # We start the SSH server in its own process so there is process
2844 2843 # separation. This prevents a whole class of potential bugs around
2845 2844 # shared state from interfering with server operation.
2846 2845 args = procutil.hgcmd() + [
2847 2846 '-R', repo.root,
2848 2847 'debugserve', '--sshstdio',
2849 2848 ]
2850 2849 proc = subprocess.Popen(args, stdin=subprocess.PIPE,
2851 2850 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
2852 2851 bufsize=0)
2853 2852
2854 2853 stdin = proc.stdin
2855 2854 stdout = proc.stdout
2856 2855 stderr = proc.stderr
2857 2856
2858 2857 # We turn the pipes into observers so we can log I/O.
2859 2858 if ui.verbose or opts['peer'] == 'raw':
2860 2859 stdin = util.makeloggingfileobject(ui, proc.stdin, b'i',
2861 2860 logdata=True)
2862 2861 stdout = util.makeloggingfileobject(ui, proc.stdout, b'o',
2863 2862 logdata=True)
2864 2863 stderr = util.makeloggingfileobject(ui, proc.stderr, b'e',
2865 2864 logdata=True)
2866 2865
2867 2866 # --localssh also implies the peer connection settings.
2868 2867
2869 2868 url = 'ssh://localserver'
2870 2869 autoreadstderr = not opts['noreadstderr']
2871 2870
2872 2871 if opts['peer'] == 'ssh1':
2873 2872 ui.write(_('creating ssh peer for wire protocol version 1\n'))
2874 2873 peer = sshpeer.sshv1peer(ui, url, proc, stdin, stdout, stderr,
2875 2874 None, autoreadstderr=autoreadstderr)
2876 2875 elif opts['peer'] == 'ssh2':
2877 2876 ui.write(_('creating ssh peer for wire protocol version 2\n'))
2878 2877 peer = sshpeer.sshv2peer(ui, url, proc, stdin, stdout, stderr,
2879 2878 None, autoreadstderr=autoreadstderr)
2880 2879 elif opts['peer'] == 'raw':
2881 2880 ui.write(_('using raw connection to peer\n'))
2882 2881 peer = None
2883 2882 else:
2884 2883 ui.write(_('creating ssh peer from handshake results\n'))
2885 2884 peer = sshpeer.makepeer(ui, url, proc, stdin, stdout, stderr,
2886 2885 autoreadstderr=autoreadstderr)
2887 2886
2888 2887 elif path:
2889 2888 # We bypass hg.peer() so we can proxy the sockets.
2890 2889 # TODO consider not doing this because we skip
2891 2890 # ``hg.wirepeersetupfuncs`` and potentially other useful functionality.
2892 2891 u = util.url(path)
2893 2892 if u.scheme != 'http':
2894 2893 raise error.Abort(_('only http:// paths are currently supported'))
2895 2894
2896 2895 url, authinfo = u.authinfo()
2897 2896 openerargs = {
2898 2897 r'useragent': b'Mercurial debugwireproto',
2899 2898 }
2900 2899
2901 2900 # Turn pipes/sockets into observers so we can log I/O.
2902 2901 if ui.verbose:
2903 2902 openerargs.update({
2904 2903 r'loggingfh': ui,
2905 2904 r'loggingname': b's',
2906 2905 r'loggingopts': {
2907 2906 r'logdata': True,
2908 2907 r'logdataapis': False,
2909 2908 },
2910 2909 })
2911 2910
2912 2911 if ui.debugflag:
2913 2912 openerargs[r'loggingopts'][r'logdataapis'] = True
2914 2913
2915 2914 # Don't send default headers when in raw mode. This allows us to
2916 2915 # bypass most of the behavior of our URL handling code so we can
2917 2916 # have near complete control over what's sent on the wire.
2918 2917 if opts['peer'] == 'raw':
2919 2918 openerargs[r'sendaccept'] = False
2920 2919
2921 2920 opener = urlmod.opener(ui, authinfo, **openerargs)
2922 2921
2923 2922 if opts['peer'] == 'http2':
2924 2923 ui.write(_('creating http peer for wire protocol version 2\n'))
2925 2924 # We go through makepeer() because we need an API descriptor for
2926 2925 # the peer instance to be useful.
2927 2926 with ui.configoverride({
2928 2927 ('experimental', 'httppeer.advertise-v2'): True}):
2929 2928 if opts['nologhandshake']:
2930 2929 ui.pushbuffer()
2931 2930
2932 2931 peer = httppeer.makepeer(ui, path, opener=opener)
2933 2932
2934 2933 if opts['nologhandshake']:
2935 2934 ui.popbuffer()
2936 2935
2937 2936 if not isinstance(peer, httppeer.httpv2peer):
2938 2937 raise error.Abort(_('could not instantiate HTTP peer for '
2939 2938 'wire protocol version 2'),
2940 2939 hint=_('the server may not have the feature '
2941 2940 'enabled or is not allowing this '
2942 2941 'client version'))
2943 2942
2944 2943 elif opts['peer'] == 'raw':
2945 2944 ui.write(_('using raw connection to peer\n'))
2946 2945 peer = None
2947 2946 elif opts['peer']:
2948 2947 raise error.Abort(_('--peer %s not supported with HTTP peers') %
2949 2948 opts['peer'])
2950 2949 else:
2951 2950 peer = httppeer.makepeer(ui, path, opener=opener)
2952 2951
2953 2952 # We /could/ populate stdin/stdout with sock.makefile()...
2954 2953 else:
2955 2954 raise error.Abort(_('unsupported connection configuration'))
2956 2955
2957 2956 batchedcommands = None
2958 2957
2959 2958 # Now perform actions based on the parsed wire language instructions.
2960 2959 for action, lines in blocks:
2961 2960 if action in ('raw', 'raw+'):
2962 2961 if not stdin:
2963 2962 raise error.Abort(_('cannot call raw/raw+ on this peer'))
2964 2963
2965 2964 # Concatenate the data together.
2966 2965 data = ''.join(l.lstrip() for l in lines)
2967 2966 data = stringutil.unescapestr(data)
2968 2967 stdin.write(data)
2969 2968
2970 2969 if action == 'raw+':
2971 2970 stdin.flush()
2972 2971 elif action == 'flush':
2973 2972 if not stdin:
2974 2973 raise error.Abort(_('cannot call flush on this peer'))
2975 2974 stdin.flush()
2976 2975 elif action.startswith('command'):
2977 2976 if not peer:
2978 2977 raise error.Abort(_('cannot send commands unless peer instance '
2979 2978 'is available'))
2980 2979
2981 2980 command = action.split(' ', 1)[1]
2982 2981
2983 2982 args = {}
2984 2983 for line in lines:
2985 2984 # We need to allow empty values.
2986 2985 fields = line.lstrip().split(' ', 1)
2987 2986 if len(fields) == 1:
2988 2987 key = fields[0]
2989 2988 value = ''
2990 2989 else:
2991 2990 key, value = fields
2992 2991
2993 2992 if value.startswith('eval:'):
2994 2993 value = stringutil.evalpythonliteral(value[5:])
2995 2994 else:
2996 2995 value = stringutil.unescapestr(value)
2997 2996
2998 2997 args[key] = value
2999 2998
3000 2999 if batchedcommands is not None:
3001 3000 batchedcommands.append((command, args))
3002 3001 continue
3003 3002
3004 3003 ui.status(_('sending %s command\n') % command)
3005 3004
3006 3005 if 'PUSHFILE' in args:
3007 3006 with open(args['PUSHFILE'], r'rb') as fh:
3008 3007 del args['PUSHFILE']
3009 3008 res, output = peer._callpush(command, fh,
3010 3009 **pycompat.strkwargs(args))
3011 3010 ui.status(_('result: %s\n') % stringutil.escapestr(res))
3012 3011 ui.status(_('remote output: %s\n') %
3013 3012 stringutil.escapestr(output))
3014 3013 else:
3015 3014 with peer.commandexecutor() as e:
3016 3015 res = e.callcommand(command, args).result()
3017 3016
3018 3017 if isinstance(res, wireprotov2peer.commandresponse):
3019 3018 val = list(res.cborobjects())
3020 3019 ui.status(_('response: %s\n') %
3021 3020 stringutil.pprint(val, bprefix=True))
3022 3021
3023 3022 else:
3024 3023 ui.status(_('response: %s\n') %
3025 3024 stringutil.pprint(res, bprefix=True))
3026 3025
3027 3026 elif action == 'batchbegin':
3028 3027 if batchedcommands is not None:
3029 3028 raise error.Abort(_('nested batchbegin not allowed'))
3030 3029
3031 3030 batchedcommands = []
3032 3031 elif action == 'batchsubmit':
3033 3032 # There is a batching API we could go through. But it would be
3034 3033 # difficult to normalize requests into function calls. It is easier
3035 3034 # to bypass this layer and normalize to commands + args.
3036 3035 ui.status(_('sending batch with %d sub-commands\n') %
3037 3036 len(batchedcommands))
3038 3037 for i, chunk in enumerate(peer._submitbatch(batchedcommands)):
3039 3038 ui.status(_('response #%d: %s\n') %
3040 3039 (i, stringutil.escapestr(chunk)))
3041 3040
3042 3041 batchedcommands = None
3043 3042
3044 3043 elif action.startswith('httprequest '):
3045 3044 if not opener:
3046 3045 raise error.Abort(_('cannot use httprequest without an HTTP '
3047 3046 'peer'))
3048 3047
3049 3048 request = action.split(' ', 2)
3050 3049 if len(request) != 3:
3051 3050 raise error.Abort(_('invalid httprequest: expected format is '
3052 3051 '"httprequest <method> <path>'))
3053 3052
3054 3053 method, httppath = request[1:]
3055 3054 headers = {}
3056 3055 body = None
3057 3056 frames = []
3058 3057 for line in lines:
3059 3058 line = line.lstrip()
3060 3059 m = re.match(b'^([a-zA-Z0-9_-]+): (.*)$', line)
3061 3060 if m:
3062 3061 headers[m.group(1)] = m.group(2)
3063 3062 continue
3064 3063
3065 3064 if line.startswith(b'BODYFILE '):
3066 3065 with open(line.split(b' ', 1), 'rb') as fh:
3067 3066 body = fh.read()
3068 3067 elif line.startswith(b'frame '):
3069 3068 frame = wireprotoframing.makeframefromhumanstring(
3070 3069 line[len(b'frame '):])
3071 3070
3072 3071 frames.append(frame)
3073 3072 else:
3074 3073 raise error.Abort(_('unknown argument to httprequest: %s') %
3075 3074 line)
3076 3075
3077 3076 url = path + httppath
3078 3077
3079 3078 if frames:
3080 3079 body = b''.join(bytes(f) for f in frames)
3081 3080
3082 3081 req = urlmod.urlreq.request(pycompat.strurl(url), body, headers)
3083 3082
3084 3083 # urllib.Request insists on using has_data() as a proxy for
3085 3084 # determining the request method. Override that to use our
3086 3085 # explicitly requested method.
3087 3086 req.get_method = lambda: method
3088 3087
3089 3088 try:
3090 3089 res = opener.open(req)
3091 3090 body = res.read()
3092 3091 except util.urlerr.urlerror as e:
3093 3092 e.read()
3094 3093 continue
3095 3094
3096 3095 if res.headers.get('Content-Type') == 'application/mercurial-cbor':
3097 3096 ui.write(_('cbor> %s\n') %
3098 3097 stringutil.pprint(cbor.loads(body), bprefix=True))
3099 3098
3100 3099 elif action == 'close':
3101 3100 peer.close()
3102 3101 elif action == 'readavailable':
3103 3102 if not stdout or not stderr:
3104 3103 raise error.Abort(_('readavailable not available on this peer'))
3105 3104
3106 3105 stdin.close()
3107 3106 stdout.read()
3108 3107 stderr.read()
3109 3108
3110 3109 elif action == 'readline':
3111 3110 if not stdout:
3112 3111 raise error.Abort(_('readline not available on this peer'))
3113 3112 stdout.readline()
3114 3113 elif action == 'ereadline':
3115 3114 if not stderr:
3116 3115 raise error.Abort(_('ereadline not available on this peer'))
3117 3116 stderr.readline()
3118 3117 elif action.startswith('read '):
3119 3118 count = int(action.split(' ', 1)[1])
3120 3119 if not stdout:
3121 3120 raise error.Abort(_('read not available on this peer'))
3122 3121 stdout.read(count)
3123 3122 elif action.startswith('eread '):
3124 3123 count = int(action.split(' ', 1)[1])
3125 3124 if not stderr:
3126 3125 raise error.Abort(_('eread not available on this peer'))
3127 3126 stderr.read(count)
3128 3127 else:
3129 3128 raise error.Abort(_('unknown action: %s') % action)
3130 3129
3131 3130 if batchedcommands is not None:
3132 3131 raise error.Abort(_('unclosed "batchbegin" request'))
3133 3132
3134 3133 if peer:
3135 3134 peer.close()
3136 3135
3137 3136 if proc:
3138 3137 proc.kill()
@@ -1,1145 +1,1131 b''
1 1 # smartset.py - data structure for revision set
2 2 #
3 3 # Copyright 2010 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 from . import (
11 11 encoding,
12 12 error,
13 13 pycompat,
14 14 util,
15 15 )
16 16
17 17 def _formatsetrepr(r):
18 18 """Format an optional printable representation of a set
19 19
20 20 ======== =================================
21 21 type(r) example
22 22 ======== =================================
23 23 tuple ('<not %r>', other)
24 24 bytes '<branch closed>'
25 25 callable lambda: '<branch %r>' % sorted(b)
26 26 object other
27 27 ======== =================================
28 28 """
29 29 if r is None:
30 30 return ''
31 31 elif isinstance(r, tuple):
32 32 return r[0] % util.rapply(pycompat.maybebytestr, r[1:])
33 33 elif isinstance(r, bytes):
34 34 return r
35 35 elif callable(r):
36 36 return r()
37 37 else:
38 38 return pycompat.byterepr(r)
39 39
40 40 def _typename(o):
41 41 return pycompat.sysbytes(type(o).__name__).lstrip('_')
42 42
43 43 class abstractsmartset(object):
44 44
45 45 def __nonzero__(self):
46 46 """True if the smartset is not empty"""
47 47 raise NotImplementedError()
48 48
49 49 __bool__ = __nonzero__
50 50
51 51 def __contains__(self, rev):
52 52 """provide fast membership testing"""
53 53 raise NotImplementedError()
54 54
55 55 def __iter__(self):
56 56 """iterate the set in the order it is supposed to be iterated"""
57 57 raise NotImplementedError()
58 58
59 59 # Attributes containing a function to perform a fast iteration in a given
60 60 # direction. A smartset can have none, one, or both defined.
61 61 #
62 62 # Default value is None instead of a function returning None to avoid
63 63 # initializing an iterator just for testing if a fast method exists.
64 64 fastasc = None
65 65 fastdesc = None
66 66
67 67 def isascending(self):
68 68 """True if the set will iterate in ascending order"""
69 69 raise NotImplementedError()
70 70
71 71 def isdescending(self):
72 72 """True if the set will iterate in descending order"""
73 73 raise NotImplementedError()
74 74
75 75 def istopo(self):
76 76 """True if the set will iterate in topographical order"""
77 77 raise NotImplementedError()
78 78
79 79 def min(self):
80 80 """return the minimum element in the set"""
81 81 if self.fastasc is None:
82 82 v = min(self)
83 83 else:
84 84 for v in self.fastasc():
85 85 break
86 86 else:
87 87 raise ValueError('arg is an empty sequence')
88 88 self.min = lambda: v
89 89 return v
90 90
91 91 def max(self):
92 92 """return the maximum element in the set"""
93 93 if self.fastdesc is None:
94 94 return max(self)
95 95 else:
96 96 for v in self.fastdesc():
97 97 break
98 98 else:
99 99 raise ValueError('arg is an empty sequence')
100 100 self.max = lambda: v
101 101 return v
102 102
103 103 def first(self):
104 104 """return the first element in the set (user iteration perspective)
105 105
106 106 Return None if the set is empty"""
107 107 raise NotImplementedError()
108 108
109 109 def last(self):
110 110 """return the last element in the set (user iteration perspective)
111 111
112 112 Return None if the set is empty"""
113 113 raise NotImplementedError()
114 114
115 115 def __len__(self):
116 116 """return the length of the smartsets
117 117
118 118 This can be expensive on smartset that could be lazy otherwise."""
119 119 raise NotImplementedError()
120 120
121 121 def reverse(self):
122 122 """reverse the expected iteration order"""
123 123 raise NotImplementedError()
124 124
125 125 def sort(self, reverse=False):
126 126 """get the set to iterate in an ascending or descending order"""
127 127 raise NotImplementedError()
128 128
129 129 def __and__(self, other):
130 130 """Returns a new object with the intersection of the two collections.
131 131
132 132 This is part of the mandatory API for smartset."""
133 133 if isinstance(other, fullreposet):
134 134 return self
135 135 return self.filter(other.__contains__, condrepr=other, cache=False)
136 136
137 137 def __add__(self, other):
138 138 """Returns a new object with the union of the two collections.
139 139
140 140 This is part of the mandatory API for smartset."""
141 141 return addset(self, other)
142 142
143 143 def __sub__(self, other):
144 144 """Returns a new object with the substraction of the two collections.
145 145
146 146 This is part of the mandatory API for smartset."""
147 147 c = other.__contains__
148 148 return self.filter(lambda r: not c(r), condrepr=('<not %r>', other),
149 149 cache=False)
150 150
151 151 def filter(self, condition, condrepr=None, cache=True):
152 152 """Returns this smartset filtered by condition as a new smartset.
153 153
154 154 `condition` is a callable which takes a revision number and returns a
155 155 boolean. Optional `condrepr` provides a printable representation of
156 156 the given `condition`.
157 157
158 158 This is part of the mandatory API for smartset."""
159 159 # builtin cannot be cached. but do not needs to
160 160 if cache and util.safehasattr(condition, 'func_code'):
161 161 condition = util.cachefunc(condition)
162 162 return filteredset(self, condition, condrepr)
163 163
164 164 def slice(self, start, stop):
165 165 """Return new smartset that contains selected elements from this set"""
166 166 if start < 0 or stop < 0:
167 167 raise error.ProgrammingError('negative index not allowed')
168 168 return self._slice(start, stop)
169 169
170 170 def _slice(self, start, stop):
171 171 # sub classes may override this. start and stop must not be negative,
172 172 # but start > stop is allowed, which should be an empty set.
173 173 ys = []
174 174 it = iter(self)
175 175 for x in xrange(start):
176 176 y = next(it, None)
177 177 if y is None:
178 178 break
179 179 for x in xrange(stop - start):
180 180 y = next(it, None)
181 181 if y is None:
182 182 break
183 183 ys.append(y)
184 184 return baseset(ys, datarepr=('slice=%d:%d %r', start, stop, self))
185 185
186 186 class baseset(abstractsmartset):
187 187 """Basic data structure that represents a revset and contains the basic
188 188 operation that it should be able to perform.
189 189
190 190 Every method in this class should be implemented by any smartset class.
191 191
192 192 This class could be constructed by an (unordered) set, or an (ordered)
193 193 list-like object. If a set is provided, it'll be sorted lazily.
194 194
195 195 >>> x = [4, 0, 7, 6]
196 196 >>> y = [5, 6, 7, 3]
197 197
198 198 Construct by a set:
199 199 >>> xs = baseset(set(x))
200 200 >>> ys = baseset(set(y))
201 201 >>> [list(i) for i in [xs + ys, xs & ys, xs - ys]]
202 202 [[0, 4, 6, 7, 3, 5], [6, 7], [0, 4]]
203 203 >>> [type(i).__name__ for i in [xs + ys, xs & ys, xs - ys]]
204 204 ['addset', 'baseset', 'baseset']
205 205
206 206 Construct by a list-like:
207 207 >>> xs = baseset(x)
208 208 >>> ys = baseset(i for i in y)
209 209 >>> [list(i) for i in [xs + ys, xs & ys, xs - ys]]
210 210 [[4, 0, 7, 6, 5, 3], [7, 6], [4, 0]]
211 211 >>> [type(i).__name__ for i in [xs + ys, xs & ys, xs - ys]]
212 212 ['addset', 'filteredset', 'filteredset']
213 213
214 214 Populate "_set" fields in the lists so set optimization may be used:
215 215 >>> [1 in xs, 3 in ys]
216 216 [False, True]
217 217
218 218 Without sort(), results won't be changed:
219 219 >>> [list(i) for i in [xs + ys, xs & ys, xs - ys]]
220 220 [[4, 0, 7, 6, 5, 3], [7, 6], [4, 0]]
221 221 >>> [type(i).__name__ for i in [xs + ys, xs & ys, xs - ys]]
222 222 ['addset', 'filteredset', 'filteredset']
223 223
224 224 With sort(), set optimization could be used:
225 225 >>> xs.sort(reverse=True)
226 226 >>> [list(i) for i in [xs + ys, xs & ys, xs - ys]]
227 227 [[7, 6, 4, 0, 5, 3], [7, 6], [4, 0]]
228 228 >>> [type(i).__name__ for i in [xs + ys, xs & ys, xs - ys]]
229 229 ['addset', 'baseset', 'baseset']
230 230
231 231 >>> ys.sort()
232 232 >>> [list(i) for i in [xs + ys, xs & ys, xs - ys]]
233 233 [[7, 6, 4, 0, 3, 5], [7, 6], [4, 0]]
234 234 >>> [type(i).__name__ for i in [xs + ys, xs & ys, xs - ys]]
235 235 ['addset', 'baseset', 'baseset']
236 236
237 237 istopo is preserved across set operations
238 238 >>> xs = baseset(set(x), istopo=True)
239 239 >>> rs = xs & ys
240 240 >>> type(rs).__name__
241 241 'baseset'
242 242 >>> rs._istopo
243 243 True
244 244 """
245 245 def __init__(self, data=(), datarepr=None, istopo=False):
246 246 """
247 247 datarepr: a tuple of (format, obj, ...), a function or an object that
248 248 provides a printable representation of the given data.
249 249 """
250 250 self._ascending = None
251 251 self._istopo = istopo
252 252 if isinstance(data, set):
253 253 # converting set to list has a cost, do it lazily
254 254 self._set = data
255 255 # set has no order we pick one for stability purpose
256 256 self._ascending = True
257 257 else:
258 258 if not isinstance(data, list):
259 259 data = list(data)
260 260 self._list = data
261 261 self._datarepr = datarepr
262 262
263 263 @util.propertycache
264 264 def _set(self):
265 265 return set(self._list)
266 266
267 267 @util.propertycache
268 268 def _asclist(self):
269 269 asclist = self._list[:]
270 270 asclist.sort()
271 271 return asclist
272 272
273 273 @util.propertycache
274 274 def _list(self):
275 275 # _list is only lazily constructed if we have _set
276 276 assert r'_set' in self.__dict__
277 277 return list(self._set)
278 278
279 279 def __iter__(self):
280 280 if self._ascending is None:
281 281 return iter(self._list)
282 282 elif self._ascending:
283 283 return iter(self._asclist)
284 284 else:
285 285 return reversed(self._asclist)
286 286
287 287 def fastasc(self):
288 288 return iter(self._asclist)
289 289
290 290 def fastdesc(self):
291 291 return reversed(self._asclist)
292 292
293 293 @util.propertycache
294 294 def __contains__(self):
295 295 return self._set.__contains__
296 296
297 297 def __nonzero__(self):
298 298 return bool(len(self))
299 299
300 300 __bool__ = __nonzero__
301 301
302 302 def sort(self, reverse=False):
303 303 self._ascending = not bool(reverse)
304 304 self._istopo = False
305 305
306 306 def reverse(self):
307 307 if self._ascending is None:
308 308 self._list.reverse()
309 309 else:
310 310 self._ascending = not self._ascending
311 311 self._istopo = False
312 312
313 313 def __len__(self):
314 314 if r'_list' in self.__dict__:
315 315 return len(self._list)
316 316 else:
317 317 return len(self._set)
318 318
319 319 def isascending(self):
320 320 """Returns True if the collection is ascending order, False if not.
321 321
322 322 This is part of the mandatory API for smartset."""
323 323 if len(self) <= 1:
324 324 return True
325 325 return self._ascending is not None and self._ascending
326 326
327 327 def isdescending(self):
328 328 """Returns True if the collection is descending order, False if not.
329 329
330 330 This is part of the mandatory API for smartset."""
331 331 if len(self) <= 1:
332 332 return True
333 333 return self._ascending is not None and not self._ascending
334 334
335 335 def istopo(self):
336 336 """Is the collection is in topographical order or not.
337 337
338 338 This is part of the mandatory API for smartset."""
339 339 if len(self) <= 1:
340 340 return True
341 341 return self._istopo
342 342
343 343 def first(self):
344 344 if self:
345 345 if self._ascending is None:
346 346 return self._list[0]
347 347 elif self._ascending:
348 348 return self._asclist[0]
349 349 else:
350 350 return self._asclist[-1]
351 351 return None
352 352
353 353 def last(self):
354 354 if self:
355 355 if self._ascending is None:
356 356 return self._list[-1]
357 357 elif self._ascending:
358 358 return self._asclist[-1]
359 359 else:
360 360 return self._asclist[0]
361 361 return None
362 362
363 363 def _fastsetop(self, other, op):
364 364 # try to use native set operations as fast paths
365 365 if (type(other) is baseset and r'_set' in other.__dict__ and r'_set' in
366 366 self.__dict__ and self._ascending is not None):
367 367 s = baseset(data=getattr(self._set, op)(other._set),
368 368 istopo=self._istopo)
369 369 s._ascending = self._ascending
370 370 else:
371 371 s = getattr(super(baseset, self), op)(other)
372 372 return s
373 373
374 374 def __and__(self, other):
375 375 return self._fastsetop(other, '__and__')
376 376
377 377 def __sub__(self, other):
378 378 return self._fastsetop(other, '__sub__')
379 379
380 380 def _slice(self, start, stop):
381 381 # creating new list should be generally cheaper than iterating items
382 382 if self._ascending is None:
383 383 return baseset(self._list[start:stop], istopo=self._istopo)
384 384
385 385 data = self._asclist
386 386 if not self._ascending:
387 387 start, stop = max(len(data) - stop, 0), max(len(data) - start, 0)
388 388 s = baseset(data[start:stop], istopo=self._istopo)
389 389 s._ascending = self._ascending
390 390 return s
391 391
392 392 @encoding.strmethod
393 393 def __repr__(self):
394 394 d = {None: '', False: '-', True: '+'}[self._ascending]
395 395 s = _formatsetrepr(self._datarepr)
396 396 if not s:
397 397 l = self._list
398 398 # if _list has been built from a set, it might have a different
399 399 # order from one python implementation to another.
400 400 # We fallback to the sorted version for a stable output.
401 401 if self._ascending is not None:
402 402 l = self._asclist
403 403 s = pycompat.byterepr(l)
404 404 return '<%s%s %s>' % (_typename(self), d, s)
405 405
406 406 class filteredset(abstractsmartset):
407 407 """Duck type for baseset class which iterates lazily over the revisions in
408 408 the subset and contains a function which tests for membership in the
409 409 revset
410 410 """
411 411 def __init__(self, subset, condition=lambda x: True, condrepr=None):
412 412 """
413 413 condition: a function that decide whether a revision in the subset
414 414 belongs to the revset or not.
415 415 condrepr: a tuple of (format, obj, ...), a function or an object that
416 416 provides a printable representation of the given condition.
417 417 """
418 418 self._subset = subset
419 419 self._condition = condition
420 420 self._condrepr = condrepr
421 421
422 422 def __contains__(self, x):
423 423 return x in self._subset and self._condition(x)
424 424
425 425 def __iter__(self):
426 426 return self._iterfilter(self._subset)
427 427
428 428 def _iterfilter(self, it):
429 429 cond = self._condition
430 430 for x in it:
431 431 if cond(x):
432 432 yield x
433 433
434 434 @property
435 435 def fastasc(self):
436 436 it = self._subset.fastasc
437 437 if it is None:
438 438 return None
439 439 return lambda: self._iterfilter(it())
440 440
441 441 @property
442 442 def fastdesc(self):
443 443 it = self._subset.fastdesc
444 444 if it is None:
445 445 return None
446 446 return lambda: self._iterfilter(it())
447 447
448 448 def __nonzero__(self):
449 449 fast = None
450 450 candidates = [self.fastasc if self.isascending() else None,
451 451 self.fastdesc if self.isdescending() else None,
452 452 self.fastasc,
453 453 self.fastdesc]
454 454 for candidate in candidates:
455 455 if candidate is not None:
456 456 fast = candidate
457 457 break
458 458
459 459 if fast is not None:
460 460 it = fast()
461 461 else:
462 462 it = self
463 463
464 464 for r in it:
465 465 return True
466 466 return False
467 467
468 468 __bool__ = __nonzero__
469 469
470 470 def __len__(self):
471 471 # Basic implementation to be changed in future patches.
472 472 # until this gets improved, we use generator expression
473 473 # here, since list comprehensions are free to call __len__ again
474 474 # causing infinite recursion
475 475 l = baseset(r for r in self)
476 476 return len(l)
477 477
478 478 def sort(self, reverse=False):
479 479 self._subset.sort(reverse=reverse)
480 480
481 481 def reverse(self):
482 482 self._subset.reverse()
483 483
484 484 def isascending(self):
485 485 return self._subset.isascending()
486 486
487 487 def isdescending(self):
488 488 return self._subset.isdescending()
489 489
490 490 def istopo(self):
491 491 return self._subset.istopo()
492 492
493 493 def first(self):
494 494 for x in self:
495 495 return x
496 496 return None
497 497
498 498 def last(self):
499 499 it = None
500 500 if self.isascending():
501 501 it = self.fastdesc
502 502 elif self.isdescending():
503 503 it = self.fastasc
504 504 if it is not None:
505 505 for x in it():
506 506 return x
507 507 return None #empty case
508 508 else:
509 509 x = None
510 510 for x in self:
511 511 pass
512 512 return x
513 513
514 514 @encoding.strmethod
515 515 def __repr__(self):
516 516 xs = [pycompat.byterepr(self._subset)]
517 517 s = _formatsetrepr(self._condrepr)
518 518 if s:
519 519 xs.append(s)
520 520 return '<%s %s>' % (_typename(self), ', '.join(xs))
521 521
522 522 def _iterordered(ascending, iter1, iter2):
523 523 """produce an ordered iteration from two iterators with the same order
524 524
525 525 The ascending is used to indicated the iteration direction.
526 526 """
527 527 choice = max
528 528 if ascending:
529 529 choice = min
530 530
531 531 val1 = None
532 532 val2 = None
533 533 try:
534 534 # Consume both iterators in an ordered way until one is empty
535 535 while True:
536 536 if val1 is None:
537 537 val1 = next(iter1)
538 538 if val2 is None:
539 539 val2 = next(iter2)
540 540 n = choice(val1, val2)
541 541 yield n
542 542 if val1 == n:
543 543 val1 = None
544 544 if val2 == n:
545 545 val2 = None
546 546 except StopIteration:
547 547 # Flush any remaining values and consume the other one
548 548 it = iter2
549 549 if val1 is not None:
550 550 yield val1
551 551 it = iter1
552 552 elif val2 is not None:
553 553 # might have been equality and both are empty
554 554 yield val2
555 555 for val in it:
556 556 yield val
557 557
558 558 class addset(abstractsmartset):
559 559 """Represent the addition of two sets
560 560
561 561 Wrapper structure for lazily adding two structures without losing much
562 562 performance on the __contains__ method
563 563
564 564 If the ascending attribute is set, that means the two structures are
565 565 ordered in either an ascending or descending way. Therefore, we can add
566 566 them maintaining the order by iterating over both at the same time
567 567
568 568 >>> xs = baseset([0, 3, 2])
569 569 >>> ys = baseset([5, 2, 4])
570 570
571 571 >>> rs = addset(xs, ys)
572 572 >>> bool(rs), 0 in rs, 1 in rs, 5 in rs, rs.first(), rs.last()
573 573 (True, True, False, True, 0, 4)
574 574 >>> rs = addset(xs, baseset([]))
575 575 >>> bool(rs), 0 in rs, 1 in rs, rs.first(), rs.last()
576 576 (True, True, False, 0, 2)
577 577 >>> rs = addset(baseset([]), baseset([]))
578 578 >>> bool(rs), 0 in rs, rs.first(), rs.last()
579 579 (False, False, None, None)
580 580
581 581 iterate unsorted:
582 582 >>> rs = addset(xs, ys)
583 583 >>> # (use generator because pypy could call len())
584 584 >>> list(x for x in rs) # without _genlist
585 585 [0, 3, 2, 5, 4]
586 586 >>> assert not rs._genlist
587 587 >>> len(rs)
588 588 5
589 589 >>> [x for x in rs] # with _genlist
590 590 [0, 3, 2, 5, 4]
591 591 >>> assert rs._genlist
592 592
593 593 iterate ascending:
594 594 >>> rs = addset(xs, ys, ascending=True)
595 595 >>> # (use generator because pypy could call len())
596 596 >>> list(x for x in rs), list(x for x in rs.fastasc()) # without _asclist
597 597 ([0, 2, 3, 4, 5], [0, 2, 3, 4, 5])
598 598 >>> assert not rs._asclist
599 599 >>> len(rs)
600 600 5
601 601 >>> [x for x in rs], [x for x in rs.fastasc()]
602 602 ([0, 2, 3, 4, 5], [0, 2, 3, 4, 5])
603 603 >>> assert rs._asclist
604 604
605 605 iterate descending:
606 606 >>> rs = addset(xs, ys, ascending=False)
607 607 >>> # (use generator because pypy could call len())
608 608 >>> list(x for x in rs), list(x for x in rs.fastdesc()) # without _asclist
609 609 ([5, 4, 3, 2, 0], [5, 4, 3, 2, 0])
610 610 >>> assert not rs._asclist
611 611 >>> len(rs)
612 612 5
613 613 >>> [x for x in rs], [x for x in rs.fastdesc()]
614 614 ([5, 4, 3, 2, 0], [5, 4, 3, 2, 0])
615 615 >>> assert rs._asclist
616 616
617 617 iterate ascending without fastasc:
618 618 >>> rs = addset(xs, generatorset(ys), ascending=True)
619 619 >>> assert rs.fastasc is None
620 620 >>> [x for x in rs]
621 621 [0, 2, 3, 4, 5]
622 622
623 623 iterate descending without fastdesc:
624 624 >>> rs = addset(generatorset(xs), ys, ascending=False)
625 625 >>> assert rs.fastdesc is None
626 626 >>> [x for x in rs]
627 627 [5, 4, 3, 2, 0]
628 628 """
629 629 def __init__(self, revs1, revs2, ascending=None):
630 630 self._r1 = revs1
631 631 self._r2 = revs2
632 632 self._iter = None
633 633 self._ascending = ascending
634 634 self._genlist = None
635 635 self._asclist = None
636 636
637 637 def __len__(self):
638 638 return len(self._list)
639 639
640 640 def __nonzero__(self):
641 641 return bool(self._r1) or bool(self._r2)
642 642
643 643 __bool__ = __nonzero__
644 644
645 645 @util.propertycache
646 646 def _list(self):
647 647 if not self._genlist:
648 648 self._genlist = baseset(iter(self))
649 649 return self._genlist
650 650
651 651 def __iter__(self):
652 652 """Iterate over both collections without repeating elements
653 653
654 654 If the ascending attribute is not set, iterate over the first one and
655 655 then over the second one checking for membership on the first one so we
656 656 dont yield any duplicates.
657 657
658 658 If the ascending attribute is set, iterate over both collections at the
659 659 same time, yielding only one value at a time in the given order.
660 660 """
661 661 if self._ascending is None:
662 662 if self._genlist:
663 663 return iter(self._genlist)
664 664 def arbitraryordergen():
665 665 for r in self._r1:
666 666 yield r
667 667 inr1 = self._r1.__contains__
668 668 for r in self._r2:
669 669 if not inr1(r):
670 670 yield r
671 671 return arbitraryordergen()
672 672 # try to use our own fast iterator if it exists
673 673 self._trysetasclist()
674 674 if self._ascending:
675 675 attr = 'fastasc'
676 676 else:
677 677 attr = 'fastdesc'
678 678 it = getattr(self, attr)
679 679 if it is not None:
680 680 return it()
681 681 # maybe half of the component supports fast
682 682 # get iterator for _r1
683 683 iter1 = getattr(self._r1, attr)
684 684 if iter1 is None:
685 685 # let's avoid side effect (not sure it matters)
686 686 iter1 = iter(sorted(self._r1, reverse=not self._ascending))
687 687 else:
688 688 iter1 = iter1()
689 689 # get iterator for _r2
690 690 iter2 = getattr(self._r2, attr)
691 691 if iter2 is None:
692 692 # let's avoid side effect (not sure it matters)
693 693 iter2 = iter(sorted(self._r2, reverse=not self._ascending))
694 694 else:
695 695 iter2 = iter2()
696 696 return _iterordered(self._ascending, iter1, iter2)
697 697
698 698 def _trysetasclist(self):
699 699 """populate the _asclist attribute if possible and necessary"""
700 700 if self._genlist is not None and self._asclist is None:
701 701 self._asclist = sorted(self._genlist)
702 702
703 703 @property
704 704 def fastasc(self):
705 705 self._trysetasclist()
706 706 if self._asclist is not None:
707 707 return self._asclist.__iter__
708 708 iter1 = self._r1.fastasc
709 709 iter2 = self._r2.fastasc
710 710 if None in (iter1, iter2):
711 711 return None
712 712 return lambda: _iterordered(True, iter1(), iter2())
713 713
714 714 @property
715 715 def fastdesc(self):
716 716 self._trysetasclist()
717 717 if self._asclist is not None:
718 718 return self._asclist.__reversed__
719 719 iter1 = self._r1.fastdesc
720 720 iter2 = self._r2.fastdesc
721 721 if None in (iter1, iter2):
722 722 return None
723 723 return lambda: _iterordered(False, iter1(), iter2())
724 724
725 725 def __contains__(self, x):
726 726 return x in self._r1 or x in self._r2
727 727
728 728 def sort(self, reverse=False):
729 729 """Sort the added set
730 730
731 731 For this we use the cached list with all the generated values and if we
732 732 know they are ascending or descending we can sort them in a smart way.
733 733 """
734 734 self._ascending = not reverse
735 735
736 736 def isascending(self):
737 737 return self._ascending is not None and self._ascending
738 738
739 739 def isdescending(self):
740 740 return self._ascending is not None and not self._ascending
741 741
742 742 def istopo(self):
743 743 # not worth the trouble asserting if the two sets combined are still
744 744 # in topographical order. Use the sort() predicate to explicitly sort
745 745 # again instead.
746 746 return False
747 747
748 748 def reverse(self):
749 749 if self._ascending is None:
750 750 self._list.reverse()
751 751 else:
752 752 self._ascending = not self._ascending
753 753
754 754 def first(self):
755 755 for x in self:
756 756 return x
757 757 return None
758 758
759 759 def last(self):
760 760 self.reverse()
761 761 val = self.first()
762 762 self.reverse()
763 763 return val
764 764
765 765 @encoding.strmethod
766 766 def __repr__(self):
767 767 d = {None: '', False: '-', True: '+'}[self._ascending]
768 768 return '<%s%s %r, %r>' % (_typename(self), d, self._r1, self._r2)
769 769
770 770 class generatorset(abstractsmartset):
771 771 """Wrap a generator for lazy iteration
772 772
773 773 Wrapper structure for generators that provides lazy membership and can
774 774 be iterated more than once.
775 775 When asked for membership it generates values until either it finds the
776 776 requested one or has gone through all the elements in the generator
777 777
778 778 >>> xs = generatorset([0, 1, 4], iterasc=True)
779 779 >>> assert xs.last() == xs.last()
780 780 >>> xs.last() # cached
781 781 4
782 782 """
783 783 def __new__(cls, gen, iterasc=None):
784 784 if iterasc is None:
785 785 typ = cls
786 786 elif iterasc:
787 787 typ = _generatorsetasc
788 788 else:
789 789 typ = _generatorsetdesc
790 790
791 791 return super(generatorset, cls).__new__(typ)
792 792
793 793 def __init__(self, gen, iterasc=None):
794 794 """
795 795 gen: a generator producing the values for the generatorset.
796 796 """
797 797 self._gen = gen
798 798 self._asclist = None
799 799 self._cache = {}
800 800 self._genlist = []
801 801 self._finished = False
802 802 self._ascending = True
803 803
804 804 def __nonzero__(self):
805 805 # Do not use 'for r in self' because it will enforce the iteration
806 806 # order (default ascending), possibly unrolling a whole descending
807 807 # iterator.
808 808 if self._genlist:
809 809 return True
810 810 for r in self._consumegen():
811 811 return True
812 812 return False
813 813
814 814 __bool__ = __nonzero__
815 815
816 816 def __contains__(self, x):
817 817 if x in self._cache:
818 818 return self._cache[x]
819 819
820 820 # Use new values only, as existing values would be cached.
821 821 for l in self._consumegen():
822 822 if l == x:
823 823 return True
824 824
825 825 self._cache[x] = False
826 826 return False
827 827
828 828 def __iter__(self):
829 829 if self._ascending:
830 830 it = self.fastasc
831 831 else:
832 832 it = self.fastdesc
833 833 if it is not None:
834 834 return it()
835 835 # we need to consume the iterator
836 836 for x in self._consumegen():
837 837 pass
838 838 # recall the same code
839 839 return iter(self)
840 840
841 841 def _iterator(self):
842 842 if self._finished:
843 843 return iter(self._genlist)
844 844
845 845 # We have to use this complex iteration strategy to allow multiple
846 846 # iterations at the same time. We need to be able to catch revision
847 847 # removed from _consumegen and added to genlist in another instance.
848 848 #
849 849 # Getting rid of it would provide an about 15% speed up on this
850 850 # iteration.
851 851 genlist = self._genlist
852 852 nextgen = self._consumegen()
853 853 _len, _next = len, next # cache global lookup
854 854 def gen():
855 855 i = 0
856 856 while True:
857 857 if i < _len(genlist):
858 858 yield genlist[i]
859 859 else:
860 860 try:
861 861 yield _next(nextgen)
862 862 except StopIteration:
863 863 return
864 864 i += 1
865 865 return gen()
866 866
867 867 def _consumegen(self):
868 868 cache = self._cache
869 869 genlist = self._genlist.append
870 870 for item in self._gen:
871 871 cache[item] = True
872 872 genlist(item)
873 873 yield item
874 874 if not self._finished:
875 875 self._finished = True
876 876 asc = self._genlist[:]
877 877 asc.sort()
878 878 self._asclist = asc
879 879 self.fastasc = asc.__iter__
880 880 self.fastdesc = asc.__reversed__
881 881
882 882 def __len__(self):
883 883 for x in self._consumegen():
884 884 pass
885 885 return len(self._genlist)
886 886
887 887 def sort(self, reverse=False):
888 888 self._ascending = not reverse
889 889
890 890 def reverse(self):
891 891 self._ascending = not self._ascending
892 892
893 893 def isascending(self):
894 894 return self._ascending
895 895
896 896 def isdescending(self):
897 897 return not self._ascending
898 898
899 899 def istopo(self):
900 900 # not worth the trouble asserting if the two sets combined are still
901 901 # in topographical order. Use the sort() predicate to explicitly sort
902 902 # again instead.
903 903 return False
904 904
905 905 def first(self):
906 906 if self._ascending:
907 907 it = self.fastasc
908 908 else:
909 909 it = self.fastdesc
910 910 if it is None:
911 911 # we need to consume all and try again
912 912 for x in self._consumegen():
913 913 pass
914 914 return self.first()
915 915 return next(it(), None)
916 916
917 917 def last(self):
918 918 if self._ascending:
919 919 it = self.fastdesc
920 920 else:
921 921 it = self.fastasc
922 922 if it is None:
923 923 # we need to consume all and try again
924 924 for x in self._consumegen():
925 925 pass
926 926 return self.last()
927 927 return next(it(), None)
928 928
929 929 @encoding.strmethod
930 930 def __repr__(self):
931 931 d = {False: '-', True: '+'}[self._ascending]
932 932 return '<%s%s>' % (_typename(self), d)
933 933
934 934 class _generatorsetasc(generatorset):
935 935 """Special case of generatorset optimized for ascending generators."""
936 936
937 937 fastasc = generatorset._iterator
938 938
939 939 def __contains__(self, x):
940 940 if x in self._cache:
941 941 return self._cache[x]
942 942
943 943 # Use new values only, as existing values would be cached.
944 944 for l in self._consumegen():
945 945 if l == x:
946 946 return True
947 947 if l > x:
948 948 break
949 949
950 950 self._cache[x] = False
951 951 return False
952 952
953 953 class _generatorsetdesc(generatorset):
954 954 """Special case of generatorset optimized for descending generators."""
955 955
956 956 fastdesc = generatorset._iterator
957 957
958 958 def __contains__(self, x):
959 959 if x in self._cache:
960 960 return self._cache[x]
961 961
962 962 # Use new values only, as existing values would be cached.
963 963 for l in self._consumegen():
964 964 if l == x:
965 965 return True
966 966 if l < x:
967 967 break
968 968
969 969 self._cache[x] = False
970 970 return False
971 971
972 972 def spanset(repo, start=0, end=None):
973 973 """Create a spanset that represents a range of repository revisions
974 974
975 975 start: first revision included the set (default to 0)
976 976 end: first revision excluded (last+1) (default to len(repo))
977 977
978 978 Spanset will be descending if `end` < `start`.
979 979 """
980 980 if end is None:
981 981 end = len(repo)
982 982 ascending = start <= end
983 983 if not ascending:
984 984 start, end = end + 1, start + 1
985 985 return _spanset(start, end, ascending, repo.changelog.filteredrevs)
986 986
987 987 class _spanset(abstractsmartset):
988 988 """Duck type for baseset class which represents a range of revisions and
989 989 can work lazily and without having all the range in memory
990 990
991 991 Note that spanset(x, y) behave almost like xrange(x, y) except for two
992 992 notable points:
993 993 - when x < y it will be automatically descending,
994 994 - revision filtered with this repoview will be skipped.
995 995
996 996 """
997 997 def __init__(self, start, end, ascending, hiddenrevs):
998 998 self._start = start
999 999 self._end = end
1000 1000 self._ascending = ascending
1001 1001 self._hiddenrevs = hiddenrevs
1002 1002
1003 1003 def sort(self, reverse=False):
1004 1004 self._ascending = not reverse
1005 1005
1006 1006 def reverse(self):
1007 1007 self._ascending = not self._ascending
1008 1008
1009 1009 def istopo(self):
1010 1010 # not worth the trouble asserting if the two sets combined are still
1011 1011 # in topographical order. Use the sort() predicate to explicitly sort
1012 1012 # again instead.
1013 1013 return False
1014 1014
1015 1015 def _iterfilter(self, iterrange):
1016 1016 s = self._hiddenrevs
1017 1017 for r in iterrange:
1018 1018 if r not in s:
1019 1019 yield r
1020 1020
1021 1021 def __iter__(self):
1022 1022 if self._ascending:
1023 1023 return self.fastasc()
1024 1024 else:
1025 1025 return self.fastdesc()
1026 1026
1027 1027 def fastasc(self):
1028 1028 iterrange = xrange(self._start, self._end)
1029 1029 if self._hiddenrevs:
1030 1030 return self._iterfilter(iterrange)
1031 1031 return iter(iterrange)
1032 1032
1033 1033 def fastdesc(self):
1034 1034 iterrange = xrange(self._end - 1, self._start - 1, -1)
1035 1035 if self._hiddenrevs:
1036 1036 return self._iterfilter(iterrange)
1037 1037 return iter(iterrange)
1038 1038
1039 1039 def __contains__(self, rev):
1040 1040 hidden = self._hiddenrevs
1041 1041 return ((self._start <= rev < self._end)
1042 1042 and not (hidden and rev in hidden))
1043 1043
1044 1044 def __nonzero__(self):
1045 1045 for r in self:
1046 1046 return True
1047 1047 return False
1048 1048
1049 1049 __bool__ = __nonzero__
1050 1050
1051 1051 def __len__(self):
1052 1052 if not self._hiddenrevs:
1053 1053 return abs(self._end - self._start)
1054 1054 else:
1055 1055 count = 0
1056 1056 start = self._start
1057 1057 end = self._end
1058 1058 for rev in self._hiddenrevs:
1059 1059 if (end < rev <= start) or (start <= rev < end):
1060 1060 count += 1
1061 1061 return abs(self._end - self._start) - count
1062 1062
1063 1063 def isascending(self):
1064 1064 return self._ascending
1065 1065
1066 1066 def isdescending(self):
1067 1067 return not self._ascending
1068 1068
1069 1069 def first(self):
1070 1070 if self._ascending:
1071 1071 it = self.fastasc
1072 1072 else:
1073 1073 it = self.fastdesc
1074 1074 for x in it():
1075 1075 return x
1076 1076 return None
1077 1077
1078 1078 def last(self):
1079 1079 if self._ascending:
1080 1080 it = self.fastdesc
1081 1081 else:
1082 1082 it = self.fastasc
1083 1083 for x in it():
1084 1084 return x
1085 1085 return None
1086 1086
1087 1087 def _slice(self, start, stop):
1088 1088 if self._hiddenrevs:
1089 1089 # unoptimized since all hidden revisions in range has to be scanned
1090 1090 return super(_spanset, self)._slice(start, stop)
1091 1091 if self._ascending:
1092 1092 x = min(self._start + start, self._end)
1093 1093 y = min(self._start + stop, self._end)
1094 1094 else:
1095 1095 x = max(self._end - stop, self._start)
1096 1096 y = max(self._end - start, self._start)
1097 1097 return _spanset(x, y, self._ascending, self._hiddenrevs)
1098 1098
1099 1099 @encoding.strmethod
1100 1100 def __repr__(self):
1101 1101 d = {False: '-', True: '+'}[self._ascending]
1102 1102 return '<%s%s %d:%d>' % (_typename(self), d, self._start, self._end)
1103 1103
1104 1104 class fullreposet(_spanset):
1105 1105 """a set containing all revisions in the repo
1106 1106
1107 1107 This class exists to host special optimization and magic to handle virtual
1108 1108 revisions such as "null".
1109 1109 """
1110 1110
1111 1111 def __init__(self, repo):
1112 1112 super(fullreposet, self).__init__(0, len(repo), True,
1113 1113 repo.changelog.filteredrevs)
1114 1114
1115 1115 def __and__(self, other):
1116 1116 """As self contains the whole repo, all of the other set should also be
1117 1117 in self. Therefore `self & other = other`.
1118 1118
1119 1119 This boldly assumes the other contains valid revs only.
1120 1120 """
1121 1121 # other not a smartset, make is so
1122 1122 if not util.safehasattr(other, 'isascending'):
1123 1123 # filter out hidden revision
1124 1124 # (this boldly assumes all smartset are pure)
1125 1125 #
1126 1126 # `other` was used with "&", let's assume this is a set like
1127 1127 # object.
1128 1128 other = baseset(other - self._hiddenrevs)
1129 1129
1130 1130 other.sort(reverse=self.isdescending())
1131 1131 return other
1132
1133 def prettyformat(revs):
1134 lines = []
1135 rs = pycompat.byterepr(revs)
1136 p = 0
1137 while p < len(rs):
1138 q = rs.find('<', p + 1)
1139 if q < 0:
1140 q = len(rs)
1141 l = rs.count('<', 0, p) - rs.count('>', 0, p)
1142 assert l >= 0
1143 lines.append((l, rs[p:q].rstrip()))
1144 p = q
1145 return '\n'.join(' ' * l + s for l, s in lines)
@@ -1,515 +1,530 b''
1 1 # stringutil.py - utility for generic string formatting, parsing, etc.
2 2 #
3 3 # Copyright 2005 K. Thananchayan <thananck@yahoo.com>
4 4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
5 5 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
6 6 #
7 7 # This software may be used and distributed according to the terms of the
8 8 # GNU General Public License version 2 or any later version.
9 9
10 10 from __future__ import absolute_import
11 11
12 12 import ast
13 13 import codecs
14 14 import re as remod
15 15 import textwrap
16 16
17 17 from ..i18n import _
18 18 from ..thirdparty import attr
19 19
20 20 from .. import (
21 21 encoding,
22 22 error,
23 23 pycompat,
24 24 )
25 25
26 26 def pprint(o, bprefix=False):
27 27 """Pretty print an object."""
28 28 if isinstance(o, bytes):
29 29 if bprefix:
30 30 return "b'%s'" % escapestr(o)
31 31 return "'%s'" % escapestr(o)
32 32 elif isinstance(o, bytearray):
33 33 # codecs.escape_encode() can't handle bytearray, so escapestr fails
34 34 # without coercion.
35 35 return "bytearray['%s']" % escapestr(bytes(o))
36 36 elif isinstance(o, list):
37 37 return '[%s]' % (b', '.join(pprint(a, bprefix=bprefix) for a in o))
38 38 elif isinstance(o, dict):
39 39 return '{%s}' % (b', '.join(
40 40 '%s: %s' % (pprint(k, bprefix=bprefix),
41 41 pprint(v, bprefix=bprefix))
42 42 for k, v in sorted(o.items())))
43 43 elif isinstance(o, tuple):
44 44 return '(%s)' % (b', '.join(pprint(a, bprefix=bprefix) for a in o))
45 45 else:
46 46 return pycompat.byterepr(o)
47 47
48 def prettyrepr(o):
49 """Pretty print a representation of a possibly-nested object"""
50 lines = []
51 rs = pycompat.byterepr(o)
52 p = 0
53 while p < len(rs):
54 q = rs.find('<', p + 1)
55 if q < 0:
56 q = len(rs)
57 l = rs.count('<', 0, p) - rs.count('>', 0, p)
58 assert l >= 0
59 lines.append((l, rs[p:q].rstrip()))
60 p = q
61 return '\n'.join(' ' * l + s for l, s in lines)
62
48 63 def binary(s):
49 64 """return true if a string is binary data"""
50 65 return bool(s and '\0' in s)
51 66
52 67 def stringmatcher(pattern, casesensitive=True):
53 68 """
54 69 accepts a string, possibly starting with 're:' or 'literal:' prefix.
55 70 returns the matcher name, pattern, and matcher function.
56 71 missing or unknown prefixes are treated as literal matches.
57 72
58 73 helper for tests:
59 74 >>> def test(pattern, *tests):
60 75 ... kind, pattern, matcher = stringmatcher(pattern)
61 76 ... return (kind, pattern, [bool(matcher(t)) for t in tests])
62 77 >>> def itest(pattern, *tests):
63 78 ... kind, pattern, matcher = stringmatcher(pattern, casesensitive=False)
64 79 ... return (kind, pattern, [bool(matcher(t)) for t in tests])
65 80
66 81 exact matching (no prefix):
67 82 >>> test(b'abcdefg', b'abc', b'def', b'abcdefg')
68 83 ('literal', 'abcdefg', [False, False, True])
69 84
70 85 regex matching ('re:' prefix)
71 86 >>> test(b're:a.+b', b'nomatch', b'fooadef', b'fooadefbar')
72 87 ('re', 'a.+b', [False, False, True])
73 88
74 89 force exact matches ('literal:' prefix)
75 90 >>> test(b'literal:re:foobar', b'foobar', b're:foobar')
76 91 ('literal', 're:foobar', [False, True])
77 92
78 93 unknown prefixes are ignored and treated as literals
79 94 >>> test(b'foo:bar', b'foo', b'bar', b'foo:bar')
80 95 ('literal', 'foo:bar', [False, False, True])
81 96
82 97 case insensitive regex matches
83 98 >>> itest(b're:A.+b', b'nomatch', b'fooadef', b'fooadefBar')
84 99 ('re', 'A.+b', [False, False, True])
85 100
86 101 case insensitive literal matches
87 102 >>> itest(b'ABCDEFG', b'abc', b'def', b'abcdefg')
88 103 ('literal', 'ABCDEFG', [False, False, True])
89 104 """
90 105 if pattern.startswith('re:'):
91 106 pattern = pattern[3:]
92 107 try:
93 108 flags = 0
94 109 if not casesensitive:
95 110 flags = remod.I
96 111 regex = remod.compile(pattern, flags)
97 112 except remod.error as e:
98 113 raise error.ParseError(_('invalid regular expression: %s')
99 114 % e)
100 115 return 're', pattern, regex.search
101 116 elif pattern.startswith('literal:'):
102 117 pattern = pattern[8:]
103 118
104 119 match = pattern.__eq__
105 120
106 121 if not casesensitive:
107 122 ipat = encoding.lower(pattern)
108 123 match = lambda s: ipat == encoding.lower(s)
109 124 return 'literal', pattern, match
110 125
111 126 def shortuser(user):
112 127 """Return a short representation of a user name or email address."""
113 128 f = user.find('@')
114 129 if f >= 0:
115 130 user = user[:f]
116 131 f = user.find('<')
117 132 if f >= 0:
118 133 user = user[f + 1:]
119 134 f = user.find(' ')
120 135 if f >= 0:
121 136 user = user[:f]
122 137 f = user.find('.')
123 138 if f >= 0:
124 139 user = user[:f]
125 140 return user
126 141
127 142 def emailuser(user):
128 143 """Return the user portion of an email address."""
129 144 f = user.find('@')
130 145 if f >= 0:
131 146 user = user[:f]
132 147 f = user.find('<')
133 148 if f >= 0:
134 149 user = user[f + 1:]
135 150 return user
136 151
137 152 def email(author):
138 153 '''get email of author.'''
139 154 r = author.find('>')
140 155 if r == -1:
141 156 r = None
142 157 return author[author.find('<') + 1:r]
143 158
144 159 def person(author):
145 160 """Returns the name before an email address,
146 161 interpreting it as per RFC 5322
147 162
148 163 >>> person(b'foo@bar')
149 164 'foo'
150 165 >>> person(b'Foo Bar <foo@bar>')
151 166 'Foo Bar'
152 167 >>> person(b'"Foo Bar" <foo@bar>')
153 168 'Foo Bar'
154 169 >>> person(b'"Foo \"buz\" Bar" <foo@bar>')
155 170 'Foo "buz" Bar'
156 171 >>> # The following are invalid, but do exist in real-life
157 172 ...
158 173 >>> person(b'Foo "buz" Bar <foo@bar>')
159 174 'Foo "buz" Bar'
160 175 >>> person(b'"Foo Bar <foo@bar>')
161 176 'Foo Bar'
162 177 """
163 178 if '@' not in author:
164 179 return author
165 180 f = author.find('<')
166 181 if f != -1:
167 182 return author[:f].strip(' "').replace('\\"', '"')
168 183 f = author.find('@')
169 184 return author[:f].replace('.', ' ')
170 185
171 186 @attr.s(hash=True)
172 187 class mailmapping(object):
173 188 '''Represents a username/email key or value in
174 189 a mailmap file'''
175 190 email = attr.ib()
176 191 name = attr.ib(default=None)
177 192
178 193 def _ismailmaplineinvalid(names, emails):
179 194 '''Returns True if the parsed names and emails
180 195 in a mailmap entry are invalid.
181 196
182 197 >>> # No names or emails fails
183 198 >>> names, emails = [], []
184 199 >>> _ismailmaplineinvalid(names, emails)
185 200 True
186 201 >>> # Only one email fails
187 202 >>> emails = [b'email@email.com']
188 203 >>> _ismailmaplineinvalid(names, emails)
189 204 True
190 205 >>> # One email and one name passes
191 206 >>> names = [b'Test Name']
192 207 >>> _ismailmaplineinvalid(names, emails)
193 208 False
194 209 >>> # No names but two emails passes
195 210 >>> names = []
196 211 >>> emails = [b'proper@email.com', b'commit@email.com']
197 212 >>> _ismailmaplineinvalid(names, emails)
198 213 False
199 214 '''
200 215 return not emails or not names and len(emails) < 2
201 216
202 217 def parsemailmap(mailmapcontent):
203 218 """Parses data in the .mailmap format
204 219
205 220 >>> mmdata = b"\\n".join([
206 221 ... b'# Comment',
207 222 ... b'Name <commit1@email.xx>',
208 223 ... b'<name@email.xx> <commit2@email.xx>',
209 224 ... b'Name <proper@email.xx> <commit3@email.xx>',
210 225 ... b'Name <proper@email.xx> Commit <commit4@email.xx>',
211 226 ... ])
212 227 >>> mm = parsemailmap(mmdata)
213 228 >>> for key in sorted(mm.keys()):
214 229 ... print(key)
215 230 mailmapping(email='commit1@email.xx', name=None)
216 231 mailmapping(email='commit2@email.xx', name=None)
217 232 mailmapping(email='commit3@email.xx', name=None)
218 233 mailmapping(email='commit4@email.xx', name='Commit')
219 234 >>> for val in sorted(mm.values()):
220 235 ... print(val)
221 236 mailmapping(email='commit1@email.xx', name='Name')
222 237 mailmapping(email='name@email.xx', name=None)
223 238 mailmapping(email='proper@email.xx', name='Name')
224 239 mailmapping(email='proper@email.xx', name='Name')
225 240 """
226 241 mailmap = {}
227 242
228 243 if mailmapcontent is None:
229 244 return mailmap
230 245
231 246 for line in mailmapcontent.splitlines():
232 247
233 248 # Don't bother checking the line if it is a comment or
234 249 # is an improperly formed author field
235 250 if line.lstrip().startswith('#'):
236 251 continue
237 252
238 253 # names, emails hold the parsed emails and names for each line
239 254 # name_builder holds the words in a persons name
240 255 names, emails = [], []
241 256 namebuilder = []
242 257
243 258 for element in line.split():
244 259 if element.startswith('#'):
245 260 # If we reach a comment in the mailmap file, move on
246 261 break
247 262
248 263 elif element.startswith('<') and element.endswith('>'):
249 264 # We have found an email.
250 265 # Parse it, and finalize any names from earlier
251 266 emails.append(element[1:-1]) # Slice off the "<>"
252 267
253 268 if namebuilder:
254 269 names.append(' '.join(namebuilder))
255 270 namebuilder = []
256 271
257 272 # Break if we have found a second email, any other
258 273 # data does not fit the spec for .mailmap
259 274 if len(emails) > 1:
260 275 break
261 276
262 277 else:
263 278 # We have found another word in the committers name
264 279 namebuilder.append(element)
265 280
266 281 # Check to see if we have parsed the line into a valid form
267 282 # We require at least one email, and either at least one
268 283 # name or a second email
269 284 if _ismailmaplineinvalid(names, emails):
270 285 continue
271 286
272 287 mailmapkey = mailmapping(
273 288 email=emails[-1],
274 289 name=names[-1] if len(names) == 2 else None,
275 290 )
276 291
277 292 mailmap[mailmapkey] = mailmapping(
278 293 email=emails[0],
279 294 name=names[0] if names else None,
280 295 )
281 296
282 297 return mailmap
283 298
284 299 def mapname(mailmap, author):
285 300 """Returns the author field according to the mailmap cache, or
286 301 the original author field.
287 302
288 303 >>> mmdata = b"\\n".join([
289 304 ... b'# Comment',
290 305 ... b'Name <commit1@email.xx>',
291 306 ... b'<name@email.xx> <commit2@email.xx>',
292 307 ... b'Name <proper@email.xx> <commit3@email.xx>',
293 308 ... b'Name <proper@email.xx> Commit <commit4@email.xx>',
294 309 ... ])
295 310 >>> m = parsemailmap(mmdata)
296 311 >>> mapname(m, b'Commit <commit1@email.xx>')
297 312 'Name <commit1@email.xx>'
298 313 >>> mapname(m, b'Name <commit2@email.xx>')
299 314 'Name <name@email.xx>'
300 315 >>> mapname(m, b'Commit <commit3@email.xx>')
301 316 'Name <proper@email.xx>'
302 317 >>> mapname(m, b'Commit <commit4@email.xx>')
303 318 'Name <proper@email.xx>'
304 319 >>> mapname(m, b'Unknown Name <unknown@email.com>')
305 320 'Unknown Name <unknown@email.com>'
306 321 """
307 322 # If the author field coming in isn't in the correct format,
308 323 # or the mailmap is empty just return the original author field
309 324 if not isauthorwellformed(author) or not mailmap:
310 325 return author
311 326
312 327 # Turn the user name into a mailmapping
313 328 commit = mailmapping(name=person(author), email=email(author))
314 329
315 330 try:
316 331 # Try and use both the commit email and name as the key
317 332 proper = mailmap[commit]
318 333
319 334 except KeyError:
320 335 # If the lookup fails, use just the email as the key instead
321 336 # We call this commit2 as not to erase original commit fields
322 337 commit2 = mailmapping(email=commit.email)
323 338 proper = mailmap.get(commit2, mailmapping(None, None))
324 339
325 340 # Return the author field with proper values filled in
326 341 return '%s <%s>' % (
327 342 proper.name if proper.name else commit.name,
328 343 proper.email if proper.email else commit.email,
329 344 )
330 345
331 346 _correctauthorformat = remod.compile(br'^[^<]+\s\<[^<>]+@[^<>]+\>$')
332 347
333 348 def isauthorwellformed(author):
334 349 '''Return True if the author field is well formed
335 350 (ie "Contributor Name <contrib@email.dom>")
336 351
337 352 >>> isauthorwellformed(b'Good Author <good@author.com>')
338 353 True
339 354 >>> isauthorwellformed(b'Author <good@author.com>')
340 355 True
341 356 >>> isauthorwellformed(b'Bad Author')
342 357 False
343 358 >>> isauthorwellformed(b'Bad Author <author@author.com')
344 359 False
345 360 >>> isauthorwellformed(b'Bad Author author@author.com')
346 361 False
347 362 >>> isauthorwellformed(b'<author@author.com>')
348 363 False
349 364 >>> isauthorwellformed(b'Bad Author <author>')
350 365 False
351 366 '''
352 367 return _correctauthorformat.match(author) is not None
353 368
354 369 def ellipsis(text, maxlength=400):
355 370 """Trim string to at most maxlength (default: 400) columns in display."""
356 371 return encoding.trim(text, maxlength, ellipsis='...')
357 372
358 373 def escapestr(s):
359 374 # call underlying function of s.encode('string_escape') directly for
360 375 # Python 3 compatibility
361 376 return codecs.escape_encode(s)[0]
362 377
363 378 def unescapestr(s):
364 379 return codecs.escape_decode(s)[0]
365 380
366 381 def forcebytestr(obj):
367 382 """Portably format an arbitrary object (e.g. exception) into a byte
368 383 string."""
369 384 try:
370 385 return pycompat.bytestr(obj)
371 386 except UnicodeEncodeError:
372 387 # non-ascii string, may be lossy
373 388 return pycompat.bytestr(encoding.strtolocal(str(obj)))
374 389
375 390 def uirepr(s):
376 391 # Avoid double backslash in Windows path repr()
377 392 return pycompat.byterepr(pycompat.bytestr(s)).replace(b'\\\\', b'\\')
378 393
379 394 # delay import of textwrap
380 395 def _MBTextWrapper(**kwargs):
381 396 class tw(textwrap.TextWrapper):
382 397 """
383 398 Extend TextWrapper for width-awareness.
384 399
385 400 Neither number of 'bytes' in any encoding nor 'characters' is
386 401 appropriate to calculate terminal columns for specified string.
387 402
388 403 Original TextWrapper implementation uses built-in 'len()' directly,
389 404 so overriding is needed to use width information of each characters.
390 405
391 406 In addition, characters classified into 'ambiguous' width are
392 407 treated as wide in East Asian area, but as narrow in other.
393 408
394 409 This requires use decision to determine width of such characters.
395 410 """
396 411 def _cutdown(self, ucstr, space_left):
397 412 l = 0
398 413 colwidth = encoding.ucolwidth
399 414 for i in xrange(len(ucstr)):
400 415 l += colwidth(ucstr[i])
401 416 if space_left < l:
402 417 return (ucstr[:i], ucstr[i:])
403 418 return ucstr, ''
404 419
405 420 # overriding of base class
406 421 def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width):
407 422 space_left = max(width - cur_len, 1)
408 423
409 424 if self.break_long_words:
410 425 cut, res = self._cutdown(reversed_chunks[-1], space_left)
411 426 cur_line.append(cut)
412 427 reversed_chunks[-1] = res
413 428 elif not cur_line:
414 429 cur_line.append(reversed_chunks.pop())
415 430
416 431 # this overriding code is imported from TextWrapper of Python 2.6
417 432 # to calculate columns of string by 'encoding.ucolwidth()'
418 433 def _wrap_chunks(self, chunks):
419 434 colwidth = encoding.ucolwidth
420 435
421 436 lines = []
422 437 if self.width <= 0:
423 438 raise ValueError("invalid width %r (must be > 0)" % self.width)
424 439
425 440 # Arrange in reverse order so items can be efficiently popped
426 441 # from a stack of chucks.
427 442 chunks.reverse()
428 443
429 444 while chunks:
430 445
431 446 # Start the list of chunks that will make up the current line.
432 447 # cur_len is just the length of all the chunks in cur_line.
433 448 cur_line = []
434 449 cur_len = 0
435 450
436 451 # Figure out which static string will prefix this line.
437 452 if lines:
438 453 indent = self.subsequent_indent
439 454 else:
440 455 indent = self.initial_indent
441 456
442 457 # Maximum width for this line.
443 458 width = self.width - len(indent)
444 459
445 460 # First chunk on line is whitespace -- drop it, unless this
446 461 # is the very beginning of the text (i.e. no lines started yet).
447 462 if self.drop_whitespace and chunks[-1].strip() == r'' and lines:
448 463 del chunks[-1]
449 464
450 465 while chunks:
451 466 l = colwidth(chunks[-1])
452 467
453 468 # Can at least squeeze this chunk onto the current line.
454 469 if cur_len + l <= width:
455 470 cur_line.append(chunks.pop())
456 471 cur_len += l
457 472
458 473 # Nope, this line is full.
459 474 else:
460 475 break
461 476
462 477 # The current line is full, and the next chunk is too big to
463 478 # fit on *any* line (not just this one).
464 479 if chunks and colwidth(chunks[-1]) > width:
465 480 self._handle_long_word(chunks, cur_line, cur_len, width)
466 481
467 482 # If the last chunk on this line is all whitespace, drop it.
468 483 if (self.drop_whitespace and
469 484 cur_line and cur_line[-1].strip() == r''):
470 485 del cur_line[-1]
471 486
472 487 # Convert current line back to a string and store it in list
473 488 # of all lines (return value).
474 489 if cur_line:
475 490 lines.append(indent + r''.join(cur_line))
476 491
477 492 return lines
478 493
479 494 global _MBTextWrapper
480 495 _MBTextWrapper = tw
481 496 return tw(**kwargs)
482 497
483 498 def wrap(line, width, initindent='', hangindent=''):
484 499 maxindent = max(len(hangindent), len(initindent))
485 500 if width <= maxindent:
486 501 # adjust for weird terminal size
487 502 width = max(78, maxindent + 1)
488 503 line = line.decode(pycompat.sysstr(encoding.encoding),
489 504 pycompat.sysstr(encoding.encodingmode))
490 505 initindent = initindent.decode(pycompat.sysstr(encoding.encoding),
491 506 pycompat.sysstr(encoding.encodingmode))
492 507 hangindent = hangindent.decode(pycompat.sysstr(encoding.encoding),
493 508 pycompat.sysstr(encoding.encodingmode))
494 509 wrapper = _MBTextWrapper(width=width,
495 510 initial_indent=initindent,
496 511 subsequent_indent=hangindent)
497 512 return wrapper.fill(line).encode(pycompat.sysstr(encoding.encoding))
498 513
499 514 _booleans = {'1': True, 'yes': True, 'true': True, 'on': True, 'always': True,
500 515 '0': False, 'no': False, 'false': False, 'off': False,
501 516 'never': False}
502 517
503 518 def parsebool(s):
504 519 """Parse s into a boolean.
505 520
506 521 If s is not a valid boolean, returns None.
507 522 """
508 523 return _booleans.get(s.lower(), None)
509 524
510 525 def evalpythonliteral(s):
511 526 """Evaluate a string containing a Python literal expression"""
512 527 # We could backport our tokenizer hack to rewrite '' to u'' if we want
513 528 if pycompat.ispy3:
514 529 return ast.literal_eval(s.decode('latin1'))
515 530 return ast.literal_eval(s)
@@ -1,3487 +1,3488 b''
1 1 @ (34) head
2 2 |
3 3 | o (33) head
4 4 | |
5 5 o | (32) expand
6 6 |\ \
7 7 | o \ (31) expand
8 8 | |\ \
9 9 | | o \ (30) expand
10 10 | | |\ \
11 11 | | | o | (29) regular commit
12 12 | | | | |
13 13 | | o | | (28) merge zero known
14 14 | | |\ \ \
15 15 o | | | | | (27) collapse
16 16 |/ / / / /
17 17 | | o---+ (26) merge one known; far right
18 18 | | | | |
19 19 +---o | | (25) merge one known; far left
20 20 | | | | |
21 21 | | o | | (24) merge one known; immediate right
22 22 | | |\| |
23 23 | | o | | (23) merge one known; immediate left
24 24 | |/| | |
25 25 +---o---+ (22) merge two known; one far left, one far right
26 26 | | / /
27 27 o | | | (21) expand
28 28 |\ \ \ \
29 29 | o---+-+ (20) merge two known; two far right
30 30 | / / /
31 31 o | | | (19) expand
32 32 |\ \ \ \
33 33 +---+---o (18) merge two known; two far left
34 34 | | | |
35 35 | o | | (17) expand
36 36 | |\ \ \
37 37 | | o---+ (16) merge two known; one immediate right, one near right
38 38 | | |/ /
39 39 o | | | (15) expand
40 40 |\ \ \ \
41 41 | o-----+ (14) merge two known; one immediate right, one far right
42 42 | |/ / /
43 43 o | | | (13) expand
44 44 |\ \ \ \
45 45 +---o | | (12) merge two known; one immediate right, one far left
46 46 | | |/ /
47 47 | o | | (11) expand
48 48 | |\ \ \
49 49 | | o---+ (10) merge two known; one immediate left, one near right
50 50 | |/ / /
51 51 o | | | (9) expand
52 52 |\ \ \ \
53 53 | o-----+ (8) merge two known; one immediate left, one far right
54 54 |/ / / /
55 55 o | | | (7) expand
56 56 |\ \ \ \
57 57 +---o | | (6) merge two known; one immediate left, one far left
58 58 | |/ / /
59 59 | o | | (5) expand
60 60 | |\ \ \
61 61 | | o | | (4) merge two known; one immediate left, one immediate right
62 62 | |/|/ /
63 63 | o / / (3) collapse
64 64 |/ / /
65 65 o / / (2) collapse
66 66 |/ /
67 67 o / (1) collapse
68 68 |/
69 69 o (0) root
70 70
71 71
72 72 $ commit()
73 73 > {
74 74 > rev=$1
75 75 > msg=$2
76 76 > shift 2
77 77 > if [ "$#" -gt 0 ]; then
78 78 > hg debugsetparents "$@"
79 79 > fi
80 80 > echo $rev > a
81 81 > hg commit -Aqd "$rev 0" -m "($rev) $msg"
82 82 > }
83 83
84 84 $ cat > printrevset.py <<EOF
85 85 > from __future__ import absolute_import
86 86 > from mercurial import (
87 87 > cmdutil,
88 88 > commands,
89 89 > extensions,
90 90 > logcmdutil,
91 91 > revsetlang,
92 92 > smartset,
93 93 > )
94 > from mercurial.utils import stringutil
94 95 >
95 96 > def logrevset(repo, pats, opts):
96 97 > revs = logcmdutil._initialrevs(repo, opts)
97 98 > if not revs:
98 99 > return None
99 100 > match, pats, slowpath = logcmdutil._makematcher(repo, revs, pats, opts)
100 101 > return logcmdutil._makerevset(repo, match, pats, slowpath, opts)
101 102 >
102 103 > def uisetup(ui):
103 104 > def printrevset(orig, repo, pats, opts):
104 105 > revs, filematcher = orig(repo, pats, opts)
105 106 > if opts.get(b'print_revset'):
106 107 > expr = logrevset(repo, pats, opts)
107 108 > if expr:
108 109 > tree = revsetlang.parse(expr)
109 110 > tree = revsetlang.analyze(tree)
110 111 > else:
111 112 > tree = []
112 113 > ui = repo.ui
113 114 > ui.write(b'%r\n' % (opts.get(b'rev', []),))
114 115 > ui.write(revsetlang.prettyformat(tree) + b'\n')
115 > ui.write(smartset.prettyformat(revs) + b'\n')
116 > ui.write(stringutil.prettyrepr(revs) + b'\n')
116 117 > revs = smartset.baseset() # display no revisions
117 118 > return revs, filematcher
118 119 > extensions.wrapfunction(logcmdutil, 'getrevs', printrevset)
119 120 > aliases, entry = cmdutil.findcmd(b'log', commands.table)
120 121 > entry[1].append((b'', b'print-revset', False,
121 122 > b'print generated revset and exit (DEPRECATED)'))
122 123 > EOF
123 124
124 125 $ echo "[extensions]" >> $HGRCPATH
125 126 $ echo "printrevset=`pwd`/printrevset.py" >> $HGRCPATH
126 127
127 128 $ hg init repo
128 129 $ cd repo
129 130
130 131 Empty repo:
131 132
132 133 $ hg log -G
133 134
134 135
135 136 Building DAG:
136 137
137 138 $ commit 0 "root"
138 139 $ commit 1 "collapse" 0
139 140 $ commit 2 "collapse" 1
140 141 $ commit 3 "collapse" 2
141 142 $ commit 4 "merge two known; one immediate left, one immediate right" 1 3
142 143 $ commit 5 "expand" 3 4
143 144 $ commit 6 "merge two known; one immediate left, one far left" 2 5
144 145 $ commit 7 "expand" 2 5
145 146 $ commit 8 "merge two known; one immediate left, one far right" 0 7
146 147 $ commit 9 "expand" 7 8
147 148 $ commit 10 "merge two known; one immediate left, one near right" 0 6
148 149 $ commit 11 "expand" 6 10
149 150 $ commit 12 "merge two known; one immediate right, one far left" 1 9
150 151 $ commit 13 "expand" 9 11
151 152 $ commit 14 "merge two known; one immediate right, one far right" 0 12
152 153 $ commit 15 "expand" 13 14
153 154 $ commit 16 "merge two known; one immediate right, one near right" 0 1
154 155 $ commit 17 "expand" 12 16
155 156 $ commit 18 "merge two known; two far left" 1 15
156 157 $ commit 19 "expand" 15 17
157 158 $ commit 20 "merge two known; two far right" 0 18
158 159 $ commit 21 "expand" 19 20
159 160 $ commit 22 "merge two known; one far left, one far right" 18 21
160 161 $ commit 23 "merge one known; immediate left" 1 22
161 162 $ commit 24 "merge one known; immediate right" 0 23
162 163 $ commit 25 "merge one known; far left" 21 24
163 164 $ commit 26 "merge one known; far right" 18 25
164 165 $ commit 27 "collapse" 21
165 166 $ commit 28 "merge zero known" 1 26
166 167 $ commit 29 "regular commit" 0
167 168 $ commit 30 "expand" 28 29
168 169 $ commit 31 "expand" 21 30
169 170 $ commit 32 "expand" 27 31
170 171 $ commit 33 "head" 18
171 172 $ commit 34 "head" 32
172 173
173 174
174 175 $ hg log -G -q
175 176 @ 34:fea3ac5810e0
176 177 |
177 178 | o 33:68608f5145f9
178 179 | |
179 180 o | 32:d06dffa21a31
180 181 |\ \
181 182 | o \ 31:621d83e11f67
182 183 | |\ \
183 184 | | o \ 30:6e11cd4b648f
184 185 | | |\ \
185 186 | | | o | 29:cd9bb2be7593
186 187 | | | | |
187 188 | | o | | 28:44ecd0b9ae99
188 189 | | |\ \ \
189 190 o | | | | | 27:886ed638191b
190 191 |/ / / / /
191 192 | | o---+ 26:7f25b6c2f0b9
192 193 | | | | |
193 194 +---o | | 25:91da8ed57247
194 195 | | | | |
195 196 | | o | | 24:a9c19a3d96b7
196 197 | | |\| |
197 198 | | o | | 23:a01cddf0766d
198 199 | |/| | |
199 200 +---o---+ 22:e0d9cccacb5d
200 201 | | / /
201 202 o | | | 21:d42a756af44d
202 203 |\ \ \ \
203 204 | o---+-+ 20:d30ed6450e32
204 205 | / / /
205 206 o | | | 19:31ddc2c1573b
206 207 |\ \ \ \
207 208 +---+---o 18:1aa84d96232a
208 209 | | | |
209 210 | o | | 17:44765d7c06e0
210 211 | |\ \ \
211 212 | | o---+ 16:3677d192927d
212 213 | | |/ /
213 214 o | | | 15:1dda3f72782d
214 215 |\ \ \ \
215 216 | o-----+ 14:8eac370358ef
216 217 | |/ / /
217 218 o | | | 13:22d8966a97e3
218 219 |\ \ \ \
219 220 +---o | | 12:86b91144a6e9
220 221 | | |/ /
221 222 | o | | 11:832d76e6bdf2
222 223 | |\ \ \
223 224 | | o---+ 10:74c64d036d72
224 225 | |/ / /
225 226 o | | | 9:7010c0af0a35
226 227 |\ \ \ \
227 228 | o-----+ 8:7a0b11f71937
228 229 |/ / / /
229 230 o | | | 7:b632bb1b1224
230 231 |\ \ \ \
231 232 +---o | | 6:b105a072e251
232 233 | |/ / /
233 234 | o | | 5:4409d547b708
234 235 | |\ \ \
235 236 | | o | | 4:26a8bac39d9f
236 237 | |/|/ /
237 238 | o / / 3:27eef8ed80b4
238 239 |/ / /
239 240 o / / 2:3d9a33b8d1e1
240 241 |/ /
241 242 o / 1:6db2ef61d156
242 243 |/
243 244 o 0:e6eb3150255d
244 245
245 246
246 247 $ hg log -G
247 248 @ changeset: 34:fea3ac5810e0
248 249 | tag: tip
249 250 | parent: 32:d06dffa21a31
250 251 | user: test
251 252 | date: Thu Jan 01 00:00:34 1970 +0000
252 253 | summary: (34) head
253 254 |
254 255 | o changeset: 33:68608f5145f9
255 256 | | parent: 18:1aa84d96232a
256 257 | | user: test
257 258 | | date: Thu Jan 01 00:00:33 1970 +0000
258 259 | | summary: (33) head
259 260 | |
260 261 o | changeset: 32:d06dffa21a31
261 262 |\ \ parent: 27:886ed638191b
262 263 | | | parent: 31:621d83e11f67
263 264 | | | user: test
264 265 | | | date: Thu Jan 01 00:00:32 1970 +0000
265 266 | | | summary: (32) expand
266 267 | | |
267 268 | o | changeset: 31:621d83e11f67
268 269 | |\ \ parent: 21:d42a756af44d
269 270 | | | | parent: 30:6e11cd4b648f
270 271 | | | | user: test
271 272 | | | | date: Thu Jan 01 00:00:31 1970 +0000
272 273 | | | | summary: (31) expand
273 274 | | | |
274 275 | | o | changeset: 30:6e11cd4b648f
275 276 | | |\ \ parent: 28:44ecd0b9ae99
276 277 | | | | | parent: 29:cd9bb2be7593
277 278 | | | | | user: test
278 279 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
279 280 | | | | | summary: (30) expand
280 281 | | | | |
281 282 | | | o | changeset: 29:cd9bb2be7593
282 283 | | | | | parent: 0:e6eb3150255d
283 284 | | | | | user: test
284 285 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
285 286 | | | | | summary: (29) regular commit
286 287 | | | | |
287 288 | | o | | changeset: 28:44ecd0b9ae99
288 289 | | |\ \ \ parent: 1:6db2ef61d156
289 290 | | | | | | parent: 26:7f25b6c2f0b9
290 291 | | | | | | user: test
291 292 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
292 293 | | | | | | summary: (28) merge zero known
293 294 | | | | | |
294 295 o | | | | | changeset: 27:886ed638191b
295 296 |/ / / / / parent: 21:d42a756af44d
296 297 | | | | | user: test
297 298 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
298 299 | | | | | summary: (27) collapse
299 300 | | | | |
300 301 | | o---+ changeset: 26:7f25b6c2f0b9
301 302 | | | | | parent: 18:1aa84d96232a
302 303 | | | | | parent: 25:91da8ed57247
303 304 | | | | | user: test
304 305 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
305 306 | | | | | summary: (26) merge one known; far right
306 307 | | | | |
307 308 +---o | | changeset: 25:91da8ed57247
308 309 | | | | | parent: 21:d42a756af44d
309 310 | | | | | parent: 24:a9c19a3d96b7
310 311 | | | | | user: test
311 312 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
312 313 | | | | | summary: (25) merge one known; far left
313 314 | | | | |
314 315 | | o | | changeset: 24:a9c19a3d96b7
315 316 | | |\| | parent: 0:e6eb3150255d
316 317 | | | | | parent: 23:a01cddf0766d
317 318 | | | | | user: test
318 319 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
319 320 | | | | | summary: (24) merge one known; immediate right
320 321 | | | | |
321 322 | | o | | changeset: 23:a01cddf0766d
322 323 | |/| | | parent: 1:6db2ef61d156
323 324 | | | | | parent: 22:e0d9cccacb5d
324 325 | | | | | user: test
325 326 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
326 327 | | | | | summary: (23) merge one known; immediate left
327 328 | | | | |
328 329 +---o---+ changeset: 22:e0d9cccacb5d
329 330 | | | | parent: 18:1aa84d96232a
330 331 | | / / parent: 21:d42a756af44d
331 332 | | | | user: test
332 333 | | | | date: Thu Jan 01 00:00:22 1970 +0000
333 334 | | | | summary: (22) merge two known; one far left, one far right
334 335 | | | |
335 336 o | | | changeset: 21:d42a756af44d
336 337 |\ \ \ \ parent: 19:31ddc2c1573b
337 338 | | | | | parent: 20:d30ed6450e32
338 339 | | | | | user: test
339 340 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
340 341 | | | | | summary: (21) expand
341 342 | | | | |
342 343 | o---+-+ changeset: 20:d30ed6450e32
343 344 | | | | parent: 0:e6eb3150255d
344 345 | / / / parent: 18:1aa84d96232a
345 346 | | | | user: test
346 347 | | | | date: Thu Jan 01 00:00:20 1970 +0000
347 348 | | | | summary: (20) merge two known; two far right
348 349 | | | |
349 350 o | | | changeset: 19:31ddc2c1573b
350 351 |\ \ \ \ parent: 15:1dda3f72782d
351 352 | | | | | parent: 17:44765d7c06e0
352 353 | | | | | user: test
353 354 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
354 355 | | | | | summary: (19) expand
355 356 | | | | |
356 357 +---+---o changeset: 18:1aa84d96232a
357 358 | | | | parent: 1:6db2ef61d156
358 359 | | | | parent: 15:1dda3f72782d
359 360 | | | | user: test
360 361 | | | | date: Thu Jan 01 00:00:18 1970 +0000
361 362 | | | | summary: (18) merge two known; two far left
362 363 | | | |
363 364 | o | | changeset: 17:44765d7c06e0
364 365 | |\ \ \ parent: 12:86b91144a6e9
365 366 | | | | | parent: 16:3677d192927d
366 367 | | | | | user: test
367 368 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
368 369 | | | | | summary: (17) expand
369 370 | | | | |
370 371 | | o---+ changeset: 16:3677d192927d
371 372 | | | | | parent: 0:e6eb3150255d
372 373 | | |/ / parent: 1:6db2ef61d156
373 374 | | | | user: test
374 375 | | | | date: Thu Jan 01 00:00:16 1970 +0000
375 376 | | | | summary: (16) merge two known; one immediate right, one near right
376 377 | | | |
377 378 o | | | changeset: 15:1dda3f72782d
378 379 |\ \ \ \ parent: 13:22d8966a97e3
379 380 | | | | | parent: 14:8eac370358ef
380 381 | | | | | user: test
381 382 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
382 383 | | | | | summary: (15) expand
383 384 | | | | |
384 385 | o-----+ changeset: 14:8eac370358ef
385 386 | | | | | parent: 0:e6eb3150255d
386 387 | |/ / / parent: 12:86b91144a6e9
387 388 | | | | user: test
388 389 | | | | date: Thu Jan 01 00:00:14 1970 +0000
389 390 | | | | summary: (14) merge two known; one immediate right, one far right
390 391 | | | |
391 392 o | | | changeset: 13:22d8966a97e3
392 393 |\ \ \ \ parent: 9:7010c0af0a35
393 394 | | | | | parent: 11:832d76e6bdf2
394 395 | | | | | user: test
395 396 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
396 397 | | | | | summary: (13) expand
397 398 | | | | |
398 399 +---o | | changeset: 12:86b91144a6e9
399 400 | | |/ / parent: 1:6db2ef61d156
400 401 | | | | parent: 9:7010c0af0a35
401 402 | | | | user: test
402 403 | | | | date: Thu Jan 01 00:00:12 1970 +0000
403 404 | | | | summary: (12) merge two known; one immediate right, one far left
404 405 | | | |
405 406 | o | | changeset: 11:832d76e6bdf2
406 407 | |\ \ \ parent: 6:b105a072e251
407 408 | | | | | parent: 10:74c64d036d72
408 409 | | | | | user: test
409 410 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
410 411 | | | | | summary: (11) expand
411 412 | | | | |
412 413 | | o---+ changeset: 10:74c64d036d72
413 414 | | | | | parent: 0:e6eb3150255d
414 415 | |/ / / parent: 6:b105a072e251
415 416 | | | | user: test
416 417 | | | | date: Thu Jan 01 00:00:10 1970 +0000
417 418 | | | | summary: (10) merge two known; one immediate left, one near right
418 419 | | | |
419 420 o | | | changeset: 9:7010c0af0a35
420 421 |\ \ \ \ parent: 7:b632bb1b1224
421 422 | | | | | parent: 8:7a0b11f71937
422 423 | | | | | user: test
423 424 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
424 425 | | | | | summary: (9) expand
425 426 | | | | |
426 427 | o-----+ changeset: 8:7a0b11f71937
427 428 | | | | | parent: 0:e6eb3150255d
428 429 |/ / / / parent: 7:b632bb1b1224
429 430 | | | | user: test
430 431 | | | | date: Thu Jan 01 00:00:08 1970 +0000
431 432 | | | | summary: (8) merge two known; one immediate left, one far right
432 433 | | | |
433 434 o | | | changeset: 7:b632bb1b1224
434 435 |\ \ \ \ parent: 2:3d9a33b8d1e1
435 436 | | | | | parent: 5:4409d547b708
436 437 | | | | | user: test
437 438 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
438 439 | | | | | summary: (7) expand
439 440 | | | | |
440 441 +---o | | changeset: 6:b105a072e251
441 442 | |/ / / parent: 2:3d9a33b8d1e1
442 443 | | | | parent: 5:4409d547b708
443 444 | | | | user: test
444 445 | | | | date: Thu Jan 01 00:00:06 1970 +0000
445 446 | | | | summary: (6) merge two known; one immediate left, one far left
446 447 | | | |
447 448 | o | | changeset: 5:4409d547b708
448 449 | |\ \ \ parent: 3:27eef8ed80b4
449 450 | | | | | parent: 4:26a8bac39d9f
450 451 | | | | | user: test
451 452 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
452 453 | | | | | summary: (5) expand
453 454 | | | | |
454 455 | | o | | changeset: 4:26a8bac39d9f
455 456 | |/|/ / parent: 1:6db2ef61d156
456 457 | | | | parent: 3:27eef8ed80b4
457 458 | | | | user: test
458 459 | | | | date: Thu Jan 01 00:00:04 1970 +0000
459 460 | | | | summary: (4) merge two known; one immediate left, one immediate right
460 461 | | | |
461 462 | o | | changeset: 3:27eef8ed80b4
462 463 |/ / / user: test
463 464 | | | date: Thu Jan 01 00:00:03 1970 +0000
464 465 | | | summary: (3) collapse
465 466 | | |
466 467 o | | changeset: 2:3d9a33b8d1e1
467 468 |/ / user: test
468 469 | | date: Thu Jan 01 00:00:02 1970 +0000
469 470 | | summary: (2) collapse
470 471 | |
471 472 o | changeset: 1:6db2ef61d156
472 473 |/ user: test
473 474 | date: Thu Jan 01 00:00:01 1970 +0000
474 475 | summary: (1) collapse
475 476 |
476 477 o changeset: 0:e6eb3150255d
477 478 user: test
478 479 date: Thu Jan 01 00:00:00 1970 +0000
479 480 summary: (0) root
480 481
481 482
482 483 File glog:
483 484 $ hg log -G a
484 485 @ changeset: 34:fea3ac5810e0
485 486 | tag: tip
486 487 | parent: 32:d06dffa21a31
487 488 | user: test
488 489 | date: Thu Jan 01 00:00:34 1970 +0000
489 490 | summary: (34) head
490 491 |
491 492 | o changeset: 33:68608f5145f9
492 493 | | parent: 18:1aa84d96232a
493 494 | | user: test
494 495 | | date: Thu Jan 01 00:00:33 1970 +0000
495 496 | | summary: (33) head
496 497 | |
497 498 o | changeset: 32:d06dffa21a31
498 499 |\ \ parent: 27:886ed638191b
499 500 | | | parent: 31:621d83e11f67
500 501 | | | user: test
501 502 | | | date: Thu Jan 01 00:00:32 1970 +0000
502 503 | | | summary: (32) expand
503 504 | | |
504 505 | o | changeset: 31:621d83e11f67
505 506 | |\ \ parent: 21:d42a756af44d
506 507 | | | | parent: 30:6e11cd4b648f
507 508 | | | | user: test
508 509 | | | | date: Thu Jan 01 00:00:31 1970 +0000
509 510 | | | | summary: (31) expand
510 511 | | | |
511 512 | | o | changeset: 30:6e11cd4b648f
512 513 | | |\ \ parent: 28:44ecd0b9ae99
513 514 | | | | | parent: 29:cd9bb2be7593
514 515 | | | | | user: test
515 516 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
516 517 | | | | | summary: (30) expand
517 518 | | | | |
518 519 | | | o | changeset: 29:cd9bb2be7593
519 520 | | | | | parent: 0:e6eb3150255d
520 521 | | | | | user: test
521 522 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
522 523 | | | | | summary: (29) regular commit
523 524 | | | | |
524 525 | | o | | changeset: 28:44ecd0b9ae99
525 526 | | |\ \ \ parent: 1:6db2ef61d156
526 527 | | | | | | parent: 26:7f25b6c2f0b9
527 528 | | | | | | user: test
528 529 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
529 530 | | | | | | summary: (28) merge zero known
530 531 | | | | | |
531 532 o | | | | | changeset: 27:886ed638191b
532 533 |/ / / / / parent: 21:d42a756af44d
533 534 | | | | | user: test
534 535 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
535 536 | | | | | summary: (27) collapse
536 537 | | | | |
537 538 | | o---+ changeset: 26:7f25b6c2f0b9
538 539 | | | | | parent: 18:1aa84d96232a
539 540 | | | | | parent: 25:91da8ed57247
540 541 | | | | | user: test
541 542 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
542 543 | | | | | summary: (26) merge one known; far right
543 544 | | | | |
544 545 +---o | | changeset: 25:91da8ed57247
545 546 | | | | | parent: 21:d42a756af44d
546 547 | | | | | parent: 24:a9c19a3d96b7
547 548 | | | | | user: test
548 549 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
549 550 | | | | | summary: (25) merge one known; far left
550 551 | | | | |
551 552 | | o | | changeset: 24:a9c19a3d96b7
552 553 | | |\| | parent: 0:e6eb3150255d
553 554 | | | | | parent: 23:a01cddf0766d
554 555 | | | | | user: test
555 556 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
556 557 | | | | | summary: (24) merge one known; immediate right
557 558 | | | | |
558 559 | | o | | changeset: 23:a01cddf0766d
559 560 | |/| | | parent: 1:6db2ef61d156
560 561 | | | | | parent: 22:e0d9cccacb5d
561 562 | | | | | user: test
562 563 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
563 564 | | | | | summary: (23) merge one known; immediate left
564 565 | | | | |
565 566 +---o---+ changeset: 22:e0d9cccacb5d
566 567 | | | | parent: 18:1aa84d96232a
567 568 | | / / parent: 21:d42a756af44d
568 569 | | | | user: test
569 570 | | | | date: Thu Jan 01 00:00:22 1970 +0000
570 571 | | | | summary: (22) merge two known; one far left, one far right
571 572 | | | |
572 573 o | | | changeset: 21:d42a756af44d
573 574 |\ \ \ \ parent: 19:31ddc2c1573b
574 575 | | | | | parent: 20:d30ed6450e32
575 576 | | | | | user: test
576 577 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
577 578 | | | | | summary: (21) expand
578 579 | | | | |
579 580 | o---+-+ changeset: 20:d30ed6450e32
580 581 | | | | parent: 0:e6eb3150255d
581 582 | / / / parent: 18:1aa84d96232a
582 583 | | | | user: test
583 584 | | | | date: Thu Jan 01 00:00:20 1970 +0000
584 585 | | | | summary: (20) merge two known; two far right
585 586 | | | |
586 587 o | | | changeset: 19:31ddc2c1573b
587 588 |\ \ \ \ parent: 15:1dda3f72782d
588 589 | | | | | parent: 17:44765d7c06e0
589 590 | | | | | user: test
590 591 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
591 592 | | | | | summary: (19) expand
592 593 | | | | |
593 594 +---+---o changeset: 18:1aa84d96232a
594 595 | | | | parent: 1:6db2ef61d156
595 596 | | | | parent: 15:1dda3f72782d
596 597 | | | | user: test
597 598 | | | | date: Thu Jan 01 00:00:18 1970 +0000
598 599 | | | | summary: (18) merge two known; two far left
599 600 | | | |
600 601 | o | | changeset: 17:44765d7c06e0
601 602 | |\ \ \ parent: 12:86b91144a6e9
602 603 | | | | | parent: 16:3677d192927d
603 604 | | | | | user: test
604 605 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
605 606 | | | | | summary: (17) expand
606 607 | | | | |
607 608 | | o---+ changeset: 16:3677d192927d
608 609 | | | | | parent: 0:e6eb3150255d
609 610 | | |/ / parent: 1:6db2ef61d156
610 611 | | | | user: test
611 612 | | | | date: Thu Jan 01 00:00:16 1970 +0000
612 613 | | | | summary: (16) merge two known; one immediate right, one near right
613 614 | | | |
614 615 o | | | changeset: 15:1dda3f72782d
615 616 |\ \ \ \ parent: 13:22d8966a97e3
616 617 | | | | | parent: 14:8eac370358ef
617 618 | | | | | user: test
618 619 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
619 620 | | | | | summary: (15) expand
620 621 | | | | |
621 622 | o-----+ changeset: 14:8eac370358ef
622 623 | | | | | parent: 0:e6eb3150255d
623 624 | |/ / / parent: 12:86b91144a6e9
624 625 | | | | user: test
625 626 | | | | date: Thu Jan 01 00:00:14 1970 +0000
626 627 | | | | summary: (14) merge two known; one immediate right, one far right
627 628 | | | |
628 629 o | | | changeset: 13:22d8966a97e3
629 630 |\ \ \ \ parent: 9:7010c0af0a35
630 631 | | | | | parent: 11:832d76e6bdf2
631 632 | | | | | user: test
632 633 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
633 634 | | | | | summary: (13) expand
634 635 | | | | |
635 636 +---o | | changeset: 12:86b91144a6e9
636 637 | | |/ / parent: 1:6db2ef61d156
637 638 | | | | parent: 9:7010c0af0a35
638 639 | | | | user: test
639 640 | | | | date: Thu Jan 01 00:00:12 1970 +0000
640 641 | | | | summary: (12) merge two known; one immediate right, one far left
641 642 | | | |
642 643 | o | | changeset: 11:832d76e6bdf2
643 644 | |\ \ \ parent: 6:b105a072e251
644 645 | | | | | parent: 10:74c64d036d72
645 646 | | | | | user: test
646 647 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
647 648 | | | | | summary: (11) expand
648 649 | | | | |
649 650 | | o---+ changeset: 10:74c64d036d72
650 651 | | | | | parent: 0:e6eb3150255d
651 652 | |/ / / parent: 6:b105a072e251
652 653 | | | | user: test
653 654 | | | | date: Thu Jan 01 00:00:10 1970 +0000
654 655 | | | | summary: (10) merge two known; one immediate left, one near right
655 656 | | | |
656 657 o | | | changeset: 9:7010c0af0a35
657 658 |\ \ \ \ parent: 7:b632bb1b1224
658 659 | | | | | parent: 8:7a0b11f71937
659 660 | | | | | user: test
660 661 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
661 662 | | | | | summary: (9) expand
662 663 | | | | |
663 664 | o-----+ changeset: 8:7a0b11f71937
664 665 | | | | | parent: 0:e6eb3150255d
665 666 |/ / / / parent: 7:b632bb1b1224
666 667 | | | | user: test
667 668 | | | | date: Thu Jan 01 00:00:08 1970 +0000
668 669 | | | | summary: (8) merge two known; one immediate left, one far right
669 670 | | | |
670 671 o | | | changeset: 7:b632bb1b1224
671 672 |\ \ \ \ parent: 2:3d9a33b8d1e1
672 673 | | | | | parent: 5:4409d547b708
673 674 | | | | | user: test
674 675 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
675 676 | | | | | summary: (7) expand
676 677 | | | | |
677 678 +---o | | changeset: 6:b105a072e251
678 679 | |/ / / parent: 2:3d9a33b8d1e1
679 680 | | | | parent: 5:4409d547b708
680 681 | | | | user: test
681 682 | | | | date: Thu Jan 01 00:00:06 1970 +0000
682 683 | | | | summary: (6) merge two known; one immediate left, one far left
683 684 | | | |
684 685 | o | | changeset: 5:4409d547b708
685 686 | |\ \ \ parent: 3:27eef8ed80b4
686 687 | | | | | parent: 4:26a8bac39d9f
687 688 | | | | | user: test
688 689 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
689 690 | | | | | summary: (5) expand
690 691 | | | | |
691 692 | | o | | changeset: 4:26a8bac39d9f
692 693 | |/|/ / parent: 1:6db2ef61d156
693 694 | | | | parent: 3:27eef8ed80b4
694 695 | | | | user: test
695 696 | | | | date: Thu Jan 01 00:00:04 1970 +0000
696 697 | | | | summary: (4) merge two known; one immediate left, one immediate right
697 698 | | | |
698 699 | o | | changeset: 3:27eef8ed80b4
699 700 |/ / / user: test
700 701 | | | date: Thu Jan 01 00:00:03 1970 +0000
701 702 | | | summary: (3) collapse
702 703 | | |
703 704 o | | changeset: 2:3d9a33b8d1e1
704 705 |/ / user: test
705 706 | | date: Thu Jan 01 00:00:02 1970 +0000
706 707 | | summary: (2) collapse
707 708 | |
708 709 o | changeset: 1:6db2ef61d156
709 710 |/ user: test
710 711 | date: Thu Jan 01 00:00:01 1970 +0000
711 712 | summary: (1) collapse
712 713 |
713 714 o changeset: 0:e6eb3150255d
714 715 user: test
715 716 date: Thu Jan 01 00:00:00 1970 +0000
716 717 summary: (0) root
717 718
718 719
719 720 File glog per revset:
720 721
721 722 $ hg log -G -r 'file("a")'
722 723 @ changeset: 34:fea3ac5810e0
723 724 | tag: tip
724 725 | parent: 32:d06dffa21a31
725 726 | user: test
726 727 | date: Thu Jan 01 00:00:34 1970 +0000
727 728 | summary: (34) head
728 729 |
729 730 | o changeset: 33:68608f5145f9
730 731 | | parent: 18:1aa84d96232a
731 732 | | user: test
732 733 | | date: Thu Jan 01 00:00:33 1970 +0000
733 734 | | summary: (33) head
734 735 | |
735 736 o | changeset: 32:d06dffa21a31
736 737 |\ \ parent: 27:886ed638191b
737 738 | | | parent: 31:621d83e11f67
738 739 | | | user: test
739 740 | | | date: Thu Jan 01 00:00:32 1970 +0000
740 741 | | | summary: (32) expand
741 742 | | |
742 743 | o | changeset: 31:621d83e11f67
743 744 | |\ \ parent: 21:d42a756af44d
744 745 | | | | parent: 30:6e11cd4b648f
745 746 | | | | user: test
746 747 | | | | date: Thu Jan 01 00:00:31 1970 +0000
747 748 | | | | summary: (31) expand
748 749 | | | |
749 750 | | o | changeset: 30:6e11cd4b648f
750 751 | | |\ \ parent: 28:44ecd0b9ae99
751 752 | | | | | parent: 29:cd9bb2be7593
752 753 | | | | | user: test
753 754 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
754 755 | | | | | summary: (30) expand
755 756 | | | | |
756 757 | | | o | changeset: 29:cd9bb2be7593
757 758 | | | | | parent: 0:e6eb3150255d
758 759 | | | | | user: test
759 760 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
760 761 | | | | | summary: (29) regular commit
761 762 | | | | |
762 763 | | o | | changeset: 28:44ecd0b9ae99
763 764 | | |\ \ \ parent: 1:6db2ef61d156
764 765 | | | | | | parent: 26:7f25b6c2f0b9
765 766 | | | | | | user: test
766 767 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
767 768 | | | | | | summary: (28) merge zero known
768 769 | | | | | |
769 770 o | | | | | changeset: 27:886ed638191b
770 771 |/ / / / / parent: 21:d42a756af44d
771 772 | | | | | user: test
772 773 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
773 774 | | | | | summary: (27) collapse
774 775 | | | | |
775 776 | | o---+ changeset: 26:7f25b6c2f0b9
776 777 | | | | | parent: 18:1aa84d96232a
777 778 | | | | | parent: 25:91da8ed57247
778 779 | | | | | user: test
779 780 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
780 781 | | | | | summary: (26) merge one known; far right
781 782 | | | | |
782 783 +---o | | changeset: 25:91da8ed57247
783 784 | | | | | parent: 21:d42a756af44d
784 785 | | | | | parent: 24:a9c19a3d96b7
785 786 | | | | | user: test
786 787 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
787 788 | | | | | summary: (25) merge one known; far left
788 789 | | | | |
789 790 | | o | | changeset: 24:a9c19a3d96b7
790 791 | | |\| | parent: 0:e6eb3150255d
791 792 | | | | | parent: 23:a01cddf0766d
792 793 | | | | | user: test
793 794 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
794 795 | | | | | summary: (24) merge one known; immediate right
795 796 | | | | |
796 797 | | o | | changeset: 23:a01cddf0766d
797 798 | |/| | | parent: 1:6db2ef61d156
798 799 | | | | | parent: 22:e0d9cccacb5d
799 800 | | | | | user: test
800 801 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
801 802 | | | | | summary: (23) merge one known; immediate left
802 803 | | | | |
803 804 +---o---+ changeset: 22:e0d9cccacb5d
804 805 | | | | parent: 18:1aa84d96232a
805 806 | | / / parent: 21:d42a756af44d
806 807 | | | | user: test
807 808 | | | | date: Thu Jan 01 00:00:22 1970 +0000
808 809 | | | | summary: (22) merge two known; one far left, one far right
809 810 | | | |
810 811 o | | | changeset: 21:d42a756af44d
811 812 |\ \ \ \ parent: 19:31ddc2c1573b
812 813 | | | | | parent: 20:d30ed6450e32
813 814 | | | | | user: test
814 815 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
815 816 | | | | | summary: (21) expand
816 817 | | | | |
817 818 | o---+-+ changeset: 20:d30ed6450e32
818 819 | | | | parent: 0:e6eb3150255d
819 820 | / / / parent: 18:1aa84d96232a
820 821 | | | | user: test
821 822 | | | | date: Thu Jan 01 00:00:20 1970 +0000
822 823 | | | | summary: (20) merge two known; two far right
823 824 | | | |
824 825 o | | | changeset: 19:31ddc2c1573b
825 826 |\ \ \ \ parent: 15:1dda3f72782d
826 827 | | | | | parent: 17:44765d7c06e0
827 828 | | | | | user: test
828 829 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
829 830 | | | | | summary: (19) expand
830 831 | | | | |
831 832 +---+---o changeset: 18:1aa84d96232a
832 833 | | | | parent: 1:6db2ef61d156
833 834 | | | | parent: 15:1dda3f72782d
834 835 | | | | user: test
835 836 | | | | date: Thu Jan 01 00:00:18 1970 +0000
836 837 | | | | summary: (18) merge two known; two far left
837 838 | | | |
838 839 | o | | changeset: 17:44765d7c06e0
839 840 | |\ \ \ parent: 12:86b91144a6e9
840 841 | | | | | parent: 16:3677d192927d
841 842 | | | | | user: test
842 843 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
843 844 | | | | | summary: (17) expand
844 845 | | | | |
845 846 | | o---+ changeset: 16:3677d192927d
846 847 | | | | | parent: 0:e6eb3150255d
847 848 | | |/ / parent: 1:6db2ef61d156
848 849 | | | | user: test
849 850 | | | | date: Thu Jan 01 00:00:16 1970 +0000
850 851 | | | | summary: (16) merge two known; one immediate right, one near right
851 852 | | | |
852 853 o | | | changeset: 15:1dda3f72782d
853 854 |\ \ \ \ parent: 13:22d8966a97e3
854 855 | | | | | parent: 14:8eac370358ef
855 856 | | | | | user: test
856 857 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
857 858 | | | | | summary: (15) expand
858 859 | | | | |
859 860 | o-----+ changeset: 14:8eac370358ef
860 861 | | | | | parent: 0:e6eb3150255d
861 862 | |/ / / parent: 12:86b91144a6e9
862 863 | | | | user: test
863 864 | | | | date: Thu Jan 01 00:00:14 1970 +0000
864 865 | | | | summary: (14) merge two known; one immediate right, one far right
865 866 | | | |
866 867 o | | | changeset: 13:22d8966a97e3
867 868 |\ \ \ \ parent: 9:7010c0af0a35
868 869 | | | | | parent: 11:832d76e6bdf2
869 870 | | | | | user: test
870 871 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
871 872 | | | | | summary: (13) expand
872 873 | | | | |
873 874 +---o | | changeset: 12:86b91144a6e9
874 875 | | |/ / parent: 1:6db2ef61d156
875 876 | | | | parent: 9:7010c0af0a35
876 877 | | | | user: test
877 878 | | | | date: Thu Jan 01 00:00:12 1970 +0000
878 879 | | | | summary: (12) merge two known; one immediate right, one far left
879 880 | | | |
880 881 | o | | changeset: 11:832d76e6bdf2
881 882 | |\ \ \ parent: 6:b105a072e251
882 883 | | | | | parent: 10:74c64d036d72
883 884 | | | | | user: test
884 885 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
885 886 | | | | | summary: (11) expand
886 887 | | | | |
887 888 | | o---+ changeset: 10:74c64d036d72
888 889 | | | | | parent: 0:e6eb3150255d
889 890 | |/ / / parent: 6:b105a072e251
890 891 | | | | user: test
891 892 | | | | date: Thu Jan 01 00:00:10 1970 +0000
892 893 | | | | summary: (10) merge two known; one immediate left, one near right
893 894 | | | |
894 895 o | | | changeset: 9:7010c0af0a35
895 896 |\ \ \ \ parent: 7:b632bb1b1224
896 897 | | | | | parent: 8:7a0b11f71937
897 898 | | | | | user: test
898 899 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
899 900 | | | | | summary: (9) expand
900 901 | | | | |
901 902 | o-----+ changeset: 8:7a0b11f71937
902 903 | | | | | parent: 0:e6eb3150255d
903 904 |/ / / / parent: 7:b632bb1b1224
904 905 | | | | user: test
905 906 | | | | date: Thu Jan 01 00:00:08 1970 +0000
906 907 | | | | summary: (8) merge two known; one immediate left, one far right
907 908 | | | |
908 909 o | | | changeset: 7:b632bb1b1224
909 910 |\ \ \ \ parent: 2:3d9a33b8d1e1
910 911 | | | | | parent: 5:4409d547b708
911 912 | | | | | user: test
912 913 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
913 914 | | | | | summary: (7) expand
914 915 | | | | |
915 916 +---o | | changeset: 6:b105a072e251
916 917 | |/ / / parent: 2:3d9a33b8d1e1
917 918 | | | | parent: 5:4409d547b708
918 919 | | | | user: test
919 920 | | | | date: Thu Jan 01 00:00:06 1970 +0000
920 921 | | | | summary: (6) merge two known; one immediate left, one far left
921 922 | | | |
922 923 | o | | changeset: 5:4409d547b708
923 924 | |\ \ \ parent: 3:27eef8ed80b4
924 925 | | | | | parent: 4:26a8bac39d9f
925 926 | | | | | user: test
926 927 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
927 928 | | | | | summary: (5) expand
928 929 | | | | |
929 930 | | o | | changeset: 4:26a8bac39d9f
930 931 | |/|/ / parent: 1:6db2ef61d156
931 932 | | | | parent: 3:27eef8ed80b4
932 933 | | | | user: test
933 934 | | | | date: Thu Jan 01 00:00:04 1970 +0000
934 935 | | | | summary: (4) merge two known; one immediate left, one immediate right
935 936 | | | |
936 937 | o | | changeset: 3:27eef8ed80b4
937 938 |/ / / user: test
938 939 | | | date: Thu Jan 01 00:00:03 1970 +0000
939 940 | | | summary: (3) collapse
940 941 | | |
941 942 o | | changeset: 2:3d9a33b8d1e1
942 943 |/ / user: test
943 944 | | date: Thu Jan 01 00:00:02 1970 +0000
944 945 | | summary: (2) collapse
945 946 | |
946 947 o | changeset: 1:6db2ef61d156
947 948 |/ user: test
948 949 | date: Thu Jan 01 00:00:01 1970 +0000
949 950 | summary: (1) collapse
950 951 |
951 952 o changeset: 0:e6eb3150255d
952 953 user: test
953 954 date: Thu Jan 01 00:00:00 1970 +0000
954 955 summary: (0) root
955 956
956 957
957 958
958 959 File glog per revset (only merges):
959 960
960 961 $ hg log -G -r 'file("a")' -m
961 962 o changeset: 32:d06dffa21a31
962 963 |\ parent: 27:886ed638191b
963 964 | : parent: 31:621d83e11f67
964 965 | : user: test
965 966 | : date: Thu Jan 01 00:00:32 1970 +0000
966 967 | : summary: (32) expand
967 968 | :
968 969 o : changeset: 31:621d83e11f67
969 970 |\: parent: 21:d42a756af44d
970 971 | : parent: 30:6e11cd4b648f
971 972 | : user: test
972 973 | : date: Thu Jan 01 00:00:31 1970 +0000
973 974 | : summary: (31) expand
974 975 | :
975 976 o : changeset: 30:6e11cd4b648f
976 977 |\ \ parent: 28:44ecd0b9ae99
977 978 | ~ : parent: 29:cd9bb2be7593
978 979 | : user: test
979 980 | : date: Thu Jan 01 00:00:30 1970 +0000
980 981 | : summary: (30) expand
981 982 | /
982 983 o : changeset: 28:44ecd0b9ae99
983 984 |\ \ parent: 1:6db2ef61d156
984 985 | ~ : parent: 26:7f25b6c2f0b9
985 986 | : user: test
986 987 | : date: Thu Jan 01 00:00:28 1970 +0000
987 988 | : summary: (28) merge zero known
988 989 | /
989 990 o : changeset: 26:7f25b6c2f0b9
990 991 |\ \ parent: 18:1aa84d96232a
991 992 | | : parent: 25:91da8ed57247
992 993 | | : user: test
993 994 | | : date: Thu Jan 01 00:00:26 1970 +0000
994 995 | | : summary: (26) merge one known; far right
995 996 | | :
996 997 | o : changeset: 25:91da8ed57247
997 998 | |\: parent: 21:d42a756af44d
998 999 | | : parent: 24:a9c19a3d96b7
999 1000 | | : user: test
1000 1001 | | : date: Thu Jan 01 00:00:25 1970 +0000
1001 1002 | | : summary: (25) merge one known; far left
1002 1003 | | :
1003 1004 | o : changeset: 24:a9c19a3d96b7
1004 1005 | |\ \ parent: 0:e6eb3150255d
1005 1006 | | ~ : parent: 23:a01cddf0766d
1006 1007 | | : user: test
1007 1008 | | : date: Thu Jan 01 00:00:24 1970 +0000
1008 1009 | | : summary: (24) merge one known; immediate right
1009 1010 | | /
1010 1011 | o : changeset: 23:a01cddf0766d
1011 1012 | |\ \ parent: 1:6db2ef61d156
1012 1013 | | ~ : parent: 22:e0d9cccacb5d
1013 1014 | | : user: test
1014 1015 | | : date: Thu Jan 01 00:00:23 1970 +0000
1015 1016 | | : summary: (23) merge one known; immediate left
1016 1017 | | /
1017 1018 | o : changeset: 22:e0d9cccacb5d
1018 1019 |/:/ parent: 18:1aa84d96232a
1019 1020 | : parent: 21:d42a756af44d
1020 1021 | : user: test
1021 1022 | : date: Thu Jan 01 00:00:22 1970 +0000
1022 1023 | : summary: (22) merge two known; one far left, one far right
1023 1024 | :
1024 1025 | o changeset: 21:d42a756af44d
1025 1026 | |\ parent: 19:31ddc2c1573b
1026 1027 | | | parent: 20:d30ed6450e32
1027 1028 | | | user: test
1028 1029 | | | date: Thu Jan 01 00:00:21 1970 +0000
1029 1030 | | | summary: (21) expand
1030 1031 | | |
1031 1032 +---o changeset: 20:d30ed6450e32
1032 1033 | | | parent: 0:e6eb3150255d
1033 1034 | | ~ parent: 18:1aa84d96232a
1034 1035 | | user: test
1035 1036 | | date: Thu Jan 01 00:00:20 1970 +0000
1036 1037 | | summary: (20) merge two known; two far right
1037 1038 | |
1038 1039 | o changeset: 19:31ddc2c1573b
1039 1040 | |\ parent: 15:1dda3f72782d
1040 1041 | | | parent: 17:44765d7c06e0
1041 1042 | | | user: test
1042 1043 | | | date: Thu Jan 01 00:00:19 1970 +0000
1043 1044 | | | summary: (19) expand
1044 1045 | | |
1045 1046 o | | changeset: 18:1aa84d96232a
1046 1047 |\| | parent: 1:6db2ef61d156
1047 1048 ~ | | parent: 15:1dda3f72782d
1048 1049 | | user: test
1049 1050 | | date: Thu Jan 01 00:00:18 1970 +0000
1050 1051 | | summary: (18) merge two known; two far left
1051 1052 / /
1052 1053 | o changeset: 17:44765d7c06e0
1053 1054 | |\ parent: 12:86b91144a6e9
1054 1055 | | | parent: 16:3677d192927d
1055 1056 | | | user: test
1056 1057 | | | date: Thu Jan 01 00:00:17 1970 +0000
1057 1058 | | | summary: (17) expand
1058 1059 | | |
1059 1060 | | o changeset: 16:3677d192927d
1060 1061 | | |\ parent: 0:e6eb3150255d
1061 1062 | | ~ ~ parent: 1:6db2ef61d156
1062 1063 | | user: test
1063 1064 | | date: Thu Jan 01 00:00:16 1970 +0000
1064 1065 | | summary: (16) merge two known; one immediate right, one near right
1065 1066 | |
1066 1067 o | changeset: 15:1dda3f72782d
1067 1068 |\ \ parent: 13:22d8966a97e3
1068 1069 | | | parent: 14:8eac370358ef
1069 1070 | | | user: test
1070 1071 | | | date: Thu Jan 01 00:00:15 1970 +0000
1071 1072 | | | summary: (15) expand
1072 1073 | | |
1073 1074 | o | changeset: 14:8eac370358ef
1074 1075 | |\| parent: 0:e6eb3150255d
1075 1076 | ~ | parent: 12:86b91144a6e9
1076 1077 | | user: test
1077 1078 | | date: Thu Jan 01 00:00:14 1970 +0000
1078 1079 | | summary: (14) merge two known; one immediate right, one far right
1079 1080 | /
1080 1081 o | changeset: 13:22d8966a97e3
1081 1082 |\ \ parent: 9:7010c0af0a35
1082 1083 | | | parent: 11:832d76e6bdf2
1083 1084 | | | user: test
1084 1085 | | | date: Thu Jan 01 00:00:13 1970 +0000
1085 1086 | | | summary: (13) expand
1086 1087 | | |
1087 1088 +---o changeset: 12:86b91144a6e9
1088 1089 | | | parent: 1:6db2ef61d156
1089 1090 | | ~ parent: 9:7010c0af0a35
1090 1091 | | user: test
1091 1092 | | date: Thu Jan 01 00:00:12 1970 +0000
1092 1093 | | summary: (12) merge two known; one immediate right, one far left
1093 1094 | |
1094 1095 | o changeset: 11:832d76e6bdf2
1095 1096 | |\ parent: 6:b105a072e251
1096 1097 | | | parent: 10:74c64d036d72
1097 1098 | | | user: test
1098 1099 | | | date: Thu Jan 01 00:00:11 1970 +0000
1099 1100 | | | summary: (11) expand
1100 1101 | | |
1101 1102 | | o changeset: 10:74c64d036d72
1102 1103 | |/| parent: 0:e6eb3150255d
1103 1104 | | ~ parent: 6:b105a072e251
1104 1105 | | user: test
1105 1106 | | date: Thu Jan 01 00:00:10 1970 +0000
1106 1107 | | summary: (10) merge two known; one immediate left, one near right
1107 1108 | |
1108 1109 o | changeset: 9:7010c0af0a35
1109 1110 |\ \ parent: 7:b632bb1b1224
1110 1111 | | | parent: 8:7a0b11f71937
1111 1112 | | | user: test
1112 1113 | | | date: Thu Jan 01 00:00:09 1970 +0000
1113 1114 | | | summary: (9) expand
1114 1115 | | |
1115 1116 | o | changeset: 8:7a0b11f71937
1116 1117 |/| | parent: 0:e6eb3150255d
1117 1118 | ~ | parent: 7:b632bb1b1224
1118 1119 | | user: test
1119 1120 | | date: Thu Jan 01 00:00:08 1970 +0000
1120 1121 | | summary: (8) merge two known; one immediate left, one far right
1121 1122 | /
1122 1123 o | changeset: 7:b632bb1b1224
1123 1124 |\ \ parent: 2:3d9a33b8d1e1
1124 1125 | ~ | parent: 5:4409d547b708
1125 1126 | | user: test
1126 1127 | | date: Thu Jan 01 00:00:07 1970 +0000
1127 1128 | | summary: (7) expand
1128 1129 | /
1129 1130 | o changeset: 6:b105a072e251
1130 1131 |/| parent: 2:3d9a33b8d1e1
1131 1132 | ~ parent: 5:4409d547b708
1132 1133 | user: test
1133 1134 | date: Thu Jan 01 00:00:06 1970 +0000
1134 1135 | summary: (6) merge two known; one immediate left, one far left
1135 1136 |
1136 1137 o changeset: 5:4409d547b708
1137 1138 |\ parent: 3:27eef8ed80b4
1138 1139 | ~ parent: 4:26a8bac39d9f
1139 1140 | user: test
1140 1141 | date: Thu Jan 01 00:00:05 1970 +0000
1141 1142 | summary: (5) expand
1142 1143 |
1143 1144 o changeset: 4:26a8bac39d9f
1144 1145 |\ parent: 1:6db2ef61d156
1145 1146 ~ ~ parent: 3:27eef8ed80b4
1146 1147 user: test
1147 1148 date: Thu Jan 01 00:00:04 1970 +0000
1148 1149 summary: (4) merge two known; one immediate left, one immediate right
1149 1150
1150 1151
1151 1152
1152 1153 Empty revision range - display nothing:
1153 1154 $ hg log -G -r 1..0
1154 1155
1155 1156 $ cd ..
1156 1157
1157 1158 #if no-outer-repo
1158 1159
1159 1160 From outer space:
1160 1161 $ hg log -G -l1 repo
1161 1162 @ changeset: 34:fea3ac5810e0
1162 1163 | tag: tip
1163 1164 ~ parent: 32:d06dffa21a31
1164 1165 user: test
1165 1166 date: Thu Jan 01 00:00:34 1970 +0000
1166 1167 summary: (34) head
1167 1168
1168 1169 $ hg log -G -l1 repo/a
1169 1170 @ changeset: 34:fea3ac5810e0
1170 1171 | tag: tip
1171 1172 ~ parent: 32:d06dffa21a31
1172 1173 user: test
1173 1174 date: Thu Jan 01 00:00:34 1970 +0000
1174 1175 summary: (34) head
1175 1176
1176 1177 $ hg log -G -l1 repo/missing
1177 1178
1178 1179 #endif
1179 1180
1180 1181 File log with revs != cset revs:
1181 1182 $ hg init flog
1182 1183 $ cd flog
1183 1184 $ echo one >one
1184 1185 $ hg add one
1185 1186 $ hg commit -mone
1186 1187 $ echo two >two
1187 1188 $ hg add two
1188 1189 $ hg commit -mtwo
1189 1190 $ echo more >two
1190 1191 $ hg commit -mmore
1191 1192 $ hg log -G two
1192 1193 @ changeset: 2:12c28321755b
1193 1194 | tag: tip
1194 1195 | user: test
1195 1196 | date: Thu Jan 01 00:00:00 1970 +0000
1196 1197 | summary: more
1197 1198 |
1198 1199 o changeset: 1:5ac72c0599bf
1199 1200 | user: test
1200 1201 ~ date: Thu Jan 01 00:00:00 1970 +0000
1201 1202 summary: two
1202 1203
1203 1204
1204 1205 Issue1896: File log with explicit style
1205 1206 $ hg log -G --style=default one
1206 1207 o changeset: 0:3d578b4a1f53
1207 1208 user: test
1208 1209 date: Thu Jan 01 00:00:00 1970 +0000
1209 1210 summary: one
1210 1211
1211 1212 Issue2395: glog --style header and footer
1212 1213 $ hg log -G --style=xml one
1213 1214 <?xml version="1.0"?>
1214 1215 <log>
1215 1216 o <logentry revision="0" node="3d578b4a1f537d5fcf7301bfa9c0b97adfaa6fb1">
1216 1217 <author email="test">test</author>
1217 1218 <date>1970-01-01T00:00:00+00:00</date>
1218 1219 <msg xml:space="preserve">one</msg>
1219 1220 </logentry>
1220 1221 </log>
1221 1222
1222 1223 $ cd ..
1223 1224
1224 1225 Incoming and outgoing:
1225 1226
1226 1227 $ hg clone -U -r31 repo repo2
1227 1228 adding changesets
1228 1229 adding manifests
1229 1230 adding file changes
1230 1231 added 31 changesets with 31 changes to 1 files
1231 1232 new changesets e6eb3150255d:621d83e11f67
1232 1233 $ cd repo2
1233 1234
1234 1235 $ hg incoming --graph ../repo
1235 1236 comparing with ../repo
1236 1237 searching for changes
1237 1238 o changeset: 34:fea3ac5810e0
1238 1239 | tag: tip
1239 1240 | parent: 32:d06dffa21a31
1240 1241 | user: test
1241 1242 | date: Thu Jan 01 00:00:34 1970 +0000
1242 1243 | summary: (34) head
1243 1244 |
1244 1245 | o changeset: 33:68608f5145f9
1245 1246 | parent: 18:1aa84d96232a
1246 1247 | user: test
1247 1248 | date: Thu Jan 01 00:00:33 1970 +0000
1248 1249 | summary: (33) head
1249 1250 |
1250 1251 o changeset: 32:d06dffa21a31
1251 1252 | parent: 27:886ed638191b
1252 1253 | parent: 31:621d83e11f67
1253 1254 | user: test
1254 1255 | date: Thu Jan 01 00:00:32 1970 +0000
1255 1256 | summary: (32) expand
1256 1257 |
1257 1258 o changeset: 27:886ed638191b
1258 1259 parent: 21:d42a756af44d
1259 1260 user: test
1260 1261 date: Thu Jan 01 00:00:27 1970 +0000
1261 1262 summary: (27) collapse
1262 1263
1263 1264 $ cd ..
1264 1265
1265 1266 $ hg -R repo outgoing --graph repo2
1266 1267 comparing with repo2
1267 1268 searching for changes
1268 1269 @ changeset: 34:fea3ac5810e0
1269 1270 | tag: tip
1270 1271 | parent: 32:d06dffa21a31
1271 1272 | user: test
1272 1273 | date: Thu Jan 01 00:00:34 1970 +0000
1273 1274 | summary: (34) head
1274 1275 |
1275 1276 | o changeset: 33:68608f5145f9
1276 1277 | parent: 18:1aa84d96232a
1277 1278 | user: test
1278 1279 | date: Thu Jan 01 00:00:33 1970 +0000
1279 1280 | summary: (33) head
1280 1281 |
1281 1282 o changeset: 32:d06dffa21a31
1282 1283 | parent: 27:886ed638191b
1283 1284 | parent: 31:621d83e11f67
1284 1285 | user: test
1285 1286 | date: Thu Jan 01 00:00:32 1970 +0000
1286 1287 | summary: (32) expand
1287 1288 |
1288 1289 o changeset: 27:886ed638191b
1289 1290 parent: 21:d42a756af44d
1290 1291 user: test
1291 1292 date: Thu Jan 01 00:00:27 1970 +0000
1292 1293 summary: (27) collapse
1293 1294
1294 1295
1295 1296 File + limit with revs != cset revs:
1296 1297 $ cd repo
1297 1298 $ touch b
1298 1299 $ hg ci -Aqm0
1299 1300 $ hg log -G -l2 a
1300 1301 o changeset: 34:fea3ac5810e0
1301 1302 | parent: 32:d06dffa21a31
1302 1303 ~ user: test
1303 1304 date: Thu Jan 01 00:00:34 1970 +0000
1304 1305 summary: (34) head
1305 1306
1306 1307 o changeset: 33:68608f5145f9
1307 1308 | parent: 18:1aa84d96232a
1308 1309 ~ user: test
1309 1310 date: Thu Jan 01 00:00:33 1970 +0000
1310 1311 summary: (33) head
1311 1312
1312 1313
1313 1314 File + limit + -ra:b, (b - a) < limit:
1314 1315 $ hg log -G -l3000 -r32:tip a
1315 1316 o changeset: 34:fea3ac5810e0
1316 1317 | parent: 32:d06dffa21a31
1317 1318 | user: test
1318 1319 | date: Thu Jan 01 00:00:34 1970 +0000
1319 1320 | summary: (34) head
1320 1321 |
1321 1322 | o changeset: 33:68608f5145f9
1322 1323 | | parent: 18:1aa84d96232a
1323 1324 | ~ user: test
1324 1325 | date: Thu Jan 01 00:00:33 1970 +0000
1325 1326 | summary: (33) head
1326 1327 |
1327 1328 o changeset: 32:d06dffa21a31
1328 1329 |\ parent: 27:886ed638191b
1329 1330 ~ ~ parent: 31:621d83e11f67
1330 1331 user: test
1331 1332 date: Thu Jan 01 00:00:32 1970 +0000
1332 1333 summary: (32) expand
1333 1334
1334 1335
1335 1336 Point out a common and an uncommon unshown parent
1336 1337
1337 1338 $ hg log -G -r 'rev(8) or rev(9)'
1338 1339 o changeset: 9:7010c0af0a35
1339 1340 |\ parent: 7:b632bb1b1224
1340 1341 | ~ parent: 8:7a0b11f71937
1341 1342 | user: test
1342 1343 | date: Thu Jan 01 00:00:09 1970 +0000
1343 1344 | summary: (9) expand
1344 1345 |
1345 1346 o changeset: 8:7a0b11f71937
1346 1347 |\ parent: 0:e6eb3150255d
1347 1348 ~ ~ parent: 7:b632bb1b1224
1348 1349 user: test
1349 1350 date: Thu Jan 01 00:00:08 1970 +0000
1350 1351 summary: (8) merge two known; one immediate left, one far right
1351 1352
1352 1353
1353 1354 File + limit + -ra:b, b < tip:
1354 1355
1355 1356 $ hg log -G -l1 -r32:34 a
1356 1357 o changeset: 34:fea3ac5810e0
1357 1358 | parent: 32:d06dffa21a31
1358 1359 ~ user: test
1359 1360 date: Thu Jan 01 00:00:34 1970 +0000
1360 1361 summary: (34) head
1361 1362
1362 1363
1363 1364 file(File) + limit + -ra:b, b < tip:
1364 1365
1365 1366 $ hg log -G -l1 -r32:34 -r 'file("a")'
1366 1367 o changeset: 34:fea3ac5810e0
1367 1368 | parent: 32:d06dffa21a31
1368 1369 ~ user: test
1369 1370 date: Thu Jan 01 00:00:34 1970 +0000
1370 1371 summary: (34) head
1371 1372
1372 1373
1373 1374 limit(file(File) and a::b), b < tip:
1374 1375
1375 1376 $ hg log -G -r 'limit(file("a") and 32::34, 1)'
1376 1377 o changeset: 32:d06dffa21a31
1377 1378 |\ parent: 27:886ed638191b
1378 1379 ~ ~ parent: 31:621d83e11f67
1379 1380 user: test
1380 1381 date: Thu Jan 01 00:00:32 1970 +0000
1381 1382 summary: (32) expand
1382 1383
1383 1384
1384 1385 File + limit + -ra:b, b < tip:
1385 1386
1386 1387 $ hg log -G -r 'limit(file("a") and 34::32, 1)'
1387 1388
1388 1389 File + limit + -ra:b, b < tip, (b - a) < limit:
1389 1390
1390 1391 $ hg log -G -l10 -r33:34 a
1391 1392 o changeset: 34:fea3ac5810e0
1392 1393 | parent: 32:d06dffa21a31
1393 1394 ~ user: test
1394 1395 date: Thu Jan 01 00:00:34 1970 +0000
1395 1396 summary: (34) head
1396 1397
1397 1398 o changeset: 33:68608f5145f9
1398 1399 | parent: 18:1aa84d96232a
1399 1400 ~ user: test
1400 1401 date: Thu Jan 01 00:00:33 1970 +0000
1401 1402 summary: (33) head
1402 1403
1403 1404
1404 1405 Do not crash or produce strange graphs if history is buggy
1405 1406
1406 1407 $ hg branch branch
1407 1408 marked working directory as branch branch
1408 1409 (branches are permanent and global, did you want a bookmark?)
1409 1410 $ commit 36 "buggy merge: identical parents" 35 35
1410 1411 $ hg log -G -l5
1411 1412 @ changeset: 36:08a19a744424
1412 1413 | branch: branch
1413 1414 | tag: tip
1414 1415 | parent: 35:9159c3644c5e
1415 1416 | parent: 35:9159c3644c5e
1416 1417 | user: test
1417 1418 | date: Thu Jan 01 00:00:36 1970 +0000
1418 1419 | summary: (36) buggy merge: identical parents
1419 1420 |
1420 1421 o changeset: 35:9159c3644c5e
1421 1422 | user: test
1422 1423 | date: Thu Jan 01 00:00:00 1970 +0000
1423 1424 | summary: 0
1424 1425 |
1425 1426 o changeset: 34:fea3ac5810e0
1426 1427 | parent: 32:d06dffa21a31
1427 1428 | user: test
1428 1429 | date: Thu Jan 01 00:00:34 1970 +0000
1429 1430 | summary: (34) head
1430 1431 |
1431 1432 | o changeset: 33:68608f5145f9
1432 1433 | | parent: 18:1aa84d96232a
1433 1434 | ~ user: test
1434 1435 | date: Thu Jan 01 00:00:33 1970 +0000
1435 1436 | summary: (33) head
1436 1437 |
1437 1438 o changeset: 32:d06dffa21a31
1438 1439 |\ parent: 27:886ed638191b
1439 1440 ~ ~ parent: 31:621d83e11f67
1440 1441 user: test
1441 1442 date: Thu Jan 01 00:00:32 1970 +0000
1442 1443 summary: (32) expand
1443 1444
1444 1445
1445 1446 Test log -G options
1446 1447
1447 1448 $ testlog() {
1448 1449 > hg log -G --print-revset "$@"
1449 1450 > hg log --template 'nodetag {rev}\n' "$@" | grep nodetag \
1450 1451 > | sed 's/.*nodetag/nodetag/' > log.nodes
1451 1452 > hg log -G --template 'nodetag {rev}\n' "$@" | grep nodetag \
1452 1453 > | sed 's/.*nodetag/nodetag/' > glog.nodes
1453 1454 > (cmp log.nodes glog.nodes || diff -u log.nodes glog.nodes) \
1454 1455 > | grep '^[-+@ ]' || :
1455 1456 > }
1456 1457
1457 1458 glog always reorders nodes which explains the difference with log
1458 1459
1459 1460 $ testlog -r 27 -r 25 -r 21 -r 34 -r 32 -r 31
1460 1461 ['27', '25', '21', '34', '32', '31']
1461 1462 []
1462 1463 <baseset- [21, 25, 27, 31, 32, 34]>
1463 1464 --- log.nodes * (glob)
1464 1465 +++ glog.nodes * (glob)
1465 1466 @@ -1,6 +1,6 @@
1466 1467 -nodetag 27
1467 1468 -nodetag 25
1468 1469 -nodetag 21
1469 1470 nodetag 34
1470 1471 nodetag 32
1471 1472 nodetag 31
1472 1473 +nodetag 27
1473 1474 +nodetag 25
1474 1475 +nodetag 21
1475 1476 $ testlog -u test -u not-a-user
1476 1477 []
1477 1478 (or
1478 1479 (list
1479 1480 (func
1480 1481 (symbol 'user')
1481 1482 (string 'test'))
1482 1483 (func
1483 1484 (symbol 'user')
1484 1485 (string 'not-a-user'))))
1485 1486 <filteredset
1486 1487 <spanset- 0:37>,
1487 1488 <addset
1488 1489 <filteredset
1489 1490 <fullreposet+ 0:37>,
1490 1491 <user 'test'>>,
1491 1492 <filteredset
1492 1493 <fullreposet+ 0:37>,
1493 1494 <user 'not-a-user'>>>>
1494 1495 $ testlog -b not-a-branch
1495 1496 abort: unknown revision 'not-a-branch'!
1496 1497 abort: unknown revision 'not-a-branch'!
1497 1498 abort: unknown revision 'not-a-branch'!
1498 1499 $ testlog -b 35 -b 36 --only-branch branch
1499 1500 []
1500 1501 (or
1501 1502 (list
1502 1503 (func
1503 1504 (symbol 'branch')
1504 1505 (string 'default'))
1505 1506 (or
1506 1507 (list
1507 1508 (func
1508 1509 (symbol 'branch')
1509 1510 (string 'branch'))
1510 1511 (func
1511 1512 (symbol 'branch')
1512 1513 (string 'branch'))))))
1513 1514 <filteredset
1514 1515 <spanset- 0:37>,
1515 1516 <addset
1516 1517 <filteredset
1517 1518 <fullreposet+ 0:37>,
1518 1519 <branch 'default'>>,
1519 1520 <addset
1520 1521 <filteredset
1521 1522 <fullreposet+ 0:37>,
1522 1523 <branch 'branch'>>,
1523 1524 <filteredset
1524 1525 <fullreposet+ 0:37>,
1525 1526 <branch 'branch'>>>>>
1526 1527 $ testlog -k expand -k merge
1527 1528 []
1528 1529 (or
1529 1530 (list
1530 1531 (func
1531 1532 (symbol 'keyword')
1532 1533 (string 'expand'))
1533 1534 (func
1534 1535 (symbol 'keyword')
1535 1536 (string 'merge'))))
1536 1537 <filteredset
1537 1538 <spanset- 0:37>,
1538 1539 <addset
1539 1540 <filteredset
1540 1541 <fullreposet+ 0:37>,
1541 1542 <keyword 'expand'>>,
1542 1543 <filteredset
1543 1544 <fullreposet+ 0:37>,
1544 1545 <keyword 'merge'>>>>
1545 1546 $ testlog --only-merges
1546 1547 []
1547 1548 (func
1548 1549 (symbol 'merge')
1549 1550 None)
1550 1551 <filteredset
1551 1552 <spanset- 0:37>,
1552 1553 <merge>>
1553 1554 $ testlog --no-merges
1554 1555 []
1555 1556 (not
1556 1557 (func
1557 1558 (symbol 'merge')
1558 1559 None))
1559 1560 <filteredset
1560 1561 <spanset- 0:37>,
1561 1562 <not
1562 1563 <filteredset
1563 1564 <spanset- 0:37>,
1564 1565 <merge>>>>
1565 1566 $ testlog --date '2 0 to 4 0'
1566 1567 []
1567 1568 (func
1568 1569 (symbol 'date')
1569 1570 (string '2 0 to 4 0'))
1570 1571 <filteredset
1571 1572 <spanset- 0:37>,
1572 1573 <date '2 0 to 4 0'>>
1573 1574 $ hg log -G -d 'brace ) in a date'
1574 1575 hg: parse error: invalid date: 'brace ) in a date'
1575 1576 [255]
1576 1577 $ testlog --prune 31 --prune 32
1577 1578 []
1578 1579 (not
1579 1580 (or
1580 1581 (list
1581 1582 (func
1582 1583 (symbol 'ancestors')
1583 1584 (string '31'))
1584 1585 (func
1585 1586 (symbol 'ancestors')
1586 1587 (string '32')))))
1587 1588 <filteredset
1588 1589 <spanset- 0:37>,
1589 1590 <not
1590 1591 <addset
1591 1592 <filteredset
1592 1593 <spanset- 0:37>,
1593 1594 <generatorsetdesc+>>,
1594 1595 <filteredset
1595 1596 <spanset- 0:37>,
1596 1597 <generatorsetdesc+>>>>>
1597 1598
1598 1599 Dedicated repo for --follow and paths filtering. The g is crafted to
1599 1600 have 2 filelog topological heads in a linear changeset graph.
1600 1601
1601 1602 $ cd ..
1602 1603 $ hg init follow
1603 1604 $ cd follow
1604 1605 $ testlog --follow
1605 1606 []
1606 1607 []
1607 1608 <baseset []>
1608 1609 $ testlog -rnull
1609 1610 ['null']
1610 1611 []
1611 1612 <baseset [-1]>
1612 1613 $ echo a > a
1613 1614 $ echo aa > aa
1614 1615 $ echo f > f
1615 1616 $ hg ci -Am "add a" a aa f
1616 1617 $ hg cp a b
1617 1618 $ hg cp f g
1618 1619 $ hg ci -m "copy a b"
1619 1620 $ mkdir dir
1620 1621 $ hg mv b dir
1621 1622 $ echo g >> g
1622 1623 $ echo f >> f
1623 1624 $ hg ci -m "mv b dir/b"
1624 1625 $ hg mv a b
1625 1626 $ hg cp -f f g
1626 1627 $ echo a > d
1627 1628 $ hg add d
1628 1629 $ hg ci -m "mv a b; add d"
1629 1630 $ hg mv dir/b e
1630 1631 $ hg ci -m "mv dir/b e"
1631 1632 $ hg log -G --template '({rev}) {desc|firstline}\n'
1632 1633 @ (4) mv dir/b e
1633 1634 |
1634 1635 o (3) mv a b; add d
1635 1636 |
1636 1637 o (2) mv b dir/b
1637 1638 |
1638 1639 o (1) copy a b
1639 1640 |
1640 1641 o (0) add a
1641 1642
1642 1643
1643 1644 $ testlog a
1644 1645 []
1645 1646 (func
1646 1647 (symbol 'filelog')
1647 1648 (string 'a'))
1648 1649 <filteredset
1649 1650 <spanset- 0:5>, set([0])>
1650 1651 $ testlog a b
1651 1652 []
1652 1653 (or
1653 1654 (list
1654 1655 (func
1655 1656 (symbol 'filelog')
1656 1657 (string 'a'))
1657 1658 (func
1658 1659 (symbol 'filelog')
1659 1660 (string 'b'))))
1660 1661 <filteredset
1661 1662 <spanset- 0:5>,
1662 1663 <addset
1663 1664 <baseset+ [0]>,
1664 1665 <baseset+ [1]>>>
1665 1666
1666 1667 Test falling back to slow path for non-existing files
1667 1668
1668 1669 $ testlog a c
1669 1670 []
1670 1671 (func
1671 1672 (symbol '_matchfiles')
1672 1673 (list
1673 1674 (string 'r:')
1674 1675 (string 'd:relpath')
1675 1676 (string 'p:a')
1676 1677 (string 'p:c')))
1677 1678 <filteredset
1678 1679 <spanset- 0:5>,
1679 1680 <matchfiles patterns=['a', 'c'], include=[] exclude=[], default='relpath', rev=2147483647>>
1680 1681
1681 1682 Test multiple --include/--exclude/paths
1682 1683
1683 1684 $ testlog --include a --include e --exclude b --exclude e a e
1684 1685 []
1685 1686 (func
1686 1687 (symbol '_matchfiles')
1687 1688 (list
1688 1689 (string 'r:')
1689 1690 (string 'd:relpath')
1690 1691 (string 'p:a')
1691 1692 (string 'p:e')
1692 1693 (string 'i:a')
1693 1694 (string 'i:e')
1694 1695 (string 'x:b')
1695 1696 (string 'x:e')))
1696 1697 <filteredset
1697 1698 <spanset- 0:5>,
1698 1699 <matchfiles patterns=['a', 'e'], include=['a', 'e'] exclude=['b', 'e'], default='relpath', rev=2147483647>>
1699 1700
1700 1701 Test glob expansion of pats
1701 1702
1702 1703 $ expandglobs=`$PYTHON -c "import mercurial.util; \
1703 1704 > print(mercurial.util.expandglobs and 'true' or 'false')"`
1704 1705 $ if [ $expandglobs = "true" ]; then
1705 1706 > testlog 'a*';
1706 1707 > else
1707 1708 > testlog a*;
1708 1709 > fi;
1709 1710 []
1710 1711 (func
1711 1712 (symbol 'filelog')
1712 1713 (string 'aa'))
1713 1714 <filteredset
1714 1715 <spanset- 0:5>, set([0])>
1715 1716
1716 1717 Test --follow on a non-existent directory
1717 1718
1718 1719 $ testlog -f dir
1719 1720 abort: cannot follow file not in parent revision: "dir"
1720 1721 abort: cannot follow file not in parent revision: "dir"
1721 1722 abort: cannot follow file not in parent revision: "dir"
1722 1723
1723 1724 Test --follow on a directory
1724 1725
1725 1726 $ hg up -q '.^'
1726 1727 $ testlog -f dir
1727 1728 []
1728 1729 (func
1729 1730 (symbol '_matchfiles')
1730 1731 (list
1731 1732 (string 'r:')
1732 1733 (string 'd:relpath')
1733 1734 (string 'p:dir')))
1734 1735 <filteredset
1735 1736 <generatorsetdesc->,
1736 1737 <matchfiles patterns=['dir'], include=[] exclude=[], default='relpath', rev=2147483647>>
1737 1738 $ hg up -q tip
1738 1739
1739 1740 Test --follow on file not in parent revision
1740 1741
1741 1742 $ testlog -f a
1742 1743 abort: cannot follow file not in parent revision: "a"
1743 1744 abort: cannot follow file not in parent revision: "a"
1744 1745 abort: cannot follow file not in parent revision: "a"
1745 1746
1746 1747 Test --follow and patterns
1747 1748
1748 1749 $ testlog -f 'glob:*'
1749 1750 []
1750 1751 (func
1751 1752 (symbol '_matchfiles')
1752 1753 (list
1753 1754 (string 'r:')
1754 1755 (string 'd:relpath')
1755 1756 (string 'p:glob:*')))
1756 1757 <filteredset
1757 1758 <generatorsetdesc->,
1758 1759 <matchfiles patterns=['glob:*'], include=[] exclude=[], default='relpath', rev=2147483647>>
1759 1760
1760 1761 Test --follow on a single rename
1761 1762
1762 1763 $ hg up -q 2
1763 1764 $ testlog -f a
1764 1765 []
1765 1766 []
1766 1767 <generatorsetdesc->
1767 1768
1768 1769 Test --follow and multiple renames
1769 1770
1770 1771 $ hg up -q tip
1771 1772 $ testlog -f e
1772 1773 []
1773 1774 []
1774 1775 <generatorsetdesc->
1775 1776
1776 1777 Test --follow and multiple filelog heads
1777 1778
1778 1779 $ hg up -q 2
1779 1780 $ testlog -f g
1780 1781 []
1781 1782 []
1782 1783 <generatorsetdesc->
1783 1784 $ cat log.nodes
1784 1785 nodetag 2
1785 1786 nodetag 1
1786 1787 nodetag 0
1787 1788 $ hg up -q tip
1788 1789 $ testlog -f g
1789 1790 []
1790 1791 []
1791 1792 <generatorsetdesc->
1792 1793 $ cat log.nodes
1793 1794 nodetag 3
1794 1795 nodetag 2
1795 1796 nodetag 0
1796 1797
1797 1798 Test --follow and multiple files
1798 1799
1799 1800 $ testlog -f g e
1800 1801 []
1801 1802 []
1802 1803 <generatorsetdesc->
1803 1804 $ cat log.nodes
1804 1805 nodetag 4
1805 1806 nodetag 3
1806 1807 nodetag 2
1807 1808 nodetag 1
1808 1809 nodetag 0
1809 1810
1810 1811 Test --follow null parent
1811 1812
1812 1813 $ hg up -q null
1813 1814 $ testlog -f
1814 1815 []
1815 1816 []
1816 1817 <baseset []>
1817 1818
1818 1819 Test --follow-first
1819 1820
1820 1821 $ hg up -q 3
1821 1822 $ echo ee > e
1822 1823 $ hg ci -Am "add another e" e
1823 1824 created new head
1824 1825 $ hg merge --tool internal:other 4
1825 1826 0 files updated, 1 files merged, 1 files removed, 0 files unresolved
1826 1827 (branch merge, don't forget to commit)
1827 1828 $ echo merge > e
1828 1829 $ hg ci -m "merge 5 and 4"
1829 1830 $ testlog --follow-first
1830 1831 []
1831 1832 []
1832 1833 <generatorsetdesc->
1833 1834
1834 1835 Cannot compare with log --follow-first FILE as it never worked
1835 1836
1836 1837 $ hg log -G --print-revset --follow-first e
1837 1838 []
1838 1839 []
1839 1840 <generatorsetdesc->
1840 1841 $ hg log -G --follow-first e --template '{rev} {desc|firstline}\n'
1841 1842 @ 6 merge 5 and 4
1842 1843 |\
1843 1844 | ~
1844 1845 o 5 add another e
1845 1846 |
1846 1847 ~
1847 1848
1848 1849 Test --copies
1849 1850
1850 1851 $ hg log -G --copies --template "{rev} {desc|firstline} \
1851 1852 > copies: {file_copies_switch}\n"
1852 1853 @ 6 merge 5 and 4 copies:
1853 1854 |\
1854 1855 | o 5 add another e copies:
1855 1856 | |
1856 1857 o | 4 mv dir/b e copies: e (dir/b)
1857 1858 |/
1858 1859 o 3 mv a b; add d copies: b (a)g (f)
1859 1860 |
1860 1861 o 2 mv b dir/b copies: dir/b (b)
1861 1862 |
1862 1863 o 1 copy a b copies: b (a)g (f)
1863 1864 |
1864 1865 o 0 add a copies:
1865 1866
1866 1867 Test "set:..." and parent revision
1867 1868
1868 1869 $ hg up -q 4
1869 1870 $ testlog "set:copied()"
1870 1871 []
1871 1872 (func
1872 1873 (symbol '_matchfiles')
1873 1874 (list
1874 1875 (string 'r:')
1875 1876 (string 'd:relpath')
1876 1877 (string 'p:set:copied()')))
1877 1878 <filteredset
1878 1879 <spanset- 0:7>,
1879 1880 <matchfiles patterns=['set:copied()'], include=[] exclude=[], default='relpath', rev=2147483647>>
1880 1881 $ testlog --include "set:copied()"
1881 1882 []
1882 1883 (func
1883 1884 (symbol '_matchfiles')
1884 1885 (list
1885 1886 (string 'r:')
1886 1887 (string 'd:relpath')
1887 1888 (string 'i:set:copied()')))
1888 1889 <filteredset
1889 1890 <spanset- 0:7>,
1890 1891 <matchfiles patterns=[], include=['set:copied()'] exclude=[], default='relpath', rev=2147483647>>
1891 1892 $ testlog -r "sort(file('set:copied()'), -rev)"
1892 1893 ["sort(file('set:copied()'), -rev)"]
1893 1894 []
1894 1895 <filteredset
1895 1896 <fullreposet- 0:7>,
1896 1897 <matchfiles patterns=['set:copied()'], include=[] exclude=[], default='glob', rev=None>>
1897 1898
1898 1899 Test --removed
1899 1900
1900 1901 $ testlog --removed
1901 1902 []
1902 1903 []
1903 1904 <spanset- 0:7>
1904 1905 $ testlog --removed a
1905 1906 []
1906 1907 (func
1907 1908 (symbol '_matchfiles')
1908 1909 (list
1909 1910 (string 'r:')
1910 1911 (string 'd:relpath')
1911 1912 (string 'p:a')))
1912 1913 <filteredset
1913 1914 <spanset- 0:7>,
1914 1915 <matchfiles patterns=['a'], include=[] exclude=[], default='relpath', rev=2147483647>>
1915 1916 $ testlog --removed --follow a
1916 1917 []
1917 1918 (func
1918 1919 (symbol '_matchfiles')
1919 1920 (list
1920 1921 (string 'r:')
1921 1922 (string 'd:relpath')
1922 1923 (string 'p:a')))
1923 1924 <filteredset
1924 1925 <generatorsetdesc->,
1925 1926 <matchfiles patterns=['a'], include=[] exclude=[], default='relpath', rev=2147483647>>
1926 1927
1927 1928 Test --patch and --stat with --follow and --follow-first
1928 1929
1929 1930 $ hg up -q 3
1930 1931 $ hg log -G --git --patch b
1931 1932 o changeset: 1:216d4c92cf98
1932 1933 | user: test
1933 1934 ~ date: Thu Jan 01 00:00:00 1970 +0000
1934 1935 summary: copy a b
1935 1936
1936 1937 diff --git a/a b/b
1937 1938 copy from a
1938 1939 copy to b
1939 1940
1940 1941
1941 1942 $ hg log -G --git --stat b
1942 1943 o changeset: 1:216d4c92cf98
1943 1944 | user: test
1944 1945 ~ date: Thu Jan 01 00:00:00 1970 +0000
1945 1946 summary: copy a b
1946 1947
1947 1948 b | 0
1948 1949 1 files changed, 0 insertions(+), 0 deletions(-)
1949 1950
1950 1951
1951 1952 $ hg log -G --git --patch --follow b
1952 1953 o changeset: 1:216d4c92cf98
1953 1954 | user: test
1954 1955 | date: Thu Jan 01 00:00:00 1970 +0000
1955 1956 | summary: copy a b
1956 1957 |
1957 1958 | diff --git a/a b/b
1958 1959 | copy from a
1959 1960 | copy to b
1960 1961 |
1961 1962 o changeset: 0:f8035bb17114
1962 1963 user: test
1963 1964 date: Thu Jan 01 00:00:00 1970 +0000
1964 1965 summary: add a
1965 1966
1966 1967 diff --git a/a b/a
1967 1968 new file mode 100644
1968 1969 --- /dev/null
1969 1970 +++ b/a
1970 1971 @@ -0,0 +1,1 @@
1971 1972 +a
1972 1973
1973 1974
1974 1975 $ hg log -G --git --stat --follow b
1975 1976 o changeset: 1:216d4c92cf98
1976 1977 | user: test
1977 1978 | date: Thu Jan 01 00:00:00 1970 +0000
1978 1979 | summary: copy a b
1979 1980 |
1980 1981 | b | 0
1981 1982 | 1 files changed, 0 insertions(+), 0 deletions(-)
1982 1983 |
1983 1984 o changeset: 0:f8035bb17114
1984 1985 user: test
1985 1986 date: Thu Jan 01 00:00:00 1970 +0000
1986 1987 summary: add a
1987 1988
1988 1989 a | 1 +
1989 1990 1 files changed, 1 insertions(+), 0 deletions(-)
1990 1991
1991 1992
1992 1993 $ hg up -q 6
1993 1994 $ hg log -G --git --patch --follow-first e
1994 1995 @ changeset: 6:fc281d8ff18d
1995 1996 |\ tag: tip
1996 1997 | ~ parent: 5:99b31f1c2782
1997 1998 | parent: 4:17d952250a9d
1998 1999 | user: test
1999 2000 | date: Thu Jan 01 00:00:00 1970 +0000
2000 2001 | summary: merge 5 and 4
2001 2002 |
2002 2003 | diff --git a/e b/e
2003 2004 | --- a/e
2004 2005 | +++ b/e
2005 2006 | @@ -1,1 +1,1 @@
2006 2007 | -ee
2007 2008 | +merge
2008 2009 |
2009 2010 o changeset: 5:99b31f1c2782
2010 2011 | parent: 3:5918b8d165d1
2011 2012 ~ user: test
2012 2013 date: Thu Jan 01 00:00:00 1970 +0000
2013 2014 summary: add another e
2014 2015
2015 2016 diff --git a/e b/e
2016 2017 new file mode 100644
2017 2018 --- /dev/null
2018 2019 +++ b/e
2019 2020 @@ -0,0 +1,1 @@
2020 2021 +ee
2021 2022
2022 2023
2023 2024 Test old-style --rev
2024 2025
2025 2026 $ hg tag 'foo-bar'
2026 2027 $ testlog -r 'foo-bar'
2027 2028 ['foo-bar']
2028 2029 []
2029 2030 <baseset [6]>
2030 2031
2031 2032 Test --follow and forward --rev
2032 2033
2033 2034 $ hg up -q 6
2034 2035 $ echo g > g
2035 2036 $ hg ci -Am 'add g' g
2036 2037 created new head
2037 2038 $ hg up -q 2
2038 2039 $ hg log -G --template "{rev} {desc|firstline}\n"
2039 2040 o 8 add g
2040 2041 |
2041 2042 | o 7 Added tag foo-bar for changeset fc281d8ff18d
2042 2043 |/
2043 2044 o 6 merge 5 and 4
2044 2045 |\
2045 2046 | o 5 add another e
2046 2047 | |
2047 2048 o | 4 mv dir/b e
2048 2049 |/
2049 2050 o 3 mv a b; add d
2050 2051 |
2051 2052 @ 2 mv b dir/b
2052 2053 |
2053 2054 o 1 copy a b
2054 2055 |
2055 2056 o 0 add a
2056 2057
2057 2058 $ hg archive -r 7 archive
2058 2059 $ grep changessincelatesttag archive/.hg_archival.txt
2059 2060 changessincelatesttag: 1
2060 2061 $ rm -r archive
2061 2062
2062 2063 changessincelatesttag with no prior tag
2063 2064 $ hg archive -r 4 archive
2064 2065 $ grep changessincelatesttag archive/.hg_archival.txt
2065 2066 changessincelatesttag: 5
2066 2067
2067 2068 $ hg export 'all()'
2068 2069 # HG changeset patch
2069 2070 # User test
2070 2071 # Date 0 0
2071 2072 # Thu Jan 01 00:00:00 1970 +0000
2072 2073 # Node ID f8035bb17114da16215af3436ec5222428ace8ee
2073 2074 # Parent 0000000000000000000000000000000000000000
2074 2075 add a
2075 2076
2076 2077 diff -r 000000000000 -r f8035bb17114 a
2077 2078 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2078 2079 +++ b/a Thu Jan 01 00:00:00 1970 +0000
2079 2080 @@ -0,0 +1,1 @@
2080 2081 +a
2081 2082 diff -r 000000000000 -r f8035bb17114 aa
2082 2083 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2083 2084 +++ b/aa Thu Jan 01 00:00:00 1970 +0000
2084 2085 @@ -0,0 +1,1 @@
2085 2086 +aa
2086 2087 diff -r 000000000000 -r f8035bb17114 f
2087 2088 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2088 2089 +++ b/f Thu Jan 01 00:00:00 1970 +0000
2089 2090 @@ -0,0 +1,1 @@
2090 2091 +f
2091 2092 # HG changeset patch
2092 2093 # User test
2093 2094 # Date 0 0
2094 2095 # Thu Jan 01 00:00:00 1970 +0000
2095 2096 # Node ID 216d4c92cf98ff2b4641d508b76b529f3d424c92
2096 2097 # Parent f8035bb17114da16215af3436ec5222428ace8ee
2097 2098 copy a b
2098 2099
2099 2100 diff -r f8035bb17114 -r 216d4c92cf98 b
2100 2101 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2101 2102 +++ b/b Thu Jan 01 00:00:00 1970 +0000
2102 2103 @@ -0,0 +1,1 @@
2103 2104 +a
2104 2105 diff -r f8035bb17114 -r 216d4c92cf98 g
2105 2106 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2106 2107 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2107 2108 @@ -0,0 +1,1 @@
2108 2109 +f
2109 2110 # HG changeset patch
2110 2111 # User test
2111 2112 # Date 0 0
2112 2113 # Thu Jan 01 00:00:00 1970 +0000
2113 2114 # Node ID bb573313a9e8349099b6ea2b2fb1fc7f424446f3
2114 2115 # Parent 216d4c92cf98ff2b4641d508b76b529f3d424c92
2115 2116 mv b dir/b
2116 2117
2117 2118 diff -r 216d4c92cf98 -r bb573313a9e8 b
2118 2119 --- a/b Thu Jan 01 00:00:00 1970 +0000
2119 2120 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2120 2121 @@ -1,1 +0,0 @@
2121 2122 -a
2122 2123 diff -r 216d4c92cf98 -r bb573313a9e8 dir/b
2123 2124 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2124 2125 +++ b/dir/b Thu Jan 01 00:00:00 1970 +0000
2125 2126 @@ -0,0 +1,1 @@
2126 2127 +a
2127 2128 diff -r 216d4c92cf98 -r bb573313a9e8 f
2128 2129 --- a/f Thu Jan 01 00:00:00 1970 +0000
2129 2130 +++ b/f Thu Jan 01 00:00:00 1970 +0000
2130 2131 @@ -1,1 +1,2 @@
2131 2132 f
2132 2133 +f
2133 2134 diff -r 216d4c92cf98 -r bb573313a9e8 g
2134 2135 --- a/g Thu Jan 01 00:00:00 1970 +0000
2135 2136 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2136 2137 @@ -1,1 +1,2 @@
2137 2138 f
2138 2139 +g
2139 2140 # HG changeset patch
2140 2141 # User test
2141 2142 # Date 0 0
2142 2143 # Thu Jan 01 00:00:00 1970 +0000
2143 2144 # Node ID 5918b8d165d1364e78a66d02e66caa0133c5d1ed
2144 2145 # Parent bb573313a9e8349099b6ea2b2fb1fc7f424446f3
2145 2146 mv a b; add d
2146 2147
2147 2148 diff -r bb573313a9e8 -r 5918b8d165d1 a
2148 2149 --- a/a Thu Jan 01 00:00:00 1970 +0000
2149 2150 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2150 2151 @@ -1,1 +0,0 @@
2151 2152 -a
2152 2153 diff -r bb573313a9e8 -r 5918b8d165d1 b
2153 2154 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2154 2155 +++ b/b Thu Jan 01 00:00:00 1970 +0000
2155 2156 @@ -0,0 +1,1 @@
2156 2157 +a
2157 2158 diff -r bb573313a9e8 -r 5918b8d165d1 d
2158 2159 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2159 2160 +++ b/d Thu Jan 01 00:00:00 1970 +0000
2160 2161 @@ -0,0 +1,1 @@
2161 2162 +a
2162 2163 diff -r bb573313a9e8 -r 5918b8d165d1 g
2163 2164 --- a/g Thu Jan 01 00:00:00 1970 +0000
2164 2165 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2165 2166 @@ -1,2 +1,2 @@
2166 2167 f
2167 2168 -g
2168 2169 +f
2169 2170 # HG changeset patch
2170 2171 # User test
2171 2172 # Date 0 0
2172 2173 # Thu Jan 01 00:00:00 1970 +0000
2173 2174 # Node ID 17d952250a9d03cc3dc77b199ab60e959b9b0260
2174 2175 # Parent 5918b8d165d1364e78a66d02e66caa0133c5d1ed
2175 2176 mv dir/b e
2176 2177
2177 2178 diff -r 5918b8d165d1 -r 17d952250a9d dir/b
2178 2179 --- a/dir/b Thu Jan 01 00:00:00 1970 +0000
2179 2180 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2180 2181 @@ -1,1 +0,0 @@
2181 2182 -a
2182 2183 diff -r 5918b8d165d1 -r 17d952250a9d e
2183 2184 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2184 2185 +++ b/e Thu Jan 01 00:00:00 1970 +0000
2185 2186 @@ -0,0 +1,1 @@
2186 2187 +a
2187 2188 # HG changeset patch
2188 2189 # User test
2189 2190 # Date 0 0
2190 2191 # Thu Jan 01 00:00:00 1970 +0000
2191 2192 # Node ID 99b31f1c2782e2deb1723cef08930f70fc84b37b
2192 2193 # Parent 5918b8d165d1364e78a66d02e66caa0133c5d1ed
2193 2194 add another e
2194 2195
2195 2196 diff -r 5918b8d165d1 -r 99b31f1c2782 e
2196 2197 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2197 2198 +++ b/e Thu Jan 01 00:00:00 1970 +0000
2198 2199 @@ -0,0 +1,1 @@
2199 2200 +ee
2200 2201 # HG changeset patch
2201 2202 # User test
2202 2203 # Date 0 0
2203 2204 # Thu Jan 01 00:00:00 1970 +0000
2204 2205 # Node ID fc281d8ff18d999ad6497b3d27390bcd695dcc73
2205 2206 # Parent 99b31f1c2782e2deb1723cef08930f70fc84b37b
2206 2207 # Parent 17d952250a9d03cc3dc77b199ab60e959b9b0260
2207 2208 merge 5 and 4
2208 2209
2209 2210 diff -r 99b31f1c2782 -r fc281d8ff18d dir/b
2210 2211 --- a/dir/b Thu Jan 01 00:00:00 1970 +0000
2211 2212 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2212 2213 @@ -1,1 +0,0 @@
2213 2214 -a
2214 2215 diff -r 99b31f1c2782 -r fc281d8ff18d e
2215 2216 --- a/e Thu Jan 01 00:00:00 1970 +0000
2216 2217 +++ b/e Thu Jan 01 00:00:00 1970 +0000
2217 2218 @@ -1,1 +1,1 @@
2218 2219 -ee
2219 2220 +merge
2220 2221 # HG changeset patch
2221 2222 # User test
2222 2223 # Date 0 0
2223 2224 # Thu Jan 01 00:00:00 1970 +0000
2224 2225 # Node ID 02dbb8e276b8ab7abfd07cab50c901647e75c2dd
2225 2226 # Parent fc281d8ff18d999ad6497b3d27390bcd695dcc73
2226 2227 Added tag foo-bar for changeset fc281d8ff18d
2227 2228
2228 2229 diff -r fc281d8ff18d -r 02dbb8e276b8 .hgtags
2229 2230 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2230 2231 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
2231 2232 @@ -0,0 +1,1 @@
2232 2233 +fc281d8ff18d999ad6497b3d27390bcd695dcc73 foo-bar
2233 2234 # HG changeset patch
2234 2235 # User test
2235 2236 # Date 0 0
2236 2237 # Thu Jan 01 00:00:00 1970 +0000
2237 2238 # Node ID 24c2e826ddebf80f9dcd60b856bdb8e6715c5449
2238 2239 # Parent fc281d8ff18d999ad6497b3d27390bcd695dcc73
2239 2240 add g
2240 2241
2241 2242 diff -r fc281d8ff18d -r 24c2e826ddeb g
2242 2243 --- a/g Thu Jan 01 00:00:00 1970 +0000
2243 2244 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2244 2245 @@ -1,2 +1,1 @@
2245 2246 -f
2246 2247 -f
2247 2248 +g
2248 2249 $ testlog --follow -r6 -r8 -r5 -r7 -r4
2249 2250 ['6', '8', '5', '7', '4']
2250 2251 []
2251 2252 <generatorsetdesc->
2252 2253
2253 2254 Test --follow-first and forward --rev
2254 2255
2255 2256 $ testlog --follow-first -r6 -r8 -r5 -r7 -r4
2256 2257 ['6', '8', '5', '7', '4']
2257 2258 []
2258 2259 <generatorsetdesc->
2259 2260
2260 2261 Test --follow and backward --rev
2261 2262
2262 2263 $ testlog --follow -r6 -r5 -r7 -r8 -r4
2263 2264 ['6', '5', '7', '8', '4']
2264 2265 []
2265 2266 <generatorsetdesc->
2266 2267
2267 2268 Test --follow-first and backward --rev
2268 2269
2269 2270 $ testlog --follow-first -r6 -r5 -r7 -r8 -r4
2270 2271 ['6', '5', '7', '8', '4']
2271 2272 []
2272 2273 <generatorsetdesc->
2273 2274
2274 2275 Test --follow with --rev of graphlog extension
2275 2276
2276 2277 $ hg --config extensions.graphlog= glog -qfr1
2277 2278 o 1:216d4c92cf98
2278 2279 |
2279 2280 o 0:f8035bb17114
2280 2281
2281 2282
2282 2283 Test subdir
2283 2284
2284 2285 $ hg up -q 3
2285 2286 $ cd dir
2286 2287 $ testlog .
2287 2288 []
2288 2289 (func
2289 2290 (symbol '_matchfiles')
2290 2291 (list
2291 2292 (string 'r:')
2292 2293 (string 'd:relpath')
2293 2294 (string 'p:.')))
2294 2295 <filteredset
2295 2296 <spanset- 0:9>,
2296 2297 <matchfiles patterns=['.'], include=[] exclude=[], default='relpath', rev=2147483647>>
2297 2298 $ testlog ../b
2298 2299 []
2299 2300 (func
2300 2301 (symbol 'filelog')
2301 2302 (string '../b'))
2302 2303 <filteredset
2303 2304 <spanset- 0:9>, set([1])>
2304 2305 $ testlog -f ../b
2305 2306 []
2306 2307 []
2307 2308 <generatorsetdesc->
2308 2309 $ cd ..
2309 2310
2310 2311 Test --hidden
2311 2312 (enable obsolete)
2312 2313
2313 2314 $ cat >> $HGRCPATH << EOF
2314 2315 > [experimental]
2315 2316 > evolution.createmarkers=True
2316 2317 > EOF
2317 2318
2318 2319 $ hg debugobsolete `hg id --debug -i -r 8`
2319 2320 obsoleted 1 changesets
2320 2321 $ testlog
2321 2322 []
2322 2323 []
2323 2324 <spanset- 0:9>
2324 2325 $ testlog --hidden
2325 2326 []
2326 2327 []
2327 2328 <spanset- 0:9>
2328 2329 $ hg log -G --template '{rev} {desc}\n'
2329 2330 o 7 Added tag foo-bar for changeset fc281d8ff18d
2330 2331 |
2331 2332 o 6 merge 5 and 4
2332 2333 |\
2333 2334 | o 5 add another e
2334 2335 | |
2335 2336 o | 4 mv dir/b e
2336 2337 |/
2337 2338 @ 3 mv a b; add d
2338 2339 |
2339 2340 o 2 mv b dir/b
2340 2341 |
2341 2342 o 1 copy a b
2342 2343 |
2343 2344 o 0 add a
2344 2345
2345 2346
2346 2347 A template without trailing newline should do something sane
2347 2348
2348 2349 $ hg log -G -r ::2 --template '{rev} {desc}'
2349 2350 o 2 mv b dir/b
2350 2351 |
2351 2352 o 1 copy a b
2352 2353 |
2353 2354 o 0 add a
2354 2355
2355 2356
2356 2357 Extra newlines must be preserved
2357 2358
2358 2359 $ hg log -G -r ::2 --template '\n{rev} {desc}\n\n'
2359 2360 o
2360 2361 | 2 mv b dir/b
2361 2362 |
2362 2363 o
2363 2364 | 1 copy a b
2364 2365 |
2365 2366 o
2366 2367 0 add a
2367 2368
2368 2369
2369 2370 The almost-empty template should do something sane too ...
2370 2371
2371 2372 $ hg log -G -r ::2 --template '\n'
2372 2373 o
2373 2374 |
2374 2375 o
2375 2376 |
2376 2377 o
2377 2378
2378 2379
2379 2380 issue3772
2380 2381
2381 2382 $ hg log -G -r :null
2382 2383 o changeset: 0:f8035bb17114
2383 2384 | user: test
2384 2385 | date: Thu Jan 01 00:00:00 1970 +0000
2385 2386 | summary: add a
2386 2387 |
2387 2388 o changeset: -1:000000000000
2388 2389 user:
2389 2390 date: Thu Jan 01 00:00:00 1970 +0000
2390 2391
2391 2392 $ hg log -G -r null:null
2392 2393 o changeset: -1:000000000000
2393 2394 user:
2394 2395 date: Thu Jan 01 00:00:00 1970 +0000
2395 2396
2396 2397
2397 2398 should not draw line down to null due to the magic of fullreposet
2398 2399
2399 2400 $ hg log -G -r 'all()' | tail -6
2400 2401 |
2401 2402 o changeset: 0:f8035bb17114
2402 2403 user: test
2403 2404 date: Thu Jan 01 00:00:00 1970 +0000
2404 2405 summary: add a
2405 2406
2406 2407
2407 2408 $ hg log -G -r 'branch(default)' | tail -6
2408 2409 |
2409 2410 o changeset: 0:f8035bb17114
2410 2411 user: test
2411 2412 date: Thu Jan 01 00:00:00 1970 +0000
2412 2413 summary: add a
2413 2414
2414 2415
2415 2416 working-directory revision
2416 2417
2417 2418 $ hg log -G -qr '. + wdir()'
2418 2419 o 2147483647:ffffffffffff
2419 2420 |
2420 2421 @ 3:5918b8d165d1
2421 2422 |
2422 2423 ~
2423 2424
2424 2425 node template with changesetprinter:
2425 2426
2426 2427 $ hg log -Gqr 5:7 --config ui.graphnodetemplate='"{rev}"'
2427 2428 7 7:02dbb8e276b8
2428 2429 |
2429 2430 6 6:fc281d8ff18d
2430 2431 |\
2431 2432 | ~
2432 2433 5 5:99b31f1c2782
2433 2434 |
2434 2435 ~
2435 2436
2436 2437 node template with changesettemplater (shared cache variable):
2437 2438
2438 2439 $ hg log -Gr 5:7 -T '{latesttag % "{rev} {tag}+{distance}"}\n' \
2439 2440 > --config ui.graphnodetemplate='{ifeq(latesttagdistance, 0, "#", graphnode)}'
2440 2441 o 7 foo-bar+1
2441 2442 |
2442 2443 # 6 foo-bar+0
2443 2444 |\
2444 2445 | ~
2445 2446 o 5 null+5
2446 2447 |
2447 2448 ~
2448 2449
2449 2450 label() should just work in node template:
2450 2451
2451 2452 $ hg log -Gqr 7 --config extensions.color= --color=debug \
2452 2453 > --config ui.graphnodetemplate='{label("branch.{branch}", rev)}'
2453 2454 [branch.default|7] [log.node|7:02dbb8e276b8]
2454 2455 |
2455 2456 ~
2456 2457
2457 2458 $ cd ..
2458 2459
2459 2460 change graph edge styling
2460 2461
2461 2462 $ cd repo
2462 2463 $ cat << EOF >> $HGRCPATH
2463 2464 > [experimental]
2464 2465 > graphstyle.parent = |
2465 2466 > graphstyle.grandparent = :
2466 2467 > graphstyle.missing =
2467 2468 > EOF
2468 2469 $ hg log -G -r 'file("a")' -m
2469 2470 @ changeset: 36:08a19a744424
2470 2471 : branch: branch
2471 2472 : tag: tip
2472 2473 : parent: 35:9159c3644c5e
2473 2474 : parent: 35:9159c3644c5e
2474 2475 : user: test
2475 2476 : date: Thu Jan 01 00:00:36 1970 +0000
2476 2477 : summary: (36) buggy merge: identical parents
2477 2478 :
2478 2479 o changeset: 32:d06dffa21a31
2479 2480 |\ parent: 27:886ed638191b
2480 2481 | : parent: 31:621d83e11f67
2481 2482 | : user: test
2482 2483 | : date: Thu Jan 01 00:00:32 1970 +0000
2483 2484 | : summary: (32) expand
2484 2485 | :
2485 2486 o : changeset: 31:621d83e11f67
2486 2487 |\: parent: 21:d42a756af44d
2487 2488 | : parent: 30:6e11cd4b648f
2488 2489 | : user: test
2489 2490 | : date: Thu Jan 01 00:00:31 1970 +0000
2490 2491 | : summary: (31) expand
2491 2492 | :
2492 2493 o : changeset: 30:6e11cd4b648f
2493 2494 |\ \ parent: 28:44ecd0b9ae99
2494 2495 | ~ : parent: 29:cd9bb2be7593
2495 2496 | : user: test
2496 2497 | : date: Thu Jan 01 00:00:30 1970 +0000
2497 2498 | : summary: (30) expand
2498 2499 | /
2499 2500 o : changeset: 28:44ecd0b9ae99
2500 2501 |\ \ parent: 1:6db2ef61d156
2501 2502 | ~ : parent: 26:7f25b6c2f0b9
2502 2503 | : user: test
2503 2504 | : date: Thu Jan 01 00:00:28 1970 +0000
2504 2505 | : summary: (28) merge zero known
2505 2506 | /
2506 2507 o : changeset: 26:7f25b6c2f0b9
2507 2508 |\ \ parent: 18:1aa84d96232a
2508 2509 | | : parent: 25:91da8ed57247
2509 2510 | | : user: test
2510 2511 | | : date: Thu Jan 01 00:00:26 1970 +0000
2511 2512 | | : summary: (26) merge one known; far right
2512 2513 | | :
2513 2514 | o : changeset: 25:91da8ed57247
2514 2515 | |\: parent: 21:d42a756af44d
2515 2516 | | : parent: 24:a9c19a3d96b7
2516 2517 | | : user: test
2517 2518 | | : date: Thu Jan 01 00:00:25 1970 +0000
2518 2519 | | : summary: (25) merge one known; far left
2519 2520 | | :
2520 2521 | o : changeset: 24:a9c19a3d96b7
2521 2522 | |\ \ parent: 0:e6eb3150255d
2522 2523 | | ~ : parent: 23:a01cddf0766d
2523 2524 | | : user: test
2524 2525 | | : date: Thu Jan 01 00:00:24 1970 +0000
2525 2526 | | : summary: (24) merge one known; immediate right
2526 2527 | | /
2527 2528 | o : changeset: 23:a01cddf0766d
2528 2529 | |\ \ parent: 1:6db2ef61d156
2529 2530 | | ~ : parent: 22:e0d9cccacb5d
2530 2531 | | : user: test
2531 2532 | | : date: Thu Jan 01 00:00:23 1970 +0000
2532 2533 | | : summary: (23) merge one known; immediate left
2533 2534 | | /
2534 2535 | o : changeset: 22:e0d9cccacb5d
2535 2536 |/:/ parent: 18:1aa84d96232a
2536 2537 | : parent: 21:d42a756af44d
2537 2538 | : user: test
2538 2539 | : date: Thu Jan 01 00:00:22 1970 +0000
2539 2540 | : summary: (22) merge two known; one far left, one far right
2540 2541 | :
2541 2542 | o changeset: 21:d42a756af44d
2542 2543 | |\ parent: 19:31ddc2c1573b
2543 2544 | | | parent: 20:d30ed6450e32
2544 2545 | | | user: test
2545 2546 | | | date: Thu Jan 01 00:00:21 1970 +0000
2546 2547 | | | summary: (21) expand
2547 2548 | | |
2548 2549 +---o changeset: 20:d30ed6450e32
2549 2550 | | | parent: 0:e6eb3150255d
2550 2551 | | ~ parent: 18:1aa84d96232a
2551 2552 | | user: test
2552 2553 | | date: Thu Jan 01 00:00:20 1970 +0000
2553 2554 | | summary: (20) merge two known; two far right
2554 2555 | |
2555 2556 | o changeset: 19:31ddc2c1573b
2556 2557 | |\ parent: 15:1dda3f72782d
2557 2558 | | | parent: 17:44765d7c06e0
2558 2559 | | | user: test
2559 2560 | | | date: Thu Jan 01 00:00:19 1970 +0000
2560 2561 | | | summary: (19) expand
2561 2562 | | |
2562 2563 o | | changeset: 18:1aa84d96232a
2563 2564 |\| | parent: 1:6db2ef61d156
2564 2565 ~ | | parent: 15:1dda3f72782d
2565 2566 | | user: test
2566 2567 | | date: Thu Jan 01 00:00:18 1970 +0000
2567 2568 | | summary: (18) merge two known; two far left
2568 2569 / /
2569 2570 | o changeset: 17:44765d7c06e0
2570 2571 | |\ parent: 12:86b91144a6e9
2571 2572 | | | parent: 16:3677d192927d
2572 2573 | | | user: test
2573 2574 | | | date: Thu Jan 01 00:00:17 1970 +0000
2574 2575 | | | summary: (17) expand
2575 2576 | | |
2576 2577 | | o changeset: 16:3677d192927d
2577 2578 | | |\ parent: 0:e6eb3150255d
2578 2579 | | ~ ~ parent: 1:6db2ef61d156
2579 2580 | | user: test
2580 2581 | | date: Thu Jan 01 00:00:16 1970 +0000
2581 2582 | | summary: (16) merge two known; one immediate right, one near right
2582 2583 | |
2583 2584 o | changeset: 15:1dda3f72782d
2584 2585 |\ \ parent: 13:22d8966a97e3
2585 2586 | | | parent: 14:8eac370358ef
2586 2587 | | | user: test
2587 2588 | | | date: Thu Jan 01 00:00:15 1970 +0000
2588 2589 | | | summary: (15) expand
2589 2590 | | |
2590 2591 | o | changeset: 14:8eac370358ef
2591 2592 | |\| parent: 0:e6eb3150255d
2592 2593 | ~ | parent: 12:86b91144a6e9
2593 2594 | | user: test
2594 2595 | | date: Thu Jan 01 00:00:14 1970 +0000
2595 2596 | | summary: (14) merge two known; one immediate right, one far right
2596 2597 | /
2597 2598 o | changeset: 13:22d8966a97e3
2598 2599 |\ \ parent: 9:7010c0af0a35
2599 2600 | | | parent: 11:832d76e6bdf2
2600 2601 | | | user: test
2601 2602 | | | date: Thu Jan 01 00:00:13 1970 +0000
2602 2603 | | | summary: (13) expand
2603 2604 | | |
2604 2605 +---o changeset: 12:86b91144a6e9
2605 2606 | | | parent: 1:6db2ef61d156
2606 2607 | | ~ parent: 9:7010c0af0a35
2607 2608 | | user: test
2608 2609 | | date: Thu Jan 01 00:00:12 1970 +0000
2609 2610 | | summary: (12) merge two known; one immediate right, one far left
2610 2611 | |
2611 2612 | o changeset: 11:832d76e6bdf2
2612 2613 | |\ parent: 6:b105a072e251
2613 2614 | | | parent: 10:74c64d036d72
2614 2615 | | | user: test
2615 2616 | | | date: Thu Jan 01 00:00:11 1970 +0000
2616 2617 | | | summary: (11) expand
2617 2618 | | |
2618 2619 | | o changeset: 10:74c64d036d72
2619 2620 | |/| parent: 0:e6eb3150255d
2620 2621 | | ~ parent: 6:b105a072e251
2621 2622 | | user: test
2622 2623 | | date: Thu Jan 01 00:00:10 1970 +0000
2623 2624 | | summary: (10) merge two known; one immediate left, one near right
2624 2625 | |
2625 2626 o | changeset: 9:7010c0af0a35
2626 2627 |\ \ parent: 7:b632bb1b1224
2627 2628 | | | parent: 8:7a0b11f71937
2628 2629 | | | user: test
2629 2630 | | | date: Thu Jan 01 00:00:09 1970 +0000
2630 2631 | | | summary: (9) expand
2631 2632 | | |
2632 2633 | o | changeset: 8:7a0b11f71937
2633 2634 |/| | parent: 0:e6eb3150255d
2634 2635 | ~ | parent: 7:b632bb1b1224
2635 2636 | | user: test
2636 2637 | | date: Thu Jan 01 00:00:08 1970 +0000
2637 2638 | | summary: (8) merge two known; one immediate left, one far right
2638 2639 | /
2639 2640 o | changeset: 7:b632bb1b1224
2640 2641 |\ \ parent: 2:3d9a33b8d1e1
2641 2642 | ~ | parent: 5:4409d547b708
2642 2643 | | user: test
2643 2644 | | date: Thu Jan 01 00:00:07 1970 +0000
2644 2645 | | summary: (7) expand
2645 2646 | /
2646 2647 | o changeset: 6:b105a072e251
2647 2648 |/| parent: 2:3d9a33b8d1e1
2648 2649 | ~ parent: 5:4409d547b708
2649 2650 | user: test
2650 2651 | date: Thu Jan 01 00:00:06 1970 +0000
2651 2652 | summary: (6) merge two known; one immediate left, one far left
2652 2653 |
2653 2654 o changeset: 5:4409d547b708
2654 2655 |\ parent: 3:27eef8ed80b4
2655 2656 | ~ parent: 4:26a8bac39d9f
2656 2657 | user: test
2657 2658 | date: Thu Jan 01 00:00:05 1970 +0000
2658 2659 | summary: (5) expand
2659 2660 |
2660 2661 o changeset: 4:26a8bac39d9f
2661 2662 |\ parent: 1:6db2ef61d156
2662 2663 ~ ~ parent: 3:27eef8ed80b4
2663 2664 user: test
2664 2665 date: Thu Jan 01 00:00:04 1970 +0000
2665 2666 summary: (4) merge two known; one immediate left, one immediate right
2666 2667
2667 2668
2668 2669 Setting HGPLAIN ignores graphmod styling:
2669 2670
2670 2671 $ HGPLAIN=1 hg log -G -r 'file("a")' -m
2671 2672 @ changeset: 36:08a19a744424
2672 2673 | branch: branch
2673 2674 | tag: tip
2674 2675 | parent: 35:9159c3644c5e
2675 2676 | parent: 35:9159c3644c5e
2676 2677 | user: test
2677 2678 | date: Thu Jan 01 00:00:36 1970 +0000
2678 2679 | summary: (36) buggy merge: identical parents
2679 2680 |
2680 2681 o changeset: 32:d06dffa21a31
2681 2682 |\ parent: 27:886ed638191b
2682 2683 | | parent: 31:621d83e11f67
2683 2684 | | user: test
2684 2685 | | date: Thu Jan 01 00:00:32 1970 +0000
2685 2686 | | summary: (32) expand
2686 2687 | |
2687 2688 o | changeset: 31:621d83e11f67
2688 2689 |\| parent: 21:d42a756af44d
2689 2690 | | parent: 30:6e11cd4b648f
2690 2691 | | user: test
2691 2692 | | date: Thu Jan 01 00:00:31 1970 +0000
2692 2693 | | summary: (31) expand
2693 2694 | |
2694 2695 o | changeset: 30:6e11cd4b648f
2695 2696 |\ \ parent: 28:44ecd0b9ae99
2696 2697 | | | parent: 29:cd9bb2be7593
2697 2698 | | | user: test
2698 2699 | | | date: Thu Jan 01 00:00:30 1970 +0000
2699 2700 | | | summary: (30) expand
2700 2701 | | |
2701 2702 o | | changeset: 28:44ecd0b9ae99
2702 2703 |\ \ \ parent: 1:6db2ef61d156
2703 2704 | | | | parent: 26:7f25b6c2f0b9
2704 2705 | | | | user: test
2705 2706 | | | | date: Thu Jan 01 00:00:28 1970 +0000
2706 2707 | | | | summary: (28) merge zero known
2707 2708 | | | |
2708 2709 o | | | changeset: 26:7f25b6c2f0b9
2709 2710 |\ \ \ \ parent: 18:1aa84d96232a
2710 2711 | | | | | parent: 25:91da8ed57247
2711 2712 | | | | | user: test
2712 2713 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
2713 2714 | | | | | summary: (26) merge one known; far right
2714 2715 | | | | |
2715 2716 | o-----+ changeset: 25:91da8ed57247
2716 2717 | | | | | parent: 21:d42a756af44d
2717 2718 | | | | | parent: 24:a9c19a3d96b7
2718 2719 | | | | | user: test
2719 2720 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
2720 2721 | | | | | summary: (25) merge one known; far left
2721 2722 | | | | |
2722 2723 | o | | | changeset: 24:a9c19a3d96b7
2723 2724 | |\ \ \ \ parent: 0:e6eb3150255d
2724 2725 | | | | | | parent: 23:a01cddf0766d
2725 2726 | | | | | | user: test
2726 2727 | | | | | | date: Thu Jan 01 00:00:24 1970 +0000
2727 2728 | | | | | | summary: (24) merge one known; immediate right
2728 2729 | | | | | |
2729 2730 | o---+ | | changeset: 23:a01cddf0766d
2730 2731 | | | | | | parent: 1:6db2ef61d156
2731 2732 | | | | | | parent: 22:e0d9cccacb5d
2732 2733 | | | | | | user: test
2733 2734 | | | | | | date: Thu Jan 01 00:00:23 1970 +0000
2734 2735 | | | | | | summary: (23) merge one known; immediate left
2735 2736 | | | | | |
2736 2737 | o-------+ changeset: 22:e0d9cccacb5d
2737 2738 | | | | | | parent: 18:1aa84d96232a
2738 2739 |/ / / / / parent: 21:d42a756af44d
2739 2740 | | | | | user: test
2740 2741 | | | | | date: Thu Jan 01 00:00:22 1970 +0000
2741 2742 | | | | | summary: (22) merge two known; one far left, one far right
2742 2743 | | | | |
2743 2744 | | | | o changeset: 21:d42a756af44d
2744 2745 | | | | |\ parent: 19:31ddc2c1573b
2745 2746 | | | | | | parent: 20:d30ed6450e32
2746 2747 | | | | | | user: test
2747 2748 | | | | | | date: Thu Jan 01 00:00:21 1970 +0000
2748 2749 | | | | | | summary: (21) expand
2749 2750 | | | | | |
2750 2751 +-+-------o changeset: 20:d30ed6450e32
2751 2752 | | | | | parent: 0:e6eb3150255d
2752 2753 | | | | | parent: 18:1aa84d96232a
2753 2754 | | | | | user: test
2754 2755 | | | | | date: Thu Jan 01 00:00:20 1970 +0000
2755 2756 | | | | | summary: (20) merge two known; two far right
2756 2757 | | | | |
2757 2758 | | | | o changeset: 19:31ddc2c1573b
2758 2759 | | | | |\ parent: 15:1dda3f72782d
2759 2760 | | | | | | parent: 17:44765d7c06e0
2760 2761 | | | | | | user: test
2761 2762 | | | | | | date: Thu Jan 01 00:00:19 1970 +0000
2762 2763 | | | | | | summary: (19) expand
2763 2764 | | | | | |
2764 2765 o---+---+ | changeset: 18:1aa84d96232a
2765 2766 | | | | | parent: 1:6db2ef61d156
2766 2767 / / / / / parent: 15:1dda3f72782d
2767 2768 | | | | | user: test
2768 2769 | | | | | date: Thu Jan 01 00:00:18 1970 +0000
2769 2770 | | | | | summary: (18) merge two known; two far left
2770 2771 | | | | |
2771 2772 | | | | o changeset: 17:44765d7c06e0
2772 2773 | | | | |\ parent: 12:86b91144a6e9
2773 2774 | | | | | | parent: 16:3677d192927d
2774 2775 | | | | | | user: test
2775 2776 | | | | | | date: Thu Jan 01 00:00:17 1970 +0000
2776 2777 | | | | | | summary: (17) expand
2777 2778 | | | | | |
2778 2779 +-+-------o changeset: 16:3677d192927d
2779 2780 | | | | | parent: 0:e6eb3150255d
2780 2781 | | | | | parent: 1:6db2ef61d156
2781 2782 | | | | | user: test
2782 2783 | | | | | date: Thu Jan 01 00:00:16 1970 +0000
2783 2784 | | | | | summary: (16) merge two known; one immediate right, one near right
2784 2785 | | | | |
2785 2786 | | | o | changeset: 15:1dda3f72782d
2786 2787 | | | |\ \ parent: 13:22d8966a97e3
2787 2788 | | | | | | parent: 14:8eac370358ef
2788 2789 | | | | | | user: test
2789 2790 | | | | | | date: Thu Jan 01 00:00:15 1970 +0000
2790 2791 | | | | | | summary: (15) expand
2791 2792 | | | | | |
2792 2793 +-------o | changeset: 14:8eac370358ef
2793 2794 | | | | |/ parent: 0:e6eb3150255d
2794 2795 | | | | | parent: 12:86b91144a6e9
2795 2796 | | | | | user: test
2796 2797 | | | | | date: Thu Jan 01 00:00:14 1970 +0000
2797 2798 | | | | | summary: (14) merge two known; one immediate right, one far right
2798 2799 | | | | |
2799 2800 | | | o | changeset: 13:22d8966a97e3
2800 2801 | | | |\ \ parent: 9:7010c0af0a35
2801 2802 | | | | | | parent: 11:832d76e6bdf2
2802 2803 | | | | | | user: test
2803 2804 | | | | | | date: Thu Jan 01 00:00:13 1970 +0000
2804 2805 | | | | | | summary: (13) expand
2805 2806 | | | | | |
2806 2807 | +---+---o changeset: 12:86b91144a6e9
2807 2808 | | | | | parent: 1:6db2ef61d156
2808 2809 | | | | | parent: 9:7010c0af0a35
2809 2810 | | | | | user: test
2810 2811 | | | | | date: Thu Jan 01 00:00:12 1970 +0000
2811 2812 | | | | | summary: (12) merge two known; one immediate right, one far left
2812 2813 | | | | |
2813 2814 | | | | o changeset: 11:832d76e6bdf2
2814 2815 | | | | |\ parent: 6:b105a072e251
2815 2816 | | | | | | parent: 10:74c64d036d72
2816 2817 | | | | | | user: test
2817 2818 | | | | | | date: Thu Jan 01 00:00:11 1970 +0000
2818 2819 | | | | | | summary: (11) expand
2819 2820 | | | | | |
2820 2821 +---------o changeset: 10:74c64d036d72
2821 2822 | | | | |/ parent: 0:e6eb3150255d
2822 2823 | | | | | parent: 6:b105a072e251
2823 2824 | | | | | user: test
2824 2825 | | | | | date: Thu Jan 01 00:00:10 1970 +0000
2825 2826 | | | | | summary: (10) merge two known; one immediate left, one near right
2826 2827 | | | | |
2827 2828 | | | o | changeset: 9:7010c0af0a35
2828 2829 | | | |\ \ parent: 7:b632bb1b1224
2829 2830 | | | | | | parent: 8:7a0b11f71937
2830 2831 | | | | | | user: test
2831 2832 | | | | | | date: Thu Jan 01 00:00:09 1970 +0000
2832 2833 | | | | | | summary: (9) expand
2833 2834 | | | | | |
2834 2835 +-------o | changeset: 8:7a0b11f71937
2835 2836 | | | |/ / parent: 0:e6eb3150255d
2836 2837 | | | | | parent: 7:b632bb1b1224
2837 2838 | | | | | user: test
2838 2839 | | | | | date: Thu Jan 01 00:00:08 1970 +0000
2839 2840 | | | | | summary: (8) merge two known; one immediate left, one far right
2840 2841 | | | | |
2841 2842 | | | o | changeset: 7:b632bb1b1224
2842 2843 | | | |\ \ parent: 2:3d9a33b8d1e1
2843 2844 | | | | | | parent: 5:4409d547b708
2844 2845 | | | | | | user: test
2845 2846 | | | | | | date: Thu Jan 01 00:00:07 1970 +0000
2846 2847 | | | | | | summary: (7) expand
2847 2848 | | | | | |
2848 2849 | | | +---o changeset: 6:b105a072e251
2849 2850 | | | | |/ parent: 2:3d9a33b8d1e1
2850 2851 | | | | | parent: 5:4409d547b708
2851 2852 | | | | | user: test
2852 2853 | | | | | date: Thu Jan 01 00:00:06 1970 +0000
2853 2854 | | | | | summary: (6) merge two known; one immediate left, one far left
2854 2855 | | | | |
2855 2856 | | | o | changeset: 5:4409d547b708
2856 2857 | | | |\ \ parent: 3:27eef8ed80b4
2857 2858 | | | | | | parent: 4:26a8bac39d9f
2858 2859 | | | | | | user: test
2859 2860 | | | | | | date: Thu Jan 01 00:00:05 1970 +0000
2860 2861 | | | | | | summary: (5) expand
2861 2862 | | | | | |
2862 2863 | +---o | | changeset: 4:26a8bac39d9f
2863 2864 | | | |/ / parent: 1:6db2ef61d156
2864 2865 | | | | | parent: 3:27eef8ed80b4
2865 2866 | | | | | user: test
2866 2867 | | | | | date: Thu Jan 01 00:00:04 1970 +0000
2867 2868 | | | | | summary: (4) merge two known; one immediate left, one immediate right
2868 2869 | | | | |
2869 2870
2870 2871 .. unless HGPLAINEXCEPT=graph is set:
2871 2872
2872 2873 $ HGPLAIN=1 HGPLAINEXCEPT=graph hg log -G -r 'file("a")' -m
2873 2874 @ changeset: 36:08a19a744424
2874 2875 : branch: branch
2875 2876 : tag: tip
2876 2877 : parent: 35:9159c3644c5e
2877 2878 : parent: 35:9159c3644c5e
2878 2879 : user: test
2879 2880 : date: Thu Jan 01 00:00:36 1970 +0000
2880 2881 : summary: (36) buggy merge: identical parents
2881 2882 :
2882 2883 o changeset: 32:d06dffa21a31
2883 2884 |\ parent: 27:886ed638191b
2884 2885 | : parent: 31:621d83e11f67
2885 2886 | : user: test
2886 2887 | : date: Thu Jan 01 00:00:32 1970 +0000
2887 2888 | : summary: (32) expand
2888 2889 | :
2889 2890 o : changeset: 31:621d83e11f67
2890 2891 |\: parent: 21:d42a756af44d
2891 2892 | : parent: 30:6e11cd4b648f
2892 2893 | : user: test
2893 2894 | : date: Thu Jan 01 00:00:31 1970 +0000
2894 2895 | : summary: (31) expand
2895 2896 | :
2896 2897 o : changeset: 30:6e11cd4b648f
2897 2898 |\ \ parent: 28:44ecd0b9ae99
2898 2899 | ~ : parent: 29:cd9bb2be7593
2899 2900 | : user: test
2900 2901 | : date: Thu Jan 01 00:00:30 1970 +0000
2901 2902 | : summary: (30) expand
2902 2903 | /
2903 2904 o : changeset: 28:44ecd0b9ae99
2904 2905 |\ \ parent: 1:6db2ef61d156
2905 2906 | ~ : parent: 26:7f25b6c2f0b9
2906 2907 | : user: test
2907 2908 | : date: Thu Jan 01 00:00:28 1970 +0000
2908 2909 | : summary: (28) merge zero known
2909 2910 | /
2910 2911 o : changeset: 26:7f25b6c2f0b9
2911 2912 |\ \ parent: 18:1aa84d96232a
2912 2913 | | : parent: 25:91da8ed57247
2913 2914 | | : user: test
2914 2915 | | : date: Thu Jan 01 00:00:26 1970 +0000
2915 2916 | | : summary: (26) merge one known; far right
2916 2917 | | :
2917 2918 | o : changeset: 25:91da8ed57247
2918 2919 | |\: parent: 21:d42a756af44d
2919 2920 | | : parent: 24:a9c19a3d96b7
2920 2921 | | : user: test
2921 2922 | | : date: Thu Jan 01 00:00:25 1970 +0000
2922 2923 | | : summary: (25) merge one known; far left
2923 2924 | | :
2924 2925 | o : changeset: 24:a9c19a3d96b7
2925 2926 | |\ \ parent: 0:e6eb3150255d
2926 2927 | | ~ : parent: 23:a01cddf0766d
2927 2928 | | : user: test
2928 2929 | | : date: Thu Jan 01 00:00:24 1970 +0000
2929 2930 | | : summary: (24) merge one known; immediate right
2930 2931 | | /
2931 2932 | o : changeset: 23:a01cddf0766d
2932 2933 | |\ \ parent: 1:6db2ef61d156
2933 2934 | | ~ : parent: 22:e0d9cccacb5d
2934 2935 | | : user: test
2935 2936 | | : date: Thu Jan 01 00:00:23 1970 +0000
2936 2937 | | : summary: (23) merge one known; immediate left
2937 2938 | | /
2938 2939 | o : changeset: 22:e0d9cccacb5d
2939 2940 |/:/ parent: 18:1aa84d96232a
2940 2941 | : parent: 21:d42a756af44d
2941 2942 | : user: test
2942 2943 | : date: Thu Jan 01 00:00:22 1970 +0000
2943 2944 | : summary: (22) merge two known; one far left, one far right
2944 2945 | :
2945 2946 | o changeset: 21:d42a756af44d
2946 2947 | |\ parent: 19:31ddc2c1573b
2947 2948 | | | parent: 20:d30ed6450e32
2948 2949 | | | user: test
2949 2950 | | | date: Thu Jan 01 00:00:21 1970 +0000
2950 2951 | | | summary: (21) expand
2951 2952 | | |
2952 2953 +---o changeset: 20:d30ed6450e32
2953 2954 | | | parent: 0:e6eb3150255d
2954 2955 | | ~ parent: 18:1aa84d96232a
2955 2956 | | user: test
2956 2957 | | date: Thu Jan 01 00:00:20 1970 +0000
2957 2958 | | summary: (20) merge two known; two far right
2958 2959 | |
2959 2960 | o changeset: 19:31ddc2c1573b
2960 2961 | |\ parent: 15:1dda3f72782d
2961 2962 | | | parent: 17:44765d7c06e0
2962 2963 | | | user: test
2963 2964 | | | date: Thu Jan 01 00:00:19 1970 +0000
2964 2965 | | | summary: (19) expand
2965 2966 | | |
2966 2967 o | | changeset: 18:1aa84d96232a
2967 2968 |\| | parent: 1:6db2ef61d156
2968 2969 ~ | | parent: 15:1dda3f72782d
2969 2970 | | user: test
2970 2971 | | date: Thu Jan 01 00:00:18 1970 +0000
2971 2972 | | summary: (18) merge two known; two far left
2972 2973 / /
2973 2974 | o changeset: 17:44765d7c06e0
2974 2975 | |\ parent: 12:86b91144a6e9
2975 2976 | | | parent: 16:3677d192927d
2976 2977 | | | user: test
2977 2978 | | | date: Thu Jan 01 00:00:17 1970 +0000
2978 2979 | | | summary: (17) expand
2979 2980 | | |
2980 2981 | | o changeset: 16:3677d192927d
2981 2982 | | |\ parent: 0:e6eb3150255d
2982 2983 | | ~ ~ parent: 1:6db2ef61d156
2983 2984 | | user: test
2984 2985 | | date: Thu Jan 01 00:00:16 1970 +0000
2985 2986 | | summary: (16) merge two known; one immediate right, one near right
2986 2987 | |
2987 2988 o | changeset: 15:1dda3f72782d
2988 2989 |\ \ parent: 13:22d8966a97e3
2989 2990 | | | parent: 14:8eac370358ef
2990 2991 | | | user: test
2991 2992 | | | date: Thu Jan 01 00:00:15 1970 +0000
2992 2993 | | | summary: (15) expand
2993 2994 | | |
2994 2995 | o | changeset: 14:8eac370358ef
2995 2996 | |\| parent: 0:e6eb3150255d
2996 2997 | ~ | parent: 12:86b91144a6e9
2997 2998 | | user: test
2998 2999 | | date: Thu Jan 01 00:00:14 1970 +0000
2999 3000 | | summary: (14) merge two known; one immediate right, one far right
3000 3001 | /
3001 3002 o | changeset: 13:22d8966a97e3
3002 3003 |\ \ parent: 9:7010c0af0a35
3003 3004 | | | parent: 11:832d76e6bdf2
3004 3005 | | | user: test
3005 3006 | | | date: Thu Jan 01 00:00:13 1970 +0000
3006 3007 | | | summary: (13) expand
3007 3008 | | |
3008 3009 +---o changeset: 12:86b91144a6e9
3009 3010 | | | parent: 1:6db2ef61d156
3010 3011 | | ~ parent: 9:7010c0af0a35
3011 3012 | | user: test
3012 3013 | | date: Thu Jan 01 00:00:12 1970 +0000
3013 3014 | | summary: (12) merge two known; one immediate right, one far left
3014 3015 | |
3015 3016 | o changeset: 11:832d76e6bdf2
3016 3017 | |\ parent: 6:b105a072e251
3017 3018 | | | parent: 10:74c64d036d72
3018 3019 | | | user: test
3019 3020 | | | date: Thu Jan 01 00:00:11 1970 +0000
3020 3021 | | | summary: (11) expand
3021 3022 | | |
3022 3023 | | o changeset: 10:74c64d036d72
3023 3024 | |/| parent: 0:e6eb3150255d
3024 3025 | | ~ parent: 6:b105a072e251
3025 3026 | | user: test
3026 3027 | | date: Thu Jan 01 00:00:10 1970 +0000
3027 3028 | | summary: (10) merge two known; one immediate left, one near right
3028 3029 | |
3029 3030 o | changeset: 9:7010c0af0a35
3030 3031 |\ \ parent: 7:b632bb1b1224
3031 3032 | | | parent: 8:7a0b11f71937
3032 3033 | | | user: test
3033 3034 | | | date: Thu Jan 01 00:00:09 1970 +0000
3034 3035 | | | summary: (9) expand
3035 3036 | | |
3036 3037 | o | changeset: 8:7a0b11f71937
3037 3038 |/| | parent: 0:e6eb3150255d
3038 3039 | ~ | parent: 7:b632bb1b1224
3039 3040 | | user: test
3040 3041 | | date: Thu Jan 01 00:00:08 1970 +0000
3041 3042 | | summary: (8) merge two known; one immediate left, one far right
3042 3043 | /
3043 3044 o | changeset: 7:b632bb1b1224
3044 3045 |\ \ parent: 2:3d9a33b8d1e1
3045 3046 | ~ | parent: 5:4409d547b708
3046 3047 | | user: test
3047 3048 | | date: Thu Jan 01 00:00:07 1970 +0000
3048 3049 | | summary: (7) expand
3049 3050 | /
3050 3051 | o changeset: 6:b105a072e251
3051 3052 |/| parent: 2:3d9a33b8d1e1
3052 3053 | ~ parent: 5:4409d547b708
3053 3054 | user: test
3054 3055 | date: Thu Jan 01 00:00:06 1970 +0000
3055 3056 | summary: (6) merge two known; one immediate left, one far left
3056 3057 |
3057 3058 o changeset: 5:4409d547b708
3058 3059 |\ parent: 3:27eef8ed80b4
3059 3060 | ~ parent: 4:26a8bac39d9f
3060 3061 | user: test
3061 3062 | date: Thu Jan 01 00:00:05 1970 +0000
3062 3063 | summary: (5) expand
3063 3064 |
3064 3065 o changeset: 4:26a8bac39d9f
3065 3066 |\ parent: 1:6db2ef61d156
3066 3067 ~ ~ parent: 3:27eef8ed80b4
3067 3068 user: test
3068 3069 date: Thu Jan 01 00:00:04 1970 +0000
3069 3070 summary: (4) merge two known; one immediate left, one immediate right
3070 3071
3071 3072 Draw only part of a grandparent line differently with "<N><char>"; only the
3072 3073 last N lines (for positive N) or everything but the first N lines (for
3073 3074 negative N) along the current node use the style, the rest of the edge uses
3074 3075 the parent edge styling.
3075 3076
3076 3077 Last 3 lines:
3077 3078
3078 3079 $ cat << EOF >> $HGRCPATH
3079 3080 > [experimental]
3080 3081 > graphstyle.parent = !
3081 3082 > graphstyle.grandparent = 3.
3082 3083 > graphstyle.missing =
3083 3084 > EOF
3084 3085 $ hg log -G -r '36:18 & file("a")' -m
3085 3086 @ changeset: 36:08a19a744424
3086 3087 ! branch: branch
3087 3088 ! tag: tip
3088 3089 ! parent: 35:9159c3644c5e
3089 3090 ! parent: 35:9159c3644c5e
3090 3091 ! user: test
3091 3092 . date: Thu Jan 01 00:00:36 1970 +0000
3092 3093 . summary: (36) buggy merge: identical parents
3093 3094 .
3094 3095 o changeset: 32:d06dffa21a31
3095 3096 !\ parent: 27:886ed638191b
3096 3097 ! ! parent: 31:621d83e11f67
3097 3098 ! ! user: test
3098 3099 ! . date: Thu Jan 01 00:00:32 1970 +0000
3099 3100 ! . summary: (32) expand
3100 3101 ! .
3101 3102 o ! changeset: 31:621d83e11f67
3102 3103 !\! parent: 21:d42a756af44d
3103 3104 ! ! parent: 30:6e11cd4b648f
3104 3105 ! ! user: test
3105 3106 ! ! date: Thu Jan 01 00:00:31 1970 +0000
3106 3107 ! ! summary: (31) expand
3107 3108 ! !
3108 3109 o ! changeset: 30:6e11cd4b648f
3109 3110 !\ \ parent: 28:44ecd0b9ae99
3110 3111 ! ~ ! parent: 29:cd9bb2be7593
3111 3112 ! ! user: test
3112 3113 ! ! date: Thu Jan 01 00:00:30 1970 +0000
3113 3114 ! ! summary: (30) expand
3114 3115 ! /
3115 3116 o ! changeset: 28:44ecd0b9ae99
3116 3117 !\ \ parent: 1:6db2ef61d156
3117 3118 ! ~ ! parent: 26:7f25b6c2f0b9
3118 3119 ! ! user: test
3119 3120 ! ! date: Thu Jan 01 00:00:28 1970 +0000
3120 3121 ! ! summary: (28) merge zero known
3121 3122 ! /
3122 3123 o ! changeset: 26:7f25b6c2f0b9
3123 3124 !\ \ parent: 18:1aa84d96232a
3124 3125 ! ! ! parent: 25:91da8ed57247
3125 3126 ! ! ! user: test
3126 3127 ! ! ! date: Thu Jan 01 00:00:26 1970 +0000
3127 3128 ! ! ! summary: (26) merge one known; far right
3128 3129 ! ! !
3129 3130 ! o ! changeset: 25:91da8ed57247
3130 3131 ! !\! parent: 21:d42a756af44d
3131 3132 ! ! ! parent: 24:a9c19a3d96b7
3132 3133 ! ! ! user: test
3133 3134 ! ! ! date: Thu Jan 01 00:00:25 1970 +0000
3134 3135 ! ! ! summary: (25) merge one known; far left
3135 3136 ! ! !
3136 3137 ! o ! changeset: 24:a9c19a3d96b7
3137 3138 ! !\ \ parent: 0:e6eb3150255d
3138 3139 ! ! ~ ! parent: 23:a01cddf0766d
3139 3140 ! ! ! user: test
3140 3141 ! ! ! date: Thu Jan 01 00:00:24 1970 +0000
3141 3142 ! ! ! summary: (24) merge one known; immediate right
3142 3143 ! ! /
3143 3144 ! o ! changeset: 23:a01cddf0766d
3144 3145 ! !\ \ parent: 1:6db2ef61d156
3145 3146 ! ! ~ ! parent: 22:e0d9cccacb5d
3146 3147 ! ! ! user: test
3147 3148 ! ! ! date: Thu Jan 01 00:00:23 1970 +0000
3148 3149 ! ! ! summary: (23) merge one known; immediate left
3149 3150 ! ! /
3150 3151 ! o ! changeset: 22:e0d9cccacb5d
3151 3152 !/!/ parent: 18:1aa84d96232a
3152 3153 ! ! parent: 21:d42a756af44d
3153 3154 ! ! user: test
3154 3155 ! ! date: Thu Jan 01 00:00:22 1970 +0000
3155 3156 ! ! summary: (22) merge two known; one far left, one far right
3156 3157 ! !
3157 3158 ! o changeset: 21:d42a756af44d
3158 3159 ! !\ parent: 19:31ddc2c1573b
3159 3160 ! ! ! parent: 20:d30ed6450e32
3160 3161 ! ! ! user: test
3161 3162 ! ! ! date: Thu Jan 01 00:00:21 1970 +0000
3162 3163 ! ! ! summary: (21) expand
3163 3164 ! ! !
3164 3165 +---o changeset: 20:d30ed6450e32
3165 3166 ! ! | parent: 0:e6eb3150255d
3166 3167 ! ! ~ parent: 18:1aa84d96232a
3167 3168 ! ! user: test
3168 3169 ! ! date: Thu Jan 01 00:00:20 1970 +0000
3169 3170 ! ! summary: (20) merge two known; two far right
3170 3171 ! !
3171 3172 ! o changeset: 19:31ddc2c1573b
3172 3173 ! |\ parent: 15:1dda3f72782d
3173 3174 ! ~ ~ parent: 17:44765d7c06e0
3174 3175 ! user: test
3175 3176 ! date: Thu Jan 01 00:00:19 1970 +0000
3176 3177 ! summary: (19) expand
3177 3178 !
3178 3179 o changeset: 18:1aa84d96232a
3179 3180 |\ parent: 1:6db2ef61d156
3180 3181 ~ ~ parent: 15:1dda3f72782d
3181 3182 user: test
3182 3183 date: Thu Jan 01 00:00:18 1970 +0000
3183 3184 summary: (18) merge two known; two far left
3184 3185
3185 3186 All but the first 3 lines:
3186 3187
3187 3188 $ cat << EOF >> $HGRCPATH
3188 3189 > [experimental]
3189 3190 > graphstyle.parent = !
3190 3191 > graphstyle.grandparent = -3.
3191 3192 > graphstyle.missing =
3192 3193 > EOF
3193 3194 $ hg log -G -r '36:18 & file("a")' -m
3194 3195 @ changeset: 36:08a19a744424
3195 3196 ! branch: branch
3196 3197 ! tag: tip
3197 3198 . parent: 35:9159c3644c5e
3198 3199 . parent: 35:9159c3644c5e
3199 3200 . user: test
3200 3201 . date: Thu Jan 01 00:00:36 1970 +0000
3201 3202 . summary: (36) buggy merge: identical parents
3202 3203 .
3203 3204 o changeset: 32:d06dffa21a31
3204 3205 !\ parent: 27:886ed638191b
3205 3206 ! ! parent: 31:621d83e11f67
3206 3207 ! . user: test
3207 3208 ! . date: Thu Jan 01 00:00:32 1970 +0000
3208 3209 ! . summary: (32) expand
3209 3210 ! .
3210 3211 o ! changeset: 31:621d83e11f67
3211 3212 !\! parent: 21:d42a756af44d
3212 3213 ! ! parent: 30:6e11cd4b648f
3213 3214 ! ! user: test
3214 3215 ! ! date: Thu Jan 01 00:00:31 1970 +0000
3215 3216 ! ! summary: (31) expand
3216 3217 ! !
3217 3218 o ! changeset: 30:6e11cd4b648f
3218 3219 !\ \ parent: 28:44ecd0b9ae99
3219 3220 ! ~ ! parent: 29:cd9bb2be7593
3220 3221 ! ! user: test
3221 3222 ! ! date: Thu Jan 01 00:00:30 1970 +0000
3222 3223 ! ! summary: (30) expand
3223 3224 ! /
3224 3225 o ! changeset: 28:44ecd0b9ae99
3225 3226 !\ \ parent: 1:6db2ef61d156
3226 3227 ! ~ ! parent: 26:7f25b6c2f0b9
3227 3228 ! ! user: test
3228 3229 ! ! date: Thu Jan 01 00:00:28 1970 +0000
3229 3230 ! ! summary: (28) merge zero known
3230 3231 ! /
3231 3232 o ! changeset: 26:7f25b6c2f0b9
3232 3233 !\ \ parent: 18:1aa84d96232a
3233 3234 ! ! ! parent: 25:91da8ed57247
3234 3235 ! ! ! user: test
3235 3236 ! ! ! date: Thu Jan 01 00:00:26 1970 +0000
3236 3237 ! ! ! summary: (26) merge one known; far right
3237 3238 ! ! !
3238 3239 ! o ! changeset: 25:91da8ed57247
3239 3240 ! !\! parent: 21:d42a756af44d
3240 3241 ! ! ! parent: 24:a9c19a3d96b7
3241 3242 ! ! ! user: test
3242 3243 ! ! ! date: Thu Jan 01 00:00:25 1970 +0000
3243 3244 ! ! ! summary: (25) merge one known; far left
3244 3245 ! ! !
3245 3246 ! o ! changeset: 24:a9c19a3d96b7
3246 3247 ! !\ \ parent: 0:e6eb3150255d
3247 3248 ! ! ~ ! parent: 23:a01cddf0766d
3248 3249 ! ! ! user: test
3249 3250 ! ! ! date: Thu Jan 01 00:00:24 1970 +0000
3250 3251 ! ! ! summary: (24) merge one known; immediate right
3251 3252 ! ! /
3252 3253 ! o ! changeset: 23:a01cddf0766d
3253 3254 ! !\ \ parent: 1:6db2ef61d156
3254 3255 ! ! ~ ! parent: 22:e0d9cccacb5d
3255 3256 ! ! ! user: test
3256 3257 ! ! ! date: Thu Jan 01 00:00:23 1970 +0000
3257 3258 ! ! ! summary: (23) merge one known; immediate left
3258 3259 ! ! /
3259 3260 ! o ! changeset: 22:e0d9cccacb5d
3260 3261 !/!/ parent: 18:1aa84d96232a
3261 3262 ! ! parent: 21:d42a756af44d
3262 3263 ! ! user: test
3263 3264 ! ! date: Thu Jan 01 00:00:22 1970 +0000
3264 3265 ! ! summary: (22) merge two known; one far left, one far right
3265 3266 ! !
3266 3267 ! o changeset: 21:d42a756af44d
3267 3268 ! !\ parent: 19:31ddc2c1573b
3268 3269 ! ! ! parent: 20:d30ed6450e32
3269 3270 ! ! ! user: test
3270 3271 ! ! ! date: Thu Jan 01 00:00:21 1970 +0000
3271 3272 ! ! ! summary: (21) expand
3272 3273 ! ! !
3273 3274 +---o changeset: 20:d30ed6450e32
3274 3275 ! ! | parent: 0:e6eb3150255d
3275 3276 ! ! ~ parent: 18:1aa84d96232a
3276 3277 ! ! user: test
3277 3278 ! ! date: Thu Jan 01 00:00:20 1970 +0000
3278 3279 ! ! summary: (20) merge two known; two far right
3279 3280 ! !
3280 3281 ! o changeset: 19:31ddc2c1573b
3281 3282 ! |\ parent: 15:1dda3f72782d
3282 3283 ! ~ ~ parent: 17:44765d7c06e0
3283 3284 ! user: test
3284 3285 ! date: Thu Jan 01 00:00:19 1970 +0000
3285 3286 ! summary: (19) expand
3286 3287 !
3287 3288 o changeset: 18:1aa84d96232a
3288 3289 |\ parent: 1:6db2ef61d156
3289 3290 ~ ~ parent: 15:1dda3f72782d
3290 3291 user: test
3291 3292 date: Thu Jan 01 00:00:18 1970 +0000
3292 3293 summary: (18) merge two known; two far left
3293 3294
3294 3295 $ cd ..
3295 3296
3296 3297 Change graph shorten, test better with graphstyle.missing not none
3297 3298
3298 3299 $ cd repo
3299 3300 $ cat << EOF >> $HGRCPATH
3300 3301 > [experimental]
3301 3302 > graphstyle.parent = |
3302 3303 > graphstyle.grandparent = :
3303 3304 > graphstyle.missing = '
3304 3305 > graphshorten = true
3305 3306 > EOF
3306 3307 $ hg log -G -r 'file("a")' -m -T '{rev} {desc}'
3307 3308 @ 36 (36) buggy merge: identical parents
3308 3309 o 32 (32) expand
3309 3310 |\
3310 3311 o : 31 (31) expand
3311 3312 |\:
3312 3313 o : 30 (30) expand
3313 3314 |\ \
3314 3315 o \ \ 28 (28) merge zero known
3315 3316 |\ \ \
3316 3317 o \ \ \ 26 (26) merge one known; far right
3317 3318 |\ \ \ \
3318 3319 | o-----+ 25 (25) merge one known; far left
3319 3320 | o ' ' : 24 (24) merge one known; immediate right
3320 3321 | |\ \ \ \
3321 3322 | o---+ ' : 23 (23) merge one known; immediate left
3322 3323 | o-------+ 22 (22) merge two known; one far left, one far right
3323 3324 |/ / / / /
3324 3325 | ' ' ' o 21 (21) expand
3325 3326 | ' ' ' |\
3326 3327 +-+-------o 20 (20) merge two known; two far right
3327 3328 | ' ' ' o 19 (19) expand
3328 3329 | ' ' ' |\
3329 3330 o---+---+ | 18 (18) merge two known; two far left
3330 3331 / / / / /
3331 3332 ' ' ' | o 17 (17) expand
3332 3333 ' ' ' | |\
3333 3334 +-+-------o 16 (16) merge two known; one immediate right, one near right
3334 3335 ' ' ' o | 15 (15) expand
3335 3336 ' ' ' |\ \
3336 3337 +-------o | 14 (14) merge two known; one immediate right, one far right
3337 3338 ' ' ' | |/
3338 3339 ' ' ' o | 13 (13) expand
3339 3340 ' ' ' |\ \
3340 3341 ' +---+---o 12 (12) merge two known; one immediate right, one far left
3341 3342 ' ' ' | o 11 (11) expand
3342 3343 ' ' ' | |\
3343 3344 +---------o 10 (10) merge two known; one immediate left, one near right
3344 3345 ' ' ' | |/
3345 3346 ' ' ' o | 9 (9) expand
3346 3347 ' ' ' |\ \
3347 3348 +-------o | 8 (8) merge two known; one immediate left, one far right
3348 3349 ' ' ' |/ /
3349 3350 ' ' ' o | 7 (7) expand
3350 3351 ' ' ' |\ \
3351 3352 ' ' ' +---o 6 (6) merge two known; one immediate left, one far left
3352 3353 ' ' ' | '/
3353 3354 ' ' ' o ' 5 (5) expand
3354 3355 ' ' ' |\ \
3355 3356 ' +---o ' ' 4 (4) merge two known; one immediate left, one immediate right
3356 3357 ' ' ' '/ /
3357 3358
3358 3359 behavior with newlines
3359 3360
3360 3361 $ hg log -G -r ::2 -T '{rev} {desc}'
3361 3362 o 2 (2) collapse
3362 3363 o 1 (1) collapse
3363 3364 o 0 (0) root
3364 3365
3365 3366 $ hg log -G -r ::2 -T '{rev} {desc}\n'
3366 3367 o 2 (2) collapse
3367 3368 o 1 (1) collapse
3368 3369 o 0 (0) root
3369 3370
3370 3371 $ hg log -G -r ::2 -T '{rev} {desc}\n\n'
3371 3372 o 2 (2) collapse
3372 3373 |
3373 3374 o 1 (1) collapse
3374 3375 |
3375 3376 o 0 (0) root
3376 3377
3377 3378
3378 3379 $ hg log -G -r ::2 -T '\n{rev} {desc}'
3379 3380 o
3380 3381 | 2 (2) collapse
3381 3382 o
3382 3383 | 1 (1) collapse
3383 3384 o
3384 3385 0 (0) root
3385 3386
3386 3387 $ hg log -G -r ::2 -T '{rev} {desc}\n\n\n'
3387 3388 o 2 (2) collapse
3388 3389 |
3389 3390 |
3390 3391 o 1 (1) collapse
3391 3392 |
3392 3393 |
3393 3394 o 0 (0) root
3394 3395
3395 3396
3396 3397 $ cd ..
3397 3398
3398 3399 When inserting extra line nodes to handle more than 2 parents, ensure that
3399 3400 the right node styles are used (issue5174):
3400 3401
3401 3402 $ hg init repo-issue5174
3402 3403 $ cd repo-issue5174
3403 3404 $ echo a > f0
3404 3405 $ hg ci -Aqm 0
3405 3406 $ echo a > f1
3406 3407 $ hg ci -Aqm 1
3407 3408 $ echo a > f2
3408 3409 $ hg ci -Aqm 2
3409 3410 $ hg co ".^"
3410 3411 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
3411 3412 $ echo a > f3
3412 3413 $ hg ci -Aqm 3
3413 3414 $ hg co ".^^"
3414 3415 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
3415 3416 $ echo a > f4
3416 3417 $ hg ci -Aqm 4
3417 3418 $ hg merge -r 2
3418 3419 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
3419 3420 (branch merge, don't forget to commit)
3420 3421 $ hg ci -qm 5
3421 3422 $ hg merge -r 3
3422 3423 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
3423 3424 (branch merge, don't forget to commit)
3424 3425 $ hg ci -qm 6
3425 3426 $ hg log -G -r '0 | 1 | 2 | 6'
3426 3427 @ changeset: 6:851fe89689ad
3427 3428 :\ tag: tip
3428 3429 : : parent: 5:4f1e3cf15f5d
3429 3430 : : parent: 3:b74ba7084d2d
3430 3431 : : user: test
3431 3432 : : date: Thu Jan 01 00:00:00 1970 +0000
3432 3433 : : summary: 6
3433 3434 : :
3434 3435 : \
3435 3436 : :\
3436 3437 : o : changeset: 2:3e6599df4cce
3437 3438 : :/ user: test
3438 3439 : : date: Thu Jan 01 00:00:00 1970 +0000
3439 3440 : : summary: 2
3440 3441 : :
3441 3442 : o changeset: 1:bd9a55143933
3442 3443 :/ user: test
3443 3444 : date: Thu Jan 01 00:00:00 1970 +0000
3444 3445 : summary: 1
3445 3446 :
3446 3447 o changeset: 0:870a5edc339c
3447 3448 user: test
3448 3449 date: Thu Jan 01 00:00:00 1970 +0000
3449 3450 summary: 0
3450 3451
3451 3452
3452 3453 $ cd ..
3453 3454
3454 3455 Multiple roots (issue5440):
3455 3456
3456 3457 $ hg init multiroots
3457 3458 $ cd multiroots
3458 3459 $ cat <<EOF > .hg/hgrc
3459 3460 > [ui]
3460 3461 > logtemplate = '{rev} {desc}\n\n'
3461 3462 > EOF
3462 3463
3463 3464 $ touch foo
3464 3465 $ hg ci -Aqm foo
3465 3466 $ hg co -q null
3466 3467 $ touch bar
3467 3468 $ hg ci -Aqm bar
3468 3469
3469 3470 $ hg log -Gr null:
3470 3471 @ 1 bar
3471 3472 |
3472 3473 | o 0 foo
3473 3474 |/
3474 3475 o -1
3475 3476
3476 3477 $ hg log -Gr null+0
3477 3478 o 0 foo
3478 3479 |
3479 3480 o -1
3480 3481
3481 3482 $ hg log -Gr null+1
3482 3483 @ 1 bar
3483 3484 |
3484 3485 o -1
3485 3486
3486 3487
3487 3488 $ cd ..
@@ -1,2841 +1,2841 b''
1 1 $ HGENCODING=utf-8
2 2 $ export HGENCODING
3 3 $ cat > testrevset.py << EOF
4 4 > import mercurial.revset
5 5 >
6 6 > baseset = mercurial.revset.baseset
7 7 >
8 8 > def r3232(repo, subset, x):
9 9 > """"simple revset that return [3,2,3,2]
10 10 >
11 11 > revisions duplicated on purpose.
12 12 > """
13 13 > if 3 not in subset:
14 14 > if 2 in subset:
15 15 > return baseset([2,2])
16 16 > return baseset()
17 17 > return baseset([3,3,2,2])
18 18 >
19 19 > mercurial.revset.symbols[b'r3232'] = r3232
20 20 > EOF
21 21 $ cat >> $HGRCPATH << EOF
22 22 > [extensions]
23 23 > drawdag=$TESTDIR/drawdag.py
24 24 > testrevset=$TESTTMP/testrevset.py
25 25 > EOF
26 26
27 27 $ try() {
28 28 > hg debugrevspec --debug "$@"
29 29 > }
30 30
31 31 $ log() {
32 32 > hg log --template '{rev}\n' -r "$1"
33 33 > }
34 34
35 35 extension to build '_intlist()' and '_hexlist()', which is necessary because
36 36 these predicates use '\0' as a separator:
37 37
38 38 $ cat <<EOF > debugrevlistspec.py
39 39 > from __future__ import absolute_import
40 40 > from mercurial import (
41 41 > node as nodemod,
42 42 > registrar,
43 43 > revset,
44 44 > revsetlang,
45 > smartset,
46 45 > )
46 > from mercurial.utils import stringutil
47 47 > cmdtable = {}
48 48 > command = registrar.command(cmdtable)
49 49 > @command(b'debugrevlistspec',
50 50 > [(b'', b'optimize', None, b'print parsed tree after optimizing'),
51 51 > (b'', b'bin', None, b'unhexlify arguments')])
52 52 > def debugrevlistspec(ui, repo, fmt, *args, **opts):
53 53 > if opts['bin']:
54 54 > args = map(nodemod.bin, args)
55 55 > expr = revsetlang.formatspec(fmt, list(args))
56 56 > if ui.verbose:
57 57 > tree = revsetlang.parse(expr, lookup=revset.lookupfn(repo))
58 58 > ui.note(revsetlang.prettyformat(tree), b"\n")
59 59 > if opts["optimize"]:
60 60 > opttree = revsetlang.optimize(revsetlang.analyze(tree))
61 61 > ui.note(b"* optimized:\n", revsetlang.prettyformat(opttree),
62 62 > b"\n")
63 63 > func = revset.match(ui, expr, lookup=revset.lookupfn(repo))
64 64 > revs = func(repo)
65 65 > if ui.verbose:
66 > ui.note(b"* set:\n", smartset.prettyformat(revs), b"\n")
66 > ui.note(b"* set:\n", stringutil.prettyrepr(revs), b"\n")
67 67 > for c in revs:
68 68 > ui.write(b"%d\n" % c)
69 69 > EOF
70 70 $ cat <<EOF >> $HGRCPATH
71 71 > [extensions]
72 72 > debugrevlistspec = $TESTTMP/debugrevlistspec.py
73 73 > EOF
74 74 $ trylist() {
75 75 > hg debugrevlistspec --debug "$@"
76 76 > }
77 77
78 78 $ hg init repo
79 79 $ cd repo
80 80
81 81 $ echo a > a
82 82 $ hg branch a
83 83 marked working directory as branch a
84 84 (branches are permanent and global, did you want a bookmark?)
85 85 $ hg ci -Aqm0
86 86
87 87 $ echo b > b
88 88 $ hg branch b
89 89 marked working directory as branch b
90 90 $ hg ci -Aqm1
91 91
92 92 $ rm a
93 93 $ hg branch a-b-c-
94 94 marked working directory as branch a-b-c-
95 95 $ hg ci -Aqm2 -u Bob
96 96
97 97 $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
98 98 2
99 99 $ hg log -r "extra('branch')" --template '{rev}\n'
100 100 0
101 101 1
102 102 2
103 103 $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
104 104 0 a
105 105 2 a-b-c-
106 106
107 107 $ hg co 1
108 108 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
109 109 $ hg branch +a+b+c+
110 110 marked working directory as branch +a+b+c+
111 111 $ hg ci -Aqm3
112 112
113 113 $ hg co 2 # interleave
114 114 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
115 115 $ echo bb > b
116 116 $ hg branch -- -a-b-c-
117 117 marked working directory as branch -a-b-c-
118 118 $ hg ci -Aqm4 -d "May 12 2005"
119 119
120 120 $ hg co 3
121 121 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
122 122 $ hg branch !a/b/c/
123 123 marked working directory as branch !a/b/c/
124 124 $ hg ci -Aqm"5 bug"
125 125
126 126 $ hg merge 4
127 127 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
128 128 (branch merge, don't forget to commit)
129 129 $ hg branch _a_b_c_
130 130 marked working directory as branch _a_b_c_
131 131 $ hg ci -Aqm"6 issue619"
132 132
133 133 $ hg branch .a.b.c.
134 134 marked working directory as branch .a.b.c.
135 135 $ hg ci -Aqm7
136 136
137 137 $ hg branch all
138 138 marked working directory as branch all
139 139
140 140 $ hg co 4
141 141 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
142 142 $ hg branch Γ©
143 143 marked working directory as branch \xc3\xa9 (esc)
144 144 $ hg ci -Aqm9
145 145
146 146 $ hg tag -r6 1.0
147 147 $ hg bookmark -r6 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
148 148
149 149 $ hg clone --quiet -U -r 7 . ../remote1
150 150 $ hg clone --quiet -U -r 8 . ../remote2
151 151 $ echo "[paths]" >> .hg/hgrc
152 152 $ echo "default = ../remote1" >> .hg/hgrc
153 153
154 154 trivial
155 155
156 156 $ try 0:1
157 157 (range
158 158 (symbol '0')
159 159 (symbol '1'))
160 160 * set:
161 161 <spanset+ 0:2>
162 162 0
163 163 1
164 164 $ try --optimize :
165 165 (rangeall
166 166 None)
167 167 * optimized:
168 168 (rangeall
169 169 None)
170 170 * set:
171 171 <spanset+ 0:10>
172 172 0
173 173 1
174 174 2
175 175 3
176 176 4
177 177 5
178 178 6
179 179 7
180 180 8
181 181 9
182 182 $ try 3::6
183 183 (dagrange
184 184 (symbol '3')
185 185 (symbol '6'))
186 186 * set:
187 187 <baseset+ [3, 5, 6]>
188 188 3
189 189 5
190 190 6
191 191 $ try '0|1|2'
192 192 (or
193 193 (list
194 194 (symbol '0')
195 195 (symbol '1')
196 196 (symbol '2')))
197 197 * set:
198 198 <baseset [0, 1, 2]>
199 199 0
200 200 1
201 201 2
202 202
203 203 names that should work without quoting
204 204
205 205 $ try a
206 206 (symbol 'a')
207 207 * set:
208 208 <baseset [0]>
209 209 0
210 210 $ try b-a
211 211 (minus
212 212 (symbol 'b')
213 213 (symbol 'a'))
214 214 * set:
215 215 <filteredset
216 216 <baseset [1]>,
217 217 <not
218 218 <baseset [0]>>>
219 219 1
220 220 $ try _a_b_c_
221 221 (symbol '_a_b_c_')
222 222 * set:
223 223 <baseset [6]>
224 224 6
225 225 $ try _a_b_c_-a
226 226 (minus
227 227 (symbol '_a_b_c_')
228 228 (symbol 'a'))
229 229 * set:
230 230 <filteredset
231 231 <baseset [6]>,
232 232 <not
233 233 <baseset [0]>>>
234 234 6
235 235 $ try .a.b.c.
236 236 (symbol '.a.b.c.')
237 237 * set:
238 238 <baseset [7]>
239 239 7
240 240 $ try .a.b.c.-a
241 241 (minus
242 242 (symbol '.a.b.c.')
243 243 (symbol 'a'))
244 244 * set:
245 245 <filteredset
246 246 <baseset [7]>,
247 247 <not
248 248 <baseset [0]>>>
249 249 7
250 250
251 251 names that should be caught by fallback mechanism
252 252
253 253 $ try -- '-a-b-c-'
254 254 (symbol '-a-b-c-')
255 255 * set:
256 256 <baseset [4]>
257 257 4
258 258 $ log -a-b-c-
259 259 4
260 260 $ try '+a+b+c+'
261 261 (symbol '+a+b+c+')
262 262 * set:
263 263 <baseset [3]>
264 264 3
265 265 $ try '+a+b+c+:'
266 266 (rangepost
267 267 (symbol '+a+b+c+'))
268 268 * set:
269 269 <spanset+ 3:10>
270 270 3
271 271 4
272 272 5
273 273 6
274 274 7
275 275 8
276 276 9
277 277 $ try ':+a+b+c+'
278 278 (rangepre
279 279 (symbol '+a+b+c+'))
280 280 * set:
281 281 <spanset+ 0:4>
282 282 0
283 283 1
284 284 2
285 285 3
286 286 $ try -- '-a-b-c-:+a+b+c+'
287 287 (range
288 288 (symbol '-a-b-c-')
289 289 (symbol '+a+b+c+'))
290 290 * set:
291 291 <spanset- 3:5>
292 292 4
293 293 3
294 294 $ log '-a-b-c-:+a+b+c+'
295 295 4
296 296 3
297 297
298 298 $ try -- -a-b-c--a # complains
299 299 (minus
300 300 (minus
301 301 (minus
302 302 (negate
303 303 (symbol 'a'))
304 304 (symbol 'b'))
305 305 (symbol 'c'))
306 306 (negate
307 307 (symbol 'a')))
308 308 abort: unknown revision '-a'!
309 309 [255]
310 310 $ try Γ©
311 311 (symbol '\xc3\xa9')
312 312 * set:
313 313 <baseset [9]>
314 314 9
315 315
316 316 no quoting needed
317 317
318 318 $ log ::a-b-c-
319 319 0
320 320 1
321 321 2
322 322
323 323 quoting needed
324 324
325 325 $ try '"-a-b-c-"-a'
326 326 (minus
327 327 (string '-a-b-c-')
328 328 (symbol 'a'))
329 329 * set:
330 330 <filteredset
331 331 <baseset [4]>,
332 332 <not
333 333 <baseset [0]>>>
334 334 4
335 335
336 336 $ log '1 or 2'
337 337 1
338 338 2
339 339 $ log '1|2'
340 340 1
341 341 2
342 342 $ log '1 and 2'
343 343 $ log '1&2'
344 344 $ try '1&2|3' # precedence - and is higher
345 345 (or
346 346 (list
347 347 (and
348 348 (symbol '1')
349 349 (symbol '2'))
350 350 (symbol '3')))
351 351 * set:
352 352 <addset
353 353 <baseset []>,
354 354 <baseset [3]>>
355 355 3
356 356 $ try '1|2&3'
357 357 (or
358 358 (list
359 359 (symbol '1')
360 360 (and
361 361 (symbol '2')
362 362 (symbol '3'))))
363 363 * set:
364 364 <addset
365 365 <baseset [1]>,
366 366 <baseset []>>
367 367 1
368 368 $ try '1&2&3' # associativity
369 369 (and
370 370 (and
371 371 (symbol '1')
372 372 (symbol '2'))
373 373 (symbol '3'))
374 374 * set:
375 375 <baseset []>
376 376 $ try '1|(2|3)'
377 377 (or
378 378 (list
379 379 (symbol '1')
380 380 (group
381 381 (or
382 382 (list
383 383 (symbol '2')
384 384 (symbol '3'))))))
385 385 * set:
386 386 <addset
387 387 <baseset [1]>,
388 388 <baseset [2, 3]>>
389 389 1
390 390 2
391 391 3
392 392 $ log '1.0' # tag
393 393 6
394 394 $ log 'a' # branch
395 395 0
396 396 $ log '2785f51ee'
397 397 0
398 398 $ log 'date(2005)'
399 399 4
400 400 $ log 'date(this is a test)'
401 401 hg: parse error at 10: unexpected token: symbol
402 402 (date(this is a test)
403 403 ^ here)
404 404 [255]
405 405 $ log 'date()'
406 406 hg: parse error: date requires a string
407 407 [255]
408 408 $ log 'date'
409 409 abort: unknown revision 'date'!
410 410 [255]
411 411 $ log 'date('
412 412 hg: parse error at 5: not a prefix: end
413 413 (date(
414 414 ^ here)
415 415 [255]
416 416 $ log 'date("\xy")'
417 417 hg: parse error: invalid \x escape* (glob)
418 418 [255]
419 419 $ log 'date(tip)'
420 420 hg: parse error: invalid date: 'tip'
421 421 [255]
422 422 $ log '0:date'
423 423 abort: unknown revision 'date'!
424 424 [255]
425 425 $ log '::"date"'
426 426 abort: unknown revision 'date'!
427 427 [255]
428 428 $ hg book date -r 4
429 429 $ log '0:date'
430 430 0
431 431 1
432 432 2
433 433 3
434 434 4
435 435 $ log '::date'
436 436 0
437 437 1
438 438 2
439 439 4
440 440 $ log '::"date"'
441 441 0
442 442 1
443 443 2
444 444 4
445 445 $ log 'date(2005) and 1::'
446 446 4
447 447 $ hg book -d date
448 448
449 449 function name should be a symbol
450 450
451 451 $ log '"date"(2005)'
452 452 hg: parse error: not a symbol
453 453 [255]
454 454
455 455 keyword arguments
456 456
457 457 $ log 'extra(branch, value=a)'
458 458 0
459 459
460 460 $ log 'extra(branch, a, b)'
461 461 hg: parse error: extra takes at most 2 positional arguments
462 462 [255]
463 463 $ log 'extra(a, label=b)'
464 464 hg: parse error: extra got multiple values for keyword argument 'label'
465 465 [255]
466 466 $ log 'extra(label=branch, default)'
467 467 hg: parse error: extra got an invalid argument
468 468 [255]
469 469 $ log 'extra(branch, foo+bar=baz)'
470 470 hg: parse error: extra got an invalid argument
471 471 [255]
472 472 $ log 'extra(unknown=branch)'
473 473 hg: parse error: extra got an unexpected keyword argument 'unknown'
474 474 [255]
475 475
476 476 $ try 'foo=bar|baz'
477 477 (keyvalue
478 478 (symbol 'foo')
479 479 (or
480 480 (list
481 481 (symbol 'bar')
482 482 (symbol 'baz'))))
483 483 hg: parse error: can't use a key-value pair in this context
484 484 [255]
485 485
486 486 right-hand side should be optimized recursively
487 487
488 488 $ try --optimize 'foo=(not public())'
489 489 (keyvalue
490 490 (symbol 'foo')
491 491 (group
492 492 (not
493 493 (func
494 494 (symbol 'public')
495 495 None))))
496 496 * optimized:
497 497 (keyvalue
498 498 (symbol 'foo')
499 499 (func
500 500 (symbol '_notpublic')
501 501 None))
502 502 hg: parse error: can't use a key-value pair in this context
503 503 [255]
504 504
505 505 relation-subscript operator has the highest binding strength (as function call):
506 506
507 507 $ hg debugrevspec -p parsed 'tip:tip^#generations[-1]'
508 508 * parsed:
509 509 (range
510 510 (symbol 'tip')
511 511 (relsubscript
512 512 (parentpost
513 513 (symbol 'tip'))
514 514 (symbol 'generations')
515 515 (negate
516 516 (symbol '1'))))
517 517 9
518 518 8
519 519 7
520 520 6
521 521 5
522 522 4
523 523
524 524 $ hg debugrevspec -p parsed --no-show-revs 'not public()#generations[0]'
525 525 * parsed:
526 526 (not
527 527 (relsubscript
528 528 (func
529 529 (symbol 'public')
530 530 None)
531 531 (symbol 'generations')
532 532 (symbol '0')))
533 533
534 534 left-hand side of relation-subscript operator should be optimized recursively:
535 535
536 536 $ hg debugrevspec -p analyzed -p optimized --no-show-revs \
537 537 > '(not public())#generations[0]'
538 538 * analyzed:
539 539 (relsubscript
540 540 (not
541 541 (func
542 542 (symbol 'public')
543 543 None))
544 544 (symbol 'generations')
545 545 (symbol '0'))
546 546 * optimized:
547 547 (relsubscript
548 548 (func
549 549 (symbol '_notpublic')
550 550 None)
551 551 (symbol 'generations')
552 552 (symbol '0'))
553 553
554 554 resolution of subscript and relation-subscript ternary operators:
555 555
556 556 $ hg debugrevspec -p analyzed 'tip[0]'
557 557 * analyzed:
558 558 (subscript
559 559 (symbol 'tip')
560 560 (symbol '0'))
561 561 hg: parse error: can't use a subscript in this context
562 562 [255]
563 563
564 564 $ hg debugrevspec -p analyzed 'tip#rel[0]'
565 565 * analyzed:
566 566 (relsubscript
567 567 (symbol 'tip')
568 568 (symbol 'rel')
569 569 (symbol '0'))
570 570 hg: parse error: unknown identifier: rel
571 571 [255]
572 572
573 573 $ hg debugrevspec -p analyzed '(tip#rel)[0]'
574 574 * analyzed:
575 575 (subscript
576 576 (relation
577 577 (symbol 'tip')
578 578 (symbol 'rel'))
579 579 (symbol '0'))
580 580 hg: parse error: can't use a subscript in this context
581 581 [255]
582 582
583 583 $ hg debugrevspec -p analyzed 'tip#rel[0][1]'
584 584 * analyzed:
585 585 (subscript
586 586 (relsubscript
587 587 (symbol 'tip')
588 588 (symbol 'rel')
589 589 (symbol '0'))
590 590 (symbol '1'))
591 591 hg: parse error: can't use a subscript in this context
592 592 [255]
593 593
594 594 $ hg debugrevspec -p analyzed 'tip#rel0#rel1[1]'
595 595 * analyzed:
596 596 (relsubscript
597 597 (relation
598 598 (symbol 'tip')
599 599 (symbol 'rel0'))
600 600 (symbol 'rel1')
601 601 (symbol '1'))
602 602 hg: parse error: unknown identifier: rel1
603 603 [255]
604 604
605 605 $ hg debugrevspec -p analyzed 'tip#rel0[0]#rel1[1]'
606 606 * analyzed:
607 607 (relsubscript
608 608 (relsubscript
609 609 (symbol 'tip')
610 610 (symbol 'rel0')
611 611 (symbol '0'))
612 612 (symbol 'rel1')
613 613 (symbol '1'))
614 614 hg: parse error: unknown identifier: rel1
615 615 [255]
616 616
617 617 parse errors of relation, subscript and relation-subscript operators:
618 618
619 619 $ hg debugrevspec '[0]'
620 620 hg: parse error at 0: not a prefix: [
621 621 ([0]
622 622 ^ here)
623 623 [255]
624 624 $ hg debugrevspec '.#'
625 625 hg: parse error at 2: not a prefix: end
626 626 (.#
627 627 ^ here)
628 628 [255]
629 629 $ hg debugrevspec '#rel'
630 630 hg: parse error at 0: not a prefix: #
631 631 (#rel
632 632 ^ here)
633 633 [255]
634 634 $ hg debugrevspec '.#rel[0'
635 635 hg: parse error at 7: unexpected token: end
636 636 (.#rel[0
637 637 ^ here)
638 638 [255]
639 639 $ hg debugrevspec '.]'
640 640 hg: parse error at 1: invalid token
641 641 (.]
642 642 ^ here)
643 643 [255]
644 644
645 645 $ hg debugrevspec '.#generations[a]'
646 646 hg: parse error: relation subscript must be an integer
647 647 [255]
648 648 $ hg debugrevspec '.#generations[1-2]'
649 649 hg: parse error: relation subscript must be an integer
650 650 [255]
651 651
652 652 parsed tree at stages:
653 653
654 654 $ hg debugrevspec -p all '()'
655 655 * parsed:
656 656 (group
657 657 None)
658 658 * expanded:
659 659 (group
660 660 None)
661 661 * concatenated:
662 662 (group
663 663 None)
664 664 * analyzed:
665 665 None
666 666 * optimized:
667 667 None
668 668 hg: parse error: missing argument
669 669 [255]
670 670
671 671 $ hg debugrevspec --no-optimized -p all '()'
672 672 * parsed:
673 673 (group
674 674 None)
675 675 * expanded:
676 676 (group
677 677 None)
678 678 * concatenated:
679 679 (group
680 680 None)
681 681 * analyzed:
682 682 None
683 683 hg: parse error: missing argument
684 684 [255]
685 685
686 686 $ hg debugrevspec -p parsed -p analyzed -p optimized '(0|1)-1'
687 687 * parsed:
688 688 (minus
689 689 (group
690 690 (or
691 691 (list
692 692 (symbol '0')
693 693 (symbol '1'))))
694 694 (symbol '1'))
695 695 * analyzed:
696 696 (and
697 697 (or
698 698 (list
699 699 (symbol '0')
700 700 (symbol '1')))
701 701 (not
702 702 (symbol '1')))
703 703 * optimized:
704 704 (difference
705 705 (func
706 706 (symbol '_list')
707 707 (string '0\x001'))
708 708 (symbol '1'))
709 709 0
710 710
711 711 $ hg debugrevspec -p unknown '0'
712 712 abort: invalid stage name: unknown
713 713 [255]
714 714
715 715 $ hg debugrevspec -p all --optimize '0'
716 716 abort: cannot use --optimize with --show-stage
717 717 [255]
718 718
719 719 verify optimized tree:
720 720
721 721 $ hg debugrevspec --verify '0|1'
722 722
723 723 $ hg debugrevspec --verify -v -p analyzed -p optimized 'r3232() & 2'
724 724 * analyzed:
725 725 (and
726 726 (func
727 727 (symbol 'r3232')
728 728 None)
729 729 (symbol '2'))
730 730 * optimized:
731 731 (andsmally
732 732 (func
733 733 (symbol 'r3232')
734 734 None)
735 735 (symbol '2'))
736 736 * analyzed set:
737 737 <baseset [2]>
738 738 * optimized set:
739 739 <baseset [2, 2]>
740 740 --- analyzed
741 741 +++ optimized
742 742 2
743 743 +2
744 744 [1]
745 745
746 746 $ hg debugrevspec --no-optimized --verify-optimized '0'
747 747 abort: cannot use --verify-optimized with --no-optimized
748 748 [255]
749 749
750 750 Test that symbols only get parsed as functions if there's an opening
751 751 parenthesis.
752 752
753 753 $ hg book only -r 9
754 754 $ log 'only(only)' # Outer "only" is a function, inner "only" is the bookmark
755 755 8
756 756 9
757 757
758 758 ':y' behaves like '0:y', but can't be rewritten as such since the revision '0'
759 759 may be hidden (issue5385)
760 760
761 761 $ try -p parsed -p analyzed ':'
762 762 * parsed:
763 763 (rangeall
764 764 None)
765 765 * analyzed:
766 766 (rangeall
767 767 None)
768 768 * set:
769 769 <spanset+ 0:10>
770 770 0
771 771 1
772 772 2
773 773 3
774 774 4
775 775 5
776 776 6
777 777 7
778 778 8
779 779 9
780 780 $ try -p analyzed ':1'
781 781 * analyzed:
782 782 (rangepre
783 783 (symbol '1'))
784 784 * set:
785 785 <spanset+ 0:2>
786 786 0
787 787 1
788 788 $ try -p analyzed ':(1|2)'
789 789 * analyzed:
790 790 (rangepre
791 791 (or
792 792 (list
793 793 (symbol '1')
794 794 (symbol '2'))))
795 795 * set:
796 796 <spanset+ 0:3>
797 797 0
798 798 1
799 799 2
800 800 $ try -p analyzed ':(1&2)'
801 801 * analyzed:
802 802 (rangepre
803 803 (and
804 804 (symbol '1')
805 805 (symbol '2')))
806 806 * set:
807 807 <baseset []>
808 808
809 809 infix/suffix resolution of ^ operator (issue2884, issue5764):
810 810
811 811 x^:y means (x^):y
812 812
813 813 $ try '1^:2'
814 814 (range
815 815 (parentpost
816 816 (symbol '1'))
817 817 (symbol '2'))
818 818 * set:
819 819 <spanset+ 0:3>
820 820 0
821 821 1
822 822 2
823 823
824 824 $ try '1^::2'
825 825 (dagrange
826 826 (parentpost
827 827 (symbol '1'))
828 828 (symbol '2'))
829 829 * set:
830 830 <baseset+ [0, 1, 2]>
831 831 0
832 832 1
833 833 2
834 834
835 835 $ try '1^..2'
836 836 (dagrange
837 837 (parentpost
838 838 (symbol '1'))
839 839 (symbol '2'))
840 840 * set:
841 841 <baseset+ [0, 1, 2]>
842 842 0
843 843 1
844 844 2
845 845
846 846 $ try '9^:'
847 847 (rangepost
848 848 (parentpost
849 849 (symbol '9')))
850 850 * set:
851 851 <spanset+ 8:10>
852 852 8
853 853 9
854 854
855 855 $ try '9^::'
856 856 (dagrangepost
857 857 (parentpost
858 858 (symbol '9')))
859 859 * set:
860 860 <generatorsetasc+>
861 861 8
862 862 9
863 863
864 864 $ try '9^..'
865 865 (dagrangepost
866 866 (parentpost
867 867 (symbol '9')))
868 868 * set:
869 869 <generatorsetasc+>
870 870 8
871 871 9
872 872
873 873 x^:y should be resolved before omitting group operators
874 874
875 875 $ try '1^(:2)'
876 876 (parent
877 877 (symbol '1')
878 878 (group
879 879 (rangepre
880 880 (symbol '2'))))
881 881 hg: parse error: ^ expects a number 0, 1, or 2
882 882 [255]
883 883
884 884 x^:y should be resolved recursively
885 885
886 886 $ try 'sort(1^:2)'
887 887 (func
888 888 (symbol 'sort')
889 889 (range
890 890 (parentpost
891 891 (symbol '1'))
892 892 (symbol '2')))
893 893 * set:
894 894 <spanset+ 0:3>
895 895 0
896 896 1
897 897 2
898 898
899 899 $ try '(3^:4)^:2'
900 900 (range
901 901 (parentpost
902 902 (group
903 903 (range
904 904 (parentpost
905 905 (symbol '3'))
906 906 (symbol '4'))))
907 907 (symbol '2'))
908 908 * set:
909 909 <spanset+ 0:3>
910 910 0
911 911 1
912 912 2
913 913
914 914 $ try '(3^::4)^::2'
915 915 (dagrange
916 916 (parentpost
917 917 (group
918 918 (dagrange
919 919 (parentpost
920 920 (symbol '3'))
921 921 (symbol '4'))))
922 922 (symbol '2'))
923 923 * set:
924 924 <baseset+ [0, 1, 2]>
925 925 0
926 926 1
927 927 2
928 928
929 929 $ try '(9^:)^:'
930 930 (rangepost
931 931 (parentpost
932 932 (group
933 933 (rangepost
934 934 (parentpost
935 935 (symbol '9'))))))
936 936 * set:
937 937 <spanset+ 4:10>
938 938 4
939 939 5
940 940 6
941 941 7
942 942 8
943 943 9
944 944
945 945 x^ in alias should also be resolved
946 946
947 947 $ try 'A' --config 'revsetalias.A=1^:2'
948 948 (symbol 'A')
949 949 * expanded:
950 950 (range
951 951 (parentpost
952 952 (symbol '1'))
953 953 (symbol '2'))
954 954 * set:
955 955 <spanset+ 0:3>
956 956 0
957 957 1
958 958 2
959 959
960 960 $ try 'A:2' --config 'revsetalias.A=1^'
961 961 (range
962 962 (symbol 'A')
963 963 (symbol '2'))
964 964 * expanded:
965 965 (range
966 966 (parentpost
967 967 (symbol '1'))
968 968 (symbol '2'))
969 969 * set:
970 970 <spanset+ 0:3>
971 971 0
972 972 1
973 973 2
974 974
975 975 but not beyond the boundary of alias expansion, because the resolution should
976 976 be made at the parsing stage
977 977
978 978 $ try '1^A' --config 'revsetalias.A=:2'
979 979 (parent
980 980 (symbol '1')
981 981 (symbol 'A'))
982 982 * expanded:
983 983 (parent
984 984 (symbol '1')
985 985 (rangepre
986 986 (symbol '2')))
987 987 hg: parse error: ^ expects a number 0, 1, or 2
988 988 [255]
989 989
990 990 '::' itself isn't a valid expression
991 991
992 992 $ try '::'
993 993 (dagrangeall
994 994 None)
995 995 hg: parse error: can't use '::' in this context
996 996 [255]
997 997
998 998 ancestor can accept 0 or more arguments
999 999
1000 1000 $ log 'ancestor()'
1001 1001 $ log 'ancestor(1)'
1002 1002 1
1003 1003 $ log 'ancestor(4,5)'
1004 1004 1
1005 1005 $ log 'ancestor(4,5) and 4'
1006 1006 $ log 'ancestor(0,0,1,3)'
1007 1007 0
1008 1008 $ log 'ancestor(3,1,5,3,5,1)'
1009 1009 1
1010 1010 $ log 'ancestor(0,1,3,5)'
1011 1011 0
1012 1012 $ log 'ancestor(1,2,3,4,5)'
1013 1013 1
1014 1014
1015 1015 test ancestors
1016 1016
1017 1017 $ hg log -G -T '{rev}\n' --config experimental.graphshorten=True
1018 1018 @ 9
1019 1019 o 8
1020 1020 | o 7
1021 1021 | o 6
1022 1022 |/|
1023 1023 | o 5
1024 1024 o | 4
1025 1025 | o 3
1026 1026 o | 2
1027 1027 |/
1028 1028 o 1
1029 1029 o 0
1030 1030
1031 1031 $ log 'ancestors(5)'
1032 1032 0
1033 1033 1
1034 1034 3
1035 1035 5
1036 1036 $ log 'ancestor(ancestors(5))'
1037 1037 0
1038 1038 $ log '::r3232()'
1039 1039 0
1040 1040 1
1041 1041 2
1042 1042 3
1043 1043
1044 1044 test ancestors with depth limit
1045 1045
1046 1046 (depth=0 selects the node itself)
1047 1047
1048 1048 $ log 'reverse(ancestors(9, depth=0))'
1049 1049 9
1050 1050
1051 1051 (interleaved: '4' would be missing if heap queue were higher depth first)
1052 1052
1053 1053 $ log 'reverse(ancestors(8:9, depth=1))'
1054 1054 9
1055 1055 8
1056 1056 4
1057 1057
1058 1058 (interleaved: '2' would be missing if heap queue were higher depth first)
1059 1059
1060 1060 $ log 'reverse(ancestors(7+8, depth=2))'
1061 1061 8
1062 1062 7
1063 1063 6
1064 1064 5
1065 1065 4
1066 1066 2
1067 1067
1068 1068 (walk example above by separate queries)
1069 1069
1070 1070 $ log 'reverse(ancestors(8, depth=2)) + reverse(ancestors(7, depth=2))'
1071 1071 8
1072 1072 4
1073 1073 2
1074 1074 7
1075 1075 6
1076 1076 5
1077 1077
1078 1078 (walk 2nd and 3rd ancestors)
1079 1079
1080 1080 $ log 'reverse(ancestors(7, depth=3, startdepth=2))'
1081 1081 5
1082 1082 4
1083 1083 3
1084 1084 2
1085 1085
1086 1086 (interleaved: '4' would be missing if higher-depth ancestors weren't scanned)
1087 1087
1088 1088 $ log 'reverse(ancestors(7+8, depth=2, startdepth=2))'
1089 1089 5
1090 1090 4
1091 1091 2
1092 1092
1093 1093 (note that 'ancestors(x, depth=y, startdepth=z)' does not identical to
1094 1094 'ancestors(x, depth=y) - ancestors(x, depth=z-1)' because a node may have
1095 1095 multiple depths)
1096 1096
1097 1097 $ log 'reverse(ancestors(7+8, depth=2) - ancestors(7+8, depth=1))'
1098 1098 5
1099 1099 2
1100 1100
1101 1101 test bad arguments passed to ancestors()
1102 1102
1103 1103 $ log 'ancestors(., depth=-1)'
1104 1104 hg: parse error: negative depth
1105 1105 [255]
1106 1106 $ log 'ancestors(., depth=foo)'
1107 1107 hg: parse error: ancestors expects an integer depth
1108 1108 [255]
1109 1109
1110 1110 test descendants
1111 1111
1112 1112 $ hg log -G -T '{rev}\n' --config experimental.graphshorten=True
1113 1113 @ 9
1114 1114 o 8
1115 1115 | o 7
1116 1116 | o 6
1117 1117 |/|
1118 1118 | o 5
1119 1119 o | 4
1120 1120 | o 3
1121 1121 o | 2
1122 1122 |/
1123 1123 o 1
1124 1124 o 0
1125 1125
1126 1126 (null is ultimate root and has optimized path)
1127 1127
1128 1128 $ log 'null:4 & descendants(null)'
1129 1129 -1
1130 1130 0
1131 1131 1
1132 1132 2
1133 1133 3
1134 1134 4
1135 1135
1136 1136 (including merge)
1137 1137
1138 1138 $ log ':8 & descendants(2)'
1139 1139 2
1140 1140 4
1141 1141 6
1142 1142 7
1143 1143 8
1144 1144
1145 1145 (multiple roots)
1146 1146
1147 1147 $ log ':8 & descendants(2+5)'
1148 1148 2
1149 1149 4
1150 1150 5
1151 1151 6
1152 1152 7
1153 1153 8
1154 1154
1155 1155 test descendants with depth limit
1156 1156
1157 1157 (depth=0 selects the node itself)
1158 1158
1159 1159 $ log 'descendants(0, depth=0)'
1160 1160 0
1161 1161 $ log 'null: & descendants(null, depth=0)'
1162 1162 -1
1163 1163
1164 1164 (p2 = null should be ignored)
1165 1165
1166 1166 $ log 'null: & descendants(null, depth=2)'
1167 1167 -1
1168 1168 0
1169 1169 1
1170 1170
1171 1171 (multiple paths: depth(6) = (2, 3))
1172 1172
1173 1173 $ log 'descendants(1+3, depth=2)'
1174 1174 1
1175 1175 2
1176 1176 3
1177 1177 4
1178 1178 5
1179 1179 6
1180 1180
1181 1181 (multiple paths: depth(5) = (1, 2), depth(6) = (2, 3))
1182 1182
1183 1183 $ log 'descendants(3+1, depth=2, startdepth=2)'
1184 1184 4
1185 1185 5
1186 1186 6
1187 1187
1188 1188 (multiple depths: depth(6) = (0, 2, 4), search for depth=2)
1189 1189
1190 1190 $ log 'descendants(0+3+6, depth=3, startdepth=1)'
1191 1191 1
1192 1192 2
1193 1193 3
1194 1194 4
1195 1195 5
1196 1196 6
1197 1197 7
1198 1198
1199 1199 (multiple depths: depth(6) = (0, 4), no match)
1200 1200
1201 1201 $ log 'descendants(0+6, depth=3, startdepth=1)'
1202 1202 1
1203 1203 2
1204 1204 3
1205 1205 4
1206 1206 5
1207 1207 7
1208 1208
1209 1209 test ancestors/descendants relation subscript:
1210 1210
1211 1211 $ log 'tip#generations[0]'
1212 1212 9
1213 1213 $ log '.#generations[-1]'
1214 1214 8
1215 1215 $ log '.#g[(-1)]'
1216 1216 8
1217 1217
1218 1218 $ hg debugrevspec -p parsed 'roots(:)#g[2]'
1219 1219 * parsed:
1220 1220 (relsubscript
1221 1221 (func
1222 1222 (symbol 'roots')
1223 1223 (rangeall
1224 1224 None))
1225 1225 (symbol 'g')
1226 1226 (symbol '2'))
1227 1227 2
1228 1228 3
1229 1229
1230 1230 test author
1231 1231
1232 1232 $ log 'author(bob)'
1233 1233 2
1234 1234 $ log 'author("re:bob|test")'
1235 1235 0
1236 1236 1
1237 1237 2
1238 1238 3
1239 1239 4
1240 1240 5
1241 1241 6
1242 1242 7
1243 1243 8
1244 1244 9
1245 1245 $ log 'author(r"re:\S")'
1246 1246 0
1247 1247 1
1248 1248 2
1249 1249 3
1250 1250 4
1251 1251 5
1252 1252 6
1253 1253 7
1254 1254 8
1255 1255 9
1256 1256 $ log 'branch(Γ©)'
1257 1257 8
1258 1258 9
1259 1259 $ log 'branch(a)'
1260 1260 0
1261 1261 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
1262 1262 0 a
1263 1263 2 a-b-c-
1264 1264 3 +a+b+c+
1265 1265 4 -a-b-c-
1266 1266 5 !a/b/c/
1267 1267 6 _a_b_c_
1268 1268 7 .a.b.c.
1269 1269 $ log 'children(ancestor(4,5))'
1270 1270 2
1271 1271 3
1272 1272
1273 1273 $ log 'children(4)'
1274 1274 6
1275 1275 8
1276 1276 $ log 'children(null)'
1277 1277 0
1278 1278
1279 1279 $ log 'closed()'
1280 1280 $ log 'contains(a)'
1281 1281 0
1282 1282 1
1283 1283 3
1284 1284 5
1285 1285 $ log 'contains("../repo/a")'
1286 1286 0
1287 1287 1
1288 1288 3
1289 1289 5
1290 1290 $ log 'desc(B)'
1291 1291 5
1292 1292 $ hg log -r 'desc(r"re:S?u")' --template "{rev} {desc|firstline}\n"
1293 1293 5 5 bug
1294 1294 6 6 issue619
1295 1295 $ log 'descendants(2 or 3)'
1296 1296 2
1297 1297 3
1298 1298 4
1299 1299 5
1300 1300 6
1301 1301 7
1302 1302 8
1303 1303 9
1304 1304 $ log 'file("b*")'
1305 1305 1
1306 1306 4
1307 1307 $ log 'filelog("b")'
1308 1308 1
1309 1309 4
1310 1310 $ log 'filelog("../repo/b")'
1311 1311 1
1312 1312 4
1313 1313 $ log 'follow()'
1314 1314 0
1315 1315 1
1316 1316 2
1317 1317 4
1318 1318 8
1319 1319 9
1320 1320 $ log 'grep("issue\d+")'
1321 1321 6
1322 1322 $ try 'grep("(")' # invalid regular expression
1323 1323 (func
1324 1324 (symbol 'grep')
1325 1325 (string '('))
1326 1326 hg: parse error: invalid match pattern: (unbalanced parenthesis|missing \),.*) (re)
1327 1327 [255]
1328 1328 $ try 'grep("\bissue\d+")'
1329 1329 (func
1330 1330 (symbol 'grep')
1331 1331 (string '\x08issue\\d+'))
1332 1332 * set:
1333 1333 <filteredset
1334 1334 <fullreposet+ 0:10>,
1335 1335 <grep '\x08issue\\d+'>>
1336 1336 $ try 'grep(r"\bissue\d+")'
1337 1337 (func
1338 1338 (symbol 'grep')
1339 1339 (string '\\bissue\\d+'))
1340 1340 * set:
1341 1341 <filteredset
1342 1342 <fullreposet+ 0:10>,
1343 1343 <grep '\\bissue\\d+'>>
1344 1344 6
1345 1345 $ try 'grep(r"\")'
1346 1346 hg: parse error at 7: unterminated string
1347 1347 (grep(r"\")
1348 1348 ^ here)
1349 1349 [255]
1350 1350 $ log 'head()'
1351 1351 0
1352 1352 1
1353 1353 2
1354 1354 3
1355 1355 4
1356 1356 5
1357 1357 6
1358 1358 7
1359 1359 9
1360 1360 $ log 'heads(6::)'
1361 1361 7
1362 1362 $ log 'keyword(issue)'
1363 1363 6
1364 1364 $ log 'keyword("test a")'
1365 1365
1366 1366 Test first (=limit) and last
1367 1367
1368 1368 $ log 'limit(head(), 1)'
1369 1369 0
1370 1370 $ log 'limit(author("re:bob|test"), 3, 5)'
1371 1371 5
1372 1372 6
1373 1373 7
1374 1374 $ log 'limit(author("re:bob|test"), offset=6)'
1375 1375 6
1376 1376 $ log 'limit(author("re:bob|test"), offset=10)'
1377 1377 $ log 'limit(all(), 1, -1)'
1378 1378 hg: parse error: negative offset
1379 1379 [255]
1380 1380 $ log 'limit(all(), -1)'
1381 1381 hg: parse error: negative number to select
1382 1382 [255]
1383 1383 $ log 'limit(all(), 0)'
1384 1384
1385 1385 $ log 'last(all(), -1)'
1386 1386 hg: parse error: negative number to select
1387 1387 [255]
1388 1388 $ log 'last(all(), 0)'
1389 1389 $ log 'last(all(), 1)'
1390 1390 9
1391 1391 $ log 'last(all(), 2)'
1392 1392 8
1393 1393 9
1394 1394
1395 1395 Test smartset.slice() by first/last()
1396 1396
1397 1397 (using unoptimized set, filteredset as example)
1398 1398
1399 1399 $ hg debugrevspec --no-show-revs -s '0:7 & branch("re:")'
1400 1400 * set:
1401 1401 <filteredset
1402 1402 <spanset+ 0:8>,
1403 1403 <branch 're:'>>
1404 1404 $ log 'limit(0:7 & branch("re:"), 3, 4)'
1405 1405 4
1406 1406 5
1407 1407 6
1408 1408 $ log 'limit(7:0 & branch("re:"), 3, 4)'
1409 1409 3
1410 1410 2
1411 1411 1
1412 1412 $ log 'last(0:7 & branch("re:"), 2)'
1413 1413 6
1414 1414 7
1415 1415
1416 1416 (using baseset)
1417 1417
1418 1418 $ hg debugrevspec --no-show-revs -s 0+1+2+3+4+5+6+7
1419 1419 * set:
1420 1420 <baseset [0, 1, 2, 3, 4, 5, 6, 7]>
1421 1421 $ hg debugrevspec --no-show-revs -s 0::7
1422 1422 * set:
1423 1423 <baseset+ [0, 1, 2, 3, 4, 5, 6, 7]>
1424 1424 $ log 'limit(0+1+2+3+4+5+6+7, 3, 4)'
1425 1425 4
1426 1426 5
1427 1427 6
1428 1428 $ log 'limit(sort(0::7, rev), 3, 4)'
1429 1429 4
1430 1430 5
1431 1431 6
1432 1432 $ log 'limit(sort(0::7, -rev), 3, 4)'
1433 1433 3
1434 1434 2
1435 1435 1
1436 1436 $ log 'last(sort(0::7, rev), 2)'
1437 1437 6
1438 1438 7
1439 1439 $ hg debugrevspec -s 'limit(sort(0::7, rev), 3, 6)'
1440 1440 * set:
1441 1441 <baseset+ [6, 7]>
1442 1442 6
1443 1443 7
1444 1444 $ hg debugrevspec -s 'limit(sort(0::7, rev), 3, 9)'
1445 1445 * set:
1446 1446 <baseset+ []>
1447 1447 $ hg debugrevspec -s 'limit(sort(0::7, -rev), 3, 6)'
1448 1448 * set:
1449 1449 <baseset- [0, 1]>
1450 1450 1
1451 1451 0
1452 1452 $ hg debugrevspec -s 'limit(sort(0::7, -rev), 3, 9)'
1453 1453 * set:
1454 1454 <baseset- []>
1455 1455 $ hg debugrevspec -s 'limit(0::7, 0)'
1456 1456 * set:
1457 1457 <baseset+ []>
1458 1458
1459 1459 (using spanset)
1460 1460
1461 1461 $ hg debugrevspec --no-show-revs -s 0:7
1462 1462 * set:
1463 1463 <spanset+ 0:8>
1464 1464 $ log 'limit(0:7, 3, 4)'
1465 1465 4
1466 1466 5
1467 1467 6
1468 1468 $ log 'limit(7:0, 3, 4)'
1469 1469 3
1470 1470 2
1471 1471 1
1472 1472 $ log 'limit(0:7, 3, 6)'
1473 1473 6
1474 1474 7
1475 1475 $ log 'limit(7:0, 3, 6)'
1476 1476 1
1477 1477 0
1478 1478 $ log 'last(0:7, 2)'
1479 1479 6
1480 1480 7
1481 1481 $ hg debugrevspec -s 'limit(0:7, 3, 6)'
1482 1482 * set:
1483 1483 <spanset+ 6:8>
1484 1484 6
1485 1485 7
1486 1486 $ hg debugrevspec -s 'limit(0:7, 3, 9)'
1487 1487 * set:
1488 1488 <spanset+ 8:8>
1489 1489 $ hg debugrevspec -s 'limit(7:0, 3, 6)'
1490 1490 * set:
1491 1491 <spanset- 0:2>
1492 1492 1
1493 1493 0
1494 1494 $ hg debugrevspec -s 'limit(7:0, 3, 9)'
1495 1495 * set:
1496 1496 <spanset- 0:0>
1497 1497 $ hg debugrevspec -s 'limit(0:7, 0)'
1498 1498 * set:
1499 1499 <spanset+ 0:0>
1500 1500
1501 1501 Test order of first/last revisions
1502 1502
1503 1503 $ hg debugrevspec -s 'first(4:0, 3) & 3:'
1504 1504 * set:
1505 1505 <filteredset
1506 1506 <spanset- 2:5>,
1507 1507 <spanset+ 3:10>>
1508 1508 4
1509 1509 3
1510 1510
1511 1511 $ hg debugrevspec -s '3: & first(4:0, 3)'
1512 1512 * set:
1513 1513 <filteredset
1514 1514 <spanset+ 3:10>,
1515 1515 <spanset- 2:5>>
1516 1516 3
1517 1517 4
1518 1518
1519 1519 $ hg debugrevspec -s 'last(4:0, 3) & :1'
1520 1520 * set:
1521 1521 <filteredset
1522 1522 <spanset- 0:3>,
1523 1523 <spanset+ 0:2>>
1524 1524 1
1525 1525 0
1526 1526
1527 1527 $ hg debugrevspec -s ':1 & last(4:0, 3)'
1528 1528 * set:
1529 1529 <filteredset
1530 1530 <spanset+ 0:2>,
1531 1531 <spanset+ 0:3>>
1532 1532 0
1533 1533 1
1534 1534
1535 1535 Test scmutil.revsingle() should return the last revision
1536 1536
1537 1537 $ hg debugrevspec -s 'last(0::)'
1538 1538 * set:
1539 1539 <baseset slice=0:1
1540 1540 <generatorsetasc->>
1541 1541 9
1542 1542 $ hg identify -r '0::' --num
1543 1543 9
1544 1544
1545 1545 Test matching
1546 1546
1547 1547 $ log 'matching(6)'
1548 1548 6
1549 1549 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
1550 1550 6
1551 1551 7
1552 1552
1553 1553 Testing min and max
1554 1554
1555 1555 max: simple
1556 1556
1557 1557 $ log 'max(contains(a))'
1558 1558 5
1559 1559
1560 1560 max: simple on unordered set)
1561 1561
1562 1562 $ log 'max((4+0+2+5+7) and contains(a))'
1563 1563 5
1564 1564
1565 1565 max: no result
1566 1566
1567 1567 $ log 'max(contains(stringthatdoesnotappearanywhere))'
1568 1568
1569 1569 max: no result on unordered set
1570 1570
1571 1571 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
1572 1572
1573 1573 min: simple
1574 1574
1575 1575 $ log 'min(contains(a))'
1576 1576 0
1577 1577
1578 1578 min: simple on unordered set
1579 1579
1580 1580 $ log 'min((4+0+2+5+7) and contains(a))'
1581 1581 0
1582 1582
1583 1583 min: empty
1584 1584
1585 1585 $ log 'min(contains(stringthatdoesnotappearanywhere))'
1586 1586
1587 1587 min: empty on unordered set
1588 1588
1589 1589 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
1590 1590
1591 1591
1592 1592 $ log 'merge()'
1593 1593 6
1594 1594 $ log 'branchpoint()'
1595 1595 1
1596 1596 4
1597 1597 $ log 'modifies(b)'
1598 1598 4
1599 1599 $ log 'modifies("path:b")'
1600 1600 4
1601 1601 $ log 'modifies("*")'
1602 1602 4
1603 1603 6
1604 1604 $ log 'modifies("set:modified()")'
1605 1605 4
1606 1606 $ log 'id(5)'
1607 1607 2
1608 1608 $ log 'only(9)'
1609 1609 8
1610 1610 9
1611 1611 $ log 'only(8)'
1612 1612 8
1613 1613 $ log 'only(9, 5)'
1614 1614 2
1615 1615 4
1616 1616 8
1617 1617 9
1618 1618 $ log 'only(7 + 9, 5 + 2)'
1619 1619 4
1620 1620 6
1621 1621 7
1622 1622 8
1623 1623 9
1624 1624
1625 1625 Test empty set input
1626 1626 $ log 'only(p2())'
1627 1627 $ log 'only(p1(), p2())'
1628 1628 0
1629 1629 1
1630 1630 2
1631 1631 4
1632 1632 8
1633 1633 9
1634 1634
1635 1635 Test '%' operator
1636 1636
1637 1637 $ log '9%'
1638 1638 8
1639 1639 9
1640 1640 $ log '9%5'
1641 1641 2
1642 1642 4
1643 1643 8
1644 1644 9
1645 1645 $ log '(7 + 9)%(5 + 2)'
1646 1646 4
1647 1647 6
1648 1648 7
1649 1649 8
1650 1650 9
1651 1651
1652 1652 Test operand of '%' is optimized recursively (issue4670)
1653 1653
1654 1654 $ try --optimize '8:9-8%'
1655 1655 (onlypost
1656 1656 (minus
1657 1657 (range
1658 1658 (symbol '8')
1659 1659 (symbol '9'))
1660 1660 (symbol '8')))
1661 1661 * optimized:
1662 1662 (func
1663 1663 (symbol 'only')
1664 1664 (difference
1665 1665 (range
1666 1666 (symbol '8')
1667 1667 (symbol '9'))
1668 1668 (symbol '8')))
1669 1669 * set:
1670 1670 <baseset+ [8, 9]>
1671 1671 8
1672 1672 9
1673 1673 $ try --optimize '(9)%(5)'
1674 1674 (only
1675 1675 (group
1676 1676 (symbol '9'))
1677 1677 (group
1678 1678 (symbol '5')))
1679 1679 * optimized:
1680 1680 (func
1681 1681 (symbol 'only')
1682 1682 (list
1683 1683 (symbol '9')
1684 1684 (symbol '5')))
1685 1685 * set:
1686 1686 <baseset+ [2, 4, 8, 9]>
1687 1687 2
1688 1688 4
1689 1689 8
1690 1690 9
1691 1691
1692 1692 Test the order of operations
1693 1693
1694 1694 $ log '7 + 9%5 + 2'
1695 1695 7
1696 1696 2
1697 1697 4
1698 1698 8
1699 1699 9
1700 1700
1701 1701 Test explicit numeric revision
1702 1702 $ log 'rev(-2)'
1703 1703 $ log 'rev(-1)'
1704 1704 -1
1705 1705 $ log 'rev(0)'
1706 1706 0
1707 1707 $ log 'rev(9)'
1708 1708 9
1709 1709 $ log 'rev(10)'
1710 1710 $ log 'rev(tip)'
1711 1711 hg: parse error: rev expects a number
1712 1712 [255]
1713 1713
1714 1714 Test hexadecimal revision
1715 1715 $ log 'id(2)'
1716 1716 $ log 'id(23268)'
1717 1717 4
1718 1718 $ log 'id(2785f51eece)'
1719 1719 0
1720 1720 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532c)'
1721 1721 8
1722 1722 $ log 'id(d5d0dcbdc4a)'
1723 1723 $ log 'id(d5d0dcbdc4w)'
1724 1724 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532d)'
1725 1725 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532q)'
1726 1726 $ log 'id(1.0)'
1727 1727 $ log 'id(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)'
1728 1728
1729 1729 Test null revision
1730 1730 $ log '(null)'
1731 1731 -1
1732 1732 $ log '(null:0)'
1733 1733 -1
1734 1734 0
1735 1735 $ log '(0:null)'
1736 1736 0
1737 1737 -1
1738 1738 $ log 'null::0'
1739 1739 -1
1740 1740 0
1741 1741 $ log 'null:tip - 0:'
1742 1742 -1
1743 1743 $ log 'null: and null::' | head -1
1744 1744 -1
1745 1745 $ log 'null: or 0:' | head -2
1746 1746 -1
1747 1747 0
1748 1748 $ log 'ancestors(null)'
1749 1749 -1
1750 1750 $ log 'reverse(null:)' | tail -2
1751 1751 0
1752 1752 -1
1753 1753 $ log 'first(null:)'
1754 1754 -1
1755 1755 $ log 'min(null:)'
1756 1756 BROKEN: should be '-1'
1757 1757 $ log 'tip:null and all()' | tail -2
1758 1758 1
1759 1759 0
1760 1760
1761 1761 Test working-directory revision
1762 1762 $ hg debugrevspec 'wdir()'
1763 1763 2147483647
1764 1764 $ hg debugrevspec 'wdir()^'
1765 1765 9
1766 1766 $ hg up 7
1767 1767 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1768 1768 $ hg debugrevspec 'wdir()^'
1769 1769 7
1770 1770 $ hg debugrevspec 'wdir()^0'
1771 1771 2147483647
1772 1772 $ hg debugrevspec 'wdir()~3'
1773 1773 5
1774 1774 $ hg debugrevspec 'ancestors(wdir())'
1775 1775 0
1776 1776 1
1777 1777 2
1778 1778 3
1779 1779 4
1780 1780 5
1781 1781 6
1782 1782 7
1783 1783 2147483647
1784 1784 $ hg debugrevspec 'wdir()~0'
1785 1785 2147483647
1786 1786 $ hg debugrevspec 'p1(wdir())'
1787 1787 7
1788 1788 $ hg debugrevspec 'p2(wdir())'
1789 1789 $ hg debugrevspec 'parents(wdir())'
1790 1790 7
1791 1791 $ hg debugrevspec 'wdir()^1'
1792 1792 7
1793 1793 $ hg debugrevspec 'wdir()^2'
1794 1794 $ hg debugrevspec 'wdir()^3'
1795 1795 hg: parse error: ^ expects a number 0, 1, or 2
1796 1796 [255]
1797 1797 For tests consistency
1798 1798 $ hg up 9
1799 1799 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1800 1800 $ hg debugrevspec 'tip or wdir()'
1801 1801 9
1802 1802 2147483647
1803 1803 $ hg debugrevspec '0:tip and wdir()'
1804 1804 $ log '0:wdir()' | tail -3
1805 1805 8
1806 1806 9
1807 1807 2147483647
1808 1808 $ log 'wdir():0' | head -3
1809 1809 2147483647
1810 1810 9
1811 1811 8
1812 1812 $ log 'wdir():wdir()'
1813 1813 2147483647
1814 1814 $ log '(all() + wdir()) & min(. + wdir())'
1815 1815 9
1816 1816 $ log '(all() + wdir()) & max(. + wdir())'
1817 1817 2147483647
1818 1818 $ log 'first(wdir() + .)'
1819 1819 2147483647
1820 1820 $ log 'last(. + wdir())'
1821 1821 2147483647
1822 1822
1823 1823 Test working-directory integer revision and node id
1824 1824 (BUG: '0:wdir()' is still needed to populate wdir revision)
1825 1825
1826 1826 $ hg debugrevspec '0:wdir() & 2147483647'
1827 1827 2147483647
1828 1828 $ hg debugrevspec '0:wdir() & rev(2147483647)'
1829 1829 2147483647
1830 1830 $ hg debugrevspec '0:wdir() & ffffffffffffffffffffffffffffffffffffffff'
1831 1831 2147483647
1832 1832 $ hg debugrevspec '0:wdir() & ffffffffffff'
1833 1833 2147483647
1834 1834 $ hg debugrevspec '0:wdir() & id(ffffffffffffffffffffffffffffffffffffffff)'
1835 1835 2147483647
1836 1836 $ hg debugrevspec '0:wdir() & id(ffffffffffff)'
1837 1837 2147483647
1838 1838
1839 1839 $ cd ..
1840 1840
1841 1841 Test short 'ff...' hash collision
1842 1842 (BUG: '0:wdir()' is still needed to populate wdir revision)
1843 1843
1844 1844 $ hg init wdir-hashcollision
1845 1845 $ cd wdir-hashcollision
1846 1846 $ cat <<EOF >> .hg/hgrc
1847 1847 > [experimental]
1848 1848 > evolution.createmarkers=True
1849 1849 > EOF
1850 1850 $ echo 0 > a
1851 1851 $ hg ci -qAm 0
1852 1852 $ for i in 2463 2961 6726 78127; do
1853 1853 > hg up -q 0
1854 1854 > echo $i > a
1855 1855 > hg ci -qm $i
1856 1856 > done
1857 1857 $ hg up -q null
1858 1858 $ hg log -r '0:wdir()' -T '{rev}:{node} {shortest(node, 3)}\n'
1859 1859 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a b4e
1860 1860 1:fffbae3886c8fbb2114296380d276fd37715d571 fffba
1861 1861 2:fffb6093b00943f91034b9bdad069402c834e572 fffb6
1862 1862 3:fff48a9b9de34a4d64120c29548214c67980ade3 fff4
1863 1863 4:ffff85cff0ff78504fcdc3c0bc10de0c65379249 ffff8
1864 1864 2147483647:ffffffffffffffffffffffffffffffffffffffff fffff
1865 1865 $ hg debugobsolete fffbae3886c8fbb2114296380d276fd37715d571
1866 1866 obsoleted 1 changesets
1867 1867
1868 1868 $ hg debugrevspec '0:wdir() & fff'
1869 1869 abort: 00changelog.i@fff: ambiguous identifier!
1870 1870 [255]
1871 1871 $ hg debugrevspec '0:wdir() & ffff'
1872 1872 abort: 00changelog.i@ffff: ambiguous identifier!
1873 1873 [255]
1874 1874 $ hg debugrevspec '0:wdir() & fffb'
1875 1875 abort: 00changelog.i@fffb: ambiguous identifier!
1876 1876 [255]
1877 1877 BROKEN should be '2' (node lookup uses unfiltered repo)
1878 1878 $ hg debugrevspec '0:wdir() & id(fffb)'
1879 1879 BROKEN should be '2' (node lookup uses unfiltered repo)
1880 1880 $ hg debugrevspec '0:wdir() & ffff8'
1881 1881 4
1882 1882 $ hg debugrevspec '0:wdir() & fffff'
1883 1883 2147483647
1884 1884
1885 1885 $ cd ..
1886 1886
1887 1887 Test branch() with wdir()
1888 1888
1889 1889 $ cd repo
1890 1890
1891 1891 $ log '0:wdir() & branch("literal:Γ©")'
1892 1892 8
1893 1893 9
1894 1894 2147483647
1895 1895 $ log '0:wdir() & branch("re:Γ©")'
1896 1896 8
1897 1897 9
1898 1898 2147483647
1899 1899 $ log '0:wdir() & branch("re:^a")'
1900 1900 0
1901 1901 2
1902 1902 $ log '0:wdir() & branch(8)'
1903 1903 8
1904 1904 9
1905 1905 2147483647
1906 1906
1907 1907 branch(wdir()) returns all revisions belonging to the working branch. The wdir
1908 1908 itself isn't returned unless it is explicitly populated.
1909 1909
1910 1910 $ log 'branch(wdir())'
1911 1911 8
1912 1912 9
1913 1913 $ log '0:wdir() & branch(wdir())'
1914 1914 8
1915 1915 9
1916 1916 2147483647
1917 1917
1918 1918 $ log 'outgoing()'
1919 1919 8
1920 1920 9
1921 1921 $ log 'outgoing("../remote1")'
1922 1922 8
1923 1923 9
1924 1924 $ log 'outgoing("../remote2")'
1925 1925 3
1926 1926 5
1927 1927 6
1928 1928 7
1929 1929 9
1930 1930 $ log 'p1(merge())'
1931 1931 5
1932 1932 $ log 'p2(merge())'
1933 1933 4
1934 1934 $ log 'parents(merge())'
1935 1935 4
1936 1936 5
1937 1937 $ log 'p1(branchpoint())'
1938 1938 0
1939 1939 2
1940 1940 $ log 'p2(branchpoint())'
1941 1941 $ log 'parents(branchpoint())'
1942 1942 0
1943 1943 2
1944 1944 $ log 'removes(a)'
1945 1945 2
1946 1946 6
1947 1947 $ log 'roots(all())'
1948 1948 0
1949 1949 $ log 'reverse(2 or 3 or 4 or 5)'
1950 1950 5
1951 1951 4
1952 1952 3
1953 1953 2
1954 1954 $ log 'reverse(all())'
1955 1955 9
1956 1956 8
1957 1957 7
1958 1958 6
1959 1959 5
1960 1960 4
1961 1961 3
1962 1962 2
1963 1963 1
1964 1964 0
1965 1965 $ log 'reverse(all()) & filelog(b)'
1966 1966 4
1967 1967 1
1968 1968 $ log 'rev(5)'
1969 1969 5
1970 1970 $ log 'sort(limit(reverse(all()), 3))'
1971 1971 7
1972 1972 8
1973 1973 9
1974 1974 $ log 'sort(2 or 3 or 4 or 5, date)'
1975 1975 2
1976 1976 3
1977 1977 5
1978 1978 4
1979 1979 $ log 'tagged()'
1980 1980 6
1981 1981 $ log 'tag()'
1982 1982 6
1983 1983 $ log 'tag(1.0)'
1984 1984 6
1985 1985 $ log 'tag(tip)'
1986 1986 9
1987 1987
1988 1988 Test order of revisions in compound expression
1989 1989 ----------------------------------------------
1990 1990
1991 1991 The general rule is that only the outermost (= leftmost) predicate can
1992 1992 enforce its ordering requirement. The other predicates should take the
1993 1993 ordering defined by it.
1994 1994
1995 1995 'A & B' should follow the order of 'A':
1996 1996
1997 1997 $ log '2:0 & 0::2'
1998 1998 2
1999 1999 1
2000 2000 0
2001 2001
2002 2002 'head()' combines sets in right order:
2003 2003
2004 2004 $ log '2:0 & head()'
2005 2005 2
2006 2006 1
2007 2007 0
2008 2008
2009 2009 'x:y' takes ordering parameter into account:
2010 2010
2011 2011 $ try -p optimized '3:0 & 0:3 & not 2:1'
2012 2012 * optimized:
2013 2013 (difference
2014 2014 (and
2015 2015 (range
2016 2016 (symbol '3')
2017 2017 (symbol '0'))
2018 2018 (range
2019 2019 (symbol '0')
2020 2020 (symbol '3')))
2021 2021 (range
2022 2022 (symbol '2')
2023 2023 (symbol '1')))
2024 2024 * set:
2025 2025 <filteredset
2026 2026 <filteredset
2027 2027 <spanset- 0:4>,
2028 2028 <spanset+ 0:4>>,
2029 2029 <not
2030 2030 <spanset+ 1:3>>>
2031 2031 3
2032 2032 0
2033 2033
2034 2034 'a + b', which is optimized to '_list(a b)', should take the ordering of
2035 2035 the left expression:
2036 2036
2037 2037 $ try --optimize '2:0 & (0 + 1 + 2)'
2038 2038 (and
2039 2039 (range
2040 2040 (symbol '2')
2041 2041 (symbol '0'))
2042 2042 (group
2043 2043 (or
2044 2044 (list
2045 2045 (symbol '0')
2046 2046 (symbol '1')
2047 2047 (symbol '2')))))
2048 2048 * optimized:
2049 2049 (and
2050 2050 (range
2051 2051 (symbol '2')
2052 2052 (symbol '0'))
2053 2053 (func
2054 2054 (symbol '_list')
2055 2055 (string '0\x001\x002')))
2056 2056 * set:
2057 2057 <filteredset
2058 2058 <spanset- 0:3>,
2059 2059 <baseset [0, 1, 2]>>
2060 2060 2
2061 2061 1
2062 2062 0
2063 2063
2064 2064 'A + B' should take the ordering of the left expression:
2065 2065
2066 2066 $ try --optimize '2:0 & (0:1 + 2)'
2067 2067 (and
2068 2068 (range
2069 2069 (symbol '2')
2070 2070 (symbol '0'))
2071 2071 (group
2072 2072 (or
2073 2073 (list
2074 2074 (range
2075 2075 (symbol '0')
2076 2076 (symbol '1'))
2077 2077 (symbol '2')))))
2078 2078 * optimized:
2079 2079 (and
2080 2080 (range
2081 2081 (symbol '2')
2082 2082 (symbol '0'))
2083 2083 (or
2084 2084 (list
2085 2085 (range
2086 2086 (symbol '0')
2087 2087 (symbol '1'))
2088 2088 (symbol '2'))))
2089 2089 * set:
2090 2090 <filteredset
2091 2091 <spanset- 0:3>,
2092 2092 <addset
2093 2093 <spanset+ 0:2>,
2094 2094 <baseset [2]>>>
2095 2095 2
2096 2096 1
2097 2097 0
2098 2098
2099 2099 '_intlist(a b)' should behave like 'a + b':
2100 2100
2101 2101 $ trylist --optimize '2:0 & %ld' 0 1 2
2102 2102 (and
2103 2103 (range
2104 2104 (symbol '2')
2105 2105 (symbol '0'))
2106 2106 (func
2107 2107 (symbol '_intlist')
2108 2108 (string '0\x001\x002')))
2109 2109 * optimized:
2110 2110 (andsmally
2111 2111 (range
2112 2112 (symbol '2')
2113 2113 (symbol '0'))
2114 2114 (func
2115 2115 (symbol '_intlist')
2116 2116 (string '0\x001\x002')))
2117 2117 * set:
2118 2118 <filteredset
2119 2119 <spanset- 0:3>,
2120 2120 <baseset+ [0, 1, 2]>>
2121 2121 2
2122 2122 1
2123 2123 0
2124 2124
2125 2125 $ trylist --optimize '%ld & 2:0' 0 2 1
2126 2126 (and
2127 2127 (func
2128 2128 (symbol '_intlist')
2129 2129 (string '0\x002\x001'))
2130 2130 (range
2131 2131 (symbol '2')
2132 2132 (symbol '0')))
2133 2133 * optimized:
2134 2134 (and
2135 2135 (func
2136 2136 (symbol '_intlist')
2137 2137 (string '0\x002\x001'))
2138 2138 (range
2139 2139 (symbol '2')
2140 2140 (symbol '0')))
2141 2141 * set:
2142 2142 <filteredset
2143 2143 <baseset [0, 2, 1]>,
2144 2144 <spanset- 0:3>>
2145 2145 0
2146 2146 2
2147 2147 1
2148 2148
2149 2149 '_hexlist(a b)' should behave like 'a + b':
2150 2150
2151 2151 $ trylist --optimize --bin '2:0 & %ln' `hg log -T '{node} ' -r0:2`
2152 2152 (and
2153 2153 (range
2154 2154 (symbol '2')
2155 2155 (symbol '0'))
2156 2156 (func
2157 2157 (symbol '_hexlist')
2158 2158 (string '*'))) (glob)
2159 2159 * optimized:
2160 2160 (and
2161 2161 (range
2162 2162 (symbol '2')
2163 2163 (symbol '0'))
2164 2164 (func
2165 2165 (symbol '_hexlist')
2166 2166 (string '*'))) (glob)
2167 2167 * set:
2168 2168 <filteredset
2169 2169 <spanset- 0:3>,
2170 2170 <baseset [0, 1, 2]>>
2171 2171 2
2172 2172 1
2173 2173 0
2174 2174
2175 2175 $ trylist --optimize --bin '%ln & 2:0' `hg log -T '{node} ' -r0+2+1`
2176 2176 (and
2177 2177 (func
2178 2178 (symbol '_hexlist')
2179 2179 (string '*')) (glob)
2180 2180 (range
2181 2181 (symbol '2')
2182 2182 (symbol '0')))
2183 2183 * optimized:
2184 2184 (andsmally
2185 2185 (func
2186 2186 (symbol '_hexlist')
2187 2187 (string '*')) (glob)
2188 2188 (range
2189 2189 (symbol '2')
2190 2190 (symbol '0')))
2191 2191 * set:
2192 2192 <baseset [0, 2, 1]>
2193 2193 0
2194 2194 2
2195 2195 1
2196 2196
2197 2197 '_list' should not go through the slow follow-order path if order doesn't
2198 2198 matter:
2199 2199
2200 2200 $ try -p optimized '2:0 & not (0 + 1)'
2201 2201 * optimized:
2202 2202 (difference
2203 2203 (range
2204 2204 (symbol '2')
2205 2205 (symbol '0'))
2206 2206 (func
2207 2207 (symbol '_list')
2208 2208 (string '0\x001')))
2209 2209 * set:
2210 2210 <filteredset
2211 2211 <spanset- 0:3>,
2212 2212 <not
2213 2213 <baseset [0, 1]>>>
2214 2214 2
2215 2215
2216 2216 $ try -p optimized '2:0 & not (0:2 & (0 + 1))'
2217 2217 * optimized:
2218 2218 (difference
2219 2219 (range
2220 2220 (symbol '2')
2221 2221 (symbol '0'))
2222 2222 (and
2223 2223 (range
2224 2224 (symbol '0')
2225 2225 (symbol '2'))
2226 2226 (func
2227 2227 (symbol '_list')
2228 2228 (string '0\x001'))))
2229 2229 * set:
2230 2230 <filteredset
2231 2231 <spanset- 0:3>,
2232 2232 <not
2233 2233 <baseset [0, 1]>>>
2234 2234 2
2235 2235
2236 2236 because 'present()' does nothing other than suppressing an error, the
2237 2237 ordering requirement should be forwarded to the nested expression
2238 2238
2239 2239 $ try -p optimized 'present(2 + 0 + 1)'
2240 2240 * optimized:
2241 2241 (func
2242 2242 (symbol 'present')
2243 2243 (func
2244 2244 (symbol '_list')
2245 2245 (string '2\x000\x001')))
2246 2246 * set:
2247 2247 <baseset [2, 0, 1]>
2248 2248 2
2249 2249 0
2250 2250 1
2251 2251
2252 2252 $ try --optimize '2:0 & present(0 + 1 + 2)'
2253 2253 (and
2254 2254 (range
2255 2255 (symbol '2')
2256 2256 (symbol '0'))
2257 2257 (func
2258 2258 (symbol 'present')
2259 2259 (or
2260 2260 (list
2261 2261 (symbol '0')
2262 2262 (symbol '1')
2263 2263 (symbol '2')))))
2264 2264 * optimized:
2265 2265 (and
2266 2266 (range
2267 2267 (symbol '2')
2268 2268 (symbol '0'))
2269 2269 (func
2270 2270 (symbol 'present')
2271 2271 (func
2272 2272 (symbol '_list')
2273 2273 (string '0\x001\x002'))))
2274 2274 * set:
2275 2275 <filteredset
2276 2276 <spanset- 0:3>,
2277 2277 <baseset [0, 1, 2]>>
2278 2278 2
2279 2279 1
2280 2280 0
2281 2281
2282 2282 'reverse()' should take effect only if it is the outermost expression:
2283 2283
2284 2284 $ try --optimize '0:2 & reverse(all())'
2285 2285 (and
2286 2286 (range
2287 2287 (symbol '0')
2288 2288 (symbol '2'))
2289 2289 (func
2290 2290 (symbol 'reverse')
2291 2291 (func
2292 2292 (symbol 'all')
2293 2293 None)))
2294 2294 * optimized:
2295 2295 (and
2296 2296 (range
2297 2297 (symbol '0')
2298 2298 (symbol '2'))
2299 2299 (func
2300 2300 (symbol 'reverse')
2301 2301 (func
2302 2302 (symbol 'all')
2303 2303 None)))
2304 2304 * set:
2305 2305 <filteredset
2306 2306 <spanset+ 0:3>,
2307 2307 <spanset+ 0:10>>
2308 2308 0
2309 2309 1
2310 2310 2
2311 2311
2312 2312 'sort()' should take effect only if it is the outermost expression:
2313 2313
2314 2314 $ try --optimize '0:2 & sort(all(), -rev)'
2315 2315 (and
2316 2316 (range
2317 2317 (symbol '0')
2318 2318 (symbol '2'))
2319 2319 (func
2320 2320 (symbol 'sort')
2321 2321 (list
2322 2322 (func
2323 2323 (symbol 'all')
2324 2324 None)
2325 2325 (negate
2326 2326 (symbol 'rev')))))
2327 2327 * optimized:
2328 2328 (and
2329 2329 (range
2330 2330 (symbol '0')
2331 2331 (symbol '2'))
2332 2332 (func
2333 2333 (symbol 'sort')
2334 2334 (list
2335 2335 (func
2336 2336 (symbol 'all')
2337 2337 None)
2338 2338 (string '-rev'))))
2339 2339 * set:
2340 2340 <filteredset
2341 2341 <spanset+ 0:3>,
2342 2342 <spanset+ 0:10>>
2343 2343 0
2344 2344 1
2345 2345 2
2346 2346
2347 2347 invalid argument passed to noop sort():
2348 2348
2349 2349 $ log '0:2 & sort()'
2350 2350 hg: parse error: sort requires one or two arguments
2351 2351 [255]
2352 2352 $ log '0:2 & sort(all(), -invalid)'
2353 2353 hg: parse error: unknown sort key '-invalid'
2354 2354 [255]
2355 2355
2356 2356 for 'A & f(B)', 'B' should not be affected by the order of 'A':
2357 2357
2358 2358 $ try --optimize '2:0 & first(1 + 0 + 2)'
2359 2359 (and
2360 2360 (range
2361 2361 (symbol '2')
2362 2362 (symbol '0'))
2363 2363 (func
2364 2364 (symbol 'first')
2365 2365 (or
2366 2366 (list
2367 2367 (symbol '1')
2368 2368 (symbol '0')
2369 2369 (symbol '2')))))
2370 2370 * optimized:
2371 2371 (and
2372 2372 (range
2373 2373 (symbol '2')
2374 2374 (symbol '0'))
2375 2375 (func
2376 2376 (symbol 'first')
2377 2377 (func
2378 2378 (symbol '_list')
2379 2379 (string '1\x000\x002'))))
2380 2380 * set:
2381 2381 <filteredset
2382 2382 <baseset [1]>,
2383 2383 <spanset- 0:3>>
2384 2384 1
2385 2385
2386 2386 $ try --optimize '2:0 & not last(0 + 2 + 1)'
2387 2387 (and
2388 2388 (range
2389 2389 (symbol '2')
2390 2390 (symbol '0'))
2391 2391 (not
2392 2392 (func
2393 2393 (symbol 'last')
2394 2394 (or
2395 2395 (list
2396 2396 (symbol '0')
2397 2397 (symbol '2')
2398 2398 (symbol '1'))))))
2399 2399 * optimized:
2400 2400 (difference
2401 2401 (range
2402 2402 (symbol '2')
2403 2403 (symbol '0'))
2404 2404 (func
2405 2405 (symbol 'last')
2406 2406 (func
2407 2407 (symbol '_list')
2408 2408 (string '0\x002\x001'))))
2409 2409 * set:
2410 2410 <filteredset
2411 2411 <spanset- 0:3>,
2412 2412 <not
2413 2413 <baseset [1]>>>
2414 2414 2
2415 2415 0
2416 2416
2417 2417 for 'A & (op)(B)', 'B' should not be affected by the order of 'A':
2418 2418
2419 2419 $ try --optimize '2:0 & (1 + 0 + 2):(0 + 2 + 1)'
2420 2420 (and
2421 2421 (range
2422 2422 (symbol '2')
2423 2423 (symbol '0'))
2424 2424 (range
2425 2425 (group
2426 2426 (or
2427 2427 (list
2428 2428 (symbol '1')
2429 2429 (symbol '0')
2430 2430 (symbol '2'))))
2431 2431 (group
2432 2432 (or
2433 2433 (list
2434 2434 (symbol '0')
2435 2435 (symbol '2')
2436 2436 (symbol '1'))))))
2437 2437 * optimized:
2438 2438 (and
2439 2439 (range
2440 2440 (symbol '2')
2441 2441 (symbol '0'))
2442 2442 (range
2443 2443 (func
2444 2444 (symbol '_list')
2445 2445 (string '1\x000\x002'))
2446 2446 (func
2447 2447 (symbol '_list')
2448 2448 (string '0\x002\x001'))))
2449 2449 * set:
2450 2450 <filteredset
2451 2451 <spanset- 0:3>,
2452 2452 <baseset [1]>>
2453 2453 1
2454 2454
2455 2455 'A & B' can be rewritten as 'flipand(B, A)' by weight.
2456 2456
2457 2457 $ try --optimize 'contains("glob:*") & (2 + 0 + 1)'
2458 2458 (and
2459 2459 (func
2460 2460 (symbol 'contains')
2461 2461 (string 'glob:*'))
2462 2462 (group
2463 2463 (or
2464 2464 (list
2465 2465 (symbol '2')
2466 2466 (symbol '0')
2467 2467 (symbol '1')))))
2468 2468 * optimized:
2469 2469 (andsmally
2470 2470 (func
2471 2471 (symbol 'contains')
2472 2472 (string 'glob:*'))
2473 2473 (func
2474 2474 (symbol '_list')
2475 2475 (string '2\x000\x001')))
2476 2476 * set:
2477 2477 <filteredset
2478 2478 <baseset+ [0, 1, 2]>,
2479 2479 <contains 'glob:*'>>
2480 2480 0
2481 2481 1
2482 2482 2
2483 2483
2484 2484 and in this example, 'A & B' is rewritten as 'B & A', but 'A' overrides
2485 2485 the order appropriately:
2486 2486
2487 2487 $ try --optimize 'reverse(contains("glob:*")) & (0 + 2 + 1)'
2488 2488 (and
2489 2489 (func
2490 2490 (symbol 'reverse')
2491 2491 (func
2492 2492 (symbol 'contains')
2493 2493 (string 'glob:*')))
2494 2494 (group
2495 2495 (or
2496 2496 (list
2497 2497 (symbol '0')
2498 2498 (symbol '2')
2499 2499 (symbol '1')))))
2500 2500 * optimized:
2501 2501 (andsmally
2502 2502 (func
2503 2503 (symbol 'reverse')
2504 2504 (func
2505 2505 (symbol 'contains')
2506 2506 (string 'glob:*')))
2507 2507 (func
2508 2508 (symbol '_list')
2509 2509 (string '0\x002\x001')))
2510 2510 * set:
2511 2511 <filteredset
2512 2512 <baseset- [0, 1, 2]>,
2513 2513 <contains 'glob:*'>>
2514 2514 2
2515 2515 1
2516 2516 0
2517 2517
2518 2518 test sort revset
2519 2519 --------------------------------------------
2520 2520
2521 2521 test when adding two unordered revsets
2522 2522
2523 2523 $ log 'sort(keyword(issue) or modifies(b))'
2524 2524 4
2525 2525 6
2526 2526
2527 2527 test when sorting a reversed collection in the same way it is
2528 2528
2529 2529 $ log 'sort(reverse(all()), -rev)'
2530 2530 9
2531 2531 8
2532 2532 7
2533 2533 6
2534 2534 5
2535 2535 4
2536 2536 3
2537 2537 2
2538 2538 1
2539 2539 0
2540 2540
2541 2541 test when sorting a reversed collection
2542 2542
2543 2543 $ log 'sort(reverse(all()), rev)'
2544 2544 0
2545 2545 1
2546 2546 2
2547 2547 3
2548 2548 4
2549 2549 5
2550 2550 6
2551 2551 7
2552 2552 8
2553 2553 9
2554 2554
2555 2555
2556 2556 test sorting two sorted collections in different orders
2557 2557
2558 2558 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
2559 2559 2
2560 2560 6
2561 2561 8
2562 2562 9
2563 2563
2564 2564 test sorting two sorted collections in different orders backwards
2565 2565
2566 2566 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
2567 2567 9
2568 2568 8
2569 2569 6
2570 2570 2
2571 2571
2572 2572 test empty sort key which is noop
2573 2573
2574 2574 $ log 'sort(0 + 2 + 1, "")'
2575 2575 0
2576 2576 2
2577 2577 1
2578 2578
2579 2579 test invalid sort keys
2580 2580
2581 2581 $ log 'sort(all(), -invalid)'
2582 2582 hg: parse error: unknown sort key '-invalid'
2583 2583 [255]
2584 2584
2585 2585 $ cd ..
2586 2586
2587 2587 test sorting by multiple keys including variable-length strings
2588 2588
2589 2589 $ hg init sorting
2590 2590 $ cd sorting
2591 2591 $ cat <<EOF >> .hg/hgrc
2592 2592 > [ui]
2593 2593 > logtemplate = '{rev} {branch|p5}{desc|p5}{author|p5}{date|hgdate}\n'
2594 2594 > [templatealias]
2595 2595 > p5(s) = pad(s, 5)
2596 2596 > EOF
2597 2597 $ hg branch -qf b12
2598 2598 $ hg ci -m m111 -u u112 -d '111 10800'
2599 2599 $ hg branch -qf b11
2600 2600 $ hg ci -m m12 -u u111 -d '112 7200'
2601 2601 $ hg branch -qf b111
2602 2602 $ hg ci -m m11 -u u12 -d '111 3600'
2603 2603 $ hg branch -qf b112
2604 2604 $ hg ci -m m111 -u u11 -d '120 0'
2605 2605 $ hg branch -qf b111
2606 2606 $ hg ci -m m112 -u u111 -d '110 14400'
2607 2607 created new head
2608 2608
2609 2609 compare revisions (has fast path):
2610 2610
2611 2611 $ hg log -r 'sort(all(), rev)'
2612 2612 0 b12 m111 u112 111 10800
2613 2613 1 b11 m12 u111 112 7200
2614 2614 2 b111 m11 u12 111 3600
2615 2615 3 b112 m111 u11 120 0
2616 2616 4 b111 m112 u111 110 14400
2617 2617
2618 2618 $ hg log -r 'sort(all(), -rev)'
2619 2619 4 b111 m112 u111 110 14400
2620 2620 3 b112 m111 u11 120 0
2621 2621 2 b111 m11 u12 111 3600
2622 2622 1 b11 m12 u111 112 7200
2623 2623 0 b12 m111 u112 111 10800
2624 2624
2625 2625 compare variable-length strings (issue5218):
2626 2626
2627 2627 $ hg log -r 'sort(all(), branch)'
2628 2628 1 b11 m12 u111 112 7200
2629 2629 2 b111 m11 u12 111 3600
2630 2630 4 b111 m112 u111 110 14400
2631 2631 3 b112 m111 u11 120 0
2632 2632 0 b12 m111 u112 111 10800
2633 2633
2634 2634 $ hg log -r 'sort(all(), -branch)'
2635 2635 0 b12 m111 u112 111 10800
2636 2636 3 b112 m111 u11 120 0
2637 2637 2 b111 m11 u12 111 3600
2638 2638 4 b111 m112 u111 110 14400
2639 2639 1 b11 m12 u111 112 7200
2640 2640
2641 2641 $ hg log -r 'sort(all(), desc)'
2642 2642 2 b111 m11 u12 111 3600
2643 2643 0 b12 m111 u112 111 10800
2644 2644 3 b112 m111 u11 120 0
2645 2645 4 b111 m112 u111 110 14400
2646 2646 1 b11 m12 u111 112 7200
2647 2647
2648 2648 $ hg log -r 'sort(all(), -desc)'
2649 2649 1 b11 m12 u111 112 7200
2650 2650 4 b111 m112 u111 110 14400
2651 2651 0 b12 m111 u112 111 10800
2652 2652 3 b112 m111 u11 120 0
2653 2653 2 b111 m11 u12 111 3600
2654 2654
2655 2655 $ hg log -r 'sort(all(), user)'
2656 2656 3 b112 m111 u11 120 0
2657 2657 1 b11 m12 u111 112 7200
2658 2658 4 b111 m112 u111 110 14400
2659 2659 0 b12 m111 u112 111 10800
2660 2660 2 b111 m11 u12 111 3600
2661 2661
2662 2662 $ hg log -r 'sort(all(), -user)'
2663 2663 2 b111 m11 u12 111 3600
2664 2664 0 b12 m111 u112 111 10800
2665 2665 1 b11 m12 u111 112 7200
2666 2666 4 b111 m112 u111 110 14400
2667 2667 3 b112 m111 u11 120 0
2668 2668
2669 2669 compare dates (tz offset should have no effect):
2670 2670
2671 2671 $ hg log -r 'sort(all(), date)'
2672 2672 4 b111 m112 u111 110 14400
2673 2673 0 b12 m111 u112 111 10800
2674 2674 2 b111 m11 u12 111 3600
2675 2675 1 b11 m12 u111 112 7200
2676 2676 3 b112 m111 u11 120 0
2677 2677
2678 2678 $ hg log -r 'sort(all(), -date)'
2679 2679 3 b112 m111 u11 120 0
2680 2680 1 b11 m12 u111 112 7200
2681 2681 0 b12 m111 u112 111 10800
2682 2682 2 b111 m11 u12 111 3600
2683 2683 4 b111 m112 u111 110 14400
2684 2684
2685 2685 be aware that 'sort(x, -k)' is not exactly the same as 'reverse(sort(x, k))'
2686 2686 because '-k' reverses the comparison, not the list itself:
2687 2687
2688 2688 $ hg log -r 'sort(0 + 2, date)'
2689 2689 0 b12 m111 u112 111 10800
2690 2690 2 b111 m11 u12 111 3600
2691 2691
2692 2692 $ hg log -r 'sort(0 + 2, -date)'
2693 2693 0 b12 m111 u112 111 10800
2694 2694 2 b111 m11 u12 111 3600
2695 2695
2696 2696 $ hg log -r 'reverse(sort(0 + 2, date))'
2697 2697 2 b111 m11 u12 111 3600
2698 2698 0 b12 m111 u112 111 10800
2699 2699
2700 2700 sort by multiple keys:
2701 2701
2702 2702 $ hg log -r 'sort(all(), "branch -rev")'
2703 2703 1 b11 m12 u111 112 7200
2704 2704 4 b111 m112 u111 110 14400
2705 2705 2 b111 m11 u12 111 3600
2706 2706 3 b112 m111 u11 120 0
2707 2707 0 b12 m111 u112 111 10800
2708 2708
2709 2709 $ hg log -r 'sort(all(), "-desc -date")'
2710 2710 1 b11 m12 u111 112 7200
2711 2711 4 b111 m112 u111 110 14400
2712 2712 3 b112 m111 u11 120 0
2713 2713 0 b12 m111 u112 111 10800
2714 2714 2 b111 m11 u12 111 3600
2715 2715
2716 2716 $ hg log -r 'sort(all(), "user -branch date rev")'
2717 2717 3 b112 m111 u11 120 0
2718 2718 4 b111 m112 u111 110 14400
2719 2719 1 b11 m12 u111 112 7200
2720 2720 0 b12 m111 u112 111 10800
2721 2721 2 b111 m11 u12 111 3600
2722 2722
2723 2723 toposort prioritises graph branches
2724 2724
2725 2725 $ hg up 2
2726 2726 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2727 2727 $ touch a
2728 2728 $ hg addremove
2729 2729 adding a
2730 2730 $ hg ci -m 't1' -u 'tu' -d '130 0'
2731 2731 created new head
2732 2732 $ echo 'a' >> a
2733 2733 $ hg ci -m 't2' -u 'tu' -d '130 0'
2734 2734 $ hg book book1
2735 2735 $ hg up 4
2736 2736 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
2737 2737 (leaving bookmark book1)
2738 2738 $ touch a
2739 2739 $ hg addremove
2740 2740 adding a
2741 2741 $ hg ci -m 't3' -u 'tu' -d '130 0'
2742 2742
2743 2743 $ hg log -r 'sort(all(), topo)'
2744 2744 7 b111 t3 tu 130 0
2745 2745 4 b111 m112 u111 110 14400
2746 2746 3 b112 m111 u11 120 0
2747 2747 6 b111 t2 tu 130 0
2748 2748 5 b111 t1 tu 130 0
2749 2749 2 b111 m11 u12 111 3600
2750 2750 1 b11 m12 u111 112 7200
2751 2751 0 b12 m111 u112 111 10800
2752 2752
2753 2753 $ hg log -r 'sort(all(), -topo)'
2754 2754 0 b12 m111 u112 111 10800
2755 2755 1 b11 m12 u111 112 7200
2756 2756 2 b111 m11 u12 111 3600
2757 2757 5 b111 t1 tu 130 0
2758 2758 6 b111 t2 tu 130 0
2759 2759 3 b112 m111 u11 120 0
2760 2760 4 b111 m112 u111 110 14400
2761 2761 7 b111 t3 tu 130 0
2762 2762
2763 2763 $ hg log -r 'sort(all(), topo, topo.firstbranch=book1)'
2764 2764 6 b111 t2 tu 130 0
2765 2765 5 b111 t1 tu 130 0
2766 2766 7 b111 t3 tu 130 0
2767 2767 4 b111 m112 u111 110 14400
2768 2768 3 b112 m111 u11 120 0
2769 2769 2 b111 m11 u12 111 3600
2770 2770 1 b11 m12 u111 112 7200
2771 2771 0 b12 m111 u112 111 10800
2772 2772
2773 2773 topographical sorting can't be combined with other sort keys, and you can't
2774 2774 use the topo.firstbranch option when topo sort is not active:
2775 2775
2776 2776 $ hg log -r 'sort(all(), "topo user")'
2777 2777 hg: parse error: topo sort order cannot be combined with other sort keys
2778 2778 [255]
2779 2779
2780 2780 $ hg log -r 'sort(all(), user, topo.firstbranch=book1)'
2781 2781 hg: parse error: topo.firstbranch can only be used when using the topo sort key
2782 2782 [255]
2783 2783
2784 2784 topo.firstbranch should accept any kind of expressions:
2785 2785
2786 2786 $ hg log -r 'sort(0, topo, topo.firstbranch=(book1))'
2787 2787 0 b12 m111 u112 111 10800
2788 2788
2789 2789 $ cd ..
2790 2790 $ cd repo
2791 2791
2792 2792 test multiline revset with errors
2793 2793
2794 2794 $ echo > multiline-revset
2795 2795 $ echo '. +' >> multiline-revset
2796 2796 $ echo '.^ +' >> multiline-revset
2797 2797 $ hg log -r "`cat multiline-revset`"
2798 2798 hg: parse error at 9: not a prefix: end
2799 2799 ( . + .^ +
2800 2800 ^ here)
2801 2801 [255]
2802 2802 $ hg debugrevspec -v 'revset(first(rev(0)))' -p all
2803 2803 * parsed:
2804 2804 (func
2805 2805 (symbol 'revset')
2806 2806 (func
2807 2807 (symbol 'first')
2808 2808 (func
2809 2809 (symbol 'rev')
2810 2810 (symbol '0'))))
2811 2811 * expanded:
2812 2812 (func
2813 2813 (symbol 'revset')
2814 2814 (func
2815 2815 (symbol 'first')
2816 2816 (func
2817 2817 (symbol 'rev')
2818 2818 (symbol '0'))))
2819 2819 * concatenated:
2820 2820 (func
2821 2821 (symbol 'revset')
2822 2822 (func
2823 2823 (symbol 'first')
2824 2824 (func
2825 2825 (symbol 'rev')
2826 2826 (symbol '0'))))
2827 2827 * analyzed:
2828 2828 (func
2829 2829 (symbol 'first')
2830 2830 (func
2831 2831 (symbol 'rev')
2832 2832 (symbol '0')))
2833 2833 * optimized:
2834 2834 (func
2835 2835 (symbol 'first')
2836 2836 (func
2837 2837 (symbol 'rev')
2838 2838 (symbol '0')))
2839 2839 * set:
2840 2840 <baseset+ [0]>
2841 2841 0
General Comments 0
You need to be logged in to leave comments. Login now