##// END OF EJS Templates
log: fill in pseudo rev and node as wdir() manifest identifiers...
Yuya Nishihara -
r39832:94ca3579 default
parent child Browse files
Show More
@@ -1,906 +1,907 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
13 13 from .i18n import _
14 14 from .node import (
15 15 nullid,
16 wdirid,
17 wdirrev,
16 18 )
17 19
18 20 from . import (
19 21 dagop,
20 22 error,
21 23 formatter,
22 24 graphmod,
23 25 match as matchmod,
24 26 mdiff,
25 27 patch,
26 28 pathutil,
27 29 pycompat,
28 30 revset,
29 31 revsetlang,
30 32 scmutil,
31 33 smartset,
32 34 templatekw,
33 35 templater,
34 36 util,
35 37 )
36 38 from .utils import (
37 39 dateutil,
38 40 stringutil,
39 41 )
40 42
41 43 def getlimit(opts):
42 44 """get the log limit according to option -l/--limit"""
43 45 limit = opts.get('limit')
44 46 if limit:
45 47 try:
46 48 limit = int(limit)
47 49 except ValueError:
48 50 raise error.Abort(_('limit must be a positive integer'))
49 51 if limit <= 0:
50 52 raise error.Abort(_('limit must be positive'))
51 53 else:
52 54 limit = None
53 55 return limit
54 56
55 57 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
56 58 changes=None, stat=False, fp=None, prefix='',
57 59 root='', listsubrepos=False, hunksfilterfn=None):
58 60 '''show diff or diffstat.'''
59 61 if root:
60 62 relroot = pathutil.canonpath(repo.root, repo.getcwd(), root)
61 63 else:
62 64 relroot = ''
63 65 if relroot != '':
64 66 # XXX relative roots currently don't work if the root is within a
65 67 # subrepo
66 68 uirelroot = match.uipath(relroot)
67 69 relroot += '/'
68 70 for matchroot in match.files():
69 71 if not matchroot.startswith(relroot):
70 72 ui.warn(_('warning: %s not inside relative root %s\n') % (
71 73 match.uipath(matchroot), uirelroot))
72 74
73 75 if stat:
74 76 diffopts = diffopts.copy(context=0, noprefix=False)
75 77 width = 80
76 78 if not ui.plain():
77 79 width = ui.termwidth()
78 80
79 81 chunks = repo[node2].diff(repo[node1], match, changes, opts=diffopts,
80 82 prefix=prefix, relroot=relroot,
81 83 hunksfilterfn=hunksfilterfn)
82 84
83 85 if fp is not None or ui.canwritewithoutlabels():
84 86 out = fp or ui
85 87 if stat:
86 88 chunks = [patch.diffstat(util.iterlines(chunks), width=width)]
87 89 for chunk in util.filechunkiter(util.chunkbuffer(chunks)):
88 90 out.write(chunk)
89 91 else:
90 92 if stat:
91 93 chunks = patch.diffstatui(util.iterlines(chunks), width=width)
92 94 else:
93 95 chunks = patch.difflabel(lambda chunks, **kwargs: chunks, chunks,
94 96 opts=diffopts)
95 97 if ui.canbatchlabeledwrites():
96 98 def gen():
97 99 for chunk, label in chunks:
98 100 yield ui.label(chunk, label=label)
99 101 for chunk in util.filechunkiter(util.chunkbuffer(gen())):
100 102 ui.write(chunk)
101 103 else:
102 104 for chunk, label in chunks:
103 105 ui.write(chunk, label=label)
104 106
105 107 if listsubrepos:
106 108 ctx1 = repo[node1]
107 109 ctx2 = repo[node2]
108 110 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
109 111 tempnode2 = node2
110 112 try:
111 113 if node2 is not None:
112 114 tempnode2 = ctx2.substate[subpath][1]
113 115 except KeyError:
114 116 # A subrepo that existed in node1 was deleted between node1 and
115 117 # node2 (inclusive). Thus, ctx2's substate won't contain that
116 118 # subpath. The best we can do is to ignore it.
117 119 tempnode2 = None
118 120 submatch = matchmod.subdirmatcher(subpath, match)
119 121 sub.diff(ui, diffopts, tempnode2, submatch, changes=changes,
120 122 stat=stat, fp=fp, prefix=prefix)
121 123
122 124 class changesetdiffer(object):
123 125 """Generate diff of changeset with pre-configured filtering functions"""
124 126
125 127 def _makefilematcher(self, ctx):
126 128 return scmutil.matchall(ctx.repo())
127 129
128 130 def _makehunksfilter(self, ctx):
129 131 return None
130 132
131 133 def showdiff(self, ui, ctx, diffopts, stat=False):
132 134 repo = ctx.repo()
133 135 node = ctx.node()
134 136 prev = ctx.p1().node()
135 137 diffordiffstat(ui, repo, diffopts, prev, node,
136 138 match=self._makefilematcher(ctx), stat=stat,
137 139 hunksfilterfn=self._makehunksfilter(ctx))
138 140
139 141 def changesetlabels(ctx):
140 142 labels = ['log.changeset', 'changeset.%s' % ctx.phasestr()]
141 143 if ctx.obsolete():
142 144 labels.append('changeset.obsolete')
143 145 if ctx.isunstable():
144 146 labels.append('changeset.unstable')
145 147 for instability in ctx.instabilities():
146 148 labels.append('instability.%s' % instability)
147 149 return ' '.join(labels)
148 150
149 151 class changesetprinter(object):
150 152 '''show changeset information when templating not requested.'''
151 153
152 154 def __init__(self, ui, repo, differ=None, diffopts=None, buffered=False):
153 155 self.ui = ui
154 156 self.repo = repo
155 157 self.buffered = buffered
156 158 self._differ = differ or changesetdiffer()
157 159 self._diffopts = patch.diffallopts(ui, diffopts)
158 160 self._includestat = diffopts and diffopts.get('stat')
159 161 self._includediff = diffopts and diffopts.get('patch')
160 162 self.header = {}
161 163 self.hunk = {}
162 164 self.lastheader = None
163 165 self.footer = None
164 166 self._columns = templatekw.getlogcolumns()
165 167
166 168 def flush(self, ctx):
167 169 rev = ctx.rev()
168 170 if rev in self.header:
169 171 h = self.header[rev]
170 172 if h != self.lastheader:
171 173 self.lastheader = h
172 174 self.ui.write(h)
173 175 del self.header[rev]
174 176 if rev in self.hunk:
175 177 self.ui.write(self.hunk[rev])
176 178 del self.hunk[rev]
177 179
178 180 def close(self):
179 181 if self.footer:
180 182 self.ui.write(self.footer)
181 183
182 184 def show(self, ctx, copies=None, **props):
183 185 props = pycompat.byteskwargs(props)
184 186 if self.buffered:
185 187 self.ui.pushbuffer(labeled=True)
186 188 self._show(ctx, copies, props)
187 189 self.hunk[ctx.rev()] = self.ui.popbuffer()
188 190 else:
189 191 self._show(ctx, copies, props)
190 192
191 193 def _show(self, ctx, copies, props):
192 194 '''show a single changeset or file revision'''
193 195 changenode = ctx.node()
194 rev = ctx.rev()
195 196
196 197 if self.ui.quiet:
197 198 self.ui.write("%s\n" % scmutil.formatchangeid(ctx),
198 199 label='log.node')
199 200 return
200 201
201 202 columns = self._columns
202 203 self.ui.write(columns['changeset'] % scmutil.formatchangeid(ctx),
203 204 label=changesetlabels(ctx))
204 205
205 206 # branches are shown first before any other names due to backwards
206 207 # compatibility
207 208 branch = ctx.branch()
208 209 # don't show the default branch name
209 210 if branch != 'default':
210 211 self.ui.write(columns['branch'] % branch, label='log.branch')
211 212
212 213 for nsname, ns in self.repo.names.iteritems():
213 214 # branches has special logic already handled above, so here we just
214 215 # skip it
215 216 if nsname == 'branches':
216 217 continue
217 218 # we will use the templatename as the color name since those two
218 219 # should be the same
219 220 for name in ns.names(self.repo, changenode):
220 221 self.ui.write(ns.logfmt % name,
221 222 label='log.%s' % ns.colorname)
222 223 if self.ui.debugflag:
223 224 self.ui.write(columns['phase'] % ctx.phasestr(), label='log.phase')
224 225 for pctx in scmutil.meaningfulparents(self.repo, ctx):
225 226 label = 'log.parent changeset.%s' % pctx.phasestr()
226 227 self.ui.write(columns['parent'] % scmutil.formatchangeid(pctx),
227 228 label=label)
228 229
229 if self.ui.debugflag and rev is not None:
230 if self.ui.debugflag:
230 231 mnode = ctx.manifestnode()
231 mrev = self.repo.manifestlog.rev(mnode)
232 if mnode is None:
233 mnode = wdirid
234 mrev = wdirrev
235 else:
236 mrev = self.repo.manifestlog.rev(mnode)
232 237 self.ui.write(columns['manifest']
233 238 % scmutil.formatrevnode(self.ui, mrev, mnode),
234 239 label='ui.debug log.manifest')
235 240 self.ui.write(columns['user'] % ctx.user(), label='log.user')
236 241 self.ui.write(columns['date'] % dateutil.datestr(ctx.date()),
237 242 label='log.date')
238 243
239 244 if ctx.isunstable():
240 245 instabilities = ctx.instabilities()
241 246 self.ui.write(columns['instability'] % ', '.join(instabilities),
242 247 label='log.instability')
243 248
244 249 elif ctx.obsolete():
245 250 self._showobsfate(ctx)
246 251
247 252 self._exthook(ctx)
248 253
249 254 if self.ui.debugflag:
250 255 files = ctx.p1().status(ctx)[:3]
251 256 for key, value in zip(['files', 'files+', 'files-'], files):
252 257 if value:
253 258 self.ui.write(columns[key] % " ".join(value),
254 259 label='ui.debug log.files')
255 260 elif ctx.files() and self.ui.verbose:
256 261 self.ui.write(columns['files'] % " ".join(ctx.files()),
257 262 label='ui.note log.files')
258 263 if copies and self.ui.verbose:
259 264 copies = ['%s (%s)' % c for c in copies]
260 265 self.ui.write(columns['copies'] % ' '.join(copies),
261 266 label='ui.note log.copies')
262 267
263 268 extra = ctx.extra()
264 269 if extra and self.ui.debugflag:
265 270 for key, value in sorted(extra.items()):
266 271 self.ui.write(columns['extra']
267 272 % (key, stringutil.escapestr(value)),
268 273 label='ui.debug log.extra')
269 274
270 275 description = ctx.description().strip()
271 276 if description:
272 277 if self.ui.verbose:
273 278 self.ui.write(_("description:\n"),
274 279 label='ui.note log.description')
275 280 self.ui.write(description,
276 281 label='ui.note log.description')
277 282 self.ui.write("\n\n")
278 283 else:
279 284 self.ui.write(columns['summary'] % description.splitlines()[0],
280 285 label='log.summary')
281 286 self.ui.write("\n")
282 287
283 288 self._showpatch(ctx)
284 289
285 290 def _showobsfate(self, ctx):
286 291 # TODO: do not depend on templater
287 292 tres = formatter.templateresources(self.repo.ui, self.repo)
288 293 t = formatter.maketemplater(self.repo.ui, '{join(obsfate, "\n")}',
289 294 defaults=templatekw.keywords,
290 295 resources=tres)
291 296 obsfate = t.renderdefault({'ctx': ctx}).splitlines()
292 297
293 298 if obsfate:
294 299 for obsfateline in obsfate:
295 300 self.ui.write(self._columns['obsolete'] % obsfateline,
296 301 label='log.obsfate')
297 302
298 303 def _exthook(self, ctx):
299 304 '''empty method used by extension as a hook point
300 305 '''
301 306
302 307 def _showpatch(self, ctx):
303 308 if self._includestat:
304 309 self._differ.showdiff(self.ui, ctx, self._diffopts, stat=True)
305 310 if self._includestat and self._includediff:
306 311 self.ui.write("\n")
307 312 if self._includediff:
308 313 self._differ.showdiff(self.ui, ctx, self._diffopts, stat=False)
309 314 if self._includestat or self._includediff:
310 315 self.ui.write("\n")
311 316
312 317 class changesetformatter(changesetprinter):
313 318 """Format changeset information by generic formatter"""
314 319
315 320 def __init__(self, ui, repo, fm, differ=None, diffopts=None,
316 321 buffered=False):
317 322 changesetprinter.__init__(self, ui, repo, differ, diffopts, buffered)
318 323 self._diffopts = patch.difffeatureopts(ui, diffopts, git=True)
319 324 self._fm = fm
320 325
321 326 def close(self):
322 327 self._fm.end()
323 328
324 329 def _show(self, ctx, copies, props):
325 330 '''show a single changeset or file revision'''
326 331 fm = self._fm
327 332 fm.startitem()
328 333 fm.context(ctx=ctx)
329 334 fm.data(rev=scmutil.intrev(ctx),
330 335 node=fm.hexfunc(scmutil.binnode(ctx)))
331 336
332 337 if self.ui.quiet:
333 338 return
334 339
335 340 fm.data(branch=ctx.branch(),
336 341 phase=ctx.phasestr(),
337 342 user=ctx.user(),
338 343 date=fm.formatdate(ctx.date()),
339 344 desc=ctx.description(),
340 345 bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'),
341 346 tags=fm.formatlist(ctx.tags(), name='tag'),
342 347 parents=fm.formatlist([fm.hexfunc(c.node())
343 348 for c in ctx.parents()], name='node'))
344 349
345 350 if self.ui.debugflag:
346 if ctx.rev() is None:
347 hexnode = None
348 else:
349 hexnode = fm.hexfunc(ctx.manifestnode())
350 fm.data(manifest=hexnode,
351 fm.data(manifest=fm.hexfunc(ctx.manifestnode() or wdirid),
351 352 extra=fm.formatdict(ctx.extra()))
352 353
353 354 files = ctx.p1().status(ctx)
354 355 fm.data(modified=fm.formatlist(files[0], name='file'),
355 356 added=fm.formatlist(files[1], name='file'),
356 357 removed=fm.formatlist(files[2], name='file'))
357 358
358 359 elif self.ui.verbose:
359 360 fm.data(files=fm.formatlist(ctx.files(), name='file'))
360 361 if copies:
361 362 fm.data(copies=fm.formatdict(copies,
362 363 key='name', value='source'))
363 364
364 365 if self._includestat:
365 366 self.ui.pushbuffer()
366 367 self._differ.showdiff(self.ui, ctx, self._diffopts, stat=True)
367 368 fm.data(diffstat=self.ui.popbuffer())
368 369 if self._includediff:
369 370 self.ui.pushbuffer()
370 371 self._differ.showdiff(self.ui, ctx, self._diffopts, stat=False)
371 372 fm.data(diff=self.ui.popbuffer())
372 373
373 374 class changesettemplater(changesetprinter):
374 375 '''format changeset information.
375 376
376 377 Note: there are a variety of convenience functions to build a
377 378 changesettemplater for common cases. See functions such as:
378 379 maketemplater, changesetdisplayer, buildcommittemplate, or other
379 380 functions that use changesest_templater.
380 381 '''
381 382
382 383 # Arguments before "buffered" used to be positional. Consider not
383 384 # adding/removing arguments before "buffered" to not break callers.
384 385 def __init__(self, ui, repo, tmplspec, differ=None, diffopts=None,
385 386 buffered=False):
386 387 changesetprinter.__init__(self, ui, repo, differ, diffopts, buffered)
387 388 # tres is shared with _graphnodeformatter()
388 389 self._tresources = tres = formatter.templateresources(ui, repo)
389 390 self.t = formatter.loadtemplater(ui, tmplspec,
390 391 defaults=templatekw.keywords,
391 392 resources=tres,
392 393 cache=templatekw.defaulttempl)
393 394 self._counter = itertools.count()
394 395
395 396 self._tref = tmplspec.ref
396 397 self._parts = {'header': '', 'footer': '',
397 398 tmplspec.ref: tmplspec.ref,
398 399 'docheader': '', 'docfooter': '',
399 400 'separator': ''}
400 401 if tmplspec.mapfile:
401 402 # find correct templates for current mode, for backward
402 403 # compatibility with 'log -v/-q/--debug' using a mapfile
403 404 tmplmodes = [
404 405 (True, ''),
405 406 (self.ui.verbose, '_verbose'),
406 407 (self.ui.quiet, '_quiet'),
407 408 (self.ui.debugflag, '_debug'),
408 409 ]
409 410 for mode, postfix in tmplmodes:
410 411 for t in self._parts:
411 412 cur = t + postfix
412 413 if mode and cur in self.t:
413 414 self._parts[t] = cur
414 415 else:
415 416 partnames = [p for p in self._parts.keys() if p != tmplspec.ref]
416 417 m = formatter.templatepartsmap(tmplspec, self.t, partnames)
417 418 self._parts.update(m)
418 419
419 420 if self._parts['docheader']:
420 421 self.ui.write(self.t.render(self._parts['docheader'], {}))
421 422
422 423 def close(self):
423 424 if self._parts['docfooter']:
424 425 if not self.footer:
425 426 self.footer = ""
426 427 self.footer += self.t.render(self._parts['docfooter'], {})
427 428 return super(changesettemplater, self).close()
428 429
429 430 def _show(self, ctx, copies, props):
430 431 '''show a single changeset or file revision'''
431 432 props = props.copy()
432 433 props['ctx'] = ctx
433 434 props['index'] = index = next(self._counter)
434 435 props['revcache'] = {'copies': copies}
435 436
436 437 # write separator, which wouldn't work well with the header part below
437 438 # since there's inherently a conflict between header (across items) and
438 439 # separator (per item)
439 440 if self._parts['separator'] and index > 0:
440 441 self.ui.write(self.t.render(self._parts['separator'], {}))
441 442
442 443 # write header
443 444 if self._parts['header']:
444 445 h = self.t.render(self._parts['header'], props)
445 446 if self.buffered:
446 447 self.header[ctx.rev()] = h
447 448 else:
448 449 if self.lastheader != h:
449 450 self.lastheader = h
450 451 self.ui.write(h)
451 452
452 453 # write changeset metadata, then patch if requested
453 454 key = self._parts[self._tref]
454 455 self.ui.write(self.t.render(key, props))
455 456 self._showpatch(ctx)
456 457
457 458 if self._parts['footer']:
458 459 if not self.footer:
459 460 self.footer = self.t.render(self._parts['footer'], props)
460 461
461 462 def templatespec(tmpl, mapfile):
462 463 if mapfile:
463 464 return formatter.templatespec('changeset', tmpl, mapfile)
464 465 else:
465 466 return formatter.templatespec('', tmpl, None)
466 467
467 468 def _lookuptemplate(ui, tmpl, style):
468 469 """Find the template matching the given template spec or style
469 470
470 471 See formatter.lookuptemplate() for details.
471 472 """
472 473
473 474 # ui settings
474 475 if not tmpl and not style: # template are stronger than style
475 476 tmpl = ui.config('ui', 'logtemplate')
476 477 if tmpl:
477 478 return templatespec(templater.unquotestring(tmpl), None)
478 479 else:
479 480 style = util.expandpath(ui.config('ui', 'style'))
480 481
481 482 if not tmpl and style:
482 483 mapfile = style
483 484 if not os.path.split(mapfile)[0]:
484 485 mapname = (templater.templatepath('map-cmdline.' + mapfile)
485 486 or templater.templatepath(mapfile))
486 487 if mapname:
487 488 mapfile = mapname
488 489 return templatespec(None, mapfile)
489 490
490 491 if not tmpl:
491 492 return templatespec(None, None)
492 493
493 494 return formatter.lookuptemplate(ui, 'changeset', tmpl)
494 495
495 496 def maketemplater(ui, repo, tmpl, buffered=False):
496 497 """Create a changesettemplater from a literal template 'tmpl'
497 498 byte-string."""
498 499 spec = templatespec(tmpl, None)
499 500 return changesettemplater(ui, repo, spec, buffered=buffered)
500 501
501 502 def changesetdisplayer(ui, repo, opts, differ=None, buffered=False):
502 503 """show one changeset using template or regular display.
503 504
504 505 Display format will be the first non-empty hit of:
505 506 1. option 'template'
506 507 2. option 'style'
507 508 3. [ui] setting 'logtemplate'
508 509 4. [ui] setting 'style'
509 510 If all of these values are either the unset or the empty string,
510 511 regular display via changesetprinter() is done.
511 512 """
512 513 postargs = (differ, opts, buffered)
513 514 if opts.get('template') == 'json':
514 515 fm = ui.formatter('log', opts)
515 516 return changesetformatter(ui, repo, fm, *postargs)
516 517
517 518 spec = _lookuptemplate(ui, opts.get('template'), opts.get('style'))
518 519
519 520 if not spec.ref and not spec.tmpl and not spec.mapfile:
520 521 return changesetprinter(ui, repo, *postargs)
521 522
522 523 return changesettemplater(ui, repo, spec, *postargs)
523 524
524 525 def _makematcher(repo, revs, pats, opts):
525 526 """Build matcher and expanded patterns from log options
526 527
527 528 If --follow, revs are the revisions to follow from.
528 529
529 530 Returns (match, pats, slowpath) where
530 531 - match: a matcher built from the given pats and -I/-X opts
531 532 - pats: patterns used (globs are expanded on Windows)
532 533 - slowpath: True if patterns aren't as simple as scanning filelogs
533 534 """
534 535 # pats/include/exclude are passed to match.match() directly in
535 536 # _matchfiles() revset but walkchangerevs() builds its matcher with
536 537 # scmutil.match(). The difference is input pats are globbed on
537 538 # platforms without shell expansion (windows).
538 539 wctx = repo[None]
539 540 match, pats = scmutil.matchandpats(wctx, pats, opts)
540 541 slowpath = match.anypats() or (not match.always() and opts.get('removed'))
541 542 if not slowpath:
542 543 follow = opts.get('follow') or opts.get('follow_first')
543 544 startctxs = []
544 545 if follow and opts.get('rev'):
545 546 startctxs = [repo[r] for r in revs]
546 547 for f in match.files():
547 548 if follow and startctxs:
548 549 # No idea if the path was a directory at that revision, so
549 550 # take the slow path.
550 551 if any(f not in c for c in startctxs):
551 552 slowpath = True
552 553 continue
553 554 elif follow and f not in wctx:
554 555 # If the file exists, it may be a directory, so let it
555 556 # take the slow path.
556 557 if os.path.exists(repo.wjoin(f)):
557 558 slowpath = True
558 559 continue
559 560 else:
560 561 raise error.Abort(_('cannot follow file not in parent '
561 562 'revision: "%s"') % f)
562 563 filelog = repo.file(f)
563 564 if not filelog:
564 565 # A zero count may be a directory or deleted file, so
565 566 # try to find matching entries on the slow path.
566 567 if follow:
567 568 raise error.Abort(
568 569 _('cannot follow nonexistent file: "%s"') % f)
569 570 slowpath = True
570 571
571 572 # We decided to fall back to the slowpath because at least one
572 573 # of the paths was not a file. Check to see if at least one of them
573 574 # existed in history - in that case, we'll continue down the
574 575 # slowpath; otherwise, we can turn off the slowpath
575 576 if slowpath:
576 577 for path in match.files():
577 578 if path == '.' or path in repo.store:
578 579 break
579 580 else:
580 581 slowpath = False
581 582
582 583 return match, pats, slowpath
583 584
584 585 def _fileancestors(repo, revs, match, followfirst):
585 586 fctxs = []
586 587 for r in revs:
587 588 ctx = repo[r]
588 589 fctxs.extend(ctx[f].introfilectx() for f in ctx.walk(match))
589 590
590 591 # When displaying a revision with --patch --follow FILE, we have
591 592 # to know which file of the revision must be diffed. With
592 593 # --follow, we want the names of the ancestors of FILE in the
593 594 # revision, stored in "fcache". "fcache" is populated as a side effect
594 595 # of the graph traversal.
595 596 fcache = {}
596 597 def filematcher(ctx):
597 598 return scmutil.matchfiles(repo, fcache.get(ctx.rev(), []))
598 599
599 600 def revgen():
600 601 for rev, cs in dagop.filectxancestors(fctxs, followfirst=followfirst):
601 602 fcache[rev] = [c.path() for c in cs]
602 603 yield rev
603 604 return smartset.generatorset(revgen(), iterasc=False), filematcher
604 605
605 606 def _makenofollowfilematcher(repo, pats, opts):
606 607 '''hook for extensions to override the filematcher for non-follow cases'''
607 608 return None
608 609
609 610 _opt2logrevset = {
610 611 'no_merges': ('not merge()', None),
611 612 'only_merges': ('merge()', None),
612 613 '_matchfiles': (None, '_matchfiles(%ps)'),
613 614 'date': ('date(%s)', None),
614 615 'branch': ('branch(%s)', '%lr'),
615 616 '_patslog': ('filelog(%s)', '%lr'),
616 617 'keyword': ('keyword(%s)', '%lr'),
617 618 'prune': ('ancestors(%s)', 'not %lr'),
618 619 'user': ('user(%s)', '%lr'),
619 620 }
620 621
621 622 def _makerevset(repo, match, pats, slowpath, opts):
622 623 """Return a revset string built from log options and file patterns"""
623 624 opts = dict(opts)
624 625 # follow or not follow?
625 626 follow = opts.get('follow') or opts.get('follow_first')
626 627
627 628 # branch and only_branch are really aliases and must be handled at
628 629 # the same time
629 630 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
630 631 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
631 632
632 633 if slowpath:
633 634 # See walkchangerevs() slow path.
634 635 #
635 636 # pats/include/exclude cannot be represented as separate
636 637 # revset expressions as their filtering logic applies at file
637 638 # level. For instance "-I a -X b" matches a revision touching
638 639 # "a" and "b" while "file(a) and not file(b)" does
639 640 # not. Besides, filesets are evaluated against the working
640 641 # directory.
641 642 matchargs = ['r:', 'd:relpath']
642 643 for p in pats:
643 644 matchargs.append('p:' + p)
644 645 for p in opts.get('include', []):
645 646 matchargs.append('i:' + p)
646 647 for p in opts.get('exclude', []):
647 648 matchargs.append('x:' + p)
648 649 opts['_matchfiles'] = matchargs
649 650 elif not follow:
650 651 opts['_patslog'] = list(pats)
651 652
652 653 expr = []
653 654 for op, val in sorted(opts.iteritems()):
654 655 if not val:
655 656 continue
656 657 if op not in _opt2logrevset:
657 658 continue
658 659 revop, listop = _opt2logrevset[op]
659 660 if revop and '%' not in revop:
660 661 expr.append(revop)
661 662 elif not listop:
662 663 expr.append(revsetlang.formatspec(revop, val))
663 664 else:
664 665 if revop:
665 666 val = [revsetlang.formatspec(revop, v) for v in val]
666 667 expr.append(revsetlang.formatspec(listop, val))
667 668
668 669 if expr:
669 670 expr = '(' + ' and '.join(expr) + ')'
670 671 else:
671 672 expr = None
672 673 return expr
673 674
674 675 def _initialrevs(repo, opts):
675 676 """Return the initial set of revisions to be filtered or followed"""
676 677 follow = opts.get('follow') or opts.get('follow_first')
677 678 if opts.get('rev'):
678 679 revs = scmutil.revrange(repo, opts['rev'])
679 680 elif follow and repo.dirstate.p1() == nullid:
680 681 revs = smartset.baseset()
681 682 elif follow:
682 683 revs = repo.revs('.')
683 684 else:
684 685 revs = smartset.spanset(repo)
685 686 revs.reverse()
686 687 return revs
687 688
688 689 def getrevs(repo, pats, opts):
689 690 """Return (revs, differ) where revs is a smartset
690 691
691 692 differ is a changesetdiffer with pre-configured file matcher.
692 693 """
693 694 follow = opts.get('follow') or opts.get('follow_first')
694 695 followfirst = opts.get('follow_first')
695 696 limit = getlimit(opts)
696 697 revs = _initialrevs(repo, opts)
697 698 if not revs:
698 699 return smartset.baseset(), None
699 700 match, pats, slowpath = _makematcher(repo, revs, pats, opts)
700 701 filematcher = None
701 702 if follow:
702 703 if slowpath or match.always():
703 704 revs = dagop.revancestors(repo, revs, followfirst=followfirst)
704 705 else:
705 706 revs, filematcher = _fileancestors(repo, revs, match, followfirst)
706 707 revs.reverse()
707 708 if filematcher is None:
708 709 filematcher = _makenofollowfilematcher(repo, pats, opts)
709 710 if filematcher is None:
710 711 def filematcher(ctx):
711 712 return match
712 713
713 714 expr = _makerevset(repo, match, pats, slowpath, opts)
714 715 if opts.get('graph') and opts.get('rev'):
715 716 # User-specified revs might be unsorted, but don't sort before
716 717 # _makerevset because it might depend on the order of revs
717 718 if not (revs.isdescending() or revs.istopo()):
718 719 revs.sort(reverse=True)
719 720 if expr:
720 721 matcher = revset.match(None, expr)
721 722 revs = matcher(repo, revs)
722 723 if limit is not None:
723 724 revs = revs.slice(0, limit)
724 725
725 726 differ = changesetdiffer()
726 727 differ._makefilematcher = filematcher
727 728 return revs, differ
728 729
729 730 def _parselinerangeopt(repo, opts):
730 731 """Parse --line-range log option and return a list of tuples (filename,
731 732 (fromline, toline)).
732 733 """
733 734 linerangebyfname = []
734 735 for pat in opts.get('line_range', []):
735 736 try:
736 737 pat, linerange = pat.rsplit(',', 1)
737 738 except ValueError:
738 739 raise error.Abort(_('malformatted line-range pattern %s') % pat)
739 740 try:
740 741 fromline, toline = map(int, linerange.split(':'))
741 742 except ValueError:
742 743 raise error.Abort(_("invalid line range for %s") % pat)
743 744 msg = _("line range pattern '%s' must match exactly one file") % pat
744 745 fname = scmutil.parsefollowlinespattern(repo, None, pat, msg)
745 746 linerangebyfname.append(
746 747 (fname, util.processlinerange(fromline, toline)))
747 748 return linerangebyfname
748 749
749 750 def getlinerangerevs(repo, userrevs, opts):
750 751 """Return (revs, differ).
751 752
752 753 "revs" are revisions obtained by processing "line-range" log options and
753 754 walking block ancestors of each specified file/line-range.
754 755
755 756 "differ" is a changesetdiffer with pre-configured file matcher and hunks
756 757 filter.
757 758 """
758 759 wctx = repo[None]
759 760
760 761 # Two-levels map of "rev -> file ctx -> [line range]".
761 762 linerangesbyrev = {}
762 763 for fname, (fromline, toline) in _parselinerangeopt(repo, opts):
763 764 if fname not in wctx:
764 765 raise error.Abort(_('cannot follow file not in parent '
765 766 'revision: "%s"') % fname)
766 767 fctx = wctx.filectx(fname)
767 768 for fctx, linerange in dagop.blockancestors(fctx, fromline, toline):
768 769 rev = fctx.introrev()
769 770 if rev not in userrevs:
770 771 continue
771 772 linerangesbyrev.setdefault(
772 773 rev, {}).setdefault(
773 774 fctx.path(), []).append(linerange)
774 775
775 776 def nofilterhunksfn(fctx, hunks):
776 777 return hunks
777 778
778 779 def hunksfilter(ctx):
779 780 fctxlineranges = linerangesbyrev.get(ctx.rev())
780 781 if fctxlineranges is None:
781 782 return nofilterhunksfn
782 783
783 784 def filterfn(fctx, hunks):
784 785 lineranges = fctxlineranges.get(fctx.path())
785 786 if lineranges is not None:
786 787 for hr, lines in hunks:
787 788 if hr is None: # binary
788 789 yield hr, lines
789 790 continue
790 791 if any(mdiff.hunkinrange(hr[2:], lr)
791 792 for lr in lineranges):
792 793 yield hr, lines
793 794 else:
794 795 for hunk in hunks:
795 796 yield hunk
796 797
797 798 return filterfn
798 799
799 800 def filematcher(ctx):
800 801 files = list(linerangesbyrev.get(ctx.rev(), []))
801 802 return scmutil.matchfiles(repo, files)
802 803
803 804 revs = sorted(linerangesbyrev, reverse=True)
804 805
805 806 differ = changesetdiffer()
806 807 differ._makefilematcher = filematcher
807 808 differ._makehunksfilter = hunksfilter
808 809 return revs, differ
809 810
810 811 def _graphnodeformatter(ui, displayer):
811 812 spec = ui.config('ui', 'graphnodetemplate')
812 813 if not spec:
813 814 return templatekw.getgraphnode # fast path for "{graphnode}"
814 815
815 816 spec = templater.unquotestring(spec)
816 817 if isinstance(displayer, changesettemplater):
817 818 # reuse cache of slow templates
818 819 tres = displayer._tresources
819 820 else:
820 821 tres = formatter.templateresources(ui)
821 822 templ = formatter.maketemplater(ui, spec, defaults=templatekw.keywords,
822 823 resources=tres)
823 824 def formatnode(repo, ctx):
824 825 props = {'ctx': ctx, 'repo': repo}
825 826 return templ.renderdefault(props)
826 827 return formatnode
827 828
828 829 def displaygraph(ui, repo, dag, displayer, edgefn, getrenamed=None, props=None):
829 830 props = props or {}
830 831 formatnode = _graphnodeformatter(ui, displayer)
831 832 state = graphmod.asciistate()
832 833 styles = state['styles']
833 834
834 835 # only set graph styling if HGPLAIN is not set.
835 836 if ui.plain('graph'):
836 837 # set all edge styles to |, the default pre-3.8 behaviour
837 838 styles.update(dict.fromkeys(styles, '|'))
838 839 else:
839 840 edgetypes = {
840 841 'parent': graphmod.PARENT,
841 842 'grandparent': graphmod.GRANDPARENT,
842 843 'missing': graphmod.MISSINGPARENT
843 844 }
844 845 for name, key in edgetypes.items():
845 846 # experimental config: experimental.graphstyle.*
846 847 styles[key] = ui.config('experimental', 'graphstyle.%s' % name,
847 848 styles[key])
848 849 if not styles[key]:
849 850 styles[key] = None
850 851
851 852 # experimental config: experimental.graphshorten
852 853 state['graphshorten'] = ui.configbool('experimental', 'graphshorten')
853 854
854 855 for rev, type, ctx, parents in dag:
855 856 char = formatnode(repo, ctx)
856 857 copies = None
857 858 if getrenamed and ctx.rev():
858 859 copies = []
859 860 for fn in ctx.files():
860 861 rename = getrenamed(fn, ctx.rev())
861 862 if rename:
862 863 copies.append((fn, rename))
863 864 edges = edgefn(type, char, state, rev, parents)
864 865 firstedge = next(edges)
865 866 width = firstedge[2]
866 867 displayer.show(ctx, copies=copies,
867 868 graphwidth=width, **pycompat.strkwargs(props))
868 869 lines = displayer.hunk.pop(rev).split('\n')
869 870 if not lines[-1]:
870 871 del lines[-1]
871 872 displayer.flush(ctx)
872 873 for type, char, width, coldata in itertools.chain([firstedge], edges):
873 874 graphmod.ascii(ui, state, type, char, lines, coldata)
874 875 lines = []
875 876 displayer.close()
876 877
877 878 def displaygraphrevs(ui, repo, revs, displayer, getrenamed):
878 879 revdag = graphmod.dagwalker(repo, revs)
879 880 displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges, getrenamed)
880 881
881 882 def displayrevs(ui, repo, revs, displayer, getrenamed):
882 883 for rev in revs:
883 884 ctx = repo[rev]
884 885 copies = None
885 886 if getrenamed is not None and rev:
886 887 copies = []
887 888 for fn in ctx.files():
888 889 rename = getrenamed(fn, rev)
889 890 if rename:
890 891 copies.append((fn, rename))
891 892 displayer.show(ctx, copies=copies)
892 893 displayer.flush(ctx)
893 894 displayer.close()
894 895
895 896 def checkunsupportedgraphflags(pats, opts):
896 897 for op in ["newest_first"]:
897 898 if op in opts and opts[op]:
898 899 raise error.Abort(_("-G/--graph option is incompatible with --%s")
899 900 % op.replace("_", "-"))
900 901
901 902 def graphrevs(repo, nodes, opts):
902 903 limit = getlimit(opts)
903 904 nodes.reverse()
904 905 if limit is not None:
905 906 nodes = nodes[:limit]
906 907 return graphmod.nodes(repo, nodes)
@@ -1,854 +1,857 b''
1 1 # templatekw.py - common changeset template keywords
2 2 #
3 3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 from .i18n import _
11 11 from .node import (
12 12 hex,
13 13 nullid,
14 wdirid,
15 wdirrev,
14 16 )
15 17
16 18 from . import (
17 19 diffutil,
18 20 encoding,
19 21 error,
20 22 hbisect,
21 23 i18n,
22 24 obsutil,
23 25 patch,
24 26 pycompat,
25 27 registrar,
26 28 scmutil,
27 29 templateutil,
28 30 util,
29 31 )
30 32 from .utils import (
31 33 stringutil,
32 34 )
33 35
34 36 _hybrid = templateutil.hybrid
35 37 hybriddict = templateutil.hybriddict
36 38 hybridlist = templateutil.hybridlist
37 39 compatdict = templateutil.compatdict
38 40 compatlist = templateutil.compatlist
39 41 _showcompatlist = templateutil._showcompatlist
40 42
41 43 def getlatesttags(context, mapping, pattern=None):
42 44 '''return date, distance and name for the latest tag of rev'''
43 45 repo = context.resource(mapping, 'repo')
44 46 ctx = context.resource(mapping, 'ctx')
45 47 cache = context.resource(mapping, 'cache')
46 48
47 49 cachename = 'latesttags'
48 50 if pattern is not None:
49 51 cachename += '-' + pattern
50 52 match = stringutil.stringmatcher(pattern)[2]
51 53 else:
52 54 match = util.always
53 55
54 56 if cachename not in cache:
55 57 # Cache mapping from rev to a tuple with tag date, tag
56 58 # distance and tag name
57 59 cache[cachename] = {-1: (0, 0, ['null'])}
58 60 latesttags = cache[cachename]
59 61
60 62 rev = ctx.rev()
61 63 todo = [rev]
62 64 while todo:
63 65 rev = todo.pop()
64 66 if rev in latesttags:
65 67 continue
66 68 ctx = repo[rev]
67 69 tags = [t for t in ctx.tags()
68 70 if (repo.tagtype(t) and repo.tagtype(t) != 'local'
69 71 and match(t))]
70 72 if tags:
71 73 latesttags[rev] = ctx.date()[0], 0, [t for t in sorted(tags)]
72 74 continue
73 75 try:
74 76 ptags = [latesttags[p.rev()] for p in ctx.parents()]
75 77 if len(ptags) > 1:
76 78 if ptags[0][2] == ptags[1][2]:
77 79 # The tuples are laid out so the right one can be found by
78 80 # comparison in this case.
79 81 pdate, pdist, ptag = max(ptags)
80 82 else:
81 83 def key(x):
82 84 changessincetag = len(repo.revs('only(%d, %s)',
83 85 ctx.rev(), x[2][0]))
84 86 # Smallest number of changes since tag wins. Date is
85 87 # used as tiebreaker.
86 88 return [-changessincetag, x[0]]
87 89 pdate, pdist, ptag = max(ptags, key=key)
88 90 else:
89 91 pdate, pdist, ptag = ptags[0]
90 92 except KeyError:
91 93 # Cache miss - recurse
92 94 todo.append(rev)
93 95 todo.extend(p.rev() for p in ctx.parents())
94 96 continue
95 97 latesttags[rev] = pdate, pdist + 1, ptag
96 98 return latesttags[rev]
97 99
98 100 def getrenamedfn(repo, endrev=None):
99 101 rcache = {}
100 102 if endrev is None:
101 103 endrev = len(repo)
102 104
103 105 def getrenamed(fn, rev):
104 106 '''looks up all renames for a file (up to endrev) the first
105 107 time the file is given. It indexes on the changerev and only
106 108 parses the manifest if linkrev != changerev.
107 109 Returns rename info for fn at changerev rev.'''
108 110 if fn not in rcache:
109 111 rcache[fn] = {}
110 112 fl = repo.file(fn)
111 113 for i in fl:
112 114 lr = fl.linkrev(i)
113 115 renamed = fl.renamed(fl.node(i))
114 116 rcache[fn][lr] = renamed and renamed[0]
115 117 if lr >= endrev:
116 118 break
117 119 if rev in rcache[fn]:
118 120 return rcache[fn][rev]
119 121
120 122 # If linkrev != rev (i.e. rev not found in rcache) fallback to
121 123 # filectx logic.
122 124 try:
123 125 renamed = repo[rev][fn].renamed()
124 126 return renamed and renamed[0]
125 127 except error.LookupError:
126 128 return None
127 129
128 130 return getrenamed
129 131
130 132 def getlogcolumns():
131 133 """Return a dict of log column labels"""
132 134 _ = pycompat.identity # temporarily disable gettext
133 135 # i18n: column positioning for "hg log"
134 136 columns = _('bookmark: %s\n'
135 137 'branch: %s\n'
136 138 'changeset: %s\n'
137 139 'copies: %s\n'
138 140 'date: %s\n'
139 141 'extra: %s=%s\n'
140 142 'files+: %s\n'
141 143 'files-: %s\n'
142 144 'files: %s\n'
143 145 'instability: %s\n'
144 146 'manifest: %s\n'
145 147 'obsolete: %s\n'
146 148 'parent: %s\n'
147 149 'phase: %s\n'
148 150 'summary: %s\n'
149 151 'tag: %s\n'
150 152 'user: %s\n')
151 153 return dict(zip([s.split(':', 1)[0] for s in columns.splitlines()],
152 154 i18n._(columns).splitlines(True)))
153 155
154 156 # default templates internally used for rendering of lists
155 157 defaulttempl = {
156 158 'parent': '{rev}:{node|formatnode} ',
157 159 'manifest': '{rev}:{node|formatnode}',
158 160 'file_copy': '{name} ({source})',
159 161 'envvar': '{key}={value}',
160 162 'extra': '{key}={value|stringescape}'
161 163 }
162 164 # filecopy is preserved for compatibility reasons
163 165 defaulttempl['filecopy'] = defaulttempl['file_copy']
164 166
165 167 # keywords are callables (see registrar.templatekeyword for details)
166 168 keywords = {}
167 169 templatekeyword = registrar.templatekeyword(keywords)
168 170
169 171 @templatekeyword('author', requires={'ctx'})
170 172 def showauthor(context, mapping):
171 173 """Alias for ``{user}``"""
172 174 return showuser(context, mapping)
173 175
174 176 @templatekeyword('bisect', requires={'repo', 'ctx'})
175 177 def showbisect(context, mapping):
176 178 """String. The changeset bisection status."""
177 179 repo = context.resource(mapping, 'repo')
178 180 ctx = context.resource(mapping, 'ctx')
179 181 return hbisect.label(repo, ctx.node())
180 182
181 183 @templatekeyword('branch', requires={'ctx'})
182 184 def showbranch(context, mapping):
183 185 """String. The name of the branch on which the changeset was
184 186 committed.
185 187 """
186 188 ctx = context.resource(mapping, 'ctx')
187 189 return ctx.branch()
188 190
189 191 @templatekeyword('branches', requires={'ctx'})
190 192 def showbranches(context, mapping):
191 193 """List of strings. The name of the branch on which the
192 194 changeset was committed. Will be empty if the branch name was
193 195 default. (DEPRECATED)
194 196 """
195 197 ctx = context.resource(mapping, 'ctx')
196 198 branch = ctx.branch()
197 199 if branch != 'default':
198 200 return compatlist(context, mapping, 'branch', [branch],
199 201 plural='branches')
200 202 return compatlist(context, mapping, 'branch', [], plural='branches')
201 203
202 204 @templatekeyword('bookmarks', requires={'repo', 'ctx'})
203 205 def showbookmarks(context, mapping):
204 206 """List of strings. Any bookmarks associated with the
205 207 changeset. Also sets 'active', the name of the active bookmark.
206 208 """
207 209 repo = context.resource(mapping, 'repo')
208 210 ctx = context.resource(mapping, 'ctx')
209 211 bookmarks = ctx.bookmarks()
210 212 active = repo._activebookmark
211 213 makemap = lambda v: {'bookmark': v, 'active': active, 'current': active}
212 214 f = _showcompatlist(context, mapping, 'bookmark', bookmarks)
213 215 return _hybrid(f, bookmarks, makemap, pycompat.identity)
214 216
215 217 @templatekeyword('children', requires={'ctx'})
216 218 def showchildren(context, mapping):
217 219 """List of strings. The children of the changeset."""
218 220 ctx = context.resource(mapping, 'ctx')
219 221 childrevs = ['%d:%s' % (cctx.rev(), cctx) for cctx in ctx.children()]
220 222 return compatlist(context, mapping, 'children', childrevs, element='child')
221 223
222 224 # Deprecated, but kept alive for help generation a purpose.
223 225 @templatekeyword('currentbookmark', requires={'repo', 'ctx'})
224 226 def showcurrentbookmark(context, mapping):
225 227 """String. The active bookmark, if it is associated with the changeset.
226 228 (DEPRECATED)"""
227 229 return showactivebookmark(context, mapping)
228 230
229 231 @templatekeyword('activebookmark', requires={'repo', 'ctx'})
230 232 def showactivebookmark(context, mapping):
231 233 """String. The active bookmark, if it is associated with the changeset."""
232 234 repo = context.resource(mapping, 'repo')
233 235 ctx = context.resource(mapping, 'ctx')
234 236 active = repo._activebookmark
235 237 if active and active in ctx.bookmarks():
236 238 return active
237 239 return ''
238 240
239 241 @templatekeyword('date', requires={'ctx'})
240 242 def showdate(context, mapping):
241 243 """Date information. The date when the changeset was committed."""
242 244 ctx = context.resource(mapping, 'ctx')
243 245 # the default string format is '<float(unixtime)><tzoffset>' because
244 246 # python-hglib splits date at decimal separator.
245 247 return templateutil.date(ctx.date(), showfmt='%d.0%d')
246 248
247 249 @templatekeyword('desc', requires={'ctx'})
248 250 def showdescription(context, mapping):
249 251 """String. The text of the changeset description."""
250 252 ctx = context.resource(mapping, 'ctx')
251 253 s = ctx.description()
252 254 if isinstance(s, encoding.localstr):
253 255 # try hard to preserve utf-8 bytes
254 256 return encoding.tolocal(encoding.fromlocal(s).strip())
255 257 elif isinstance(s, encoding.safelocalstr):
256 258 return encoding.safelocalstr(s.strip())
257 259 else:
258 260 return s.strip()
259 261
260 262 @templatekeyword('diffstat', requires={'ui', 'ctx'})
261 263 def showdiffstat(context, mapping):
262 264 """String. Statistics of changes with the following format:
263 265 "modified files: +added/-removed lines"
264 266 """
265 267 ui = context.resource(mapping, 'ui')
266 268 ctx = context.resource(mapping, 'ctx')
267 269 diffopts = diffutil.diffallopts(ui, {'noprefix': False})
268 270 diff = ctx.diff(opts=diffopts)
269 271 stats = patch.diffstatdata(util.iterlines(diff))
270 272 maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats)
271 273 return '%d: +%d/-%d' % (len(stats), adds, removes)
272 274
273 275 @templatekeyword('envvars', requires={'ui'})
274 276 def showenvvars(context, mapping):
275 277 """A dictionary of environment variables. (EXPERIMENTAL)"""
276 278 ui = context.resource(mapping, 'ui')
277 279 env = ui.exportableenviron()
278 280 env = util.sortdict((k, env[k]) for k in sorted(env))
279 281 return compatdict(context, mapping, 'envvar', env, plural='envvars')
280 282
281 283 @templatekeyword('extras', requires={'ctx'})
282 284 def showextras(context, mapping):
283 285 """List of dicts with key, value entries of the 'extras'
284 286 field of this changeset."""
285 287 ctx = context.resource(mapping, 'ctx')
286 288 extras = ctx.extra()
287 289 extras = util.sortdict((k, extras[k]) for k in sorted(extras))
288 290 makemap = lambda k: {'key': k, 'value': extras[k]}
289 291 c = [makemap(k) for k in extras]
290 292 f = _showcompatlist(context, mapping, 'extra', c, plural='extras')
291 293 return _hybrid(f, extras, makemap,
292 294 lambda k: '%s=%s' % (k, stringutil.escapestr(extras[k])))
293 295
294 296 def _getfilestatus(context, mapping, listall=False):
295 297 ctx = context.resource(mapping, 'ctx')
296 298 revcache = context.resource(mapping, 'revcache')
297 299 if 'filestatus' not in revcache or revcache['filestatusall'] < listall:
298 300 stat = ctx.p1().status(ctx, listignored=listall, listclean=listall,
299 301 listunknown=listall)
300 302 revcache['filestatus'] = stat
301 303 revcache['filestatusall'] = listall
302 304 return revcache['filestatus']
303 305
304 306 def _getfilestatusmap(context, mapping, listall=False):
305 307 revcache = context.resource(mapping, 'revcache')
306 308 if 'filestatusmap' not in revcache or revcache['filestatusall'] < listall:
307 309 stat = _getfilestatus(context, mapping, listall=listall)
308 310 revcache['filestatusmap'] = statmap = {}
309 311 for char, files in zip(pycompat.iterbytestr('MAR!?IC'), stat):
310 312 statmap.update((f, char) for f in files)
311 313 return revcache['filestatusmap'] # {path: statchar}
312 314
313 315 def _showfilesbystat(context, mapping, name, index):
314 316 stat = _getfilestatus(context, mapping)
315 317 files = stat[index]
316 318 return templateutil.compatfileslist(context, mapping, name, files)
317 319
318 320 @templatekeyword('file_adds', requires={'ctx', 'revcache'})
319 321 def showfileadds(context, mapping):
320 322 """List of strings. Files added by this changeset."""
321 323 return _showfilesbystat(context, mapping, 'file_add', 1)
322 324
323 325 @templatekeyword('file_copies',
324 326 requires={'repo', 'ctx', 'cache', 'revcache'})
325 327 def showfilecopies(context, mapping):
326 328 """List of strings. Files copied in this changeset with
327 329 their sources.
328 330 """
329 331 repo = context.resource(mapping, 'repo')
330 332 ctx = context.resource(mapping, 'ctx')
331 333 cache = context.resource(mapping, 'cache')
332 334 copies = context.resource(mapping, 'revcache').get('copies')
333 335 if copies is None:
334 336 if 'getrenamed' not in cache:
335 337 cache['getrenamed'] = getrenamedfn(repo)
336 338 copies = []
337 339 getrenamed = cache['getrenamed']
338 340 for fn in ctx.files():
339 341 rename = getrenamed(fn, ctx.rev())
340 342 if rename:
341 343 copies.append((fn, rename))
342 344 return templateutil.compatfilecopiesdict(context, mapping, 'file_copy',
343 345 copies)
344 346
345 347 # showfilecopiesswitch() displays file copies only if copy records are
346 348 # provided before calling the templater, usually with a --copies
347 349 # command line switch.
348 350 @templatekeyword('file_copies_switch', requires={'revcache'})
349 351 def showfilecopiesswitch(context, mapping):
350 352 """List of strings. Like "file_copies" but displayed
351 353 only if the --copied switch is set.
352 354 """
353 355 copies = context.resource(mapping, 'revcache').get('copies') or []
354 356 return templateutil.compatfilecopiesdict(context, mapping, 'file_copy',
355 357 copies)
356 358
357 359 @templatekeyword('file_dels', requires={'ctx', 'revcache'})
358 360 def showfiledels(context, mapping):
359 361 """List of strings. Files removed by this changeset."""
360 362 return _showfilesbystat(context, mapping, 'file_del', 2)
361 363
362 364 @templatekeyword('file_mods', requires={'ctx', 'revcache'})
363 365 def showfilemods(context, mapping):
364 366 """List of strings. Files modified by this changeset."""
365 367 return _showfilesbystat(context, mapping, 'file_mod', 0)
366 368
367 369 @templatekeyword('files', requires={'ctx'})
368 370 def showfiles(context, mapping):
369 371 """List of strings. All files modified, added, or removed by this
370 372 changeset.
371 373 """
372 374 ctx = context.resource(mapping, 'ctx')
373 375 return templateutil.compatfileslist(context, mapping, 'file', ctx.files())
374 376
375 377 @templatekeyword('graphnode', requires={'repo', 'ctx'})
376 378 def showgraphnode(context, mapping):
377 379 """String. The character representing the changeset node in an ASCII
378 380 revision graph."""
379 381 repo = context.resource(mapping, 'repo')
380 382 ctx = context.resource(mapping, 'ctx')
381 383 return getgraphnode(repo, ctx)
382 384
383 385 def getgraphnode(repo, ctx):
384 386 return getgraphnodecurrent(repo, ctx) or getgraphnodesymbol(ctx)
385 387
386 388 def getgraphnodecurrent(repo, ctx):
387 389 wpnodes = repo.dirstate.parents()
388 390 if wpnodes[1] == nullid:
389 391 wpnodes = wpnodes[:1]
390 392 if ctx.node() in wpnodes:
391 393 return '@'
392 394 else:
393 395 return ''
394 396
395 397 def getgraphnodesymbol(ctx):
396 398 if ctx.obsolete():
397 399 return 'x'
398 400 elif ctx.isunstable():
399 401 return '*'
400 402 elif ctx.closesbranch():
401 403 return '_'
402 404 else:
403 405 return 'o'
404 406
405 407 @templatekeyword('graphwidth', requires=())
406 408 def showgraphwidth(context, mapping):
407 409 """Integer. The width of the graph drawn by 'log --graph' or zero."""
408 410 # just hosts documentation; should be overridden by template mapping
409 411 return 0
410 412
411 413 @templatekeyword('index', requires=())
412 414 def showindex(context, mapping):
413 415 """Integer. The current iteration of the loop. (0 indexed)"""
414 416 # just hosts documentation; should be overridden by template mapping
415 417 raise error.Abort(_("can't use index in this context"))
416 418
417 419 @templatekeyword('latesttag', requires={'repo', 'ctx', 'cache'})
418 420 def showlatesttag(context, mapping):
419 421 """List of strings. The global tags on the most recent globally
420 422 tagged ancestor of this changeset. If no such tags exist, the list
421 423 consists of the single string "null".
422 424 """
423 425 return showlatesttags(context, mapping, None)
424 426
425 427 def showlatesttags(context, mapping, pattern):
426 428 """helper method for the latesttag keyword and function"""
427 429 latesttags = getlatesttags(context, mapping, pattern)
428 430
429 431 # latesttag[0] is an implementation detail for sorting csets on different
430 432 # branches in a stable manner- it is the date the tagged cset was created,
431 433 # not the date the tag was created. Therefore it isn't made visible here.
432 434 makemap = lambda v: {
433 435 'changes': _showchangessincetag,
434 436 'distance': latesttags[1],
435 437 'latesttag': v, # BC with {latesttag % '{latesttag}'}
436 438 'tag': v
437 439 }
438 440
439 441 tags = latesttags[2]
440 442 f = _showcompatlist(context, mapping, 'latesttag', tags, separator=':')
441 443 return _hybrid(f, tags, makemap, pycompat.identity)
442 444
443 445 @templatekeyword('latesttagdistance', requires={'repo', 'ctx', 'cache'})
444 446 def showlatesttagdistance(context, mapping):
445 447 """Integer. Longest path to the latest tag."""
446 448 return getlatesttags(context, mapping)[1]
447 449
448 450 @templatekeyword('changessincelatesttag', requires={'repo', 'ctx', 'cache'})
449 451 def showchangessincelatesttag(context, mapping):
450 452 """Integer. All ancestors not in the latest tag."""
451 453 tag = getlatesttags(context, mapping)[2][0]
452 454 mapping = context.overlaymap(mapping, {'tag': tag})
453 455 return _showchangessincetag(context, mapping)
454 456
455 457 def _showchangessincetag(context, mapping):
456 458 repo = context.resource(mapping, 'repo')
457 459 ctx = context.resource(mapping, 'ctx')
458 460 offset = 0
459 461 revs = [ctx.rev()]
460 462 tag = context.symbol(mapping, 'tag')
461 463
462 464 # The only() revset doesn't currently support wdir()
463 465 if ctx.rev() is None:
464 466 offset = 1
465 467 revs = [p.rev() for p in ctx.parents()]
466 468
467 469 return len(repo.revs('only(%ld, %s)', revs, tag)) + offset
468 470
469 471 # teach templater latesttags.changes is switched to (context, mapping) API
470 472 _showchangessincetag._requires = {'repo', 'ctx'}
471 473
472 474 @templatekeyword('manifest', requires={'repo', 'ctx'})
473 475 def showmanifest(context, mapping):
474 476 repo = context.resource(mapping, 'repo')
475 477 ctx = context.resource(mapping, 'ctx')
476 478 mnode = ctx.manifestnode()
477 479 if mnode is None:
478 # just avoid crash, we might want to use the 'ff...' hash in future
479 return
480 mrev = repo.manifestlog.rev(mnode)
480 mnode = wdirid
481 mrev = wdirrev
482 else:
483 mrev = repo.manifestlog.rev(mnode)
481 484 mhex = hex(mnode)
482 485 mapping = context.overlaymap(mapping, {'rev': mrev, 'node': mhex})
483 486 f = context.process('manifest', mapping)
484 487 return templateutil.hybriditem(f, None, f,
485 488 lambda x: {'rev': mrev, 'node': mhex})
486 489
487 490 @templatekeyword('obsfate', requires={'ui', 'repo', 'ctx'})
488 491 def showobsfate(context, mapping):
489 492 # this function returns a list containing pre-formatted obsfate strings.
490 493 #
491 494 # This function will be replaced by templates fragments when we will have
492 495 # the verbosity templatekw available.
493 496 succsandmarkers = showsuccsandmarkers(context, mapping)
494 497
495 498 ui = context.resource(mapping, 'ui')
496 499 repo = context.resource(mapping, 'repo')
497 500 values = []
498 501
499 502 for x in succsandmarkers.tovalue(context, mapping):
500 503 v = obsutil.obsfateprinter(ui, repo, x['successors'], x['markers'],
501 504 scmutil.formatchangeid)
502 505 values.append(v)
503 506
504 507 return compatlist(context, mapping, "fate", values)
505 508
506 509 def shownames(context, mapping, namespace):
507 510 """helper method to generate a template keyword for a namespace"""
508 511 repo = context.resource(mapping, 'repo')
509 512 ctx = context.resource(mapping, 'ctx')
510 513 ns = repo.names[namespace]
511 514 names = ns.names(repo, ctx.node())
512 515 return compatlist(context, mapping, ns.templatename, names,
513 516 plural=namespace)
514 517
515 518 @templatekeyword('namespaces', requires={'repo', 'ctx'})
516 519 def shownamespaces(context, mapping):
517 520 """Dict of lists. Names attached to this changeset per
518 521 namespace."""
519 522 repo = context.resource(mapping, 'repo')
520 523 ctx = context.resource(mapping, 'ctx')
521 524
522 525 namespaces = util.sortdict()
523 526 def makensmapfn(ns):
524 527 # 'name' for iterating over namespaces, templatename for local reference
525 528 return lambda v: {'name': v, ns.templatename: v}
526 529
527 530 for k, ns in repo.names.iteritems():
528 531 names = ns.names(repo, ctx.node())
529 532 f = _showcompatlist(context, mapping, 'name', names)
530 533 namespaces[k] = _hybrid(f, names, makensmapfn(ns), pycompat.identity)
531 534
532 535 f = _showcompatlist(context, mapping, 'namespace', list(namespaces))
533 536
534 537 def makemap(ns):
535 538 return {
536 539 'namespace': ns,
537 540 'names': namespaces[ns],
538 541 'builtin': repo.names[ns].builtin,
539 542 'colorname': repo.names[ns].colorname,
540 543 }
541 544
542 545 return _hybrid(f, namespaces, makemap, pycompat.identity)
543 546
544 547 @templatekeyword('node', requires={'ctx'})
545 548 def shownode(context, mapping):
546 549 """String. The changeset identification hash, as a 40 hexadecimal
547 550 digit string.
548 551 """
549 552 ctx = context.resource(mapping, 'ctx')
550 553 return ctx.hex()
551 554
552 555 @templatekeyword('obsolete', requires={'ctx'})
553 556 def showobsolete(context, mapping):
554 557 """String. Whether the changeset is obsolete. (EXPERIMENTAL)"""
555 558 ctx = context.resource(mapping, 'ctx')
556 559 if ctx.obsolete():
557 560 return 'obsolete'
558 561 return ''
559 562
560 563 @templatekeyword('path', requires={'fctx'})
561 564 def showpath(context, mapping):
562 565 """String. Repository-absolute path of the current file. (EXPERIMENTAL)"""
563 566 fctx = context.resource(mapping, 'fctx')
564 567 return fctx.path()
565 568
566 569 @templatekeyword('peerurls', requires={'repo'})
567 570 def showpeerurls(context, mapping):
568 571 """A dictionary of repository locations defined in the [paths] section
569 572 of your configuration file."""
570 573 repo = context.resource(mapping, 'repo')
571 574 # see commands.paths() for naming of dictionary keys
572 575 paths = repo.ui.paths
573 576 urls = util.sortdict((k, p.rawloc) for k, p in sorted(paths.iteritems()))
574 577 def makemap(k):
575 578 p = paths[k]
576 579 d = {'name': k, 'url': p.rawloc}
577 580 d.update((o, v) for o, v in sorted(p.suboptions.iteritems()))
578 581 return d
579 582 return _hybrid(None, urls, makemap, lambda k: '%s=%s' % (k, urls[k]))
580 583
581 584 @templatekeyword("predecessors", requires={'repo', 'ctx'})
582 585 def showpredecessors(context, mapping):
583 586 """Returns the list if the closest visible successors. (EXPERIMENTAL)"""
584 587 repo = context.resource(mapping, 'repo')
585 588 ctx = context.resource(mapping, 'ctx')
586 589 predecessors = sorted(obsutil.closestpredecessors(repo, ctx.node()))
587 590 predecessors = pycompat.maplist(hex, predecessors)
588 591
589 592 return _hybrid(None, predecessors,
590 593 lambda x: {'ctx': repo[x]},
591 594 lambda x: scmutil.formatchangeid(repo[x]))
592 595
593 596 @templatekeyword('reporoot', requires={'repo'})
594 597 def showreporoot(context, mapping):
595 598 """String. The root directory of the current repository."""
596 599 repo = context.resource(mapping, 'repo')
597 600 return repo.root
598 601
599 602 @templatekeyword('size', requires={'fctx'})
600 603 def showsize(context, mapping):
601 604 """Integer. Size of the current file in bytes. (EXPERIMENTAL)"""
602 605 fctx = context.resource(mapping, 'fctx')
603 606 return fctx.size()
604 607
605 608 # requires 'fctx' to denote {status} depends on (ctx, path) pair
606 609 @templatekeyword('status', requires={'ctx', 'fctx', 'revcache'})
607 610 def showstatus(context, mapping):
608 611 """String. Status code of the current file. (EXPERIMENTAL)"""
609 612 path = templateutil.runsymbol(context, mapping, 'path')
610 613 path = templateutil.stringify(context, mapping, path)
611 614 if not path:
612 615 return
613 616 statmap = _getfilestatusmap(context, mapping)
614 617 if path not in statmap:
615 618 statmap = _getfilestatusmap(context, mapping, listall=True)
616 619 return statmap.get(path)
617 620
618 621 @templatekeyword("successorssets", requires={'repo', 'ctx'})
619 622 def showsuccessorssets(context, mapping):
620 623 """Returns a string of sets of successors for a changectx. Format used
621 624 is: [ctx1, ctx2], [ctx3] if ctx has been splitted into ctx1 and ctx2
622 625 while also diverged into ctx3. (EXPERIMENTAL)"""
623 626 repo = context.resource(mapping, 'repo')
624 627 ctx = context.resource(mapping, 'ctx')
625 628 if not ctx.obsolete():
626 629 return ''
627 630
628 631 ssets = obsutil.successorssets(repo, ctx.node(), closest=True)
629 632 ssets = [[hex(n) for n in ss] for ss in ssets]
630 633
631 634 data = []
632 635 for ss in ssets:
633 636 h = _hybrid(None, ss, lambda x: {'ctx': repo[x]},
634 637 lambda x: scmutil.formatchangeid(repo[x]))
635 638 data.append(h)
636 639
637 640 # Format the successorssets
638 641 def render(d):
639 642 return templateutil.stringify(context, mapping, d)
640 643
641 644 def gen(data):
642 645 yield "; ".join(render(d) for d in data)
643 646
644 647 return _hybrid(gen(data), data, lambda x: {'successorset': x},
645 648 pycompat.identity)
646 649
647 650 @templatekeyword("succsandmarkers", requires={'repo', 'ctx'})
648 651 def showsuccsandmarkers(context, mapping):
649 652 """Returns a list of dict for each final successor of ctx. The dict
650 653 contains successors node id in "successors" keys and the list of
651 654 obs-markers from ctx to the set of successors in "markers".
652 655 (EXPERIMENTAL)
653 656 """
654 657 repo = context.resource(mapping, 'repo')
655 658 ctx = context.resource(mapping, 'ctx')
656 659
657 660 values = obsutil.successorsandmarkers(repo, ctx)
658 661
659 662 if values is None:
660 663 values = []
661 664
662 665 # Format successors and markers to avoid exposing binary to templates
663 666 data = []
664 667 for i in values:
665 668 # Format successors
666 669 successors = i['successors']
667 670
668 671 successors = [hex(n) for n in successors]
669 672 successors = _hybrid(None, successors,
670 673 lambda x: {'ctx': repo[x]},
671 674 lambda x: scmutil.formatchangeid(repo[x]))
672 675
673 676 # Format markers
674 677 finalmarkers = []
675 678 for m in i['markers']:
676 679 hexprec = hex(m[0])
677 680 hexsucs = tuple(hex(n) for n in m[1])
678 681 hexparents = None
679 682 if m[5] is not None:
680 683 hexparents = tuple(hex(n) for n in m[5])
681 684 newmarker = (hexprec, hexsucs) + m[2:5] + (hexparents,) + m[6:]
682 685 finalmarkers.append(newmarker)
683 686
684 687 data.append({'successors': successors, 'markers': finalmarkers})
685 688
686 689 return templateutil.mappinglist(data)
687 690
688 691 @templatekeyword('p1rev', requires={'ctx'})
689 692 def showp1rev(context, mapping):
690 693 """Integer. The repository-local revision number of the changeset's
691 694 first parent, or -1 if the changeset has no parents."""
692 695 ctx = context.resource(mapping, 'ctx')
693 696 return ctx.p1().rev()
694 697
695 698 @templatekeyword('p2rev', requires={'ctx'})
696 699 def showp2rev(context, mapping):
697 700 """Integer. The repository-local revision number of the changeset's
698 701 second parent, or -1 if the changeset has no second parent."""
699 702 ctx = context.resource(mapping, 'ctx')
700 703 return ctx.p2().rev()
701 704
702 705 @templatekeyword('p1node', requires={'ctx'})
703 706 def showp1node(context, mapping):
704 707 """String. The identification hash of the changeset's first parent,
705 708 as a 40 digit hexadecimal string. If the changeset has no parents, all
706 709 digits are 0."""
707 710 ctx = context.resource(mapping, 'ctx')
708 711 return ctx.p1().hex()
709 712
710 713 @templatekeyword('p2node', requires={'ctx'})
711 714 def showp2node(context, mapping):
712 715 """String. The identification hash of the changeset's second
713 716 parent, as a 40 digit hexadecimal string. If the changeset has no second
714 717 parent, all digits are 0."""
715 718 ctx = context.resource(mapping, 'ctx')
716 719 return ctx.p2().hex()
717 720
718 721 @templatekeyword('parents', requires={'repo', 'ctx'})
719 722 def showparents(context, mapping):
720 723 """List of strings. The parents of the changeset in "rev:node"
721 724 format. If the changeset has only one "natural" parent (the predecessor
722 725 revision) nothing is shown."""
723 726 repo = context.resource(mapping, 'repo')
724 727 ctx = context.resource(mapping, 'ctx')
725 728 pctxs = scmutil.meaningfulparents(repo, ctx)
726 729 prevs = [p.rev() for p in pctxs]
727 730 parents = [[('rev', p.rev()),
728 731 ('node', p.hex()),
729 732 ('phase', p.phasestr())]
730 733 for p in pctxs]
731 734 f = _showcompatlist(context, mapping, 'parent', parents)
732 735 return _hybrid(f, prevs, lambda x: {'ctx': repo[x]},
733 736 lambda x: scmutil.formatchangeid(repo[x]), keytype=int)
734 737
735 738 @templatekeyword('phase', requires={'ctx'})
736 739 def showphase(context, mapping):
737 740 """String. The changeset phase name."""
738 741 ctx = context.resource(mapping, 'ctx')
739 742 return ctx.phasestr()
740 743
741 744 @templatekeyword('phaseidx', requires={'ctx'})
742 745 def showphaseidx(context, mapping):
743 746 """Integer. The changeset phase index. (ADVANCED)"""
744 747 ctx = context.resource(mapping, 'ctx')
745 748 return ctx.phase()
746 749
747 750 @templatekeyword('rev', requires={'ctx'})
748 751 def showrev(context, mapping):
749 752 """Integer. The repository-local changeset revision number."""
750 753 ctx = context.resource(mapping, 'ctx')
751 754 return scmutil.intrev(ctx)
752 755
753 756 def showrevslist(context, mapping, name, revs):
754 757 """helper to generate a list of revisions in which a mapped template will
755 758 be evaluated"""
756 759 repo = context.resource(mapping, 'repo')
757 760 f = _showcompatlist(context, mapping, name, ['%d' % r for r in revs])
758 761 return _hybrid(f, revs,
759 762 lambda x: {name: x, 'ctx': repo[x]},
760 763 pycompat.identity, keytype=int)
761 764
762 765 @templatekeyword('subrepos', requires={'ctx'})
763 766 def showsubrepos(context, mapping):
764 767 """List of strings. Updated subrepositories in the changeset."""
765 768 ctx = context.resource(mapping, 'ctx')
766 769 substate = ctx.substate
767 770 if not substate:
768 771 return compatlist(context, mapping, 'subrepo', [])
769 772 psubstate = ctx.parents()[0].substate or {}
770 773 subrepos = []
771 774 for sub in substate:
772 775 if sub not in psubstate or substate[sub] != psubstate[sub]:
773 776 subrepos.append(sub) # modified or newly added in ctx
774 777 for sub in psubstate:
775 778 if sub not in substate:
776 779 subrepos.append(sub) # removed in ctx
777 780 return compatlist(context, mapping, 'subrepo', sorted(subrepos))
778 781
779 782 # don't remove "showtags" definition, even though namespaces will put
780 783 # a helper function for "tags" keyword into "keywords" map automatically,
781 784 # because online help text is built without namespaces initialization
782 785 @templatekeyword('tags', requires={'repo', 'ctx'})
783 786 def showtags(context, mapping):
784 787 """List of strings. Any tags associated with the changeset."""
785 788 return shownames(context, mapping, 'tags')
786 789
787 790 @templatekeyword('termwidth', requires={'ui'})
788 791 def showtermwidth(context, mapping):
789 792 """Integer. The width of the current terminal."""
790 793 ui = context.resource(mapping, 'ui')
791 794 return ui.termwidth()
792 795
793 796 @templatekeyword('user', requires={'ctx'})
794 797 def showuser(context, mapping):
795 798 """String. The unmodified author of the changeset."""
796 799 ctx = context.resource(mapping, 'ctx')
797 800 return ctx.user()
798 801
799 802 @templatekeyword('instabilities', requires={'ctx'})
800 803 def showinstabilities(context, mapping):
801 804 """List of strings. Evolution instabilities affecting the changeset.
802 805 (EXPERIMENTAL)
803 806 """
804 807 ctx = context.resource(mapping, 'ctx')
805 808 return compatlist(context, mapping, 'instability', ctx.instabilities(),
806 809 plural='instabilities')
807 810
808 811 @templatekeyword('verbosity', requires={'ui'})
809 812 def showverbosity(context, mapping):
810 813 """String. The current output verbosity in 'debug', 'quiet', 'verbose',
811 814 or ''."""
812 815 ui = context.resource(mapping, 'ui')
813 816 # see logcmdutil.changesettemplater for priority of these flags
814 817 if ui.debugflag:
815 818 return 'debug'
816 819 elif ui.quiet:
817 820 return 'quiet'
818 821 elif ui.verbose:
819 822 return 'verbose'
820 823 return ''
821 824
822 825 @templatekeyword('whyunstable', requires={'repo', 'ctx'})
823 826 def showwhyunstable(context, mapping):
824 827 """List of dicts explaining all instabilities of a changeset.
825 828 (EXPERIMENTAL)
826 829 """
827 830 repo = context.resource(mapping, 'repo')
828 831 ctx = context.resource(mapping, 'ctx')
829 832
830 833 def formatnode(ctx):
831 834 return '%s (%s)' % (scmutil.formatchangeid(ctx), ctx.phasestr())
832 835
833 836 entries = obsutil.whyunstable(repo, ctx)
834 837
835 838 for entry in entries:
836 839 if entry.get('divergentnodes'):
837 840 dnodes = entry['divergentnodes']
838 841 dnhybrid = _hybrid(None, [dnode.hex() for dnode in dnodes],
839 842 lambda x: {'ctx': repo[x]},
840 843 lambda x: formatnode(repo[x]))
841 844 entry['divergentnodes'] = dnhybrid
842 845
843 846 tmpl = ('{instability}:{if(divergentnodes, " ")}{divergentnodes} '
844 847 '{reason} {node|short}')
845 848 return templateutil.mappinglist(entries, tmpl=tmpl, sep='\n')
846 849
847 850 def loadkeyword(ui, extname, registrarobj):
848 851 """Load template keyword from specified registrarobj
849 852 """
850 853 for name, func in registrarobj._table.iteritems():
851 854 keywords[name] = func
852 855
853 856 # tell hggettext to extract docstrings from these functions:
854 857 i18nfunctions = keywords.values()
@@ -1,2637 +1,2639 b''
1 1 Log on empty repository: checking consistency
2 2
3 3 $ hg init empty
4 4 $ cd empty
5 5 $ hg log
6 6 $ hg log -r 1
7 7 abort: unknown revision '1'!
8 8 [255]
9 9 $ hg log -r -1:0
10 10 abort: unknown revision '-1'!
11 11 [255]
12 12 $ hg log -r 'branch(name)'
13 13 abort: unknown revision 'name'!
14 14 [255]
15 15 $ hg log -r null -q
16 16 -1:000000000000
17 17
18 18 $ cd ..
19 19
20 20 The g is crafted to have 2 filelog topological heads in a linear
21 21 changeset graph
22 22
23 23 $ hg init a
24 24 $ cd a
25 25 $ echo a > a
26 26 $ echo f > f
27 27 $ hg ci -Ama -d '1 0'
28 28 adding a
29 29 adding f
30 30
31 31 $ hg cp a b
32 32 $ hg cp f g
33 33 $ hg ci -mb -d '2 0'
34 34
35 35 $ mkdir dir
36 36 $ hg mv b dir
37 37 $ echo g >> g
38 38 $ echo f >> f
39 39 $ hg ci -mc -d '3 0'
40 40
41 41 $ hg mv a b
42 42 $ hg cp -f f g
43 43 $ echo a > d
44 44 $ hg add d
45 45 $ hg ci -md -d '4 0'
46 46
47 47 $ hg mv dir/b e
48 48 $ hg ci -me -d '5 0'
49 49
50 50 Make sure largefiles doesn't interfere with logging a regular file
51 51 $ hg --debug log a -T '{rev}: {desc}\n' --config extensions.largefiles=
52 52 The fsmonitor extension is incompatible with the largefiles extension and has been disabled. (fsmonitor !)
53 53 updated patterns: .hglf/a, a
54 54 0: a
55 55 $ hg log a
56 56 changeset: 0:9161b9aeaf16
57 57 user: test
58 58 date: Thu Jan 01 00:00:01 1970 +0000
59 59 summary: a
60 60
61 61 $ hg log glob:a*
62 62 changeset: 3:2ca5ba701980
63 63 user: test
64 64 date: Thu Jan 01 00:00:04 1970 +0000
65 65 summary: d
66 66
67 67 changeset: 0:9161b9aeaf16
68 68 user: test
69 69 date: Thu Jan 01 00:00:01 1970 +0000
70 70 summary: a
71 71
72 72 $ hg --debug log glob:a* -T '{rev}: {desc}\n' --config extensions.largefiles=
73 73 The fsmonitor extension is incompatible with the largefiles extension and has been disabled. (fsmonitor !)
74 74 updated patterns: glob:.hglf/a*, glob:a*
75 75 3: d
76 76 0: a
77 77
78 78 log on directory
79 79
80 80 $ hg log dir
81 81 changeset: 4:7e4639b4691b
82 82 tag: tip
83 83 user: test
84 84 date: Thu Jan 01 00:00:05 1970 +0000
85 85 summary: e
86 86
87 87 changeset: 2:f8954cd4dc1f
88 88 user: test
89 89 date: Thu Jan 01 00:00:03 1970 +0000
90 90 summary: c
91 91
92 92 $ hg log somethingthatdoesntexist dir
93 93 changeset: 4:7e4639b4691b
94 94 tag: tip
95 95 user: test
96 96 date: Thu Jan 01 00:00:05 1970 +0000
97 97 summary: e
98 98
99 99 changeset: 2:f8954cd4dc1f
100 100 user: test
101 101 date: Thu Jan 01 00:00:03 1970 +0000
102 102 summary: c
103 103
104 104
105 105 -X, with explicit path
106 106
107 107 $ hg log a -X a
108 108
109 109 -f, non-existent directory
110 110
111 111 $ hg log -f dir
112 112 abort: cannot follow file not in parent revision: "dir"
113 113 [255]
114 114
115 115 -f, directory
116 116
117 117 $ hg up -q 3
118 118 $ hg log -f dir
119 119 changeset: 2:f8954cd4dc1f
120 120 user: test
121 121 date: Thu Jan 01 00:00:03 1970 +0000
122 122 summary: c
123 123
124 124 -f, directory with --patch
125 125
126 126 $ hg log -f dir -p
127 127 changeset: 2:f8954cd4dc1f
128 128 user: test
129 129 date: Thu Jan 01 00:00:03 1970 +0000
130 130 summary: c
131 131
132 132 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
133 133 --- /dev/null* (glob)
134 134 +++ b/dir/b* (glob)
135 135 @@ -0,0 +1,1 @@
136 136 +a
137 137
138 138
139 139 -f, pattern
140 140
141 141 $ hg log -f -I 'dir**' -p
142 142 changeset: 2:f8954cd4dc1f
143 143 user: test
144 144 date: Thu Jan 01 00:00:03 1970 +0000
145 145 summary: c
146 146
147 147 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
148 148 --- /dev/null* (glob)
149 149 +++ b/dir/b* (glob)
150 150 @@ -0,0 +1,1 @@
151 151 +a
152 152
153 153 $ hg up -q 4
154 154
155 155 -f, a wrong style
156 156
157 157 $ hg log -f -l1 --style something
158 158 abort: style 'something' not found
159 159 (available styles: bisect, changelog, compact, default, phases, show, status, xml)
160 160 [255]
161 161
162 162 -f, phases style
163 163
164 164
165 165 $ hg log -f -l1 --style phases
166 166 changeset: 4:7e4639b4691b
167 167 tag: tip
168 168 phase: draft
169 169 user: test
170 170 date: Thu Jan 01 00:00:05 1970 +0000
171 171 summary: e
172 172
173 173
174 174 $ hg log -f -l1 --style phases -q
175 175 4:7e4639b4691b
176 176
177 177 -f, but no args
178 178
179 179 $ hg log -f
180 180 changeset: 4:7e4639b4691b
181 181 tag: tip
182 182 user: test
183 183 date: Thu Jan 01 00:00:05 1970 +0000
184 184 summary: e
185 185
186 186 changeset: 3:2ca5ba701980
187 187 user: test
188 188 date: Thu Jan 01 00:00:04 1970 +0000
189 189 summary: d
190 190
191 191 changeset: 2:f8954cd4dc1f
192 192 user: test
193 193 date: Thu Jan 01 00:00:03 1970 +0000
194 194 summary: c
195 195
196 196 changeset: 1:d89b0a12d229
197 197 user: test
198 198 date: Thu Jan 01 00:00:02 1970 +0000
199 199 summary: b
200 200
201 201 changeset: 0:9161b9aeaf16
202 202 user: test
203 203 date: Thu Jan 01 00:00:01 1970 +0000
204 204 summary: a
205 205
206 206
207 207 one rename
208 208
209 209 $ hg up -q 2
210 210 $ hg log -vf a
211 211 changeset: 0:9161b9aeaf16
212 212 user: test
213 213 date: Thu Jan 01 00:00:01 1970 +0000
214 214 files: a f
215 215 description:
216 216 a
217 217
218 218
219 219
220 220 many renames
221 221
222 222 $ hg up -q tip
223 223 $ hg log -vf e
224 224 changeset: 4:7e4639b4691b
225 225 tag: tip
226 226 user: test
227 227 date: Thu Jan 01 00:00:05 1970 +0000
228 228 files: dir/b e
229 229 description:
230 230 e
231 231
232 232
233 233 changeset: 2:f8954cd4dc1f
234 234 user: test
235 235 date: Thu Jan 01 00:00:03 1970 +0000
236 236 files: b dir/b f g
237 237 description:
238 238 c
239 239
240 240
241 241 changeset: 1:d89b0a12d229
242 242 user: test
243 243 date: Thu Jan 01 00:00:02 1970 +0000
244 244 files: b g
245 245 description:
246 246 b
247 247
248 248
249 249 changeset: 0:9161b9aeaf16
250 250 user: test
251 251 date: Thu Jan 01 00:00:01 1970 +0000
252 252 files: a f
253 253 description:
254 254 a
255 255
256 256
257 257
258 258
259 259 log -pf dir/b
260 260
261 261 $ hg up -q 3
262 262 $ hg log -pf dir/b
263 263 changeset: 2:f8954cd4dc1f
264 264 user: test
265 265 date: Thu Jan 01 00:00:03 1970 +0000
266 266 summary: c
267 267
268 268 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
269 269 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
270 270 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
271 271 @@ -0,0 +1,1 @@
272 272 +a
273 273
274 274 changeset: 1:d89b0a12d229
275 275 user: test
276 276 date: Thu Jan 01 00:00:02 1970 +0000
277 277 summary: b
278 278
279 279 diff -r 9161b9aeaf16 -r d89b0a12d229 b
280 280 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
281 281 +++ b/b Thu Jan 01 00:00:02 1970 +0000
282 282 @@ -0,0 +1,1 @@
283 283 +a
284 284
285 285 changeset: 0:9161b9aeaf16
286 286 user: test
287 287 date: Thu Jan 01 00:00:01 1970 +0000
288 288 summary: a
289 289
290 290 diff -r 000000000000 -r 9161b9aeaf16 a
291 291 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
292 292 +++ b/a Thu Jan 01 00:00:01 1970 +0000
293 293 @@ -0,0 +1,1 @@
294 294 +a
295 295
296 296
297 297 log -pf b inside dir
298 298
299 299 $ hg --cwd=dir log -pf b
300 300 changeset: 2:f8954cd4dc1f
301 301 user: test
302 302 date: Thu Jan 01 00:00:03 1970 +0000
303 303 summary: c
304 304
305 305 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
306 306 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
307 307 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
308 308 @@ -0,0 +1,1 @@
309 309 +a
310 310
311 311 changeset: 1:d89b0a12d229
312 312 user: test
313 313 date: Thu Jan 01 00:00:02 1970 +0000
314 314 summary: b
315 315
316 316 diff -r 9161b9aeaf16 -r d89b0a12d229 b
317 317 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
318 318 +++ b/b Thu Jan 01 00:00:02 1970 +0000
319 319 @@ -0,0 +1,1 @@
320 320 +a
321 321
322 322 changeset: 0:9161b9aeaf16
323 323 user: test
324 324 date: Thu Jan 01 00:00:01 1970 +0000
325 325 summary: a
326 326
327 327 diff -r 000000000000 -r 9161b9aeaf16 a
328 328 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
329 329 +++ b/a Thu Jan 01 00:00:01 1970 +0000
330 330 @@ -0,0 +1,1 @@
331 331 +a
332 332
333 333
334 334 log -pf, but no args
335 335
336 336 $ hg log -pf
337 337 changeset: 3:2ca5ba701980
338 338 user: test
339 339 date: Thu Jan 01 00:00:04 1970 +0000
340 340 summary: d
341 341
342 342 diff -r f8954cd4dc1f -r 2ca5ba701980 a
343 343 --- a/a Thu Jan 01 00:00:03 1970 +0000
344 344 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
345 345 @@ -1,1 +0,0 @@
346 346 -a
347 347 diff -r f8954cd4dc1f -r 2ca5ba701980 b
348 348 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
349 349 +++ b/b Thu Jan 01 00:00:04 1970 +0000
350 350 @@ -0,0 +1,1 @@
351 351 +a
352 352 diff -r f8954cd4dc1f -r 2ca5ba701980 d
353 353 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
354 354 +++ b/d Thu Jan 01 00:00:04 1970 +0000
355 355 @@ -0,0 +1,1 @@
356 356 +a
357 357 diff -r f8954cd4dc1f -r 2ca5ba701980 g
358 358 --- a/g Thu Jan 01 00:00:03 1970 +0000
359 359 +++ b/g Thu Jan 01 00:00:04 1970 +0000
360 360 @@ -1,2 +1,2 @@
361 361 f
362 362 -g
363 363 +f
364 364
365 365 changeset: 2:f8954cd4dc1f
366 366 user: test
367 367 date: Thu Jan 01 00:00:03 1970 +0000
368 368 summary: c
369 369
370 370 diff -r d89b0a12d229 -r f8954cd4dc1f b
371 371 --- a/b Thu Jan 01 00:00:02 1970 +0000
372 372 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
373 373 @@ -1,1 +0,0 @@
374 374 -a
375 375 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
376 376 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
377 377 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
378 378 @@ -0,0 +1,1 @@
379 379 +a
380 380 diff -r d89b0a12d229 -r f8954cd4dc1f f
381 381 --- a/f Thu Jan 01 00:00:02 1970 +0000
382 382 +++ b/f Thu Jan 01 00:00:03 1970 +0000
383 383 @@ -1,1 +1,2 @@
384 384 f
385 385 +f
386 386 diff -r d89b0a12d229 -r f8954cd4dc1f g
387 387 --- a/g Thu Jan 01 00:00:02 1970 +0000
388 388 +++ b/g Thu Jan 01 00:00:03 1970 +0000
389 389 @@ -1,1 +1,2 @@
390 390 f
391 391 +g
392 392
393 393 changeset: 1:d89b0a12d229
394 394 user: test
395 395 date: Thu Jan 01 00:00:02 1970 +0000
396 396 summary: b
397 397
398 398 diff -r 9161b9aeaf16 -r d89b0a12d229 b
399 399 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
400 400 +++ b/b Thu Jan 01 00:00:02 1970 +0000
401 401 @@ -0,0 +1,1 @@
402 402 +a
403 403 diff -r 9161b9aeaf16 -r d89b0a12d229 g
404 404 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
405 405 +++ b/g Thu Jan 01 00:00:02 1970 +0000
406 406 @@ -0,0 +1,1 @@
407 407 +f
408 408
409 409 changeset: 0:9161b9aeaf16
410 410 user: test
411 411 date: Thu Jan 01 00:00:01 1970 +0000
412 412 summary: a
413 413
414 414 diff -r 000000000000 -r 9161b9aeaf16 a
415 415 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
416 416 +++ b/a Thu Jan 01 00:00:01 1970 +0000
417 417 @@ -0,0 +1,1 @@
418 418 +a
419 419 diff -r 000000000000 -r 9161b9aeaf16 f
420 420 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
421 421 +++ b/f Thu Jan 01 00:00:01 1970 +0000
422 422 @@ -0,0 +1,1 @@
423 423 +f
424 424
425 425
426 426 log -vf dir/b
427 427
428 428 $ hg log -vf dir/b
429 429 changeset: 2:f8954cd4dc1f
430 430 user: test
431 431 date: Thu Jan 01 00:00:03 1970 +0000
432 432 files: b dir/b f g
433 433 description:
434 434 c
435 435
436 436
437 437 changeset: 1:d89b0a12d229
438 438 user: test
439 439 date: Thu Jan 01 00:00:02 1970 +0000
440 440 files: b g
441 441 description:
442 442 b
443 443
444 444
445 445 changeset: 0:9161b9aeaf16
446 446 user: test
447 447 date: Thu Jan 01 00:00:01 1970 +0000
448 448 files: a f
449 449 description:
450 450 a
451 451
452 452
453 453
454 454
455 455 -f and multiple filelog heads
456 456
457 457 $ hg up -q 2
458 458 $ hg log -f g --template '{rev}\n'
459 459 2
460 460 1
461 461 0
462 462 $ hg up -q tip
463 463 $ hg log -f g --template '{rev}\n'
464 464 3
465 465 2
466 466 0
467 467
468 468 follow files from the specified revisions (issue4959)
469 469
470 470 $ hg log -G -T '{rev} {files},{file_copies % " {source}->{name}"}\n'
471 471 @ 4 dir/b e, dir/b->e
472 472 |
473 473 o 3 a b d g, a->b f->g
474 474 |
475 475 o 2 b dir/b f g, b->dir/b
476 476 |
477 477 o 1 b g, a->b f->g
478 478 |
479 479 o 0 a f,
480 480
481 481
482 482 $ hg log -T '{rev}\n' -fr 4 e
483 483 4
484 484 2
485 485 1
486 486 0
487 487 $ hg log -T '{rev}\n' -fr 2 g
488 488 2
489 489 1
490 490 0
491 491 $ hg log -T '{rev}\n' -fr '2+3' g
492 492 3
493 493 2
494 494 1
495 495 0
496 496
497 497 follow files from the specified revisions with glob patterns (issue5053)
498 498 (BROKEN: should follow copies from e@4)
499 499
500 500 $ hg log -T '{rev}\n' -fr4 e -X '[abcdfg]'
501 501 4
502 502 2 (false !)
503 503 1 (false !)
504 504 0 (false !)
505 505
506 506 follow files from the specified revisions with missing patterns
507 507 (BROKEN: should follow copies from e@4)
508 508
509 509 $ hg log -T '{rev}\n' -fr4 e x
510 510 4
511 511 2 (false !)
512 512 1 (false !)
513 513 0 (false !)
514 514
515 515 follow files from the specified revisions across copies with -p/--patch
516 516
517 517 $ hg log -T '== rev: {rev},{file_copies % " {source}->{name}"} ==\n' -fpr 4 e g
518 518 == rev: 4, dir/b->e ==
519 519 diff -r 2ca5ba701980 -r 7e4639b4691b e
520 520 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
521 521 +++ b/e Thu Jan 01 00:00:05 1970 +0000
522 522 @@ -0,0 +1,1 @@
523 523 +a
524 524
525 525 == rev: 3, a->b f->g ==
526 526 diff -r f8954cd4dc1f -r 2ca5ba701980 g
527 527 --- a/g Thu Jan 01 00:00:03 1970 +0000
528 528 +++ b/g Thu Jan 01 00:00:04 1970 +0000
529 529 @@ -1,2 +1,2 @@
530 530 f
531 531 -g
532 532 +f
533 533
534 534 == rev: 2, b->dir/b ==
535 535 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
536 536 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
537 537 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
538 538 @@ -0,0 +1,1 @@
539 539 +a
540 540 diff -r d89b0a12d229 -r f8954cd4dc1f f
541 541 --- a/f Thu Jan 01 00:00:02 1970 +0000
542 542 +++ b/f Thu Jan 01 00:00:03 1970 +0000
543 543 @@ -1,1 +1,2 @@
544 544 f
545 545 +f
546 546
547 547 == rev: 1, a->b f->g ==
548 548 diff -r 9161b9aeaf16 -r d89b0a12d229 b
549 549 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
550 550 +++ b/b Thu Jan 01 00:00:02 1970 +0000
551 551 @@ -0,0 +1,1 @@
552 552 +a
553 553
554 554 == rev: 0, ==
555 555 diff -r 000000000000 -r 9161b9aeaf16 a
556 556 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
557 557 +++ b/a Thu Jan 01 00:00:01 1970 +0000
558 558 @@ -0,0 +1,1 @@
559 559 +a
560 560 diff -r 000000000000 -r 9161b9aeaf16 f
561 561 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
562 562 +++ b/f Thu Jan 01 00:00:01 1970 +0000
563 563 @@ -0,0 +1,1 @@
564 564 +f
565 565
566 566
567 567 log copies with --copies
568 568
569 569 $ hg log -vC --template '{rev} {file_copies}\n'
570 570 4 e (dir/b)
571 571 3 b (a)g (f)
572 572 2 dir/b (b)
573 573 1 b (a)g (f)
574 574 0
575 575
576 576 log copies switch without --copies, with old filecopy template
577 577
578 578 $ hg log -v --template '{rev} {file_copies_switch%filecopy}\n'
579 579 4
580 580 3
581 581 2
582 582 1
583 583 0
584 584
585 585 log copies switch with --copies
586 586
587 587 $ hg log -vC --template '{rev} {file_copies_switch}\n'
588 588 4 e (dir/b)
589 589 3 b (a)g (f)
590 590 2 dir/b (b)
591 591 1 b (a)g (f)
592 592 0
593 593
594 594
595 595 log copies with hardcoded style and with --style=default
596 596
597 597 $ hg log -vC -r4
598 598 changeset: 4:7e4639b4691b
599 599 tag: tip
600 600 user: test
601 601 date: Thu Jan 01 00:00:05 1970 +0000
602 602 files: dir/b e
603 603 copies: e (dir/b)
604 604 description:
605 605 e
606 606
607 607
608 608 $ hg log -vC -r4 --style=default
609 609 changeset: 4:7e4639b4691b
610 610 tag: tip
611 611 user: test
612 612 date: Thu Jan 01 00:00:05 1970 +0000
613 613 files: dir/b e
614 614 copies: e (dir/b)
615 615 description:
616 616 e
617 617
618 618
619 619 $ hg log -vC -r4 -Tjson
620 620 [
621 621 {
622 622 "bookmarks": [],
623 623 "branch": "default",
624 624 "copies": {"e": "dir/b"},
625 625 "date": [5, 0],
626 626 "desc": "e",
627 627 "files": ["dir/b", "e"],
628 628 "node": "7e4639b4691b9f84b81036a8d4fb218ce3c5e3a3",
629 629 "parents": ["2ca5ba7019804f1f597249caddf22a64d34df0ba"],
630 630 "phase": "draft",
631 631 "rev": 4,
632 632 "tags": ["tip"],
633 633 "user": "test"
634 634 }
635 635 ]
636 636
637 637 log copies, non-linear manifest
638 638
639 639 $ hg up -C 3
640 640 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
641 641 $ hg mv dir/b e
642 642 $ echo foo > foo
643 643 $ hg ci -Ame2 -d '6 0'
644 644 adding foo
645 645 created new head
646 646 $ hg log -v --template '{rev} {file_copies}\n' -r 5
647 647 5 e (dir/b)
648 648
649 649
650 650 log copies, execute bit set
651 651
652 652 #if execbit
653 653 $ chmod +x e
654 654 $ hg ci -me3 -d '7 0'
655 655 $ hg log -v --template '{rev} {file_copies}\n' -r 6
656 656 6
657 657 #endif
658 658
659 659 log copies, empty set
660 660
661 661 $ hg log --copies -r '0 and not 0'
662 662
663 663 log -p d
664 664
665 665 $ hg log -pv d
666 666 changeset: 3:2ca5ba701980
667 667 user: test
668 668 date: Thu Jan 01 00:00:04 1970 +0000
669 669 files: a b d g
670 670 description:
671 671 d
672 672
673 673
674 674 diff -r f8954cd4dc1f -r 2ca5ba701980 d
675 675 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
676 676 +++ b/d Thu Jan 01 00:00:04 1970 +0000
677 677 @@ -0,0 +1,1 @@
678 678 +a
679 679
680 680
681 681
682 682 log --removed file
683 683
684 684 $ hg log --removed -v a
685 685 changeset: 3:2ca5ba701980
686 686 user: test
687 687 date: Thu Jan 01 00:00:04 1970 +0000
688 688 files: a b d g
689 689 description:
690 690 d
691 691
692 692
693 693 changeset: 0:9161b9aeaf16
694 694 user: test
695 695 date: Thu Jan 01 00:00:01 1970 +0000
696 696 files: a f
697 697 description:
698 698 a
699 699
700 700
701 701
702 702 log --removed revrange file
703 703
704 704 $ hg log --removed -v -r0:2 a
705 705 changeset: 0:9161b9aeaf16
706 706 user: test
707 707 date: Thu Jan 01 00:00:01 1970 +0000
708 708 files: a f
709 709 description:
710 710 a
711 711
712 712
713 713 $ cd ..
714 714
715 715 log --follow tests
716 716
717 717 $ hg init follow
718 718 $ cd follow
719 719
720 720 $ echo base > base
721 721 $ hg ci -Ambase -d '1 0'
722 722 adding base
723 723
724 724 $ echo r1 >> base
725 725 $ hg ci -Amr1 -d '1 0'
726 726 $ echo r2 >> base
727 727 $ hg ci -Amr2 -d '1 0'
728 728
729 729 $ hg up -C 1
730 730 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
731 731 $ echo b1 > b1
732 732
733 733 log -r "follow('set:clean()')"
734 734
735 735 $ hg log -r "follow('set:clean()')"
736 736 changeset: 0:67e992f2c4f3
737 737 user: test
738 738 date: Thu Jan 01 00:00:01 1970 +0000
739 739 summary: base
740 740
741 741 changeset: 1:3d5bf5654eda
742 742 user: test
743 743 date: Thu Jan 01 00:00:01 1970 +0000
744 744 summary: r1
745 745
746 746
747 747 $ hg ci -Amb1 -d '1 0'
748 748 adding b1
749 749 created new head
750 750
751 751
752 752 log -f
753 753
754 754 $ hg log -f
755 755 changeset: 3:e62f78d544b4
756 756 tag: tip
757 757 parent: 1:3d5bf5654eda
758 758 user: test
759 759 date: Thu Jan 01 00:00:01 1970 +0000
760 760 summary: b1
761 761
762 762 changeset: 1:3d5bf5654eda
763 763 user: test
764 764 date: Thu Jan 01 00:00:01 1970 +0000
765 765 summary: r1
766 766
767 767 changeset: 0:67e992f2c4f3
768 768 user: test
769 769 date: Thu Jan 01 00:00:01 1970 +0000
770 770 summary: base
771 771
772 772
773 773 log -r follow('glob:b*')
774 774
775 775 $ hg log -r "follow('glob:b*')"
776 776 changeset: 0:67e992f2c4f3
777 777 user: test
778 778 date: Thu Jan 01 00:00:01 1970 +0000
779 779 summary: base
780 780
781 781 changeset: 1:3d5bf5654eda
782 782 user: test
783 783 date: Thu Jan 01 00:00:01 1970 +0000
784 784 summary: r1
785 785
786 786 changeset: 3:e62f78d544b4
787 787 tag: tip
788 788 parent: 1:3d5bf5654eda
789 789 user: test
790 790 date: Thu Jan 01 00:00:01 1970 +0000
791 791 summary: b1
792 792
793 793 log -f -r '1 + 4'
794 794
795 795 $ hg up -C 0
796 796 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
797 797 $ echo b2 > b2
798 798 $ hg ci -Amb2 -d '1 0'
799 799 adding b2
800 800 created new head
801 801 $ hg log -f -r '1 + 4'
802 802 changeset: 4:ddb82e70d1a1
803 803 tag: tip
804 804 parent: 0:67e992f2c4f3
805 805 user: test
806 806 date: Thu Jan 01 00:00:01 1970 +0000
807 807 summary: b2
808 808
809 809 changeset: 1:3d5bf5654eda
810 810 user: test
811 811 date: Thu Jan 01 00:00:01 1970 +0000
812 812 summary: r1
813 813
814 814 changeset: 0:67e992f2c4f3
815 815 user: test
816 816 date: Thu Jan 01 00:00:01 1970 +0000
817 817 summary: base
818 818
819 819
820 820 log -fr with aliases: 'A' should be expanded, but 'reverse()' should have no
821 821 effect
822 822
823 823 $ hg log --config 'revsetalias.reverse(x)=x' --config 'revsetalias.A=1+4' -qfrA
824 824 4:ddb82e70d1a1
825 825 1:3d5bf5654eda
826 826 0:67e992f2c4f3
827 827
828 828 log -r "follow('set:grep(b2)')"
829 829
830 830 $ hg log -r "follow('set:grep(b2)')"
831 831 changeset: 4:ddb82e70d1a1
832 832 tag: tip
833 833 parent: 0:67e992f2c4f3
834 834 user: test
835 835 date: Thu Jan 01 00:00:01 1970 +0000
836 836 summary: b2
837 837
838 838 log -r "follow('set:grep(b2)', 4)"
839 839
840 840 $ hg up -qC 0
841 841 $ hg log -r "follow('set:grep(b2)', 4)"
842 842 changeset: 4:ddb82e70d1a1
843 843 tag: tip
844 844 parent: 0:67e992f2c4f3
845 845 user: test
846 846 date: Thu Jan 01 00:00:01 1970 +0000
847 847 summary: b2
848 848
849 849
850 850 follow files starting from multiple revisions:
851 851
852 852 $ hg log -T '{rev}: {files}\n' -r "follow('glob:b?', startrev=2+3+4)"
853 853 3: b1
854 854 4: b2
855 855
856 856 follow files starting from empty revision:
857 857
858 858 $ hg log -T '{rev}: {files}\n' -r "follow('glob:*', startrev=.-.)"
859 859
860 860 follow starting from revisions:
861 861
862 862 $ hg log -Gq -r "follow(startrev=2+4)"
863 863 o 4:ddb82e70d1a1
864 864 |
865 865 | o 2:60c670bf5b30
866 866 | |
867 867 | o 1:3d5bf5654eda
868 868 |/
869 869 @ 0:67e992f2c4f3
870 870
871 871
872 872 follow the current revision:
873 873
874 874 $ hg log -Gq -r "follow()"
875 875 @ 0:67e992f2c4f3
876 876
877 877
878 878 $ hg up -qC 4
879 879
880 880 log -f -r null
881 881
882 882 $ hg log -f -r null
883 883 changeset: -1:000000000000
884 884 user:
885 885 date: Thu Jan 01 00:00:00 1970 +0000
886 886
887 887 $ hg log -f -r null -G
888 888 o changeset: -1:000000000000
889 889 user:
890 890 date: Thu Jan 01 00:00:00 1970 +0000
891 891
892 892
893 893
894 894 log -f with null parent
895 895
896 896 $ hg up -C null
897 897 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
898 898 $ hg log -f
899 899
900 900
901 901 log -r . with two parents
902 902
903 903 $ hg up -C 3
904 904 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
905 905 $ hg merge tip
906 906 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
907 907 (branch merge, don't forget to commit)
908 908 $ hg log -r .
909 909 changeset: 3:e62f78d544b4
910 910 parent: 1:3d5bf5654eda
911 911 user: test
912 912 date: Thu Jan 01 00:00:01 1970 +0000
913 913 summary: b1
914 914
915 915
916 916
917 917 log -r . with one parent
918 918
919 919 $ hg ci -mm12 -d '1 0'
920 920 $ hg log -r .
921 921 changeset: 5:302e9dd6890d
922 922 tag: tip
923 923 parent: 3:e62f78d544b4
924 924 parent: 4:ddb82e70d1a1
925 925 user: test
926 926 date: Thu Jan 01 00:00:01 1970 +0000
927 927 summary: m12
928 928
929 929
930 930 $ echo postm >> b1
931 931 $ hg ci -Amb1.1 -d'1 0'
932 932
933 933
934 934 log --follow-first
935 935
936 936 $ hg log --follow-first
937 937 changeset: 6:2404bbcab562
938 938 tag: tip
939 939 user: test
940 940 date: Thu Jan 01 00:00:01 1970 +0000
941 941 summary: b1.1
942 942
943 943 changeset: 5:302e9dd6890d
944 944 parent: 3:e62f78d544b4
945 945 parent: 4:ddb82e70d1a1
946 946 user: test
947 947 date: Thu Jan 01 00:00:01 1970 +0000
948 948 summary: m12
949 949
950 950 changeset: 3:e62f78d544b4
951 951 parent: 1:3d5bf5654eda
952 952 user: test
953 953 date: Thu Jan 01 00:00:01 1970 +0000
954 954 summary: b1
955 955
956 956 changeset: 1:3d5bf5654eda
957 957 user: test
958 958 date: Thu Jan 01 00:00:01 1970 +0000
959 959 summary: r1
960 960
961 961 changeset: 0:67e992f2c4f3
962 962 user: test
963 963 date: Thu Jan 01 00:00:01 1970 +0000
964 964 summary: base
965 965
966 966
967 967
968 968 log -P 2
969 969
970 970 $ hg log -P 2
971 971 changeset: 6:2404bbcab562
972 972 tag: tip
973 973 user: test
974 974 date: Thu Jan 01 00:00:01 1970 +0000
975 975 summary: b1.1
976 976
977 977 changeset: 5:302e9dd6890d
978 978 parent: 3:e62f78d544b4
979 979 parent: 4:ddb82e70d1a1
980 980 user: test
981 981 date: Thu Jan 01 00:00:01 1970 +0000
982 982 summary: m12
983 983
984 984 changeset: 4:ddb82e70d1a1
985 985 parent: 0:67e992f2c4f3
986 986 user: test
987 987 date: Thu Jan 01 00:00:01 1970 +0000
988 988 summary: b2
989 989
990 990 changeset: 3:e62f78d544b4
991 991 parent: 1:3d5bf5654eda
992 992 user: test
993 993 date: Thu Jan 01 00:00:01 1970 +0000
994 994 summary: b1
995 995
996 996
997 997
998 998 log -r tip -p --git
999 999
1000 1000 $ hg log -r tip -p --git
1001 1001 changeset: 6:2404bbcab562
1002 1002 tag: tip
1003 1003 user: test
1004 1004 date: Thu Jan 01 00:00:01 1970 +0000
1005 1005 summary: b1.1
1006 1006
1007 1007 diff --git a/b1 b/b1
1008 1008 --- a/b1
1009 1009 +++ b/b1
1010 1010 @@ -1,1 +1,2 @@
1011 1011 b1
1012 1012 +postm
1013 1013
1014 1014
1015 1015
1016 1016 log -r ""
1017 1017
1018 1018 $ hg log -r ''
1019 1019 hg: parse error: empty query
1020 1020 [255]
1021 1021
1022 1022 log -r <some unknown node id>
1023 1023
1024 1024 $ hg log -r 1000000000000000000000000000000000000000
1025 1025 abort: unknown revision '1000000000000000000000000000000000000000'!
1026 1026 [255]
1027 1027
1028 1028 log -k r1
1029 1029
1030 1030 $ hg log -k r1
1031 1031 changeset: 1:3d5bf5654eda
1032 1032 user: test
1033 1033 date: Thu Jan 01 00:00:01 1970 +0000
1034 1034 summary: r1
1035 1035
1036 1036 log -p -l2 --color=always
1037 1037
1038 1038 $ hg --config extensions.color= --config color.mode=ansi \
1039 1039 > log -p -l2 --color=always
1040 1040 \x1b[0;33mchangeset: 6:2404bbcab562\x1b[0m (esc)
1041 1041 tag: tip
1042 1042 user: test
1043 1043 date: Thu Jan 01 00:00:01 1970 +0000
1044 1044 summary: b1.1
1045 1045
1046 1046 \x1b[0;1mdiff -r 302e9dd6890d -r 2404bbcab562 b1\x1b[0m (esc)
1047 1047 \x1b[0;31;1m--- a/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
1048 1048 \x1b[0;32;1m+++ b/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
1049 1049 \x1b[0;35m@@ -1,1 +1,2 @@\x1b[0m (esc)
1050 1050 b1
1051 1051 \x1b[0;32m+postm\x1b[0m (esc)
1052 1052
1053 1053 \x1b[0;33mchangeset: 5:302e9dd6890d\x1b[0m (esc)
1054 1054 parent: 3:e62f78d544b4
1055 1055 parent: 4:ddb82e70d1a1
1056 1056 user: test
1057 1057 date: Thu Jan 01 00:00:01 1970 +0000
1058 1058 summary: m12
1059 1059
1060 1060 \x1b[0;1mdiff -r e62f78d544b4 -r 302e9dd6890d b2\x1b[0m (esc)
1061 1061 \x1b[0;31;1m--- /dev/null Thu Jan 01 00:00:00 1970 +0000\x1b[0m (esc)
1062 1062 \x1b[0;32;1m+++ b/b2 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
1063 1063 \x1b[0;35m@@ -0,0 +1,1 @@\x1b[0m (esc)
1064 1064 \x1b[0;32m+b2\x1b[0m (esc)
1065 1065
1066 1066
1067 1067
1068 1068 log -r tip --stat
1069 1069
1070 1070 $ hg log -r tip --stat
1071 1071 changeset: 6:2404bbcab562
1072 1072 tag: tip
1073 1073 user: test
1074 1074 date: Thu Jan 01 00:00:01 1970 +0000
1075 1075 summary: b1.1
1076 1076
1077 1077 b1 | 1 +
1078 1078 1 files changed, 1 insertions(+), 0 deletions(-)
1079 1079
1080 1080
1081 1081 $ cd ..
1082 1082
1083 1083 log --follow --patch FILE in repository where linkrev isn't trustworthy
1084 1084 (issue5376)
1085 1085
1086 1086 $ hg init follow-dup
1087 1087 $ cd follow-dup
1088 1088 $ cat <<EOF >> .hg/hgrc
1089 1089 > [ui]
1090 1090 > logtemplate = '=== {rev}: {desc}\n'
1091 1091 > [diff]
1092 1092 > nodates = True
1093 1093 > EOF
1094 1094 $ echo 0 >> a
1095 1095 $ hg ci -qAm 'a0'
1096 1096 $ echo 1 >> a
1097 1097 $ hg ci -m 'a1'
1098 1098 $ hg up -q 0
1099 1099 $ echo 1 >> a
1100 1100 $ touch b
1101 1101 $ hg ci -qAm 'a1 with b'
1102 1102 $ echo 3 >> a
1103 1103 $ hg ci -m 'a3'
1104 1104
1105 1105 fctx.rev() == 2, but fctx.linkrev() == 1
1106 1106
1107 1107 $ hg log -pf a
1108 1108 === 3: a3
1109 1109 diff -r 4ea02ba94d66 -r e7a6331a34f0 a
1110 1110 --- a/a
1111 1111 +++ b/a
1112 1112 @@ -1,2 +1,3 @@
1113 1113 0
1114 1114 1
1115 1115 +3
1116 1116
1117 1117 === 2: a1 with b
1118 1118 diff -r 49b5e81287e2 -r 4ea02ba94d66 a
1119 1119 --- a/a
1120 1120 +++ b/a
1121 1121 @@ -1,1 +1,2 @@
1122 1122 0
1123 1123 +1
1124 1124
1125 1125 === 0: a0
1126 1126 diff -r 000000000000 -r 49b5e81287e2 a
1127 1127 --- /dev/null
1128 1128 +++ b/a
1129 1129 @@ -0,0 +1,1 @@
1130 1130 +0
1131 1131
1132 1132
1133 1133 fctx.introrev() == 2, but fctx.linkrev() == 1
1134 1134
1135 1135 $ hg up -q 2
1136 1136 $ hg log -pf a
1137 1137 === 2: a1 with b
1138 1138 diff -r 49b5e81287e2 -r 4ea02ba94d66 a
1139 1139 --- a/a
1140 1140 +++ b/a
1141 1141 @@ -1,1 +1,2 @@
1142 1142 0
1143 1143 +1
1144 1144
1145 1145 === 0: a0
1146 1146 diff -r 000000000000 -r 49b5e81287e2 a
1147 1147 --- /dev/null
1148 1148 +++ b/a
1149 1149 @@ -0,0 +1,1 @@
1150 1150 +0
1151 1151
1152 1152
1153 1153 $ cd ..
1154 1154
1155 1155 Multiple copy sources of a file:
1156 1156
1157 1157 $ hg init follow-multi
1158 1158 $ cd follow-multi
1159 1159 $ echo 0 >> a
1160 1160 $ hg ci -qAm 'a'
1161 1161 $ hg cp a b
1162 1162 $ hg ci -m 'a->b'
1163 1163 $ echo 2 >> a
1164 1164 $ hg ci -m 'a'
1165 1165 $ echo 3 >> b
1166 1166 $ hg ci -m 'b'
1167 1167 $ echo 4 >> a
1168 1168 $ echo 4 >> b
1169 1169 $ hg ci -m 'a,b'
1170 1170 $ echo 5 >> a
1171 1171 $ hg ci -m 'a0'
1172 1172 $ echo 6 >> b
1173 1173 $ hg ci -m 'b0'
1174 1174 $ hg up -q 4
1175 1175 $ echo 7 >> b
1176 1176 $ hg ci -m 'b1'
1177 1177 created new head
1178 1178 $ echo 8 >> a
1179 1179 $ hg ci -m 'a1'
1180 1180 $ hg rm a
1181 1181 $ hg mv b a
1182 1182 $ hg ci -m 'b1->a1'
1183 1183 $ hg merge -qt :local
1184 1184 $ hg ci -m '(a0,b1->a1)->a'
1185 1185
1186 1186 $ hg log -GT '{rev}: {desc}\n'
1187 1187 @ 10: (a0,b1->a1)->a
1188 1188 |\
1189 1189 | o 9: b1->a1
1190 1190 | |
1191 1191 | o 8: a1
1192 1192 | |
1193 1193 | o 7: b1
1194 1194 | |
1195 1195 o | 6: b0
1196 1196 | |
1197 1197 o | 5: a0
1198 1198 |/
1199 1199 o 4: a,b
1200 1200 |
1201 1201 o 3: b
1202 1202 |
1203 1203 o 2: a
1204 1204 |
1205 1205 o 1: a->b
1206 1206 |
1207 1207 o 0: a
1208 1208
1209 1209
1210 1210 since file 'a' has multiple copy sources at the revision 4, ancestors can't
1211 1211 be indexed solely by fctx.linkrev().
1212 1212
1213 1213 $ hg log -T '{rev}: {desc}\n' -f a
1214 1214 10: (a0,b1->a1)->a
1215 1215 9: b1->a1
1216 1216 7: b1
1217 1217 5: a0
1218 1218 4: a,b
1219 1219 3: b
1220 1220 2: a
1221 1221 1: a->b
1222 1222 0: a
1223 1223
1224 1224 $ cd ..
1225 1225
1226 1226 Test that log should respect the order of -rREV even if multiple OR conditions
1227 1227 are specified (issue5100):
1228 1228
1229 1229 $ hg init revorder
1230 1230 $ cd revorder
1231 1231
1232 1232 $ hg branch -q b0
1233 1233 $ echo 0 >> f0
1234 1234 $ hg ci -qAm k0 -u u0
1235 1235 $ hg branch -q b1
1236 1236 $ echo 1 >> f1
1237 1237 $ hg ci -qAm k1 -u u1
1238 1238 $ hg branch -q b2
1239 1239 $ echo 2 >> f2
1240 1240 $ hg ci -qAm k2 -u u2
1241 1241
1242 1242 $ hg update -q b2
1243 1243 $ echo 3 >> f2
1244 1244 $ hg ci -qAm k2 -u u2
1245 1245 $ hg update -q b1
1246 1246 $ echo 4 >> f1
1247 1247 $ hg ci -qAm k1 -u u1
1248 1248 $ hg update -q b0
1249 1249 $ echo 5 >> f0
1250 1250 $ hg ci -qAm k0 -u u0
1251 1251
1252 1252 summary of revisions:
1253 1253
1254 1254 $ hg log -G -T '{rev} {branch} {author} {desc} {files}\n'
1255 1255 @ 5 b0 u0 k0 f0
1256 1256 |
1257 1257 | o 4 b1 u1 k1 f1
1258 1258 | |
1259 1259 | | o 3 b2 u2 k2 f2
1260 1260 | | |
1261 1261 | | o 2 b2 u2 k2 f2
1262 1262 | |/
1263 1263 | o 1 b1 u1 k1 f1
1264 1264 |/
1265 1265 o 0 b0 u0 k0 f0
1266 1266
1267 1267
1268 1268 log -b BRANCH in ascending order:
1269 1269
1270 1270 $ hg log -r0:tip -T '{rev} {branch}\n' -b b0 -b b1
1271 1271 0 b0
1272 1272 1 b1
1273 1273 4 b1
1274 1274 5 b0
1275 1275 $ hg log -r0:tip -T '{rev} {branch}\n' -b b1 -b b0
1276 1276 0 b0
1277 1277 1 b1
1278 1278 4 b1
1279 1279 5 b0
1280 1280
1281 1281 log --only-branch BRANCH in descending order:
1282 1282
1283 1283 $ hg log -rtip:0 -T '{rev} {branch}\n' --only-branch b1 --only-branch b2
1284 1284 4 b1
1285 1285 3 b2
1286 1286 2 b2
1287 1287 1 b1
1288 1288 $ hg log -rtip:0 -T '{rev} {branch}\n' --only-branch b2 --only-branch b1
1289 1289 4 b1
1290 1290 3 b2
1291 1291 2 b2
1292 1292 1 b1
1293 1293
1294 1294 log -u USER in ascending order, against compound set:
1295 1295
1296 1296 $ hg log -r'::head()' -T '{rev} {author}\n' -u u0 -u u2
1297 1297 0 u0
1298 1298 2 u2
1299 1299 3 u2
1300 1300 5 u0
1301 1301 $ hg log -r'::head()' -T '{rev} {author}\n' -u u2 -u u0
1302 1302 0 u0
1303 1303 2 u2
1304 1304 3 u2
1305 1305 5 u0
1306 1306
1307 1307 log -k TEXT in descending order, against compound set:
1308 1308
1309 1309 $ hg log -r'5 + reverse(::3)' -T '{rev} {desc}\n' -k k0 -k k1 -k k2
1310 1310 5 k0
1311 1311 3 k2
1312 1312 2 k2
1313 1313 1 k1
1314 1314 0 k0
1315 1315 $ hg log -r'5 + reverse(::3)' -T '{rev} {desc}\n' -k k2 -k k1 -k k0
1316 1316 5 k0
1317 1317 3 k2
1318 1318 2 k2
1319 1319 1 k1
1320 1320 0 k0
1321 1321
1322 1322 log FILE in ascending order, against dagrange:
1323 1323
1324 1324 $ hg log -r1:: -T '{rev} {files}\n' f1 f2
1325 1325 1 f1
1326 1326 2 f2
1327 1327 3 f2
1328 1328 4 f1
1329 1329 $ hg log -r1:: -T '{rev} {files}\n' f2 f1
1330 1330 1 f1
1331 1331 2 f2
1332 1332 3 f2
1333 1333 4 f1
1334 1334
1335 1335 $ cd ..
1336 1336
1337 1337 User
1338 1338
1339 1339 $ hg init usertest
1340 1340 $ cd usertest
1341 1341
1342 1342 $ echo a > a
1343 1343 $ hg ci -A -m "a" -u "User One <user1@example.org>"
1344 1344 adding a
1345 1345 $ echo b > b
1346 1346 $ hg ci -A -m "b" -u "User Two <user2@example.org>"
1347 1347 adding b
1348 1348
1349 1349 $ hg log -u "User One <user1@example.org>"
1350 1350 changeset: 0:29a4c94f1924
1351 1351 user: User One <user1@example.org>
1352 1352 date: Thu Jan 01 00:00:00 1970 +0000
1353 1353 summary: a
1354 1354
1355 1355 $ hg log -u "user1" -u "user2"
1356 1356 changeset: 1:e834b5e69c0e
1357 1357 tag: tip
1358 1358 user: User Two <user2@example.org>
1359 1359 date: Thu Jan 01 00:00:00 1970 +0000
1360 1360 summary: b
1361 1361
1362 1362 changeset: 0:29a4c94f1924
1363 1363 user: User One <user1@example.org>
1364 1364 date: Thu Jan 01 00:00:00 1970 +0000
1365 1365 summary: a
1366 1366
1367 1367 $ hg log -u "user3"
1368 1368
1369 1369 "-u USER" shouldn't be overridden by "user(USER)" alias
1370 1370
1371 1371 $ hg log --config 'revsetalias.user(x)=branch(x)' -u default
1372 1372 $ hg log --config 'revsetalias.user(x)=branch(x)' -u user1
1373 1373 changeset: 0:29a4c94f1924
1374 1374 user: User One <user1@example.org>
1375 1375 date: Thu Jan 01 00:00:00 1970 +0000
1376 1376 summary: a
1377 1377
1378 1378
1379 1379 $ cd ..
1380 1380
1381 1381 $ hg init branches
1382 1382 $ cd branches
1383 1383
1384 1384 $ echo a > a
1385 1385 $ hg ci -A -m "commit on default"
1386 1386 adding a
1387 1387 $ hg branch test
1388 1388 marked working directory as branch test
1389 1389 (branches are permanent and global, did you want a bookmark?)
1390 1390 $ echo b > b
1391 1391 $ hg ci -A -m "commit on test"
1392 1392 adding b
1393 1393
1394 1394 $ hg up default
1395 1395 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1396 1396 $ echo c > c
1397 1397 $ hg ci -A -m "commit on default"
1398 1398 adding c
1399 1399 $ hg up test
1400 1400 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1401 1401 $ echo c > c
1402 1402 $ hg ci -A -m "commit on test"
1403 1403 adding c
1404 1404
1405 1405
1406 1406 log -b default
1407 1407
1408 1408 $ hg log -b default
1409 1409 changeset: 2:c3a4f03cc9a7
1410 1410 parent: 0:24427303d56f
1411 1411 user: test
1412 1412 date: Thu Jan 01 00:00:00 1970 +0000
1413 1413 summary: commit on default
1414 1414
1415 1415 changeset: 0:24427303d56f
1416 1416 user: test
1417 1417 date: Thu Jan 01 00:00:00 1970 +0000
1418 1418 summary: commit on default
1419 1419
1420 1420
1421 1421
1422 1422 log -b test
1423 1423
1424 1424 $ hg log -b test
1425 1425 changeset: 3:f5d8de11c2e2
1426 1426 branch: test
1427 1427 tag: tip
1428 1428 parent: 1:d32277701ccb
1429 1429 user: test
1430 1430 date: Thu Jan 01 00:00:00 1970 +0000
1431 1431 summary: commit on test
1432 1432
1433 1433 changeset: 1:d32277701ccb
1434 1434 branch: test
1435 1435 user: test
1436 1436 date: Thu Jan 01 00:00:00 1970 +0000
1437 1437 summary: commit on test
1438 1438
1439 1439
1440 1440
1441 1441 log -b dummy
1442 1442
1443 1443 $ hg log -b dummy
1444 1444 abort: unknown revision 'dummy'!
1445 1445 [255]
1446 1446
1447 1447
1448 1448 log -b .
1449 1449
1450 1450 $ hg log -b .
1451 1451 changeset: 3:f5d8de11c2e2
1452 1452 branch: test
1453 1453 tag: tip
1454 1454 parent: 1:d32277701ccb
1455 1455 user: test
1456 1456 date: Thu Jan 01 00:00:00 1970 +0000
1457 1457 summary: commit on test
1458 1458
1459 1459 changeset: 1:d32277701ccb
1460 1460 branch: test
1461 1461 user: test
1462 1462 date: Thu Jan 01 00:00:00 1970 +0000
1463 1463 summary: commit on test
1464 1464
1465 1465
1466 1466
1467 1467 log -b default -b test
1468 1468
1469 1469 $ hg log -b default -b test
1470 1470 changeset: 3:f5d8de11c2e2
1471 1471 branch: test
1472 1472 tag: tip
1473 1473 parent: 1:d32277701ccb
1474 1474 user: test
1475 1475 date: Thu Jan 01 00:00:00 1970 +0000
1476 1476 summary: commit on test
1477 1477
1478 1478 changeset: 2:c3a4f03cc9a7
1479 1479 parent: 0:24427303d56f
1480 1480 user: test
1481 1481 date: Thu Jan 01 00:00:00 1970 +0000
1482 1482 summary: commit on default
1483 1483
1484 1484 changeset: 1:d32277701ccb
1485 1485 branch: test
1486 1486 user: test
1487 1487 date: Thu Jan 01 00:00:00 1970 +0000
1488 1488 summary: commit on test
1489 1489
1490 1490 changeset: 0:24427303d56f
1491 1491 user: test
1492 1492 date: Thu Jan 01 00:00:00 1970 +0000
1493 1493 summary: commit on default
1494 1494
1495 1495
1496 1496
1497 1497 log -b default -b .
1498 1498
1499 1499 $ hg log -b default -b .
1500 1500 changeset: 3:f5d8de11c2e2
1501 1501 branch: test
1502 1502 tag: tip
1503 1503 parent: 1:d32277701ccb
1504 1504 user: test
1505 1505 date: Thu Jan 01 00:00:00 1970 +0000
1506 1506 summary: commit on test
1507 1507
1508 1508 changeset: 2:c3a4f03cc9a7
1509 1509 parent: 0:24427303d56f
1510 1510 user: test
1511 1511 date: Thu Jan 01 00:00:00 1970 +0000
1512 1512 summary: commit on default
1513 1513
1514 1514 changeset: 1:d32277701ccb
1515 1515 branch: test
1516 1516 user: test
1517 1517 date: Thu Jan 01 00:00:00 1970 +0000
1518 1518 summary: commit on test
1519 1519
1520 1520 changeset: 0:24427303d56f
1521 1521 user: test
1522 1522 date: Thu Jan 01 00:00:00 1970 +0000
1523 1523 summary: commit on default
1524 1524
1525 1525
1526 1526
1527 1527 log -b . -b test
1528 1528
1529 1529 $ hg log -b . -b test
1530 1530 changeset: 3:f5d8de11c2e2
1531 1531 branch: test
1532 1532 tag: tip
1533 1533 parent: 1:d32277701ccb
1534 1534 user: test
1535 1535 date: Thu Jan 01 00:00:00 1970 +0000
1536 1536 summary: commit on test
1537 1537
1538 1538 changeset: 1:d32277701ccb
1539 1539 branch: test
1540 1540 user: test
1541 1541 date: Thu Jan 01 00:00:00 1970 +0000
1542 1542 summary: commit on test
1543 1543
1544 1544
1545 1545
1546 1546 log -b 2
1547 1547
1548 1548 $ hg log -b 2
1549 1549 changeset: 2:c3a4f03cc9a7
1550 1550 parent: 0:24427303d56f
1551 1551 user: test
1552 1552 date: Thu Jan 01 00:00:00 1970 +0000
1553 1553 summary: commit on default
1554 1554
1555 1555 changeset: 0:24427303d56f
1556 1556 user: test
1557 1557 date: Thu Jan 01 00:00:00 1970 +0000
1558 1558 summary: commit on default
1559 1559
1560 1560 #if gettext
1561 1561
1562 1562 Test that all log names are translated (e.g. branches, bookmarks, tags):
1563 1563
1564 1564 $ hg bookmark babar -r tip
1565 1565
1566 1566 $ HGENCODING=UTF-8 LANGUAGE=de hg log -r tip
1567 1567 \xc3\x84nderung: 3:f5d8de11c2e2 (esc)
1568 1568 Zweig: test
1569 1569 Lesezeichen: babar
1570 1570 Marke: tip
1571 1571 Vorg\xc3\xa4nger: 1:d32277701ccb (esc)
1572 1572 Nutzer: test
1573 1573 Datum: Thu Jan 01 00:00:00 1970 +0000
1574 1574 Zusammenfassung: commit on test
1575 1575
1576 1576 $ hg bookmark -d babar
1577 1577
1578 1578 #endif
1579 1579
1580 1580 log -p --cwd dir (in subdir)
1581 1581
1582 1582 $ mkdir dir
1583 1583 $ hg log -p --cwd dir
1584 1584 changeset: 3:f5d8de11c2e2
1585 1585 branch: test
1586 1586 tag: tip
1587 1587 parent: 1:d32277701ccb
1588 1588 user: test
1589 1589 date: Thu Jan 01 00:00:00 1970 +0000
1590 1590 summary: commit on test
1591 1591
1592 1592 diff -r d32277701ccb -r f5d8de11c2e2 c
1593 1593 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1594 1594 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1595 1595 @@ -0,0 +1,1 @@
1596 1596 +c
1597 1597
1598 1598 changeset: 2:c3a4f03cc9a7
1599 1599 parent: 0:24427303d56f
1600 1600 user: test
1601 1601 date: Thu Jan 01 00:00:00 1970 +0000
1602 1602 summary: commit on default
1603 1603
1604 1604 diff -r 24427303d56f -r c3a4f03cc9a7 c
1605 1605 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1606 1606 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1607 1607 @@ -0,0 +1,1 @@
1608 1608 +c
1609 1609
1610 1610 changeset: 1:d32277701ccb
1611 1611 branch: test
1612 1612 user: test
1613 1613 date: Thu Jan 01 00:00:00 1970 +0000
1614 1614 summary: commit on test
1615 1615
1616 1616 diff -r 24427303d56f -r d32277701ccb b
1617 1617 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1618 1618 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1619 1619 @@ -0,0 +1,1 @@
1620 1620 +b
1621 1621
1622 1622 changeset: 0:24427303d56f
1623 1623 user: test
1624 1624 date: Thu Jan 01 00:00:00 1970 +0000
1625 1625 summary: commit on default
1626 1626
1627 1627 diff -r 000000000000 -r 24427303d56f a
1628 1628 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1629 1629 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1630 1630 @@ -0,0 +1,1 @@
1631 1631 +a
1632 1632
1633 1633
1634 1634
1635 1635 log -p -R repo
1636 1636
1637 1637 $ cd dir
1638 1638 $ hg log -p -R .. ../a
1639 1639 changeset: 0:24427303d56f
1640 1640 user: test
1641 1641 date: Thu Jan 01 00:00:00 1970 +0000
1642 1642 summary: commit on default
1643 1643
1644 1644 diff -r 000000000000 -r 24427303d56f a
1645 1645 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1646 1646 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1647 1647 @@ -0,0 +1,1 @@
1648 1648 +a
1649 1649
1650 1650
1651 1651 $ cd ../..
1652 1652
1653 1653 $ hg init follow2
1654 1654 $ cd follow2
1655 1655
1656 1656 # Build the following history:
1657 1657 # tip - o - x - o - x - x
1658 1658 # \ /
1659 1659 # o - o - o - x
1660 1660 # \ /
1661 1661 # o
1662 1662 #
1663 1663 # Where "o" is a revision containing "foo" and
1664 1664 # "x" is a revision without "foo"
1665 1665
1666 1666 $ touch init
1667 1667 $ hg ci -A -m "init, unrelated"
1668 1668 adding init
1669 1669 $ echo 'foo' > init
1670 1670 $ hg ci -m "change, unrelated"
1671 1671 $ echo 'foo' > foo
1672 1672 $ hg ci -A -m "add unrelated old foo"
1673 1673 adding foo
1674 1674 $ hg rm foo
1675 1675 $ hg ci -m "delete foo, unrelated"
1676 1676 $ echo 'related' > foo
1677 1677 $ hg ci -A -m "add foo, related"
1678 1678 adding foo
1679 1679
1680 1680 $ hg up 0
1681 1681 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1682 1682 $ touch branch
1683 1683 $ hg ci -A -m "first branch, unrelated"
1684 1684 adding branch
1685 1685 created new head
1686 1686 $ touch foo
1687 1687 $ hg ci -A -m "create foo, related"
1688 1688 adding foo
1689 1689 $ echo 'change' > foo
1690 1690 $ hg ci -m "change foo, related"
1691 1691
1692 1692 $ hg up 6
1693 1693 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1694 1694 $ echo 'change foo in branch' > foo
1695 1695 $ hg ci -m "change foo in branch, related"
1696 1696 created new head
1697 1697 $ hg merge 7
1698 1698 merging foo
1699 1699 warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
1700 1700 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
1701 1701 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
1702 1702 [1]
1703 1703 $ echo 'merge 1' > foo
1704 1704 $ hg resolve -m foo
1705 1705 (no more unresolved files)
1706 1706 $ hg ci -m "First merge, related"
1707 1707
1708 1708 $ hg merge 4
1709 1709 merging foo
1710 1710 warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
1711 1711 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
1712 1712 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
1713 1713 [1]
1714 1714 $ echo 'merge 2' > foo
1715 1715 $ hg resolve -m foo
1716 1716 (no more unresolved files)
1717 1717 $ hg ci -m "Last merge, related"
1718 1718
1719 1719 $ hg log --graph
1720 1720 @ changeset: 10:4dae8563d2c5
1721 1721 |\ tag: tip
1722 1722 | | parent: 9:7b35701b003e
1723 1723 | | parent: 4:88176d361b69
1724 1724 | | user: test
1725 1725 | | date: Thu Jan 01 00:00:00 1970 +0000
1726 1726 | | summary: Last merge, related
1727 1727 | |
1728 1728 | o changeset: 9:7b35701b003e
1729 1729 | |\ parent: 8:e5416ad8a855
1730 1730 | | | parent: 7:87fe3144dcfa
1731 1731 | | | user: test
1732 1732 | | | date: Thu Jan 01 00:00:00 1970 +0000
1733 1733 | | | summary: First merge, related
1734 1734 | | |
1735 1735 | | o changeset: 8:e5416ad8a855
1736 1736 | | | parent: 6:dc6c325fe5ee
1737 1737 | | | user: test
1738 1738 | | | date: Thu Jan 01 00:00:00 1970 +0000
1739 1739 | | | summary: change foo in branch, related
1740 1740 | | |
1741 1741 | o | changeset: 7:87fe3144dcfa
1742 1742 | |/ user: test
1743 1743 | | date: Thu Jan 01 00:00:00 1970 +0000
1744 1744 | | summary: change foo, related
1745 1745 | |
1746 1746 | o changeset: 6:dc6c325fe5ee
1747 1747 | | user: test
1748 1748 | | date: Thu Jan 01 00:00:00 1970 +0000
1749 1749 | | summary: create foo, related
1750 1750 | |
1751 1751 | o changeset: 5:73db34516eb9
1752 1752 | | parent: 0:e87515fd044a
1753 1753 | | user: test
1754 1754 | | date: Thu Jan 01 00:00:00 1970 +0000
1755 1755 | | summary: first branch, unrelated
1756 1756 | |
1757 1757 o | changeset: 4:88176d361b69
1758 1758 | | user: test
1759 1759 | | date: Thu Jan 01 00:00:00 1970 +0000
1760 1760 | | summary: add foo, related
1761 1761 | |
1762 1762 o | changeset: 3:dd78ae4afb56
1763 1763 | | user: test
1764 1764 | | date: Thu Jan 01 00:00:00 1970 +0000
1765 1765 | | summary: delete foo, unrelated
1766 1766 | |
1767 1767 o | changeset: 2:c4c64aedf0f7
1768 1768 | | user: test
1769 1769 | | date: Thu Jan 01 00:00:00 1970 +0000
1770 1770 | | summary: add unrelated old foo
1771 1771 | |
1772 1772 o | changeset: 1:e5faa7440653
1773 1773 |/ user: test
1774 1774 | date: Thu Jan 01 00:00:00 1970 +0000
1775 1775 | summary: change, unrelated
1776 1776 |
1777 1777 o changeset: 0:e87515fd044a
1778 1778 user: test
1779 1779 date: Thu Jan 01 00:00:00 1970 +0000
1780 1780 summary: init, unrelated
1781 1781
1782 1782
1783 1783 $ hg --traceback log -f foo
1784 1784 changeset: 10:4dae8563d2c5
1785 1785 tag: tip
1786 1786 parent: 9:7b35701b003e
1787 1787 parent: 4:88176d361b69
1788 1788 user: test
1789 1789 date: Thu Jan 01 00:00:00 1970 +0000
1790 1790 summary: Last merge, related
1791 1791
1792 1792 changeset: 9:7b35701b003e
1793 1793 parent: 8:e5416ad8a855
1794 1794 parent: 7:87fe3144dcfa
1795 1795 user: test
1796 1796 date: Thu Jan 01 00:00:00 1970 +0000
1797 1797 summary: First merge, related
1798 1798
1799 1799 changeset: 8:e5416ad8a855
1800 1800 parent: 6:dc6c325fe5ee
1801 1801 user: test
1802 1802 date: Thu Jan 01 00:00:00 1970 +0000
1803 1803 summary: change foo in branch, related
1804 1804
1805 1805 changeset: 7:87fe3144dcfa
1806 1806 user: test
1807 1807 date: Thu Jan 01 00:00:00 1970 +0000
1808 1808 summary: change foo, related
1809 1809
1810 1810 changeset: 6:dc6c325fe5ee
1811 1811 user: test
1812 1812 date: Thu Jan 01 00:00:00 1970 +0000
1813 1813 summary: create foo, related
1814 1814
1815 1815 changeset: 4:88176d361b69
1816 1816 user: test
1817 1817 date: Thu Jan 01 00:00:00 1970 +0000
1818 1818 summary: add foo, related
1819 1819
1820 1820
1821 1821 Also check when maxrev < lastrevfilelog
1822 1822
1823 1823 $ hg --traceback log -f -r4 foo
1824 1824 changeset: 4:88176d361b69
1825 1825 user: test
1826 1826 date: Thu Jan 01 00:00:00 1970 +0000
1827 1827 summary: add foo, related
1828 1828
1829 1829 $ cd ..
1830 1830
1831 1831 Issue2383: hg log showing _less_ differences than hg diff
1832 1832
1833 1833 $ hg init issue2383
1834 1834 $ cd issue2383
1835 1835
1836 1836 Create a test repo:
1837 1837
1838 1838 $ echo a > a
1839 1839 $ hg ci -Am0
1840 1840 adding a
1841 1841 $ echo b > b
1842 1842 $ hg ci -Am1
1843 1843 adding b
1844 1844 $ hg co 0
1845 1845 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1846 1846 $ echo b > a
1847 1847 $ hg ci -m2
1848 1848 created new head
1849 1849
1850 1850 Merge:
1851 1851
1852 1852 $ hg merge
1853 1853 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1854 1854 (branch merge, don't forget to commit)
1855 1855
1856 1856 Make sure there's a file listed in the merge to trigger the bug:
1857 1857
1858 1858 $ echo c > a
1859 1859 $ hg ci -m3
1860 1860
1861 1861 Two files shown here in diff:
1862 1862
1863 1863 $ hg diff --rev 2:3
1864 1864 diff -r b09be438c43a -r 8e07aafe1edc a
1865 1865 --- a/a Thu Jan 01 00:00:00 1970 +0000
1866 1866 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1867 1867 @@ -1,1 +1,1 @@
1868 1868 -b
1869 1869 +c
1870 1870 diff -r b09be438c43a -r 8e07aafe1edc b
1871 1871 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1872 1872 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1873 1873 @@ -0,0 +1,1 @@
1874 1874 +b
1875 1875
1876 1876 Diff here should be the same:
1877 1877
1878 1878 $ hg log -vpr 3
1879 1879 changeset: 3:8e07aafe1edc
1880 1880 tag: tip
1881 1881 parent: 2:b09be438c43a
1882 1882 parent: 1:925d80f479bb
1883 1883 user: test
1884 1884 date: Thu Jan 01 00:00:00 1970 +0000
1885 1885 files: a
1886 1886 description:
1887 1887 3
1888 1888
1889 1889
1890 1890 diff -r b09be438c43a -r 8e07aafe1edc a
1891 1891 --- a/a Thu Jan 01 00:00:00 1970 +0000
1892 1892 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1893 1893 @@ -1,1 +1,1 @@
1894 1894 -b
1895 1895 +c
1896 1896 diff -r b09be438c43a -r 8e07aafe1edc b
1897 1897 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1898 1898 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1899 1899 @@ -0,0 +1,1 @@
1900 1900 +b
1901 1901
1902 1902 $ cd ..
1903 1903
1904 1904 'hg log -r rev fn' when last(filelog(fn)) != rev
1905 1905
1906 1906 $ hg init simplelog
1907 1907 $ cd simplelog
1908 1908 $ echo f > a
1909 1909 $ hg ci -Am'a' -d '0 0'
1910 1910 adding a
1911 1911 $ echo f >> a
1912 1912 $ hg ci -Am'a bis' -d '1 0'
1913 1913
1914 1914 $ hg log -r0 a
1915 1915 changeset: 0:9f758d63dcde
1916 1916 user: test
1917 1917 date: Thu Jan 01 00:00:00 1970 +0000
1918 1918 summary: a
1919 1919
1920 1920 enable obsolete to test hidden feature
1921 1921
1922 1922 $ cat >> $HGRCPATH << EOF
1923 1923 > [experimental]
1924 1924 > evolution.createmarkers=True
1925 1925 > EOF
1926 1926
1927 1927 $ hg log --template='{rev}:{node}\n'
1928 1928 1:a765632148dc55d38c35c4f247c618701886cb2f
1929 1929 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1930 1930 $ hg debugobsolete a765632148dc55d38c35c4f247c618701886cb2f
1931 1931 obsoleted 1 changesets
1932 1932 $ hg up null -q
1933 1933 $ hg log --template='{rev}:{node}\n'
1934 1934 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1935 1935 $ hg log --template='{rev}:{node}\n' --hidden
1936 1936 1:a765632148dc55d38c35c4f247c618701886cb2f
1937 1937 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1938 1938 $ hg log -r a
1939 1939 abort: hidden revision 'a' is pruned!
1940 1940 (use --hidden to access hidden revisions)
1941 1941 [255]
1942 1942
1943 1943 test that parent prevent a changeset to be hidden
1944 1944
1945 1945 $ hg up 1 -q --hidden
1946 1946 updated to hidden changeset a765632148dc
1947 1947 (hidden revision 'a765632148dc' is pruned)
1948 1948 $ hg log --template='{rev}:{node}\n'
1949 1949 1:a765632148dc55d38c35c4f247c618701886cb2f
1950 1950 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1951 1951
1952 1952 test that second parent prevent a changeset to be hidden too
1953 1953
1954 1954 $ hg debugsetparents 0 1 # nothing suitable to merge here
1955 1955 $ hg log --template='{rev}:{node}\n'
1956 1956 1:a765632148dc55d38c35c4f247c618701886cb2f
1957 1957 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1958 1958 $ hg debugsetparents 1
1959 1959 $ hg up -q null
1960 1960
1961 1961 bookmarks prevent a changeset being hidden
1962 1962
1963 1963 $ hg bookmark --hidden -r 1 X
1964 1964 bookmarking hidden changeset a765632148dc
1965 1965 (hidden revision 'a765632148dc' is pruned)
1966 1966 $ hg log --template '{rev}:{node}\n'
1967 1967 1:a765632148dc55d38c35c4f247c618701886cb2f
1968 1968 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1969 1969 $ hg bookmark -d X
1970 1970
1971 1971 divergent bookmarks are not hidden
1972 1972
1973 1973 $ hg bookmark --hidden -r 1 X@foo
1974 1974 bookmarking hidden changeset a765632148dc
1975 1975 (hidden revision 'a765632148dc' is pruned)
1976 1976 $ hg log --template '{rev}:{node}\n'
1977 1977 1:a765632148dc55d38c35c4f247c618701886cb2f
1978 1978 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1979 1979
1980 1980 test hidden revision 0 (issue5385)
1981 1981
1982 1982 $ hg bookmark -d X@foo
1983 1983 $ hg up null -q
1984 1984 $ hg debugobsolete 9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1985 1985 obsoleted 1 changesets
1986 1986 $ echo f > b
1987 1987 $ hg ci -Am'b' -d '2 0'
1988 1988 adding b
1989 1989 $ echo f >> b
1990 1990 $ hg ci -m'b bis' -d '3 0'
1991 1991 $ hg log -T'{rev}:{node}\n'
1992 1992 3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e
1993 1993 2:94375ec45bddd2a824535fc04855bd058c926ec0
1994 1994
1995 1995 $ hg log -T'{rev}:{node}\n' -r:
1996 1996 2:94375ec45bddd2a824535fc04855bd058c926ec0
1997 1997 3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e
1998 1998 $ hg log -T'{rev}:{node}\n' -r:tip
1999 1999 2:94375ec45bddd2a824535fc04855bd058c926ec0
2000 2000 3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e
2001 2001 $ hg log -T'{rev}:{node}\n' -r:0
2002 2002 abort: hidden revision '0' is pruned!
2003 2003 (use --hidden to access hidden revisions)
2004 2004 [255]
2005 2005 $ hg log -T'{rev}:{node}\n' -f
2006 2006 3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e
2007 2007 2:94375ec45bddd2a824535fc04855bd058c926ec0
2008 2008
2009 2009 clear extensions configuration
2010 2010 $ echo '[extensions]' >> $HGRCPATH
2011 2011 $ echo "obs=!" >> $HGRCPATH
2012 2012 $ cd ..
2013 2013
2014 2014 test -u/-k for problematic encoding
2015 2015 # unicode: cp932:
2016 2016 # u30A2 0x83 0x41(= 'A')
2017 2017 # u30C2 0x83 0x61(= 'a')
2018 2018
2019 2019 $ hg init problematicencoding
2020 2020 $ cd problematicencoding
2021 2021
2022 2022 >>> with open('setup.sh', 'wb') as f:
2023 2023 ... f.write(u'''
2024 2024 ... echo a > text
2025 2025 ... hg add text
2026 2026 ... hg --encoding utf-8 commit -u '\u30A2' -m none
2027 2027 ... echo b > text
2028 2028 ... hg --encoding utf-8 commit -u '\u30C2' -m none
2029 2029 ... echo c > text
2030 2030 ... hg --encoding utf-8 commit -u none -m '\u30A2'
2031 2031 ... echo d > text
2032 2032 ... hg --encoding utf-8 commit -u none -m '\u30C2'
2033 2033 ... '''.encode('utf-8')) and None
2034 2034 $ sh < setup.sh
2035 2035
2036 2036 test in problematic encoding
2037 2037 >>> with open('test.sh', 'wb') as f:
2038 2038 ... f.write(u'''
2039 2039 ... hg --encoding cp932 log --template '{rev}\\n' -u '\u30A2'
2040 2040 ... echo ====
2041 2041 ... hg --encoding cp932 log --template '{rev}\\n' -u '\u30C2'
2042 2042 ... echo ====
2043 2043 ... hg --encoding cp932 log --template '{rev}\\n' -k '\u30A2'
2044 2044 ... echo ====
2045 2045 ... hg --encoding cp932 log --template '{rev}\\n' -k '\u30C2'
2046 2046 ... '''.encode('cp932')) and None
2047 2047 $ sh < test.sh
2048 2048 0
2049 2049 ====
2050 2050 1
2051 2051 ====
2052 2052 2
2053 2053 0
2054 2054 ====
2055 2055 3
2056 2056 1
2057 2057
2058 2058 $ cd ..
2059 2059
2060 2060 test hg log on non-existent files and on directories
2061 2061 $ hg init issue1340
2062 2062 $ cd issue1340
2063 2063 $ mkdir d1; mkdir D2; mkdir D3.i; mkdir d4.hg; mkdir d5.d; mkdir .d6
2064 2064 $ echo 1 > d1/f1
2065 2065 $ echo 1 > D2/f1
2066 2066 $ echo 1 > D3.i/f1
2067 2067 $ echo 1 > d4.hg/f1
2068 2068 $ echo 1 > d5.d/f1
2069 2069 $ echo 1 > .d6/f1
2070 2070 $ hg -q add .
2071 2071 $ hg commit -m "a bunch of weird directories"
2072 2072 $ hg log -l1 d1/f1 | grep changeset
2073 2073 changeset: 0:65624cd9070a
2074 2074 $ hg log -l1 f1
2075 2075 $ hg log -l1 . | grep changeset
2076 2076 changeset: 0:65624cd9070a
2077 2077 $ hg log -l1 ./ | grep changeset
2078 2078 changeset: 0:65624cd9070a
2079 2079 $ hg log -l1 d1 | grep changeset
2080 2080 changeset: 0:65624cd9070a
2081 2081 $ hg log -l1 D2 | grep changeset
2082 2082 changeset: 0:65624cd9070a
2083 2083 $ hg log -l1 D2/f1 | grep changeset
2084 2084 changeset: 0:65624cd9070a
2085 2085 $ hg log -l1 D3.i | grep changeset
2086 2086 changeset: 0:65624cd9070a
2087 2087 $ hg log -l1 D3.i/f1 | grep changeset
2088 2088 changeset: 0:65624cd9070a
2089 2089 $ hg log -l1 d4.hg | grep changeset
2090 2090 changeset: 0:65624cd9070a
2091 2091 $ hg log -l1 d4.hg/f1 | grep changeset
2092 2092 changeset: 0:65624cd9070a
2093 2093 $ hg log -l1 d5.d | grep changeset
2094 2094 changeset: 0:65624cd9070a
2095 2095 $ hg log -l1 d5.d/f1 | grep changeset
2096 2096 changeset: 0:65624cd9070a
2097 2097 $ hg log -l1 .d6 | grep changeset
2098 2098 changeset: 0:65624cd9070a
2099 2099 $ hg log -l1 .d6/f1 | grep changeset
2100 2100 changeset: 0:65624cd9070a
2101 2101
2102 2102 issue3772: hg log -r :null showing revision 0 as well
2103 2103
2104 2104 $ hg log -r :null
2105 2105 changeset: 0:65624cd9070a
2106 2106 tag: tip
2107 2107 user: test
2108 2108 date: Thu Jan 01 00:00:00 1970 +0000
2109 2109 summary: a bunch of weird directories
2110 2110
2111 2111 changeset: -1:000000000000
2112 2112 user:
2113 2113 date: Thu Jan 01 00:00:00 1970 +0000
2114 2114
2115 2115 $ hg log -r null:null
2116 2116 changeset: -1:000000000000
2117 2117 user:
2118 2118 date: Thu Jan 01 00:00:00 1970 +0000
2119 2119
2120 2120 working-directory revision requires special treatment
2121 2121
2122 2122 clean:
2123 2123
2124 2124 $ hg log -r 'wdir()' --debug
2125 2125 changeset: 2147483647:ffffffffffffffffffffffffffffffffffffffff
2126 2126 phase: draft
2127 2127 parent: 0:65624cd9070a035fa7191a54f2b8af39f16b0c08
2128 2128 parent: -1:0000000000000000000000000000000000000000
2129 manifest: 2147483647:ffffffffffffffffffffffffffffffffffffffff
2129 2130 user: test
2130 2131 date: [A-Za-z0-9:+ ]+ (re)
2131 2132 extra: branch=default
2132 2133
2133 2134 $ hg log -r 'wdir()' -p --stat
2134 2135 changeset: 2147483647:ffffffffffff
2135 2136 parent: 0:65624cd9070a
2136 2137 user: test
2137 2138 date: [A-Za-z0-9:+ ]+ (re)
2138 2139
2139 2140
2140 2141
2141 2142
2142 2143 dirty:
2143 2144
2144 2145 $ echo 2 >> d1/f1
2145 2146 $ echo 2 > d1/f2
2146 2147 $ hg add d1/f2
2147 2148 $ hg remove .d6/f1
2148 2149 $ hg status
2149 2150 M d1/f1
2150 2151 A d1/f2
2151 2152 R .d6/f1
2152 2153
2153 2154 $ hg log -r 'wdir()'
2154 2155 changeset: 2147483647:ffffffffffff
2155 2156 parent: 0:65624cd9070a
2156 2157 user: test
2157 2158 date: [A-Za-z0-9:+ ]+ (re)
2158 2159
2159 2160 $ hg log -r 'wdir()' -q
2160 2161 2147483647:ffffffffffff
2161 2162
2162 2163 $ hg log -r 'wdir()' --debug
2163 2164 changeset: 2147483647:ffffffffffffffffffffffffffffffffffffffff
2164 2165 phase: draft
2165 2166 parent: 0:65624cd9070a035fa7191a54f2b8af39f16b0c08
2166 2167 parent: -1:0000000000000000000000000000000000000000
2168 manifest: 2147483647:ffffffffffffffffffffffffffffffffffffffff
2167 2169 user: test
2168 2170 date: [A-Za-z0-9:+ ]+ (re)
2169 2171 files: d1/f1
2170 2172 files+: d1/f2
2171 2173 files-: .d6/f1
2172 2174 extra: branch=default
2173 2175
2174 2176 $ hg log -r 'wdir()' -p --stat --git
2175 2177 changeset: 2147483647:ffffffffffff
2176 2178 parent: 0:65624cd9070a
2177 2179 user: test
2178 2180 date: [A-Za-z0-9:+ ]+ (re)
2179 2181
2180 2182 .d6/f1 | 1 -
2181 2183 d1/f1 | 1 +
2182 2184 d1/f2 | 1 +
2183 2185 3 files changed, 2 insertions(+), 1 deletions(-)
2184 2186
2185 2187 diff --git a/.d6/f1 b/.d6/f1
2186 2188 deleted file mode 100644
2187 2189 --- a/.d6/f1
2188 2190 +++ /dev/null
2189 2191 @@ -1,1 +0,0 @@
2190 2192 -1
2191 2193 diff --git a/d1/f1 b/d1/f1
2192 2194 --- a/d1/f1
2193 2195 +++ b/d1/f1
2194 2196 @@ -1,1 +1,2 @@
2195 2197 1
2196 2198 +2
2197 2199 diff --git a/d1/f2 b/d1/f2
2198 2200 new file mode 100644
2199 2201 --- /dev/null
2200 2202 +++ b/d1/f2
2201 2203 @@ -0,0 +1,1 @@
2202 2204 +2
2203 2205
2204 2206 $ hg log -r 'wdir()' -Tjson
2205 2207 [
2206 2208 {
2207 2209 "bookmarks": [],
2208 2210 "branch": "default",
2209 2211 "date": [*, 0], (glob)
2210 2212 "desc": "",
2211 2213 "node": "ffffffffffffffffffffffffffffffffffffffff",
2212 2214 "parents": ["65624cd9070a035fa7191a54f2b8af39f16b0c08"],
2213 2215 "phase": "draft",
2214 2216 "rev": 2147483647,
2215 2217 "tags": [],
2216 2218 "user": "test"
2217 2219 }
2218 2220 ]
2219 2221
2220 2222 $ hg log -r 'wdir()' -Tjson -q
2221 2223 [
2222 2224 {
2223 2225 "node": "ffffffffffffffffffffffffffffffffffffffff",
2224 2226 "rev": 2147483647
2225 2227 }
2226 2228 ]
2227 2229
2228 2230 $ hg log -r 'wdir()' -Tjson --debug
2229 2231 [
2230 2232 {
2231 2233 "added": ["d1/f2"],
2232 2234 "bookmarks": [],
2233 2235 "branch": "default",
2234 2236 "date": [*, 0], (glob)
2235 2237 "desc": "",
2236 2238 "extra": {"branch": "default"},
2237 "manifest": null,
2239 "manifest": "ffffffffffffffffffffffffffffffffffffffff",
2238 2240 "modified": ["d1/f1"],
2239 2241 "node": "ffffffffffffffffffffffffffffffffffffffff",
2240 2242 "parents": ["65624cd9070a035fa7191a54f2b8af39f16b0c08"],
2241 2243 "phase": "draft",
2242 2244 "removed": [".d6/f1"],
2243 2245 "rev": 2147483647,
2244 2246 "tags": [],
2245 2247 "user": "test"
2246 2248 }
2247 2249 ]
2248 2250
2249 2251 $ hg revert -aqC
2250 2252
2251 2253 Check that adding an arbitrary name shows up in log automatically
2252 2254
2253 2255 $ cat > ../names.py <<EOF
2254 2256 > """A small extension to test adding arbitrary names to a repo"""
2255 2257 > from __future__ import absolute_import
2256 2258 > from mercurial import namespaces
2257 2259 >
2258 2260 > def reposetup(ui, repo):
2259 2261 > foo = {b'foo': repo[0].node()}
2260 2262 > names = lambda r: foo.keys()
2261 2263 > namemap = lambda r, name: foo.get(name)
2262 2264 > nodemap = lambda r, node: [name for name, n in foo.items()
2263 2265 > if n == node]
2264 2266 > ns = namespaces.namespace(
2265 2267 > b"bars", templatename=b"bar", logname=b"barlog",
2266 2268 > colorname=b"barcolor", listnames=names, namemap=namemap,
2267 2269 > nodemap=nodemap)
2268 2270 >
2269 2271 > repo.names.addnamespace(ns)
2270 2272 > EOF
2271 2273
2272 2274 $ hg --config extensions.names=../names.py log -r 0
2273 2275 changeset: 0:65624cd9070a
2274 2276 tag: tip
2275 2277 barlog: foo
2276 2278 user: test
2277 2279 date: Thu Jan 01 00:00:00 1970 +0000
2278 2280 summary: a bunch of weird directories
2279 2281
2280 2282 $ hg --config extensions.names=../names.py \
2281 2283 > --config extensions.color= --config color.log.barcolor=red \
2282 2284 > --color=always log -r 0
2283 2285 \x1b[0;33mchangeset: 0:65624cd9070a\x1b[0m (esc)
2284 2286 tag: tip
2285 2287 \x1b[0;31mbarlog: foo\x1b[0m (esc)
2286 2288 user: test
2287 2289 date: Thu Jan 01 00:00:00 1970 +0000
2288 2290 summary: a bunch of weird directories
2289 2291
2290 2292 $ hg --config extensions.names=../names.py log -r 0 --template '{bars}\n'
2291 2293 foo
2292 2294
2293 2295 Templater parse errors:
2294 2296
2295 2297 simple error
2296 2298 $ hg log -r . -T '{shortest(node}'
2297 2299 hg: parse error at 14: unexpected token: end
2298 2300 ({shortest(node}
2299 2301 ^ here)
2300 2302 [255]
2301 2303
2302 2304 multi-line template with error
2303 2305 $ hg log -r . -T 'line 1
2304 2306 > line2
2305 2307 > {shortest(node}
2306 2308 > line4\nline5'
2307 2309 hg: parse error at 27: unexpected token: end
2308 2310 (line 1\nline2\n{shortest(node}\nline4\nline5
2309 2311 ^ here)
2310 2312 [255]
2311 2313
2312 2314 $ cd ..
2313 2315
2314 2316 hg log -f dir across branches
2315 2317
2316 2318 $ hg init acrossbranches
2317 2319 $ cd acrossbranches
2318 2320 $ mkdir d
2319 2321 $ echo a > d/a && hg ci -Aqm a
2320 2322 $ echo b > d/a && hg ci -Aqm b
2321 2323 $ hg up -q 0
2322 2324 $ echo b > d/a && hg ci -Aqm c
2323 2325 $ hg log -f d -T '{desc}' -G
2324 2326 @ c
2325 2327 |
2326 2328 o a
2327 2329
2328 2330 Ensure that largefiles doesn't interfere with following a normal file
2329 2331 $ hg --config extensions.largefiles= log -f d -T '{desc}' -G
2330 2332 The fsmonitor extension is incompatible with the largefiles extension and has been disabled. (fsmonitor !)
2331 2333 @ c
2332 2334 |
2333 2335 o a
2334 2336
2335 2337 $ hg log -f d/a -T '{desc}' -G
2336 2338 @ c
2337 2339 |
2338 2340 o a
2339 2341
2340 2342 $ cd ..
2341 2343
2342 2344 hg log -f with linkrev pointing to another branch
2343 2345 -------------------------------------------------
2344 2346
2345 2347 create history with a filerev whose linkrev points to another branch
2346 2348
2347 2349 $ hg init branchedlinkrev
2348 2350 $ cd branchedlinkrev
2349 2351 $ echo 1 > a
2350 2352 $ hg commit -Am 'content1'
2351 2353 adding a
2352 2354 $ echo 2 > a
2353 2355 $ hg commit -m 'content2'
2354 2356 $ hg up --rev 'desc(content1)'
2355 2357 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
2356 2358 $ echo unrelated > unrelated
2357 2359 $ hg commit -Am 'unrelated'
2358 2360 adding unrelated
2359 2361 created new head
2360 2362 $ hg graft -r 'desc(content2)'
2361 2363 grafting 1:2294ae80ad84 "content2"
2362 2364 $ echo 3 > a
2363 2365 $ hg commit -m 'content3'
2364 2366 $ hg log -G
2365 2367 @ changeset: 4:50b9b36e9c5d
2366 2368 | tag: tip
2367 2369 | user: test
2368 2370 | date: Thu Jan 01 00:00:00 1970 +0000
2369 2371 | summary: content3
2370 2372 |
2371 2373 o changeset: 3:15b2327059e5
2372 2374 | user: test
2373 2375 | date: Thu Jan 01 00:00:00 1970 +0000
2374 2376 | summary: content2
2375 2377 |
2376 2378 o changeset: 2:2029acd1168c
2377 2379 | parent: 0:ae0a3c9f9e95
2378 2380 | user: test
2379 2381 | date: Thu Jan 01 00:00:00 1970 +0000
2380 2382 | summary: unrelated
2381 2383 |
2382 2384 | o changeset: 1:2294ae80ad84
2383 2385 |/ user: test
2384 2386 | date: Thu Jan 01 00:00:00 1970 +0000
2385 2387 | summary: content2
2386 2388 |
2387 2389 o changeset: 0:ae0a3c9f9e95
2388 2390 user: test
2389 2391 date: Thu Jan 01 00:00:00 1970 +0000
2390 2392 summary: content1
2391 2393
2392 2394
2393 2395 log -f on the file should list the graft result.
2394 2396
2395 2397 $ hg log -Gf a
2396 2398 @ changeset: 4:50b9b36e9c5d
2397 2399 | tag: tip
2398 2400 | user: test
2399 2401 | date: Thu Jan 01 00:00:00 1970 +0000
2400 2402 | summary: content3
2401 2403 |
2402 2404 o changeset: 3:15b2327059e5
2403 2405 : user: test
2404 2406 : date: Thu Jan 01 00:00:00 1970 +0000
2405 2407 : summary: content2
2406 2408 :
2407 2409 o changeset: 0:ae0a3c9f9e95
2408 2410 user: test
2409 2411 date: Thu Jan 01 00:00:00 1970 +0000
2410 2412 summary: content1
2411 2413
2412 2414
2413 2415 plain log lists the original version
2414 2416 (XXX we should probably list both)
2415 2417
2416 2418 $ hg log -G a
2417 2419 @ changeset: 4:50b9b36e9c5d
2418 2420 : tag: tip
2419 2421 : user: test
2420 2422 : date: Thu Jan 01 00:00:00 1970 +0000
2421 2423 : summary: content3
2422 2424 :
2423 2425 : o changeset: 1:2294ae80ad84
2424 2426 :/ user: test
2425 2427 : date: Thu Jan 01 00:00:00 1970 +0000
2426 2428 : summary: content2
2427 2429 :
2428 2430 o changeset: 0:ae0a3c9f9e95
2429 2431 user: test
2430 2432 date: Thu Jan 01 00:00:00 1970 +0000
2431 2433 summary: content1
2432 2434
2433 2435
2434 2436 hg log -f from the grafted changeset
2435 2437 (The bootstrap should properly take the topology in account)
2436 2438
2437 2439 $ hg up 'desc(content3)^'
2438 2440 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
2439 2441 $ hg log -Gf a
2440 2442 @ changeset: 3:15b2327059e5
2441 2443 : user: test
2442 2444 : date: Thu Jan 01 00:00:00 1970 +0000
2443 2445 : summary: content2
2444 2446 :
2445 2447 o changeset: 0:ae0a3c9f9e95
2446 2448 user: test
2447 2449 date: Thu Jan 01 00:00:00 1970 +0000
2448 2450 summary: content1
2449 2451
2450 2452
2451 2453 Test that we use the first non-hidden changeset in that case.
2452 2454
2453 2455 (hide the changeset)
2454 2456
2455 2457 $ hg log -T '{node}\n' -r 1
2456 2458 2294ae80ad8447bc78383182eeac50cb049df623
2457 2459 $ hg debugobsolete 2294ae80ad8447bc78383182eeac50cb049df623
2458 2460 obsoleted 1 changesets
2459 2461 $ hg log -G
2460 2462 o changeset: 4:50b9b36e9c5d
2461 2463 | tag: tip
2462 2464 | user: test
2463 2465 | date: Thu Jan 01 00:00:00 1970 +0000
2464 2466 | summary: content3
2465 2467 |
2466 2468 @ changeset: 3:15b2327059e5
2467 2469 | user: test
2468 2470 | date: Thu Jan 01 00:00:00 1970 +0000
2469 2471 | summary: content2
2470 2472 |
2471 2473 o changeset: 2:2029acd1168c
2472 2474 | parent: 0:ae0a3c9f9e95
2473 2475 | user: test
2474 2476 | date: Thu Jan 01 00:00:00 1970 +0000
2475 2477 | summary: unrelated
2476 2478 |
2477 2479 o changeset: 0:ae0a3c9f9e95
2478 2480 user: test
2479 2481 date: Thu Jan 01 00:00:00 1970 +0000
2480 2482 summary: content1
2481 2483
2482 2484
2483 2485 Check that log on the file does not drop the file revision.
2484 2486
2485 2487 $ hg log -G a
2486 2488 o changeset: 4:50b9b36e9c5d
2487 2489 | tag: tip
2488 2490 | user: test
2489 2491 | date: Thu Jan 01 00:00:00 1970 +0000
2490 2492 | summary: content3
2491 2493 |
2492 2494 @ changeset: 3:15b2327059e5
2493 2495 : user: test
2494 2496 : date: Thu Jan 01 00:00:00 1970 +0000
2495 2497 : summary: content2
2496 2498 :
2497 2499 o changeset: 0:ae0a3c9f9e95
2498 2500 user: test
2499 2501 date: Thu Jan 01 00:00:00 1970 +0000
2500 2502 summary: content1
2501 2503
2502 2504
2503 2505 Even when a head revision is linkrev-shadowed.
2504 2506
2505 2507 $ hg log -T '{node}\n' -r 4
2506 2508 50b9b36e9c5df2c6fc6dcefa8ad0da929e84aed2
2507 2509 $ hg debugobsolete 50b9b36e9c5df2c6fc6dcefa8ad0da929e84aed2
2508 2510 obsoleted 1 changesets
2509 2511 $ hg log -G a
2510 2512 @ changeset: 3:15b2327059e5
2511 2513 : tag: tip
2512 2514 : user: test
2513 2515 : date: Thu Jan 01 00:00:00 1970 +0000
2514 2516 : summary: content2
2515 2517 :
2516 2518 o changeset: 0:ae0a3c9f9e95
2517 2519 user: test
2518 2520 date: Thu Jan 01 00:00:00 1970 +0000
2519 2521 summary: content1
2520 2522
2521 2523
2522 2524 $ cd ..
2523 2525
2524 2526 Even when the file revision is missing from some head:
2525 2527
2526 2528 $ hg init issue4490
2527 2529 $ cd issue4490
2528 2530 $ echo '[experimental]' >> .hg/hgrc
2529 2531 $ echo 'evolution.createmarkers=True' >> .hg/hgrc
2530 2532 $ echo a > a
2531 2533 $ hg ci -Am0
2532 2534 adding a
2533 2535 $ echo b > b
2534 2536 $ hg ci -Am1
2535 2537 adding b
2536 2538 $ echo B > b
2537 2539 $ hg ci --amend -m 1
2538 2540 $ hg up 0
2539 2541 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
2540 2542 $ echo c > c
2541 2543 $ hg ci -Am2
2542 2544 adding c
2543 2545 created new head
2544 2546 $ hg up 'head() and not .'
2545 2547 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
2546 2548 $ hg log -G
2547 2549 o changeset: 3:db815d6d32e6
2548 2550 | tag: tip
2549 2551 | parent: 0:f7b1eb17ad24
2550 2552 | user: test
2551 2553 | date: Thu Jan 01 00:00:00 1970 +0000
2552 2554 | summary: 2
2553 2555 |
2554 2556 | @ changeset: 2:9bc8ce7f9356
2555 2557 |/ parent: 0:f7b1eb17ad24
2556 2558 | user: test
2557 2559 | date: Thu Jan 01 00:00:00 1970 +0000
2558 2560 | summary: 1
2559 2561 |
2560 2562 o changeset: 0:f7b1eb17ad24
2561 2563 user: test
2562 2564 date: Thu Jan 01 00:00:00 1970 +0000
2563 2565 summary: 0
2564 2566
2565 2567 $ hg log -f -G b
2566 2568 @ changeset: 2:9bc8ce7f9356
2567 2569 | parent: 0:f7b1eb17ad24
2568 2570 ~ user: test
2569 2571 date: Thu Jan 01 00:00:00 1970 +0000
2570 2572 summary: 1
2571 2573
2572 2574 $ hg log -G b
2573 2575 @ changeset: 2:9bc8ce7f9356
2574 2576 | parent: 0:f7b1eb17ad24
2575 2577 ~ user: test
2576 2578 date: Thu Jan 01 00:00:00 1970 +0000
2577 2579 summary: 1
2578 2580
2579 2581 $ cd ..
2580 2582
2581 2583 Check proper report when the manifest changes but not the file issue4499
2582 2584 ------------------------------------------------------------------------
2583 2585
2584 2586 $ hg init issue4499
2585 2587 $ cd issue4499
2586 2588 $ for f in A B C D F E G H I J K L M N O P Q R S T U; do
2587 2589 > echo 1 > $f;
2588 2590 > hg add $f;
2589 2591 > done
2590 2592 $ hg commit -m 'A1B1C1'
2591 2593 $ echo 2 > A
2592 2594 $ echo 2 > B
2593 2595 $ echo 2 > C
2594 2596 $ hg commit -m 'A2B2C2'
2595 2597 $ hg up 0
2596 2598 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
2597 2599 $ echo 3 > A
2598 2600 $ echo 2 > B
2599 2601 $ echo 2 > C
2600 2602 $ hg commit -m 'A3B2C2'
2601 2603 created new head
2602 2604
2603 2605 $ hg log -G
2604 2606 @ changeset: 2:fe5fc3d0eb17
2605 2607 | tag: tip
2606 2608 | parent: 0:abf4f0e38563
2607 2609 | user: test
2608 2610 | date: Thu Jan 01 00:00:00 1970 +0000
2609 2611 | summary: A3B2C2
2610 2612 |
2611 2613 | o changeset: 1:07dcc6b312c0
2612 2614 |/ user: test
2613 2615 | date: Thu Jan 01 00:00:00 1970 +0000
2614 2616 | summary: A2B2C2
2615 2617 |
2616 2618 o changeset: 0:abf4f0e38563
2617 2619 user: test
2618 2620 date: Thu Jan 01 00:00:00 1970 +0000
2619 2621 summary: A1B1C1
2620 2622
2621 2623
2622 2624 Log -f on B should reports current changesets
2623 2625
2624 2626 $ hg log -fG B
2625 2627 @ changeset: 2:fe5fc3d0eb17
2626 2628 | tag: tip
2627 2629 | parent: 0:abf4f0e38563
2628 2630 | user: test
2629 2631 | date: Thu Jan 01 00:00:00 1970 +0000
2630 2632 | summary: A3B2C2
2631 2633 |
2632 2634 o changeset: 0:abf4f0e38563
2633 2635 user: test
2634 2636 date: Thu Jan 01 00:00:00 1970 +0000
2635 2637 summary: A1B1C1
2636 2638
2637 2639 $ cd ..
@@ -1,1306 +1,1303 b''
1 1 Test template keywords
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 Working-directory revision has special identifiers, though they are still
50 50 experimental:
51 51
52 52 $ hg log -r 'wdir()' -T '{rev}:{node}\n'
53 53 2147483647:ffffffffffffffffffffffffffffffffffffffff
54 54
55 55 $ hg log -r 'wdir()' -Tjson --debug
56 56 [
57 57 {
58 58 "added": [],
59 59 "bookmarks": [],
60 60 "branch": "default",
61 61 "date": [0, 0],
62 62 "desc": "",
63 63 "extra": {"branch": "default"},
64 "manifest": null,
64 "manifest": "ffffffffffffffffffffffffffffffffffffffff",
65 65 "modified": [],
66 66 "node": "ffffffffffffffffffffffffffffffffffffffff",
67 67 "parents": ["95c24699272ef57d062b8bccc32c878bf841784a"],
68 68 "phase": "draft",
69 69 "removed": [],
70 70 "rev": 2147483647,
71 71 "tags": [],
72 72 "user": "test"
73 73 }
74 74 ]
75 75
76 Some keywords are invalid for working-directory revision, but they should
77 never cause crash:
78
79 76 $ hg log -r 'wdir()' -T '{manifest}\n'
80
77 2147483647:ffffffffffff
81 78
82 79 Changectx-derived keywords are disabled within {manifest} as {node} changes:
83 80
84 81 $ hg log -r0 -T 'outer:{p1node} {manifest % "inner:{p1node}"}\n'
85 82 outer:0000000000000000000000000000000000000000 inner:
86 83
87 84 Check that {phase} works correctly on parents:
88 85
89 86 $ cat << EOF > parentphase
90 87 > changeset_debug = '{rev} ({phase}):{parents}\n'
91 88 > parent = ' {rev} ({phase})'
92 89 > EOF
93 90 $ hg phase -r 5 --public
94 91 $ hg phase -r 7 --secret --force
95 92 $ hg log --debug -G --style ./parentphase
96 93 @ 8 (secret): 7 (secret) -1 (public)
97 94 |
98 95 o 7 (secret): -1 (public) -1 (public)
99 96
100 97 o 6 (draft): 5 (public) 4 (draft)
101 98 |\
102 99 | o 5 (public): 3 (public) -1 (public)
103 100 | |
104 101 o | 4 (draft): 3 (public) -1 (public)
105 102 |/
106 103 o 3 (public): 2 (public) -1 (public)
107 104 |
108 105 o 2 (public): 1 (public) -1 (public)
109 106 |
110 107 o 1 (public): 0 (public) -1 (public)
111 108 |
112 109 o 0 (public): -1 (public) -1 (public)
113 110
114 111
115 112 Keys work:
116 113
117 114 $ for key in author branch branches date desc file_adds file_dels file_mods \
118 115 > file_copies file_copies_switch files \
119 116 > manifest node parents rev tags diffstat extras \
120 117 > p1rev p2rev p1node p2node user; do
121 118 > for mode in '' --verbose --debug; do
122 119 > hg log $mode --template "$key$mode: {$key}\n"
123 120 > done
124 121 > done
125 122 author: test
126 123 author: User Name <user@hostname>
127 124 author: person
128 125 author: person
129 126 author: person
130 127 author: person
131 128 author: other@place
132 129 author: A. N. Other <other@place>
133 130 author: User Name <user@hostname>
134 131 author--verbose: test
135 132 author--verbose: User Name <user@hostname>
136 133 author--verbose: person
137 134 author--verbose: person
138 135 author--verbose: person
139 136 author--verbose: person
140 137 author--verbose: other@place
141 138 author--verbose: A. N. Other <other@place>
142 139 author--verbose: User Name <user@hostname>
143 140 author--debug: test
144 141 author--debug: User Name <user@hostname>
145 142 author--debug: person
146 143 author--debug: person
147 144 author--debug: person
148 145 author--debug: person
149 146 author--debug: other@place
150 147 author--debug: A. N. Other <other@place>
151 148 author--debug: User Name <user@hostname>
152 149 branch: default
153 150 branch: default
154 151 branch: default
155 152 branch: default
156 153 branch: foo
157 154 branch: default
158 155 branch: default
159 156 branch: default
160 157 branch: default
161 158 branch--verbose: default
162 159 branch--verbose: default
163 160 branch--verbose: default
164 161 branch--verbose: default
165 162 branch--verbose: foo
166 163 branch--verbose: default
167 164 branch--verbose: default
168 165 branch--verbose: default
169 166 branch--verbose: default
170 167 branch--debug: default
171 168 branch--debug: default
172 169 branch--debug: default
173 170 branch--debug: default
174 171 branch--debug: foo
175 172 branch--debug: default
176 173 branch--debug: default
177 174 branch--debug: default
178 175 branch--debug: default
179 176 branches:
180 177 branches:
181 178 branches:
182 179 branches:
183 180 branches: foo
184 181 branches:
185 182 branches:
186 183 branches:
187 184 branches:
188 185 branches--verbose:
189 186 branches--verbose:
190 187 branches--verbose:
191 188 branches--verbose:
192 189 branches--verbose: foo
193 190 branches--verbose:
194 191 branches--verbose:
195 192 branches--verbose:
196 193 branches--verbose:
197 194 branches--debug:
198 195 branches--debug:
199 196 branches--debug:
200 197 branches--debug:
201 198 branches--debug: foo
202 199 branches--debug:
203 200 branches--debug:
204 201 branches--debug:
205 202 branches--debug:
206 203 date: 1577872860.00
207 204 date: 1000000.00
208 205 date: 1500001.00
209 206 date: 1500000.00
210 207 date: 1400000.00
211 208 date: 1300000.00
212 209 date: 1200000.00
213 210 date: 1100000.00
214 211 date: 1000000.00
215 212 date--verbose: 1577872860.00
216 213 date--verbose: 1000000.00
217 214 date--verbose: 1500001.00
218 215 date--verbose: 1500000.00
219 216 date--verbose: 1400000.00
220 217 date--verbose: 1300000.00
221 218 date--verbose: 1200000.00
222 219 date--verbose: 1100000.00
223 220 date--verbose: 1000000.00
224 221 date--debug: 1577872860.00
225 222 date--debug: 1000000.00
226 223 date--debug: 1500001.00
227 224 date--debug: 1500000.00
228 225 date--debug: 1400000.00
229 226 date--debug: 1300000.00
230 227 date--debug: 1200000.00
231 228 date--debug: 1100000.00
232 229 date--debug: 1000000.00
233 230 desc: third
234 231 desc: second
235 232 desc: merge
236 233 desc: new head
237 234 desc: new branch
238 235 desc: no user, no domain
239 236 desc: no person
240 237 desc: other 1
241 238 other 2
242 239
243 240 other 3
244 241 desc: line 1
245 242 line 2
246 243 desc--verbose: third
247 244 desc--verbose: second
248 245 desc--verbose: merge
249 246 desc--verbose: new head
250 247 desc--verbose: new branch
251 248 desc--verbose: no user, no domain
252 249 desc--verbose: no person
253 250 desc--verbose: other 1
254 251 other 2
255 252
256 253 other 3
257 254 desc--verbose: line 1
258 255 line 2
259 256 desc--debug: third
260 257 desc--debug: second
261 258 desc--debug: merge
262 259 desc--debug: new head
263 260 desc--debug: new branch
264 261 desc--debug: no user, no domain
265 262 desc--debug: no person
266 263 desc--debug: other 1
267 264 other 2
268 265
269 266 other 3
270 267 desc--debug: line 1
271 268 line 2
272 269 file_adds: fourth third
273 270 file_adds: second
274 271 file_adds:
275 272 file_adds: d
276 273 file_adds:
277 274 file_adds:
278 275 file_adds: c
279 276 file_adds: b
280 277 file_adds: a
281 278 file_adds--verbose: fourth third
282 279 file_adds--verbose: second
283 280 file_adds--verbose:
284 281 file_adds--verbose: d
285 282 file_adds--verbose:
286 283 file_adds--verbose:
287 284 file_adds--verbose: c
288 285 file_adds--verbose: b
289 286 file_adds--verbose: a
290 287 file_adds--debug: fourth third
291 288 file_adds--debug: second
292 289 file_adds--debug:
293 290 file_adds--debug: d
294 291 file_adds--debug:
295 292 file_adds--debug:
296 293 file_adds--debug: c
297 294 file_adds--debug: b
298 295 file_adds--debug: a
299 296 file_dels: second
300 297 file_dels:
301 298 file_dels:
302 299 file_dels:
303 300 file_dels:
304 301 file_dels:
305 302 file_dels:
306 303 file_dels:
307 304 file_dels:
308 305 file_dels--verbose: second
309 306 file_dels--verbose:
310 307 file_dels--verbose:
311 308 file_dels--verbose:
312 309 file_dels--verbose:
313 310 file_dels--verbose:
314 311 file_dels--verbose:
315 312 file_dels--verbose:
316 313 file_dels--verbose:
317 314 file_dels--debug: second
318 315 file_dels--debug:
319 316 file_dels--debug:
320 317 file_dels--debug:
321 318 file_dels--debug:
322 319 file_dels--debug:
323 320 file_dels--debug:
324 321 file_dels--debug:
325 322 file_dels--debug:
326 323 file_mods:
327 324 file_mods:
328 325 file_mods:
329 326 file_mods:
330 327 file_mods:
331 328 file_mods: c
332 329 file_mods:
333 330 file_mods:
334 331 file_mods:
335 332 file_mods--verbose:
336 333 file_mods--verbose:
337 334 file_mods--verbose:
338 335 file_mods--verbose:
339 336 file_mods--verbose:
340 337 file_mods--verbose: c
341 338 file_mods--verbose:
342 339 file_mods--verbose:
343 340 file_mods--verbose:
344 341 file_mods--debug:
345 342 file_mods--debug:
346 343 file_mods--debug:
347 344 file_mods--debug:
348 345 file_mods--debug:
349 346 file_mods--debug: c
350 347 file_mods--debug:
351 348 file_mods--debug:
352 349 file_mods--debug:
353 350 file_copies: fourth (second)
354 351 file_copies:
355 352 file_copies:
356 353 file_copies:
357 354 file_copies:
358 355 file_copies:
359 356 file_copies:
360 357 file_copies:
361 358 file_copies:
362 359 file_copies--verbose: fourth (second)
363 360 file_copies--verbose:
364 361 file_copies--verbose:
365 362 file_copies--verbose:
366 363 file_copies--verbose:
367 364 file_copies--verbose:
368 365 file_copies--verbose:
369 366 file_copies--verbose:
370 367 file_copies--verbose:
371 368 file_copies--debug: fourth (second)
372 369 file_copies--debug:
373 370 file_copies--debug:
374 371 file_copies--debug:
375 372 file_copies--debug:
376 373 file_copies--debug:
377 374 file_copies--debug:
378 375 file_copies--debug:
379 376 file_copies--debug:
380 377 file_copies_switch:
381 378 file_copies_switch:
382 379 file_copies_switch:
383 380 file_copies_switch:
384 381 file_copies_switch:
385 382 file_copies_switch:
386 383 file_copies_switch:
387 384 file_copies_switch:
388 385 file_copies_switch:
389 386 file_copies_switch--verbose:
390 387 file_copies_switch--verbose:
391 388 file_copies_switch--verbose:
392 389 file_copies_switch--verbose:
393 390 file_copies_switch--verbose:
394 391 file_copies_switch--verbose:
395 392 file_copies_switch--verbose:
396 393 file_copies_switch--verbose:
397 394 file_copies_switch--verbose:
398 395 file_copies_switch--debug:
399 396 file_copies_switch--debug:
400 397 file_copies_switch--debug:
401 398 file_copies_switch--debug:
402 399 file_copies_switch--debug:
403 400 file_copies_switch--debug:
404 401 file_copies_switch--debug:
405 402 file_copies_switch--debug:
406 403 file_copies_switch--debug:
407 404 files: fourth second third
408 405 files: second
409 406 files:
410 407 files: d
411 408 files:
412 409 files: c
413 410 files: c
414 411 files: b
415 412 files: a
416 413 files--verbose: fourth second third
417 414 files--verbose: second
418 415 files--verbose:
419 416 files--verbose: d
420 417 files--verbose:
421 418 files--verbose: c
422 419 files--verbose: c
423 420 files--verbose: b
424 421 files--verbose: a
425 422 files--debug: fourth second third
426 423 files--debug: second
427 424 files--debug:
428 425 files--debug: d
429 426 files--debug:
430 427 files--debug: c
431 428 files--debug: c
432 429 files--debug: b
433 430 files--debug: a
434 431 manifest: 6:94961b75a2da
435 432 manifest: 5:f2dbc354b94e
436 433 manifest: 4:4dc3def4f9b4
437 434 manifest: 4:4dc3def4f9b4
438 435 manifest: 3:cb5a1327723b
439 436 manifest: 3:cb5a1327723b
440 437 manifest: 2:6e0e82995c35
441 438 manifest: 1:4e8d705b1e53
442 439 manifest: 0:a0c8bcbbb45c
443 440 manifest--verbose: 6:94961b75a2da
444 441 manifest--verbose: 5:f2dbc354b94e
445 442 manifest--verbose: 4:4dc3def4f9b4
446 443 manifest--verbose: 4:4dc3def4f9b4
447 444 manifest--verbose: 3:cb5a1327723b
448 445 manifest--verbose: 3:cb5a1327723b
449 446 manifest--verbose: 2:6e0e82995c35
450 447 manifest--verbose: 1:4e8d705b1e53
451 448 manifest--verbose: 0:a0c8bcbbb45c
452 449 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
453 450 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
454 451 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
455 452 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
456 453 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
457 454 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
458 455 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
459 456 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
460 457 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
461 458 node: 95c24699272ef57d062b8bccc32c878bf841784a
462 459 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
463 460 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
464 461 node: 13207e5a10d9fd28ec424934298e176197f2c67f
465 462 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
466 463 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
467 464 node: 97054abb4ab824450e9164180baf491ae0078465
468 465 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
469 466 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
470 467 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
471 468 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
472 469 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
473 470 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
474 471 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
475 472 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
476 473 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
477 474 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
478 475 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
479 476 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
480 477 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
481 478 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
482 479 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
483 480 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
484 481 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
485 482 node--debug: 97054abb4ab824450e9164180baf491ae0078465
486 483 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
487 484 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
488 485 parents:
489 486 parents: -1:000000000000
490 487 parents: 5:13207e5a10d9 4:bbe44766e73d
491 488 parents: 3:10e46f2dcbf4
492 489 parents:
493 490 parents:
494 491 parents:
495 492 parents:
496 493 parents:
497 494 parents--verbose:
498 495 parents--verbose: -1:000000000000
499 496 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
500 497 parents--verbose: 3:10e46f2dcbf4
501 498 parents--verbose:
502 499 parents--verbose:
503 500 parents--verbose:
504 501 parents--verbose:
505 502 parents--verbose:
506 503 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
507 504 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
508 505 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
509 506 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
510 507 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
511 508 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
512 509 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
513 510 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
514 511 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
515 512 rev: 8
516 513 rev: 7
517 514 rev: 6
518 515 rev: 5
519 516 rev: 4
520 517 rev: 3
521 518 rev: 2
522 519 rev: 1
523 520 rev: 0
524 521 rev--verbose: 8
525 522 rev--verbose: 7
526 523 rev--verbose: 6
527 524 rev--verbose: 5
528 525 rev--verbose: 4
529 526 rev--verbose: 3
530 527 rev--verbose: 2
531 528 rev--verbose: 1
532 529 rev--verbose: 0
533 530 rev--debug: 8
534 531 rev--debug: 7
535 532 rev--debug: 6
536 533 rev--debug: 5
537 534 rev--debug: 4
538 535 rev--debug: 3
539 536 rev--debug: 2
540 537 rev--debug: 1
541 538 rev--debug: 0
542 539 tags: tip
543 540 tags:
544 541 tags:
545 542 tags:
546 543 tags:
547 544 tags:
548 545 tags:
549 546 tags:
550 547 tags:
551 548 tags--verbose: tip
552 549 tags--verbose:
553 550 tags--verbose:
554 551 tags--verbose:
555 552 tags--verbose:
556 553 tags--verbose:
557 554 tags--verbose:
558 555 tags--verbose:
559 556 tags--verbose:
560 557 tags--debug: tip
561 558 tags--debug:
562 559 tags--debug:
563 560 tags--debug:
564 561 tags--debug:
565 562 tags--debug:
566 563 tags--debug:
567 564 tags--debug:
568 565 tags--debug:
569 566 diffstat: 3: +2/-1
570 567 diffstat: 1: +1/-0
571 568 diffstat: 0: +0/-0
572 569 diffstat: 1: +1/-0
573 570 diffstat: 0: +0/-0
574 571 diffstat: 1: +1/-0
575 572 diffstat: 1: +4/-0
576 573 diffstat: 1: +2/-0
577 574 diffstat: 1: +1/-0
578 575 diffstat--verbose: 3: +2/-1
579 576 diffstat--verbose: 1: +1/-0
580 577 diffstat--verbose: 0: +0/-0
581 578 diffstat--verbose: 1: +1/-0
582 579 diffstat--verbose: 0: +0/-0
583 580 diffstat--verbose: 1: +1/-0
584 581 diffstat--verbose: 1: +4/-0
585 582 diffstat--verbose: 1: +2/-0
586 583 diffstat--verbose: 1: +1/-0
587 584 diffstat--debug: 3: +2/-1
588 585 diffstat--debug: 1: +1/-0
589 586 diffstat--debug: 0: +0/-0
590 587 diffstat--debug: 1: +1/-0
591 588 diffstat--debug: 0: +0/-0
592 589 diffstat--debug: 1: +1/-0
593 590 diffstat--debug: 1: +4/-0
594 591 diffstat--debug: 1: +2/-0
595 592 diffstat--debug: 1: +1/-0
596 593 extras: branch=default
597 594 extras: branch=default
598 595 extras: branch=default
599 596 extras: branch=default
600 597 extras: branch=foo
601 598 extras: branch=default
602 599 extras: branch=default
603 600 extras: branch=default
604 601 extras: branch=default
605 602 extras--verbose: branch=default
606 603 extras--verbose: branch=default
607 604 extras--verbose: branch=default
608 605 extras--verbose: branch=default
609 606 extras--verbose: branch=foo
610 607 extras--verbose: branch=default
611 608 extras--verbose: branch=default
612 609 extras--verbose: branch=default
613 610 extras--verbose: branch=default
614 611 extras--debug: branch=default
615 612 extras--debug: branch=default
616 613 extras--debug: branch=default
617 614 extras--debug: branch=default
618 615 extras--debug: branch=foo
619 616 extras--debug: branch=default
620 617 extras--debug: branch=default
621 618 extras--debug: branch=default
622 619 extras--debug: branch=default
623 620 p1rev: 7
624 621 p1rev: -1
625 622 p1rev: 5
626 623 p1rev: 3
627 624 p1rev: 3
628 625 p1rev: 2
629 626 p1rev: 1
630 627 p1rev: 0
631 628 p1rev: -1
632 629 p1rev--verbose: 7
633 630 p1rev--verbose: -1
634 631 p1rev--verbose: 5
635 632 p1rev--verbose: 3
636 633 p1rev--verbose: 3
637 634 p1rev--verbose: 2
638 635 p1rev--verbose: 1
639 636 p1rev--verbose: 0
640 637 p1rev--verbose: -1
641 638 p1rev--debug: 7
642 639 p1rev--debug: -1
643 640 p1rev--debug: 5
644 641 p1rev--debug: 3
645 642 p1rev--debug: 3
646 643 p1rev--debug: 2
647 644 p1rev--debug: 1
648 645 p1rev--debug: 0
649 646 p1rev--debug: -1
650 647 p2rev: -1
651 648 p2rev: -1
652 649 p2rev: 4
653 650 p2rev: -1
654 651 p2rev: -1
655 652 p2rev: -1
656 653 p2rev: -1
657 654 p2rev: -1
658 655 p2rev: -1
659 656 p2rev--verbose: -1
660 657 p2rev--verbose: -1
661 658 p2rev--verbose: 4
662 659 p2rev--verbose: -1
663 660 p2rev--verbose: -1
664 661 p2rev--verbose: -1
665 662 p2rev--verbose: -1
666 663 p2rev--verbose: -1
667 664 p2rev--verbose: -1
668 665 p2rev--debug: -1
669 666 p2rev--debug: -1
670 667 p2rev--debug: 4
671 668 p2rev--debug: -1
672 669 p2rev--debug: -1
673 670 p2rev--debug: -1
674 671 p2rev--debug: -1
675 672 p2rev--debug: -1
676 673 p2rev--debug: -1
677 674 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
678 675 p1node: 0000000000000000000000000000000000000000
679 676 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
680 677 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
681 678 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
682 679 p1node: 97054abb4ab824450e9164180baf491ae0078465
683 680 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
684 681 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
685 682 p1node: 0000000000000000000000000000000000000000
686 683 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
687 684 p1node--verbose: 0000000000000000000000000000000000000000
688 685 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
689 686 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
690 687 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
691 688 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
692 689 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
693 690 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
694 691 p1node--verbose: 0000000000000000000000000000000000000000
695 692 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
696 693 p1node--debug: 0000000000000000000000000000000000000000
697 694 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
698 695 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
699 696 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
700 697 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
701 698 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
702 699 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
703 700 p1node--debug: 0000000000000000000000000000000000000000
704 701 p2node: 0000000000000000000000000000000000000000
705 702 p2node: 0000000000000000000000000000000000000000
706 703 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
707 704 p2node: 0000000000000000000000000000000000000000
708 705 p2node: 0000000000000000000000000000000000000000
709 706 p2node: 0000000000000000000000000000000000000000
710 707 p2node: 0000000000000000000000000000000000000000
711 708 p2node: 0000000000000000000000000000000000000000
712 709 p2node: 0000000000000000000000000000000000000000
713 710 p2node--verbose: 0000000000000000000000000000000000000000
714 711 p2node--verbose: 0000000000000000000000000000000000000000
715 712 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
716 713 p2node--verbose: 0000000000000000000000000000000000000000
717 714 p2node--verbose: 0000000000000000000000000000000000000000
718 715 p2node--verbose: 0000000000000000000000000000000000000000
719 716 p2node--verbose: 0000000000000000000000000000000000000000
720 717 p2node--verbose: 0000000000000000000000000000000000000000
721 718 p2node--verbose: 0000000000000000000000000000000000000000
722 719 p2node--debug: 0000000000000000000000000000000000000000
723 720 p2node--debug: 0000000000000000000000000000000000000000
724 721 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
725 722 p2node--debug: 0000000000000000000000000000000000000000
726 723 p2node--debug: 0000000000000000000000000000000000000000
727 724 p2node--debug: 0000000000000000000000000000000000000000
728 725 p2node--debug: 0000000000000000000000000000000000000000
729 726 p2node--debug: 0000000000000000000000000000000000000000
730 727 p2node--debug: 0000000000000000000000000000000000000000
731 728 user: test
732 729 user: User Name <user@hostname>
733 730 user: person
734 731 user: person
735 732 user: person
736 733 user: person
737 734 user: other@place
738 735 user: A. N. Other <other@place>
739 736 user: User Name <user@hostname>
740 737 user--verbose: test
741 738 user--verbose: User Name <user@hostname>
742 739 user--verbose: person
743 740 user--verbose: person
744 741 user--verbose: person
745 742 user--verbose: person
746 743 user--verbose: other@place
747 744 user--verbose: A. N. Other <other@place>
748 745 user--verbose: User Name <user@hostname>
749 746 user--debug: test
750 747 user--debug: User Name <user@hostname>
751 748 user--debug: person
752 749 user--debug: person
753 750 user--debug: person
754 751 user--debug: person
755 752 user--debug: other@place
756 753 user--debug: A. N. Other <other@place>
757 754 user--debug: User Name <user@hostname>
758 755
759 756 Add a dummy commit to make up for the instability of the above:
760 757
761 758 $ echo a > a
762 759 $ hg add a
763 760 $ hg ci -m future
764 761
765 762 Add a commit that does all possible modifications at once
766 763
767 764 $ echo modify >> third
768 765 $ touch b
769 766 $ hg add b
770 767 $ hg mv fourth fifth
771 768 $ hg rm a
772 769 $ hg ci -m "Modify, add, remove, rename"
773 770
774 771 Test files list:
775 772
776 773 $ hg log -l1 -T '{join(file_mods, " ")}\n'
777 774 third
778 775 $ hg log -l1 -T '{file_mods % "{file}\n"}'
779 776 third
780 777 $ hg log -l1 -T '{file_mods % "{path}\n"}'
781 778 third
782 779
783 780 $ hg log -l1 -T '{join(files, " ")}\n'
784 781 a b fifth fourth third
785 782 $ hg log -l1 -T '{files % "{file}\n"}'
786 783 a
787 784 b
788 785 fifth
789 786 fourth
790 787 third
791 788 $ hg log -l1 -T '{files % "{path}\n"}'
792 789 a
793 790 b
794 791 fifth
795 792 fourth
796 793 third
797 794
798 795 Test file copies dict:
799 796
800 797 $ hg log -r8 -T '{join(file_copies, " ")}\n'
801 798 fourth (second)
802 799 $ hg log -r8 -T '{file_copies % "{name} <- {source}\n"}'
803 800 fourth <- second
804 801 $ hg log -r8 -T '{file_copies % "{path} <- {source}\n"}'
805 802 fourth <- second
806 803
807 804 $ hg log -r8 -T '{join(file_copies_switch, " ")}\n'
808 805
809 806 $ hg log -r8 -C -T '{join(file_copies_switch, " ")}\n'
810 807 fourth (second)
811 808 $ hg log -r8 -C -T '{file_copies_switch % "{name} <- {source}\n"}'
812 809 fourth <- second
813 810 $ hg log -r8 -C -T '{file_copies_switch % "{path} <- {source}\n"}'
814 811 fourth <- second
815 812
816 813 Test file attributes:
817 814
818 815 $ hg log -l1 -T '{files % "{status} {pad(size, 3, left=True)} {path}\n"}'
819 816 R a
820 817 A 0 b
821 818 A 7 fifth
822 819 R fourth
823 820 M 13 third
824 821
825 822 Test file status including clean ones:
826 823
827 824 $ hg log -r9 -T '{files("**") % "{status} {path}\n"}'
828 825 A a
829 826 C fourth
830 827 C third
831 828
832 829 Test index keyword:
833 830
834 831 $ hg log -l 2 -T '{index + 10}{files % " {index}:{file}"}\n'
835 832 10 0:a 1:b 2:fifth 3:fourth 4:third
836 833 11 0:a
837 834
838 835 $ hg branches -T '{index} {branch}\n'
839 836 0 default
840 837 1 foo
841 838
842 839 ui verbosity:
843 840
844 841 $ hg log -l1 -T '{verbosity}\n'
845 842
846 843 $ hg log -l1 -T '{verbosity}\n' --debug
847 844 debug
848 845 $ hg log -l1 -T '{verbosity}\n' --quiet
849 846 quiet
850 847 $ hg log -l1 -T '{verbosity}\n' --verbose
851 848 verbose
852 849
853 850 $ cd ..
854 851
855 852 latesttag:
856 853
857 854 $ hg init latesttag
858 855 $ cd latesttag
859 856
860 857 $ echo a > file
861 858 $ hg ci -Am a -d '0 0'
862 859 adding file
863 860
864 861 $ echo b >> file
865 862 $ hg ci -m b -d '1 0'
866 863
867 864 $ echo c >> head1
868 865 $ hg ci -Am h1c -d '2 0'
869 866 adding head1
870 867
871 868 $ hg update -q 1
872 869 $ echo d >> head2
873 870 $ hg ci -Am h2d -d '3 0'
874 871 adding head2
875 872 created new head
876 873
877 874 $ echo e >> head2
878 875 $ hg ci -m h2e -d '4 0'
879 876
880 877 $ hg merge -q
881 878 $ hg ci -m merge -d '5 -3600'
882 879
883 880 No tag set:
884 881
885 882 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
886 883 @ 5: null+5
887 884 |\
888 885 | o 4: null+4
889 886 | |
890 887 | o 3: null+3
891 888 | |
892 889 o | 2: null+3
893 890 |/
894 891 o 1: null+2
895 892 |
896 893 o 0: null+1
897 894
898 895
899 896 One common tag: longest path wins for {latesttagdistance}:
900 897
901 898 $ hg tag -r 1 -m t1 -d '6 0' t1
902 899 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
903 900 @ 6: t1+4
904 901 |
905 902 o 5: t1+3
906 903 |\
907 904 | o 4: t1+2
908 905 | |
909 906 | o 3: t1+1
910 907 | |
911 908 o | 2: t1+1
912 909 |/
913 910 o 1: t1+0
914 911 |
915 912 o 0: null+1
916 913
917 914
918 915 One ancestor tag: closest wins:
919 916
920 917 $ hg tag -r 2 -m t2 -d '7 0' t2
921 918 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
922 919 @ 7: t2+3
923 920 |
924 921 o 6: t2+2
925 922 |
926 923 o 5: t2+1
927 924 |\
928 925 | o 4: t1+2
929 926 | |
930 927 | o 3: t1+1
931 928 | |
932 929 o | 2: t2+0
933 930 |/
934 931 o 1: t1+0
935 932 |
936 933 o 0: null+1
937 934
938 935
939 936 Two branch tags: more recent wins if same number of changes:
940 937
941 938 $ hg tag -r 3 -m t3 -d '8 0' t3
942 939 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
943 940 @ 8: t3+5
944 941 |
945 942 o 7: t3+4
946 943 |
947 944 o 6: t3+3
948 945 |
949 946 o 5: t3+2
950 947 |\
951 948 | o 4: t3+1
952 949 | |
953 950 | o 3: t3+0
954 951 | |
955 952 o | 2: t2+0
956 953 |/
957 954 o 1: t1+0
958 955 |
959 956 o 0: null+1
960 957
961 958
962 959 Two branch tags: fewest changes wins:
963 960
964 961 $ hg tag -r 4 -m t4 -d '4 0' t4 # older than t2, but should not matter
965 962 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
966 963 @ 9: t4+5,6
967 964 |
968 965 o 8: t4+4,5
969 966 |
970 967 o 7: t4+3,4
971 968 |
972 969 o 6: t4+2,3
973 970 |
974 971 o 5: t4+1,2
975 972 |\
976 973 | o 4: t4+0,0
977 974 | |
978 975 | o 3: t3+0,0
979 976 | |
980 977 o | 2: t2+0,0
981 978 |/
982 979 o 1: t1+0,0
983 980 |
984 981 o 0: null+1,1
985 982
986 983
987 984 Merged tag overrides:
988 985
989 986 $ hg tag -r 5 -m t5 -d '9 0' t5
990 987 $ hg tag -r 3 -m at3 -d '10 0' at3
991 988 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
992 989 @ 11: t5+6
993 990 |
994 991 o 10: t5+5
995 992 |
996 993 o 9: t5+4
997 994 |
998 995 o 8: t5+3
999 996 |
1000 997 o 7: t5+2
1001 998 |
1002 999 o 6: t5+1
1003 1000 |
1004 1001 o 5: t5+0
1005 1002 |\
1006 1003 | o 4: t4+0
1007 1004 | |
1008 1005 | o 3: at3:t3+0
1009 1006 | |
1010 1007 o | 2: t2+0
1011 1008 |/
1012 1009 o 1: t1+0
1013 1010 |
1014 1011 o 0: null+1
1015 1012
1016 1013
1017 1014 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
1018 1015 @ 11: t5+6,6
1019 1016 |
1020 1017 o 10: t5+5,5
1021 1018 |
1022 1019 o 9: t5+4,4
1023 1020 |
1024 1021 o 8: t5+3,3
1025 1022 |
1026 1023 o 7: t5+2,2
1027 1024 |
1028 1025 o 6: t5+1,1
1029 1026 |
1030 1027 o 5: t5+0,0
1031 1028 |\
1032 1029 | o 4: t4+0,0
1033 1030 | |
1034 1031 | o 3: at3+0,0 t3+0,0
1035 1032 | |
1036 1033 o | 2: t2+0,0
1037 1034 |/
1038 1035 o 1: t1+0,0
1039 1036 |
1040 1037 o 0: null+1,1
1041 1038
1042 1039
1043 1040 $ cd ..
1044 1041
1045 1042 Set up repository containing template fragments in commit metadata:
1046 1043
1047 1044 $ hg init r
1048 1045 $ cd r
1049 1046 $ echo a > a
1050 1047 $ hg ci -Am '{rev}'
1051 1048 adding a
1052 1049
1053 1050 $ hg branch -q 'text.{rev}'
1054 1051 $ echo aa >> aa
1055 1052 $ hg ci -u '{node|short}' -m 'desc to be wrapped desc to be wrapped'
1056 1053
1057 1054 Test termwidth:
1058 1055
1059 1056 $ COLUMNS=25 hg log -l1 --template '{fill(desc, termwidth, "{node|short}:", "termwidth.{rev}:")}'
1060 1057 bcc7ff960b8e:desc to be
1061 1058 termwidth.1:wrapped desc
1062 1059 termwidth.1:to be wrapped (no-eol)
1063 1060
1064 1061 Just one more commit:
1065 1062
1066 1063 $ echo b > b
1067 1064 $ hg ci -qAm b
1068 1065
1069 1066 Test 'originalnode'
1070 1067
1071 1068 $ hg log -r 1 -T '{revset("null") % "{node|short} {originalnode|short}"}\n'
1072 1069 000000000000 bcc7ff960b8e
1073 1070 $ hg log -r 0 -T '{manifest % "{node} {originalnode}"}\n'
1074 1071 a0c8bcbbb45c63b90b70ad007bf38961f64f2af0 f7769ec2ab975ad19684098ad1ffd9b81ecc71a1
1075 1072
1076 1073 Test active bookmark templating
1077 1074
1078 1075 $ hg book foo
1079 1076 $ hg book bar
1080 1077 $ hg log --template "{rev} {bookmarks % '{bookmark}{ifeq(bookmark, active, \"*\")} '}\n"
1081 1078 2 bar* foo
1082 1079 1
1083 1080 0
1084 1081 $ hg log --template "{rev} {activebookmark}\n"
1085 1082 2 bar
1086 1083 1
1087 1084 0
1088 1085 $ hg bookmarks --inactive bar
1089 1086 $ hg log --template "{rev} {activebookmark}\n"
1090 1087 2
1091 1088 1
1092 1089 0
1093 1090 $ hg book -r1 baz
1094 1091 $ hg log --template "{rev} {join(bookmarks, ' ')}\n"
1095 1092 2 bar foo
1096 1093 1 baz
1097 1094 0
1098 1095 $ hg log --template "{rev} {ifcontains('foo', bookmarks, 't', 'f')}\n"
1099 1096 2 t
1100 1097 1 f
1101 1098 0 f
1102 1099
1103 1100 Test namespaces dict
1104 1101
1105 1102 $ hg --config extensions.revnamesext=$TESTDIR/revnamesext.py log -T '{rev}\n{namespaces % " {namespace} color={colorname} builtin={builtin}\n {join(names, ",")}\n"}\n'
1106 1103 2
1107 1104 bookmarks color=bookmark builtin=True
1108 1105 bar,foo
1109 1106 tags color=tag builtin=True
1110 1107 tip
1111 1108 branches color=branch builtin=True
1112 1109 text.{rev}
1113 1110 revnames color=revname builtin=False
1114 1111 r2
1115 1112
1116 1113 1
1117 1114 bookmarks color=bookmark builtin=True
1118 1115 baz
1119 1116 tags color=tag builtin=True
1120 1117
1121 1118 branches color=branch builtin=True
1122 1119 text.{rev}
1123 1120 revnames color=revname builtin=False
1124 1121 r1
1125 1122
1126 1123 0
1127 1124 bookmarks color=bookmark builtin=True
1128 1125
1129 1126 tags color=tag builtin=True
1130 1127
1131 1128 branches color=branch builtin=True
1132 1129 default
1133 1130 revnames color=revname builtin=False
1134 1131 r0
1135 1132
1136 1133 $ hg log -r2 -T '{namespaces % "{namespace}: {names}\n"}'
1137 1134 bookmarks: bar foo
1138 1135 tags: tip
1139 1136 branches: text.{rev}
1140 1137 $ hg log -r2 -T '{namespaces % "{namespace}:\n{names % " {name}\n"}"}'
1141 1138 bookmarks:
1142 1139 bar
1143 1140 foo
1144 1141 tags:
1145 1142 tip
1146 1143 branches:
1147 1144 text.{rev}
1148 1145 $ hg log -r2 -T '{get(namespaces, "bookmarks") % "{name}\n"}'
1149 1146 bar
1150 1147 foo
1151 1148 $ hg log -r2 -T '{namespaces.bookmarks % "{bookmark}\n"}'
1152 1149 bar
1153 1150 foo
1154 1151
1155 1152 $ cd ..
1156 1153
1157 1154 Test 'graphwidth' in 'hg log' on various topologies. The key here is that the
1158 1155 printed graphwidths 3, 5, 7, etc. should all line up in their respective
1159 1156 columns. We don't care about other aspects of the graph rendering here.
1160 1157
1161 1158 $ hg init graphwidth
1162 1159 $ cd graphwidth
1163 1160
1164 1161 $ wrappabletext="a a a a a a a a a a a a"
1165 1162
1166 1163 $ printf "first\n" > file
1167 1164 $ hg add file
1168 1165 $ hg commit -m "$wrappabletext"
1169 1166
1170 1167 $ printf "first\nsecond\n" > file
1171 1168 $ hg commit -m "$wrappabletext"
1172 1169
1173 1170 $ hg checkout 0
1174 1171 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1175 1172 $ printf "third\nfirst\n" > file
1176 1173 $ hg commit -m "$wrappabletext"
1177 1174 created new head
1178 1175
1179 1176 $ hg merge
1180 1177 merging file
1181 1178 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
1182 1179 (branch merge, don't forget to commit)
1183 1180
1184 1181 $ hg log --graph -T "{graphwidth}"
1185 1182 @ 3
1186 1183 |
1187 1184 | @ 5
1188 1185 |/
1189 1186 o 3
1190 1187
1191 1188 $ hg commit -m "$wrappabletext"
1192 1189
1193 1190 $ hg log --graph -T "{graphwidth}"
1194 1191 @ 5
1195 1192 |\
1196 1193 | o 5
1197 1194 | |
1198 1195 o | 5
1199 1196 |/
1200 1197 o 3
1201 1198
1202 1199
1203 1200 $ hg checkout 0
1204 1201 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1205 1202 $ printf "third\nfirst\nsecond\n" > file
1206 1203 $ hg commit -m "$wrappabletext"
1207 1204 created new head
1208 1205
1209 1206 $ hg log --graph -T "{graphwidth}"
1210 1207 @ 3
1211 1208 |
1212 1209 | o 7
1213 1210 | |\
1214 1211 +---o 7
1215 1212 | |
1216 1213 | o 5
1217 1214 |/
1218 1215 o 3
1219 1216
1220 1217
1221 1218 $ hg log --graph -T "{graphwidth}" -r 3
1222 1219 o 5
1223 1220 |\
1224 1221 ~ ~
1225 1222
1226 1223 $ hg log --graph -T "{graphwidth}" -r 1
1227 1224 o 3
1228 1225 |
1229 1226 ~
1230 1227
1231 1228 $ hg merge
1232 1229 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1233 1230 (branch merge, don't forget to commit)
1234 1231 $ hg commit -m "$wrappabletext"
1235 1232
1236 1233 $ printf "seventh\n" >> file
1237 1234 $ hg commit -m "$wrappabletext"
1238 1235
1239 1236 $ hg log --graph -T "{graphwidth}"
1240 1237 @ 3
1241 1238 |
1242 1239 o 5
1243 1240 |\
1244 1241 | o 5
1245 1242 | |
1246 1243 o | 7
1247 1244 |\ \
1248 1245 | o | 7
1249 1246 | |/
1250 1247 o / 5
1251 1248 |/
1252 1249 o 3
1253 1250
1254 1251
1255 1252 The point of graphwidth is to allow wrapping that accounts for the space taken
1256 1253 by the graph.
1257 1254
1258 1255 $ COLUMNS=10 hg log --graph -T "{fill(desc, termwidth - graphwidth)}"
1259 1256 @ a a a a
1260 1257 | a a a a
1261 1258 | a a a a
1262 1259 o a a a
1263 1260 |\ a a a
1264 1261 | | a a a
1265 1262 | | a a a
1266 1263 | o a a a
1267 1264 | | a a a
1268 1265 | | a a a
1269 1266 | | a a a
1270 1267 o | a a
1271 1268 |\ \ a a
1272 1269 | | | a a
1273 1270 | | | a a
1274 1271 | | | a a
1275 1272 | | | a a
1276 1273 | o | a a
1277 1274 | |/ a a
1278 1275 | | a a
1279 1276 | | a a
1280 1277 | | a a
1281 1278 | | a a
1282 1279 o | a a a
1283 1280 |/ a a a
1284 1281 | a a a
1285 1282 | a a a
1286 1283 o a a a a
1287 1284 a a a a
1288 1285 a a a a
1289 1286
1290 1287 Something tricky happens when there are elided nodes; the next drawn row of
1291 1288 edges can be more than one column wider, but the graph width only increases by
1292 1289 one column. The remaining columns are added in between the nodes.
1293 1290
1294 1291 $ hg log --graph -T "{graphwidth}" -r "0|2|4|5"
1295 1292 o 5
1296 1293 |\
1297 1294 | \
1298 1295 | :\
1299 1296 o : : 7
1300 1297 :/ /
1301 1298 : o 5
1302 1299 :/
1303 1300 o 3
1304 1301
1305 1302
1306 1303 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now