##// END OF EJS Templates
log: populate keywords if specified in custom -Tjson(...) or -Tcbor(...)...
Yuya Nishihara -
r43372:829088e8 default
parent child Browse files
Show More
@@ -1,1064 +1,1071 b''
1 1 # logcmdutil.py - utility for log-like commands
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import itertools
11 11 import os
12 12 import posixpath
13 13
14 14 from .i18n import _
15 15 from .node import (
16 16 nullid,
17 17 wdirid,
18 18 wdirrev,
19 19 )
20 20
21 21 from . import (
22 22 dagop,
23 23 error,
24 24 formatter,
25 25 graphmod,
26 26 match as matchmod,
27 27 mdiff,
28 28 patch,
29 29 pathutil,
30 30 pycompat,
31 31 revset,
32 32 revsetlang,
33 33 scmutil,
34 34 smartset,
35 35 templatekw,
36 36 templater,
37 37 util,
38 38 )
39 39 from .utils import (
40 40 dateutil,
41 41 stringutil,
42 42 )
43 43
44 44
45 45 def getlimit(opts):
46 46 """get the log limit according to option -l/--limit"""
47 47 limit = opts.get(b'limit')
48 48 if limit:
49 49 try:
50 50 limit = int(limit)
51 51 except ValueError:
52 52 raise error.Abort(_(b'limit must be a positive integer'))
53 53 if limit <= 0:
54 54 raise error.Abort(_(b'limit must be positive'))
55 55 else:
56 56 limit = None
57 57 return limit
58 58
59 59
60 60 def diffordiffstat(
61 61 ui,
62 62 repo,
63 63 diffopts,
64 64 node1,
65 65 node2,
66 66 match,
67 67 changes=None,
68 68 stat=False,
69 69 fp=None,
70 70 graphwidth=0,
71 71 prefix=b'',
72 72 root=b'',
73 73 listsubrepos=False,
74 74 hunksfilterfn=None,
75 75 ):
76 76 '''show diff or diffstat.'''
77 77 ctx1 = repo[node1]
78 78 ctx2 = repo[node2]
79 79 if root:
80 80 relroot = pathutil.canonpath(repo.root, repo.getcwd(), root)
81 81 else:
82 82 relroot = b''
83 83 copysourcematch = None
84 84
85 85 def compose(f, g):
86 86 return lambda x: f(g(x))
87 87
88 88 def pathfn(f):
89 89 return posixpath.join(prefix, f)
90 90
91 91 if relroot != b'':
92 92 # XXX relative roots currently don't work if the root is within a
93 93 # subrepo
94 94 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
95 95 uirelroot = uipathfn(pathfn(relroot))
96 96 relroot += b'/'
97 97 for matchroot in match.files():
98 98 if not matchroot.startswith(relroot):
99 99 ui.warn(
100 100 _(b'warning: %s not inside relative root %s\n')
101 101 % (uipathfn(pathfn(matchroot)), uirelroot)
102 102 )
103 103
104 104 relrootmatch = scmutil.match(ctx2, pats=[relroot], default=b'path')
105 105 match = matchmod.intersectmatchers(match, relrootmatch)
106 106 copysourcematch = relrootmatch
107 107
108 108 checkroot = repo.ui.configbool(
109 109 b'devel', b'all-warnings'
110 110 ) or repo.ui.configbool(b'devel', b'check-relroot')
111 111
112 112 def relrootpathfn(f):
113 113 if checkroot and not f.startswith(relroot):
114 114 raise AssertionError(
115 115 b"file %s doesn't start with relroot %s" % (f, relroot)
116 116 )
117 117 return f[len(relroot) :]
118 118
119 119 pathfn = compose(relrootpathfn, pathfn)
120 120
121 121 if stat:
122 122 diffopts = diffopts.copy(context=0, noprefix=False)
123 123 width = 80
124 124 if not ui.plain():
125 125 width = ui.termwidth() - graphwidth
126 126 # If an explicit --root was given, don't respect ui.relative-paths
127 127 if not relroot:
128 128 pathfn = compose(scmutil.getuipathfn(repo), pathfn)
129 129
130 130 chunks = ctx2.diff(
131 131 ctx1,
132 132 match,
133 133 changes,
134 134 opts=diffopts,
135 135 pathfn=pathfn,
136 136 copysourcematch=copysourcematch,
137 137 hunksfilterfn=hunksfilterfn,
138 138 )
139 139
140 140 if fp is not None or ui.canwritewithoutlabels():
141 141 out = fp or ui
142 142 if stat:
143 143 chunks = [patch.diffstat(util.iterlines(chunks), width=width)]
144 144 for chunk in util.filechunkiter(util.chunkbuffer(chunks)):
145 145 out.write(chunk)
146 146 else:
147 147 if stat:
148 148 chunks = patch.diffstatui(util.iterlines(chunks), width=width)
149 149 else:
150 150 chunks = patch.difflabel(
151 151 lambda chunks, **kwargs: chunks, chunks, opts=diffopts
152 152 )
153 153 if ui.canbatchlabeledwrites():
154 154
155 155 def gen():
156 156 for chunk, label in chunks:
157 157 yield ui.label(chunk, label=label)
158 158
159 159 for chunk in util.filechunkiter(util.chunkbuffer(gen())):
160 160 ui.write(chunk)
161 161 else:
162 162 for chunk, label in chunks:
163 163 ui.write(chunk, label=label)
164 164
165 165 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
166 166 tempnode2 = node2
167 167 try:
168 168 if node2 is not None:
169 169 tempnode2 = ctx2.substate[subpath][1]
170 170 except KeyError:
171 171 # A subrepo that existed in node1 was deleted between node1 and
172 172 # node2 (inclusive). Thus, ctx2's substate won't contain that
173 173 # subpath. The best we can do is to ignore it.
174 174 tempnode2 = None
175 175 submatch = matchmod.subdirmatcher(subpath, match)
176 176 subprefix = repo.wvfs.reljoin(prefix, subpath)
177 177 if listsubrepos or match.exact(subpath) or any(submatch.files()):
178 178 sub.diff(
179 179 ui,
180 180 diffopts,
181 181 tempnode2,
182 182 submatch,
183 183 changes=changes,
184 184 stat=stat,
185 185 fp=fp,
186 186 prefix=subprefix,
187 187 )
188 188
189 189
190 190 class changesetdiffer(object):
191 191 """Generate diff of changeset with pre-configured filtering functions"""
192 192
193 193 def _makefilematcher(self, ctx):
194 194 return scmutil.matchall(ctx.repo())
195 195
196 196 def _makehunksfilter(self, ctx):
197 197 return None
198 198
199 199 def showdiff(self, ui, ctx, diffopts, graphwidth=0, stat=False):
200 200 repo = ctx.repo()
201 201 node = ctx.node()
202 202 prev = ctx.p1().node()
203 203 diffordiffstat(
204 204 ui,
205 205 repo,
206 206 diffopts,
207 207 prev,
208 208 node,
209 209 match=self._makefilematcher(ctx),
210 210 stat=stat,
211 211 graphwidth=graphwidth,
212 212 hunksfilterfn=self._makehunksfilter(ctx),
213 213 )
214 214
215 215
216 216 def changesetlabels(ctx):
217 217 labels = [b'log.changeset', b'changeset.%s' % ctx.phasestr()]
218 218 if ctx.obsolete():
219 219 labels.append(b'changeset.obsolete')
220 220 if ctx.isunstable():
221 221 labels.append(b'changeset.unstable')
222 222 for instability in ctx.instabilities():
223 223 labels.append(b'instability.%s' % instability)
224 224 return b' '.join(labels)
225 225
226 226
227 227 class changesetprinter(object):
228 228 '''show changeset information when templating not requested.'''
229 229
230 230 def __init__(self, ui, repo, differ=None, diffopts=None, buffered=False):
231 231 self.ui = ui
232 232 self.repo = repo
233 233 self.buffered = buffered
234 234 self._differ = differ or changesetdiffer()
235 235 self._diffopts = patch.diffallopts(ui, diffopts)
236 236 self._includestat = diffopts and diffopts.get(b'stat')
237 237 self._includediff = diffopts and diffopts.get(b'patch')
238 238 self.header = {}
239 239 self.hunk = {}
240 240 self.lastheader = None
241 241 self.footer = None
242 242 self._columns = templatekw.getlogcolumns()
243 243
244 244 def flush(self, ctx):
245 245 rev = ctx.rev()
246 246 if rev in self.header:
247 247 h = self.header[rev]
248 248 if h != self.lastheader:
249 249 self.lastheader = h
250 250 self.ui.write(h)
251 251 del self.header[rev]
252 252 if rev in self.hunk:
253 253 self.ui.write(self.hunk[rev])
254 254 del self.hunk[rev]
255 255
256 256 def close(self):
257 257 if self.footer:
258 258 self.ui.write(self.footer)
259 259
260 260 def show(self, ctx, copies=None, **props):
261 261 props = pycompat.byteskwargs(props)
262 262 if self.buffered:
263 263 self.ui.pushbuffer(labeled=True)
264 264 self._show(ctx, copies, props)
265 265 self.hunk[ctx.rev()] = self.ui.popbuffer()
266 266 else:
267 267 self._show(ctx, copies, props)
268 268
269 269 def _show(self, ctx, copies, props):
270 270 '''show a single changeset or file revision'''
271 271 changenode = ctx.node()
272 272 graphwidth = props.get(b'graphwidth', 0)
273 273
274 274 if self.ui.quiet:
275 275 self.ui.write(
276 276 b"%s\n" % scmutil.formatchangeid(ctx), label=b'log.node'
277 277 )
278 278 return
279 279
280 280 columns = self._columns
281 281 self.ui.write(
282 282 columns[b'changeset'] % scmutil.formatchangeid(ctx),
283 283 label=changesetlabels(ctx),
284 284 )
285 285
286 286 # branches are shown first before any other names due to backwards
287 287 # compatibility
288 288 branch = ctx.branch()
289 289 # don't show the default branch name
290 290 if branch != b'default':
291 291 self.ui.write(columns[b'branch'] % branch, label=b'log.branch')
292 292
293 293 for nsname, ns in self.repo.names.iteritems():
294 294 # branches has special logic already handled above, so here we just
295 295 # skip it
296 296 if nsname == b'branches':
297 297 continue
298 298 # we will use the templatename as the color name since those two
299 299 # should be the same
300 300 for name in ns.names(self.repo, changenode):
301 301 self.ui.write(ns.logfmt % name, label=b'log.%s' % ns.colorname)
302 302 if self.ui.debugflag:
303 303 self.ui.write(
304 304 columns[b'phase'] % ctx.phasestr(), label=b'log.phase'
305 305 )
306 306 for pctx in scmutil.meaningfulparents(self.repo, ctx):
307 307 label = b'log.parent changeset.%s' % pctx.phasestr()
308 308 self.ui.write(
309 309 columns[b'parent'] % scmutil.formatchangeid(pctx), label=label
310 310 )
311 311
312 312 if self.ui.debugflag:
313 313 mnode = ctx.manifestnode()
314 314 if mnode is None:
315 315 mnode = wdirid
316 316 mrev = wdirrev
317 317 else:
318 318 mrev = self.repo.manifestlog.rev(mnode)
319 319 self.ui.write(
320 320 columns[b'manifest']
321 321 % scmutil.formatrevnode(self.ui, mrev, mnode),
322 322 label=b'ui.debug log.manifest',
323 323 )
324 324 self.ui.write(columns[b'user'] % ctx.user(), label=b'log.user')
325 325 self.ui.write(
326 326 columns[b'date'] % dateutil.datestr(ctx.date()), label=b'log.date'
327 327 )
328 328
329 329 if ctx.isunstable():
330 330 instabilities = ctx.instabilities()
331 331 self.ui.write(
332 332 columns[b'instability'] % b', '.join(instabilities),
333 333 label=b'log.instability',
334 334 )
335 335
336 336 elif ctx.obsolete():
337 337 self._showobsfate(ctx)
338 338
339 339 self._exthook(ctx)
340 340
341 341 if self.ui.debugflag:
342 342 files = ctx.p1().status(ctx)[:3]
343 343 for key, value in zip([b'files', b'files+', b'files-'], files):
344 344 if value:
345 345 self.ui.write(
346 346 columns[key] % b" ".join(value),
347 347 label=b'ui.debug log.files',
348 348 )
349 349 elif ctx.files() and self.ui.verbose:
350 350 self.ui.write(
351 351 columns[b'files'] % b" ".join(ctx.files()),
352 352 label=b'ui.note log.files',
353 353 )
354 354 if copies and self.ui.verbose:
355 355 copies = [b'%s (%s)' % c for c in copies]
356 356 self.ui.write(
357 357 columns[b'copies'] % b' '.join(copies),
358 358 label=b'ui.note log.copies',
359 359 )
360 360
361 361 extra = ctx.extra()
362 362 if extra and self.ui.debugflag:
363 363 for key, value in sorted(extra.items()):
364 364 self.ui.write(
365 365 columns[b'extra'] % (key, stringutil.escapestr(value)),
366 366 label=b'ui.debug log.extra',
367 367 )
368 368
369 369 description = ctx.description().strip()
370 370 if description:
371 371 if self.ui.verbose:
372 372 self.ui.write(
373 373 _(b"description:\n"), label=b'ui.note log.description'
374 374 )
375 375 self.ui.write(description, label=b'ui.note log.description')
376 376 self.ui.write(b"\n\n")
377 377 else:
378 378 self.ui.write(
379 379 columns[b'summary'] % description.splitlines()[0],
380 380 label=b'log.summary',
381 381 )
382 382 self.ui.write(b"\n")
383 383
384 384 self._showpatch(ctx, graphwidth)
385 385
386 386 def _showobsfate(self, ctx):
387 387 # TODO: do not depend on templater
388 388 tres = formatter.templateresources(self.repo.ui, self.repo)
389 389 t = formatter.maketemplater(
390 390 self.repo.ui,
391 391 b'{join(obsfate, "\n")}',
392 392 defaults=templatekw.keywords,
393 393 resources=tres,
394 394 )
395 395 obsfate = t.renderdefault({b'ctx': ctx}).splitlines()
396 396
397 397 if obsfate:
398 398 for obsfateline in obsfate:
399 399 self.ui.write(
400 400 self._columns[b'obsolete'] % obsfateline,
401 401 label=b'log.obsfate',
402 402 )
403 403
404 404 def _exthook(self, ctx):
405 405 '''empty method used by extension as a hook point
406 406 '''
407 407
408 408 def _showpatch(self, ctx, graphwidth=0):
409 409 if self._includestat:
410 410 self._differ.showdiff(
411 411 self.ui, ctx, self._diffopts, graphwidth, stat=True
412 412 )
413 413 if self._includestat and self._includediff:
414 414 self.ui.write(b"\n")
415 415 if self._includediff:
416 416 self._differ.showdiff(
417 417 self.ui, ctx, self._diffopts, graphwidth, stat=False
418 418 )
419 419 if self._includestat or self._includediff:
420 420 self.ui.write(b"\n")
421 421
422 422
423 423 class changesetformatter(changesetprinter):
424 424 """Format changeset information by generic formatter"""
425 425
426 426 def __init__(
427 427 self, ui, repo, fm, differ=None, diffopts=None, buffered=False
428 428 ):
429 429 changesetprinter.__init__(self, ui, repo, differ, diffopts, buffered)
430 430 self._diffopts = patch.difffeatureopts(ui, diffopts, git=True)
431 431 self._fm = fm
432 432
433 433 def close(self):
434 434 self._fm.end()
435 435
436 436 def _show(self, ctx, copies, props):
437 437 '''show a single changeset or file revision'''
438 438 fm = self._fm
439 439 fm.startitem()
440 440 fm.context(ctx=ctx)
441 441 fm.data(rev=scmutil.intrev(ctx), node=fm.hexfunc(scmutil.binnode(ctx)))
442 442
443 if self.ui.quiet:
443 datahint = fm.datahint()
444 if self.ui.quiet and not datahint:
444 445 return
445 446
446 447 fm.data(
447 448 branch=ctx.branch(),
448 449 phase=ctx.phasestr(),
449 450 user=ctx.user(),
450 451 date=fm.formatdate(ctx.date()),
451 452 desc=ctx.description(),
452 453 bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'),
453 454 tags=fm.formatlist(ctx.tags(), name=b'tag'),
454 455 parents=fm.formatlist(
455 456 [fm.hexfunc(c.node()) for c in ctx.parents()], name=b'node'
456 457 ),
457 458 )
458 459
459 if self.ui.debugflag:
460 fm.data(
461 manifest=fm.hexfunc(ctx.manifestnode() or wdirid),
462 extra=fm.formatdict(ctx.extra()),
463 )
460 if self.ui.debugflag or b'manifest' in datahint:
461 fm.data(manifest=fm.hexfunc(ctx.manifestnode() or wdirid))
462 if self.ui.debugflag or b'extra' in datahint:
463 fm.data(extra=fm.formatdict(ctx.extra()))
464 464
465 if (
466 self.ui.debugflag
467 or b'modified' in datahint
468 or b'added' in datahint
469 or b'removed' in datahint
470 ):
465 471 files = ctx.p1().status(ctx)
466 472 fm.data(
467 473 modified=fm.formatlist(files[0], name=b'file'),
468 474 added=fm.formatlist(files[1], name=b'file'),
469 475 removed=fm.formatlist(files[2], name=b'file'),
470 476 )
471 477
472 elif self.ui.verbose:
478 verbose = not self.ui.debugflag and self.ui.verbose
479 if verbose or b'files' in datahint:
473 480 fm.data(files=fm.formatlist(ctx.files(), name=b'file'))
474 if copies:
481 if verbose and copies or b'copies' in datahint:
475 482 fm.data(
476 copies=fm.formatdict(copies, key=b'name', value=b'source')
483 copies=fm.formatdict(copies or {}, key=b'name', value=b'source')
477 484 )
478 485
479 if self._includestat:
486 if self._includestat or b'diffstat' in datahint:
480 487 self.ui.pushbuffer()
481 488 self._differ.showdiff(self.ui, ctx, self._diffopts, stat=True)
482 489 fm.data(diffstat=self.ui.popbuffer())
483 if self._includediff:
490 if self._includediff or b'diff' in datahint:
484 491 self.ui.pushbuffer()
485 492 self._differ.showdiff(self.ui, ctx, self._diffopts, stat=False)
486 493 fm.data(diff=self.ui.popbuffer())
487 494
488 495
489 496 class changesettemplater(changesetprinter):
490 497 '''format changeset information.
491 498
492 499 Note: there are a variety of convenience functions to build a
493 500 changesettemplater for common cases. See functions such as:
494 501 maketemplater, changesetdisplayer, buildcommittemplate, or other
495 502 functions that use changesest_templater.
496 503 '''
497 504
498 505 # Arguments before "buffered" used to be positional. Consider not
499 506 # adding/removing arguments before "buffered" to not break callers.
500 507 def __init__(
501 508 self, ui, repo, tmplspec, differ=None, diffopts=None, buffered=False
502 509 ):
503 510 changesetprinter.__init__(self, ui, repo, differ, diffopts, buffered)
504 511 # tres is shared with _graphnodeformatter()
505 512 self._tresources = tres = formatter.templateresources(ui, repo)
506 513 self.t = formatter.loadtemplater(
507 514 ui,
508 515 tmplspec,
509 516 defaults=templatekw.keywords,
510 517 resources=tres,
511 518 cache=templatekw.defaulttempl,
512 519 )
513 520 self._counter = itertools.count()
514 521
515 522 self._tref = tmplspec.ref
516 523 self._parts = {
517 524 b'header': b'',
518 525 b'footer': b'',
519 526 tmplspec.ref: tmplspec.ref,
520 527 b'docheader': b'',
521 528 b'docfooter': b'',
522 529 b'separator': b'',
523 530 }
524 531 if tmplspec.mapfile:
525 532 # find correct templates for current mode, for backward
526 533 # compatibility with 'log -v/-q/--debug' using a mapfile
527 534 tmplmodes = [
528 535 (True, b''),
529 536 (self.ui.verbose, b'_verbose'),
530 537 (self.ui.quiet, b'_quiet'),
531 538 (self.ui.debugflag, b'_debug'),
532 539 ]
533 540 for mode, postfix in tmplmodes:
534 541 for t in self._parts:
535 542 cur = t + postfix
536 543 if mode and cur in self.t:
537 544 self._parts[t] = cur
538 545 else:
539 546 partnames = [p for p in self._parts.keys() if p != tmplspec.ref]
540 547 m = formatter.templatepartsmap(tmplspec, self.t, partnames)
541 548 self._parts.update(m)
542 549
543 550 if self._parts[b'docheader']:
544 551 self.ui.write(self.t.render(self._parts[b'docheader'], {}))
545 552
546 553 def close(self):
547 554 if self._parts[b'docfooter']:
548 555 if not self.footer:
549 556 self.footer = b""
550 557 self.footer += self.t.render(self._parts[b'docfooter'], {})
551 558 return super(changesettemplater, self).close()
552 559
553 560 def _show(self, ctx, copies, props):
554 561 '''show a single changeset or file revision'''
555 562 props = props.copy()
556 563 props[b'ctx'] = ctx
557 564 props[b'index'] = index = next(self._counter)
558 565 props[b'revcache'] = {b'copies': copies}
559 566 graphwidth = props.get(b'graphwidth', 0)
560 567
561 568 # write separator, which wouldn't work well with the header part below
562 569 # since there's inherently a conflict between header (across items) and
563 570 # separator (per item)
564 571 if self._parts[b'separator'] and index > 0:
565 572 self.ui.write(self.t.render(self._parts[b'separator'], {}))
566 573
567 574 # write header
568 575 if self._parts[b'header']:
569 576 h = self.t.render(self._parts[b'header'], props)
570 577 if self.buffered:
571 578 self.header[ctx.rev()] = h
572 579 else:
573 580 if self.lastheader != h:
574 581 self.lastheader = h
575 582 self.ui.write(h)
576 583
577 584 # write changeset metadata, then patch if requested
578 585 key = self._parts[self._tref]
579 586 self.ui.write(self.t.render(key, props))
580 587 self._showpatch(ctx, graphwidth)
581 588
582 589 if self._parts[b'footer']:
583 590 if not self.footer:
584 591 self.footer = self.t.render(self._parts[b'footer'], props)
585 592
586 593
587 594 def templatespec(tmpl, mapfile):
588 595 if pycompat.ispy3:
589 596 assert not isinstance(tmpl, str), b'tmpl must not be a str'
590 597 if mapfile:
591 598 return formatter.templatespec(b'changeset', tmpl, mapfile)
592 599 else:
593 600 return formatter.templatespec(b'', tmpl, None)
594 601
595 602
596 603 def _lookuptemplate(ui, tmpl, style):
597 604 """Find the template matching the given template spec or style
598 605
599 606 See formatter.lookuptemplate() for details.
600 607 """
601 608
602 609 # ui settings
603 610 if not tmpl and not style: # template are stronger than style
604 611 tmpl = ui.config(b'ui', b'logtemplate')
605 612 if tmpl:
606 613 return templatespec(templater.unquotestring(tmpl), None)
607 614 else:
608 615 style = util.expandpath(ui.config(b'ui', b'style'))
609 616
610 617 if not tmpl and style:
611 618 mapfile = style
612 619 if not os.path.split(mapfile)[0]:
613 620 mapname = templater.templatepath(
614 621 b'map-cmdline.' + mapfile
615 622 ) or templater.templatepath(mapfile)
616 623 if mapname:
617 624 mapfile = mapname
618 625 return templatespec(None, mapfile)
619 626
620 627 return formatter.lookuptemplate(ui, b'changeset', tmpl)
621 628
622 629
623 630 def maketemplater(ui, repo, tmpl, buffered=False):
624 631 """Create a changesettemplater from a literal template 'tmpl'
625 632 byte-string."""
626 633 spec = templatespec(tmpl, None)
627 634 return changesettemplater(ui, repo, spec, buffered=buffered)
628 635
629 636
630 637 def changesetdisplayer(ui, repo, opts, differ=None, buffered=False):
631 638 """show one changeset using template or regular display.
632 639
633 640 Display format will be the first non-empty hit of:
634 641 1. option 'template'
635 642 2. option 'style'
636 643 3. [ui] setting 'logtemplate'
637 644 4. [ui] setting 'style'
638 645 If all of these values are either the unset or the empty string,
639 646 regular display via changesetprinter() is done.
640 647 """
641 648 postargs = (differ, opts, buffered)
642 649 spec = _lookuptemplate(ui, opts.get(b'template'), opts.get(b'style'))
643 650
644 651 # machine-readable formats have slightly different keyword set than
645 652 # plain templates, which are handled by changesetformatter.
646 653 # note that {b'pickle', b'debug'} can also be added to the list if needed.
647 654 if spec.ref in {b'cbor', b'json'}:
648 655 fm = ui.formatter(b'log', opts)
649 656 return changesetformatter(ui, repo, fm, *postargs)
650 657
651 658 if not spec.ref and not spec.tmpl and not spec.mapfile:
652 659 return changesetprinter(ui, repo, *postargs)
653 660
654 661 return changesettemplater(ui, repo, spec, *postargs)
655 662
656 663
657 664 def _makematcher(repo, revs, pats, opts):
658 665 """Build matcher and expanded patterns from log options
659 666
660 667 If --follow, revs are the revisions to follow from.
661 668
662 669 Returns (match, pats, slowpath) where
663 670 - match: a matcher built from the given pats and -I/-X opts
664 671 - pats: patterns used (globs are expanded on Windows)
665 672 - slowpath: True if patterns aren't as simple as scanning filelogs
666 673 """
667 674 # pats/include/exclude are passed to match.match() directly in
668 675 # _matchfiles() revset but walkchangerevs() builds its matcher with
669 676 # scmutil.match(). The difference is input pats are globbed on
670 677 # platforms without shell expansion (windows).
671 678 wctx = repo[None]
672 679 match, pats = scmutil.matchandpats(wctx, pats, opts)
673 680 slowpath = match.anypats() or (not match.always() and opts.get(b'removed'))
674 681 if not slowpath:
675 682 follow = opts.get(b'follow') or opts.get(b'follow_first')
676 683 startctxs = []
677 684 if follow and opts.get(b'rev'):
678 685 startctxs = [repo[r] for r in revs]
679 686 for f in match.files():
680 687 if follow and startctxs:
681 688 # No idea if the path was a directory at that revision, so
682 689 # take the slow path.
683 690 if any(f not in c for c in startctxs):
684 691 slowpath = True
685 692 continue
686 693 elif follow and f not in wctx:
687 694 # If the file exists, it may be a directory, so let it
688 695 # take the slow path.
689 696 if os.path.exists(repo.wjoin(f)):
690 697 slowpath = True
691 698 continue
692 699 else:
693 700 raise error.Abort(
694 701 _(
695 702 b'cannot follow file not in parent '
696 703 b'revision: "%s"'
697 704 )
698 705 % f
699 706 )
700 707 filelog = repo.file(f)
701 708 if not filelog:
702 709 # A zero count may be a directory or deleted file, so
703 710 # try to find matching entries on the slow path.
704 711 if follow:
705 712 raise error.Abort(
706 713 _(b'cannot follow nonexistent file: "%s"') % f
707 714 )
708 715 slowpath = True
709 716
710 717 # We decided to fall back to the slowpath because at least one
711 718 # of the paths was not a file. Check to see if at least one of them
712 719 # existed in history - in that case, we'll continue down the
713 720 # slowpath; otherwise, we can turn off the slowpath
714 721 if slowpath:
715 722 for path in match.files():
716 723 if path == b'.' or path in repo.store:
717 724 break
718 725 else:
719 726 slowpath = False
720 727
721 728 return match, pats, slowpath
722 729
723 730
724 731 def _fileancestors(repo, revs, match, followfirst):
725 732 fctxs = []
726 733 for r in revs:
727 734 ctx = repo[r]
728 735 fctxs.extend(ctx[f].introfilectx() for f in ctx.walk(match))
729 736
730 737 # When displaying a revision with --patch --follow FILE, we have
731 738 # to know which file of the revision must be diffed. With
732 739 # --follow, we want the names of the ancestors of FILE in the
733 740 # revision, stored in "fcache". "fcache" is populated as a side effect
734 741 # of the graph traversal.
735 742 fcache = {}
736 743
737 744 def filematcher(ctx):
738 745 return scmutil.matchfiles(repo, fcache.get(ctx.rev(), []))
739 746
740 747 def revgen():
741 748 for rev, cs in dagop.filectxancestors(fctxs, followfirst=followfirst):
742 749 fcache[rev] = [c.path() for c in cs]
743 750 yield rev
744 751
745 752 return smartset.generatorset(revgen(), iterasc=False), filematcher
746 753
747 754
748 755 def _makenofollowfilematcher(repo, pats, opts):
749 756 '''hook for extensions to override the filematcher for non-follow cases'''
750 757 return None
751 758
752 759
753 760 _opt2logrevset = {
754 761 b'no_merges': (b'not merge()', None),
755 762 b'only_merges': (b'merge()', None),
756 763 b'_matchfiles': (None, b'_matchfiles(%ps)'),
757 764 b'date': (b'date(%s)', None),
758 765 b'branch': (b'branch(%s)', b'%lr'),
759 766 b'_patslog': (b'filelog(%s)', b'%lr'),
760 767 b'keyword': (b'keyword(%s)', b'%lr'),
761 768 b'prune': (b'ancestors(%s)', b'not %lr'),
762 769 b'user': (b'user(%s)', b'%lr'),
763 770 }
764 771
765 772
766 773 def _makerevset(repo, match, pats, slowpath, opts):
767 774 """Return a revset string built from log options and file patterns"""
768 775 opts = dict(opts)
769 776 # follow or not follow?
770 777 follow = opts.get(b'follow') or opts.get(b'follow_first')
771 778
772 779 # branch and only_branch are really aliases and must be handled at
773 780 # the same time
774 781 opts[b'branch'] = opts.get(b'branch', []) + opts.get(b'only_branch', [])
775 782 opts[b'branch'] = [repo.lookupbranch(b) for b in opts[b'branch']]
776 783
777 784 if slowpath:
778 785 # See walkchangerevs() slow path.
779 786 #
780 787 # pats/include/exclude cannot be represented as separate
781 788 # revset expressions as their filtering logic applies at file
782 789 # level. For instance "-I a -X b" matches a revision touching
783 790 # "a" and "b" while "file(a) and not file(b)" does
784 791 # not. Besides, filesets are evaluated against the working
785 792 # directory.
786 793 matchargs = [b'r:', b'd:relpath']
787 794 for p in pats:
788 795 matchargs.append(b'p:' + p)
789 796 for p in opts.get(b'include', []):
790 797 matchargs.append(b'i:' + p)
791 798 for p in opts.get(b'exclude', []):
792 799 matchargs.append(b'x:' + p)
793 800 opts[b'_matchfiles'] = matchargs
794 801 elif not follow:
795 802 opts[b'_patslog'] = list(pats)
796 803
797 804 expr = []
798 805 for op, val in sorted(opts.iteritems()):
799 806 if not val:
800 807 continue
801 808 if op not in _opt2logrevset:
802 809 continue
803 810 revop, listop = _opt2logrevset[op]
804 811 if revop and b'%' not in revop:
805 812 expr.append(revop)
806 813 elif not listop:
807 814 expr.append(revsetlang.formatspec(revop, val))
808 815 else:
809 816 if revop:
810 817 val = [revsetlang.formatspec(revop, v) for v in val]
811 818 expr.append(revsetlang.formatspec(listop, val))
812 819
813 820 if expr:
814 821 expr = b'(' + b' and '.join(expr) + b')'
815 822 else:
816 823 expr = None
817 824 return expr
818 825
819 826
820 827 def _initialrevs(repo, opts):
821 828 """Return the initial set of revisions to be filtered or followed"""
822 829 follow = opts.get(b'follow') or opts.get(b'follow_first')
823 830 if opts.get(b'rev'):
824 831 revs = scmutil.revrange(repo, opts[b'rev'])
825 832 elif follow and repo.dirstate.p1() == nullid:
826 833 revs = smartset.baseset()
827 834 elif follow:
828 835 revs = repo.revs(b'.')
829 836 else:
830 837 revs = smartset.spanset(repo)
831 838 revs.reverse()
832 839 return revs
833 840
834 841
835 842 def getrevs(repo, pats, opts):
836 843 """Return (revs, differ) where revs is a smartset
837 844
838 845 differ is a changesetdiffer with pre-configured file matcher.
839 846 """
840 847 follow = opts.get(b'follow') or opts.get(b'follow_first')
841 848 followfirst = opts.get(b'follow_first')
842 849 limit = getlimit(opts)
843 850 revs = _initialrevs(repo, opts)
844 851 if not revs:
845 852 return smartset.baseset(), None
846 853 match, pats, slowpath = _makematcher(repo, revs, pats, opts)
847 854 filematcher = None
848 855 if follow:
849 856 if slowpath or match.always():
850 857 revs = dagop.revancestors(repo, revs, followfirst=followfirst)
851 858 else:
852 859 revs, filematcher = _fileancestors(repo, revs, match, followfirst)
853 860 revs.reverse()
854 861 if filematcher is None:
855 862 filematcher = _makenofollowfilematcher(repo, pats, opts)
856 863 if filematcher is None:
857 864
858 865 def filematcher(ctx):
859 866 return match
860 867
861 868 expr = _makerevset(repo, match, pats, slowpath, opts)
862 869 if opts.get(b'graph'):
863 870 # User-specified revs might be unsorted, but don't sort before
864 871 # _makerevset because it might depend on the order of revs
865 872 if repo.ui.configbool(b'experimental', b'log.topo'):
866 873 if not revs.istopo():
867 874 revs = dagop.toposort(revs, repo.changelog.parentrevs)
868 875 # TODO: try to iterate the set lazily
869 876 revs = revset.baseset(list(revs), istopo=True)
870 877 elif not (revs.isdescending() or revs.istopo()):
871 878 revs.sort(reverse=True)
872 879 if expr:
873 880 matcher = revset.match(None, expr)
874 881 revs = matcher(repo, revs)
875 882 if limit is not None:
876 883 revs = revs.slice(0, limit)
877 884
878 885 differ = changesetdiffer()
879 886 differ._makefilematcher = filematcher
880 887 return revs, differ
881 888
882 889
883 890 def _parselinerangeopt(repo, opts):
884 891 """Parse --line-range log option and return a list of tuples (filename,
885 892 (fromline, toline)).
886 893 """
887 894 linerangebyfname = []
888 895 for pat in opts.get(b'line_range', []):
889 896 try:
890 897 pat, linerange = pat.rsplit(b',', 1)
891 898 except ValueError:
892 899 raise error.Abort(_(b'malformatted line-range pattern %s') % pat)
893 900 try:
894 901 fromline, toline = map(int, linerange.split(b':'))
895 902 except ValueError:
896 903 raise error.Abort(_(b"invalid line range for %s") % pat)
897 904 msg = _(b"line range pattern '%s' must match exactly one file") % pat
898 905 fname = scmutil.parsefollowlinespattern(repo, None, pat, msg)
899 906 linerangebyfname.append(
900 907 (fname, util.processlinerange(fromline, toline))
901 908 )
902 909 return linerangebyfname
903 910
904 911
905 912 def getlinerangerevs(repo, userrevs, opts):
906 913 """Return (revs, differ).
907 914
908 915 "revs" are revisions obtained by processing "line-range" log options and
909 916 walking block ancestors of each specified file/line-range.
910 917
911 918 "differ" is a changesetdiffer with pre-configured file matcher and hunks
912 919 filter.
913 920 """
914 921 wctx = repo[None]
915 922
916 923 # Two-levels map of "rev -> file ctx -> [line range]".
917 924 linerangesbyrev = {}
918 925 for fname, (fromline, toline) in _parselinerangeopt(repo, opts):
919 926 if fname not in wctx:
920 927 raise error.Abort(
921 928 _(b'cannot follow file not in parent ' b'revision: "%s"')
922 929 % fname
923 930 )
924 931 fctx = wctx.filectx(fname)
925 932 for fctx, linerange in dagop.blockancestors(fctx, fromline, toline):
926 933 rev = fctx.introrev()
927 934 if rev not in userrevs:
928 935 continue
929 936 linerangesbyrev.setdefault(rev, {}).setdefault(
930 937 fctx.path(), []
931 938 ).append(linerange)
932 939
933 940 def nofilterhunksfn(fctx, hunks):
934 941 return hunks
935 942
936 943 def hunksfilter(ctx):
937 944 fctxlineranges = linerangesbyrev.get(ctx.rev())
938 945 if fctxlineranges is None:
939 946 return nofilterhunksfn
940 947
941 948 def filterfn(fctx, hunks):
942 949 lineranges = fctxlineranges.get(fctx.path())
943 950 if lineranges is not None:
944 951 for hr, lines in hunks:
945 952 if hr is None: # binary
946 953 yield hr, lines
947 954 continue
948 955 if any(mdiff.hunkinrange(hr[2:], lr) for lr in lineranges):
949 956 yield hr, lines
950 957 else:
951 958 for hunk in hunks:
952 959 yield hunk
953 960
954 961 return filterfn
955 962
956 963 def filematcher(ctx):
957 964 files = list(linerangesbyrev.get(ctx.rev(), []))
958 965 return scmutil.matchfiles(repo, files)
959 966
960 967 revs = sorted(linerangesbyrev, reverse=True)
961 968
962 969 differ = changesetdiffer()
963 970 differ._makefilematcher = filematcher
964 971 differ._makehunksfilter = hunksfilter
965 972 return revs, differ
966 973
967 974
968 975 def _graphnodeformatter(ui, displayer):
969 976 spec = ui.config(b'ui', b'graphnodetemplate')
970 977 if not spec:
971 978 return templatekw.getgraphnode # fast path for "{graphnode}"
972 979
973 980 spec = templater.unquotestring(spec)
974 981 if isinstance(displayer, changesettemplater):
975 982 # reuse cache of slow templates
976 983 tres = displayer._tresources
977 984 else:
978 985 tres = formatter.templateresources(ui)
979 986 templ = formatter.maketemplater(
980 987 ui, spec, defaults=templatekw.keywords, resources=tres
981 988 )
982 989
983 990 def formatnode(repo, ctx):
984 991 props = {b'ctx': ctx, b'repo': repo}
985 992 return templ.renderdefault(props)
986 993
987 994 return formatnode
988 995
989 996
990 997 def displaygraph(ui, repo, dag, displayer, edgefn, getcopies=None, props=None):
991 998 props = props or {}
992 999 formatnode = _graphnodeformatter(ui, displayer)
993 1000 state = graphmod.asciistate()
994 1001 styles = state[b'styles']
995 1002
996 1003 # only set graph styling if HGPLAIN is not set.
997 1004 if ui.plain(b'graph'):
998 1005 # set all edge styles to |, the default pre-3.8 behaviour
999 1006 styles.update(dict.fromkeys(styles, b'|'))
1000 1007 else:
1001 1008 edgetypes = {
1002 1009 b'parent': graphmod.PARENT,
1003 1010 b'grandparent': graphmod.GRANDPARENT,
1004 1011 b'missing': graphmod.MISSINGPARENT,
1005 1012 }
1006 1013 for name, key in edgetypes.items():
1007 1014 # experimental config: experimental.graphstyle.*
1008 1015 styles[key] = ui.config(
1009 1016 b'experimental', b'graphstyle.%s' % name, styles[key]
1010 1017 )
1011 1018 if not styles[key]:
1012 1019 styles[key] = None
1013 1020
1014 1021 # experimental config: experimental.graphshorten
1015 1022 state[b'graphshorten'] = ui.configbool(b'experimental', b'graphshorten')
1016 1023
1017 1024 for rev, type, ctx, parents in dag:
1018 1025 char = formatnode(repo, ctx)
1019 1026 copies = getcopies(ctx) if getcopies else None
1020 1027 edges = edgefn(type, char, state, rev, parents)
1021 1028 firstedge = next(edges)
1022 1029 width = firstedge[2]
1023 1030 displayer.show(
1024 1031 ctx, copies=copies, graphwidth=width, **pycompat.strkwargs(props)
1025 1032 )
1026 1033 lines = displayer.hunk.pop(rev).split(b'\n')
1027 1034 if not lines[-1]:
1028 1035 del lines[-1]
1029 1036 displayer.flush(ctx)
1030 1037 for type, char, width, coldata in itertools.chain([firstedge], edges):
1031 1038 graphmod.ascii(ui, state, type, char, lines, coldata)
1032 1039 lines = []
1033 1040 displayer.close()
1034 1041
1035 1042
1036 1043 def displaygraphrevs(ui, repo, revs, displayer, getrenamed):
1037 1044 revdag = graphmod.dagwalker(repo, revs)
1038 1045 displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges, getrenamed)
1039 1046
1040 1047
1041 1048 def displayrevs(ui, repo, revs, displayer, getcopies):
1042 1049 for rev in revs:
1043 1050 ctx = repo[rev]
1044 1051 copies = getcopies(ctx) if getcopies else None
1045 1052 displayer.show(ctx, copies=copies)
1046 1053 displayer.flush(ctx)
1047 1054 displayer.close()
1048 1055
1049 1056
1050 1057 def checkunsupportedgraphflags(pats, opts):
1051 1058 for op in [b"newest_first"]:
1052 1059 if op in opts and opts[op]:
1053 1060 raise error.Abort(
1054 1061 _(b"-G/--graph option is incompatible with --%s")
1055 1062 % op.replace(b"_", b"-")
1056 1063 )
1057 1064
1058 1065
1059 1066 def graphrevs(repo, nodes, opts):
1060 1067 limit = getlimit(opts)
1061 1068 nodes.reverse()
1062 1069 if limit is not None:
1063 1070 nodes = nodes[:limit]
1064 1071 return graphmod.nodes(repo, nodes)
@@ -1,1878 +1,1932 b''
1 1 Test template map files and styles
2 2 ==================================
3 3
4 4 $ hg init a
5 5 $ cd a
6 6 $ echo a > a
7 7 $ hg add a
8 8 $ echo line 1 > b
9 9 $ echo line 2 >> b
10 10 $ hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
11 11
12 12 $ hg add b
13 13 $ echo other 1 > c
14 14 $ echo other 2 >> c
15 15 $ echo >> c
16 16 $ echo other 3 >> c
17 17 $ hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
18 18
19 19 $ hg add c
20 20 $ hg commit -m 'no person' -d '1200000 0' -u 'other@place'
21 21 $ echo c >> c
22 22 $ hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
23 23
24 24 $ echo foo > .hg/branch
25 25 $ hg commit -m 'new branch' -d '1400000 0' -u 'person'
26 26
27 27 $ hg co -q 3
28 28 $ echo other 4 >> d
29 29 $ hg add d
30 30 $ hg commit -m 'new head' -d '1500000 0' -u 'person'
31 31
32 32 $ hg merge -q foo
33 33 $ hg commit -m 'merge' -d '1500001 0' -u 'person'
34 34
35 35 Second branch starting at nullrev:
36 36
37 37 $ hg update null
38 38 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
39 39 $ echo second > second
40 40 $ hg add second
41 41 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
42 42 created new head
43 43
44 44 $ echo third > third
45 45 $ hg add third
46 46 $ hg mv second fourth
47 47 $ hg commit -m third -d "2020-01-01 10:01"
48 48
49 49 Make sure user/global hgrc does not affect tests
50 50
51 51 $ echo '[ui]' > .hg/hgrc
52 52 $ echo 'logtemplate =' >> .hg/hgrc
53 53 $ echo 'style =' >> .hg/hgrc
54 54
55 55 Add some simple styles to settings
56 56
57 57 $ cat <<'EOF' >> .hg/hgrc
58 58 > [templates]
59 59 > simple = "{rev}\n"
60 60 > simple2 = {rev}\n
61 61 > rev = "should not precede {rev} keyword\n"
62 62 > EOF
63 63
64 64 $ hg log -l1 -Tsimple
65 65 8
66 66 $ hg log -l1 -Tsimple2
67 67 8
68 68 $ hg log -l1 -Trev
69 69 should not precede 8 keyword
70 70 $ hg log -l1 -T '{simple}'
71 71 8
72 72
73 73 Map file shouldn't see user templates:
74 74
75 75 $ cat <<EOF > tmpl
76 76 > changeset = 'nothing expanded:{simple}\n'
77 77 > EOF
78 78 $ hg log -l1 --style ./tmpl
79 79 nothing expanded:
80 80
81 81 Test templates and style maps in files:
82 82
83 83 $ echo "{rev}" > tmpl
84 84 $ hg log -l1 -T./tmpl
85 85 8
86 86 $ hg log -l1 -Tblah/blah
87 87 blah/blah (no-eol)
88 88
89 89 $ printf 'changeset = "{rev}\\n"\n' > map-simple
90 90 $ hg log -l1 -T./map-simple
91 91 8
92 92
93 93 a map file may have [templates] and [templatealias] sections:
94 94
95 95 $ cat <<'EOF' > map-simple
96 96 > [templates]
97 97 > changeset = "{a}\n"
98 98 > [templatealias]
99 99 > a = rev
100 100 > EOF
101 101 $ hg log -l1 -T./map-simple
102 102 8
103 103
104 104 so it can be included in hgrc
105 105
106 106 $ cat <<EOF > myhgrc
107 107 > %include $HGRCPATH
108 108 > %include map-simple
109 109 > [templates]
110 110 > foo = "{changeset}"
111 111 > EOF
112 112 $ HGRCPATH=./myhgrc hg log -l1 -Tfoo
113 113 8
114 114 $ HGRCPATH=./myhgrc hg log -l1 -T'{a}\n'
115 115 8
116 116
117 117 Test template map inheritance
118 118
119 119 $ echo "__base__ = map-cmdline.default" > map-simple
120 120 $ printf 'cset = "changeset: ***{rev}***\\n"\n' >> map-simple
121 121 $ hg log -l1 -T./map-simple
122 122 changeset: ***8***
123 123 tag: tip
124 124 user: test
125 125 date: Wed Jan 01 10:01:00 2020 +0000
126 126 summary: third
127 127
128 128
129 129 Test docheader, docfooter and separator in template map
130 130
131 131 $ cat <<'EOF' > map-myjson
132 132 > docheader = '\{\n'
133 133 > docfooter = '\n}\n'
134 134 > separator = ',\n'
135 135 > changeset = ' {dict(rev, node|short)|json}'
136 136 > EOF
137 137 $ hg log -l2 -T./map-myjson
138 138 {
139 139 {"node": "95c24699272e", "rev": 8},
140 140 {"node": "29114dbae42b", "rev": 7}
141 141 }
142 142
143 143 Test docheader, docfooter and separator in [templates] section
144 144
145 145 $ cat <<'EOF' >> .hg/hgrc
146 146 > [templates]
147 147 > myjson = ' {dict(rev, node|short)|json}'
148 148 > myjson:docheader = '\{\n'
149 149 > myjson:docfooter = '\n}\n'
150 150 > myjson:separator = ',\n'
151 151 > :docheader = 'should not be selected as a docheader for literal templates\n'
152 152 > EOF
153 153 $ hg log -l2 -Tmyjson
154 154 {
155 155 {"node": "95c24699272e", "rev": 8},
156 156 {"node": "29114dbae42b", "rev": 7}
157 157 }
158 158 $ hg log -l1 -T'{rev}\n'
159 159 8
160 160
161 161 Template should precede style option
162 162
163 163 $ hg log -l1 --style default -T '{rev}\n'
164 164 8
165 165
166 166 Add a commit with empty description, to ensure that the templates
167 167 below will omit the description line.
168 168
169 169 $ echo c >> c
170 170 $ hg add c
171 171 $ hg commit -qm ' '
172 172
173 173 Default style is like normal output. Phases style should be the same
174 174 as default style, except for extra phase lines.
175 175
176 176 $ hg log > log.out
177 177 $ hg log --style default > style.out
178 178 $ cmp log.out style.out || diff -u log.out style.out
179 179 $ hg log -T phases > phases.out
180 180 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
181 181 +phase: draft
182 182 +phase: draft
183 183 +phase: draft
184 184 +phase: draft
185 185 +phase: draft
186 186 +phase: draft
187 187 +phase: draft
188 188 +phase: draft
189 189 +phase: draft
190 190 +phase: draft
191 191
192 192 $ hg log -v > log.out
193 193 $ hg log -v --style default > style.out
194 194 $ cmp log.out style.out || diff -u log.out style.out
195 195 $ hg log -v -T phases > phases.out
196 196 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
197 197 +phase: draft
198 198 +phase: draft
199 199 +phase: draft
200 200 +phase: draft
201 201 +phase: draft
202 202 +phase: draft
203 203 +phase: draft
204 204 +phase: draft
205 205 +phase: draft
206 206 +phase: draft
207 207
208 208 $ hg log -q > log.out
209 209 $ hg log -q --style default > style.out
210 210 $ cmp log.out style.out || diff -u log.out style.out
211 211 $ hg log -q -T phases > phases.out
212 212 $ cmp log.out phases.out || diff -u log.out phases.out
213 213
214 214 $ hg log --debug > log.out
215 215 $ hg log --debug --style default > style.out
216 216 $ cmp log.out style.out || diff -u log.out style.out
217 217 $ hg log --debug -T phases > phases.out
218 218 $ cmp log.out phases.out || diff -u log.out phases.out
219 219
220 220 Default style of working-directory revision should also be the same (but
221 221 date may change while running tests):
222 222
223 223 $ hg log -r 'wdir()' | sed 's|^date:.*|date:|' > log.out
224 224 $ hg log -r 'wdir()' --style default | sed 's|^date:.*|date:|' > style.out
225 225 $ cmp log.out style.out || diff -u log.out style.out
226 226
227 227 $ hg log -r 'wdir()' -v | sed 's|^date:.*|date:|' > log.out
228 228 $ hg log -r 'wdir()' -v --style default | sed 's|^date:.*|date:|' > style.out
229 229 $ cmp log.out style.out || diff -u log.out style.out
230 230
231 231 $ hg log -r 'wdir()' -q > log.out
232 232 $ hg log -r 'wdir()' -q --style default > style.out
233 233 $ cmp log.out style.out || diff -u log.out style.out
234 234
235 235 $ hg log -r 'wdir()' --debug | sed 's|^date:.*|date:|' > log.out
236 236 $ hg log -r 'wdir()' --debug --style default \
237 237 > | sed 's|^date:.*|date:|' > style.out
238 238 $ cmp log.out style.out || diff -u log.out style.out
239 239
240 240 Default style should also preserve color information (issue2866):
241 241
242 242 $ cp $HGRCPATH $HGRCPATH-bak
243 243 $ cat <<EOF >> $HGRCPATH
244 244 > [extensions]
245 245 > color=
246 246 > EOF
247 247
248 248 $ hg --color=debug log > log.out
249 249 $ hg --color=debug log --style default > style.out
250 250 $ cmp log.out style.out || diff -u log.out style.out
251 251 $ hg --color=debug log -T phases > phases.out
252 252 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
253 253 +[log.phase|phase: draft]
254 254 +[log.phase|phase: draft]
255 255 +[log.phase|phase: draft]
256 256 +[log.phase|phase: draft]
257 257 +[log.phase|phase: draft]
258 258 +[log.phase|phase: draft]
259 259 +[log.phase|phase: draft]
260 260 +[log.phase|phase: draft]
261 261 +[log.phase|phase: draft]
262 262 +[log.phase|phase: draft]
263 263
264 264 $ hg --color=debug -v log > log.out
265 265 $ hg --color=debug -v log --style default > style.out
266 266 $ cmp log.out style.out || diff -u log.out style.out
267 267 $ hg --color=debug -v log -T phases > phases.out
268 268 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
269 269 +[log.phase|phase: draft]
270 270 +[log.phase|phase: draft]
271 271 +[log.phase|phase: draft]
272 272 +[log.phase|phase: draft]
273 273 +[log.phase|phase: draft]
274 274 +[log.phase|phase: draft]
275 275 +[log.phase|phase: draft]
276 276 +[log.phase|phase: draft]
277 277 +[log.phase|phase: draft]
278 278 +[log.phase|phase: draft]
279 279
280 280 $ hg --color=debug -q log > log.out
281 281 $ hg --color=debug -q log --style default > style.out
282 282 $ cmp log.out style.out || diff -u log.out style.out
283 283 $ hg --color=debug -q log -T phases > phases.out
284 284 $ cmp log.out phases.out || diff -u log.out phases.out
285 285
286 286 $ hg --color=debug --debug log > log.out
287 287 $ hg --color=debug --debug log --style default > style.out
288 288 $ cmp log.out style.out || diff -u log.out style.out
289 289 $ hg --color=debug --debug log -T phases > phases.out
290 290 $ cmp log.out phases.out || diff -u log.out phases.out
291 291
292 292 $ mv $HGRCPATH-bak $HGRCPATH
293 293
294 294 Remove commit with empty commit message, so as to not pollute further
295 295 tests.
296 296
297 297 $ hg --config extensions.strip= strip -q .
298 298
299 299 Revision with no copies (used to print a traceback):
300 300
301 301 $ hg tip -v --template '\n'
302 302
303 303
304 304 Compact style works:
305 305
306 306 $ hg log -Tcompact
307 307 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
308 308 third
309 309
310 310 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
311 311 second
312 312
313 313 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
314 314 merge
315 315
316 316 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
317 317 new head
318 318
319 319 4 bbe44766e73d 1970-01-17 04:53 +0000 person
320 320 new branch
321 321
322 322 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
323 323 no user, no domain
324 324
325 325 2 97054abb4ab8 1970-01-14 21:20 +0000 other
326 326 no person
327 327
328 328 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
329 329 other 1
330 330
331 331 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
332 332 line 1
333 333
334 334
335 335 $ hg log -v --style compact
336 336 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
337 337 third
338 338
339 339 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
340 340 second
341 341
342 342 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
343 343 merge
344 344
345 345 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
346 346 new head
347 347
348 348 4 bbe44766e73d 1970-01-17 04:53 +0000 person
349 349 new branch
350 350
351 351 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
352 352 no user, no domain
353 353
354 354 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
355 355 no person
356 356
357 357 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
358 358 other 1
359 359 other 2
360 360
361 361 other 3
362 362
363 363 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
364 364 line 1
365 365 line 2
366 366
367 367
368 368 $ hg log --debug --style compact
369 369 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
370 370 third
371 371
372 372 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
373 373 second
374 374
375 375 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
376 376 merge
377 377
378 378 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
379 379 new head
380 380
381 381 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
382 382 new branch
383 383
384 384 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
385 385 no user, no domain
386 386
387 387 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
388 388 no person
389 389
390 390 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
391 391 other 1
392 392 other 2
393 393
394 394 other 3
395 395
396 396 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
397 397 line 1
398 398 line 2
399 399
400 400
401 401 Test xml styles:
402 402
403 403 $ hg log --style xml -r 'not all()'
404 404 <?xml version="1.0"?>
405 405 <log>
406 406 </log>
407 407
408 408 $ hg log --style xml
409 409 <?xml version="1.0"?>
410 410 <log>
411 411 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
412 412 <tag>tip</tag>
413 413 <author email="test">test</author>
414 414 <date>2020-01-01T10:01:00+00:00</date>
415 415 <msg xml:space="preserve">third</msg>
416 416 </logentry>
417 417 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
418 418 <parent revision="-1" node="0000000000000000000000000000000000000000" />
419 419 <author email="user@hostname">User Name</author>
420 420 <date>1970-01-12T13:46:40+00:00</date>
421 421 <msg xml:space="preserve">second</msg>
422 422 </logentry>
423 423 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
424 424 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
425 425 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
426 426 <author email="person">person</author>
427 427 <date>1970-01-18T08:40:01+00:00</date>
428 428 <msg xml:space="preserve">merge</msg>
429 429 </logentry>
430 430 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
431 431 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
432 432 <author email="person">person</author>
433 433 <date>1970-01-18T08:40:00+00:00</date>
434 434 <msg xml:space="preserve">new head</msg>
435 435 </logentry>
436 436 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
437 437 <branch>foo</branch>
438 438 <author email="person">person</author>
439 439 <date>1970-01-17T04:53:20+00:00</date>
440 440 <msg xml:space="preserve">new branch</msg>
441 441 </logentry>
442 442 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
443 443 <author email="person">person</author>
444 444 <date>1970-01-16T01:06:40+00:00</date>
445 445 <msg xml:space="preserve">no user, no domain</msg>
446 446 </logentry>
447 447 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
448 448 <author email="other@place">other</author>
449 449 <date>1970-01-14T21:20:00+00:00</date>
450 450 <msg xml:space="preserve">no person</msg>
451 451 </logentry>
452 452 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
453 453 <author email="other@place">A. N. Other</author>
454 454 <date>1970-01-13T17:33:20+00:00</date>
455 455 <msg xml:space="preserve">other 1
456 456 other 2
457 457
458 458 other 3</msg>
459 459 </logentry>
460 460 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
461 461 <author email="user@hostname">User Name</author>
462 462 <date>1970-01-12T13:46:40+00:00</date>
463 463 <msg xml:space="preserve">line 1
464 464 line 2</msg>
465 465 </logentry>
466 466 </log>
467 467
468 468 $ hg log -v --style xml
469 469 <?xml version="1.0"?>
470 470 <log>
471 471 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
472 472 <tag>tip</tag>
473 473 <author email="test">test</author>
474 474 <date>2020-01-01T10:01:00+00:00</date>
475 475 <msg xml:space="preserve">third</msg>
476 476 <paths>
477 477 <path action="A">fourth</path>
478 478 <path action="A">third</path>
479 479 <path action="R">second</path>
480 480 </paths>
481 481 <copies>
482 482 <copy source="second">fourth</copy>
483 483 </copies>
484 484 </logentry>
485 485 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
486 486 <parent revision="-1" node="0000000000000000000000000000000000000000" />
487 487 <author email="user@hostname">User Name</author>
488 488 <date>1970-01-12T13:46:40+00:00</date>
489 489 <msg xml:space="preserve">second</msg>
490 490 <paths>
491 491 <path action="A">second</path>
492 492 </paths>
493 493 </logentry>
494 494 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
495 495 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
496 496 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
497 497 <author email="person">person</author>
498 498 <date>1970-01-18T08:40:01+00:00</date>
499 499 <msg xml:space="preserve">merge</msg>
500 500 <paths>
501 501 </paths>
502 502 </logentry>
503 503 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
504 504 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
505 505 <author email="person">person</author>
506 506 <date>1970-01-18T08:40:00+00:00</date>
507 507 <msg xml:space="preserve">new head</msg>
508 508 <paths>
509 509 <path action="A">d</path>
510 510 </paths>
511 511 </logentry>
512 512 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
513 513 <branch>foo</branch>
514 514 <author email="person">person</author>
515 515 <date>1970-01-17T04:53:20+00:00</date>
516 516 <msg xml:space="preserve">new branch</msg>
517 517 <paths>
518 518 </paths>
519 519 </logentry>
520 520 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
521 521 <author email="person">person</author>
522 522 <date>1970-01-16T01:06:40+00:00</date>
523 523 <msg xml:space="preserve">no user, no domain</msg>
524 524 <paths>
525 525 <path action="M">c</path>
526 526 </paths>
527 527 </logentry>
528 528 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
529 529 <author email="other@place">other</author>
530 530 <date>1970-01-14T21:20:00+00:00</date>
531 531 <msg xml:space="preserve">no person</msg>
532 532 <paths>
533 533 <path action="A">c</path>
534 534 </paths>
535 535 </logentry>
536 536 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
537 537 <author email="other@place">A. N. Other</author>
538 538 <date>1970-01-13T17:33:20+00:00</date>
539 539 <msg xml:space="preserve">other 1
540 540 other 2
541 541
542 542 other 3</msg>
543 543 <paths>
544 544 <path action="A">b</path>
545 545 </paths>
546 546 </logentry>
547 547 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
548 548 <author email="user@hostname">User Name</author>
549 549 <date>1970-01-12T13:46:40+00:00</date>
550 550 <msg xml:space="preserve">line 1
551 551 line 2</msg>
552 552 <paths>
553 553 <path action="A">a</path>
554 554 </paths>
555 555 </logentry>
556 556 </log>
557 557
558 558 $ hg log --debug --style xml
559 559 <?xml version="1.0"?>
560 560 <log>
561 561 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
562 562 <tag>tip</tag>
563 563 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
564 564 <parent revision="-1" node="0000000000000000000000000000000000000000" />
565 565 <author email="test">test</author>
566 566 <date>2020-01-01T10:01:00+00:00</date>
567 567 <msg xml:space="preserve">third</msg>
568 568 <paths>
569 569 <path action="A">fourth</path>
570 570 <path action="A">third</path>
571 571 <path action="R">second</path>
572 572 </paths>
573 573 <copies>
574 574 <copy source="second">fourth</copy>
575 575 </copies>
576 576 <extra key="branch">default</extra>
577 577 </logentry>
578 578 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
579 579 <parent revision="-1" node="0000000000000000000000000000000000000000" />
580 580 <parent revision="-1" node="0000000000000000000000000000000000000000" />
581 581 <author email="user@hostname">User Name</author>
582 582 <date>1970-01-12T13:46:40+00:00</date>
583 583 <msg xml:space="preserve">second</msg>
584 584 <paths>
585 585 <path action="A">second</path>
586 586 </paths>
587 587 <extra key="branch">default</extra>
588 588 </logentry>
589 589 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
590 590 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
591 591 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
592 592 <author email="person">person</author>
593 593 <date>1970-01-18T08:40:01+00:00</date>
594 594 <msg xml:space="preserve">merge</msg>
595 595 <paths>
596 596 </paths>
597 597 <extra key="branch">default</extra>
598 598 </logentry>
599 599 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
600 600 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
601 601 <parent revision="-1" node="0000000000000000000000000000000000000000" />
602 602 <author email="person">person</author>
603 603 <date>1970-01-18T08:40:00+00:00</date>
604 604 <msg xml:space="preserve">new head</msg>
605 605 <paths>
606 606 <path action="A">d</path>
607 607 </paths>
608 608 <extra key="branch">default</extra>
609 609 </logentry>
610 610 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
611 611 <branch>foo</branch>
612 612 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
613 613 <parent revision="-1" node="0000000000000000000000000000000000000000" />
614 614 <author email="person">person</author>
615 615 <date>1970-01-17T04:53:20+00:00</date>
616 616 <msg xml:space="preserve">new branch</msg>
617 617 <paths>
618 618 </paths>
619 619 <extra key="branch">foo</extra>
620 620 </logentry>
621 621 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
622 622 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
623 623 <parent revision="-1" node="0000000000000000000000000000000000000000" />
624 624 <author email="person">person</author>
625 625 <date>1970-01-16T01:06:40+00:00</date>
626 626 <msg xml:space="preserve">no user, no domain</msg>
627 627 <paths>
628 628 <path action="M">c</path>
629 629 </paths>
630 630 <extra key="branch">default</extra>
631 631 </logentry>
632 632 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
633 633 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
634 634 <parent revision="-1" node="0000000000000000000000000000000000000000" />
635 635 <author email="other@place">other</author>
636 636 <date>1970-01-14T21:20:00+00:00</date>
637 637 <msg xml:space="preserve">no person</msg>
638 638 <paths>
639 639 <path action="A">c</path>
640 640 </paths>
641 641 <extra key="branch">default</extra>
642 642 </logentry>
643 643 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
644 644 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
645 645 <parent revision="-1" node="0000000000000000000000000000000000000000" />
646 646 <author email="other@place">A. N. Other</author>
647 647 <date>1970-01-13T17:33:20+00:00</date>
648 648 <msg xml:space="preserve">other 1
649 649 other 2
650 650
651 651 other 3</msg>
652 652 <paths>
653 653 <path action="A">b</path>
654 654 </paths>
655 655 <extra key="branch">default</extra>
656 656 </logentry>
657 657 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
658 658 <parent revision="-1" node="0000000000000000000000000000000000000000" />
659 659 <parent revision="-1" node="0000000000000000000000000000000000000000" />
660 660 <author email="user@hostname">User Name</author>
661 661 <date>1970-01-12T13:46:40+00:00</date>
662 662 <msg xml:space="preserve">line 1
663 663 line 2</msg>
664 664 <paths>
665 665 <path action="A">a</path>
666 666 </paths>
667 667 <extra key="branch">default</extra>
668 668 </logentry>
669 669 </log>
670 670
671 671
672 672 test CBOR style:
673 673
674 674 $ cat <<'EOF' > "$TESTTMP/decodecborarray.py"
675 675 > from __future__ import absolute_import
676 676 > from mercurial import (
677 677 > dispatch,
678 678 > pycompat,
679 679 > )
680 680 > from mercurial.utils import (
681 681 > cborutil,
682 682 > stringutil,
683 683 > )
684 684 > dispatch.initstdio()
685 685 > data = pycompat.stdin.read()
686 686 > # our CBOR decoder doesn't support parsing indefinite-length arrays,
687 687 > # but the log output is indefinite stream by nature.
688 688 > assert data[:1] == cborutil.BEGIN_INDEFINITE_ARRAY
689 689 > assert data[-1:] == cborutil.BREAK
690 690 > items = cborutil.decodeall(data[1:-1])
691 691 > pycompat.stdout.write(stringutil.pprint(items, indent=1) + b'\n')
692 692 > EOF
693 693
694 694 $ hg log -k nosuch -Tcbor | "$PYTHON" "$TESTTMP/decodecborarray.py"
695 695 []
696 696
697 697 $ hg log -qr0:1 -Tcbor | "$PYTHON" "$TESTTMP/decodecborarray.py"
698 698 [
699 699 {
700 700 'node': '1e4e1b8f71e05681d422154f5421e385fec3454f',
701 701 'rev': 0
702 702 },
703 703 {
704 704 'node': 'b608e9d1a3f0273ccf70fb85fd6866b3482bf965',
705 705 'rev': 1
706 706 }
707 707 ]
708 708
709 709 $ hg log -vpr . -Tcbor --stat | "$PYTHON" "$TESTTMP/decodecborarray.py"
710 710 [
711 711 {
712 712 'bookmarks': [],
713 713 'branch': 'default',
714 714 'date': [
715 715 1577872860,
716 716 0
717 717 ],
718 718 'desc': 'third',
719 719 'diff': 'diff -r 29114dbae42b -r 95c24699272e fourth\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/fourth\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+second\ndiff -r 29114dbae42b -r 95c24699272e second\n--- a/second\tMon Jan 12 13:46:40 1970 +0000\n+++ /dev/null\tThu Jan 01 00:00:00 1970 +0000\n@@ -1,1 +0,0 @@\n-second\ndiff -r 29114dbae42b -r 95c24699272e third\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/third\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+third\n',
720 720 'diffstat': ' fourth | 1 +\n second | 1 -\n third | 1 +\n 3 files changed, 2 insertions(+), 1 deletions(-)\n',
721 721 'files': [
722 722 'fourth',
723 723 'second',
724 724 'third'
725 725 ],
726 726 'node': '95c24699272ef57d062b8bccc32c878bf841784a',
727 727 'parents': [
728 728 '29114dbae42b9f078cf2714dbe3a86bba8ec7453'
729 729 ],
730 730 'phase': 'draft',
731 731 'rev': 8,
732 732 'tags': [
733 733 'tip'
734 734 ],
735 735 'user': 'test'
736 736 }
737 737 ]
738 738
739 739 $ hg log -r . -T'cbor(rev, node|short)' | "$PYTHON" "$TESTTMP/decodecborarray.py"
740 740 [
741 741 {
742 742 'node': '95c24699272e',
743 743 'rev': 8
744 744 }
745 745 ]
746 746
747 747 $ hg log -r . -T'cbor()' | "$PYTHON" "$TESTTMP/decodecborarray.py"
748 748 [
749 749 {}
750 750 ]
751 751
752 752 Test JSON style:
753 753
754 754 $ hg log -k nosuch -Tjson
755 755 [
756 756 ]
757 757
758 758 $ hg log -qr . -Tjson
759 759 [
760 760 {
761 761 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
762 762 "rev": 8
763 763 }
764 764 ]
765 765
766 766 $ hg log -vpr . -Tjson --stat
767 767 [
768 768 {
769 769 "bookmarks": [],
770 770 "branch": "default",
771 771 "date": [1577872860, 0],
772 772 "desc": "third",
773 773 "diff": "diff -r 29114dbae42b -r 95c24699272e fourth\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/fourth\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+second\ndiff -r 29114dbae42b -r 95c24699272e second\n--- a/second\tMon Jan 12 13:46:40 1970 +0000\n+++ /dev/null\tThu Jan 01 00:00:00 1970 +0000\n@@ -1,1 +0,0 @@\n-second\ndiff -r 29114dbae42b -r 95c24699272e third\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/third\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+third\n",
774 774 "diffstat": " fourth | 1 +\n second | 1 -\n third | 1 +\n 3 files changed, 2 insertions(+), 1 deletions(-)\n",
775 775 "files": ["fourth", "second", "third"],
776 776 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
777 777 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
778 778 "phase": "draft",
779 779 "rev": 8,
780 780 "tags": ["tip"],
781 781 "user": "test"
782 782 }
783 783 ]
784 784
785 785 honor --git but not format-breaking diffopts
786 786 $ hg --config diff.noprefix=True log --git -vpr . -Tjson
787 787 [
788 788 {
789 789 "bookmarks": [],
790 790 "branch": "default",
791 791 "date": [1577872860, 0],
792 792 "desc": "third",
793 793 "diff": "diff --git a/second b/fourth\nrename from second\nrename to fourth\ndiff --git a/third b/third\nnew file mode 100644\n--- /dev/null\n+++ b/third\n@@ -0,0 +1,1 @@\n+third\n",
794 794 "files": ["fourth", "second", "third"],
795 795 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
796 796 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
797 797 "phase": "draft",
798 798 "rev": 8,
799 799 "tags": ["tip"],
800 800 "user": "test"
801 801 }
802 802 ]
803 803
804 804 $ hg log -T json
805 805 [
806 806 {
807 807 "bookmarks": [],
808 808 "branch": "default",
809 809 "date": [1577872860, 0],
810 810 "desc": "third",
811 811 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
812 812 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
813 813 "phase": "draft",
814 814 "rev": 8,
815 815 "tags": ["tip"],
816 816 "user": "test"
817 817 },
818 818 {
819 819 "bookmarks": [],
820 820 "branch": "default",
821 821 "date": [1000000, 0],
822 822 "desc": "second",
823 823 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
824 824 "parents": ["0000000000000000000000000000000000000000"],
825 825 "phase": "draft",
826 826 "rev": 7,
827 827 "tags": [],
828 828 "user": "User Name <user@hostname>"
829 829 },
830 830 {
831 831 "bookmarks": [],
832 832 "branch": "default",
833 833 "date": [1500001, 0],
834 834 "desc": "merge",
835 835 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
836 836 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
837 837 "phase": "draft",
838 838 "rev": 6,
839 839 "tags": [],
840 840 "user": "person"
841 841 },
842 842 {
843 843 "bookmarks": [],
844 844 "branch": "default",
845 845 "date": [1500000, 0],
846 846 "desc": "new head",
847 847 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
848 848 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
849 849 "phase": "draft",
850 850 "rev": 5,
851 851 "tags": [],
852 852 "user": "person"
853 853 },
854 854 {
855 855 "bookmarks": [],
856 856 "branch": "foo",
857 857 "date": [1400000, 0],
858 858 "desc": "new branch",
859 859 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
860 860 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
861 861 "phase": "draft",
862 862 "rev": 4,
863 863 "tags": [],
864 864 "user": "person"
865 865 },
866 866 {
867 867 "bookmarks": [],
868 868 "branch": "default",
869 869 "date": [1300000, 0],
870 870 "desc": "no user, no domain",
871 871 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
872 872 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
873 873 "phase": "draft",
874 874 "rev": 3,
875 875 "tags": [],
876 876 "user": "person"
877 877 },
878 878 {
879 879 "bookmarks": [],
880 880 "branch": "default",
881 881 "date": [1200000, 0],
882 882 "desc": "no person",
883 883 "node": "97054abb4ab824450e9164180baf491ae0078465",
884 884 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
885 885 "phase": "draft",
886 886 "rev": 2,
887 887 "tags": [],
888 888 "user": "other@place"
889 889 },
890 890 {
891 891 "bookmarks": [],
892 892 "branch": "default",
893 893 "date": [1100000, 0],
894 894 "desc": "other 1\nother 2\n\nother 3",
895 895 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
896 896 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
897 897 "phase": "draft",
898 898 "rev": 1,
899 899 "tags": [],
900 900 "user": "A. N. Other <other@place>"
901 901 },
902 902 {
903 903 "bookmarks": [],
904 904 "branch": "default",
905 905 "date": [1000000, 0],
906 906 "desc": "line 1\nline 2",
907 907 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
908 908 "parents": ["0000000000000000000000000000000000000000"],
909 909 "phase": "draft",
910 910 "rev": 0,
911 911 "tags": [],
912 912 "user": "User Name <user@hostname>"
913 913 }
914 914 ]
915 915
916 916 $ hg heads -v -Tjson
917 917 [
918 918 {
919 919 "bookmarks": [],
920 920 "branch": "default",
921 921 "date": [1577872860, 0],
922 922 "desc": "third",
923 923 "files": ["fourth", "second", "third"],
924 924 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
925 925 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
926 926 "phase": "draft",
927 927 "rev": 8,
928 928 "tags": ["tip"],
929 929 "user": "test"
930 930 },
931 931 {
932 932 "bookmarks": [],
933 933 "branch": "default",
934 934 "date": [1500001, 0],
935 935 "desc": "merge",
936 936 "files": [],
937 937 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
938 938 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
939 939 "phase": "draft",
940 940 "rev": 6,
941 941 "tags": [],
942 942 "user": "person"
943 943 },
944 944 {
945 945 "bookmarks": [],
946 946 "branch": "foo",
947 947 "date": [1400000, 0],
948 948 "desc": "new branch",
949 949 "files": [],
950 950 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
951 951 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
952 952 "phase": "draft",
953 953 "rev": 4,
954 954 "tags": [],
955 955 "user": "person"
956 956 }
957 957 ]
958 958
959 959 $ hg log --debug -Tjson
960 960 [
961 961 {
962 962 "added": ["fourth", "third"],
963 963 "bookmarks": [],
964 964 "branch": "default",
965 965 "date": [1577872860, 0],
966 966 "desc": "third",
967 967 "extra": {"branch": "default"},
968 968 "manifest": "94961b75a2da554b4df6fb599e5bfc7d48de0c64",
969 969 "modified": [],
970 970 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
971 971 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
972 972 "phase": "draft",
973 973 "removed": ["second"],
974 974 "rev": 8,
975 975 "tags": ["tip"],
976 976 "user": "test"
977 977 },
978 978 {
979 979 "added": ["second"],
980 980 "bookmarks": [],
981 981 "branch": "default",
982 982 "date": [1000000, 0],
983 983 "desc": "second",
984 984 "extra": {"branch": "default"},
985 985 "manifest": "f2dbc354b94e5ec0b4f10680ee0cee816101d0bf",
986 986 "modified": [],
987 987 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
988 988 "parents": ["0000000000000000000000000000000000000000"],
989 989 "phase": "draft",
990 990 "removed": [],
991 991 "rev": 7,
992 992 "tags": [],
993 993 "user": "User Name <user@hostname>"
994 994 },
995 995 {
996 996 "added": [],
997 997 "bookmarks": [],
998 998 "branch": "default",
999 999 "date": [1500001, 0],
1000 1000 "desc": "merge",
1001 1001 "extra": {"branch": "default"},
1002 1002 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1003 1003 "modified": [],
1004 1004 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
1005 1005 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
1006 1006 "phase": "draft",
1007 1007 "removed": [],
1008 1008 "rev": 6,
1009 1009 "tags": [],
1010 1010 "user": "person"
1011 1011 },
1012 1012 {
1013 1013 "added": ["d"],
1014 1014 "bookmarks": [],
1015 1015 "branch": "default",
1016 1016 "date": [1500000, 0],
1017 1017 "desc": "new head",
1018 1018 "extra": {"branch": "default"},
1019 1019 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1020 1020 "modified": [],
1021 1021 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
1022 1022 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1023 1023 "phase": "draft",
1024 1024 "removed": [],
1025 1025 "rev": 5,
1026 1026 "tags": [],
1027 1027 "user": "person"
1028 1028 },
1029 1029 {
1030 1030 "added": [],
1031 1031 "bookmarks": [],
1032 1032 "branch": "foo",
1033 1033 "date": [1400000, 0],
1034 1034 "desc": "new branch",
1035 1035 "extra": {"branch": "foo"},
1036 1036 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1037 1037 "modified": [],
1038 1038 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
1039 1039 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1040 1040 "phase": "draft",
1041 1041 "removed": [],
1042 1042 "rev": 4,
1043 1043 "tags": [],
1044 1044 "user": "person"
1045 1045 },
1046 1046 {
1047 1047 "added": [],
1048 1048 "bookmarks": [],
1049 1049 "branch": "default",
1050 1050 "date": [1300000, 0],
1051 1051 "desc": "no user, no domain",
1052 1052 "extra": {"branch": "default"},
1053 1053 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1054 1054 "modified": ["c"],
1055 1055 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
1056 1056 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
1057 1057 "phase": "draft",
1058 1058 "removed": [],
1059 1059 "rev": 3,
1060 1060 "tags": [],
1061 1061 "user": "person"
1062 1062 },
1063 1063 {
1064 1064 "added": ["c"],
1065 1065 "bookmarks": [],
1066 1066 "branch": "default",
1067 1067 "date": [1200000, 0],
1068 1068 "desc": "no person",
1069 1069 "extra": {"branch": "default"},
1070 1070 "manifest": "6e0e82995c35d0d57a52aca8da4e56139e06b4b1",
1071 1071 "modified": [],
1072 1072 "node": "97054abb4ab824450e9164180baf491ae0078465",
1073 1073 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
1074 1074 "phase": "draft",
1075 1075 "removed": [],
1076 1076 "rev": 2,
1077 1077 "tags": [],
1078 1078 "user": "other@place"
1079 1079 },
1080 1080 {
1081 1081 "added": ["b"],
1082 1082 "bookmarks": [],
1083 1083 "branch": "default",
1084 1084 "date": [1100000, 0],
1085 1085 "desc": "other 1\nother 2\n\nother 3",
1086 1086 "extra": {"branch": "default"},
1087 1087 "manifest": "4e8d705b1e53e3f9375e0e60dc7b525d8211fe55",
1088 1088 "modified": [],
1089 1089 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
1090 1090 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
1091 1091 "phase": "draft",
1092 1092 "removed": [],
1093 1093 "rev": 1,
1094 1094 "tags": [],
1095 1095 "user": "A. N. Other <other@place>"
1096 1096 },
1097 1097 {
1098 1098 "added": ["a"],
1099 1099 "bookmarks": [],
1100 1100 "branch": "default",
1101 1101 "date": [1000000, 0],
1102 1102 "desc": "line 1\nline 2",
1103 1103 "extra": {"branch": "default"},
1104 1104 "manifest": "a0c8bcbbb45c63b90b70ad007bf38961f64f2af0",
1105 1105 "modified": [],
1106 1106 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
1107 1107 "parents": ["0000000000000000000000000000000000000000"],
1108 1108 "phase": "draft",
1109 1109 "removed": [],
1110 1110 "rev": 0,
1111 1111 "tags": [],
1112 1112 "user": "User Name <user@hostname>"
1113 1113 }
1114 1114 ]
1115 1115
1116 1116 $ hg log -l2 -T'json(rev, parents)'
1117 1117 [
1118 1118 {"parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"], "rev": 8},
1119 1119 {"parents": ["0000000000000000000000000000000000000000"], "rev": 7}
1120 1120 ]
1121 1121
1122 $ hg log -qr. -T'json(rev, parents)'
1123 [
1124 {"parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"], "rev": 8}
1125 ]
1126
1127 $ hg log -r. -T'json(diff)'
1128 [
1129 {"diff": "diff -r 29114dbae42b -r 95c24699272e fourth\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/fourth\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+second\ndiff -r 29114dbae42b -r 95c24699272e second\n--- a/second\tMon Jan 12 13:46:40 1970 +0000\n+++ /dev/null\tThu Jan 01 00:00:00 1970 +0000\n@@ -1,1 +0,0 @@\n-second\ndiff -r 29114dbae42b -r 95c24699272e third\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/third\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+third\n"}
1130 ]
1131
1132 $ hg log -r. -T'json(diffstat)'
1133 [
1134 {"diffstat": " fourth | 1 +\n second | 1 -\n third | 1 +\n 3 files changed, 2 insertions(+), 1 deletions(-)\n"}
1135 ]
1136
1137 $ hg log -r. -T'json(manifest)'
1138 [
1139 {"manifest": "94961b75a2da554b4df6fb599e5bfc7d48de0c64"}
1140 ]
1141
1142 $ hg log -r. -T'json(extra)'
1143 [
1144 {"extra": {"branch": "default"}}
1145 ]
1146
1147 $ hg log -r3 -T'json(modified)'
1148 [
1149 {"modified": ["c"]}
1150 ]
1151
1152 $ hg log -r. -T'json(added)'
1153 [
1154 {"added": ["fourth", "third"]}
1155 ]
1156
1157 $ hg log -r. -T'json(removed)'
1158 [
1159 {"removed": ["second"]}
1160 ]
1161
1162 $ hg log -r. -T'json(files)'
1163 [
1164 {"files": ["fourth", "second", "third"]}
1165 ]
1166
1167 --copies is the exception. copies dict is built only when --copies switch
1168 is on:
1169
1170 $ hg log -r'.^:' -T'json(copies)' --copies
1171 [
1172 {"copies": {}},
1173 {"copies": {"fourth": "second"}}
1174 ]
1175
1122 1176 $ hg log -r. -T'json()'
1123 1177 [
1124 1178 {}
1125 1179 ]
1126 1180
1127 1181 Other unsupported formatter styles:
1128 1182
1129 1183 $ hg log -qr . -Tpickle
1130 1184 abort: "pickle" not in template map
1131 1185 [255]
1132 1186 $ hg log -qr . -Tdebug
1133 1187 abort: "debug" not in template map
1134 1188 [255]
1135 1189
1136 1190 Unparsable function-style references:
1137 1191
1138 1192 $ hg log -qr . -T'json(-)'
1139 1193 hg: parse error at 6: not a prefix: )
1140 1194 (json(-)
1141 1195 ^ here)
1142 1196 [255]
1143 1197
1144 1198 For backward compatibility, the following examples are not parsed as
1145 1199 function-style references:
1146 1200
1147 1201 $ hg log -qr . -T'cbor(rev'
1148 1202 cbor(rev (no-eol)
1149 1203 $ hg log -qr . -T'json (rev)'
1150 1204 json (rev) (no-eol)
1151 1205 $ hg log -qr . -T'json(x="{rev}")'
1152 1206 json(x="8") (no-eol)
1153 1207
1154 1208 Error if style not readable:
1155 1209
1156 1210 #if unix-permissions no-root
1157 1211 $ touch q
1158 1212 $ chmod 0 q
1159 1213 $ hg log --style ./q
1160 1214 abort: Permission denied: './q'
1161 1215 [255]
1162 1216 #endif
1163 1217
1164 1218 Error if no style:
1165 1219
1166 1220 $ hg log --style notexist
1167 1221 abort: style 'notexist' not found
1168 1222 (available styles: bisect, changelog, compact, default, phases, show, status, xml)
1169 1223 [255]
1170 1224
1171 1225 $ hg log -T list
1172 1226 available styles: bisect, changelog, compact, default, phases, show, status, xml
1173 1227 abort: specify a template
1174 1228 [255]
1175 1229
1176 1230 Error if style missing key:
1177 1231
1178 1232 $ echo 'q = q' > t
1179 1233 $ hg log --style ./t
1180 1234 abort: "changeset" not in template map
1181 1235 [255]
1182 1236
1183 1237 Error if style missing value:
1184 1238
1185 1239 $ echo 'changeset =' > t
1186 1240 $ hg log --style t
1187 1241 hg: parse error at t:1: missing value
1188 1242 [255]
1189 1243
1190 1244 Error if include fails:
1191 1245
1192 1246 $ echo 'changeset = q' >> t
1193 1247 #if unix-permissions no-root
1194 1248 $ hg log --style ./t
1195 1249 abort: template file ./q: Permission denied
1196 1250 [255]
1197 1251 $ rm -f q
1198 1252 #endif
1199 1253
1200 1254 Include works:
1201 1255
1202 1256 $ echo '{rev}' > q
1203 1257 $ hg log --style ./t
1204 1258 8
1205 1259 7
1206 1260 6
1207 1261 5
1208 1262 4
1209 1263 3
1210 1264 2
1211 1265 1
1212 1266 0
1213 1267
1214 1268 $ hg phase -r 5 --public
1215 1269 $ hg phase -r 7 --secret --force
1216 1270
1217 1271 Missing non-standard names give no error (backward compatibility):
1218 1272
1219 1273 $ echo "changeset = '{c}'" > t
1220 1274 $ hg log --style ./t
1221 1275
1222 1276 Defining non-standard name works:
1223 1277
1224 1278 $ cat <<EOF > t
1225 1279 > changeset = '{c}'
1226 1280 > c = q
1227 1281 > EOF
1228 1282 $ hg log --style ./t
1229 1283 8
1230 1284 7
1231 1285 6
1232 1286 5
1233 1287 4
1234 1288 3
1235 1289 2
1236 1290 1
1237 1291 0
1238 1292
1239 1293 ui.style works:
1240 1294
1241 1295 $ echo '[ui]' > .hg/hgrc
1242 1296 $ echo 'style = t' >> .hg/hgrc
1243 1297 $ hg log
1244 1298 8
1245 1299 7
1246 1300 6
1247 1301 5
1248 1302 4
1249 1303 3
1250 1304 2
1251 1305 1
1252 1306 0
1253 1307
1254 1308 Issue338:
1255 1309
1256 1310 $ hg log --style=changelog > changelog
1257 1311
1258 1312 $ cat changelog
1259 1313 2020-01-01 test <test>
1260 1314
1261 1315 * fourth, second, third:
1262 1316 third
1263 1317 [95c24699272e] [tip]
1264 1318
1265 1319 1970-01-12 User Name <user@hostname>
1266 1320
1267 1321 * second:
1268 1322 second
1269 1323 [29114dbae42b]
1270 1324
1271 1325 1970-01-18 person <person>
1272 1326
1273 1327 * merge
1274 1328 [d41e714fe50d]
1275 1329
1276 1330 * d:
1277 1331 new head
1278 1332 [13207e5a10d9]
1279 1333
1280 1334 1970-01-17 person <person>
1281 1335
1282 1336 * new branch
1283 1337 [bbe44766e73d] <foo>
1284 1338
1285 1339 1970-01-16 person <person>
1286 1340
1287 1341 * c:
1288 1342 no user, no domain
1289 1343 [10e46f2dcbf4]
1290 1344
1291 1345 1970-01-14 other <other@place>
1292 1346
1293 1347 * c:
1294 1348 no person
1295 1349 [97054abb4ab8]
1296 1350
1297 1351 1970-01-13 A. N. Other <other@place>
1298 1352
1299 1353 * b:
1300 1354 other 1 other 2
1301 1355
1302 1356 other 3
1303 1357 [b608e9d1a3f0]
1304 1358
1305 1359 1970-01-12 User Name <user@hostname>
1306 1360
1307 1361 * a:
1308 1362 line 1 line 2
1309 1363 [1e4e1b8f71e0]
1310 1364
1311 1365
1312 1366 Issue2130: xml output for 'hg heads' is malformed
1313 1367
1314 1368 $ hg heads --style changelog
1315 1369 2020-01-01 test <test>
1316 1370
1317 1371 * fourth, second, third:
1318 1372 third
1319 1373 [95c24699272e] [tip]
1320 1374
1321 1375 1970-01-18 person <person>
1322 1376
1323 1377 * merge
1324 1378 [d41e714fe50d]
1325 1379
1326 1380 1970-01-17 person <person>
1327 1381
1328 1382 * new branch
1329 1383 [bbe44766e73d] <foo>
1330 1384
1331 1385
1332 1386 Add a dummy commit to make up for the instability of the above:
1333 1387
1334 1388 $ echo a > a
1335 1389 $ hg add a
1336 1390 $ hg ci -m future
1337 1391
1338 1392 Add a commit that does all possible modifications at once
1339 1393
1340 1394 $ echo modify >> third
1341 1395 $ touch b
1342 1396 $ hg add b
1343 1397 $ hg mv fourth fifth
1344 1398 $ hg rm a
1345 1399 $ hg ci -m "Modify, add, remove, rename"
1346 1400
1347 1401 Check the status template
1348 1402
1349 1403 $ cat <<EOF >> $HGRCPATH
1350 1404 > [extensions]
1351 1405 > color=
1352 1406 > EOF
1353 1407
1354 1408 $ hg log -T status -r 10
1355 1409 changeset: 10:0f9759ec227a
1356 1410 tag: tip
1357 1411 user: test
1358 1412 date: Thu Jan 01 00:00:00 1970 +0000
1359 1413 summary: Modify, add, remove, rename
1360 1414 files:
1361 1415 M third
1362 1416 A b
1363 1417 A fifth
1364 1418 R a
1365 1419 R fourth
1366 1420
1367 1421 $ hg log -T status -C -r 10
1368 1422 changeset: 10:0f9759ec227a
1369 1423 tag: tip
1370 1424 user: test
1371 1425 date: Thu Jan 01 00:00:00 1970 +0000
1372 1426 summary: Modify, add, remove, rename
1373 1427 files:
1374 1428 M third
1375 1429 A b
1376 1430 A fifth
1377 1431 fourth
1378 1432 R a
1379 1433 R fourth
1380 1434
1381 1435 $ hg log -T status -C -r 10 -v
1382 1436 changeset: 10:0f9759ec227a
1383 1437 tag: tip
1384 1438 user: test
1385 1439 date: Thu Jan 01 00:00:00 1970 +0000
1386 1440 description:
1387 1441 Modify, add, remove, rename
1388 1442
1389 1443 files:
1390 1444 M third
1391 1445 A b
1392 1446 A fifth
1393 1447 fourth
1394 1448 R a
1395 1449 R fourth
1396 1450
1397 1451 $ hg log -T status -C -r 10 --debug
1398 1452 changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c
1399 1453 tag: tip
1400 1454 phase: secret
1401 1455 parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066
1402 1456 parent: -1:0000000000000000000000000000000000000000
1403 1457 manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567
1404 1458 user: test
1405 1459 date: Thu Jan 01 00:00:00 1970 +0000
1406 1460 extra: branch=default
1407 1461 description:
1408 1462 Modify, add, remove, rename
1409 1463
1410 1464 files:
1411 1465 M third
1412 1466 A b
1413 1467 A fifth
1414 1468 fourth
1415 1469 R a
1416 1470 R fourth
1417 1471
1418 1472 $ hg log -T status -C -r 10 --quiet
1419 1473 10:0f9759ec227a
1420 1474 $ hg --color=debug log -T status -r 10
1421 1475 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
1422 1476 [log.tag|tag: tip]
1423 1477 [log.user|user: test]
1424 1478 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
1425 1479 [log.summary|summary: Modify, add, remove, rename]
1426 1480 [ui.note log.files|files:]
1427 1481 [status.modified|M third]
1428 1482 [status.added|A b]
1429 1483 [status.added|A fifth]
1430 1484 [status.removed|R a]
1431 1485 [status.removed|R fourth]
1432 1486
1433 1487 $ hg --color=debug log -T status -C -r 10
1434 1488 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
1435 1489 [log.tag|tag: tip]
1436 1490 [log.user|user: test]
1437 1491 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
1438 1492 [log.summary|summary: Modify, add, remove, rename]
1439 1493 [ui.note log.files|files:]
1440 1494 [status.modified|M third]
1441 1495 [status.added|A b]
1442 1496 [status.added|A fifth]
1443 1497 [status.copied| fourth]
1444 1498 [status.removed|R a]
1445 1499 [status.removed|R fourth]
1446 1500
1447 1501 $ hg --color=debug log -T status -C -r 10 -v
1448 1502 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
1449 1503 [log.tag|tag: tip]
1450 1504 [log.user|user: test]
1451 1505 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
1452 1506 [ui.note log.description|description:]
1453 1507 [ui.note log.description|Modify, add, remove, rename]
1454 1508
1455 1509 [ui.note log.files|files:]
1456 1510 [status.modified|M third]
1457 1511 [status.added|A b]
1458 1512 [status.added|A fifth]
1459 1513 [status.copied| fourth]
1460 1514 [status.removed|R a]
1461 1515 [status.removed|R fourth]
1462 1516
1463 1517 $ hg --color=debug log -T status -C -r 10 --debug
1464 1518 [log.changeset changeset.secret|changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c]
1465 1519 [log.tag|tag: tip]
1466 1520 [log.phase|phase: secret]
1467 1521 [log.parent changeset.secret|parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066]
1468 1522 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
1469 1523 [ui.debug log.manifest|manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567]
1470 1524 [log.user|user: test]
1471 1525 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
1472 1526 [ui.debug log.extra|extra: branch=default]
1473 1527 [ui.note log.description|description:]
1474 1528 [ui.note log.description|Modify, add, remove, rename]
1475 1529
1476 1530 [ui.note log.files|files:]
1477 1531 [status.modified|M third]
1478 1532 [status.added|A b]
1479 1533 [status.added|A fifth]
1480 1534 [status.copied| fourth]
1481 1535 [status.removed|R a]
1482 1536 [status.removed|R fourth]
1483 1537
1484 1538 $ hg --color=debug log -T status -C -r 10 --quiet
1485 1539 [log.node|10:0f9759ec227a]
1486 1540
1487 1541 Check the bisect template
1488 1542
1489 1543 $ hg bisect -g 1
1490 1544 $ hg bisect -b 3 --noupdate
1491 1545 Testing changeset 2:97054abb4ab8 (2 changesets remaining, ~1 tests)
1492 1546 $ hg log -T bisect -r 0:4
1493 1547 changeset: 0:1e4e1b8f71e0
1494 1548 bisect: good (implicit)
1495 1549 user: User Name <user@hostname>
1496 1550 date: Mon Jan 12 13:46:40 1970 +0000
1497 1551 summary: line 1
1498 1552
1499 1553 changeset: 1:b608e9d1a3f0
1500 1554 bisect: good
1501 1555 user: A. N. Other <other@place>
1502 1556 date: Tue Jan 13 17:33:20 1970 +0000
1503 1557 summary: other 1
1504 1558
1505 1559 changeset: 2:97054abb4ab8
1506 1560 bisect: untested
1507 1561 user: other@place
1508 1562 date: Wed Jan 14 21:20:00 1970 +0000
1509 1563 summary: no person
1510 1564
1511 1565 changeset: 3:10e46f2dcbf4
1512 1566 bisect: bad
1513 1567 user: person
1514 1568 date: Fri Jan 16 01:06:40 1970 +0000
1515 1569 summary: no user, no domain
1516 1570
1517 1571 changeset: 4:bbe44766e73d
1518 1572 bisect: bad (implicit)
1519 1573 branch: foo
1520 1574 user: person
1521 1575 date: Sat Jan 17 04:53:20 1970 +0000
1522 1576 summary: new branch
1523 1577
1524 1578 $ hg log --debug -T bisect -r 0:4
1525 1579 changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
1526 1580 bisect: good (implicit)
1527 1581 phase: public
1528 1582 parent: -1:0000000000000000000000000000000000000000
1529 1583 parent: -1:0000000000000000000000000000000000000000
1530 1584 manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
1531 1585 user: User Name <user@hostname>
1532 1586 date: Mon Jan 12 13:46:40 1970 +0000
1533 1587 files+: a
1534 1588 extra: branch=default
1535 1589 description:
1536 1590 line 1
1537 1591 line 2
1538 1592
1539 1593
1540 1594 changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1541 1595 bisect: good
1542 1596 phase: public
1543 1597 parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
1544 1598 parent: -1:0000000000000000000000000000000000000000
1545 1599 manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
1546 1600 user: A. N. Other <other@place>
1547 1601 date: Tue Jan 13 17:33:20 1970 +0000
1548 1602 files+: b
1549 1603 extra: branch=default
1550 1604 description:
1551 1605 other 1
1552 1606 other 2
1553 1607
1554 1608 other 3
1555 1609
1556 1610
1557 1611 changeset: 2:97054abb4ab824450e9164180baf491ae0078465
1558 1612 bisect: untested
1559 1613 phase: public
1560 1614 parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1561 1615 parent: -1:0000000000000000000000000000000000000000
1562 1616 manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
1563 1617 user: other@place
1564 1618 date: Wed Jan 14 21:20:00 1970 +0000
1565 1619 files+: c
1566 1620 extra: branch=default
1567 1621 description:
1568 1622 no person
1569 1623
1570 1624
1571 1625 changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
1572 1626 bisect: bad
1573 1627 phase: public
1574 1628 parent: 2:97054abb4ab824450e9164180baf491ae0078465
1575 1629 parent: -1:0000000000000000000000000000000000000000
1576 1630 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1577 1631 user: person
1578 1632 date: Fri Jan 16 01:06:40 1970 +0000
1579 1633 files: c
1580 1634 extra: branch=default
1581 1635 description:
1582 1636 no user, no domain
1583 1637
1584 1638
1585 1639 changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
1586 1640 bisect: bad (implicit)
1587 1641 branch: foo
1588 1642 phase: draft
1589 1643 parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
1590 1644 parent: -1:0000000000000000000000000000000000000000
1591 1645 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1592 1646 user: person
1593 1647 date: Sat Jan 17 04:53:20 1970 +0000
1594 1648 extra: branch=foo
1595 1649 description:
1596 1650 new branch
1597 1651
1598 1652
1599 1653 $ hg log -v -T bisect -r 0:4
1600 1654 changeset: 0:1e4e1b8f71e0
1601 1655 bisect: good (implicit)
1602 1656 user: User Name <user@hostname>
1603 1657 date: Mon Jan 12 13:46:40 1970 +0000
1604 1658 files: a
1605 1659 description:
1606 1660 line 1
1607 1661 line 2
1608 1662
1609 1663
1610 1664 changeset: 1:b608e9d1a3f0
1611 1665 bisect: good
1612 1666 user: A. N. Other <other@place>
1613 1667 date: Tue Jan 13 17:33:20 1970 +0000
1614 1668 files: b
1615 1669 description:
1616 1670 other 1
1617 1671 other 2
1618 1672
1619 1673 other 3
1620 1674
1621 1675
1622 1676 changeset: 2:97054abb4ab8
1623 1677 bisect: untested
1624 1678 user: other@place
1625 1679 date: Wed Jan 14 21:20:00 1970 +0000
1626 1680 files: c
1627 1681 description:
1628 1682 no person
1629 1683
1630 1684
1631 1685 changeset: 3:10e46f2dcbf4
1632 1686 bisect: bad
1633 1687 user: person
1634 1688 date: Fri Jan 16 01:06:40 1970 +0000
1635 1689 files: c
1636 1690 description:
1637 1691 no user, no domain
1638 1692
1639 1693
1640 1694 changeset: 4:bbe44766e73d
1641 1695 bisect: bad (implicit)
1642 1696 branch: foo
1643 1697 user: person
1644 1698 date: Sat Jan 17 04:53:20 1970 +0000
1645 1699 description:
1646 1700 new branch
1647 1701
1648 1702
1649 1703 $ hg --color=debug log -T bisect -r 0:4
1650 1704 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
1651 1705 [log.bisect bisect.good|bisect: good (implicit)]
1652 1706 [log.user|user: User Name <user@hostname>]
1653 1707 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
1654 1708 [log.summary|summary: line 1]
1655 1709
1656 1710 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
1657 1711 [log.bisect bisect.good|bisect: good]
1658 1712 [log.user|user: A. N. Other <other@place>]
1659 1713 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
1660 1714 [log.summary|summary: other 1]
1661 1715
1662 1716 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
1663 1717 [log.bisect bisect.untested|bisect: untested]
1664 1718 [log.user|user: other@place]
1665 1719 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
1666 1720 [log.summary|summary: no person]
1667 1721
1668 1722 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
1669 1723 [log.bisect bisect.bad|bisect: bad]
1670 1724 [log.user|user: person]
1671 1725 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
1672 1726 [log.summary|summary: no user, no domain]
1673 1727
1674 1728 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
1675 1729 [log.bisect bisect.bad|bisect: bad (implicit)]
1676 1730 [log.branch|branch: foo]
1677 1731 [log.user|user: person]
1678 1732 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
1679 1733 [log.summary|summary: new branch]
1680 1734
1681 1735 $ hg --color=debug log --debug -T bisect -r 0:4
1682 1736 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
1683 1737 [log.bisect bisect.good|bisect: good (implicit)]
1684 1738 [log.phase|phase: public]
1685 1739 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
1686 1740 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
1687 1741 [ui.debug log.manifest|manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0]
1688 1742 [log.user|user: User Name <user@hostname>]
1689 1743 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
1690 1744 [ui.debug log.files|files+: a]
1691 1745 [ui.debug log.extra|extra: branch=default]
1692 1746 [ui.note log.description|description:]
1693 1747 [ui.note log.description|line 1
1694 1748 line 2]
1695 1749
1696 1750
1697 1751 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
1698 1752 [log.bisect bisect.good|bisect: good]
1699 1753 [log.phase|phase: public]
1700 1754 [log.parent changeset.public|parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
1701 1755 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
1702 1756 [ui.debug log.manifest|manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55]
1703 1757 [log.user|user: A. N. Other <other@place>]
1704 1758 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
1705 1759 [ui.debug log.files|files+: b]
1706 1760 [ui.debug log.extra|extra: branch=default]
1707 1761 [ui.note log.description|description:]
1708 1762 [ui.note log.description|other 1
1709 1763 other 2
1710 1764
1711 1765 other 3]
1712 1766
1713 1767
1714 1768 [log.changeset changeset.public|changeset: 2:97054abb4ab824450e9164180baf491ae0078465]
1715 1769 [log.bisect bisect.untested|bisect: untested]
1716 1770 [log.phase|phase: public]
1717 1771 [log.parent changeset.public|parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
1718 1772 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
1719 1773 [ui.debug log.manifest|manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1]
1720 1774 [log.user|user: other@place]
1721 1775 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
1722 1776 [ui.debug log.files|files+: c]
1723 1777 [ui.debug log.extra|extra: branch=default]
1724 1778 [ui.note log.description|description:]
1725 1779 [ui.note log.description|no person]
1726 1780
1727 1781
1728 1782 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
1729 1783 [log.bisect bisect.bad|bisect: bad]
1730 1784 [log.phase|phase: public]
1731 1785 [log.parent changeset.public|parent: 2:97054abb4ab824450e9164180baf491ae0078465]
1732 1786 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
1733 1787 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
1734 1788 [log.user|user: person]
1735 1789 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
1736 1790 [ui.debug log.files|files: c]
1737 1791 [ui.debug log.extra|extra: branch=default]
1738 1792 [ui.note log.description|description:]
1739 1793 [ui.note log.description|no user, no domain]
1740 1794
1741 1795
1742 1796 [log.changeset changeset.draft|changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74]
1743 1797 [log.bisect bisect.bad|bisect: bad (implicit)]
1744 1798 [log.branch|branch: foo]
1745 1799 [log.phase|phase: draft]
1746 1800 [log.parent changeset.public|parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
1747 1801 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
1748 1802 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
1749 1803 [log.user|user: person]
1750 1804 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
1751 1805 [ui.debug log.extra|extra: branch=foo]
1752 1806 [ui.note log.description|description:]
1753 1807 [ui.note log.description|new branch]
1754 1808
1755 1809
1756 1810 $ hg --color=debug log -v -T bisect -r 0:4
1757 1811 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
1758 1812 [log.bisect bisect.good|bisect: good (implicit)]
1759 1813 [log.user|user: User Name <user@hostname>]
1760 1814 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
1761 1815 [ui.note log.files|files: a]
1762 1816 [ui.note log.description|description:]
1763 1817 [ui.note log.description|line 1
1764 1818 line 2]
1765 1819
1766 1820
1767 1821 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
1768 1822 [log.bisect bisect.good|bisect: good]
1769 1823 [log.user|user: A. N. Other <other@place>]
1770 1824 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
1771 1825 [ui.note log.files|files: b]
1772 1826 [ui.note log.description|description:]
1773 1827 [ui.note log.description|other 1
1774 1828 other 2
1775 1829
1776 1830 other 3]
1777 1831
1778 1832
1779 1833 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
1780 1834 [log.bisect bisect.untested|bisect: untested]
1781 1835 [log.user|user: other@place]
1782 1836 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
1783 1837 [ui.note log.files|files: c]
1784 1838 [ui.note log.description|description:]
1785 1839 [ui.note log.description|no person]
1786 1840
1787 1841
1788 1842 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
1789 1843 [log.bisect bisect.bad|bisect: bad]
1790 1844 [log.user|user: person]
1791 1845 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
1792 1846 [ui.note log.files|files: c]
1793 1847 [ui.note log.description|description:]
1794 1848 [ui.note log.description|no user, no domain]
1795 1849
1796 1850
1797 1851 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
1798 1852 [log.bisect bisect.bad|bisect: bad (implicit)]
1799 1853 [log.branch|branch: foo]
1800 1854 [log.user|user: person]
1801 1855 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
1802 1856 [ui.note log.description|description:]
1803 1857 [ui.note log.description|new branch]
1804 1858
1805 1859
1806 1860 $ hg bisect --reset
1807 1861
1808 1862 $ cd ..
1809 1863
1810 1864 Set up latesttag repository:
1811 1865
1812 1866 $ hg init latesttag
1813 1867 $ cd latesttag
1814 1868
1815 1869 $ echo a > file
1816 1870 $ hg ci -Am a -d '0 0'
1817 1871 adding file
1818 1872
1819 1873 $ echo b >> file
1820 1874 $ hg ci -m b -d '1 0'
1821 1875
1822 1876 $ echo c >> head1
1823 1877 $ hg ci -Am h1c -d '2 0'
1824 1878 adding head1
1825 1879
1826 1880 $ hg update -q 1
1827 1881 $ echo d >> head2
1828 1882 $ hg ci -Am h2d -d '3 0'
1829 1883 adding head2
1830 1884 created new head
1831 1885
1832 1886 $ echo e >> head2
1833 1887 $ hg ci -m h2e -d '4 0'
1834 1888
1835 1889 $ hg merge -q
1836 1890 $ hg ci -m merge -d '5 -3600'
1837 1891
1838 1892 $ hg tag -r 1 -m t1 -d '6 0' t1
1839 1893 $ hg tag -r 2 -m t2 -d '7 0' t2
1840 1894 $ hg tag -r 3 -m t3 -d '8 0' t3
1841 1895 $ hg tag -r 4 -m t4 -d '4 0' t4 # older than t2, but should not matter
1842 1896 $ hg tag -r 5 -m t5 -d '9 0' t5
1843 1897 $ hg tag -r 3 -m at3 -d '10 0' at3
1844 1898
1845 1899 $ cd ..
1846 1900
1847 1901 Style path expansion: issue1948 - ui.style option doesn't work on OSX
1848 1902 if it is a relative path
1849 1903
1850 1904 $ mkdir -p home/styles
1851 1905
1852 1906 $ cat > home/styles/teststyle <<EOF
1853 1907 > changeset = 'test {rev}:{node|short}\n'
1854 1908 > EOF
1855 1909
1856 1910 $ HOME=`pwd`/home; export HOME
1857 1911
1858 1912 $ cat > latesttag/.hg/hgrc <<EOF
1859 1913 > [ui]
1860 1914 > style = ~/styles/teststyle
1861 1915 > EOF
1862 1916
1863 1917 $ hg -R latesttag tip
1864 1918 test 11:97e5943b523a
1865 1919
1866 1920 Test recursive showlist template (issue1989):
1867 1921
1868 1922 $ cat > style1989 <<EOF
1869 1923 > changeset = '{file_mods}{manifest}{extras}'
1870 1924 > file_mod = 'M|{author|person}\n'
1871 1925 > manifest = '{rev},{author}\n'
1872 1926 > extra = '{key}: {author}\n'
1873 1927 > EOF
1874 1928
1875 1929 $ hg -R latesttag log -r tip --style=style1989
1876 1930 M|test
1877 1931 11,
1878 1932 branch: test
General Comments 0
You need to be logged in to leave comments. Login now