##// END OF EJS Templates
log: respect diff.merge in -p output...
Martin von Zweigbergk -
r47226:a788e4bb default draft
parent child Browse files
Show More
@@ -1,1250 +1,1250 b''
1 1 # logcmdutil.py - utility for log-like commands
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import itertools
11 11 import os
12 12 import posixpath
13 13
14 14 from .i18n import _
15 15 from .node import (
16 16 nullid,
17 17 wdirid,
18 18 wdirrev,
19 19 )
20 20
21 21 from .thirdparty import attr
22 22
23 23 from . import (
24 24 dagop,
25 25 error,
26 26 formatter,
27 27 graphmod,
28 28 match as matchmod,
29 29 mdiff,
30 30 merge,
31 31 patch,
32 32 pathutil,
33 33 pycompat,
34 34 revset,
35 35 revsetlang,
36 36 scmutil,
37 37 smartset,
38 38 templatekw,
39 39 templater,
40 40 util,
41 41 )
42 42 from .utils import (
43 43 dateutil,
44 44 stringutil,
45 45 )
46 46
47 47
48 48 if pycompat.TYPE_CHECKING:
49 49 from typing import (
50 50 Any,
51 51 Callable,
52 52 Dict,
53 53 List,
54 54 Optional,
55 55 Tuple,
56 56 )
57 57
58 58 for t in (Any, Callable, Dict, List, Optional, Tuple):
59 59 assert t
60 60
61 61
62 62 def getlimit(opts):
63 63 """get the log limit according to option -l/--limit"""
64 64 limit = opts.get(b'limit')
65 65 if limit:
66 66 try:
67 67 limit = int(limit)
68 68 except ValueError:
69 69 raise error.Abort(_(b'limit must be a positive integer'))
70 70 if limit <= 0:
71 71 raise error.Abort(_(b'limit must be positive'))
72 72 else:
73 73 limit = None
74 74 return limit
75 75
76 76
77 77 def diff_parent(ctx):
78 78 """get the context object to use as parent when diffing
79 79
80 80
81 81 If diff.merge is enabled, an overlayworkingctx of the auto-merged parents will be returned.
82 82 """
83 83 repo = ctx.repo()
84 84 if repo.ui.configbool(b"diff", b"merge") and ctx.p2().node() != nullid:
85 85 # avoid cycle context -> subrepo -> cmdutil -> logcmdutil
86 86 from . import context
87 87
88 88 wctx = context.overlayworkingctx(repo)
89 89 wctx.setbase(ctx.p1())
90 90 with repo.ui.configoverride(
91 91 {
92 92 (
93 93 b"ui",
94 94 b"forcemerge",
95 95 ): b"internal:merge3-lie-about-conflicts",
96 96 },
97 97 b"merge-diff",
98 98 ):
99 99 repo.ui.pushbuffer()
100 100 merge.merge(ctx.p2(), wc=wctx)
101 101 repo.ui.popbuffer()
102 102 return wctx
103 103 else:
104 104 return ctx.p1()
105 105
106 106
107 107 def diffordiffstat(
108 108 ui,
109 109 repo,
110 110 diffopts,
111 111 ctx1,
112 112 ctx2,
113 113 match,
114 114 changes=None,
115 115 stat=False,
116 116 fp=None,
117 117 graphwidth=0,
118 118 prefix=b'',
119 119 root=b'',
120 120 listsubrepos=False,
121 121 hunksfilterfn=None,
122 122 ):
123 123 '''show diff or diffstat.'''
124 124 if root:
125 125 relroot = pathutil.canonpath(repo.root, repo.getcwd(), root)
126 126 else:
127 127 relroot = b''
128 128 copysourcematch = None
129 129
130 130 def compose(f, g):
131 131 return lambda x: f(g(x))
132 132
133 133 def pathfn(f):
134 134 return posixpath.join(prefix, f)
135 135
136 136 if relroot != b'':
137 137 # XXX relative roots currently don't work if the root is within a
138 138 # subrepo
139 139 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
140 140 uirelroot = uipathfn(pathfn(relroot))
141 141 relroot += b'/'
142 142 for matchroot in match.files():
143 143 if not matchroot.startswith(relroot):
144 144 ui.warn(
145 145 _(b'warning: %s not inside relative root %s\n')
146 146 % (uipathfn(pathfn(matchroot)), uirelroot)
147 147 )
148 148
149 149 relrootmatch = scmutil.match(ctx2, pats=[relroot], default=b'path')
150 150 match = matchmod.intersectmatchers(match, relrootmatch)
151 151 copysourcematch = relrootmatch
152 152
153 153 checkroot = repo.ui.configbool(
154 154 b'devel', b'all-warnings'
155 155 ) or repo.ui.configbool(b'devel', b'check-relroot')
156 156
157 157 def relrootpathfn(f):
158 158 if checkroot and not f.startswith(relroot):
159 159 raise AssertionError(
160 160 b"file %s doesn't start with relroot %s" % (f, relroot)
161 161 )
162 162 return f[len(relroot) :]
163 163
164 164 pathfn = compose(relrootpathfn, pathfn)
165 165
166 166 if stat:
167 167 diffopts = diffopts.copy(context=0, noprefix=False)
168 168 width = 80
169 169 if not ui.plain():
170 170 width = ui.termwidth() - graphwidth
171 171 # If an explicit --root was given, don't respect ui.relative-paths
172 172 if not relroot:
173 173 pathfn = compose(scmutil.getuipathfn(repo), pathfn)
174 174
175 175 chunks = ctx2.diff(
176 176 ctx1,
177 177 match,
178 178 changes,
179 179 opts=diffopts,
180 180 pathfn=pathfn,
181 181 copysourcematch=copysourcematch,
182 182 hunksfilterfn=hunksfilterfn,
183 183 )
184 184
185 185 if fp is not None or ui.canwritewithoutlabels():
186 186 out = fp or ui
187 187 if stat:
188 188 chunks = [patch.diffstat(util.iterlines(chunks), width=width)]
189 189 for chunk in util.filechunkiter(util.chunkbuffer(chunks)):
190 190 out.write(chunk)
191 191 else:
192 192 if stat:
193 193 chunks = patch.diffstatui(util.iterlines(chunks), width=width)
194 194 else:
195 195 chunks = patch.difflabel(
196 196 lambda chunks, **kwargs: chunks, chunks, opts=diffopts
197 197 )
198 198 if ui.canbatchlabeledwrites():
199 199
200 200 def gen():
201 201 for chunk, label in chunks:
202 202 yield ui.label(chunk, label=label)
203 203
204 204 for chunk in util.filechunkiter(util.chunkbuffer(gen())):
205 205 ui.write(chunk)
206 206 else:
207 207 for chunk, label in chunks:
208 208 ui.write(chunk, label=label)
209 209
210 210 node2 = ctx2.node()
211 211 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
212 212 tempnode2 = node2
213 213 try:
214 214 if node2 is not None:
215 215 tempnode2 = ctx2.substate[subpath][1]
216 216 except KeyError:
217 217 # A subrepo that existed in node1 was deleted between node1 and
218 218 # node2 (inclusive). Thus, ctx2's substate won't contain that
219 219 # subpath. The best we can do is to ignore it.
220 220 tempnode2 = None
221 221 submatch = matchmod.subdirmatcher(subpath, match)
222 222 subprefix = repo.wvfs.reljoin(prefix, subpath)
223 223 if listsubrepos or match.exact(subpath) or any(submatch.files()):
224 224 sub.diff(
225 225 ui,
226 226 diffopts,
227 227 tempnode2,
228 228 submatch,
229 229 changes=changes,
230 230 stat=stat,
231 231 fp=fp,
232 232 prefix=subprefix,
233 233 )
234 234
235 235
236 236 class changesetdiffer(object):
237 237 """Generate diff of changeset with pre-configured filtering functions"""
238 238
239 239 def _makefilematcher(self, ctx):
240 240 return scmutil.matchall(ctx.repo())
241 241
242 242 def _makehunksfilter(self, ctx):
243 243 return None
244 244
245 245 def showdiff(self, ui, ctx, diffopts, graphwidth=0, stat=False):
246 246 diffordiffstat(
247 247 ui,
248 248 ctx.repo(),
249 249 diffopts,
250 ctx.p1(),
250 diff_parent(ctx),
251 251 ctx,
252 252 match=self._makefilematcher(ctx),
253 253 stat=stat,
254 254 graphwidth=graphwidth,
255 255 hunksfilterfn=self._makehunksfilter(ctx),
256 256 )
257 257
258 258
259 259 def changesetlabels(ctx):
260 260 labels = [b'log.changeset', b'changeset.%s' % ctx.phasestr()]
261 261 if ctx.obsolete():
262 262 labels.append(b'changeset.obsolete')
263 263 if ctx.isunstable():
264 264 labels.append(b'changeset.unstable')
265 265 for instability in ctx.instabilities():
266 266 labels.append(b'instability.%s' % instability)
267 267 return b' '.join(labels)
268 268
269 269
270 270 class changesetprinter(object):
271 271 '''show changeset information when templating not requested.'''
272 272
273 273 def __init__(self, ui, repo, differ=None, diffopts=None, buffered=False):
274 274 self.ui = ui
275 275 self.repo = repo
276 276 self.buffered = buffered
277 277 self._differ = differ or changesetdiffer()
278 278 self._diffopts = patch.diffallopts(ui, diffopts)
279 279 self._includestat = diffopts and diffopts.get(b'stat')
280 280 self._includediff = diffopts and diffopts.get(b'patch')
281 281 self.header = {}
282 282 self.hunk = {}
283 283 self.lastheader = None
284 284 self.footer = None
285 285 self._columns = templatekw.getlogcolumns()
286 286
287 287 def flush(self, ctx):
288 288 rev = ctx.rev()
289 289 if rev in self.header:
290 290 h = self.header[rev]
291 291 if h != self.lastheader:
292 292 self.lastheader = h
293 293 self.ui.write(h)
294 294 del self.header[rev]
295 295 if rev in self.hunk:
296 296 self.ui.write(self.hunk[rev])
297 297 del self.hunk[rev]
298 298
299 299 def close(self):
300 300 if self.footer:
301 301 self.ui.write(self.footer)
302 302
303 303 def show(self, ctx, copies=None, **props):
304 304 props = pycompat.byteskwargs(props)
305 305 if self.buffered:
306 306 self.ui.pushbuffer(labeled=True)
307 307 self._show(ctx, copies, props)
308 308 self.hunk[ctx.rev()] = self.ui.popbuffer()
309 309 else:
310 310 self._show(ctx, copies, props)
311 311
312 312 def _show(self, ctx, copies, props):
313 313 '''show a single changeset or file revision'''
314 314 changenode = ctx.node()
315 315 graphwidth = props.get(b'graphwidth', 0)
316 316
317 317 if self.ui.quiet:
318 318 self.ui.write(
319 319 b"%s\n" % scmutil.formatchangeid(ctx), label=b'log.node'
320 320 )
321 321 return
322 322
323 323 columns = self._columns
324 324 self.ui.write(
325 325 columns[b'changeset'] % scmutil.formatchangeid(ctx),
326 326 label=changesetlabels(ctx),
327 327 )
328 328
329 329 # branches are shown first before any other names due to backwards
330 330 # compatibility
331 331 branch = ctx.branch()
332 332 # don't show the default branch name
333 333 if branch != b'default':
334 334 self.ui.write(columns[b'branch'] % branch, label=b'log.branch')
335 335
336 336 for nsname, ns in pycompat.iteritems(self.repo.names):
337 337 # branches has special logic already handled above, so here we just
338 338 # skip it
339 339 if nsname == b'branches':
340 340 continue
341 341 # we will use the templatename as the color name since those two
342 342 # should be the same
343 343 for name in ns.names(self.repo, changenode):
344 344 self.ui.write(ns.logfmt % name, label=b'log.%s' % ns.colorname)
345 345 if self.ui.debugflag:
346 346 self.ui.write(
347 347 columns[b'phase'] % ctx.phasestr(), label=b'log.phase'
348 348 )
349 349 for pctx in scmutil.meaningfulparents(self.repo, ctx):
350 350 label = b'log.parent changeset.%s' % pctx.phasestr()
351 351 self.ui.write(
352 352 columns[b'parent'] % scmutil.formatchangeid(pctx), label=label
353 353 )
354 354
355 355 if self.ui.debugflag:
356 356 mnode = ctx.manifestnode()
357 357 if mnode is None:
358 358 mnode = wdirid
359 359 mrev = wdirrev
360 360 else:
361 361 mrev = self.repo.manifestlog.rev(mnode)
362 362 self.ui.write(
363 363 columns[b'manifest']
364 364 % scmutil.formatrevnode(self.ui, mrev, mnode),
365 365 label=b'ui.debug log.manifest',
366 366 )
367 367 self.ui.write(columns[b'user'] % ctx.user(), label=b'log.user')
368 368 self.ui.write(
369 369 columns[b'date'] % dateutil.datestr(ctx.date()), label=b'log.date'
370 370 )
371 371
372 372 if ctx.isunstable():
373 373 instabilities = ctx.instabilities()
374 374 self.ui.write(
375 375 columns[b'instability'] % b', '.join(instabilities),
376 376 label=b'log.instability',
377 377 )
378 378
379 379 elif ctx.obsolete():
380 380 self._showobsfate(ctx)
381 381
382 382 self._exthook(ctx)
383 383
384 384 if self.ui.debugflag:
385 385 files = ctx.p1().status(ctx)
386 386 for key, value in zip(
387 387 [b'files', b'files+', b'files-'],
388 388 [files.modified, files.added, files.removed],
389 389 ):
390 390 if value:
391 391 self.ui.write(
392 392 columns[key] % b" ".join(value),
393 393 label=b'ui.debug log.files',
394 394 )
395 395 elif ctx.files() and self.ui.verbose:
396 396 self.ui.write(
397 397 columns[b'files'] % b" ".join(ctx.files()),
398 398 label=b'ui.note log.files',
399 399 )
400 400 if copies and self.ui.verbose:
401 401 copies = [b'%s (%s)' % c for c in copies]
402 402 self.ui.write(
403 403 columns[b'copies'] % b' '.join(copies),
404 404 label=b'ui.note log.copies',
405 405 )
406 406
407 407 extra = ctx.extra()
408 408 if extra and self.ui.debugflag:
409 409 for key, value in sorted(extra.items()):
410 410 self.ui.write(
411 411 columns[b'extra'] % (key, stringutil.escapestr(value)),
412 412 label=b'ui.debug log.extra',
413 413 )
414 414
415 415 description = ctx.description().strip()
416 416 if description:
417 417 if self.ui.verbose:
418 418 self.ui.write(
419 419 _(b"description:\n"), label=b'ui.note log.description'
420 420 )
421 421 self.ui.write(description, label=b'ui.note log.description')
422 422 self.ui.write(b"\n\n")
423 423 else:
424 424 self.ui.write(
425 425 columns[b'summary'] % description.splitlines()[0],
426 426 label=b'log.summary',
427 427 )
428 428 self.ui.write(b"\n")
429 429
430 430 self._showpatch(ctx, graphwidth)
431 431
432 432 def _showobsfate(self, ctx):
433 433 # TODO: do not depend on templater
434 434 tres = formatter.templateresources(self.repo.ui, self.repo)
435 435 t = formatter.maketemplater(
436 436 self.repo.ui,
437 437 b'{join(obsfate, "\n")}',
438 438 defaults=templatekw.keywords,
439 439 resources=tres,
440 440 )
441 441 obsfate = t.renderdefault({b'ctx': ctx}).splitlines()
442 442
443 443 if obsfate:
444 444 for obsfateline in obsfate:
445 445 self.ui.write(
446 446 self._columns[b'obsolete'] % obsfateline,
447 447 label=b'log.obsfate',
448 448 )
449 449
450 450 def _exthook(self, ctx):
451 451 """empty method used by extension as a hook point"""
452 452
453 453 def _showpatch(self, ctx, graphwidth=0):
454 454 if self._includestat:
455 455 self._differ.showdiff(
456 456 self.ui, ctx, self._diffopts, graphwidth, stat=True
457 457 )
458 458 if self._includestat and self._includediff:
459 459 self.ui.write(b"\n")
460 460 if self._includediff:
461 461 self._differ.showdiff(
462 462 self.ui, ctx, self._diffopts, graphwidth, stat=False
463 463 )
464 464 if self._includestat or self._includediff:
465 465 self.ui.write(b"\n")
466 466
467 467
468 468 class changesetformatter(changesetprinter):
469 469 """Format changeset information by generic formatter"""
470 470
471 471 def __init__(
472 472 self, ui, repo, fm, differ=None, diffopts=None, buffered=False
473 473 ):
474 474 changesetprinter.__init__(self, ui, repo, differ, diffopts, buffered)
475 475 self._diffopts = patch.difffeatureopts(ui, diffopts, git=True)
476 476 self._fm = fm
477 477
478 478 def close(self):
479 479 self._fm.end()
480 480
481 481 def _show(self, ctx, copies, props):
482 482 '''show a single changeset or file revision'''
483 483 fm = self._fm
484 484 fm.startitem()
485 485 fm.context(ctx=ctx)
486 486 fm.data(rev=scmutil.intrev(ctx), node=fm.hexfunc(scmutil.binnode(ctx)))
487 487
488 488 datahint = fm.datahint()
489 489 if self.ui.quiet and not datahint:
490 490 return
491 491
492 492 fm.data(
493 493 branch=ctx.branch(),
494 494 phase=ctx.phasestr(),
495 495 user=ctx.user(),
496 496 date=fm.formatdate(ctx.date()),
497 497 desc=ctx.description(),
498 498 bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'),
499 499 tags=fm.formatlist(ctx.tags(), name=b'tag'),
500 500 parents=fm.formatlist(
501 501 [fm.hexfunc(c.node()) for c in ctx.parents()], name=b'node'
502 502 ),
503 503 )
504 504
505 505 if self.ui.debugflag or b'manifest' in datahint:
506 506 fm.data(manifest=fm.hexfunc(ctx.manifestnode() or wdirid))
507 507 if self.ui.debugflag or b'extra' in datahint:
508 508 fm.data(extra=fm.formatdict(ctx.extra()))
509 509
510 510 if (
511 511 self.ui.debugflag
512 512 or b'modified' in datahint
513 513 or b'added' in datahint
514 514 or b'removed' in datahint
515 515 ):
516 516 files = ctx.p1().status(ctx)
517 517 fm.data(
518 518 modified=fm.formatlist(files.modified, name=b'file'),
519 519 added=fm.formatlist(files.added, name=b'file'),
520 520 removed=fm.formatlist(files.removed, name=b'file'),
521 521 )
522 522
523 523 verbose = not self.ui.debugflag and self.ui.verbose
524 524 if verbose or b'files' in datahint:
525 525 fm.data(files=fm.formatlist(ctx.files(), name=b'file'))
526 526 if verbose and copies or b'copies' in datahint:
527 527 fm.data(
528 528 copies=fm.formatdict(copies or {}, key=b'name', value=b'source')
529 529 )
530 530
531 531 if self._includestat or b'diffstat' in datahint:
532 532 self.ui.pushbuffer()
533 533 self._differ.showdiff(self.ui, ctx, self._diffopts, stat=True)
534 534 fm.data(diffstat=self.ui.popbuffer())
535 535 if self._includediff or b'diff' in datahint:
536 536 self.ui.pushbuffer()
537 537 self._differ.showdiff(self.ui, ctx, self._diffopts, stat=False)
538 538 fm.data(diff=self.ui.popbuffer())
539 539
540 540
541 541 class changesettemplater(changesetprinter):
542 542 """format changeset information.
543 543
544 544 Note: there are a variety of convenience functions to build a
545 545 changesettemplater for common cases. See functions such as:
546 546 maketemplater, changesetdisplayer, buildcommittemplate, or other
547 547 functions that use changesest_templater.
548 548 """
549 549
550 550 # Arguments before "buffered" used to be positional. Consider not
551 551 # adding/removing arguments before "buffered" to not break callers.
552 552 def __init__(
553 553 self, ui, repo, tmplspec, differ=None, diffopts=None, buffered=False
554 554 ):
555 555 changesetprinter.__init__(self, ui, repo, differ, diffopts, buffered)
556 556 # tres is shared with _graphnodeformatter()
557 557 self._tresources = tres = formatter.templateresources(ui, repo)
558 558 self.t = formatter.loadtemplater(
559 559 ui,
560 560 tmplspec,
561 561 defaults=templatekw.keywords,
562 562 resources=tres,
563 563 cache=templatekw.defaulttempl,
564 564 )
565 565 self._counter = itertools.count()
566 566
567 567 self._tref = tmplspec.ref
568 568 self._parts = {
569 569 b'header': b'',
570 570 b'footer': b'',
571 571 tmplspec.ref: tmplspec.ref,
572 572 b'docheader': b'',
573 573 b'docfooter': b'',
574 574 b'separator': b'',
575 575 }
576 576 if tmplspec.mapfile:
577 577 # find correct templates for current mode, for backward
578 578 # compatibility with 'log -v/-q/--debug' using a mapfile
579 579 tmplmodes = [
580 580 (True, b''),
581 581 (self.ui.verbose, b'_verbose'),
582 582 (self.ui.quiet, b'_quiet'),
583 583 (self.ui.debugflag, b'_debug'),
584 584 ]
585 585 for mode, postfix in tmplmodes:
586 586 for t in self._parts:
587 587 cur = t + postfix
588 588 if mode and cur in self.t:
589 589 self._parts[t] = cur
590 590 else:
591 591 partnames = [p for p in self._parts.keys() if p != tmplspec.ref]
592 592 m = formatter.templatepartsmap(tmplspec, self.t, partnames)
593 593 self._parts.update(m)
594 594
595 595 if self._parts[b'docheader']:
596 596 self.ui.write(self.t.render(self._parts[b'docheader'], {}))
597 597
598 598 def close(self):
599 599 if self._parts[b'docfooter']:
600 600 if not self.footer:
601 601 self.footer = b""
602 602 self.footer += self.t.render(self._parts[b'docfooter'], {})
603 603 return super(changesettemplater, self).close()
604 604
605 605 def _show(self, ctx, copies, props):
606 606 '''show a single changeset or file revision'''
607 607 props = props.copy()
608 608 props[b'ctx'] = ctx
609 609 props[b'index'] = index = next(self._counter)
610 610 props[b'revcache'] = {b'copies': copies}
611 611 graphwidth = props.get(b'graphwidth', 0)
612 612
613 613 # write separator, which wouldn't work well with the header part below
614 614 # since there's inherently a conflict between header (across items) and
615 615 # separator (per item)
616 616 if self._parts[b'separator'] and index > 0:
617 617 self.ui.write(self.t.render(self._parts[b'separator'], {}))
618 618
619 619 # write header
620 620 if self._parts[b'header']:
621 621 h = self.t.render(self._parts[b'header'], props)
622 622 if self.buffered:
623 623 self.header[ctx.rev()] = h
624 624 else:
625 625 if self.lastheader != h:
626 626 self.lastheader = h
627 627 self.ui.write(h)
628 628
629 629 # write changeset metadata, then patch if requested
630 630 key = self._parts[self._tref]
631 631 self.ui.write(self.t.render(key, props))
632 632 self._exthook(ctx)
633 633 self._showpatch(ctx, graphwidth)
634 634
635 635 if self._parts[b'footer']:
636 636 if not self.footer:
637 637 self.footer = self.t.render(self._parts[b'footer'], props)
638 638
639 639
640 640 def templatespec(tmpl, mapfile):
641 641 assert not (tmpl and mapfile)
642 642 if mapfile:
643 643 return formatter.mapfile_templatespec(b'changeset', mapfile)
644 644 else:
645 645 return formatter.literal_templatespec(tmpl)
646 646
647 647
648 648 def _lookuptemplate(ui, tmpl, style):
649 649 """Find the template matching the given template spec or style
650 650
651 651 See formatter.lookuptemplate() for details.
652 652 """
653 653
654 654 # ui settings
655 655 if not tmpl and not style: # template are stronger than style
656 656 tmpl = ui.config(b'command-templates', b'log')
657 657 if tmpl:
658 658 return formatter.literal_templatespec(templater.unquotestring(tmpl))
659 659 else:
660 660 style = util.expandpath(ui.config(b'ui', b'style'))
661 661
662 662 if not tmpl and style:
663 663 mapfile = style
664 664 fp = None
665 665 if not os.path.split(mapfile)[0]:
666 666 (mapname, fp) = templater.try_open_template(
667 667 b'map-cmdline.' + mapfile
668 668 ) or templater.try_open_template(mapfile)
669 669 if mapname:
670 670 mapfile = mapname
671 671 return formatter.mapfile_templatespec(b'changeset', mapfile, fp)
672 672
673 673 return formatter.lookuptemplate(ui, b'changeset', tmpl)
674 674
675 675
676 676 def maketemplater(ui, repo, tmpl, buffered=False):
677 677 """Create a changesettemplater from a literal template 'tmpl'
678 678 byte-string."""
679 679 spec = formatter.literal_templatespec(tmpl)
680 680 return changesettemplater(ui, repo, spec, buffered=buffered)
681 681
682 682
683 683 def changesetdisplayer(ui, repo, opts, differ=None, buffered=False):
684 684 """show one changeset using template or regular display.
685 685
686 686 Display format will be the first non-empty hit of:
687 687 1. option 'template'
688 688 2. option 'style'
689 689 3. [command-templates] setting 'log'
690 690 4. [ui] setting 'style'
691 691 If all of these values are either the unset or the empty string,
692 692 regular display via changesetprinter() is done.
693 693 """
694 694 postargs = (differ, opts, buffered)
695 695 spec = _lookuptemplate(ui, opts.get(b'template'), opts.get(b'style'))
696 696
697 697 # machine-readable formats have slightly different keyword set than
698 698 # plain templates, which are handled by changesetformatter.
699 699 # note that {b'pickle', b'debug'} can also be added to the list if needed.
700 700 if spec.ref in {b'cbor', b'json'}:
701 701 fm = ui.formatter(b'log', opts)
702 702 return changesetformatter(ui, repo, fm, *postargs)
703 703
704 704 if not spec.ref and not spec.tmpl and not spec.mapfile:
705 705 return changesetprinter(ui, repo, *postargs)
706 706
707 707 return changesettemplater(ui, repo, spec, *postargs)
708 708
709 709
710 710 @attr.s
711 711 class walkopts(object):
712 712 """Options to configure a set of revisions and file matcher factory
713 713 to scan revision/file history
714 714 """
715 715
716 716 # raw command-line parameters, which a matcher will be built from
717 717 pats = attr.ib() # type: List[bytes]
718 718 opts = attr.ib() # type: Dict[bytes, Any]
719 719
720 720 # a list of revset expressions to be traversed; if follow, it specifies
721 721 # the start revisions
722 722 revspec = attr.ib() # type: List[bytes]
723 723
724 724 # miscellaneous queries to filter revisions (see "hg help log" for details)
725 725 bookmarks = attr.ib(default=attr.Factory(list)) # type: List[bytes]
726 726 branches = attr.ib(default=attr.Factory(list)) # type: List[bytes]
727 727 date = attr.ib(default=None) # type: Optional[bytes]
728 728 keywords = attr.ib(default=attr.Factory(list)) # type: List[bytes]
729 729 no_merges = attr.ib(default=False) # type: bool
730 730 only_merges = attr.ib(default=False) # type: bool
731 731 prune_ancestors = attr.ib(default=attr.Factory(list)) # type: List[bytes]
732 732 users = attr.ib(default=attr.Factory(list)) # type: List[bytes]
733 733
734 734 # miscellaneous matcher arguments
735 735 include_pats = attr.ib(default=attr.Factory(list)) # type: List[bytes]
736 736 exclude_pats = attr.ib(default=attr.Factory(list)) # type: List[bytes]
737 737
738 738 # 0: no follow, 1: follow first, 2: follow both parents
739 739 follow = attr.ib(default=0) # type: int
740 740
741 741 # do not attempt filelog-based traversal, which may be fast but cannot
742 742 # include revisions where files were removed
743 743 force_changelog_traversal = attr.ib(default=False) # type: bool
744 744
745 745 # filter revisions by file patterns, which should be disabled only if
746 746 # you want to include revisions where files were unmodified
747 747 filter_revisions_by_pats = attr.ib(default=True) # type: bool
748 748
749 749 # sort revisions prior to traversal: 'desc', 'topo', or None
750 750 sort_revisions = attr.ib(default=None) # type: Optional[bytes]
751 751
752 752 # limit number of changes displayed; None means unlimited
753 753 limit = attr.ib(default=None) # type: Optional[int]
754 754
755 755
756 756 def parseopts(ui, pats, opts):
757 757 # type: (Any, List[bytes], Dict[bytes, Any]) -> walkopts
758 758 """Parse log command options into walkopts
759 759
760 760 The returned walkopts will be passed in to getrevs() or makewalker().
761 761 """
762 762 if opts.get(b'follow_first'):
763 763 follow = 1
764 764 elif opts.get(b'follow'):
765 765 follow = 2
766 766 else:
767 767 follow = 0
768 768
769 769 if opts.get(b'graph'):
770 770 if ui.configbool(b'experimental', b'log.topo'):
771 771 sort_revisions = b'topo'
772 772 else:
773 773 sort_revisions = b'desc'
774 774 else:
775 775 sort_revisions = None
776 776
777 777 return walkopts(
778 778 pats=pats,
779 779 opts=opts,
780 780 revspec=opts.get(b'rev', []),
781 781 bookmarks=opts.get(b'bookmark', []),
782 782 # branch and only_branch are really aliases and must be handled at
783 783 # the same time
784 784 branches=opts.get(b'branch', []) + opts.get(b'only_branch', []),
785 785 date=opts.get(b'date'),
786 786 keywords=opts.get(b'keyword', []),
787 787 no_merges=bool(opts.get(b'no_merges')),
788 788 only_merges=bool(opts.get(b'only_merges')),
789 789 prune_ancestors=opts.get(b'prune', []),
790 790 users=opts.get(b'user', []),
791 791 include_pats=opts.get(b'include', []),
792 792 exclude_pats=opts.get(b'exclude', []),
793 793 follow=follow,
794 794 force_changelog_traversal=bool(opts.get(b'removed')),
795 795 sort_revisions=sort_revisions,
796 796 limit=getlimit(opts),
797 797 )
798 798
799 799
800 800 def _makematcher(repo, revs, wopts):
801 801 """Build matcher and expanded patterns from log options
802 802
803 803 If --follow, revs are the revisions to follow from.
804 804
805 805 Returns (match, pats, slowpath) where
806 806 - match: a matcher built from the given pats and -I/-X opts
807 807 - pats: patterns used (globs are expanded on Windows)
808 808 - slowpath: True if patterns aren't as simple as scanning filelogs
809 809 """
810 810 # pats/include/exclude are passed to match.match() directly in
811 811 # _matchfiles() revset, but a log-like command should build its matcher
812 812 # with scmutil.match(). The difference is input pats are globbed on
813 813 # platforms without shell expansion (windows).
814 814 wctx = repo[None]
815 815 match, pats = scmutil.matchandpats(wctx, wopts.pats, wopts.opts)
816 816 slowpath = match.anypats() or (
817 817 not match.always() and wopts.force_changelog_traversal
818 818 )
819 819 if not slowpath:
820 820 if wopts.follow and wopts.revspec:
821 821 # There may be the case that a path doesn't exist in some (but
822 822 # not all) of the specified start revisions, but let's consider
823 823 # the path is valid. Missing files will be warned by the matcher.
824 824 startctxs = [repo[r] for r in revs]
825 825 for f in match.files():
826 826 found = False
827 827 for c in startctxs:
828 828 if f in c:
829 829 found = True
830 830 elif c.hasdir(f):
831 831 # If a directory exists in any of the start revisions,
832 832 # take the slow path.
833 833 found = slowpath = True
834 834 if not found:
835 835 raise error.Abort(
836 836 _(
837 837 b'cannot follow file not in any of the specified '
838 838 b'revisions: "%s"'
839 839 )
840 840 % f
841 841 )
842 842 elif wopts.follow:
843 843 for f in match.files():
844 844 if f not in wctx:
845 845 # If the file exists, it may be a directory, so let it
846 846 # take the slow path.
847 847 if os.path.exists(repo.wjoin(f)):
848 848 slowpath = True
849 849 continue
850 850 else:
851 851 raise error.Abort(
852 852 _(
853 853 b'cannot follow file not in parent '
854 854 b'revision: "%s"'
855 855 )
856 856 % f
857 857 )
858 858 filelog = repo.file(f)
859 859 if not filelog:
860 860 # A file exists in wdir but not in history, which means
861 861 # the file isn't committed yet.
862 862 raise error.Abort(
863 863 _(b'cannot follow nonexistent file: "%s"') % f
864 864 )
865 865 else:
866 866 for f in match.files():
867 867 filelog = repo.file(f)
868 868 if not filelog:
869 869 # A zero count may be a directory or deleted file, so
870 870 # try to find matching entries on the slow path.
871 871 slowpath = True
872 872
873 873 # We decided to fall back to the slowpath because at least one
874 874 # of the paths was not a file. Check to see if at least one of them
875 875 # existed in history - in that case, we'll continue down the
876 876 # slowpath; otherwise, we can turn off the slowpath
877 877 if slowpath:
878 878 for path in match.files():
879 879 if path == b'.' or path in repo.store:
880 880 break
881 881 else:
882 882 slowpath = False
883 883
884 884 return match, pats, slowpath
885 885
886 886
887 887 def _fileancestors(repo, revs, match, followfirst):
888 888 fctxs = []
889 889 for r in revs:
890 890 ctx = repo[r]
891 891 fctxs.extend(ctx[f].introfilectx() for f in ctx.walk(match))
892 892
893 893 # When displaying a revision with --patch --follow FILE, we have
894 894 # to know which file of the revision must be diffed. With
895 895 # --follow, we want the names of the ancestors of FILE in the
896 896 # revision, stored in "fcache". "fcache" is populated as a side effect
897 897 # of the graph traversal.
898 898 fcache = {}
899 899
900 900 def filematcher(ctx):
901 901 return scmutil.matchfiles(repo, fcache.get(scmutil.intrev(ctx), []))
902 902
903 903 def revgen():
904 904 for rev, cs in dagop.filectxancestors(fctxs, followfirst=followfirst):
905 905 fcache[rev] = [c.path() for c in cs]
906 906 yield rev
907 907
908 908 return smartset.generatorset(revgen(), iterasc=False), filematcher
909 909
910 910
911 911 def _makenofollowfilematcher(repo, pats, opts):
912 912 '''hook for extensions to override the filematcher for non-follow cases'''
913 913 return None
914 914
915 915
916 916 _opt2logrevset = {
917 917 b'no_merges': (b'not merge()', None),
918 918 b'only_merges': (b'merge()', None),
919 919 b'_matchfiles': (None, b'_matchfiles(%ps)'),
920 920 b'date': (b'date(%s)', None),
921 921 b'branch': (b'branch(%s)', b'%lr'),
922 922 b'_patslog': (b'filelog(%s)', b'%lr'),
923 923 b'keyword': (b'keyword(%s)', b'%lr'),
924 924 b'prune': (b'ancestors(%s)', b'not %lr'),
925 925 b'user': (b'user(%s)', b'%lr'),
926 926 }
927 927
928 928
929 929 def _makerevset(repo, wopts, slowpath):
930 930 """Return a revset string built from log options and file patterns"""
931 931 opts = {
932 932 b'branch': [b'literal:' + repo.lookupbranch(b) for b in wopts.branches],
933 933 b'date': wopts.date,
934 934 b'keyword': wopts.keywords,
935 935 b'no_merges': wopts.no_merges,
936 936 b'only_merges': wopts.only_merges,
937 937 b'prune': wopts.prune_ancestors,
938 938 b'user': [b'literal:' + v for v in wopts.users],
939 939 }
940 940
941 941 if wopts.filter_revisions_by_pats and slowpath:
942 942 # pats/include/exclude cannot be represented as separate
943 943 # revset expressions as their filtering logic applies at file
944 944 # level. For instance "-I a -X b" matches a revision touching
945 945 # "a" and "b" while "file(a) and not file(b)" does
946 946 # not. Besides, filesets are evaluated against the working
947 947 # directory.
948 948 matchargs = [b'r:', b'd:relpath']
949 949 for p in wopts.pats:
950 950 matchargs.append(b'p:' + p)
951 951 for p in wopts.include_pats:
952 952 matchargs.append(b'i:' + p)
953 953 for p in wopts.exclude_pats:
954 954 matchargs.append(b'x:' + p)
955 955 opts[b'_matchfiles'] = matchargs
956 956 elif wopts.filter_revisions_by_pats and not wopts.follow:
957 957 opts[b'_patslog'] = list(wopts.pats)
958 958
959 959 expr = []
960 960 for op, val in sorted(pycompat.iteritems(opts)):
961 961 if not val:
962 962 continue
963 963 revop, listop = _opt2logrevset[op]
964 964 if revop and b'%' not in revop:
965 965 expr.append(revop)
966 966 elif not listop:
967 967 expr.append(revsetlang.formatspec(revop, val))
968 968 else:
969 969 if revop:
970 970 val = [revsetlang.formatspec(revop, v) for v in val]
971 971 expr.append(revsetlang.formatspec(listop, val))
972 972
973 973 if wopts.bookmarks:
974 974 expr.append(
975 975 revsetlang.formatspec(
976 976 b'%lr',
977 977 [scmutil.format_bookmark_revspec(v) for v in wopts.bookmarks],
978 978 )
979 979 )
980 980
981 981 if expr:
982 982 expr = b'(' + b' and '.join(expr) + b')'
983 983 else:
984 984 expr = None
985 985 return expr
986 986
987 987
988 988 def _initialrevs(repo, wopts):
989 989 """Return the initial set of revisions to be filtered or followed"""
990 990 if wopts.revspec:
991 991 revs = scmutil.revrange(repo, wopts.revspec)
992 992 elif wopts.follow and repo.dirstate.p1() == nullid:
993 993 revs = smartset.baseset()
994 994 elif wopts.follow:
995 995 revs = repo.revs(b'.')
996 996 else:
997 997 revs = smartset.spanset(repo)
998 998 revs.reverse()
999 999 return revs
1000 1000
1001 1001
1002 1002 def makewalker(repo, wopts):
1003 1003 # type: (Any, walkopts) -> Tuple[smartset.abstractsmartset, Optional[Callable[[Any], matchmod.basematcher]]]
1004 1004 """Build (revs, makefilematcher) to scan revision/file history
1005 1005
1006 1006 - revs is the smartset to be traversed.
1007 1007 - makefilematcher is a function to map ctx to a matcher for that revision
1008 1008 """
1009 1009 revs = _initialrevs(repo, wopts)
1010 1010 if not revs:
1011 1011 return smartset.baseset(), None
1012 1012 # TODO: might want to merge slowpath with wopts.force_changelog_traversal
1013 1013 match, pats, slowpath = _makematcher(repo, revs, wopts)
1014 1014 wopts = attr.evolve(wopts, pats=pats)
1015 1015
1016 1016 filematcher = None
1017 1017 if wopts.follow:
1018 1018 if slowpath or match.always():
1019 1019 revs = dagop.revancestors(repo, revs, followfirst=wopts.follow == 1)
1020 1020 else:
1021 1021 assert not wopts.force_changelog_traversal
1022 1022 revs, filematcher = _fileancestors(
1023 1023 repo, revs, match, followfirst=wopts.follow == 1
1024 1024 )
1025 1025 revs.reverse()
1026 1026 if filematcher is None:
1027 1027 filematcher = _makenofollowfilematcher(repo, wopts.pats, wopts.opts)
1028 1028 if filematcher is None:
1029 1029
1030 1030 def filematcher(ctx):
1031 1031 return match
1032 1032
1033 1033 expr = _makerevset(repo, wopts, slowpath)
1034 1034 if wopts.sort_revisions:
1035 1035 assert wopts.sort_revisions in {b'topo', b'desc'}
1036 1036 if wopts.sort_revisions == b'topo':
1037 1037 if not revs.istopo():
1038 1038 revs = dagop.toposort(revs, repo.changelog.parentrevs)
1039 1039 # TODO: try to iterate the set lazily
1040 1040 revs = revset.baseset(list(revs), istopo=True)
1041 1041 elif not (revs.isdescending() or revs.istopo()):
1042 1042 # User-specified revs might be unsorted
1043 1043 revs.sort(reverse=True)
1044 1044 if expr:
1045 1045 matcher = revset.match(None, expr)
1046 1046 revs = matcher(repo, revs)
1047 1047 if wopts.limit is not None:
1048 1048 revs = revs.slice(0, wopts.limit)
1049 1049
1050 1050 return revs, filematcher
1051 1051
1052 1052
1053 1053 def getrevs(repo, wopts):
1054 1054 # type: (Any, walkopts) -> Tuple[smartset.abstractsmartset, Optional[changesetdiffer]]
1055 1055 """Return (revs, differ) where revs is a smartset
1056 1056
1057 1057 differ is a changesetdiffer with pre-configured file matcher.
1058 1058 """
1059 1059 revs, filematcher = makewalker(repo, wopts)
1060 1060 if not revs:
1061 1061 return revs, None
1062 1062 differ = changesetdiffer()
1063 1063 differ._makefilematcher = filematcher
1064 1064 return revs, differ
1065 1065
1066 1066
1067 1067 def _parselinerangeopt(repo, opts):
1068 1068 """Parse --line-range log option and return a list of tuples (filename,
1069 1069 (fromline, toline)).
1070 1070 """
1071 1071 linerangebyfname = []
1072 1072 for pat in opts.get(b'line_range', []):
1073 1073 try:
1074 1074 pat, linerange = pat.rsplit(b',', 1)
1075 1075 except ValueError:
1076 1076 raise error.Abort(_(b'malformatted line-range pattern %s') % pat)
1077 1077 try:
1078 1078 fromline, toline = map(int, linerange.split(b':'))
1079 1079 except ValueError:
1080 1080 raise error.Abort(_(b"invalid line range for %s") % pat)
1081 1081 msg = _(b"line range pattern '%s' must match exactly one file") % pat
1082 1082 fname = scmutil.parsefollowlinespattern(repo, None, pat, msg)
1083 1083 linerangebyfname.append(
1084 1084 (fname, util.processlinerange(fromline, toline))
1085 1085 )
1086 1086 return linerangebyfname
1087 1087
1088 1088
1089 1089 def getlinerangerevs(repo, userrevs, opts):
1090 1090 """Return (revs, differ).
1091 1091
1092 1092 "revs" are revisions obtained by processing "line-range" log options and
1093 1093 walking block ancestors of each specified file/line-range.
1094 1094
1095 1095 "differ" is a changesetdiffer with pre-configured file matcher and hunks
1096 1096 filter.
1097 1097 """
1098 1098 wctx = repo[None]
1099 1099
1100 1100 # Two-levels map of "rev -> file ctx -> [line range]".
1101 1101 linerangesbyrev = {}
1102 1102 for fname, (fromline, toline) in _parselinerangeopt(repo, opts):
1103 1103 if fname not in wctx:
1104 1104 raise error.Abort(
1105 1105 _(b'cannot follow file not in parent revision: "%s"') % fname
1106 1106 )
1107 1107 fctx = wctx.filectx(fname)
1108 1108 for fctx, linerange in dagop.blockancestors(fctx, fromline, toline):
1109 1109 rev = fctx.introrev()
1110 1110 if rev is None:
1111 1111 rev = wdirrev
1112 1112 if rev not in userrevs:
1113 1113 continue
1114 1114 linerangesbyrev.setdefault(rev, {}).setdefault(
1115 1115 fctx.path(), []
1116 1116 ).append(linerange)
1117 1117
1118 1118 def nofilterhunksfn(fctx, hunks):
1119 1119 return hunks
1120 1120
1121 1121 def hunksfilter(ctx):
1122 1122 fctxlineranges = linerangesbyrev.get(scmutil.intrev(ctx))
1123 1123 if fctxlineranges is None:
1124 1124 return nofilterhunksfn
1125 1125
1126 1126 def filterfn(fctx, hunks):
1127 1127 lineranges = fctxlineranges.get(fctx.path())
1128 1128 if lineranges is not None:
1129 1129 for hr, lines in hunks:
1130 1130 if hr is None: # binary
1131 1131 yield hr, lines
1132 1132 continue
1133 1133 if any(mdiff.hunkinrange(hr[2:], lr) for lr in lineranges):
1134 1134 yield hr, lines
1135 1135 else:
1136 1136 for hunk in hunks:
1137 1137 yield hunk
1138 1138
1139 1139 return filterfn
1140 1140
1141 1141 def filematcher(ctx):
1142 1142 files = list(linerangesbyrev.get(scmutil.intrev(ctx), []))
1143 1143 return scmutil.matchfiles(repo, files)
1144 1144
1145 1145 revs = sorted(linerangesbyrev, reverse=True)
1146 1146
1147 1147 differ = changesetdiffer()
1148 1148 differ._makefilematcher = filematcher
1149 1149 differ._makehunksfilter = hunksfilter
1150 1150 return smartset.baseset(revs), differ
1151 1151
1152 1152
1153 1153 def _graphnodeformatter(ui, displayer):
1154 1154 spec = ui.config(b'command-templates', b'graphnode')
1155 1155 if not spec:
1156 1156 return templatekw.getgraphnode # fast path for "{graphnode}"
1157 1157
1158 1158 spec = templater.unquotestring(spec)
1159 1159 if isinstance(displayer, changesettemplater):
1160 1160 # reuse cache of slow templates
1161 1161 tres = displayer._tresources
1162 1162 else:
1163 1163 tres = formatter.templateresources(ui)
1164 1164 templ = formatter.maketemplater(
1165 1165 ui, spec, defaults=templatekw.keywords, resources=tres
1166 1166 )
1167 1167
1168 1168 def formatnode(repo, ctx, cache):
1169 1169 props = {b'ctx': ctx, b'repo': repo}
1170 1170 return templ.renderdefault(props)
1171 1171
1172 1172 return formatnode
1173 1173
1174 1174
1175 1175 def displaygraph(ui, repo, dag, displayer, edgefn, getcopies=None, props=None):
1176 1176 props = props or {}
1177 1177 formatnode = _graphnodeformatter(ui, displayer)
1178 1178 state = graphmod.asciistate()
1179 1179 styles = state.styles
1180 1180
1181 1181 # only set graph styling if HGPLAIN is not set.
1182 1182 if ui.plain(b'graph'):
1183 1183 # set all edge styles to |, the default pre-3.8 behaviour
1184 1184 styles.update(dict.fromkeys(styles, b'|'))
1185 1185 else:
1186 1186 edgetypes = {
1187 1187 b'parent': graphmod.PARENT,
1188 1188 b'grandparent': graphmod.GRANDPARENT,
1189 1189 b'missing': graphmod.MISSINGPARENT,
1190 1190 }
1191 1191 for name, key in edgetypes.items():
1192 1192 # experimental config: experimental.graphstyle.*
1193 1193 styles[key] = ui.config(
1194 1194 b'experimental', b'graphstyle.%s' % name, styles[key]
1195 1195 )
1196 1196 if not styles[key]:
1197 1197 styles[key] = None
1198 1198
1199 1199 # experimental config: experimental.graphshorten
1200 1200 state.graphshorten = ui.configbool(b'experimental', b'graphshorten')
1201 1201
1202 1202 formatnode_cache = {}
1203 1203 for rev, type, ctx, parents in dag:
1204 1204 char = formatnode(repo, ctx, formatnode_cache)
1205 1205 copies = getcopies(ctx) if getcopies else None
1206 1206 edges = edgefn(type, char, state, rev, parents)
1207 1207 firstedge = next(edges)
1208 1208 width = firstedge[2]
1209 1209 displayer.show(
1210 1210 ctx, copies=copies, graphwidth=width, **pycompat.strkwargs(props)
1211 1211 )
1212 1212 lines = displayer.hunk.pop(rev).split(b'\n')
1213 1213 if not lines[-1]:
1214 1214 del lines[-1]
1215 1215 displayer.flush(ctx)
1216 1216 for type, char, width, coldata in itertools.chain([firstedge], edges):
1217 1217 graphmod.ascii(ui, state, type, char, lines, coldata)
1218 1218 lines = []
1219 1219 displayer.close()
1220 1220
1221 1221
1222 1222 def displaygraphrevs(ui, repo, revs, displayer, getrenamed):
1223 1223 revdag = graphmod.dagwalker(repo, revs)
1224 1224 displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges, getrenamed)
1225 1225
1226 1226
1227 1227 def displayrevs(ui, repo, revs, displayer, getcopies):
1228 1228 for rev in revs:
1229 1229 ctx = repo[rev]
1230 1230 copies = getcopies(ctx) if getcopies else None
1231 1231 displayer.show(ctx, copies=copies)
1232 1232 displayer.flush(ctx)
1233 1233 displayer.close()
1234 1234
1235 1235
1236 1236 def checkunsupportedgraphflags(pats, opts):
1237 1237 for op in [b"newest_first"]:
1238 1238 if op in opts and opts[op]:
1239 1239 raise error.Abort(
1240 1240 _(b"-G/--graph option is incompatible with --%s")
1241 1241 % op.replace(b"_", b"-")
1242 1242 )
1243 1243
1244 1244
1245 1245 def graphrevs(repo, nodes, opts):
1246 1246 limit = getlimit(opts)
1247 1247 nodes.reverse()
1248 1248 if limit is not None:
1249 1249 nodes = nodes[:limit]
1250 1250 return graphmod.nodes(repo, nodes)
@@ -1,27 +1,28 b''
1 1 == New Features ==
2 2
3 3 * `hg purge` is now a core command using `--confirm` by default.
4 4
5 5 * The `rev-branch-cache` is now updated incrementally whenever changesets
6 6 are added.
7 7
8 8
9 9 == New Experimental Features ==
10 10
11 11 * There's a new `diff.merge` config option to show the changes
12 12 relative to an automerge for merge changesets. This makes it
13 13 easier to detect and review manual changes performed in merge
14 changesets. It is only supported by `hg diff --change` so far.
14 changesets. It is supported by `hg diff --change`, `hg log -p`
15 `hg incoming -p`, and `hg outgoing -p` so far.
15 16
16 17
17 18 == Bug Fixes ==
18 19
19 20
20 21
21 22 == Backwards Compatibility Changes ==
22 23
23 24
24 25 == Internal API Changes ==
25 26
26 27 * `changelog.branchinfo` is deprecated and will be removed after 5.8.
27 28 It is superseded by `changelogrevision.branchinfo`.
@@ -1,2917 +1,2937 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 Respects ui.logtemplate and command-templates.log configs (the latter takes
454 454 precedence)
455 455
456 456 $ hg log -r 0 --config ui.logtemplate="foo {rev}\n"
457 457 foo 0
458 458 $ hg log -r 0 --config command-templates.log="bar {rev}\n"
459 459 bar 0
460 460 $ hg log -r 0 --config ui.logtemplate="foo {rev}\n" \
461 461 > --config command-templates.log="bar {rev}\n"
462 462 bar 0
463 463
464 464
465 465 -f and multiple filelog heads
466 466
467 467 $ hg up -q 2
468 468 $ hg log -f g --template '{rev}\n'
469 469 2
470 470 1
471 471 0
472 472 $ hg up -q tip
473 473 $ hg log -f g --template '{rev}\n'
474 474 3
475 475 2
476 476 0
477 477
478 478 follow files from the specified revisions (issue4959)
479 479
480 480 $ hg log -G -T '{rev} {files},{file_copies % " {source}->{name}"}\n'
481 481 @ 4 dir/b e, dir/b->e
482 482 |
483 483 o 3 a b d g, a->b f->g
484 484 |
485 485 o 2 b dir/b f g, b->dir/b
486 486 |
487 487 o 1 b g, a->b f->g
488 488 |
489 489 o 0 a f,
490 490
491 491
492 492 $ hg log -T '{rev}\n' -fr 4 e
493 493 4
494 494 2
495 495 1
496 496 0
497 497 $ hg log -T '{rev}\n' -fr 2 g
498 498 2
499 499 1
500 500 0
501 501 $ hg log -T '{rev}\n' -fr '2+3' g
502 502 3
503 503 2
504 504 1
505 505 0
506 506
507 507 follow files from the specified revisions with glob patterns (issue5053)
508 508 (BROKEN: should follow copies from e@4)
509 509
510 510 $ hg log -T '{rev}\n' -fr4 e -X '[abcdfg]'
511 511 4
512 512 2 (false !)
513 513 1 (false !)
514 514 0 (false !)
515 515
516 516 follow files from the specified revisions with missing patterns
517 517
518 518 $ hg log -T '{rev}\n' -fr4 e x
519 519 abort: cannot follow file not in any of the specified revisions: "x"
520 520 [255]
521 521
522 522 follow files from the specified revisions with directory patterns
523 523 (BROKEN: should follow copies from dir/b@2)
524 524
525 525 $ hg log -T '{rev}\n' -fr2 dir/b dir
526 526 2
527 527 1 (false !)
528 528 0 (false !)
529 529
530 530 follow files from multiple revisions, but the pattern is missing in
531 531 one of the specified revisions
532 532
533 533 $ hg log -T '{rev}\n' -fr'2+4' dir/b e
534 534 e: no such file in rev f8954cd4dc1f
535 535 dir/b: no such file in rev 7e4639b4691b
536 536 4
537 537 2
538 538 1
539 539 0
540 540
541 541 follow files from multiple revisions, and the pattern matches a file in
542 542 one revision but matches a directory in another:
543 543 (BROKEN: should follow copies from dir/b@2 and dir/b/g@5)
544 544 (BROKEN: the revision 4 should not be included since dir/b/g@5 is unchanged)
545 545
546 546 $ mkdir -p dir/b
547 547 $ hg mv g dir/b
548 548 $ hg ci -m 'make dir/b a directory'
549 549
550 550 $ hg log -T '{rev}\n' -fr'2+5' dir/b
551 551 5
552 552 4
553 553 3 (false !)
554 554 2
555 555 1 (false !)
556 556 0 (false !)
557 557
558 558 $ hg --config extensions.strip= strip -r. --no-backup
559 559 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
560 560
561 561 follow files from the specified revisions across copies with -p/--patch
562 562
563 563 $ hg log -T '== rev: {rev},{file_copies % " {source}->{name}"} ==\n' -fpr 4 e g
564 564 == rev: 4, dir/b->e ==
565 565 diff -r 2ca5ba701980 -r 7e4639b4691b e
566 566 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
567 567 +++ b/e Thu Jan 01 00:00:05 1970 +0000
568 568 @@ -0,0 +1,1 @@
569 569 +a
570 570
571 571 == rev: 3, a->b f->g ==
572 572 diff -r f8954cd4dc1f -r 2ca5ba701980 g
573 573 --- a/g Thu Jan 01 00:00:03 1970 +0000
574 574 +++ b/g Thu Jan 01 00:00:04 1970 +0000
575 575 @@ -1,2 +1,2 @@
576 576 f
577 577 -g
578 578 +f
579 579
580 580 == rev: 2, b->dir/b ==
581 581 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
582 582 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
583 583 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
584 584 @@ -0,0 +1,1 @@
585 585 +a
586 586 diff -r d89b0a12d229 -r f8954cd4dc1f f
587 587 --- a/f Thu Jan 01 00:00:02 1970 +0000
588 588 +++ b/f Thu Jan 01 00:00:03 1970 +0000
589 589 @@ -1,1 +1,2 @@
590 590 f
591 591 +f
592 592
593 593 == rev: 1, a->b f->g ==
594 594 diff -r 9161b9aeaf16 -r d89b0a12d229 b
595 595 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
596 596 +++ b/b Thu Jan 01 00:00:02 1970 +0000
597 597 @@ -0,0 +1,1 @@
598 598 +a
599 599
600 600 == rev: 0, ==
601 601 diff -r 000000000000 -r 9161b9aeaf16 a
602 602 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
603 603 +++ b/a Thu Jan 01 00:00:01 1970 +0000
604 604 @@ -0,0 +1,1 @@
605 605 +a
606 606 diff -r 000000000000 -r 9161b9aeaf16 f
607 607 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
608 608 +++ b/f Thu Jan 01 00:00:01 1970 +0000
609 609 @@ -0,0 +1,1 @@
610 610 +f
611 611
612 612
613 613 log copies with --copies
614 614
615 615 $ hg log -vC --template '{rev} {file_copies}\n'
616 616 4 e (dir/b)
617 617 3 b (a)g (f)
618 618 2 dir/b (b)
619 619 1 b (a)g (f)
620 620 0
621 621
622 622 log copies switch without --copies, with old filecopy template
623 623
624 624 $ hg log -v --template '{rev} {file_copies_switch%filecopy}\n'
625 625 4
626 626 3
627 627 2
628 628 1
629 629 0
630 630
631 631 log copies switch with --copies
632 632
633 633 $ hg log -vC --template '{rev} {file_copies_switch}\n'
634 634 4 e (dir/b)
635 635 3 b (a)g (f)
636 636 2 dir/b (b)
637 637 1 b (a)g (f)
638 638 0
639 639
640 640
641 641 log copies with hardcoded style and with --style=default
642 642
643 643 $ hg log -vC -r4
644 644 changeset: 4:7e4639b4691b
645 645 tag: tip
646 646 user: test
647 647 date: Thu Jan 01 00:00:05 1970 +0000
648 648 files: dir/b e
649 649 copies: e (dir/b)
650 650 description:
651 651 e
652 652
653 653
654 654 $ hg log -vC -r4 --style=default
655 655 changeset: 4:7e4639b4691b
656 656 tag: tip
657 657 user: test
658 658 date: Thu Jan 01 00:00:05 1970 +0000
659 659 files: dir/b e
660 660 copies: e (dir/b)
661 661 description:
662 662 e
663 663
664 664
665 665 $ hg log -vC -r4 -Tjson
666 666 [
667 667 {
668 668 "bookmarks": [],
669 669 "branch": "default",
670 670 "copies": {"e": "dir/b"},
671 671 "date": [5, 0],
672 672 "desc": "e",
673 673 "files": ["dir/b", "e"],
674 674 "node": "7e4639b4691b9f84b81036a8d4fb218ce3c5e3a3",
675 675 "parents": ["2ca5ba7019804f1f597249caddf22a64d34df0ba"],
676 676 "phase": "draft",
677 677 "rev": 4,
678 678 "tags": ["tip"],
679 679 "user": "test"
680 680 }
681 681 ]
682 682
683 683 log copies, non-linear manifest
684 684
685 685 $ hg up -C 3
686 686 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
687 687 $ hg mv dir/b e
688 688 $ echo foo > foo
689 689 $ hg ci -Ame2 -d '6 0'
690 690 adding foo
691 691 created new head
692 692 $ hg log -v --template '{rev} {file_copies}\n' -r 5
693 693 5 e (dir/b)
694 694
695 695
696 696 log copies, execute bit set
697 697
698 698 #if execbit
699 699 $ chmod +x e
700 700 $ hg ci -me3 -d '7 0'
701 701 $ hg log -v --template '{rev} {file_copies}\n' -r 6
702 702 6
703 703 #endif
704 704
705 705 log copies, empty set
706 706
707 707 $ hg log --copies -r '0 and not 0'
708 708
709 709 log -p d
710 710
711 711 $ hg log -pv d
712 712 changeset: 3:2ca5ba701980
713 713 user: test
714 714 date: Thu Jan 01 00:00:04 1970 +0000
715 715 files: a b d g
716 716 description:
717 717 d
718 718
719 719
720 720 diff -r f8954cd4dc1f -r 2ca5ba701980 d
721 721 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
722 722 +++ b/d Thu Jan 01 00:00:04 1970 +0000
723 723 @@ -0,0 +1,1 @@
724 724 +a
725 725
726 726
727 727
728 728 log --removed file
729 729
730 730 $ hg log --removed -v a
731 731 changeset: 3:2ca5ba701980
732 732 user: test
733 733 date: Thu Jan 01 00:00:04 1970 +0000
734 734 files: a b d g
735 735 description:
736 736 d
737 737
738 738
739 739 changeset: 0:9161b9aeaf16
740 740 user: test
741 741 date: Thu Jan 01 00:00:01 1970 +0000
742 742 files: a f
743 743 description:
744 744 a
745 745
746 746
747 747
748 748 log --removed revrange file
749 749
750 750 $ hg log --removed -v -r0:2 a
751 751 changeset: 0:9161b9aeaf16
752 752 user: test
753 753 date: Thu Jan 01 00:00:01 1970 +0000
754 754 files: a f
755 755 description:
756 756 a
757 757
758 758
759 759 $ cd ..
760 760
761 761 log --follow tests
762 762
763 763 $ hg init follow
764 764 $ cd follow
765 765
766 766 $ echo base > base
767 767 $ hg ci -Ambase -d '1 0'
768 768 adding base
769 769
770 770 $ echo r1 >> base
771 771 $ hg ci -Amr1 -d '1 0'
772 772 $ echo r2 >> base
773 773 $ hg ci -Amr2 -d '1 0'
774 774
775 775 $ hg up -C 1
776 776 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
777 777 $ echo b1 > b1
778 778
779 779 log -r "follow('set:clean()')"
780 780
781 781 $ hg log -r "follow('set:clean()')"
782 782 changeset: 0:67e992f2c4f3
783 783 user: test
784 784 date: Thu Jan 01 00:00:01 1970 +0000
785 785 summary: base
786 786
787 787 changeset: 1:3d5bf5654eda
788 788 user: test
789 789 date: Thu Jan 01 00:00:01 1970 +0000
790 790 summary: r1
791 791
792 792
793 793 $ hg ci -Amb1 -d '1 0'
794 794 adding b1
795 795 created new head
796 796
797 797
798 798 log -f
799 799
800 800 $ hg log -f
801 801 changeset: 3:e62f78d544b4
802 802 tag: tip
803 803 parent: 1:3d5bf5654eda
804 804 user: test
805 805 date: Thu Jan 01 00:00:01 1970 +0000
806 806 summary: b1
807 807
808 808 changeset: 1:3d5bf5654eda
809 809 user: test
810 810 date: Thu Jan 01 00:00:01 1970 +0000
811 811 summary: r1
812 812
813 813 changeset: 0:67e992f2c4f3
814 814 user: test
815 815 date: Thu Jan 01 00:00:01 1970 +0000
816 816 summary: base
817 817
818 818
819 819 log -r follow('glob:b*')
820 820
821 821 $ hg log -r "follow('glob:b*')"
822 822 changeset: 0:67e992f2c4f3
823 823 user: test
824 824 date: Thu Jan 01 00:00:01 1970 +0000
825 825 summary: base
826 826
827 827 changeset: 1:3d5bf5654eda
828 828 user: test
829 829 date: Thu Jan 01 00:00:01 1970 +0000
830 830 summary: r1
831 831
832 832 changeset: 3:e62f78d544b4
833 833 tag: tip
834 834 parent: 1:3d5bf5654eda
835 835 user: test
836 836 date: Thu Jan 01 00:00:01 1970 +0000
837 837 summary: b1
838 838
839 839 log -f -r '1 + 4'
840 840
841 841 $ hg up -C 0
842 842 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
843 843 $ echo b2 > b2
844 844 $ hg ci -Amb2 -d '1 0'
845 845 adding b2
846 846 created new head
847 847 $ hg log -f -r '1 + 4'
848 848 changeset: 4:ddb82e70d1a1
849 849 tag: tip
850 850 parent: 0:67e992f2c4f3
851 851 user: test
852 852 date: Thu Jan 01 00:00:01 1970 +0000
853 853 summary: b2
854 854
855 855 changeset: 1:3d5bf5654eda
856 856 user: test
857 857 date: Thu Jan 01 00:00:01 1970 +0000
858 858 summary: r1
859 859
860 860 changeset: 0:67e992f2c4f3
861 861 user: test
862 862 date: Thu Jan 01 00:00:01 1970 +0000
863 863 summary: base
864 864
865 865
866 866 log -fr with aliases: 'A' should be expanded, but 'reverse()' should have no
867 867 effect
868 868
869 869 $ hg log --config 'revsetalias.reverse(x)=x' --config 'revsetalias.A=1+4' -qfrA
870 870 4:ddb82e70d1a1
871 871 1:3d5bf5654eda
872 872 0:67e992f2c4f3
873 873
874 874 log -r "follow('set:grep(b2)')"
875 875
876 876 $ hg log -r "follow('set:grep(b2)')"
877 877 changeset: 4:ddb82e70d1a1
878 878 tag: tip
879 879 parent: 0:67e992f2c4f3
880 880 user: test
881 881 date: Thu Jan 01 00:00:01 1970 +0000
882 882 summary: b2
883 883
884 884 log -r "follow('set:grep(b2)', 4)"
885 885
886 886 $ hg up -qC 0
887 887 $ hg log -r "follow('set:grep(b2)', 4)"
888 888 changeset: 4:ddb82e70d1a1
889 889 tag: tip
890 890 parent: 0:67e992f2c4f3
891 891 user: test
892 892 date: Thu Jan 01 00:00:01 1970 +0000
893 893 summary: b2
894 894
895 895
896 896 follow files starting from multiple revisions:
897 897
898 898 $ hg log -T '{rev}: {files}\n' -r "follow('glob:b?', startrev=2+3+4)"
899 899 3: b1
900 900 4: b2
901 901
902 902 follow files starting from empty revision:
903 903
904 904 $ hg log -T '{rev}: {files}\n' -r "follow('glob:*', startrev=.-.)"
905 905
906 906 follow starting from revisions:
907 907
908 908 $ hg log -Gq -r "follow(startrev=2+4)"
909 909 o 4:ddb82e70d1a1
910 910 |
911 911 | o 2:60c670bf5b30
912 912 | |
913 913 | o 1:3d5bf5654eda
914 914 |/
915 915 @ 0:67e992f2c4f3
916 916
917 917
918 918 follow the current revision:
919 919
920 920 $ hg log -Gq -r "follow()"
921 921 @ 0:67e992f2c4f3
922 922
923 923
924 924 $ hg up -qC 4
925 925
926 926 log -f -r null
927 927
928 928 $ hg log -f -r null
929 929 changeset: -1:000000000000
930 930 user:
931 931 date: Thu Jan 01 00:00:00 1970 +0000
932 932
933 933 $ hg log -f -r null -G
934 934 o changeset: -1:000000000000
935 935 user:
936 936 date: Thu Jan 01 00:00:00 1970 +0000
937 937
938 938
939 939
940 940 log -f with null parent
941 941
942 942 $ hg up -C null
943 943 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
944 944 $ hg log -f
945 945
946 946
947 947 log -r . with two parents
948 948
949 949 $ hg up -C 3
950 950 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
951 951 $ hg merge tip
952 952 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
953 953 (branch merge, don't forget to commit)
954 954 $ hg log -r .
955 955 changeset: 3:e62f78d544b4
956 956 parent: 1:3d5bf5654eda
957 957 user: test
958 958 date: Thu Jan 01 00:00:01 1970 +0000
959 959 summary: b1
960 960
961 961
962 962
963 963 log -r . with one parent
964 964
965 965 $ hg ci -mm12 -d '1 0'
966 966 $ hg log -r .
967 967 changeset: 5:302e9dd6890d
968 968 tag: tip
969 969 parent: 3:e62f78d544b4
970 970 parent: 4:ddb82e70d1a1
971 971 user: test
972 972 date: Thu Jan 01 00:00:01 1970 +0000
973 973 summary: m12
974 974
975 975
976 976 $ echo postm >> b1
977 977 $ hg ci -Amb1.1 -d'1 0'
978 978
979 979
980 980 log --follow-first
981 981
982 982 $ hg log --follow-first
983 983 changeset: 6:2404bbcab562
984 984 tag: tip
985 985 user: test
986 986 date: Thu Jan 01 00:00:01 1970 +0000
987 987 summary: b1.1
988 988
989 989 changeset: 5:302e9dd6890d
990 990 parent: 3:e62f78d544b4
991 991 parent: 4:ddb82e70d1a1
992 992 user: test
993 993 date: Thu Jan 01 00:00:01 1970 +0000
994 994 summary: m12
995 995
996 996 changeset: 3:e62f78d544b4
997 997 parent: 1:3d5bf5654eda
998 998 user: test
999 999 date: Thu Jan 01 00:00:01 1970 +0000
1000 1000 summary: b1
1001 1001
1002 1002 changeset: 1:3d5bf5654eda
1003 1003 user: test
1004 1004 date: Thu Jan 01 00:00:01 1970 +0000
1005 1005 summary: r1
1006 1006
1007 1007 changeset: 0:67e992f2c4f3
1008 1008 user: test
1009 1009 date: Thu Jan 01 00:00:01 1970 +0000
1010 1010 summary: base
1011 1011
1012 1012
1013 1013
1014 1014 log -P 2
1015 1015
1016 1016 $ hg log -P 2
1017 1017 changeset: 6:2404bbcab562
1018 1018 tag: tip
1019 1019 user: test
1020 1020 date: Thu Jan 01 00:00:01 1970 +0000
1021 1021 summary: b1.1
1022 1022
1023 1023 changeset: 5:302e9dd6890d
1024 1024 parent: 3:e62f78d544b4
1025 1025 parent: 4:ddb82e70d1a1
1026 1026 user: test
1027 1027 date: Thu Jan 01 00:00:01 1970 +0000
1028 1028 summary: m12
1029 1029
1030 1030 changeset: 4:ddb82e70d1a1
1031 1031 parent: 0:67e992f2c4f3
1032 1032 user: test
1033 1033 date: Thu Jan 01 00:00:01 1970 +0000
1034 1034 summary: b2
1035 1035
1036 1036 changeset: 3:e62f78d544b4
1037 1037 parent: 1:3d5bf5654eda
1038 1038 user: test
1039 1039 date: Thu Jan 01 00:00:01 1970 +0000
1040 1040 summary: b1
1041 1041
1042 1042
1043 1043
1044 1044 log -r tip -p --git
1045 1045
1046 1046 $ hg log -r tip -p --git
1047 1047 changeset: 6:2404bbcab562
1048 1048 tag: tip
1049 1049 user: test
1050 1050 date: Thu Jan 01 00:00:01 1970 +0000
1051 1051 summary: b1.1
1052 1052
1053 1053 diff --git a/b1 b/b1
1054 1054 --- a/b1
1055 1055 +++ b/b1
1056 1056 @@ -1,1 +1,2 @@
1057 1057 b1
1058 1058 +postm
1059 1059
1060 1060
1061 1061
1062 1062 log -r ""
1063 1063
1064 1064 $ hg log -r ''
1065 1065 hg: parse error: empty query
1066 1066 [10]
1067 1067
1068 1068 log -r <some unknown node id>
1069 1069
1070 1070 $ hg log -r 1000000000000000000000000000000000000000
1071 1071 abort: unknown revision '1000000000000000000000000000000000000000'
1072 1072 [255]
1073 1073
1074 1074 log -k r1
1075 1075
1076 1076 $ hg log -k r1
1077 1077 changeset: 1:3d5bf5654eda
1078 1078 user: test
1079 1079 date: Thu Jan 01 00:00:01 1970 +0000
1080 1080 summary: r1
1081 1081
1082 1082 log -p -l2 --color=always
1083 1083
1084 1084 $ hg --config extensions.color= --config color.mode=ansi \
1085 1085 > log -p -l2 --color=always
1086 1086 \x1b[0;33mchangeset: 6:2404bbcab562\x1b[0m (esc)
1087 1087 tag: tip
1088 1088 user: test
1089 1089 date: Thu Jan 01 00:00:01 1970 +0000
1090 1090 summary: b1.1
1091 1091
1092 1092 \x1b[0;1mdiff -r 302e9dd6890d -r 2404bbcab562 b1\x1b[0m (esc)
1093 1093 \x1b[0;31;1m--- a/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
1094 1094 \x1b[0;32;1m+++ b/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
1095 1095 \x1b[0;35m@@ -1,1 +1,2 @@\x1b[0m (esc)
1096 1096 b1
1097 1097 \x1b[0;32m+postm\x1b[0m (esc)
1098 1098
1099 1099 \x1b[0;33mchangeset: 5:302e9dd6890d\x1b[0m (esc)
1100 1100 parent: 3:e62f78d544b4
1101 1101 parent: 4:ddb82e70d1a1
1102 1102 user: test
1103 1103 date: Thu Jan 01 00:00:01 1970 +0000
1104 1104 summary: m12
1105 1105
1106 1106 \x1b[0;1mdiff -r e62f78d544b4 -r 302e9dd6890d b2\x1b[0m (esc)
1107 1107 \x1b[0;31;1m--- /dev/null Thu Jan 01 00:00:00 1970 +0000\x1b[0m (esc)
1108 1108 \x1b[0;32;1m+++ b/b2 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
1109 1109 \x1b[0;35m@@ -0,0 +1,1 @@\x1b[0m (esc)
1110 1110 \x1b[0;32m+b2\x1b[0m (esc)
1111 1111
1112 1112
1113 1113
1114 1114 log -r tip --stat
1115 1115
1116 1116 $ hg log -r tip --stat
1117 1117 changeset: 6:2404bbcab562
1118 1118 tag: tip
1119 1119 user: test
1120 1120 date: Thu Jan 01 00:00:01 1970 +0000
1121 1121 summary: b1.1
1122 1122
1123 1123 b1 | 1 +
1124 1124 1 files changed, 1 insertions(+), 0 deletions(-)
1125 1125
1126 1126
1127 1127 $ cd ..
1128 1128
1129 1129 log --follow --patch FILE in repository where linkrev isn't trustworthy
1130 1130 (issue5376, issue6124)
1131 1131
1132 1132 $ hg init follow-dup
1133 1133 $ cd follow-dup
1134 1134 $ cat <<EOF >> .hg/hgrc
1135 1135 > [command-templates]
1136 1136 > log = '=== {rev}: {desc}\n'
1137 1137 > [diff]
1138 1138 > nodates = True
1139 1139 > EOF
1140 1140 $ echo 0 >> a
1141 1141 $ hg ci -qAm 'a0'
1142 1142 $ echo 1 >> a
1143 1143 $ hg ci -m 'a1'
1144 1144 $ hg up -q 0
1145 1145 $ echo 1 >> a
1146 1146 $ touch b
1147 1147 $ hg ci -qAm 'a1 with b'
1148 1148 $ echo 3 >> a
1149 1149 $ hg ci -m 'a3'
1150 1150
1151 1151 fctx.rev() == 2, but fctx.linkrev() == 1
1152 1152
1153 1153 $ hg log -pf a
1154 1154 === 3: a3
1155 1155 diff -r 4ea02ba94d66 -r e7a6331a34f0 a
1156 1156 --- a/a
1157 1157 +++ b/a
1158 1158 @@ -1,2 +1,3 @@
1159 1159 0
1160 1160 1
1161 1161 +3
1162 1162
1163 1163 === 2: a1 with b
1164 1164 diff -r 49b5e81287e2 -r 4ea02ba94d66 a
1165 1165 --- a/a
1166 1166 +++ b/a
1167 1167 @@ -1,1 +1,2 @@
1168 1168 0
1169 1169 +1
1170 1170
1171 1171 === 0: a0
1172 1172 diff -r 000000000000 -r 49b5e81287e2 a
1173 1173 --- /dev/null
1174 1174 +++ b/a
1175 1175 @@ -0,0 +1,1 @@
1176 1176 +0
1177 1177
1178 1178 $ hg log -pr . a
1179 1179 === 3: a3
1180 1180 diff -r 4ea02ba94d66 -r e7a6331a34f0 a
1181 1181 --- a/a
1182 1182 +++ b/a
1183 1183 @@ -1,2 +1,3 @@
1184 1184 0
1185 1185 1
1186 1186 +3
1187 1187
1188 1188
1189 1189 fctx.introrev() == 2, but fctx.linkrev() == 1
1190 1190
1191 1191 $ hg up -q 2
1192 1192 $ hg log -pf a
1193 1193 === 2: a1 with b
1194 1194 diff -r 49b5e81287e2 -r 4ea02ba94d66 a
1195 1195 --- a/a
1196 1196 +++ b/a
1197 1197 @@ -1,1 +1,2 @@
1198 1198 0
1199 1199 +1
1200 1200
1201 1201 === 0: a0
1202 1202 diff -r 000000000000 -r 49b5e81287e2 a
1203 1203 --- /dev/null
1204 1204 +++ b/a
1205 1205 @@ -0,0 +1,1 @@
1206 1206 +0
1207 1207
1208 1208
1209 1209 BROKEN: should show the same diff as for rev 2 above
1210 1210 $ hg log -pr . a
1211 1211
1212 1212 $ cd ..
1213 1213
1214 1214 Multiple copy sources of a file:
1215 1215
1216 1216 $ hg init follow-multi
1217 1217 $ cd follow-multi
1218 1218 $ echo 0 >> a
1219 1219 $ hg ci -qAm 'a'
1220 1220 $ hg cp a b
1221 1221 $ hg ci -m 'a->b'
1222 1222 $ echo 2 >> a
1223 1223 $ hg ci -m 'a'
1224 1224 $ echo 3 >> b
1225 1225 $ hg ci -m 'b'
1226 1226 $ echo 4 >> a
1227 1227 $ echo 4 >> b
1228 1228 $ hg ci -m 'a,b'
1229 1229 $ echo 5 >> a
1230 1230 $ hg ci -m 'a0'
1231 1231 $ echo 6 >> b
1232 1232 $ hg ci -m 'b0'
1233 1233 $ hg up -q 4
1234 1234 $ echo 7 >> b
1235 1235 $ hg ci -m 'b1'
1236 1236 created new head
1237 1237 $ echo 8 >> a
1238 1238 $ hg ci -m 'a1'
1239 1239 $ hg rm a
1240 1240 $ hg mv b a
1241 1241 $ hg ci -m 'b1->a1'
1242 1242 $ hg merge -qt :local
1243 1243 $ hg ci -m '(a0,b1->a1)->a'
1244 1244
1245 1245 $ hg log -GT '{rev}: {desc}\n'
1246 1246 @ 10: (a0,b1->a1)->a
1247 1247 |\
1248 1248 | o 9: b1->a1
1249 1249 | |
1250 1250 | o 8: a1
1251 1251 | |
1252 1252 | o 7: b1
1253 1253 | |
1254 1254 o | 6: b0
1255 1255 | |
1256 1256 o | 5: a0
1257 1257 |/
1258 1258 o 4: a,b
1259 1259 |
1260 1260 o 3: b
1261 1261 |
1262 1262 o 2: a
1263 1263 |
1264 1264 o 1: a->b
1265 1265 |
1266 1266 o 0: a
1267 1267
1268 1268
1269 1269 since file 'a' has multiple copy sources at the revision 4, ancestors can't
1270 1270 be indexed solely by fctx.linkrev().
1271 1271
1272 1272 $ hg log -T '{rev}: {desc}\n' -f a
1273 1273 10: (a0,b1->a1)->a
1274 1274 9: b1->a1
1275 1275 7: b1
1276 1276 5: a0
1277 1277 4: a,b
1278 1278 3: b
1279 1279 2: a
1280 1280 1: a->b
1281 1281 0: a
1282 1282
1283 1283 $ cd ..
1284 1284
1285 1285 Test that log should respect the order of -rREV even if multiple OR conditions
1286 1286 are specified (issue5100):
1287 1287
1288 1288 $ hg init revorder
1289 1289 $ cd revorder
1290 1290
1291 1291 $ hg branch -q b0
1292 1292 $ echo 0 >> f0
1293 1293 $ hg ci -qAm k0 -u u0
1294 1294 $ hg branch -q b1
1295 1295 $ echo 1 >> f1
1296 1296 $ hg ci -qAm k1 -u u1
1297 1297 $ hg branch -q b2
1298 1298 $ echo 2 >> f2
1299 1299 $ hg ci -qAm k2 -u u2
1300 1300
1301 1301 $ hg update -q b2
1302 1302 $ echo 3 >> f2
1303 1303 $ hg ci -qAm k2 -u u2
1304 1304 $ hg update -q b1
1305 1305 $ echo 4 >> f1
1306 1306 $ hg ci -qAm k1 -u u1
1307 1307 $ hg update -q b0
1308 1308 $ echo 5 >> f0
1309 1309 $ hg ci -qAm k0 -u u0
1310 1310
1311 1311 summary of revisions:
1312 1312
1313 1313 $ hg log -G -T '{rev} {branch} {author} {desc} {files}\n'
1314 1314 @ 5 b0 u0 k0 f0
1315 1315 |
1316 1316 | o 4 b1 u1 k1 f1
1317 1317 | |
1318 1318 | | o 3 b2 u2 k2 f2
1319 1319 | | |
1320 1320 | | o 2 b2 u2 k2 f2
1321 1321 | |/
1322 1322 | o 1 b1 u1 k1 f1
1323 1323 |/
1324 1324 o 0 b0 u0 k0 f0
1325 1325
1326 1326
1327 1327 log -b BRANCH in ascending order:
1328 1328
1329 1329 $ hg log -r0:tip -T '{rev} {branch}\n' -b b0 -b b1
1330 1330 0 b0
1331 1331 1 b1
1332 1332 4 b1
1333 1333 5 b0
1334 1334 $ hg log -r0:tip -T '{rev} {branch}\n' -b b1 -b b0
1335 1335 0 b0
1336 1336 1 b1
1337 1337 4 b1
1338 1338 5 b0
1339 1339
1340 1340 log --only-branch BRANCH in descending order:
1341 1341
1342 1342 $ hg log -rtip:0 -T '{rev} {branch}\n' --only-branch b1 --only-branch b2
1343 1343 4 b1
1344 1344 3 b2
1345 1345 2 b2
1346 1346 1 b1
1347 1347 $ hg log -rtip:0 -T '{rev} {branch}\n' --only-branch b2 --only-branch b1
1348 1348 4 b1
1349 1349 3 b2
1350 1350 2 b2
1351 1351 1 b1
1352 1352
1353 1353 log -u USER in ascending order, against compound set:
1354 1354
1355 1355 $ hg log -r'::head()' -T '{rev} {author}\n' -u u0 -u u2
1356 1356 0 u0
1357 1357 2 u2
1358 1358 3 u2
1359 1359 5 u0
1360 1360 $ hg log -r'::head()' -T '{rev} {author}\n' -u u2 -u u0
1361 1361 0 u0
1362 1362 2 u2
1363 1363 3 u2
1364 1364 5 u0
1365 1365
1366 1366 log -k TEXT in descending order, against compound set:
1367 1367
1368 1368 $ hg log -r'5 + reverse(::3)' -T '{rev} {desc}\n' -k k0 -k k1 -k k2
1369 1369 5 k0
1370 1370 3 k2
1371 1371 2 k2
1372 1372 1 k1
1373 1373 0 k0
1374 1374 $ hg log -r'5 + reverse(::3)' -T '{rev} {desc}\n' -k k2 -k k1 -k k0
1375 1375 5 k0
1376 1376 3 k2
1377 1377 2 k2
1378 1378 1 k1
1379 1379 0 k0
1380 1380
1381 1381 log -b/-u/-k shouldn't accept string-matcher syntax:
1382 1382
1383 1383 $ hg log -b 're:.*'
1384 1384 abort: unknown revision 're:.*'
1385 1385 [255]
1386 1386 $ hg log -k 're:.*'
1387 1387 $ hg log -u 're:.*'
1388 1388
1389 1389 log FILE in ascending order, against dagrange:
1390 1390
1391 1391 $ hg log -r1:: -T '{rev} {files}\n' f1 f2
1392 1392 1 f1
1393 1393 2 f2
1394 1394 3 f2
1395 1395 4 f1
1396 1396 $ hg log -r1:: -T '{rev} {files}\n' f2 f1
1397 1397 1 f1
1398 1398 2 f2
1399 1399 3 f2
1400 1400 4 f1
1401 1401
1402 1402 $ cd ..
1403 1403
1404 1404 User
1405 1405
1406 1406 $ hg init usertest
1407 1407 $ cd usertest
1408 1408
1409 1409 $ echo a > a
1410 1410 $ hg ci -A -m "a" -u "User One <user1@example.org>"
1411 1411 adding a
1412 1412 $ echo b > b
1413 1413 $ hg ci -A -m "b" -u "User Two <user2@example.org>"
1414 1414 adding b
1415 1415
1416 1416 $ hg log -u "User One <user1@example.org>"
1417 1417 changeset: 0:29a4c94f1924
1418 1418 user: User One <user1@example.org>
1419 1419 date: Thu Jan 01 00:00:00 1970 +0000
1420 1420 summary: a
1421 1421
1422 1422 $ hg log -u "user1" -u "user2"
1423 1423 changeset: 1:e834b5e69c0e
1424 1424 tag: tip
1425 1425 user: User Two <user2@example.org>
1426 1426 date: Thu Jan 01 00:00:00 1970 +0000
1427 1427 summary: b
1428 1428
1429 1429 changeset: 0:29a4c94f1924
1430 1430 user: User One <user1@example.org>
1431 1431 date: Thu Jan 01 00:00:00 1970 +0000
1432 1432 summary: a
1433 1433
1434 1434 $ hg log -u "user3"
1435 1435
1436 1436 "-u USER" shouldn't be overridden by "user(USER)" alias
1437 1437
1438 1438 $ hg log --config 'revsetalias.user(x)=branch(x)' -u default
1439 1439 $ hg log --config 'revsetalias.user(x)=branch(x)' -u user1
1440 1440 changeset: 0:29a4c94f1924
1441 1441 user: User One <user1@example.org>
1442 1442 date: Thu Jan 01 00:00:00 1970 +0000
1443 1443 summary: a
1444 1444
1445 1445
1446 1446 $ cd ..
1447 1447
1448 1448 $ hg init branches
1449 1449 $ cd branches
1450 1450
1451 1451 $ echo a > a
1452 1452 $ hg ci -A -m "commit on default"
1453 1453 adding a
1454 1454 $ hg branch test
1455 1455 marked working directory as branch test
1456 1456 (branches are permanent and global, did you want a bookmark?)
1457 1457 $ echo b > b
1458 1458 $ hg ci -A -m "commit on test"
1459 1459 adding b
1460 1460
1461 1461 $ hg up default
1462 1462 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1463 1463 $ echo c > c
1464 1464 $ hg ci -A -m "commit on default"
1465 1465 adding c
1466 1466 $ hg up test
1467 1467 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1468 1468 $ echo c > c
1469 1469 $ hg ci -A -m "commit on test"
1470 1470 adding c
1471 1471
1472 1472
1473 1473 log -b default
1474 1474
1475 1475 $ hg log -b default
1476 1476 changeset: 2:c3a4f03cc9a7
1477 1477 parent: 0:24427303d56f
1478 1478 user: test
1479 1479 date: Thu Jan 01 00:00:00 1970 +0000
1480 1480 summary: commit on default
1481 1481
1482 1482 changeset: 0:24427303d56f
1483 1483 user: test
1484 1484 date: Thu Jan 01 00:00:00 1970 +0000
1485 1485 summary: commit on default
1486 1486
1487 1487
1488 1488
1489 1489 log -b test
1490 1490
1491 1491 $ hg log -b test
1492 1492 changeset: 3:f5d8de11c2e2
1493 1493 branch: test
1494 1494 tag: tip
1495 1495 parent: 1:d32277701ccb
1496 1496 user: test
1497 1497 date: Thu Jan 01 00:00:00 1970 +0000
1498 1498 summary: commit on test
1499 1499
1500 1500 changeset: 1:d32277701ccb
1501 1501 branch: test
1502 1502 user: test
1503 1503 date: Thu Jan 01 00:00:00 1970 +0000
1504 1504 summary: commit on test
1505 1505
1506 1506
1507 1507
1508 1508 log -b dummy
1509 1509
1510 1510 $ hg log -b dummy
1511 1511 abort: unknown revision 'dummy'
1512 1512 [255]
1513 1513
1514 1514
1515 1515 log -b .
1516 1516
1517 1517 $ hg log -b .
1518 1518 changeset: 3:f5d8de11c2e2
1519 1519 branch: test
1520 1520 tag: tip
1521 1521 parent: 1:d32277701ccb
1522 1522 user: test
1523 1523 date: Thu Jan 01 00:00:00 1970 +0000
1524 1524 summary: commit on test
1525 1525
1526 1526 changeset: 1:d32277701ccb
1527 1527 branch: test
1528 1528 user: test
1529 1529 date: Thu Jan 01 00:00:00 1970 +0000
1530 1530 summary: commit on test
1531 1531
1532 1532
1533 1533
1534 1534 log -b default -b test
1535 1535
1536 1536 $ hg log -b default -b test
1537 1537 changeset: 3:f5d8de11c2e2
1538 1538 branch: test
1539 1539 tag: tip
1540 1540 parent: 1:d32277701ccb
1541 1541 user: test
1542 1542 date: Thu Jan 01 00:00:00 1970 +0000
1543 1543 summary: commit on test
1544 1544
1545 1545 changeset: 2:c3a4f03cc9a7
1546 1546 parent: 0:24427303d56f
1547 1547 user: test
1548 1548 date: Thu Jan 01 00:00:00 1970 +0000
1549 1549 summary: commit on default
1550 1550
1551 1551 changeset: 1:d32277701ccb
1552 1552 branch: test
1553 1553 user: test
1554 1554 date: Thu Jan 01 00:00:00 1970 +0000
1555 1555 summary: commit on test
1556 1556
1557 1557 changeset: 0:24427303d56f
1558 1558 user: test
1559 1559 date: Thu Jan 01 00:00:00 1970 +0000
1560 1560 summary: commit on default
1561 1561
1562 1562
1563 1563
1564 1564 log -b default -b .
1565 1565
1566 1566 $ hg log -b default -b .
1567 1567 changeset: 3:f5d8de11c2e2
1568 1568 branch: test
1569 1569 tag: tip
1570 1570 parent: 1:d32277701ccb
1571 1571 user: test
1572 1572 date: Thu Jan 01 00:00:00 1970 +0000
1573 1573 summary: commit on test
1574 1574
1575 1575 changeset: 2:c3a4f03cc9a7
1576 1576 parent: 0:24427303d56f
1577 1577 user: test
1578 1578 date: Thu Jan 01 00:00:00 1970 +0000
1579 1579 summary: commit on default
1580 1580
1581 1581 changeset: 1:d32277701ccb
1582 1582 branch: test
1583 1583 user: test
1584 1584 date: Thu Jan 01 00:00:00 1970 +0000
1585 1585 summary: commit on test
1586 1586
1587 1587 changeset: 0:24427303d56f
1588 1588 user: test
1589 1589 date: Thu Jan 01 00:00:00 1970 +0000
1590 1590 summary: commit on default
1591 1591
1592 1592
1593 1593
1594 1594 log -b . -b test
1595 1595
1596 1596 $ hg log -b . -b test
1597 1597 changeset: 3:f5d8de11c2e2
1598 1598 branch: test
1599 1599 tag: tip
1600 1600 parent: 1:d32277701ccb
1601 1601 user: test
1602 1602 date: Thu Jan 01 00:00:00 1970 +0000
1603 1603 summary: commit on test
1604 1604
1605 1605 changeset: 1:d32277701ccb
1606 1606 branch: test
1607 1607 user: test
1608 1608 date: Thu Jan 01 00:00:00 1970 +0000
1609 1609 summary: commit on test
1610 1610
1611 1611
1612 1612
1613 1613 log -b 2
1614 1614
1615 1615 $ hg log -b 2
1616 1616 changeset: 2:c3a4f03cc9a7
1617 1617 parent: 0:24427303d56f
1618 1618 user: test
1619 1619 date: Thu Jan 01 00:00:00 1970 +0000
1620 1620 summary: commit on default
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 #if gettext
1628 1628
1629 1629 Test that all log names are translated (e.g. branches, bookmarks, tags):
1630 1630
1631 1631 $ hg bookmark babar -r tip
1632 1632
1633 1633 $ HGENCODING=UTF-8 LANGUAGE=de hg log -r tip
1634 1634 \xc3\x84nderung: 3:f5d8de11c2e2 (esc)
1635 1635 Zweig: test
1636 1636 Lesezeichen: babar
1637 1637 Marke: tip
1638 1638 Vorg\xc3\xa4nger: 1:d32277701ccb (esc)
1639 1639 Nutzer: test
1640 1640 Datum: Thu Jan 01 00:00:00 1970 +0000
1641 1641 Zusammenfassung: commit on test
1642 1642
1643 1643 $ hg bookmark -d babar
1644 1644
1645 1645 #endif
1646 1646
1647 1647 log -p --cwd dir (in subdir)
1648 1648
1649 1649 $ mkdir dir
1650 1650 $ hg log -p --cwd dir
1651 1651 changeset: 3:f5d8de11c2e2
1652 1652 branch: test
1653 1653 tag: tip
1654 1654 parent: 1:d32277701ccb
1655 1655 user: test
1656 1656 date: Thu Jan 01 00:00:00 1970 +0000
1657 1657 summary: commit on test
1658 1658
1659 1659 diff -r d32277701ccb -r f5d8de11c2e2 c
1660 1660 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1661 1661 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1662 1662 @@ -0,0 +1,1 @@
1663 1663 +c
1664 1664
1665 1665 changeset: 2:c3a4f03cc9a7
1666 1666 parent: 0:24427303d56f
1667 1667 user: test
1668 1668 date: Thu Jan 01 00:00:00 1970 +0000
1669 1669 summary: commit on default
1670 1670
1671 1671 diff -r 24427303d56f -r c3a4f03cc9a7 c
1672 1672 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1673 1673 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1674 1674 @@ -0,0 +1,1 @@
1675 1675 +c
1676 1676
1677 1677 changeset: 1:d32277701ccb
1678 1678 branch: test
1679 1679 user: test
1680 1680 date: Thu Jan 01 00:00:00 1970 +0000
1681 1681 summary: commit on test
1682 1682
1683 1683 diff -r 24427303d56f -r d32277701ccb b
1684 1684 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1685 1685 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1686 1686 @@ -0,0 +1,1 @@
1687 1687 +b
1688 1688
1689 1689 changeset: 0:24427303d56f
1690 1690 user: test
1691 1691 date: Thu Jan 01 00:00:00 1970 +0000
1692 1692 summary: commit on default
1693 1693
1694 1694 diff -r 000000000000 -r 24427303d56f a
1695 1695 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1696 1696 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1697 1697 @@ -0,0 +1,1 @@
1698 1698 +a
1699 1699
1700 1700
1701 1701
1702 1702 log -p -R repo
1703 1703
1704 1704 $ cd dir
1705 1705 $ hg log -p -R .. ../a
1706 1706 changeset: 0:24427303d56f
1707 1707 user: test
1708 1708 date: Thu Jan 01 00:00:00 1970 +0000
1709 1709 summary: commit on default
1710 1710
1711 1711 diff -r 000000000000 -r 24427303d56f a
1712 1712 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1713 1713 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1714 1714 @@ -0,0 +1,1 @@
1715 1715 +a
1716 1716
1717 1717
1718 1718 $ cd ../..
1719 1719
1720 1720 $ hg init follow2
1721 1721 $ cd follow2
1722 1722
1723 1723 # Build the following history:
1724 1724 # tip - o - x - o - x - x
1725 1725 # \ /
1726 1726 # o - o - o - x
1727 1727 # \ /
1728 1728 # o
1729 1729 #
1730 1730 # Where "o" is a revision containing "foo" and
1731 1731 # "x" is a revision without "foo"
1732 1732
1733 1733 $ touch init
1734 1734 $ hg ci -A -m "init, unrelated"
1735 1735 adding init
1736 1736 $ echo 'foo' > init
1737 1737 $ hg ci -m "change, unrelated"
1738 1738 $ echo 'foo' > foo
1739 1739 $ hg ci -A -m "add unrelated old foo"
1740 1740 adding foo
1741 1741 $ hg rm foo
1742 1742 $ hg ci -m "delete foo, unrelated"
1743 1743 $ echo 'related' > foo
1744 1744 $ hg ci -A -m "add foo, related"
1745 1745 adding foo
1746 1746
1747 1747 $ hg up 0
1748 1748 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1749 1749 $ touch branch
1750 1750 $ hg ci -A -m "first branch, unrelated"
1751 1751 adding branch
1752 1752 created new head
1753 1753 $ touch foo
1754 1754 $ hg ci -A -m "create foo, related"
1755 1755 adding foo
1756 1756 $ echo 'change' > foo
1757 1757 $ hg ci -m "change foo, related"
1758 1758
1759 1759 $ hg up 6
1760 1760 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1761 1761 $ echo 'change foo in branch' > foo
1762 1762 $ hg ci -m "change foo in branch, related"
1763 1763 created new head
1764 1764 $ hg merge 7
1765 1765 merging foo
1766 1766 warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
1767 1767 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
1768 1768 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
1769 1769 [1]
1770 1770 $ echo 'merge 1' > foo
1771 1771 $ hg resolve -m foo
1772 1772 (no more unresolved files)
1773 1773 $ hg ci -m "First merge, related"
1774 1774
1775 1775 $ hg merge 4
1776 1776 merging foo
1777 1777 warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
1778 1778 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
1779 1779 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
1780 1780 [1]
1781 1781 $ echo 'merge 2' > foo
1782 1782 $ hg resolve -m foo
1783 1783 (no more unresolved files)
1784 1784 $ hg ci -m "Last merge, related"
1785 1785
1786 1786 $ hg log --graph
1787 1787 @ changeset: 10:4dae8563d2c5
1788 1788 |\ tag: tip
1789 1789 | | parent: 9:7b35701b003e
1790 1790 | | parent: 4:88176d361b69
1791 1791 | | user: test
1792 1792 | | date: Thu Jan 01 00:00:00 1970 +0000
1793 1793 | | summary: Last merge, related
1794 1794 | |
1795 1795 | o changeset: 9:7b35701b003e
1796 1796 | |\ parent: 8:e5416ad8a855
1797 1797 | | | parent: 7:87fe3144dcfa
1798 1798 | | | user: test
1799 1799 | | | date: Thu Jan 01 00:00:00 1970 +0000
1800 1800 | | | summary: First merge, related
1801 1801 | | |
1802 1802 | | o changeset: 8:e5416ad8a855
1803 1803 | | | parent: 6:dc6c325fe5ee
1804 1804 | | | user: test
1805 1805 | | | date: Thu Jan 01 00:00:00 1970 +0000
1806 1806 | | | summary: change foo in branch, related
1807 1807 | | |
1808 1808 | o | changeset: 7:87fe3144dcfa
1809 1809 | |/ user: test
1810 1810 | | date: Thu Jan 01 00:00:00 1970 +0000
1811 1811 | | summary: change foo, related
1812 1812 | |
1813 1813 | o changeset: 6:dc6c325fe5ee
1814 1814 | | user: test
1815 1815 | | date: Thu Jan 01 00:00:00 1970 +0000
1816 1816 | | summary: create foo, related
1817 1817 | |
1818 1818 | o changeset: 5:73db34516eb9
1819 1819 | | parent: 0:e87515fd044a
1820 1820 | | user: test
1821 1821 | | date: Thu Jan 01 00:00:00 1970 +0000
1822 1822 | | summary: first branch, unrelated
1823 1823 | |
1824 1824 o | 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 o | changeset: 3:dd78ae4afb56
1830 1830 | | user: test
1831 1831 | | date: Thu Jan 01 00:00:00 1970 +0000
1832 1832 | | summary: delete foo, unrelated
1833 1833 | |
1834 1834 o | changeset: 2:c4c64aedf0f7
1835 1835 | | user: test
1836 1836 | | date: Thu Jan 01 00:00:00 1970 +0000
1837 1837 | | summary: add unrelated old foo
1838 1838 | |
1839 1839 o | changeset: 1:e5faa7440653
1840 1840 |/ user: test
1841 1841 | date: Thu Jan 01 00:00:00 1970 +0000
1842 1842 | summary: change, unrelated
1843 1843 |
1844 1844 o changeset: 0:e87515fd044a
1845 1845 user: test
1846 1846 date: Thu Jan 01 00:00:00 1970 +0000
1847 1847 summary: init, unrelated
1848 1848
1849 1849
1850 1850 $ hg --traceback log -f foo
1851 1851 changeset: 10:4dae8563d2c5
1852 1852 tag: tip
1853 1853 parent: 9:7b35701b003e
1854 1854 parent: 4:88176d361b69
1855 1855 user: test
1856 1856 date: Thu Jan 01 00:00:00 1970 +0000
1857 1857 summary: Last merge, related
1858 1858
1859 1859 changeset: 9:7b35701b003e
1860 1860 parent: 8:e5416ad8a855
1861 1861 parent: 7:87fe3144dcfa
1862 1862 user: test
1863 1863 date: Thu Jan 01 00:00:00 1970 +0000
1864 1864 summary: First merge, related
1865 1865
1866 1866 changeset: 8:e5416ad8a855
1867 1867 parent: 6:dc6c325fe5ee
1868 1868 user: test
1869 1869 date: Thu Jan 01 00:00:00 1970 +0000
1870 1870 summary: change foo in branch, related
1871 1871
1872 1872 changeset: 7:87fe3144dcfa
1873 1873 user: test
1874 1874 date: Thu Jan 01 00:00:00 1970 +0000
1875 1875 summary: change foo, related
1876 1876
1877 1877 changeset: 6:dc6c325fe5ee
1878 1878 user: test
1879 1879 date: Thu Jan 01 00:00:00 1970 +0000
1880 1880 summary: create foo, related
1881 1881
1882 1882 changeset: 4:88176d361b69
1883 1883 user: test
1884 1884 date: Thu Jan 01 00:00:00 1970 +0000
1885 1885 summary: add foo, related
1886 1886
1887 1887
1888 1888 Also check when maxrev < lastrevfilelog
1889 1889
1890 1890 $ hg --traceback log -f -r4 foo
1891 1891 changeset: 4:88176d361b69
1892 1892 user: test
1893 1893 date: Thu Jan 01 00:00:00 1970 +0000
1894 1894 summary: add foo, related
1895 1895
1896 1896 $ cd ..
1897 1897
1898 1898 Issue2383: hg log showing _less_ differences than hg diff
1899 1899
1900 1900 $ hg init issue2383
1901 1901 $ cd issue2383
1902 1902
1903 1903 Create a test repo:
1904 1904
1905 1905 $ echo a > a
1906 1906 $ hg ci -Am0
1907 1907 adding a
1908 1908 $ echo b > b
1909 1909 $ hg ci -Am1
1910 1910 adding b
1911 1911 $ hg co 0
1912 1912 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1913 1913 $ echo b > a
1914 1914 $ hg ci -m2
1915 1915 created new head
1916 1916
1917 1917 Merge:
1918 1918
1919 1919 $ hg merge
1920 1920 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1921 1921 (branch merge, don't forget to commit)
1922 1922
1923 1923 Make sure there's a file listed in the merge to trigger the bug:
1924 1924
1925 1925 $ echo c > a
1926 1926 $ hg ci -m3
1927 1927
1928 1928 Two files shown here in diff:
1929 1929
1930 1930 $ hg diff --rev 2:3
1931 1931 diff -r b09be438c43a -r 8e07aafe1edc a
1932 1932 --- a/a Thu Jan 01 00:00:00 1970 +0000
1933 1933 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1934 1934 @@ -1,1 +1,1 @@
1935 1935 -b
1936 1936 +c
1937 1937 diff -r b09be438c43a -r 8e07aafe1edc b
1938 1938 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1939 1939 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1940 1940 @@ -0,0 +1,1 @@
1941 1941 +b
1942 1942
1943 1943 Diff here should be the same:
1944 1944
1945 1945 $ hg log -vpr 3
1946 1946 changeset: 3:8e07aafe1edc
1947 1947 tag: tip
1948 1948 parent: 2:b09be438c43a
1949 1949 parent: 1:925d80f479bb
1950 1950 user: test
1951 1951 date: Thu Jan 01 00:00:00 1970 +0000
1952 1952 files: a
1953 1953 description:
1954 1954 3
1955 1955
1956 1956
1957 1957 diff -r b09be438c43a -r 8e07aafe1edc a
1958 1958 --- a/a Thu Jan 01 00:00:00 1970 +0000
1959 1959 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1960 1960 @@ -1,1 +1,1 @@
1961 1961 -b
1962 1962 +c
1963 1963 diff -r b09be438c43a -r 8e07aafe1edc b
1964 1964 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1965 1965 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1966 1966 @@ -0,0 +1,1 @@
1967 1967 +b
1968 1968
1969
1970 Test that diff.merge is respected (file b was added on one side and
1971 and therefore merged cleanly)
1972
1973 $ hg log -pr 3 --config diff.merge=yes
1974 changeset: 3:8e07aafe1edc
1975 tag: tip
1976 parent: 2:b09be438c43a
1977 parent: 1:925d80f479bb
1978 user: test
1979 date: Thu Jan 01 00:00:00 1970 +0000
1980 summary: 3
1981
1982 diff -r 8e07aafe1edc a
1983 --- a/a Thu Jan 01 00:00:00 1970 +0000
1984 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1985 @@ -1,1 +1,1 @@
1986 -b
1987 +c
1988
1969 1989 $ cd ..
1970 1990
1971 1991 'hg log -r rev fn' when last(filelog(fn)) != rev
1972 1992
1973 1993 $ hg init simplelog
1974 1994 $ cd simplelog
1975 1995 $ echo f > a
1976 1996 $ hg ci -Am'a' -d '0 0'
1977 1997 adding a
1978 1998 $ echo f >> a
1979 1999 $ hg ci -Am'a bis' -d '1 0'
1980 2000
1981 2001 $ hg log -r0 a
1982 2002 changeset: 0:9f758d63dcde
1983 2003 user: test
1984 2004 date: Thu Jan 01 00:00:00 1970 +0000
1985 2005 summary: a
1986 2006
1987 2007 enable obsolete to test hidden feature
1988 2008
1989 2009 $ cat >> $HGRCPATH << EOF
1990 2010 > [experimental]
1991 2011 > evolution.createmarkers=True
1992 2012 > EOF
1993 2013
1994 2014 $ hg log --template='{rev}:{node}\n'
1995 2015 1:a765632148dc55d38c35c4f247c618701886cb2f
1996 2016 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1997 2017 $ hg debugobsolete a765632148dc55d38c35c4f247c618701886cb2f
1998 2018 1 new obsolescence markers
1999 2019 obsoleted 1 changesets
2000 2020 $ hg up null -q
2001 2021 $ hg log --template='{rev}:{node}\n'
2002 2022 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
2003 2023 $ hg log --template='{rev}:{node}\n' --hidden
2004 2024 1:a765632148dc55d38c35c4f247c618701886cb2f
2005 2025 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
2006 2026 $ hg log -r a
2007 2027 abort: hidden revision 'a' is pruned
2008 2028 (use --hidden to access hidden revisions)
2009 2029 [255]
2010 2030
2011 2031 test that parent prevent a changeset to be hidden
2012 2032
2013 2033 $ hg up 1 -q --hidden
2014 2034 updated to hidden changeset a765632148dc
2015 2035 (hidden revision 'a765632148dc' is pruned)
2016 2036 $ hg log --template='{rev}:{node}\n'
2017 2037 1:a765632148dc55d38c35c4f247c618701886cb2f
2018 2038 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
2019 2039
2020 2040 test that second parent prevent a changeset to be hidden too
2021 2041
2022 2042 $ hg debugsetparents 0 1 # nothing suitable to merge here
2023 2043 $ hg log --template='{rev}:{node}\n'
2024 2044 1:a765632148dc55d38c35c4f247c618701886cb2f
2025 2045 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
2026 2046 $ hg debugsetparents 1
2027 2047 $ hg up -q null
2028 2048
2029 2049 bookmarks prevent a changeset being hidden
2030 2050
2031 2051 $ hg bookmark --hidden -r 1 X
2032 2052 bookmarking hidden changeset a765632148dc
2033 2053 (hidden revision 'a765632148dc' is pruned)
2034 2054 $ hg log --template '{rev}:{node}\n'
2035 2055 1:a765632148dc55d38c35c4f247c618701886cb2f
2036 2056 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
2037 2057 $ hg bookmark -d X
2038 2058
2039 2059 divergent bookmarks are not hidden
2040 2060
2041 2061 $ hg bookmark --hidden -r 1 X@foo
2042 2062 bookmarking hidden changeset a765632148dc
2043 2063 (hidden revision 'a765632148dc' is pruned)
2044 2064 $ hg log --template '{rev}:{node}\n'
2045 2065 1:a765632148dc55d38c35c4f247c618701886cb2f
2046 2066 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
2047 2067
2048 2068 test hidden revision 0 (issue5385)
2049 2069
2050 2070 $ hg bookmark -d X@foo
2051 2071 $ hg up null -q
2052 2072 $ hg debugobsolete 9f758d63dcde62d547ebfb08e1e7ee96535f2b05
2053 2073 1 new obsolescence markers
2054 2074 obsoleted 1 changesets
2055 2075 $ echo f > b
2056 2076 $ hg ci -Am'b' -d '2 0'
2057 2077 adding b
2058 2078 $ echo f >> b
2059 2079 $ hg ci -m'b bis' -d '3 0'
2060 2080 $ hg log -T'{rev}:{node}\n'
2061 2081 3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e
2062 2082 2:94375ec45bddd2a824535fc04855bd058c926ec0
2063 2083
2064 2084 $ hg log -T'{rev}:{node}\n' -r:
2065 2085 2:94375ec45bddd2a824535fc04855bd058c926ec0
2066 2086 3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e
2067 2087 $ hg log -T'{rev}:{node}\n' -r:tip
2068 2088 2:94375ec45bddd2a824535fc04855bd058c926ec0
2069 2089 3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e
2070 2090 $ hg log -T'{rev}:{node}\n' -r:0
2071 2091 abort: hidden revision '0' is pruned
2072 2092 (use --hidden to access hidden revisions)
2073 2093 [255]
2074 2094 $ hg log -T'{rev}:{node}\n' -f
2075 2095 3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e
2076 2096 2:94375ec45bddd2a824535fc04855bd058c926ec0
2077 2097
2078 2098 clear extensions configuration
2079 2099 $ echo '[extensions]' >> $HGRCPATH
2080 2100 $ echo "obs=!" >> $HGRCPATH
2081 2101 $ cd ..
2082 2102
2083 2103 test -u/-k for problematic encoding
2084 2104 # unicode: cp932:
2085 2105 # u30A2 0x83 0x41(= 'A')
2086 2106 # u30C2 0x83 0x61(= 'a')
2087 2107
2088 2108 $ hg init problematicencoding
2089 2109 $ cd problematicencoding
2090 2110
2091 2111 >>> with open('setup.sh', 'wb') as f:
2092 2112 ... f.write(u'''
2093 2113 ... echo a > text
2094 2114 ... hg add text
2095 2115 ... hg --encoding utf-8 commit -u '\u30A2' -m none
2096 2116 ... echo b > text
2097 2117 ... hg --encoding utf-8 commit -u '\u30C2' -m none
2098 2118 ... echo c > text
2099 2119 ... hg --encoding utf-8 commit -u none -m '\u30A2'
2100 2120 ... echo d > text
2101 2121 ... hg --encoding utf-8 commit -u none -m '\u30C2'
2102 2122 ... '''.encode('utf-8')) and None
2103 2123 $ sh < setup.sh
2104 2124
2105 2125 test in problematic encoding
2106 2126 >>> with open('test.sh', 'wb') as f:
2107 2127 ... f.write(u'''
2108 2128 ... hg --encoding cp932 log --template '{rev}\\n' -u '\u30A2'
2109 2129 ... echo ====
2110 2130 ... hg --encoding cp932 log --template '{rev}\\n' -u '\u30C2'
2111 2131 ... echo ====
2112 2132 ... hg --encoding cp932 log --template '{rev}\\n' -k '\u30A2'
2113 2133 ... echo ====
2114 2134 ... hg --encoding cp932 log --template '{rev}\\n' -k '\u30C2'
2115 2135 ... '''.encode('cp932')) and None
2116 2136 $ sh < test.sh
2117 2137 0
2118 2138 ====
2119 2139 1
2120 2140 ====
2121 2141 2
2122 2142 0
2123 2143 ====
2124 2144 3
2125 2145 1
2126 2146
2127 2147 $ cd ..
2128 2148
2129 2149 test hg log on non-existent files and on directories
2130 2150 $ hg init issue1340
2131 2151 $ cd issue1340
2132 2152 $ mkdir d1; mkdir D2; mkdir D3.i; mkdir d4.hg; mkdir d5.d; mkdir .d6
2133 2153 $ echo 1 > d1/f1
2134 2154 $ echo 1 > D2/f1
2135 2155 $ echo 1 > D3.i/f1
2136 2156 $ echo 1 > d4.hg/f1
2137 2157 $ echo 1 > d5.d/f1
2138 2158 $ echo 1 > .d6/f1
2139 2159 $ hg -q add .
2140 2160 $ hg commit -m "a bunch of weird directories"
2141 2161 $ hg log -l1 d1/f1 | grep changeset
2142 2162 changeset: 0:65624cd9070a
2143 2163 $ hg log -l1 f1
2144 2164 $ hg log -l1 . | grep changeset
2145 2165 changeset: 0:65624cd9070a
2146 2166 $ hg log -l1 ./ | grep changeset
2147 2167 changeset: 0:65624cd9070a
2148 2168 $ hg log -l1 d1 | grep changeset
2149 2169 changeset: 0:65624cd9070a
2150 2170 $ hg log -l1 D2 | grep changeset
2151 2171 changeset: 0:65624cd9070a
2152 2172 $ hg log -l1 D2/f1 | grep changeset
2153 2173 changeset: 0:65624cd9070a
2154 2174 $ hg log -l1 D3.i | grep changeset
2155 2175 changeset: 0:65624cd9070a
2156 2176 $ hg log -l1 D3.i/f1 | grep changeset
2157 2177 changeset: 0:65624cd9070a
2158 2178 $ hg log -l1 d4.hg | grep changeset
2159 2179 changeset: 0:65624cd9070a
2160 2180 $ hg log -l1 d4.hg/f1 | grep changeset
2161 2181 changeset: 0:65624cd9070a
2162 2182 $ hg log -l1 d5.d | grep changeset
2163 2183 changeset: 0:65624cd9070a
2164 2184 $ hg log -l1 d5.d/f1 | grep changeset
2165 2185 changeset: 0:65624cd9070a
2166 2186 $ hg log -l1 .d6 | grep changeset
2167 2187 changeset: 0:65624cd9070a
2168 2188 $ hg log -l1 .d6/f1 | grep changeset
2169 2189 changeset: 0:65624cd9070a
2170 2190
2171 2191 issue3772: hg log -r :null showing revision 0 as well
2172 2192
2173 2193 $ hg log -r :null
2174 2194 changeset: 0:65624cd9070a
2175 2195 tag: tip
2176 2196 user: test
2177 2197 date: Thu Jan 01 00:00:00 1970 +0000
2178 2198 summary: a bunch of weird directories
2179 2199
2180 2200 changeset: -1:000000000000
2181 2201 user:
2182 2202 date: Thu Jan 01 00:00:00 1970 +0000
2183 2203
2184 2204 $ hg log -r null:null
2185 2205 changeset: -1:000000000000
2186 2206 user:
2187 2207 date: Thu Jan 01 00:00:00 1970 +0000
2188 2208
2189 2209 working-directory revision requires special treatment
2190 2210
2191 2211 clean:
2192 2212
2193 2213 $ hg log -r 'wdir()' --debug
2194 2214 changeset: 2147483647:ffffffffffffffffffffffffffffffffffffffff
2195 2215 phase: draft
2196 2216 parent: 0:65624cd9070a035fa7191a54f2b8af39f16b0c08
2197 2217 parent: -1:0000000000000000000000000000000000000000
2198 2218 manifest: 2147483647:ffffffffffffffffffffffffffffffffffffffff
2199 2219 user: test
2200 2220 date: [A-Za-z0-9:+ ]+ (re)
2201 2221 extra: branch=default
2202 2222
2203 2223 $ hg log -r 'wdir()' -p --stat
2204 2224 changeset: 2147483647:ffffffffffff
2205 2225 parent: 0:65624cd9070a
2206 2226 user: test
2207 2227 date: [A-Za-z0-9:+ ]+ (re)
2208 2228
2209 2229
2210 2230
2211 2231
2212 2232 dirty:
2213 2233
2214 2234 $ echo 2 >> d1/f1
2215 2235 $ echo 2 > d1/f2
2216 2236 $ hg add d1/f2
2217 2237 $ hg remove .d6/f1
2218 2238 $ hg status
2219 2239 M d1/f1
2220 2240 A d1/f2
2221 2241 R .d6/f1
2222 2242
2223 2243 $ hg log -r 'wdir()'
2224 2244 changeset: 2147483647:ffffffffffff
2225 2245 parent: 0:65624cd9070a
2226 2246 user: test
2227 2247 date: [A-Za-z0-9:+ ]+ (re)
2228 2248
2229 2249 $ hg log -r 'wdir()' -q
2230 2250 2147483647:ffffffffffff
2231 2251
2232 2252 $ hg log -r 'wdir()' --debug
2233 2253 changeset: 2147483647:ffffffffffffffffffffffffffffffffffffffff
2234 2254 phase: draft
2235 2255 parent: 0:65624cd9070a035fa7191a54f2b8af39f16b0c08
2236 2256 parent: -1:0000000000000000000000000000000000000000
2237 2257 manifest: 2147483647:ffffffffffffffffffffffffffffffffffffffff
2238 2258 user: test
2239 2259 date: [A-Za-z0-9:+ ]+ (re)
2240 2260 files: d1/f1
2241 2261 files+: d1/f2
2242 2262 files-: .d6/f1
2243 2263 extra: branch=default
2244 2264
2245 2265 $ hg log -r 'wdir()' -p --stat --git
2246 2266 changeset: 2147483647:ffffffffffff
2247 2267 parent: 0:65624cd9070a
2248 2268 user: test
2249 2269 date: [A-Za-z0-9:+ ]+ (re)
2250 2270
2251 2271 .d6/f1 | 1 -
2252 2272 d1/f1 | 1 +
2253 2273 d1/f2 | 1 +
2254 2274 3 files changed, 2 insertions(+), 1 deletions(-)
2255 2275
2256 2276 diff --git a/.d6/f1 b/.d6/f1
2257 2277 deleted file mode 100644
2258 2278 --- a/.d6/f1
2259 2279 +++ /dev/null
2260 2280 @@ -1,1 +0,0 @@
2261 2281 -1
2262 2282 diff --git a/d1/f1 b/d1/f1
2263 2283 --- a/d1/f1
2264 2284 +++ b/d1/f1
2265 2285 @@ -1,1 +1,2 @@
2266 2286 1
2267 2287 +2
2268 2288 diff --git a/d1/f2 b/d1/f2
2269 2289 new file mode 100644
2270 2290 --- /dev/null
2271 2291 +++ b/d1/f2
2272 2292 @@ -0,0 +1,1 @@
2273 2293 +2
2274 2294
2275 2295 $ hg log -r 'wdir()' -Tjson
2276 2296 [
2277 2297 {
2278 2298 "bookmarks": [],
2279 2299 "branch": "default",
2280 2300 "date": [*, 0], (glob)
2281 2301 "desc": "",
2282 2302 "node": "ffffffffffffffffffffffffffffffffffffffff",
2283 2303 "parents": ["65624cd9070a035fa7191a54f2b8af39f16b0c08"],
2284 2304 "phase": "draft",
2285 2305 "rev": 2147483647,
2286 2306 "tags": [],
2287 2307 "user": "test"
2288 2308 }
2289 2309 ]
2290 2310
2291 2311 $ hg log -r 'wdir()' -Tjson -q
2292 2312 [
2293 2313 {
2294 2314 "node": "ffffffffffffffffffffffffffffffffffffffff",
2295 2315 "rev": 2147483647
2296 2316 }
2297 2317 ]
2298 2318
2299 2319 $ hg log -r 'wdir()' -Tjson --debug
2300 2320 [
2301 2321 {
2302 2322 "added": ["d1/f2"],
2303 2323 "bookmarks": [],
2304 2324 "branch": "default",
2305 2325 "date": [*, 0], (glob)
2306 2326 "desc": "",
2307 2327 "extra": {"branch": "default"},
2308 2328 "manifest": "ffffffffffffffffffffffffffffffffffffffff",
2309 2329 "modified": ["d1/f1"],
2310 2330 "node": "ffffffffffffffffffffffffffffffffffffffff",
2311 2331 "parents": ["65624cd9070a035fa7191a54f2b8af39f16b0c08"],
2312 2332 "phase": "draft",
2313 2333 "removed": [".d6/f1"],
2314 2334 "rev": 2147483647,
2315 2335 "tags": [],
2316 2336 "user": "test"
2317 2337 }
2318 2338 ]
2319 2339
2320 2340 follow files from wdir
2321 2341
2322 2342 $ hg cp d1/f1 f1-copy
2323 2343 $ hg stat --all
2324 2344 M d1/f1
2325 2345 A d1/f2
2326 2346 A f1-copy
2327 2347 d1/f1
2328 2348 R .d6/f1
2329 2349 C D2/f1
2330 2350 C D3.i/f1
2331 2351 C d4.hg/f1
2332 2352 C d5.d/f1
2333 2353
2334 2354 $ hg log -T '== {rev} ==\n' -fr'wdir()' --git --stat d5.d/f1
2335 2355 == 2147483647 ==
2336 2356
2337 2357 == 0 ==
2338 2358 d5.d/f1 | 1 +
2339 2359 1 files changed, 1 insertions(+), 0 deletions(-)
2340 2360
2341 2361
2342 2362 $ hg log -T '== {rev} ==\n' -fr'wdir()' --git --stat d1/f1
2343 2363 == 2147483647 ==
2344 2364 d1/f1 | 1 +
2345 2365 1 files changed, 1 insertions(+), 0 deletions(-)
2346 2366
2347 2367 == 0 ==
2348 2368 d1/f1 | 1 +
2349 2369 1 files changed, 1 insertions(+), 0 deletions(-)
2350 2370
2351 2371
2352 2372 $ hg log -T '== {rev} ==\n' -fr'wdir()' --git --stat d1/f2
2353 2373 == 2147483647 ==
2354 2374 d1/f2 | 1 +
2355 2375 1 files changed, 1 insertions(+), 0 deletions(-)
2356 2376
2357 2377
2358 2378 $ hg log -T '== {rev} ==\n' -fr'wdir()' --git --stat f1-copy
2359 2379 == 2147483647 ==
2360 2380 f1-copy | 1 +
2361 2381 1 files changed, 1 insertions(+), 0 deletions(-)
2362 2382
2363 2383 == 0 ==
2364 2384 d1/f1 | 1 +
2365 2385 1 files changed, 1 insertions(+), 0 deletions(-)
2366 2386
2367 2387
2368 2388 $ hg log -T '== {rev} ==\n' -fr'wdir()' --git --stat notfound
2369 2389 abort: cannot follow file not in any of the specified revisions: "notfound"
2370 2390 [255]
2371 2391
2372 2392 follow files from wdir and non-wdir revision:
2373 2393
2374 2394 $ hg log -T '{rev}\n' -fr'wdir()+.' f1-copy
2375 2395 f1-copy: no such file in rev 65624cd9070a
2376 2396 2147483647
2377 2397 0
2378 2398
2379 2399 follow added/removed files from wdir parent
2380 2400
2381 2401 $ hg log -T '{rev}\n' -f d1/f2
2382 2402 abort: cannot follow nonexistent file: "d1/f2"
2383 2403 [255]
2384 2404
2385 2405 $ hg log -T '{rev}\n' -f f1-copy
2386 2406 abort: cannot follow nonexistent file: "f1-copy"
2387 2407 [255]
2388 2408
2389 2409 $ hg log -T '{rev}\n' -f .d6/f1
2390 2410 abort: cannot follow file not in parent revision: ".d6/f1"
2391 2411 [255]
2392 2412
2393 2413 $ hg revert -aqC
2394 2414
2395 2415 Check that adding an arbitrary name shows up in log automatically
2396 2416
2397 2417 $ cat > ../names.py <<EOF
2398 2418 > """A small extension to test adding arbitrary names to a repo"""
2399 2419 > from __future__ import absolute_import
2400 2420 > from mercurial import namespaces
2401 2421 >
2402 2422 > def reposetup(ui, repo):
2403 2423 > if not repo.local():
2404 2424 > return
2405 2425 > foo = {b'foo': repo[0].node()}
2406 2426 > names = lambda r: foo.keys()
2407 2427 > namemap = lambda r, name: foo.get(name)
2408 2428 > nodemap = lambda r, node: [name for name, n in foo.items()
2409 2429 > if n == node]
2410 2430 > ns = namespaces.namespace(
2411 2431 > b"bars", templatename=b"bar", logname=b"barlog",
2412 2432 > colorname=b"barcolor", listnames=names, namemap=namemap,
2413 2433 > nodemap=nodemap)
2414 2434 >
2415 2435 > repo.names.addnamespace(ns)
2416 2436 > EOF
2417 2437
2418 2438 $ hg --config extensions.names=../names.py log -r 0
2419 2439 changeset: 0:65624cd9070a
2420 2440 tag: tip
2421 2441 barlog: foo
2422 2442 user: test
2423 2443 date: Thu Jan 01 00:00:00 1970 +0000
2424 2444 summary: a bunch of weird directories
2425 2445
2426 2446 $ hg --config extensions.names=../names.py \
2427 2447 > --config extensions.color= --config color.log.barcolor=red \
2428 2448 > --color=always log -r 0
2429 2449 \x1b[0;33mchangeset: 0:65624cd9070a\x1b[0m (esc)
2430 2450 tag: tip
2431 2451 \x1b[0;31mbarlog: foo\x1b[0m (esc)
2432 2452 user: test
2433 2453 date: Thu Jan 01 00:00:00 1970 +0000
2434 2454 summary: a bunch of weird directories
2435 2455
2436 2456 $ hg --config extensions.names=../names.py log -r 0 --template '{bars}\n'
2437 2457 foo
2438 2458
2439 2459 Templater parse errors:
2440 2460
2441 2461 simple error
2442 2462 $ hg log -r . -T '{shortest(node}'
2443 2463 hg: parse error at 14: unexpected token: end
2444 2464 ({shortest(node}
2445 2465 ^ here)
2446 2466 [10]
2447 2467
2448 2468 multi-line template with error
2449 2469 $ hg log -r . -T 'line 1
2450 2470 > line2
2451 2471 > {shortest(node}
2452 2472 > line4\nline5'
2453 2473 hg: parse error at 27: unexpected token: end
2454 2474 (line 1\nline2\n{shortest(node}\nline4\nline5
2455 2475 ^ here)
2456 2476 [10]
2457 2477
2458 2478 $ cd ..
2459 2479
2460 2480 New namespace is registered per repo instance, but the template keyword
2461 2481 is global. So we shouldn't expect the namespace always exists. Using
2462 2482 ssh:// makes sure a bundle repository is created from scratch. (issue6301)
2463 2483
2464 2484 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" \
2465 2485 > -qr0 "ssh://user@dummy/`pwd`/a" a-clone
2466 2486 $ hg incoming --config extensions.names=names.py -R a-clone \
2467 2487 > -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" -T '{bars}\n' -l1
2468 2488 comparing with ssh://user@dummy/$TESTTMP/a
2469 2489 searching for changes
2470 2490
2471 2491
2472 2492 hg log -f dir across branches
2473 2493
2474 2494 $ hg init acrossbranches
2475 2495 $ cd acrossbranches
2476 2496 $ mkdir d
2477 2497 $ echo a > d/a && hg ci -Aqm a
2478 2498 $ echo b > d/a && hg ci -Aqm b
2479 2499 $ hg up -q 0
2480 2500 $ echo b > d/a && hg ci -Aqm c
2481 2501 $ hg log -f d -T '{desc}' -G
2482 2502 @ c
2483 2503 |
2484 2504 o a
2485 2505
2486 2506 Ensure that largefiles doesn't interfere with following a normal file
2487 2507 $ hg --config extensions.largefiles= log -f d -T '{desc}' -G
2488 2508 The fsmonitor extension is incompatible with the largefiles extension and has been disabled. (fsmonitor !)
2489 2509 @ c
2490 2510 |
2491 2511 o a
2492 2512
2493 2513 $ hg log -f d/a -T '{desc}' -G
2494 2514 @ c
2495 2515 |
2496 2516 o a
2497 2517
2498 2518 $ cd ..
2499 2519
2500 2520 hg log -f with linkrev pointing to another branch
2501 2521 -------------------------------------------------
2502 2522
2503 2523 create history with a filerev whose linkrev points to another branch
2504 2524
2505 2525 $ hg init branchedlinkrev
2506 2526 $ cd branchedlinkrev
2507 2527 $ echo 1 > a
2508 2528 $ hg commit -Am 'content1'
2509 2529 adding a
2510 2530 $ echo 2 > a
2511 2531 $ hg commit -m 'content2'
2512 2532 $ hg up --rev 'desc(content1)'
2513 2533 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
2514 2534 $ echo unrelated > unrelated
2515 2535 $ hg commit -Am 'unrelated'
2516 2536 adding unrelated
2517 2537 created new head
2518 2538 $ hg graft -r 'desc(content2)'
2519 2539 grafting 1:2294ae80ad84 "content2"
2520 2540 $ echo 3 > a
2521 2541 $ hg commit -m 'content3'
2522 2542 $ hg log -G
2523 2543 @ changeset: 4:50b9b36e9c5d
2524 2544 | tag: tip
2525 2545 | user: test
2526 2546 | date: Thu Jan 01 00:00:00 1970 +0000
2527 2547 | summary: content3
2528 2548 |
2529 2549 o changeset: 3:15b2327059e5
2530 2550 | user: test
2531 2551 | date: Thu Jan 01 00:00:00 1970 +0000
2532 2552 | summary: content2
2533 2553 |
2534 2554 o changeset: 2:2029acd1168c
2535 2555 | parent: 0:ae0a3c9f9e95
2536 2556 | user: test
2537 2557 | date: Thu Jan 01 00:00:00 1970 +0000
2538 2558 | summary: unrelated
2539 2559 |
2540 2560 | o changeset: 1:2294ae80ad84
2541 2561 |/ user: test
2542 2562 | date: Thu Jan 01 00:00:00 1970 +0000
2543 2563 | summary: content2
2544 2564 |
2545 2565 o changeset: 0:ae0a3c9f9e95
2546 2566 user: test
2547 2567 date: Thu Jan 01 00:00:00 1970 +0000
2548 2568 summary: content1
2549 2569
2550 2570
2551 2571 log -f on the file should list the graft result.
2552 2572
2553 2573 $ hg log -Gf a
2554 2574 @ changeset: 4:50b9b36e9c5d
2555 2575 | tag: tip
2556 2576 | user: test
2557 2577 | date: Thu Jan 01 00:00:00 1970 +0000
2558 2578 | summary: content3
2559 2579 |
2560 2580 o changeset: 3:15b2327059e5
2561 2581 : user: test
2562 2582 : date: Thu Jan 01 00:00:00 1970 +0000
2563 2583 : summary: content2
2564 2584 :
2565 2585 o changeset: 0:ae0a3c9f9e95
2566 2586 user: test
2567 2587 date: Thu Jan 01 00:00:00 1970 +0000
2568 2588 summary: content1
2569 2589
2570 2590
2571 2591 plain log lists the original version
2572 2592 (XXX we should probably list both)
2573 2593
2574 2594 $ hg log -G a
2575 2595 @ changeset: 4:50b9b36e9c5d
2576 2596 : tag: tip
2577 2597 : user: test
2578 2598 : date: Thu Jan 01 00:00:00 1970 +0000
2579 2599 : summary: content3
2580 2600 :
2581 2601 : o changeset: 1:2294ae80ad84
2582 2602 :/ user: test
2583 2603 : date: Thu Jan 01 00:00:00 1970 +0000
2584 2604 : summary: content2
2585 2605 :
2586 2606 o changeset: 0:ae0a3c9f9e95
2587 2607 user: test
2588 2608 date: Thu Jan 01 00:00:00 1970 +0000
2589 2609 summary: content1
2590 2610
2591 2611
2592 2612 hg log -f from the grafted changeset
2593 2613 (The bootstrap should properly take the topology in account)
2594 2614
2595 2615 $ hg up 'desc(content3)^'
2596 2616 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
2597 2617 $ hg log -Gf a
2598 2618 @ changeset: 3:15b2327059e5
2599 2619 : user: test
2600 2620 : date: Thu Jan 01 00:00:00 1970 +0000
2601 2621 : summary: content2
2602 2622 :
2603 2623 o changeset: 0:ae0a3c9f9e95
2604 2624 user: test
2605 2625 date: Thu Jan 01 00:00:00 1970 +0000
2606 2626 summary: content1
2607 2627
2608 2628
2609 2629 Test that we use the first non-hidden changeset in that case.
2610 2630
2611 2631 (hide the changeset)
2612 2632
2613 2633 $ hg log -T '{node}\n' -r 1
2614 2634 2294ae80ad8447bc78383182eeac50cb049df623
2615 2635 $ hg debugobsolete 2294ae80ad8447bc78383182eeac50cb049df623
2616 2636 1 new obsolescence markers
2617 2637 obsoleted 1 changesets
2618 2638 $ hg log -G
2619 2639 o changeset: 4:50b9b36e9c5d
2620 2640 | tag: tip
2621 2641 | user: test
2622 2642 | date: Thu Jan 01 00:00:00 1970 +0000
2623 2643 | summary: content3
2624 2644 |
2625 2645 @ changeset: 3:15b2327059e5
2626 2646 | user: test
2627 2647 | date: Thu Jan 01 00:00:00 1970 +0000
2628 2648 | summary: content2
2629 2649 |
2630 2650 o changeset: 2:2029acd1168c
2631 2651 | parent: 0:ae0a3c9f9e95
2632 2652 | user: test
2633 2653 | date: Thu Jan 01 00:00:00 1970 +0000
2634 2654 | summary: unrelated
2635 2655 |
2636 2656 o changeset: 0:ae0a3c9f9e95
2637 2657 user: test
2638 2658 date: Thu Jan 01 00:00:00 1970 +0000
2639 2659 summary: content1
2640 2660
2641 2661
2642 2662 Check that log on the file does not drop the file revision.
2643 2663
2644 2664 $ hg log -G a
2645 2665 o changeset: 4:50b9b36e9c5d
2646 2666 | tag: tip
2647 2667 | user: test
2648 2668 | date: Thu Jan 01 00:00:00 1970 +0000
2649 2669 | summary: content3
2650 2670 |
2651 2671 @ changeset: 3:15b2327059e5
2652 2672 : user: test
2653 2673 : date: Thu Jan 01 00:00:00 1970 +0000
2654 2674 : summary: content2
2655 2675 :
2656 2676 o changeset: 0:ae0a3c9f9e95
2657 2677 user: test
2658 2678 date: Thu Jan 01 00:00:00 1970 +0000
2659 2679 summary: content1
2660 2680
2661 2681
2662 2682 Even when a head revision is linkrev-shadowed.
2663 2683
2664 2684 $ hg log -T '{node}\n' -r 4
2665 2685 50b9b36e9c5df2c6fc6dcefa8ad0da929e84aed2
2666 2686 $ hg debugobsolete 50b9b36e9c5df2c6fc6dcefa8ad0da929e84aed2
2667 2687 1 new obsolescence markers
2668 2688 obsoleted 1 changesets
2669 2689 $ hg log -G a
2670 2690 @ changeset: 3:15b2327059e5
2671 2691 : tag: tip
2672 2692 : user: test
2673 2693 : date: Thu Jan 01 00:00:00 1970 +0000
2674 2694 : summary: content2
2675 2695 :
2676 2696 o changeset: 0:ae0a3c9f9e95
2677 2697 user: test
2678 2698 date: Thu Jan 01 00:00:00 1970 +0000
2679 2699 summary: content1
2680 2700
2681 2701
2682 2702 $ cd ..
2683 2703
2684 2704 Even when the file revision is missing from some head:
2685 2705
2686 2706 $ hg init issue4490
2687 2707 $ cd issue4490
2688 2708 $ echo '[experimental]' >> .hg/hgrc
2689 2709 $ echo 'evolution.createmarkers=True' >> .hg/hgrc
2690 2710 $ echo a > a
2691 2711 $ hg ci -Am0
2692 2712 adding a
2693 2713 $ echo b > b
2694 2714 $ hg ci -Am1
2695 2715 adding b
2696 2716 $ echo B > b
2697 2717 $ hg ci --amend -m 1
2698 2718 $ hg up 0
2699 2719 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
2700 2720 $ echo c > c
2701 2721 $ hg ci -Am2
2702 2722 adding c
2703 2723 created new head
2704 2724 $ hg up 'head() and not .'
2705 2725 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
2706 2726 $ hg log -G
2707 2727 o changeset: 3:db815d6d32e6
2708 2728 | tag: tip
2709 2729 | parent: 0:f7b1eb17ad24
2710 2730 | user: test
2711 2731 | date: Thu Jan 01 00:00:00 1970 +0000
2712 2732 | summary: 2
2713 2733 |
2714 2734 | @ changeset: 2:9bc8ce7f9356
2715 2735 |/ parent: 0:f7b1eb17ad24
2716 2736 | user: test
2717 2737 | date: Thu Jan 01 00:00:00 1970 +0000
2718 2738 | summary: 1
2719 2739 |
2720 2740 o changeset: 0:f7b1eb17ad24
2721 2741 user: test
2722 2742 date: Thu Jan 01 00:00:00 1970 +0000
2723 2743 summary: 0
2724 2744
2725 2745 $ hg log -f -G b
2726 2746 @ changeset: 2:9bc8ce7f9356
2727 2747 | parent: 0:f7b1eb17ad24
2728 2748 ~ user: test
2729 2749 date: Thu Jan 01 00:00:00 1970 +0000
2730 2750 summary: 1
2731 2751
2732 2752 $ hg log -G b
2733 2753 @ changeset: 2:9bc8ce7f9356
2734 2754 | parent: 0:f7b1eb17ad24
2735 2755 ~ user: test
2736 2756 date: Thu Jan 01 00:00:00 1970 +0000
2737 2757 summary: 1
2738 2758
2739 2759 $ cd ..
2740 2760
2741 2761 Check proper report when the manifest changes but not the file issue4499
2742 2762 ------------------------------------------------------------------------
2743 2763
2744 2764 $ hg init issue4499
2745 2765 $ cd issue4499
2746 2766 $ 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
2747 2767 > echo 1 > $f;
2748 2768 > hg add $f;
2749 2769 > done
2750 2770 $ hg commit -m 'A1B1C1'
2751 2771 $ echo 2 > A
2752 2772 $ echo 2 > B
2753 2773 $ echo 2 > C
2754 2774 $ hg commit -m 'A2B2C2'
2755 2775 $ hg up 0
2756 2776 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
2757 2777 $ echo 3 > A
2758 2778 $ echo 2 > B
2759 2779 $ echo 2 > C
2760 2780 $ hg commit -m 'A3B2C2'
2761 2781 created new head
2762 2782
2763 2783 $ hg log -G
2764 2784 @ changeset: 2:fe5fc3d0eb17
2765 2785 | tag: tip
2766 2786 | parent: 0:abf4f0e38563
2767 2787 | user: test
2768 2788 | date: Thu Jan 01 00:00:00 1970 +0000
2769 2789 | summary: A3B2C2
2770 2790 |
2771 2791 | o changeset: 1:07dcc6b312c0
2772 2792 |/ user: test
2773 2793 | date: Thu Jan 01 00:00:00 1970 +0000
2774 2794 | summary: A2B2C2
2775 2795 |
2776 2796 o changeset: 0:abf4f0e38563
2777 2797 user: test
2778 2798 date: Thu Jan 01 00:00:00 1970 +0000
2779 2799 summary: A1B1C1
2780 2800
2781 2801
2782 2802 Log -f on B should reports current changesets
2783 2803
2784 2804 $ hg log -fG B
2785 2805 @ changeset: 2:fe5fc3d0eb17
2786 2806 | tag: tip
2787 2807 | parent: 0:abf4f0e38563
2788 2808 | user: test
2789 2809 | date: Thu Jan 01 00:00:00 1970 +0000
2790 2810 | summary: A3B2C2
2791 2811 |
2792 2812 o changeset: 0:abf4f0e38563
2793 2813 user: test
2794 2814 date: Thu Jan 01 00:00:00 1970 +0000
2795 2815 summary: A1B1C1
2796 2816
2797 2817 $ cd ..
2798 2818
2799 2819 --- going to test line wrap fix on using both --stat and -G (issue5800)
2800 2820 $ hg init issue5800
2801 2821 $ cd issue5800
2802 2822 $ touch a
2803 2823 $ hg ci -Am 'add a'
2804 2824 adding a
2805 2825 ---- now we are going to add 300 lines to a
2806 2826 $ for i in `$TESTDIR/seq.py 1 300`; do echo $i >> a; done
2807 2827 $ hg ci -m 'modify a'
2808 2828 $ hg log
2809 2829 changeset: 1:a98683e6a834
2810 2830 tag: tip
2811 2831 user: test
2812 2832 date: Thu Jan 01 00:00:00 1970 +0000
2813 2833 summary: modify a
2814 2834
2815 2835 changeset: 0:ac82d8b1f7c4
2816 2836 user: test
2817 2837 date: Thu Jan 01 00:00:00 1970 +0000
2818 2838 summary: add a
2819 2839
2820 2840 ---- now visualise the changes we made without template
2821 2841 $ hg log -l1 -r a98683e6a834 --stat -G
2822 2842 @ changeset: 1:a98683e6a834
2823 2843 | tag: tip
2824 2844 ~ user: test
2825 2845 date: Thu Jan 01 00:00:00 1970 +0000
2826 2846 summary: modify a
2827 2847
2828 2848 a | 300 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2829 2849 1 files changed, 300 insertions(+), 0 deletions(-)
2830 2850
2831 2851 ---- with template
2832 2852 $ hg log -l1 -r a98683e6a834 --stat -G -T bisect
2833 2853 @ changeset: 1:a98683e6a834
2834 2854 | bisect:
2835 2855 ~ tag: tip
2836 2856 user: test
2837 2857 date: Thu Jan 01 00:00:00 1970 +0000
2838 2858 summary: modify a
2839 2859
2840 2860 a | 300 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2841 2861 1 files changed, 300 insertions(+), 0 deletions(-)
2842 2862
2843 2863 $ hg log -l1 -r a98683e6a834 --stat -G -T changelog
2844 2864 1970-01-01 test <test>
2845 2865
2846 2866 @ * a:
2847 2867 | modify a
2848 2868 ~ [a98683e6a834] [tip]
2849 2869
2850 2870 a | 300 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2851 2871 1 files changed, 300 insertions(+), 0 deletions(-)
2852 2872
2853 2873 $ hg log -l1 -r a98683e6a834 --stat -G -T compact
2854 2874 @ 1[tip] a98683e6a834 1970-01-01 00:00 +0000 test
2855 2875 | modify a
2856 2876 ~
2857 2877 a | 300 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2858 2878 1 files changed, 300 insertions(+), 0 deletions(-)
2859 2879
2860 2880 $ hg log -l1 -r a98683e6a834 --stat -G -T default
2861 2881 @ changeset: 1:a98683e6a834
2862 2882 | tag: tip
2863 2883 ~ user: test
2864 2884 date: Thu Jan 01 00:00:00 1970 +0000
2865 2885 summary: modify a
2866 2886
2867 2887 a | 300 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2868 2888 1 files changed, 300 insertions(+), 0 deletions(-)
2869 2889
2870 2890 $ hg log -l1 -r a98683e6a834 --stat -G -T phases
2871 2891 @ changeset: 1:a98683e6a834
2872 2892 | tag: tip
2873 2893 ~ phase: draft
2874 2894 user: test
2875 2895 date: Thu Jan 01 00:00:00 1970 +0000
2876 2896 summary: modify a
2877 2897
2878 2898 a | 300 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2879 2899 1 files changed, 300 insertions(+), 0 deletions(-)
2880 2900
2881 2901 $ hg log -l1 -r a98683e6a834 --stat -G -T show
2882 2902 @ changeset: 1:a98683e6a834
2883 2903 | tag: tip
2884 2904 ~ user: test
2885 2905 date: Thu Jan 01 00:00:00 1970 +0000
2886 2906 summary: modify a
2887 2907
2888 2908 a | 300 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2889 2909 1 files changed, 300 insertions(+), 0 deletions(-)
2890 2910
2891 2911 $ hg log -l1 -r a98683e6a834 --stat -G -T status
2892 2912 @ changeset: 1:a98683e6a834
2893 2913 | tag: tip
2894 2914 ~ user: test
2895 2915 date: Thu Jan 01 00:00:00 1970 +0000
2896 2916 summary: modify a
2897 2917 files:
2898 2918 M a
2899 2919
2900 2920 a | 300 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2901 2921 1 files changed, 300 insertions(+), 0 deletions(-)
2902 2922
2903 2923 $ hg log -l1 -r a98683e6a834 --stat -G -T xml
2904 2924 <?xml version="1.0"?>
2905 2925 <log>
2906 2926 @ <logentry revision="1" node="a98683e6a8340830a7683909768b62871e84bc9d">
2907 2927 | <tag>tip</tag>
2908 2928 ~ <author email="test">test</author>
2909 2929 <date>1970-01-01T00:00:00+00:00</date>
2910 2930 <msg xml:space="preserve">modify a</msg>
2911 2931 </logentry>
2912 2932 a | 300 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2913 2933 1 files changed, 300 insertions(+), 0 deletions(-)
2914 2934
2915 2935 </log>
2916 2936
2917 2937 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now