##// END OF EJS Templates
changeset_printer: display wdirrev/wdirnode values for workingctx...
Yuya Nishihara -
r25762:f4412380 default
parent child Browse files
Show More
@@ -1,3337 +1,3335 b''
1 1 # cmdutil.py - help for command processing in mercurial
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 from node import hex, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 9 from i18n import _
10 10 import os, sys, errno, re, tempfile, cStringIO, shutil
11 11 import util, scmutil, templater, patch, error, templatekw, revlog, copies
12 12 import match as matchmod
13 13 import context, repair, graphmod, revset, phases, obsolete, pathutil
14 14 import changelog
15 15 import bookmarks
16 16 import encoding
17 17 import formatter
18 18 import crecord as crecordmod
19 19 import lock as lockmod
20 20
21 21 def ishunk(x):
22 22 hunkclasses = (crecordmod.uihunk, patch.recordhunk)
23 23 return isinstance(x, hunkclasses)
24 24
25 25 def newandmodified(chunks, originalchunks):
26 26 newlyaddedandmodifiedfiles = set()
27 27 for chunk in chunks:
28 28 if ishunk(chunk) and chunk.header.isnewfile() and chunk not in \
29 29 originalchunks:
30 30 newlyaddedandmodifiedfiles.add(chunk.header.filename())
31 31 return newlyaddedandmodifiedfiles
32 32
33 33 def parsealiases(cmd):
34 34 return cmd.lstrip("^").split("|")
35 35
36 36 def setupwrapcolorwrite(ui):
37 37 # wrap ui.write so diff output can be labeled/colorized
38 38 def wrapwrite(orig, *args, **kw):
39 39 label = kw.pop('label', '')
40 40 for chunk, l in patch.difflabel(lambda: args):
41 41 orig(chunk, label=label + l)
42 42
43 43 oldwrite = ui.write
44 44 def wrap(*args, **kwargs):
45 45 return wrapwrite(oldwrite, *args, **kwargs)
46 46 setattr(ui, 'write', wrap)
47 47 return oldwrite
48 48
49 49 def filterchunks(ui, originalhunks, usecurses, testfile, operation=None):
50 50 if usecurses:
51 51 if testfile:
52 52 recordfn = crecordmod.testdecorator(testfile,
53 53 crecordmod.testchunkselector)
54 54 else:
55 55 recordfn = crecordmod.chunkselector
56 56
57 57 return crecordmod.filterpatch(ui, originalhunks, recordfn, operation)
58 58
59 59 else:
60 60 return patch.filterpatch(ui, originalhunks, operation)
61 61
62 62 def recordfilter(ui, originalhunks, operation=None):
63 63 """ Prompts the user to filter the originalhunks and return a list of
64 64 selected hunks.
65 65 *operation* is used for ui purposes to indicate the user
66 66 what kind of filtering they are doing: reverting, commiting, shelving, etc.
67 67 *operation* has to be a translated string.
68 68 """
69 69 usecurses = ui.configbool('experimental', 'crecord', False)
70 70 testfile = ui.config('experimental', 'crecordtest', None)
71 71 oldwrite = setupwrapcolorwrite(ui)
72 72 try:
73 73 newchunks = filterchunks(ui, originalhunks, usecurses, testfile,
74 74 operation)
75 75 finally:
76 76 ui.write = oldwrite
77 77 return newchunks
78 78
79 79 def dorecord(ui, repo, commitfunc, cmdsuggest, backupall,
80 80 filterfn, *pats, **opts):
81 81 import merge as mergemod
82 82
83 83 if not ui.interactive():
84 84 raise util.Abort(_('running non-interactively, use %s instead') %
85 85 cmdsuggest)
86 86
87 87 # make sure username is set before going interactive
88 88 if not opts.get('user'):
89 89 ui.username() # raise exception, username not provided
90 90
91 91 def recordfunc(ui, repo, message, match, opts):
92 92 """This is generic record driver.
93 93
94 94 Its job is to interactively filter local changes, and
95 95 accordingly prepare working directory into a state in which the
96 96 job can be delegated to a non-interactive commit command such as
97 97 'commit' or 'qrefresh'.
98 98
99 99 After the actual job is done by non-interactive command, the
100 100 working directory is restored to its original state.
101 101
102 102 In the end we'll record interesting changes, and everything else
103 103 will be left in place, so the user can continue working.
104 104 """
105 105
106 106 checkunfinished(repo, commit=True)
107 107 merge = len(repo[None].parents()) > 1
108 108 if merge:
109 109 raise util.Abort(_('cannot partially commit a merge '
110 110 '(use "hg commit" instead)'))
111 111
112 112 status = repo.status(match=match)
113 113 diffopts = patch.difffeatureopts(ui, opts=opts, whitespace=True)
114 114 diffopts.nodates = True
115 115 diffopts.git = True
116 116 originaldiff = patch.diff(repo, changes=status, opts=diffopts)
117 117 originalchunks = patch.parsepatch(originaldiff)
118 118
119 119 # 1. filter patch, so we have intending-to apply subset of it
120 120 try:
121 121 chunks = filterfn(ui, originalchunks)
122 122 except patch.PatchError as err:
123 123 raise util.Abort(_('error parsing patch: %s') % err)
124 124
125 125 # We need to keep a backup of files that have been newly added and
126 126 # modified during the recording process because there is a previous
127 127 # version without the edit in the workdir
128 128 newlyaddedandmodifiedfiles = newandmodified(chunks, originalchunks)
129 129 contenders = set()
130 130 for h in chunks:
131 131 try:
132 132 contenders.update(set(h.files()))
133 133 except AttributeError:
134 134 pass
135 135
136 136 changed = status.modified + status.added + status.removed
137 137 newfiles = [f for f in changed if f in contenders]
138 138 if not newfiles:
139 139 ui.status(_('no changes to record\n'))
140 140 return 0
141 141
142 142 modified = set(status.modified)
143 143
144 144 # 2. backup changed files, so we can restore them in the end
145 145
146 146 if backupall:
147 147 tobackup = changed
148 148 else:
149 149 tobackup = [f for f in newfiles if f in modified or f in \
150 150 newlyaddedandmodifiedfiles]
151 151 backups = {}
152 152 if tobackup:
153 153 backupdir = repo.join('record-backups')
154 154 try:
155 155 os.mkdir(backupdir)
156 156 except OSError as err:
157 157 if err.errno != errno.EEXIST:
158 158 raise
159 159 try:
160 160 # backup continues
161 161 for f in tobackup:
162 162 fd, tmpname = tempfile.mkstemp(prefix=f.replace('/', '_')+'.',
163 163 dir=backupdir)
164 164 os.close(fd)
165 165 ui.debug('backup %r as %r\n' % (f, tmpname))
166 166 util.copyfile(repo.wjoin(f), tmpname)
167 167 shutil.copystat(repo.wjoin(f), tmpname)
168 168 backups[f] = tmpname
169 169
170 170 fp = cStringIO.StringIO()
171 171 for c in chunks:
172 172 fname = c.filename()
173 173 if fname in backups:
174 174 c.write(fp)
175 175 dopatch = fp.tell()
176 176 fp.seek(0)
177 177
178 178 [os.unlink(repo.wjoin(c)) for c in newlyaddedandmodifiedfiles]
179 179 # 3a. apply filtered patch to clean repo (clean)
180 180 if backups:
181 181 # Equivalent to hg.revert
182 182 choices = lambda key: key in backups
183 183 mergemod.update(repo, repo.dirstate.p1(),
184 184 False, True, choices)
185 185
186 186 # 3b. (apply)
187 187 if dopatch:
188 188 try:
189 189 ui.debug('applying patch\n')
190 190 ui.debug(fp.getvalue())
191 191 patch.internalpatch(ui, repo, fp, 1, eolmode=None)
192 192 except patch.PatchError as err:
193 193 raise util.Abort(str(err))
194 194 del fp
195 195
196 196 # 4. We prepared working directory according to filtered
197 197 # patch. Now is the time to delegate the job to
198 198 # commit/qrefresh or the like!
199 199
200 200 # Make all of the pathnames absolute.
201 201 newfiles = [repo.wjoin(nf) for nf in newfiles]
202 202 return commitfunc(ui, repo, *newfiles, **opts)
203 203 finally:
204 204 # 5. finally restore backed-up files
205 205 try:
206 206 dirstate = repo.dirstate
207 207 for realname, tmpname in backups.iteritems():
208 208 ui.debug('restoring %r to %r\n' % (tmpname, realname))
209 209
210 210 if dirstate[realname] == 'n':
211 211 # without normallookup, restoring timestamp
212 212 # may cause partially committed files
213 213 # to be treated as unmodified
214 214 dirstate.normallookup(realname)
215 215
216 216 util.copyfile(tmpname, repo.wjoin(realname))
217 217 # Our calls to copystat() here and above are a
218 218 # hack to trick any editors that have f open that
219 219 # we haven't modified them.
220 220 #
221 221 # Also note that this racy as an editor could
222 222 # notice the file's mtime before we've finished
223 223 # writing it.
224 224 shutil.copystat(tmpname, repo.wjoin(realname))
225 225 os.unlink(tmpname)
226 226 if tobackup:
227 227 os.rmdir(backupdir)
228 228 except OSError:
229 229 pass
230 230
231 231 def recordinwlock(ui, repo, message, match, opts):
232 232 wlock = repo.wlock()
233 233 try:
234 234 return recordfunc(ui, repo, message, match, opts)
235 235 finally:
236 236 wlock.release()
237 237
238 238 return commit(ui, repo, recordinwlock, pats, opts)
239 239
240 240 def findpossible(cmd, table, strict=False):
241 241 """
242 242 Return cmd -> (aliases, command table entry)
243 243 for each matching command.
244 244 Return debug commands (or their aliases) only if no normal command matches.
245 245 """
246 246 choice = {}
247 247 debugchoice = {}
248 248
249 249 if cmd in table:
250 250 # short-circuit exact matches, "log" alias beats "^log|history"
251 251 keys = [cmd]
252 252 else:
253 253 keys = table.keys()
254 254
255 255 allcmds = []
256 256 for e in keys:
257 257 aliases = parsealiases(e)
258 258 allcmds.extend(aliases)
259 259 found = None
260 260 if cmd in aliases:
261 261 found = cmd
262 262 elif not strict:
263 263 for a in aliases:
264 264 if a.startswith(cmd):
265 265 found = a
266 266 break
267 267 if found is not None:
268 268 if aliases[0].startswith("debug") or found.startswith("debug"):
269 269 debugchoice[found] = (aliases, table[e])
270 270 else:
271 271 choice[found] = (aliases, table[e])
272 272
273 273 if not choice and debugchoice:
274 274 choice = debugchoice
275 275
276 276 return choice, allcmds
277 277
278 278 def findcmd(cmd, table, strict=True):
279 279 """Return (aliases, command table entry) for command string."""
280 280 choice, allcmds = findpossible(cmd, table, strict)
281 281
282 282 if cmd in choice:
283 283 return choice[cmd]
284 284
285 285 if len(choice) > 1:
286 286 clist = choice.keys()
287 287 clist.sort()
288 288 raise error.AmbiguousCommand(cmd, clist)
289 289
290 290 if choice:
291 291 return choice.values()[0]
292 292
293 293 raise error.UnknownCommand(cmd, allcmds)
294 294
295 295 def findrepo(p):
296 296 while not os.path.isdir(os.path.join(p, ".hg")):
297 297 oldp, p = p, os.path.dirname(p)
298 298 if p == oldp:
299 299 return None
300 300
301 301 return p
302 302
303 303 def bailifchanged(repo, merge=True):
304 304 if merge and repo.dirstate.p2() != nullid:
305 305 raise util.Abort(_('outstanding uncommitted merge'))
306 306 modified, added, removed, deleted = repo.status()[:4]
307 307 if modified or added or removed or deleted:
308 308 raise util.Abort(_('uncommitted changes'))
309 309 ctx = repo[None]
310 310 for s in sorted(ctx.substate):
311 311 ctx.sub(s).bailifchanged()
312 312
313 313 def logmessage(ui, opts):
314 314 """ get the log message according to -m and -l option """
315 315 message = opts.get('message')
316 316 logfile = opts.get('logfile')
317 317
318 318 if message and logfile:
319 319 raise util.Abort(_('options --message and --logfile are mutually '
320 320 'exclusive'))
321 321 if not message and logfile:
322 322 try:
323 323 if logfile == '-':
324 324 message = ui.fin.read()
325 325 else:
326 326 message = '\n'.join(util.readfile(logfile).splitlines())
327 327 except IOError as inst:
328 328 raise util.Abort(_("can't read commit message '%s': %s") %
329 329 (logfile, inst.strerror))
330 330 return message
331 331
332 332 def mergeeditform(ctxorbool, baseformname):
333 333 """return appropriate editform name (referencing a committemplate)
334 334
335 335 'ctxorbool' is either a ctx to be committed, or a bool indicating whether
336 336 merging is committed.
337 337
338 338 This returns baseformname with '.merge' appended if it is a merge,
339 339 otherwise '.normal' is appended.
340 340 """
341 341 if isinstance(ctxorbool, bool):
342 342 if ctxorbool:
343 343 return baseformname + ".merge"
344 344 elif 1 < len(ctxorbool.parents()):
345 345 return baseformname + ".merge"
346 346
347 347 return baseformname + ".normal"
348 348
349 349 def getcommiteditor(edit=False, finishdesc=None, extramsg=None,
350 350 editform='', **opts):
351 351 """get appropriate commit message editor according to '--edit' option
352 352
353 353 'finishdesc' is a function to be called with edited commit message
354 354 (= 'description' of the new changeset) just after editing, but
355 355 before checking empty-ness. It should return actual text to be
356 356 stored into history. This allows to change description before
357 357 storing.
358 358
359 359 'extramsg' is a extra message to be shown in the editor instead of
360 360 'Leave message empty to abort commit' line. 'HG: ' prefix and EOL
361 361 is automatically added.
362 362
363 363 'editform' is a dot-separated list of names, to distinguish
364 364 the purpose of commit text editing.
365 365
366 366 'getcommiteditor' returns 'commitforceeditor' regardless of
367 367 'edit', if one of 'finishdesc' or 'extramsg' is specified, because
368 368 they are specific for usage in MQ.
369 369 """
370 370 if edit or finishdesc or extramsg:
371 371 return lambda r, c, s: commitforceeditor(r, c, s,
372 372 finishdesc=finishdesc,
373 373 extramsg=extramsg,
374 374 editform=editform)
375 375 elif editform:
376 376 return lambda r, c, s: commiteditor(r, c, s, editform=editform)
377 377 else:
378 378 return commiteditor
379 379
380 380 def loglimit(opts):
381 381 """get the log limit according to option -l/--limit"""
382 382 limit = opts.get('limit')
383 383 if limit:
384 384 try:
385 385 limit = int(limit)
386 386 except ValueError:
387 387 raise util.Abort(_('limit must be a positive integer'))
388 388 if limit <= 0:
389 389 raise util.Abort(_('limit must be positive'))
390 390 else:
391 391 limit = None
392 392 return limit
393 393
394 394 def makefilename(repo, pat, node, desc=None,
395 395 total=None, seqno=None, revwidth=None, pathname=None):
396 396 node_expander = {
397 397 'H': lambda: hex(node),
398 398 'R': lambda: str(repo.changelog.rev(node)),
399 399 'h': lambda: short(node),
400 400 'm': lambda: re.sub('[^\w]', '_', str(desc))
401 401 }
402 402 expander = {
403 403 '%': lambda: '%',
404 404 'b': lambda: os.path.basename(repo.root),
405 405 }
406 406
407 407 try:
408 408 if node:
409 409 expander.update(node_expander)
410 410 if node:
411 411 expander['r'] = (lambda:
412 412 str(repo.changelog.rev(node)).zfill(revwidth or 0))
413 413 if total is not None:
414 414 expander['N'] = lambda: str(total)
415 415 if seqno is not None:
416 416 expander['n'] = lambda: str(seqno)
417 417 if total is not None and seqno is not None:
418 418 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
419 419 if pathname is not None:
420 420 expander['s'] = lambda: os.path.basename(pathname)
421 421 expander['d'] = lambda: os.path.dirname(pathname) or '.'
422 422 expander['p'] = lambda: pathname
423 423
424 424 newname = []
425 425 patlen = len(pat)
426 426 i = 0
427 427 while i < patlen:
428 428 c = pat[i]
429 429 if c == '%':
430 430 i += 1
431 431 c = pat[i]
432 432 c = expander[c]()
433 433 newname.append(c)
434 434 i += 1
435 435 return ''.join(newname)
436 436 except KeyError as inst:
437 437 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
438 438 inst.args[0])
439 439
440 440 def makefileobj(repo, pat, node=None, desc=None, total=None,
441 441 seqno=None, revwidth=None, mode='wb', modemap=None,
442 442 pathname=None):
443 443
444 444 writable = mode not in ('r', 'rb')
445 445
446 446 if not pat or pat == '-':
447 447 if writable:
448 448 fp = repo.ui.fout
449 449 else:
450 450 fp = repo.ui.fin
451 451 if util.safehasattr(fp, 'fileno'):
452 452 return os.fdopen(os.dup(fp.fileno()), mode)
453 453 else:
454 454 # if this fp can't be duped properly, return
455 455 # a dummy object that can be closed
456 456 class wrappedfileobj(object):
457 457 noop = lambda x: None
458 458 def __init__(self, f):
459 459 self.f = f
460 460 def __getattr__(self, attr):
461 461 if attr == 'close':
462 462 return self.noop
463 463 else:
464 464 return getattr(self.f, attr)
465 465
466 466 return wrappedfileobj(fp)
467 467 if util.safehasattr(pat, 'write') and writable:
468 468 return pat
469 469 if util.safehasattr(pat, 'read') and 'r' in mode:
470 470 return pat
471 471 fn = makefilename(repo, pat, node, desc, total, seqno, revwidth, pathname)
472 472 if modemap is not None:
473 473 mode = modemap.get(fn, mode)
474 474 if mode == 'wb':
475 475 modemap[fn] = 'ab'
476 476 return open(fn, mode)
477 477
478 478 def openrevlog(repo, cmd, file_, opts):
479 479 """opens the changelog, manifest, a filelog or a given revlog"""
480 480 cl = opts['changelog']
481 481 mf = opts['manifest']
482 482 dir = opts['dir']
483 483 msg = None
484 484 if cl and mf:
485 485 msg = _('cannot specify --changelog and --manifest at the same time')
486 486 elif cl and dir:
487 487 msg = _('cannot specify --changelog and --dir at the same time')
488 488 elif cl or mf:
489 489 if file_:
490 490 msg = _('cannot specify filename with --changelog or --manifest')
491 491 elif not repo:
492 492 msg = _('cannot specify --changelog or --manifest or --dir '
493 493 'without a repository')
494 494 if msg:
495 495 raise util.Abort(msg)
496 496
497 497 r = None
498 498 if repo:
499 499 if cl:
500 500 r = repo.unfiltered().changelog
501 501 elif dir:
502 502 if 'treemanifest' not in repo.requirements:
503 503 raise util.Abort(_("--dir can only be used on repos with "
504 504 "treemanifest enabled"))
505 505 dirlog = repo.dirlog(file_)
506 506 if len(dirlog):
507 507 r = dirlog
508 508 elif mf:
509 509 r = repo.manifest
510 510 elif file_:
511 511 filelog = repo.file(file_)
512 512 if len(filelog):
513 513 r = filelog
514 514 if not r:
515 515 if not file_:
516 516 raise error.CommandError(cmd, _('invalid arguments'))
517 517 if not os.path.isfile(file_):
518 518 raise util.Abort(_("revlog '%s' not found") % file_)
519 519 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
520 520 file_[:-2] + ".i")
521 521 return r
522 522
523 523 def copy(ui, repo, pats, opts, rename=False):
524 524 # called with the repo lock held
525 525 #
526 526 # hgsep => pathname that uses "/" to separate directories
527 527 # ossep => pathname that uses os.sep to separate directories
528 528 cwd = repo.getcwd()
529 529 targets = {}
530 530 after = opts.get("after")
531 531 dryrun = opts.get("dry_run")
532 532 wctx = repo[None]
533 533
534 534 def walkpat(pat):
535 535 srcs = []
536 536 if after:
537 537 badstates = '?'
538 538 else:
539 539 badstates = '?r'
540 540 m = scmutil.match(repo[None], [pat], opts, globbed=True)
541 541 for abs in repo.walk(m):
542 542 state = repo.dirstate[abs]
543 543 rel = m.rel(abs)
544 544 exact = m.exact(abs)
545 545 if state in badstates:
546 546 if exact and state == '?':
547 547 ui.warn(_('%s: not copying - file is not managed\n') % rel)
548 548 if exact and state == 'r':
549 549 ui.warn(_('%s: not copying - file has been marked for'
550 550 ' remove\n') % rel)
551 551 continue
552 552 # abs: hgsep
553 553 # rel: ossep
554 554 srcs.append((abs, rel, exact))
555 555 return srcs
556 556
557 557 # abssrc: hgsep
558 558 # relsrc: ossep
559 559 # otarget: ossep
560 560 def copyfile(abssrc, relsrc, otarget, exact):
561 561 abstarget = pathutil.canonpath(repo.root, cwd, otarget)
562 562 if '/' in abstarget:
563 563 # We cannot normalize abstarget itself, this would prevent
564 564 # case only renames, like a => A.
565 565 abspath, absname = abstarget.rsplit('/', 1)
566 566 abstarget = repo.dirstate.normalize(abspath) + '/' + absname
567 567 reltarget = repo.pathto(abstarget, cwd)
568 568 target = repo.wjoin(abstarget)
569 569 src = repo.wjoin(abssrc)
570 570 state = repo.dirstate[abstarget]
571 571
572 572 scmutil.checkportable(ui, abstarget)
573 573
574 574 # check for collisions
575 575 prevsrc = targets.get(abstarget)
576 576 if prevsrc is not None:
577 577 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
578 578 (reltarget, repo.pathto(abssrc, cwd),
579 579 repo.pathto(prevsrc, cwd)))
580 580 return
581 581
582 582 # check for overwrites
583 583 exists = os.path.lexists(target)
584 584 samefile = False
585 585 if exists and abssrc != abstarget:
586 586 if (repo.dirstate.normalize(abssrc) ==
587 587 repo.dirstate.normalize(abstarget)):
588 588 if not rename:
589 589 ui.warn(_("%s: can't copy - same file\n") % reltarget)
590 590 return
591 591 exists = False
592 592 samefile = True
593 593
594 594 if not after and exists or after and state in 'mn':
595 595 if not opts['force']:
596 596 ui.warn(_('%s: not overwriting - file exists\n') %
597 597 reltarget)
598 598 return
599 599
600 600 if after:
601 601 if not exists:
602 602 if rename:
603 603 ui.warn(_('%s: not recording move - %s does not exist\n') %
604 604 (relsrc, reltarget))
605 605 else:
606 606 ui.warn(_('%s: not recording copy - %s does not exist\n') %
607 607 (relsrc, reltarget))
608 608 return
609 609 elif not dryrun:
610 610 try:
611 611 if exists:
612 612 os.unlink(target)
613 613 targetdir = os.path.dirname(target) or '.'
614 614 if not os.path.isdir(targetdir):
615 615 os.makedirs(targetdir)
616 616 if samefile:
617 617 tmp = target + "~hgrename"
618 618 os.rename(src, tmp)
619 619 os.rename(tmp, target)
620 620 else:
621 621 util.copyfile(src, target)
622 622 srcexists = True
623 623 except IOError as inst:
624 624 if inst.errno == errno.ENOENT:
625 625 ui.warn(_('%s: deleted in working directory\n') % relsrc)
626 626 srcexists = False
627 627 else:
628 628 ui.warn(_('%s: cannot copy - %s\n') %
629 629 (relsrc, inst.strerror))
630 630 return True # report a failure
631 631
632 632 if ui.verbose or not exact:
633 633 if rename:
634 634 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
635 635 else:
636 636 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
637 637
638 638 targets[abstarget] = abssrc
639 639
640 640 # fix up dirstate
641 641 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
642 642 dryrun=dryrun, cwd=cwd)
643 643 if rename and not dryrun:
644 644 if not after and srcexists and not samefile:
645 645 util.unlinkpath(repo.wjoin(abssrc))
646 646 wctx.forget([abssrc])
647 647
648 648 # pat: ossep
649 649 # dest ossep
650 650 # srcs: list of (hgsep, hgsep, ossep, bool)
651 651 # return: function that takes hgsep and returns ossep
652 652 def targetpathfn(pat, dest, srcs):
653 653 if os.path.isdir(pat):
654 654 abspfx = pathutil.canonpath(repo.root, cwd, pat)
655 655 abspfx = util.localpath(abspfx)
656 656 if destdirexists:
657 657 striplen = len(os.path.split(abspfx)[0])
658 658 else:
659 659 striplen = len(abspfx)
660 660 if striplen:
661 661 striplen += len(os.sep)
662 662 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
663 663 elif destdirexists:
664 664 res = lambda p: os.path.join(dest,
665 665 os.path.basename(util.localpath(p)))
666 666 else:
667 667 res = lambda p: dest
668 668 return res
669 669
670 670 # pat: ossep
671 671 # dest ossep
672 672 # srcs: list of (hgsep, hgsep, ossep, bool)
673 673 # return: function that takes hgsep and returns ossep
674 674 def targetpathafterfn(pat, dest, srcs):
675 675 if matchmod.patkind(pat):
676 676 # a mercurial pattern
677 677 res = lambda p: os.path.join(dest,
678 678 os.path.basename(util.localpath(p)))
679 679 else:
680 680 abspfx = pathutil.canonpath(repo.root, cwd, pat)
681 681 if len(abspfx) < len(srcs[0][0]):
682 682 # A directory. Either the target path contains the last
683 683 # component of the source path or it does not.
684 684 def evalpath(striplen):
685 685 score = 0
686 686 for s in srcs:
687 687 t = os.path.join(dest, util.localpath(s[0])[striplen:])
688 688 if os.path.lexists(t):
689 689 score += 1
690 690 return score
691 691
692 692 abspfx = util.localpath(abspfx)
693 693 striplen = len(abspfx)
694 694 if striplen:
695 695 striplen += len(os.sep)
696 696 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
697 697 score = evalpath(striplen)
698 698 striplen1 = len(os.path.split(abspfx)[0])
699 699 if striplen1:
700 700 striplen1 += len(os.sep)
701 701 if evalpath(striplen1) > score:
702 702 striplen = striplen1
703 703 res = lambda p: os.path.join(dest,
704 704 util.localpath(p)[striplen:])
705 705 else:
706 706 # a file
707 707 if destdirexists:
708 708 res = lambda p: os.path.join(dest,
709 709 os.path.basename(util.localpath(p)))
710 710 else:
711 711 res = lambda p: dest
712 712 return res
713 713
714 714 pats = scmutil.expandpats(pats)
715 715 if not pats:
716 716 raise util.Abort(_('no source or destination specified'))
717 717 if len(pats) == 1:
718 718 raise util.Abort(_('no destination specified'))
719 719 dest = pats.pop()
720 720 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
721 721 if not destdirexists:
722 722 if len(pats) > 1 or matchmod.patkind(pats[0]):
723 723 raise util.Abort(_('with multiple sources, destination must be an '
724 724 'existing directory'))
725 725 if util.endswithsep(dest):
726 726 raise util.Abort(_('destination %s is not a directory') % dest)
727 727
728 728 tfn = targetpathfn
729 729 if after:
730 730 tfn = targetpathafterfn
731 731 copylist = []
732 732 for pat in pats:
733 733 srcs = walkpat(pat)
734 734 if not srcs:
735 735 continue
736 736 copylist.append((tfn(pat, dest, srcs), srcs))
737 737 if not copylist:
738 738 raise util.Abort(_('no files to copy'))
739 739
740 740 errors = 0
741 741 for targetpath, srcs in copylist:
742 742 for abssrc, relsrc, exact in srcs:
743 743 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
744 744 errors += 1
745 745
746 746 if errors:
747 747 ui.warn(_('(consider using --after)\n'))
748 748
749 749 return errors != 0
750 750
751 751 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
752 752 runargs=None, appendpid=False):
753 753 '''Run a command as a service.'''
754 754
755 755 def writepid(pid):
756 756 if opts['pid_file']:
757 757 if appendpid:
758 758 mode = 'a'
759 759 else:
760 760 mode = 'w'
761 761 fp = open(opts['pid_file'], mode)
762 762 fp.write(str(pid) + '\n')
763 763 fp.close()
764 764
765 765 if opts['daemon'] and not opts['daemon_pipefds']:
766 766 # Signal child process startup with file removal
767 767 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
768 768 os.close(lockfd)
769 769 try:
770 770 if not runargs:
771 771 runargs = util.hgcmd() + sys.argv[1:]
772 772 runargs.append('--daemon-pipefds=%s' % lockpath)
773 773 # Don't pass --cwd to the child process, because we've already
774 774 # changed directory.
775 775 for i in xrange(1, len(runargs)):
776 776 if runargs[i].startswith('--cwd='):
777 777 del runargs[i]
778 778 break
779 779 elif runargs[i].startswith('--cwd'):
780 780 del runargs[i:i + 2]
781 781 break
782 782 def condfn():
783 783 return not os.path.exists(lockpath)
784 784 pid = util.rundetached(runargs, condfn)
785 785 if pid < 0:
786 786 raise util.Abort(_('child process failed to start'))
787 787 writepid(pid)
788 788 finally:
789 789 try:
790 790 os.unlink(lockpath)
791 791 except OSError as e:
792 792 if e.errno != errno.ENOENT:
793 793 raise
794 794 if parentfn:
795 795 return parentfn(pid)
796 796 else:
797 797 return
798 798
799 799 if initfn:
800 800 initfn()
801 801
802 802 if not opts['daemon']:
803 803 writepid(os.getpid())
804 804
805 805 if opts['daemon_pipefds']:
806 806 lockpath = opts['daemon_pipefds']
807 807 try:
808 808 os.setsid()
809 809 except AttributeError:
810 810 pass
811 811 os.unlink(lockpath)
812 812 util.hidewindow()
813 813 sys.stdout.flush()
814 814 sys.stderr.flush()
815 815
816 816 nullfd = os.open(os.devnull, os.O_RDWR)
817 817 logfilefd = nullfd
818 818 if logfile:
819 819 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
820 820 os.dup2(nullfd, 0)
821 821 os.dup2(logfilefd, 1)
822 822 os.dup2(logfilefd, 2)
823 823 if nullfd not in (0, 1, 2):
824 824 os.close(nullfd)
825 825 if logfile and logfilefd not in (0, 1, 2):
826 826 os.close(logfilefd)
827 827
828 828 if runfn:
829 829 return runfn()
830 830
831 831 def tryimportone(ui, repo, hunk, parents, opts, msgs, updatefunc):
832 832 """Utility function used by commands.import to import a single patch
833 833
834 834 This function is explicitly defined here to help the evolve extension to
835 835 wrap this part of the import logic.
836 836
837 837 The API is currently a bit ugly because it a simple code translation from
838 838 the import command. Feel free to make it better.
839 839
840 840 :hunk: a patch (as a binary string)
841 841 :parents: nodes that will be parent of the created commit
842 842 :opts: the full dict of option passed to the import command
843 843 :msgs: list to save commit message to.
844 844 (used in case we need to save it when failing)
845 845 :updatefunc: a function that update a repo to a given node
846 846 updatefunc(<repo>, <node>)
847 847 """
848 848 tmpname, message, user, date, branch, nodeid, p1, p2 = \
849 849 patch.extract(ui, hunk)
850 850
851 851 update = not opts.get('bypass')
852 852 strip = opts["strip"]
853 853 prefix = opts["prefix"]
854 854 sim = float(opts.get('similarity') or 0)
855 855 if not tmpname:
856 856 return (None, None, False)
857 857 msg = _('applied to working directory')
858 858
859 859 rejects = False
860 860 dsguard = None
861 861
862 862 try:
863 863 cmdline_message = logmessage(ui, opts)
864 864 if cmdline_message:
865 865 # pickup the cmdline msg
866 866 message = cmdline_message
867 867 elif message:
868 868 # pickup the patch msg
869 869 message = message.strip()
870 870 else:
871 871 # launch the editor
872 872 message = None
873 873 ui.debug('message:\n%s\n' % message)
874 874
875 875 if len(parents) == 1:
876 876 parents.append(repo[nullid])
877 877 if opts.get('exact'):
878 878 if not nodeid or not p1:
879 879 raise util.Abort(_('not a Mercurial patch'))
880 880 p1 = repo[p1]
881 881 p2 = repo[p2 or nullid]
882 882 elif p2:
883 883 try:
884 884 p1 = repo[p1]
885 885 p2 = repo[p2]
886 886 # Without any options, consider p2 only if the
887 887 # patch is being applied on top of the recorded
888 888 # first parent.
889 889 if p1 != parents[0]:
890 890 p1 = parents[0]
891 891 p2 = repo[nullid]
892 892 except error.RepoError:
893 893 p1, p2 = parents
894 894 if p2.node() == nullid:
895 895 ui.warn(_("warning: import the patch as a normal revision\n"
896 896 "(use --exact to import the patch as a merge)\n"))
897 897 else:
898 898 p1, p2 = parents
899 899
900 900 n = None
901 901 if update:
902 902 dsguard = dirstateguard(repo, 'tryimportone')
903 903 if p1 != parents[0]:
904 904 updatefunc(repo, p1.node())
905 905 if p2 != parents[1]:
906 906 repo.setparents(p1.node(), p2.node())
907 907
908 908 if opts.get('exact') or opts.get('import_branch'):
909 909 repo.dirstate.setbranch(branch or 'default')
910 910
911 911 partial = opts.get('partial', False)
912 912 files = set()
913 913 try:
914 914 patch.patch(ui, repo, tmpname, strip=strip, prefix=prefix,
915 915 files=files, eolmode=None, similarity=sim / 100.0)
916 916 except patch.PatchError as e:
917 917 if not partial:
918 918 raise util.Abort(str(e))
919 919 if partial:
920 920 rejects = True
921 921
922 922 files = list(files)
923 923 if opts.get('no_commit'):
924 924 if message:
925 925 msgs.append(message)
926 926 else:
927 927 if opts.get('exact') or p2:
928 928 # If you got here, you either use --force and know what
929 929 # you are doing or used --exact or a merge patch while
930 930 # being updated to its first parent.
931 931 m = None
932 932 else:
933 933 m = scmutil.matchfiles(repo, files or [])
934 934 editform = mergeeditform(repo[None], 'import.normal')
935 935 if opts.get('exact'):
936 936 editor = None
937 937 else:
938 938 editor = getcommiteditor(editform=editform, **opts)
939 939 allowemptyback = repo.ui.backupconfig('ui', 'allowemptycommit')
940 940 try:
941 941 if partial:
942 942 repo.ui.setconfig('ui', 'allowemptycommit', True)
943 943 n = repo.commit(message, opts.get('user') or user,
944 944 opts.get('date') or date, match=m,
945 945 editor=editor)
946 946 finally:
947 947 repo.ui.restoreconfig(allowemptyback)
948 948 dsguard.close()
949 949 else:
950 950 if opts.get('exact') or opts.get('import_branch'):
951 951 branch = branch or 'default'
952 952 else:
953 953 branch = p1.branch()
954 954 store = patch.filestore()
955 955 try:
956 956 files = set()
957 957 try:
958 958 patch.patchrepo(ui, repo, p1, store, tmpname, strip, prefix,
959 959 files, eolmode=None)
960 960 except patch.PatchError as e:
961 961 raise util.Abort(str(e))
962 962 if opts.get('exact'):
963 963 editor = None
964 964 else:
965 965 editor = getcommiteditor(editform='import.bypass')
966 966 memctx = context.makememctx(repo, (p1.node(), p2.node()),
967 967 message,
968 968 opts.get('user') or user,
969 969 opts.get('date') or date,
970 970 branch, files, store,
971 971 editor=editor)
972 972 n = memctx.commit()
973 973 finally:
974 974 store.close()
975 975 if opts.get('exact') and opts.get('no_commit'):
976 976 # --exact with --no-commit is still useful in that it does merge
977 977 # and branch bits
978 978 ui.warn(_("warning: can't check exact import with --no-commit\n"))
979 979 elif opts.get('exact') and hex(n) != nodeid:
980 980 raise util.Abort(_('patch is damaged or loses information'))
981 981 if n:
982 982 # i18n: refers to a short changeset id
983 983 msg = _('created %s') % short(n)
984 984 return (msg, n, rejects)
985 985 finally:
986 986 lockmod.release(dsguard)
987 987 os.unlink(tmpname)
988 988
989 989 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
990 990 opts=None):
991 991 '''export changesets as hg patches.'''
992 992
993 993 total = len(revs)
994 994 revwidth = max([len(str(rev)) for rev in revs])
995 995 filemode = {}
996 996
997 997 def single(rev, seqno, fp):
998 998 ctx = repo[rev]
999 999 node = ctx.node()
1000 1000 parents = [p.node() for p in ctx.parents() if p]
1001 1001 branch = ctx.branch()
1002 1002 if switch_parent:
1003 1003 parents.reverse()
1004 1004
1005 1005 if parents:
1006 1006 prev = parents[0]
1007 1007 else:
1008 1008 prev = nullid
1009 1009
1010 1010 shouldclose = False
1011 1011 if not fp and len(template) > 0:
1012 1012 desc_lines = ctx.description().rstrip().split('\n')
1013 1013 desc = desc_lines[0] #Commit always has a first line.
1014 1014 fp = makefileobj(repo, template, node, desc=desc, total=total,
1015 1015 seqno=seqno, revwidth=revwidth, mode='wb',
1016 1016 modemap=filemode)
1017 1017 if fp != template:
1018 1018 shouldclose = True
1019 1019 if fp and fp != sys.stdout and util.safehasattr(fp, 'name'):
1020 1020 repo.ui.note("%s\n" % fp.name)
1021 1021
1022 1022 if not fp:
1023 1023 write = repo.ui.write
1024 1024 else:
1025 1025 def write(s, **kw):
1026 1026 fp.write(s)
1027 1027
1028 1028 write("# HG changeset patch\n")
1029 1029 write("# User %s\n" % ctx.user())
1030 1030 write("# Date %d %d\n" % ctx.date())
1031 1031 write("# %s\n" % util.datestr(ctx.date()))
1032 1032 if branch and branch != 'default':
1033 1033 write("# Branch %s\n" % branch)
1034 1034 write("# Node ID %s\n" % hex(node))
1035 1035 write("# Parent %s\n" % hex(prev))
1036 1036 if len(parents) > 1:
1037 1037 write("# Parent %s\n" % hex(parents[1]))
1038 1038 write(ctx.description().rstrip())
1039 1039 write("\n\n")
1040 1040
1041 1041 for chunk, label in patch.diffui(repo, prev, node, opts=opts):
1042 1042 write(chunk, label=label)
1043 1043
1044 1044 if shouldclose:
1045 1045 fp.close()
1046 1046
1047 1047 for seqno, rev in enumerate(revs):
1048 1048 single(rev, seqno + 1, fp)
1049 1049
1050 1050 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
1051 1051 changes=None, stat=False, fp=None, prefix='',
1052 1052 root='', listsubrepos=False):
1053 1053 '''show diff or diffstat.'''
1054 1054 if fp is None:
1055 1055 write = ui.write
1056 1056 else:
1057 1057 def write(s, **kw):
1058 1058 fp.write(s)
1059 1059
1060 1060 if root:
1061 1061 relroot = pathutil.canonpath(repo.root, repo.getcwd(), root)
1062 1062 else:
1063 1063 relroot = ''
1064 1064 if relroot != '':
1065 1065 # XXX relative roots currently don't work if the root is within a
1066 1066 # subrepo
1067 1067 uirelroot = match.uipath(relroot)
1068 1068 relroot += '/'
1069 1069 for matchroot in match.files():
1070 1070 if not matchroot.startswith(relroot):
1071 1071 ui.warn(_('warning: %s not inside relative root %s\n') % (
1072 1072 match.uipath(matchroot), uirelroot))
1073 1073
1074 1074 if stat:
1075 1075 diffopts = diffopts.copy(context=0)
1076 1076 width = 80
1077 1077 if not ui.plain():
1078 1078 width = ui.termwidth()
1079 1079 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
1080 1080 prefix=prefix, relroot=relroot)
1081 1081 for chunk, label in patch.diffstatui(util.iterlines(chunks),
1082 1082 width=width,
1083 1083 git=diffopts.git):
1084 1084 write(chunk, label=label)
1085 1085 else:
1086 1086 for chunk, label in patch.diffui(repo, node1, node2, match,
1087 1087 changes, diffopts, prefix=prefix,
1088 1088 relroot=relroot):
1089 1089 write(chunk, label=label)
1090 1090
1091 1091 if listsubrepos:
1092 1092 ctx1 = repo[node1]
1093 1093 ctx2 = repo[node2]
1094 1094 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
1095 1095 tempnode2 = node2
1096 1096 try:
1097 1097 if node2 is not None:
1098 1098 tempnode2 = ctx2.substate[subpath][1]
1099 1099 except KeyError:
1100 1100 # A subrepo that existed in node1 was deleted between node1 and
1101 1101 # node2 (inclusive). Thus, ctx2's substate won't contain that
1102 1102 # subpath. The best we can do is to ignore it.
1103 1103 tempnode2 = None
1104 1104 submatch = matchmod.narrowmatcher(subpath, match)
1105 1105 sub.diff(ui, diffopts, tempnode2, submatch, changes=changes,
1106 1106 stat=stat, fp=fp, prefix=prefix)
1107 1107
1108 1108 class changeset_printer(object):
1109 1109 '''show changeset information when templating not requested.'''
1110 1110
1111 1111 def __init__(self, ui, repo, matchfn, diffopts, buffered):
1112 1112 self.ui = ui
1113 1113 self.repo = repo
1114 1114 self.buffered = buffered
1115 1115 self.matchfn = matchfn
1116 1116 self.diffopts = diffopts
1117 1117 self.header = {}
1118 1118 self.hunk = {}
1119 1119 self.lastheader = None
1120 1120 self.footer = None
1121 1121
1122 1122 def flush(self, rev):
1123 1123 if rev in self.header:
1124 1124 h = self.header[rev]
1125 1125 if h != self.lastheader:
1126 1126 self.lastheader = h
1127 1127 self.ui.write(h)
1128 1128 del self.header[rev]
1129 1129 if rev in self.hunk:
1130 1130 self.ui.write(self.hunk[rev])
1131 1131 del self.hunk[rev]
1132 1132 return 1
1133 1133 return 0
1134 1134
1135 1135 def close(self):
1136 1136 if self.footer:
1137 1137 self.ui.write(self.footer)
1138 1138
1139 1139 def show(self, ctx, copies=None, matchfn=None, **props):
1140 1140 if self.buffered:
1141 1141 self.ui.pushbuffer()
1142 1142 self._show(ctx, copies, matchfn, props)
1143 1143 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
1144 1144 else:
1145 1145 self._show(ctx, copies, matchfn, props)
1146 1146
1147 1147 def _show(self, ctx, copies, matchfn, props):
1148 1148 '''show a single changeset or file revision'''
1149 1149 changenode = ctx.node()
1150 1150 rev = ctx.rev()
1151 1151 if self.ui.debugflag:
1152 1152 hexfunc = hex
1153 1153 else:
1154 1154 hexfunc = short
1155 if rev is None:
1156 pctx = ctx.p1()
1157 revnode = (pctx.rev(), hexfunc(pctx.node()) + '+')
1158 else:
1159 revnode = (rev, hexfunc(changenode))
1155 # as of now, wctx.node() and wctx.rev() return None, but we want to
1156 # show the same values as {node} and {rev} templatekw
1157 revnode = (scmutil.intrev(rev), hexfunc(bin(ctx.hex())))
1160 1158
1161 1159 if self.ui.quiet:
1162 1160 self.ui.write("%d:%s\n" % revnode, label='log.node')
1163 1161 return
1164 1162
1165 1163 date = util.datestr(ctx.date())
1166 1164
1167 1165 # i18n: column positioning for "hg log"
1168 1166 self.ui.write(_("changeset: %d:%s\n") % revnode,
1169 1167 label='log.changeset changeset.%s' % ctx.phasestr())
1170 1168
1171 1169 # branches are shown first before any other names due to backwards
1172 1170 # compatibility
1173 1171 branch = ctx.branch()
1174 1172 # don't show the default branch name
1175 1173 if branch != 'default':
1176 1174 # i18n: column positioning for "hg log"
1177 1175 self.ui.write(_("branch: %s\n") % branch,
1178 1176 label='log.branch')
1179 1177
1180 1178 for name, ns in self.repo.names.iteritems():
1181 1179 # branches has special logic already handled above, so here we just
1182 1180 # skip it
1183 1181 if name == 'branches':
1184 1182 continue
1185 1183 # we will use the templatename as the color name since those two
1186 1184 # should be the same
1187 1185 for name in ns.names(self.repo, changenode):
1188 1186 self.ui.write(ns.logfmt % name,
1189 1187 label='log.%s' % ns.colorname)
1190 1188 if self.ui.debugflag:
1191 1189 # i18n: column positioning for "hg log"
1192 1190 self.ui.write(_("phase: %s\n") % ctx.phasestr(),
1193 1191 label='log.phase')
1194 1192 for pctx in self._meaningful_parentrevs(ctx):
1195 1193 label = 'log.parent changeset.%s' % pctx.phasestr()
1196 1194 # i18n: column positioning for "hg log"
1197 1195 self.ui.write(_("parent: %d:%s\n")
1198 1196 % (pctx.rev(), hexfunc(pctx.node())),
1199 1197 label=label)
1200 1198
1201 1199 if self.ui.debugflag and rev is not None:
1202 1200 mnode = ctx.manifestnode()
1203 1201 # i18n: column positioning for "hg log"
1204 1202 self.ui.write(_("manifest: %d:%s\n") %
1205 1203 (self.repo.manifest.rev(mnode), hex(mnode)),
1206 1204 label='ui.debug log.manifest')
1207 1205 # i18n: column positioning for "hg log"
1208 1206 self.ui.write(_("user: %s\n") % ctx.user(),
1209 1207 label='log.user')
1210 1208 # i18n: column positioning for "hg log"
1211 1209 self.ui.write(_("date: %s\n") % date,
1212 1210 label='log.date')
1213 1211
1214 1212 if self.ui.debugflag:
1215 1213 files = ctx.p1().status(ctx)[:3]
1216 1214 for key, value in zip([# i18n: column positioning for "hg log"
1217 1215 _("files:"),
1218 1216 # i18n: column positioning for "hg log"
1219 1217 _("files+:"),
1220 1218 # i18n: column positioning for "hg log"
1221 1219 _("files-:")], files):
1222 1220 if value:
1223 1221 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
1224 1222 label='ui.debug log.files')
1225 1223 elif ctx.files() and self.ui.verbose:
1226 1224 # i18n: column positioning for "hg log"
1227 1225 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
1228 1226 label='ui.note log.files')
1229 1227 if copies and self.ui.verbose:
1230 1228 copies = ['%s (%s)' % c for c in copies]
1231 1229 # i18n: column positioning for "hg log"
1232 1230 self.ui.write(_("copies: %s\n") % ' '.join(copies),
1233 1231 label='ui.note log.copies')
1234 1232
1235 1233 extra = ctx.extra()
1236 1234 if extra and self.ui.debugflag:
1237 1235 for key, value in sorted(extra.items()):
1238 1236 # i18n: column positioning for "hg log"
1239 1237 self.ui.write(_("extra: %s=%s\n")
1240 1238 % (key, value.encode('string_escape')),
1241 1239 label='ui.debug log.extra')
1242 1240
1243 1241 description = ctx.description().strip()
1244 1242 if description:
1245 1243 if self.ui.verbose:
1246 1244 self.ui.write(_("description:\n"),
1247 1245 label='ui.note log.description')
1248 1246 self.ui.write(description,
1249 1247 label='ui.note log.description')
1250 1248 self.ui.write("\n\n")
1251 1249 else:
1252 1250 # i18n: column positioning for "hg log"
1253 1251 self.ui.write(_("summary: %s\n") %
1254 1252 description.splitlines()[0],
1255 1253 label='log.summary')
1256 1254 self.ui.write("\n")
1257 1255
1258 1256 self.showpatch(changenode, matchfn)
1259 1257
1260 1258 def showpatch(self, node, matchfn):
1261 1259 if not matchfn:
1262 1260 matchfn = self.matchfn
1263 1261 if matchfn:
1264 1262 stat = self.diffopts.get('stat')
1265 1263 diff = self.diffopts.get('patch')
1266 1264 diffopts = patch.diffallopts(self.ui, self.diffopts)
1267 1265 prev = self.repo.changelog.parents(node)[0]
1268 1266 if stat:
1269 1267 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
1270 1268 match=matchfn, stat=True)
1271 1269 if diff:
1272 1270 if stat:
1273 1271 self.ui.write("\n")
1274 1272 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
1275 1273 match=matchfn, stat=False)
1276 1274 self.ui.write("\n")
1277 1275
1278 1276 def _meaningful_parentrevs(self, ctx):
1279 1277 """Return list of meaningful (or all if debug) parentrevs for rev.
1280 1278
1281 1279 For merges (two non-nullrev revisions) both parents are meaningful.
1282 1280 Otherwise the first parent revision is considered meaningful if it
1283 1281 is not the preceding revision.
1284 1282 """
1285 1283 parents = ctx.parents()
1286 1284 if len(parents) > 1:
1287 1285 return parents
1288 1286 if self.ui.debugflag:
1289 1287 return [parents[0], self.repo['null']]
1290 1288 if parents[0].rev() >= scmutil.intrev(ctx.rev()) - 1:
1291 1289 return []
1292 1290 return parents
1293 1291
1294 1292 class jsonchangeset(changeset_printer):
1295 1293 '''format changeset information.'''
1296 1294
1297 1295 def __init__(self, ui, repo, matchfn, diffopts, buffered):
1298 1296 changeset_printer.__init__(self, ui, repo, matchfn, diffopts, buffered)
1299 1297 self.cache = {}
1300 1298 self._first = True
1301 1299
1302 1300 def close(self):
1303 1301 if not self._first:
1304 1302 self.ui.write("\n]\n")
1305 1303 else:
1306 1304 self.ui.write("[]\n")
1307 1305
1308 1306 def _show(self, ctx, copies, matchfn, props):
1309 1307 '''show a single changeset or file revision'''
1310 1308 rev = ctx.rev()
1311 1309 if rev is None:
1312 1310 jrev = jnode = 'null'
1313 1311 else:
1314 1312 jrev = str(rev)
1315 1313 jnode = '"%s"' % hex(ctx.node())
1316 1314 j = encoding.jsonescape
1317 1315
1318 1316 if self._first:
1319 1317 self.ui.write("[\n {")
1320 1318 self._first = False
1321 1319 else:
1322 1320 self.ui.write(",\n {")
1323 1321
1324 1322 if self.ui.quiet:
1325 1323 self.ui.write('\n "rev": %s' % jrev)
1326 1324 self.ui.write(',\n "node": %s' % jnode)
1327 1325 self.ui.write('\n }')
1328 1326 return
1329 1327
1330 1328 self.ui.write('\n "rev": %s' % jrev)
1331 1329 self.ui.write(',\n "node": %s' % jnode)
1332 1330 self.ui.write(',\n "branch": "%s"' % j(ctx.branch()))
1333 1331 self.ui.write(',\n "phase": "%s"' % ctx.phasestr())
1334 1332 self.ui.write(',\n "user": "%s"' % j(ctx.user()))
1335 1333 self.ui.write(',\n "date": [%d, %d]' % ctx.date())
1336 1334 self.ui.write(',\n "desc": "%s"' % j(ctx.description()))
1337 1335
1338 1336 self.ui.write(',\n "bookmarks": [%s]' %
1339 1337 ", ".join('"%s"' % j(b) for b in ctx.bookmarks()))
1340 1338 self.ui.write(',\n "tags": [%s]' %
1341 1339 ", ".join('"%s"' % j(t) for t in ctx.tags()))
1342 1340 self.ui.write(',\n "parents": [%s]' %
1343 1341 ", ".join('"%s"' % c.hex() for c in ctx.parents()))
1344 1342
1345 1343 if self.ui.debugflag:
1346 1344 if rev is None:
1347 1345 jmanifestnode = 'null'
1348 1346 else:
1349 1347 jmanifestnode = '"%s"' % hex(ctx.manifestnode())
1350 1348 self.ui.write(',\n "manifest": %s' % jmanifestnode)
1351 1349
1352 1350 self.ui.write(',\n "extra": {%s}' %
1353 1351 ", ".join('"%s": "%s"' % (j(k), j(v))
1354 1352 for k, v in ctx.extra().items()))
1355 1353
1356 1354 files = ctx.p1().status(ctx)
1357 1355 self.ui.write(',\n "modified": [%s]' %
1358 1356 ", ".join('"%s"' % j(f) for f in files[0]))
1359 1357 self.ui.write(',\n "added": [%s]' %
1360 1358 ", ".join('"%s"' % j(f) for f in files[1]))
1361 1359 self.ui.write(',\n "removed": [%s]' %
1362 1360 ", ".join('"%s"' % j(f) for f in files[2]))
1363 1361
1364 1362 elif self.ui.verbose:
1365 1363 self.ui.write(',\n "files": [%s]' %
1366 1364 ", ".join('"%s"' % j(f) for f in ctx.files()))
1367 1365
1368 1366 if copies:
1369 1367 self.ui.write(',\n "copies": {%s}' %
1370 1368 ", ".join('"%s": "%s"' % (j(k), j(v))
1371 1369 for k, v in copies))
1372 1370
1373 1371 matchfn = self.matchfn
1374 1372 if matchfn:
1375 1373 stat = self.diffopts.get('stat')
1376 1374 diff = self.diffopts.get('patch')
1377 1375 diffopts = patch.difffeatureopts(self.ui, self.diffopts, git=True)
1378 1376 node, prev = ctx.node(), ctx.p1().node()
1379 1377 if stat:
1380 1378 self.ui.pushbuffer()
1381 1379 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
1382 1380 match=matchfn, stat=True)
1383 1381 self.ui.write(',\n "diffstat": "%s"' % j(self.ui.popbuffer()))
1384 1382 if diff:
1385 1383 self.ui.pushbuffer()
1386 1384 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
1387 1385 match=matchfn, stat=False)
1388 1386 self.ui.write(',\n "diff": "%s"' % j(self.ui.popbuffer()))
1389 1387
1390 1388 self.ui.write("\n }")
1391 1389
1392 1390 class changeset_templater(changeset_printer):
1393 1391 '''format changeset information.'''
1394 1392
1395 1393 def __init__(self, ui, repo, matchfn, diffopts, tmpl, mapfile, buffered):
1396 1394 changeset_printer.__init__(self, ui, repo, matchfn, diffopts, buffered)
1397 1395 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
1398 1396 defaulttempl = {
1399 1397 'parent': '{rev}:{node|formatnode} ',
1400 1398 'manifest': '{rev}:{node|formatnode}',
1401 1399 'file_copy': '{name} ({source})',
1402 1400 'extra': '{key}={value|stringescape}'
1403 1401 }
1404 1402 # filecopy is preserved for compatibility reasons
1405 1403 defaulttempl['filecopy'] = defaulttempl['file_copy']
1406 1404 self.t = templater.templater(mapfile, {'formatnode': formatnode},
1407 1405 cache=defaulttempl)
1408 1406 if tmpl:
1409 1407 self.t.cache['changeset'] = tmpl
1410 1408
1411 1409 self.cache = {}
1412 1410
1413 1411 def _show(self, ctx, copies, matchfn, props):
1414 1412 '''show a single changeset or file revision'''
1415 1413
1416 1414 showlist = templatekw.showlist
1417 1415
1418 1416 # showparents() behaviour depends on ui trace level which
1419 1417 # causes unexpected behaviours at templating level and makes
1420 1418 # it harder to extract it in a standalone function. Its
1421 1419 # behaviour cannot be changed so leave it here for now.
1422 1420 def showparents(**args):
1423 1421 ctx = args['ctx']
1424 1422 parents = [[('rev', p.rev()),
1425 1423 ('node', p.hex()),
1426 1424 ('phase', p.phasestr())]
1427 1425 for p in self._meaningful_parentrevs(ctx)]
1428 1426 return showlist('parent', parents, **args)
1429 1427
1430 1428 props = props.copy()
1431 1429 props.update(templatekw.keywords)
1432 1430 props['parents'] = showparents
1433 1431 props['templ'] = self.t
1434 1432 props['ctx'] = ctx
1435 1433 props['repo'] = self.repo
1436 1434 props['revcache'] = {'copies': copies}
1437 1435 props['cache'] = self.cache
1438 1436
1439 1437 # find correct templates for current mode
1440 1438
1441 1439 tmplmodes = [
1442 1440 (True, None),
1443 1441 (self.ui.verbose, 'verbose'),
1444 1442 (self.ui.quiet, 'quiet'),
1445 1443 (self.ui.debugflag, 'debug'),
1446 1444 ]
1447 1445
1448 1446 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
1449 1447 for mode, postfix in tmplmodes:
1450 1448 for type in types:
1451 1449 cur = postfix and ('%s_%s' % (type, postfix)) or type
1452 1450 if mode and cur in self.t:
1453 1451 types[type] = cur
1454 1452
1455 1453 try:
1456 1454
1457 1455 # write header
1458 1456 if types['header']:
1459 1457 h = templater.stringify(self.t(types['header'], **props))
1460 1458 if self.buffered:
1461 1459 self.header[ctx.rev()] = h
1462 1460 else:
1463 1461 if self.lastheader != h:
1464 1462 self.lastheader = h
1465 1463 self.ui.write(h)
1466 1464
1467 1465 # write changeset metadata, then patch if requested
1468 1466 key = types['changeset']
1469 1467 self.ui.write(templater.stringify(self.t(key, **props)))
1470 1468 self.showpatch(ctx.node(), matchfn)
1471 1469
1472 1470 if types['footer']:
1473 1471 if not self.footer:
1474 1472 self.footer = templater.stringify(self.t(types['footer'],
1475 1473 **props))
1476 1474
1477 1475 except KeyError as inst:
1478 1476 msg = _("%s: no key named '%s'")
1479 1477 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
1480 1478 except SyntaxError as inst:
1481 1479 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
1482 1480
1483 1481 def gettemplate(ui, tmpl, style):
1484 1482 """
1485 1483 Find the template matching the given template spec or style.
1486 1484 """
1487 1485
1488 1486 # ui settings
1489 1487 if not tmpl and not style: # template are stronger than style
1490 1488 tmpl = ui.config('ui', 'logtemplate')
1491 1489 if tmpl:
1492 1490 try:
1493 1491 tmpl = templater.unquotestring(tmpl)
1494 1492 except SyntaxError:
1495 1493 pass
1496 1494 return tmpl, None
1497 1495 else:
1498 1496 style = util.expandpath(ui.config('ui', 'style', ''))
1499 1497
1500 1498 if not tmpl and style:
1501 1499 mapfile = style
1502 1500 if not os.path.split(mapfile)[0]:
1503 1501 mapname = (templater.templatepath('map-cmdline.' + mapfile)
1504 1502 or templater.templatepath(mapfile))
1505 1503 if mapname:
1506 1504 mapfile = mapname
1507 1505 return None, mapfile
1508 1506
1509 1507 if not tmpl:
1510 1508 return None, None
1511 1509
1512 1510 return formatter.lookuptemplate(ui, 'changeset', tmpl)
1513 1511
1514 1512 def show_changeset(ui, repo, opts, buffered=False):
1515 1513 """show one changeset using template or regular display.
1516 1514
1517 1515 Display format will be the first non-empty hit of:
1518 1516 1. option 'template'
1519 1517 2. option 'style'
1520 1518 3. [ui] setting 'logtemplate'
1521 1519 4. [ui] setting 'style'
1522 1520 If all of these values are either the unset or the empty string,
1523 1521 regular display via changeset_printer() is done.
1524 1522 """
1525 1523 # options
1526 1524 matchfn = None
1527 1525 if opts.get('patch') or opts.get('stat'):
1528 1526 matchfn = scmutil.matchall(repo)
1529 1527
1530 1528 if opts.get('template') == 'json':
1531 1529 return jsonchangeset(ui, repo, matchfn, opts, buffered)
1532 1530
1533 1531 tmpl, mapfile = gettemplate(ui, opts.get('template'), opts.get('style'))
1534 1532
1535 1533 if not tmpl and not mapfile:
1536 1534 return changeset_printer(ui, repo, matchfn, opts, buffered)
1537 1535
1538 1536 try:
1539 1537 t = changeset_templater(ui, repo, matchfn, opts, tmpl, mapfile,
1540 1538 buffered)
1541 1539 except SyntaxError as inst:
1542 1540 raise util.Abort(inst.args[0])
1543 1541 return t
1544 1542
1545 1543 def showmarker(ui, marker):
1546 1544 """utility function to display obsolescence marker in a readable way
1547 1545
1548 1546 To be used by debug function."""
1549 1547 ui.write(hex(marker.precnode()))
1550 1548 for repl in marker.succnodes():
1551 1549 ui.write(' ')
1552 1550 ui.write(hex(repl))
1553 1551 ui.write(' %X ' % marker.flags())
1554 1552 parents = marker.parentnodes()
1555 1553 if parents is not None:
1556 1554 ui.write('{%s} ' % ', '.join(hex(p) for p in parents))
1557 1555 ui.write('(%s) ' % util.datestr(marker.date()))
1558 1556 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
1559 1557 sorted(marker.metadata().items())
1560 1558 if t[0] != 'date')))
1561 1559 ui.write('\n')
1562 1560
1563 1561 def finddate(ui, repo, date):
1564 1562 """Find the tipmost changeset that matches the given date spec"""
1565 1563
1566 1564 df = util.matchdate(date)
1567 1565 m = scmutil.matchall(repo)
1568 1566 results = {}
1569 1567
1570 1568 def prep(ctx, fns):
1571 1569 d = ctx.date()
1572 1570 if df(d[0]):
1573 1571 results[ctx.rev()] = d
1574 1572
1575 1573 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
1576 1574 rev = ctx.rev()
1577 1575 if rev in results:
1578 1576 ui.status(_("found revision %s from %s\n") %
1579 1577 (rev, util.datestr(results[rev])))
1580 1578 return str(rev)
1581 1579
1582 1580 raise util.Abort(_("revision matching date not found"))
1583 1581
1584 1582 def increasingwindows(windowsize=8, sizelimit=512):
1585 1583 while True:
1586 1584 yield windowsize
1587 1585 if windowsize < sizelimit:
1588 1586 windowsize *= 2
1589 1587
1590 1588 class FileWalkError(Exception):
1591 1589 pass
1592 1590
1593 1591 def walkfilerevs(repo, match, follow, revs, fncache):
1594 1592 '''Walks the file history for the matched files.
1595 1593
1596 1594 Returns the changeset revs that are involved in the file history.
1597 1595
1598 1596 Throws FileWalkError if the file history can't be walked using
1599 1597 filelogs alone.
1600 1598 '''
1601 1599 wanted = set()
1602 1600 copies = []
1603 1601 minrev, maxrev = min(revs), max(revs)
1604 1602 def filerevgen(filelog, last):
1605 1603 """
1606 1604 Only files, no patterns. Check the history of each file.
1607 1605
1608 1606 Examines filelog entries within minrev, maxrev linkrev range
1609 1607 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1610 1608 tuples in backwards order
1611 1609 """
1612 1610 cl_count = len(repo)
1613 1611 revs = []
1614 1612 for j in xrange(0, last + 1):
1615 1613 linkrev = filelog.linkrev(j)
1616 1614 if linkrev < minrev:
1617 1615 continue
1618 1616 # only yield rev for which we have the changelog, it can
1619 1617 # happen while doing "hg log" during a pull or commit
1620 1618 if linkrev >= cl_count:
1621 1619 break
1622 1620
1623 1621 parentlinkrevs = []
1624 1622 for p in filelog.parentrevs(j):
1625 1623 if p != nullrev:
1626 1624 parentlinkrevs.append(filelog.linkrev(p))
1627 1625 n = filelog.node(j)
1628 1626 revs.append((linkrev, parentlinkrevs,
1629 1627 follow and filelog.renamed(n)))
1630 1628
1631 1629 return reversed(revs)
1632 1630 def iterfiles():
1633 1631 pctx = repo['.']
1634 1632 for filename in match.files():
1635 1633 if follow:
1636 1634 if filename not in pctx:
1637 1635 raise util.Abort(_('cannot follow file not in parent '
1638 1636 'revision: "%s"') % filename)
1639 1637 yield filename, pctx[filename].filenode()
1640 1638 else:
1641 1639 yield filename, None
1642 1640 for filename_node in copies:
1643 1641 yield filename_node
1644 1642
1645 1643 for file_, node in iterfiles():
1646 1644 filelog = repo.file(file_)
1647 1645 if not len(filelog):
1648 1646 if node is None:
1649 1647 # A zero count may be a directory or deleted file, so
1650 1648 # try to find matching entries on the slow path.
1651 1649 if follow:
1652 1650 raise util.Abort(
1653 1651 _('cannot follow nonexistent file: "%s"') % file_)
1654 1652 raise FileWalkError("Cannot walk via filelog")
1655 1653 else:
1656 1654 continue
1657 1655
1658 1656 if node is None:
1659 1657 last = len(filelog) - 1
1660 1658 else:
1661 1659 last = filelog.rev(node)
1662 1660
1663 1661 # keep track of all ancestors of the file
1664 1662 ancestors = set([filelog.linkrev(last)])
1665 1663
1666 1664 # iterate from latest to oldest revision
1667 1665 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1668 1666 if not follow:
1669 1667 if rev > maxrev:
1670 1668 continue
1671 1669 else:
1672 1670 # Note that last might not be the first interesting
1673 1671 # rev to us:
1674 1672 # if the file has been changed after maxrev, we'll
1675 1673 # have linkrev(last) > maxrev, and we still need
1676 1674 # to explore the file graph
1677 1675 if rev not in ancestors:
1678 1676 continue
1679 1677 # XXX insert 1327 fix here
1680 1678 if flparentlinkrevs:
1681 1679 ancestors.update(flparentlinkrevs)
1682 1680
1683 1681 fncache.setdefault(rev, []).append(file_)
1684 1682 wanted.add(rev)
1685 1683 if copied:
1686 1684 copies.append(copied)
1687 1685
1688 1686 return wanted
1689 1687
1690 1688 class _followfilter(object):
1691 1689 def __init__(self, repo, onlyfirst=False):
1692 1690 self.repo = repo
1693 1691 self.startrev = nullrev
1694 1692 self.roots = set()
1695 1693 self.onlyfirst = onlyfirst
1696 1694
1697 1695 def match(self, rev):
1698 1696 def realparents(rev):
1699 1697 if self.onlyfirst:
1700 1698 return self.repo.changelog.parentrevs(rev)[0:1]
1701 1699 else:
1702 1700 return filter(lambda x: x != nullrev,
1703 1701 self.repo.changelog.parentrevs(rev))
1704 1702
1705 1703 if self.startrev == nullrev:
1706 1704 self.startrev = rev
1707 1705 return True
1708 1706
1709 1707 if rev > self.startrev:
1710 1708 # forward: all descendants
1711 1709 if not self.roots:
1712 1710 self.roots.add(self.startrev)
1713 1711 for parent in realparents(rev):
1714 1712 if parent in self.roots:
1715 1713 self.roots.add(rev)
1716 1714 return True
1717 1715 else:
1718 1716 # backwards: all parents
1719 1717 if not self.roots:
1720 1718 self.roots.update(realparents(self.startrev))
1721 1719 if rev in self.roots:
1722 1720 self.roots.remove(rev)
1723 1721 self.roots.update(realparents(rev))
1724 1722 return True
1725 1723
1726 1724 return False
1727 1725
1728 1726 def walkchangerevs(repo, match, opts, prepare):
1729 1727 '''Iterate over files and the revs in which they changed.
1730 1728
1731 1729 Callers most commonly need to iterate backwards over the history
1732 1730 in which they are interested. Doing so has awful (quadratic-looking)
1733 1731 performance, so we use iterators in a "windowed" way.
1734 1732
1735 1733 We walk a window of revisions in the desired order. Within the
1736 1734 window, we first walk forwards to gather data, then in the desired
1737 1735 order (usually backwards) to display it.
1738 1736
1739 1737 This function returns an iterator yielding contexts. Before
1740 1738 yielding each context, the iterator will first call the prepare
1741 1739 function on each context in the window in forward order.'''
1742 1740
1743 1741 follow = opts.get('follow') or opts.get('follow_first')
1744 1742 revs = _logrevs(repo, opts)
1745 1743 if not revs:
1746 1744 return []
1747 1745 wanted = set()
1748 1746 slowpath = match.anypats() or ((match.isexact() or match.prefix()) and
1749 1747 opts.get('removed'))
1750 1748 fncache = {}
1751 1749 change = repo.changectx
1752 1750
1753 1751 # First step is to fill wanted, the set of revisions that we want to yield.
1754 1752 # When it does not induce extra cost, we also fill fncache for revisions in
1755 1753 # wanted: a cache of filenames that were changed (ctx.files()) and that
1756 1754 # match the file filtering conditions.
1757 1755
1758 1756 if match.always():
1759 1757 # No files, no patterns. Display all revs.
1760 1758 wanted = revs
1761 1759 elif not slowpath:
1762 1760 # We only have to read through the filelog to find wanted revisions
1763 1761
1764 1762 try:
1765 1763 wanted = walkfilerevs(repo, match, follow, revs, fncache)
1766 1764 except FileWalkError:
1767 1765 slowpath = True
1768 1766
1769 1767 # We decided to fall back to the slowpath because at least one
1770 1768 # of the paths was not a file. Check to see if at least one of them
1771 1769 # existed in history, otherwise simply return
1772 1770 for path in match.files():
1773 1771 if path == '.' or path in repo.store:
1774 1772 break
1775 1773 else:
1776 1774 return []
1777 1775
1778 1776 if slowpath:
1779 1777 # We have to read the changelog to match filenames against
1780 1778 # changed files
1781 1779
1782 1780 if follow:
1783 1781 raise util.Abort(_('can only follow copies/renames for explicit '
1784 1782 'filenames'))
1785 1783
1786 1784 # The slow path checks files modified in every changeset.
1787 1785 # This is really slow on large repos, so compute the set lazily.
1788 1786 class lazywantedset(object):
1789 1787 def __init__(self):
1790 1788 self.set = set()
1791 1789 self.revs = set(revs)
1792 1790
1793 1791 # No need to worry about locality here because it will be accessed
1794 1792 # in the same order as the increasing window below.
1795 1793 def __contains__(self, value):
1796 1794 if value in self.set:
1797 1795 return True
1798 1796 elif not value in self.revs:
1799 1797 return False
1800 1798 else:
1801 1799 self.revs.discard(value)
1802 1800 ctx = change(value)
1803 1801 matches = filter(match, ctx.files())
1804 1802 if matches:
1805 1803 fncache[value] = matches
1806 1804 self.set.add(value)
1807 1805 return True
1808 1806 return False
1809 1807
1810 1808 def discard(self, value):
1811 1809 self.revs.discard(value)
1812 1810 self.set.discard(value)
1813 1811
1814 1812 wanted = lazywantedset()
1815 1813
1816 1814 # it might be worthwhile to do this in the iterator if the rev range
1817 1815 # is descending and the prune args are all within that range
1818 1816 for rev in opts.get('prune', ()):
1819 1817 rev = repo[rev].rev()
1820 1818 ff = _followfilter(repo)
1821 1819 stop = min(revs[0], revs[-1])
1822 1820 for x in xrange(rev, stop - 1, -1):
1823 1821 if ff.match(x):
1824 1822 wanted = wanted - [x]
1825 1823
1826 1824 # Now that wanted is correctly initialized, we can iterate over the
1827 1825 # revision range, yielding only revisions in wanted.
1828 1826 def iterate():
1829 1827 if follow and match.always():
1830 1828 ff = _followfilter(repo, onlyfirst=opts.get('follow_first'))
1831 1829 def want(rev):
1832 1830 return ff.match(rev) and rev in wanted
1833 1831 else:
1834 1832 def want(rev):
1835 1833 return rev in wanted
1836 1834
1837 1835 it = iter(revs)
1838 1836 stopiteration = False
1839 1837 for windowsize in increasingwindows():
1840 1838 nrevs = []
1841 1839 for i in xrange(windowsize):
1842 1840 rev = next(it, None)
1843 1841 if rev is None:
1844 1842 stopiteration = True
1845 1843 break
1846 1844 elif want(rev):
1847 1845 nrevs.append(rev)
1848 1846 for rev in sorted(nrevs):
1849 1847 fns = fncache.get(rev)
1850 1848 ctx = change(rev)
1851 1849 if not fns:
1852 1850 def fns_generator():
1853 1851 for f in ctx.files():
1854 1852 if match(f):
1855 1853 yield f
1856 1854 fns = fns_generator()
1857 1855 prepare(ctx, fns)
1858 1856 for rev in nrevs:
1859 1857 yield change(rev)
1860 1858
1861 1859 if stopiteration:
1862 1860 break
1863 1861
1864 1862 return iterate()
1865 1863
1866 1864 def _makefollowlogfilematcher(repo, files, followfirst):
1867 1865 # When displaying a revision with --patch --follow FILE, we have
1868 1866 # to know which file of the revision must be diffed. With
1869 1867 # --follow, we want the names of the ancestors of FILE in the
1870 1868 # revision, stored in "fcache". "fcache" is populated by
1871 1869 # reproducing the graph traversal already done by --follow revset
1872 1870 # and relating linkrevs to file names (which is not "correct" but
1873 1871 # good enough).
1874 1872 fcache = {}
1875 1873 fcacheready = [False]
1876 1874 pctx = repo['.']
1877 1875
1878 1876 def populate():
1879 1877 for fn in files:
1880 1878 for i in ((pctx[fn],), pctx[fn].ancestors(followfirst=followfirst)):
1881 1879 for c in i:
1882 1880 fcache.setdefault(c.linkrev(), set()).add(c.path())
1883 1881
1884 1882 def filematcher(rev):
1885 1883 if not fcacheready[0]:
1886 1884 # Lazy initialization
1887 1885 fcacheready[0] = True
1888 1886 populate()
1889 1887 return scmutil.matchfiles(repo, fcache.get(rev, []))
1890 1888
1891 1889 return filematcher
1892 1890
1893 1891 def _makenofollowlogfilematcher(repo, pats, opts):
1894 1892 '''hook for extensions to override the filematcher for non-follow cases'''
1895 1893 return None
1896 1894
1897 1895 def _makelogrevset(repo, pats, opts, revs):
1898 1896 """Return (expr, filematcher) where expr is a revset string built
1899 1897 from log options and file patterns or None. If --stat or --patch
1900 1898 are not passed filematcher is None. Otherwise it is a callable
1901 1899 taking a revision number and returning a match objects filtering
1902 1900 the files to be detailed when displaying the revision.
1903 1901 """
1904 1902 opt2revset = {
1905 1903 'no_merges': ('not merge()', None),
1906 1904 'only_merges': ('merge()', None),
1907 1905 '_ancestors': ('ancestors(%(val)s)', None),
1908 1906 '_fancestors': ('_firstancestors(%(val)s)', None),
1909 1907 '_descendants': ('descendants(%(val)s)', None),
1910 1908 '_fdescendants': ('_firstdescendants(%(val)s)', None),
1911 1909 '_matchfiles': ('_matchfiles(%(val)s)', None),
1912 1910 'date': ('date(%(val)r)', None),
1913 1911 'branch': ('branch(%(val)r)', ' or '),
1914 1912 '_patslog': ('filelog(%(val)r)', ' or '),
1915 1913 '_patsfollow': ('follow(%(val)r)', ' or '),
1916 1914 '_patsfollowfirst': ('_followfirst(%(val)r)', ' or '),
1917 1915 'keyword': ('keyword(%(val)r)', ' or '),
1918 1916 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '),
1919 1917 'user': ('user(%(val)r)', ' or '),
1920 1918 }
1921 1919
1922 1920 opts = dict(opts)
1923 1921 # follow or not follow?
1924 1922 follow = opts.get('follow') or opts.get('follow_first')
1925 1923 if opts.get('follow_first'):
1926 1924 followfirst = 1
1927 1925 else:
1928 1926 followfirst = 0
1929 1927 # --follow with FILE behaviour depends on revs...
1930 1928 it = iter(revs)
1931 1929 startrev = it.next()
1932 1930 followdescendants = startrev < next(it, startrev)
1933 1931
1934 1932 # branch and only_branch are really aliases and must be handled at
1935 1933 # the same time
1936 1934 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
1937 1935 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
1938 1936 # pats/include/exclude are passed to match.match() directly in
1939 1937 # _matchfiles() revset but walkchangerevs() builds its matcher with
1940 1938 # scmutil.match(). The difference is input pats are globbed on
1941 1939 # platforms without shell expansion (windows).
1942 1940 wctx = repo[None]
1943 1941 match, pats = scmutil.matchandpats(wctx, pats, opts)
1944 1942 slowpath = match.anypats() or ((match.isexact() or match.prefix()) and
1945 1943 opts.get('removed'))
1946 1944 if not slowpath:
1947 1945 for f in match.files():
1948 1946 if follow and f not in wctx:
1949 1947 # If the file exists, it may be a directory, so let it
1950 1948 # take the slow path.
1951 1949 if os.path.exists(repo.wjoin(f)):
1952 1950 slowpath = True
1953 1951 continue
1954 1952 else:
1955 1953 raise util.Abort(_('cannot follow file not in parent '
1956 1954 'revision: "%s"') % f)
1957 1955 filelog = repo.file(f)
1958 1956 if not filelog:
1959 1957 # A zero count may be a directory or deleted file, so
1960 1958 # try to find matching entries on the slow path.
1961 1959 if follow:
1962 1960 raise util.Abort(
1963 1961 _('cannot follow nonexistent file: "%s"') % f)
1964 1962 slowpath = True
1965 1963
1966 1964 # We decided to fall back to the slowpath because at least one
1967 1965 # of the paths was not a file. Check to see if at least one of them
1968 1966 # existed in history - in that case, we'll continue down the
1969 1967 # slowpath; otherwise, we can turn off the slowpath
1970 1968 if slowpath:
1971 1969 for path in match.files():
1972 1970 if path == '.' or path in repo.store:
1973 1971 break
1974 1972 else:
1975 1973 slowpath = False
1976 1974
1977 1975 fpats = ('_patsfollow', '_patsfollowfirst')
1978 1976 fnopats = (('_ancestors', '_fancestors'),
1979 1977 ('_descendants', '_fdescendants'))
1980 1978 if slowpath:
1981 1979 # See walkchangerevs() slow path.
1982 1980 #
1983 1981 # pats/include/exclude cannot be represented as separate
1984 1982 # revset expressions as their filtering logic applies at file
1985 1983 # level. For instance "-I a -X a" matches a revision touching
1986 1984 # "a" and "b" while "file(a) and not file(b)" does
1987 1985 # not. Besides, filesets are evaluated against the working
1988 1986 # directory.
1989 1987 matchargs = ['r:', 'd:relpath']
1990 1988 for p in pats:
1991 1989 matchargs.append('p:' + p)
1992 1990 for p in opts.get('include', []):
1993 1991 matchargs.append('i:' + p)
1994 1992 for p in opts.get('exclude', []):
1995 1993 matchargs.append('x:' + p)
1996 1994 matchargs = ','.join(('%r' % p) for p in matchargs)
1997 1995 opts['_matchfiles'] = matchargs
1998 1996 if follow:
1999 1997 opts[fnopats[0][followfirst]] = '.'
2000 1998 else:
2001 1999 if follow:
2002 2000 if pats:
2003 2001 # follow() revset interprets its file argument as a
2004 2002 # manifest entry, so use match.files(), not pats.
2005 2003 opts[fpats[followfirst]] = list(match.files())
2006 2004 else:
2007 2005 op = fnopats[followdescendants][followfirst]
2008 2006 opts[op] = 'rev(%d)' % startrev
2009 2007 else:
2010 2008 opts['_patslog'] = list(pats)
2011 2009
2012 2010 filematcher = None
2013 2011 if opts.get('patch') or opts.get('stat'):
2014 2012 # When following files, track renames via a special matcher.
2015 2013 # If we're forced to take the slowpath it means we're following
2016 2014 # at least one pattern/directory, so don't bother with rename tracking.
2017 2015 if follow and not match.always() and not slowpath:
2018 2016 # _makefollowlogfilematcher expects its files argument to be
2019 2017 # relative to the repo root, so use match.files(), not pats.
2020 2018 filematcher = _makefollowlogfilematcher(repo, match.files(),
2021 2019 followfirst)
2022 2020 else:
2023 2021 filematcher = _makenofollowlogfilematcher(repo, pats, opts)
2024 2022 if filematcher is None:
2025 2023 filematcher = lambda rev: match
2026 2024
2027 2025 expr = []
2028 2026 for op, val in sorted(opts.iteritems()):
2029 2027 if not val:
2030 2028 continue
2031 2029 if op not in opt2revset:
2032 2030 continue
2033 2031 revop, andor = opt2revset[op]
2034 2032 if '%(val)' not in revop:
2035 2033 expr.append(revop)
2036 2034 else:
2037 2035 if not isinstance(val, list):
2038 2036 e = revop % {'val': val}
2039 2037 else:
2040 2038 e = '(' + andor.join((revop % {'val': v}) for v in val) + ')'
2041 2039 expr.append(e)
2042 2040
2043 2041 if expr:
2044 2042 expr = '(' + ' and '.join(expr) + ')'
2045 2043 else:
2046 2044 expr = None
2047 2045 return expr, filematcher
2048 2046
2049 2047 def _logrevs(repo, opts):
2050 2048 # Default --rev value depends on --follow but --follow behaviour
2051 2049 # depends on revisions resolved from --rev...
2052 2050 follow = opts.get('follow') or opts.get('follow_first')
2053 2051 if opts.get('rev'):
2054 2052 revs = scmutil.revrange(repo, opts['rev'])
2055 2053 elif follow and repo.dirstate.p1() == nullid:
2056 2054 revs = revset.baseset()
2057 2055 elif follow:
2058 2056 revs = repo.revs('reverse(:.)')
2059 2057 else:
2060 2058 revs = revset.spanset(repo)
2061 2059 revs.reverse()
2062 2060 return revs
2063 2061
2064 2062 def getgraphlogrevs(repo, pats, opts):
2065 2063 """Return (revs, expr, filematcher) where revs is an iterable of
2066 2064 revision numbers, expr is a revset string built from log options
2067 2065 and file patterns or None, and used to filter 'revs'. If --stat or
2068 2066 --patch are not passed filematcher is None. Otherwise it is a
2069 2067 callable taking a revision number and returning a match objects
2070 2068 filtering the files to be detailed when displaying the revision.
2071 2069 """
2072 2070 limit = loglimit(opts)
2073 2071 revs = _logrevs(repo, opts)
2074 2072 if not revs:
2075 2073 return revset.baseset(), None, None
2076 2074 expr, filematcher = _makelogrevset(repo, pats, opts, revs)
2077 2075 if opts.get('rev'):
2078 2076 # User-specified revs might be unsorted, but don't sort before
2079 2077 # _makelogrevset because it might depend on the order of revs
2080 2078 revs.sort(reverse=True)
2081 2079 if expr:
2082 2080 # Revset matchers often operate faster on revisions in changelog
2083 2081 # order, because most filters deal with the changelog.
2084 2082 revs.reverse()
2085 2083 matcher = revset.match(repo.ui, expr)
2086 2084 # Revset matches can reorder revisions. "A or B" typically returns
2087 2085 # returns the revision matching A then the revision matching B. Sort
2088 2086 # again to fix that.
2089 2087 revs = matcher(repo, revs)
2090 2088 revs.sort(reverse=True)
2091 2089 if limit is not None:
2092 2090 limitedrevs = []
2093 2091 for idx, rev in enumerate(revs):
2094 2092 if idx >= limit:
2095 2093 break
2096 2094 limitedrevs.append(rev)
2097 2095 revs = revset.baseset(limitedrevs)
2098 2096
2099 2097 return revs, expr, filematcher
2100 2098
2101 2099 def getlogrevs(repo, pats, opts):
2102 2100 """Return (revs, expr, filematcher) where revs is an iterable of
2103 2101 revision numbers, expr is a revset string built from log options
2104 2102 and file patterns or None, and used to filter 'revs'. If --stat or
2105 2103 --patch are not passed filematcher is None. Otherwise it is a
2106 2104 callable taking a revision number and returning a match objects
2107 2105 filtering the files to be detailed when displaying the revision.
2108 2106 """
2109 2107 limit = loglimit(opts)
2110 2108 revs = _logrevs(repo, opts)
2111 2109 if not revs:
2112 2110 return revset.baseset([]), None, None
2113 2111 expr, filematcher = _makelogrevset(repo, pats, opts, revs)
2114 2112 if expr:
2115 2113 # Revset matchers often operate faster on revisions in changelog
2116 2114 # order, because most filters deal with the changelog.
2117 2115 if not opts.get('rev'):
2118 2116 revs.reverse()
2119 2117 matcher = revset.match(repo.ui, expr)
2120 2118 # Revset matches can reorder revisions. "A or B" typically returns
2121 2119 # returns the revision matching A then the revision matching B. Sort
2122 2120 # again to fix that.
2123 2121 revs = matcher(repo, revs)
2124 2122 if not opts.get('rev'):
2125 2123 revs.sort(reverse=True)
2126 2124 if limit is not None:
2127 2125 limitedrevs = []
2128 2126 for idx, r in enumerate(revs):
2129 2127 if limit <= idx:
2130 2128 break
2131 2129 limitedrevs.append(r)
2132 2130 revs = revset.baseset(limitedrevs)
2133 2131
2134 2132 return revs, expr, filematcher
2135 2133
2136 2134 def displaygraph(ui, dag, displayer, showparents, edgefn, getrenamed=None,
2137 2135 filematcher=None):
2138 2136 seen, state = [], graphmod.asciistate()
2139 2137 for rev, type, ctx, parents in dag:
2140 2138 char = 'o'
2141 2139 if ctx.node() in showparents:
2142 2140 char = '@'
2143 2141 elif ctx.obsolete():
2144 2142 char = 'x'
2145 2143 elif ctx.closesbranch():
2146 2144 char = '_'
2147 2145 copies = None
2148 2146 if getrenamed and ctx.rev():
2149 2147 copies = []
2150 2148 for fn in ctx.files():
2151 2149 rename = getrenamed(fn, ctx.rev())
2152 2150 if rename:
2153 2151 copies.append((fn, rename[0]))
2154 2152 revmatchfn = None
2155 2153 if filematcher is not None:
2156 2154 revmatchfn = filematcher(ctx.rev())
2157 2155 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2158 2156 lines = displayer.hunk.pop(rev).split('\n')
2159 2157 if not lines[-1]:
2160 2158 del lines[-1]
2161 2159 displayer.flush(rev)
2162 2160 edges = edgefn(type, char, lines, seen, rev, parents)
2163 2161 for type, char, lines, coldata in edges:
2164 2162 graphmod.ascii(ui, state, type, char, lines, coldata)
2165 2163 displayer.close()
2166 2164
2167 2165 def graphlog(ui, repo, *pats, **opts):
2168 2166 # Parameters are identical to log command ones
2169 2167 revs, expr, filematcher = getgraphlogrevs(repo, pats, opts)
2170 2168 revdag = graphmod.dagwalker(repo, revs)
2171 2169
2172 2170 getrenamed = None
2173 2171 if opts.get('copies'):
2174 2172 endrev = None
2175 2173 if opts.get('rev'):
2176 2174 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
2177 2175 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2178 2176 displayer = show_changeset(ui, repo, opts, buffered=True)
2179 2177 showparents = [ctx.node() for ctx in repo[None].parents()]
2180 2178 displaygraph(ui, revdag, displayer, showparents,
2181 2179 graphmod.asciiedges, getrenamed, filematcher)
2182 2180
2183 2181 def checkunsupportedgraphflags(pats, opts):
2184 2182 for op in ["newest_first"]:
2185 2183 if op in opts and opts[op]:
2186 2184 raise util.Abort(_("-G/--graph option is incompatible with --%s")
2187 2185 % op.replace("_", "-"))
2188 2186
2189 2187 def graphrevs(repo, nodes, opts):
2190 2188 limit = loglimit(opts)
2191 2189 nodes.reverse()
2192 2190 if limit is not None:
2193 2191 nodes = nodes[:limit]
2194 2192 return graphmod.nodes(repo, nodes)
2195 2193
2196 2194 def add(ui, repo, match, prefix, explicitonly, **opts):
2197 2195 join = lambda f: os.path.join(prefix, f)
2198 2196 bad = []
2199 2197
2200 2198 badfn = lambda x, y: bad.append(x) or match.bad(x, y)
2201 2199 names = []
2202 2200 wctx = repo[None]
2203 2201 cca = None
2204 2202 abort, warn = scmutil.checkportabilityalert(ui)
2205 2203 if abort or warn:
2206 2204 cca = scmutil.casecollisionauditor(ui, abort, repo.dirstate)
2207 2205
2208 2206 for f in wctx.walk(matchmod.badmatch(match, badfn)):
2209 2207 exact = match.exact(f)
2210 2208 if exact or not explicitonly and f not in wctx and repo.wvfs.lexists(f):
2211 2209 if cca:
2212 2210 cca(f)
2213 2211 names.append(f)
2214 2212 if ui.verbose or not exact:
2215 2213 ui.status(_('adding %s\n') % match.rel(f))
2216 2214
2217 2215 for subpath in sorted(wctx.substate):
2218 2216 sub = wctx.sub(subpath)
2219 2217 try:
2220 2218 submatch = matchmod.narrowmatcher(subpath, match)
2221 2219 if opts.get('subrepos'):
2222 2220 bad.extend(sub.add(ui, submatch, prefix, False, **opts))
2223 2221 else:
2224 2222 bad.extend(sub.add(ui, submatch, prefix, True, **opts))
2225 2223 except error.LookupError:
2226 2224 ui.status(_("skipping missing subrepository: %s\n")
2227 2225 % join(subpath))
2228 2226
2229 2227 if not opts.get('dry_run'):
2230 2228 rejected = wctx.add(names, prefix)
2231 2229 bad.extend(f for f in rejected if f in match.files())
2232 2230 return bad
2233 2231
2234 2232 def forget(ui, repo, match, prefix, explicitonly):
2235 2233 join = lambda f: os.path.join(prefix, f)
2236 2234 bad = []
2237 2235 badfn = lambda x, y: bad.append(x) or match.bad(x, y)
2238 2236 wctx = repo[None]
2239 2237 forgot = []
2240 2238
2241 2239 s = repo.status(match=matchmod.badmatch(match, badfn), clean=True)
2242 2240 forget = sorted(s[0] + s[1] + s[3] + s[6])
2243 2241 if explicitonly:
2244 2242 forget = [f for f in forget if match.exact(f)]
2245 2243
2246 2244 for subpath in sorted(wctx.substate):
2247 2245 sub = wctx.sub(subpath)
2248 2246 try:
2249 2247 submatch = matchmod.narrowmatcher(subpath, match)
2250 2248 subbad, subforgot = sub.forget(submatch, prefix)
2251 2249 bad.extend([subpath + '/' + f for f in subbad])
2252 2250 forgot.extend([subpath + '/' + f for f in subforgot])
2253 2251 except error.LookupError:
2254 2252 ui.status(_("skipping missing subrepository: %s\n")
2255 2253 % join(subpath))
2256 2254
2257 2255 if not explicitonly:
2258 2256 for f in match.files():
2259 2257 if f not in repo.dirstate and not repo.wvfs.isdir(f):
2260 2258 if f not in forgot:
2261 2259 if repo.wvfs.exists(f):
2262 2260 # Don't complain if the exact case match wasn't given.
2263 2261 # But don't do this until after checking 'forgot', so
2264 2262 # that subrepo files aren't normalized, and this op is
2265 2263 # purely from data cached by the status walk above.
2266 2264 if repo.dirstate.normalize(f) in repo.dirstate:
2267 2265 continue
2268 2266 ui.warn(_('not removing %s: '
2269 2267 'file is already untracked\n')
2270 2268 % match.rel(f))
2271 2269 bad.append(f)
2272 2270
2273 2271 for f in forget:
2274 2272 if ui.verbose or not match.exact(f):
2275 2273 ui.status(_('removing %s\n') % match.rel(f))
2276 2274
2277 2275 rejected = wctx.forget(forget, prefix)
2278 2276 bad.extend(f for f in rejected if f in match.files())
2279 2277 forgot.extend(f for f in forget if f not in rejected)
2280 2278 return bad, forgot
2281 2279
2282 2280 def files(ui, ctx, m, fm, fmt, subrepos):
2283 2281 rev = ctx.rev()
2284 2282 ret = 1
2285 2283 ds = ctx.repo().dirstate
2286 2284
2287 2285 for f in ctx.matches(m):
2288 2286 if rev is None and ds[f] == 'r':
2289 2287 continue
2290 2288 fm.startitem()
2291 2289 if ui.verbose:
2292 2290 fc = ctx[f]
2293 2291 fm.write('size flags', '% 10d % 1s ', fc.size(), fc.flags())
2294 2292 fm.data(abspath=f)
2295 2293 fm.write('path', fmt, m.rel(f))
2296 2294 ret = 0
2297 2295
2298 2296 for subpath in sorted(ctx.substate):
2299 2297 def matchessubrepo(subpath):
2300 2298 return (m.always() or m.exact(subpath)
2301 2299 or any(f.startswith(subpath + '/') for f in m.files()))
2302 2300
2303 2301 if subrepos or matchessubrepo(subpath):
2304 2302 sub = ctx.sub(subpath)
2305 2303 try:
2306 2304 submatch = matchmod.narrowmatcher(subpath, m)
2307 2305 if sub.printfiles(ui, submatch, fm, fmt, subrepos) == 0:
2308 2306 ret = 0
2309 2307 except error.LookupError:
2310 2308 ui.status(_("skipping missing subrepository: %s\n")
2311 2309 % m.abs(subpath))
2312 2310
2313 2311 return ret
2314 2312
2315 2313 def remove(ui, repo, m, prefix, after, force, subrepos):
2316 2314 join = lambda f: os.path.join(prefix, f)
2317 2315 ret = 0
2318 2316 s = repo.status(match=m, clean=True)
2319 2317 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2320 2318
2321 2319 wctx = repo[None]
2322 2320
2323 2321 for subpath in sorted(wctx.substate):
2324 2322 def matchessubrepo(matcher, subpath):
2325 2323 if matcher.exact(subpath):
2326 2324 return True
2327 2325 for f in matcher.files():
2328 2326 if f.startswith(subpath):
2329 2327 return True
2330 2328 return False
2331 2329
2332 2330 if subrepos or matchessubrepo(m, subpath):
2333 2331 sub = wctx.sub(subpath)
2334 2332 try:
2335 2333 submatch = matchmod.narrowmatcher(subpath, m)
2336 2334 if sub.removefiles(submatch, prefix, after, force, subrepos):
2337 2335 ret = 1
2338 2336 except error.LookupError:
2339 2337 ui.status(_("skipping missing subrepository: %s\n")
2340 2338 % join(subpath))
2341 2339
2342 2340 # warn about failure to delete explicit files/dirs
2343 2341 deleteddirs = util.dirs(deleted)
2344 2342 for f in m.files():
2345 2343 def insubrepo():
2346 2344 for subpath in wctx.substate:
2347 2345 if f.startswith(subpath):
2348 2346 return True
2349 2347 return False
2350 2348
2351 2349 isdir = f in deleteddirs or wctx.hasdir(f)
2352 2350 if f in repo.dirstate or isdir or f == '.' or insubrepo():
2353 2351 continue
2354 2352
2355 2353 if repo.wvfs.exists(f):
2356 2354 if repo.wvfs.isdir(f):
2357 2355 ui.warn(_('not removing %s: no tracked files\n')
2358 2356 % m.rel(f))
2359 2357 else:
2360 2358 ui.warn(_('not removing %s: file is untracked\n')
2361 2359 % m.rel(f))
2362 2360 # missing files will generate a warning elsewhere
2363 2361 ret = 1
2364 2362
2365 2363 if force:
2366 2364 list = modified + deleted + clean + added
2367 2365 elif after:
2368 2366 list = deleted
2369 2367 for f in modified + added + clean:
2370 2368 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
2371 2369 ret = 1
2372 2370 else:
2373 2371 list = deleted + clean
2374 2372 for f in modified:
2375 2373 ui.warn(_('not removing %s: file is modified (use -f'
2376 2374 ' to force removal)\n') % m.rel(f))
2377 2375 ret = 1
2378 2376 for f in added:
2379 2377 ui.warn(_('not removing %s: file has been marked for add'
2380 2378 ' (use forget to undo)\n') % m.rel(f))
2381 2379 ret = 1
2382 2380
2383 2381 for f in sorted(list):
2384 2382 if ui.verbose or not m.exact(f):
2385 2383 ui.status(_('removing %s\n') % m.rel(f))
2386 2384
2387 2385 wlock = repo.wlock()
2388 2386 try:
2389 2387 if not after:
2390 2388 for f in list:
2391 2389 if f in added:
2392 2390 continue # we never unlink added files on remove
2393 2391 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
2394 2392 repo[None].forget(list)
2395 2393 finally:
2396 2394 wlock.release()
2397 2395
2398 2396 return ret
2399 2397
2400 2398 def cat(ui, repo, ctx, matcher, prefix, **opts):
2401 2399 err = 1
2402 2400
2403 2401 def write(path):
2404 2402 fp = makefileobj(repo, opts.get('output'), ctx.node(),
2405 2403 pathname=os.path.join(prefix, path))
2406 2404 data = ctx[path].data()
2407 2405 if opts.get('decode'):
2408 2406 data = repo.wwritedata(path, data)
2409 2407 fp.write(data)
2410 2408 fp.close()
2411 2409
2412 2410 # Automation often uses hg cat on single files, so special case it
2413 2411 # for performance to avoid the cost of parsing the manifest.
2414 2412 if len(matcher.files()) == 1 and not matcher.anypats():
2415 2413 file = matcher.files()[0]
2416 2414 mf = repo.manifest
2417 2415 mfnode = ctx.manifestnode()
2418 2416 if mfnode and mf.find(mfnode, file)[0]:
2419 2417 write(file)
2420 2418 return 0
2421 2419
2422 2420 # Don't warn about "missing" files that are really in subrepos
2423 2421 def badfn(path, msg):
2424 2422 for subpath in ctx.substate:
2425 2423 if path.startswith(subpath):
2426 2424 return
2427 2425 matcher.bad(path, msg)
2428 2426
2429 2427 for abs in ctx.walk(matchmod.badmatch(matcher, badfn)):
2430 2428 write(abs)
2431 2429 err = 0
2432 2430
2433 2431 for subpath in sorted(ctx.substate):
2434 2432 sub = ctx.sub(subpath)
2435 2433 try:
2436 2434 submatch = matchmod.narrowmatcher(subpath, matcher)
2437 2435
2438 2436 if not sub.cat(submatch, os.path.join(prefix, sub._path),
2439 2437 **opts):
2440 2438 err = 0
2441 2439 except error.RepoLookupError:
2442 2440 ui.status(_("skipping missing subrepository: %s\n")
2443 2441 % os.path.join(prefix, subpath))
2444 2442
2445 2443 return err
2446 2444
2447 2445 def commit(ui, repo, commitfunc, pats, opts):
2448 2446 '''commit the specified files or all outstanding changes'''
2449 2447 date = opts.get('date')
2450 2448 if date:
2451 2449 opts['date'] = util.parsedate(date)
2452 2450 message = logmessage(ui, opts)
2453 2451 matcher = scmutil.match(repo[None], pats, opts)
2454 2452
2455 2453 # extract addremove carefully -- this function can be called from a command
2456 2454 # that doesn't support addremove
2457 2455 if opts.get('addremove'):
2458 2456 if scmutil.addremove(repo, matcher, "", opts) != 0:
2459 2457 raise util.Abort(
2460 2458 _("failed to mark all new/missing files as added/removed"))
2461 2459
2462 2460 return commitfunc(ui, repo, message, matcher, opts)
2463 2461
2464 2462 def amend(ui, repo, commitfunc, old, extra, pats, opts):
2465 2463 # amend will reuse the existing user if not specified, but the obsolete
2466 2464 # marker creation requires that the current user's name is specified.
2467 2465 if obsolete.isenabled(repo, obsolete.createmarkersopt):
2468 2466 ui.username() # raise exception if username not set
2469 2467
2470 2468 ui.note(_('amending changeset %s\n') % old)
2471 2469 base = old.p1()
2472 2470 createmarkers = obsolete.isenabled(repo, obsolete.createmarkersopt)
2473 2471
2474 2472 wlock = dsguard = lock = newid = None
2475 2473 try:
2476 2474 wlock = repo.wlock()
2477 2475 dsguard = dirstateguard(repo, 'amend')
2478 2476 lock = repo.lock()
2479 2477 tr = repo.transaction('amend')
2480 2478 try:
2481 2479 # See if we got a message from -m or -l, if not, open the editor
2482 2480 # with the message of the changeset to amend
2483 2481 message = logmessage(ui, opts)
2484 2482 # ensure logfile does not conflict with later enforcement of the
2485 2483 # message. potential logfile content has been processed by
2486 2484 # `logmessage` anyway.
2487 2485 opts.pop('logfile')
2488 2486 # First, do a regular commit to record all changes in the working
2489 2487 # directory (if there are any)
2490 2488 ui.callhooks = False
2491 2489 activebookmark = repo._activebookmark
2492 2490 try:
2493 2491 repo._activebookmark = None
2494 2492 opts['message'] = 'temporary amend commit for %s' % old
2495 2493 node = commit(ui, repo, commitfunc, pats, opts)
2496 2494 finally:
2497 2495 repo._activebookmark = activebookmark
2498 2496 ui.callhooks = True
2499 2497 ctx = repo[node]
2500 2498
2501 2499 # Participating changesets:
2502 2500 #
2503 2501 # node/ctx o - new (intermediate) commit that contains changes
2504 2502 # | from working dir to go into amending commit
2505 2503 # | (or a workingctx if there were no changes)
2506 2504 # |
2507 2505 # old o - changeset to amend
2508 2506 # |
2509 2507 # base o - parent of amending changeset
2510 2508
2511 2509 # Update extra dict from amended commit (e.g. to preserve graft
2512 2510 # source)
2513 2511 extra.update(old.extra())
2514 2512
2515 2513 # Also update it from the intermediate commit or from the wctx
2516 2514 extra.update(ctx.extra())
2517 2515
2518 2516 if len(old.parents()) > 1:
2519 2517 # ctx.files() isn't reliable for merges, so fall back to the
2520 2518 # slower repo.status() method
2521 2519 files = set([fn for st in repo.status(base, old)[:3]
2522 2520 for fn in st])
2523 2521 else:
2524 2522 files = set(old.files())
2525 2523
2526 2524 # Second, we use either the commit we just did, or if there were no
2527 2525 # changes the parent of the working directory as the version of the
2528 2526 # files in the final amend commit
2529 2527 if node:
2530 2528 ui.note(_('copying changeset %s to %s\n') % (ctx, base))
2531 2529
2532 2530 user = ctx.user()
2533 2531 date = ctx.date()
2534 2532 # Recompute copies (avoid recording a -> b -> a)
2535 2533 copied = copies.pathcopies(base, ctx)
2536 2534 if old.p2:
2537 2535 copied.update(copies.pathcopies(old.p2(), ctx))
2538 2536
2539 2537 # Prune files which were reverted by the updates: if old
2540 2538 # introduced file X and our intermediate commit, node,
2541 2539 # renamed that file, then those two files are the same and
2542 2540 # we can discard X from our list of files. Likewise if X
2543 2541 # was deleted, it's no longer relevant
2544 2542 files.update(ctx.files())
2545 2543
2546 2544 def samefile(f):
2547 2545 if f in ctx.manifest():
2548 2546 a = ctx.filectx(f)
2549 2547 if f in base.manifest():
2550 2548 b = base.filectx(f)
2551 2549 return (not a.cmp(b)
2552 2550 and a.flags() == b.flags())
2553 2551 else:
2554 2552 return False
2555 2553 else:
2556 2554 return f not in base.manifest()
2557 2555 files = [f for f in files if not samefile(f)]
2558 2556
2559 2557 def filectxfn(repo, ctx_, path):
2560 2558 try:
2561 2559 fctx = ctx[path]
2562 2560 flags = fctx.flags()
2563 2561 mctx = context.memfilectx(repo,
2564 2562 fctx.path(), fctx.data(),
2565 2563 islink='l' in flags,
2566 2564 isexec='x' in flags,
2567 2565 copied=copied.get(path))
2568 2566 return mctx
2569 2567 except KeyError:
2570 2568 return None
2571 2569 else:
2572 2570 ui.note(_('copying changeset %s to %s\n') % (old, base))
2573 2571
2574 2572 # Use version of files as in the old cset
2575 2573 def filectxfn(repo, ctx_, path):
2576 2574 try:
2577 2575 return old.filectx(path)
2578 2576 except KeyError:
2579 2577 return None
2580 2578
2581 2579 user = opts.get('user') or old.user()
2582 2580 date = opts.get('date') or old.date()
2583 2581 editform = mergeeditform(old, 'commit.amend')
2584 2582 editor = getcommiteditor(editform=editform, **opts)
2585 2583 if not message:
2586 2584 editor = getcommiteditor(edit=True, editform=editform)
2587 2585 message = old.description()
2588 2586
2589 2587 pureextra = extra.copy()
2590 2588 extra['amend_source'] = old.hex()
2591 2589
2592 2590 new = context.memctx(repo,
2593 2591 parents=[base.node(), old.p2().node()],
2594 2592 text=message,
2595 2593 files=files,
2596 2594 filectxfn=filectxfn,
2597 2595 user=user,
2598 2596 date=date,
2599 2597 extra=extra,
2600 2598 editor=editor)
2601 2599
2602 2600 newdesc = changelog.stripdesc(new.description())
2603 2601 if ((not node)
2604 2602 and newdesc == old.description()
2605 2603 and user == old.user()
2606 2604 and date == old.date()
2607 2605 and pureextra == old.extra()):
2608 2606 # nothing changed. continuing here would create a new node
2609 2607 # anyway because of the amend_source noise.
2610 2608 #
2611 2609 # This not what we expect from amend.
2612 2610 return old.node()
2613 2611
2614 2612 ph = repo.ui.config('phases', 'new-commit', phases.draft)
2615 2613 try:
2616 2614 if opts.get('secret'):
2617 2615 commitphase = 'secret'
2618 2616 else:
2619 2617 commitphase = old.phase()
2620 2618 repo.ui.setconfig('phases', 'new-commit', commitphase, 'amend')
2621 2619 newid = repo.commitctx(new)
2622 2620 finally:
2623 2621 repo.ui.setconfig('phases', 'new-commit', ph, 'amend')
2624 2622 if newid != old.node():
2625 2623 # Reroute the working copy parent to the new changeset
2626 2624 repo.setparents(newid, nullid)
2627 2625
2628 2626 # Move bookmarks from old parent to amend commit
2629 2627 bms = repo.nodebookmarks(old.node())
2630 2628 if bms:
2631 2629 marks = repo._bookmarks
2632 2630 for bm in bms:
2633 2631 ui.debug('moving bookmarks %r from %s to %s\n' %
2634 2632 (marks, old.hex(), hex(newid)))
2635 2633 marks[bm] = newid
2636 2634 marks.recordchange(tr)
2637 2635 #commit the whole amend process
2638 2636 if createmarkers:
2639 2637 # mark the new changeset as successor of the rewritten one
2640 2638 new = repo[newid]
2641 2639 obs = [(old, (new,))]
2642 2640 if node:
2643 2641 obs.append((ctx, ()))
2644 2642
2645 2643 obsolete.createmarkers(repo, obs)
2646 2644 tr.close()
2647 2645 finally:
2648 2646 tr.release()
2649 2647 dsguard.close()
2650 2648 if not createmarkers and newid != old.node():
2651 2649 # Strip the intermediate commit (if there was one) and the amended
2652 2650 # commit
2653 2651 if node:
2654 2652 ui.note(_('stripping intermediate changeset %s\n') % ctx)
2655 2653 ui.note(_('stripping amended changeset %s\n') % old)
2656 2654 repair.strip(ui, repo, old.node(), topic='amend-backup')
2657 2655 finally:
2658 2656 lockmod.release(lock, dsguard, wlock)
2659 2657 return newid
2660 2658
2661 2659 def commiteditor(repo, ctx, subs, editform=''):
2662 2660 if ctx.description():
2663 2661 return ctx.description()
2664 2662 return commitforceeditor(repo, ctx, subs, editform=editform)
2665 2663
2666 2664 def commitforceeditor(repo, ctx, subs, finishdesc=None, extramsg=None,
2667 2665 editform=''):
2668 2666 if not extramsg:
2669 2667 extramsg = _("Leave message empty to abort commit.")
2670 2668
2671 2669 forms = [e for e in editform.split('.') if e]
2672 2670 forms.insert(0, 'changeset')
2673 2671 while forms:
2674 2672 tmpl = repo.ui.config('committemplate', '.'.join(forms))
2675 2673 if tmpl:
2676 2674 committext = buildcommittemplate(repo, ctx, subs, extramsg, tmpl)
2677 2675 break
2678 2676 forms.pop()
2679 2677 else:
2680 2678 committext = buildcommittext(repo, ctx, subs, extramsg)
2681 2679
2682 2680 # run editor in the repository root
2683 2681 olddir = os.getcwd()
2684 2682 os.chdir(repo.root)
2685 2683 text = repo.ui.edit(committext, ctx.user(), ctx.extra(), editform=editform)
2686 2684 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
2687 2685 os.chdir(olddir)
2688 2686
2689 2687 if finishdesc:
2690 2688 text = finishdesc(text)
2691 2689 if not text.strip():
2692 2690 raise util.Abort(_("empty commit message"))
2693 2691
2694 2692 return text
2695 2693
2696 2694 def buildcommittemplate(repo, ctx, subs, extramsg, tmpl):
2697 2695 ui = repo.ui
2698 2696 tmpl, mapfile = gettemplate(ui, tmpl, None)
2699 2697
2700 2698 try:
2701 2699 t = changeset_templater(ui, repo, None, {}, tmpl, mapfile, False)
2702 2700 except SyntaxError as inst:
2703 2701 raise util.Abort(inst.args[0])
2704 2702
2705 2703 for k, v in repo.ui.configitems('committemplate'):
2706 2704 if k != 'changeset':
2707 2705 t.t.cache[k] = v
2708 2706
2709 2707 if not extramsg:
2710 2708 extramsg = '' # ensure that extramsg is string
2711 2709
2712 2710 ui.pushbuffer()
2713 2711 t.show(ctx, extramsg=extramsg)
2714 2712 return ui.popbuffer()
2715 2713
2716 2714 def buildcommittext(repo, ctx, subs, extramsg):
2717 2715 edittext = []
2718 2716 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
2719 2717 if ctx.description():
2720 2718 edittext.append(ctx.description())
2721 2719 edittext.append("")
2722 2720 edittext.append("") # Empty line between message and comments.
2723 2721 edittext.append(_("HG: Enter commit message."
2724 2722 " Lines beginning with 'HG:' are removed."))
2725 2723 edittext.append("HG: %s" % extramsg)
2726 2724 edittext.append("HG: --")
2727 2725 edittext.append(_("HG: user: %s") % ctx.user())
2728 2726 if ctx.p2():
2729 2727 edittext.append(_("HG: branch merge"))
2730 2728 if ctx.branch():
2731 2729 edittext.append(_("HG: branch '%s'") % ctx.branch())
2732 2730 if bookmarks.isactivewdirparent(repo):
2733 2731 edittext.append(_("HG: bookmark '%s'") % repo._activebookmark)
2734 2732 edittext.extend([_("HG: subrepo %s") % s for s in subs])
2735 2733 edittext.extend([_("HG: added %s") % f for f in added])
2736 2734 edittext.extend([_("HG: changed %s") % f for f in modified])
2737 2735 edittext.extend([_("HG: removed %s") % f for f in removed])
2738 2736 if not added and not modified and not removed:
2739 2737 edittext.append(_("HG: no files changed"))
2740 2738 edittext.append("")
2741 2739
2742 2740 return "\n".join(edittext)
2743 2741
2744 2742 def commitstatus(repo, node, branch, bheads=None, opts={}):
2745 2743 ctx = repo[node]
2746 2744 parents = ctx.parents()
2747 2745
2748 2746 if (not opts.get('amend') and bheads and node not in bheads and not
2749 2747 [x for x in parents if x.node() in bheads and x.branch() == branch]):
2750 2748 repo.ui.status(_('created new head\n'))
2751 2749 # The message is not printed for initial roots. For the other
2752 2750 # changesets, it is printed in the following situations:
2753 2751 #
2754 2752 # Par column: for the 2 parents with ...
2755 2753 # N: null or no parent
2756 2754 # B: parent is on another named branch
2757 2755 # C: parent is a regular non head changeset
2758 2756 # H: parent was a branch head of the current branch
2759 2757 # Msg column: whether we print "created new head" message
2760 2758 # In the following, it is assumed that there already exists some
2761 2759 # initial branch heads of the current branch, otherwise nothing is
2762 2760 # printed anyway.
2763 2761 #
2764 2762 # Par Msg Comment
2765 2763 # N N y additional topo root
2766 2764 #
2767 2765 # B N y additional branch root
2768 2766 # C N y additional topo head
2769 2767 # H N n usual case
2770 2768 #
2771 2769 # B B y weird additional branch root
2772 2770 # C B y branch merge
2773 2771 # H B n merge with named branch
2774 2772 #
2775 2773 # C C y additional head from merge
2776 2774 # C H n merge with a head
2777 2775 #
2778 2776 # H H n head merge: head count decreases
2779 2777
2780 2778 if not opts.get('close_branch'):
2781 2779 for r in parents:
2782 2780 if r.closesbranch() and r.branch() == branch:
2783 2781 repo.ui.status(_('reopening closed branch head %d\n') % r)
2784 2782
2785 2783 if repo.ui.debugflag:
2786 2784 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
2787 2785 elif repo.ui.verbose:
2788 2786 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
2789 2787
2790 2788 def revert(ui, repo, ctx, parents, *pats, **opts):
2791 2789 parent, p2 = parents
2792 2790 node = ctx.node()
2793 2791
2794 2792 mf = ctx.manifest()
2795 2793 if node == p2:
2796 2794 parent = p2
2797 2795 if node == parent:
2798 2796 pmf = mf
2799 2797 else:
2800 2798 pmf = None
2801 2799
2802 2800 # need all matching names in dirstate and manifest of target rev,
2803 2801 # so have to walk both. do not print errors if files exist in one
2804 2802 # but not other. in both cases, filesets should be evaluated against
2805 2803 # workingctx to get consistent result (issue4497). this means 'set:**'
2806 2804 # cannot be used to select missing files from target rev.
2807 2805
2808 2806 # `names` is a mapping for all elements in working copy and target revision
2809 2807 # The mapping is in the form:
2810 2808 # <asb path in repo> -> (<path from CWD>, <exactly specified by matcher?>)
2811 2809 names = {}
2812 2810
2813 2811 wlock = repo.wlock()
2814 2812 try:
2815 2813 ## filling of the `names` mapping
2816 2814 # walk dirstate to fill `names`
2817 2815
2818 2816 interactive = opts.get('interactive', False)
2819 2817 wctx = repo[None]
2820 2818 m = scmutil.match(wctx, pats, opts)
2821 2819
2822 2820 # we'll need this later
2823 2821 targetsubs = sorted(s for s in wctx.substate if m(s))
2824 2822
2825 2823 if not m.always():
2826 2824 for abs in repo.walk(matchmod.badmatch(m, lambda x, y: False)):
2827 2825 names[abs] = m.rel(abs), m.exact(abs)
2828 2826
2829 2827 # walk target manifest to fill `names`
2830 2828
2831 2829 def badfn(path, msg):
2832 2830 if path in names:
2833 2831 return
2834 2832 if path in ctx.substate:
2835 2833 return
2836 2834 path_ = path + '/'
2837 2835 for f in names:
2838 2836 if f.startswith(path_):
2839 2837 return
2840 2838 ui.warn("%s: %s\n" % (m.rel(path), msg))
2841 2839
2842 2840 for abs in ctx.walk(matchmod.badmatch(m, badfn)):
2843 2841 if abs not in names:
2844 2842 names[abs] = m.rel(abs), m.exact(abs)
2845 2843
2846 2844 # Find status of all file in `names`.
2847 2845 m = scmutil.matchfiles(repo, names)
2848 2846
2849 2847 changes = repo.status(node1=node, match=m,
2850 2848 unknown=True, ignored=True, clean=True)
2851 2849 else:
2852 2850 changes = repo.status(node1=node, match=m)
2853 2851 for kind in changes:
2854 2852 for abs in kind:
2855 2853 names[abs] = m.rel(abs), m.exact(abs)
2856 2854
2857 2855 m = scmutil.matchfiles(repo, names)
2858 2856
2859 2857 modified = set(changes.modified)
2860 2858 added = set(changes.added)
2861 2859 removed = set(changes.removed)
2862 2860 _deleted = set(changes.deleted)
2863 2861 unknown = set(changes.unknown)
2864 2862 unknown.update(changes.ignored)
2865 2863 clean = set(changes.clean)
2866 2864 modadded = set()
2867 2865
2868 2866 # split between files known in target manifest and the others
2869 2867 smf = set(mf)
2870 2868
2871 2869 # determine the exact nature of the deleted changesets
2872 2870 deladded = _deleted - smf
2873 2871 deleted = _deleted - deladded
2874 2872
2875 2873 # We need to account for the state of the file in the dirstate,
2876 2874 # even when we revert against something else than parent. This will
2877 2875 # slightly alter the behavior of revert (doing back up or not, delete
2878 2876 # or just forget etc).
2879 2877 if parent == node:
2880 2878 dsmodified = modified
2881 2879 dsadded = added
2882 2880 dsremoved = removed
2883 2881 # store all local modifications, useful later for rename detection
2884 2882 localchanges = dsmodified | dsadded
2885 2883 modified, added, removed = set(), set(), set()
2886 2884 else:
2887 2885 changes = repo.status(node1=parent, match=m)
2888 2886 dsmodified = set(changes.modified)
2889 2887 dsadded = set(changes.added)
2890 2888 dsremoved = set(changes.removed)
2891 2889 # store all local modifications, useful later for rename detection
2892 2890 localchanges = dsmodified | dsadded
2893 2891
2894 2892 # only take into account for removes between wc and target
2895 2893 clean |= dsremoved - removed
2896 2894 dsremoved &= removed
2897 2895 # distinct between dirstate remove and other
2898 2896 removed -= dsremoved
2899 2897
2900 2898 modadded = added & dsmodified
2901 2899 added -= modadded
2902 2900
2903 2901 # tell newly modified apart.
2904 2902 dsmodified &= modified
2905 2903 dsmodified |= modified & dsadded # dirstate added may needs backup
2906 2904 modified -= dsmodified
2907 2905
2908 2906 # We need to wait for some post-processing to update this set
2909 2907 # before making the distinction. The dirstate will be used for
2910 2908 # that purpose.
2911 2909 dsadded = added
2912 2910
2913 2911 # in case of merge, files that are actually added can be reported as
2914 2912 # modified, we need to post process the result
2915 2913 if p2 != nullid:
2916 2914 if pmf is None:
2917 2915 # only need parent manifest in the merge case,
2918 2916 # so do not read by default
2919 2917 pmf = repo[parent].manifest()
2920 2918 mergeadd = dsmodified - set(pmf)
2921 2919 dsadded |= mergeadd
2922 2920 dsmodified -= mergeadd
2923 2921
2924 2922 # if f is a rename, update `names` to also revert the source
2925 2923 cwd = repo.getcwd()
2926 2924 for f in localchanges:
2927 2925 src = repo.dirstate.copied(f)
2928 2926 # XXX should we check for rename down to target node?
2929 2927 if src and src not in names and repo.dirstate[src] == 'r':
2930 2928 dsremoved.add(src)
2931 2929 names[src] = (repo.pathto(src, cwd), True)
2932 2930
2933 2931 # distinguish between file to forget and the other
2934 2932 added = set()
2935 2933 for abs in dsadded:
2936 2934 if repo.dirstate[abs] != 'a':
2937 2935 added.add(abs)
2938 2936 dsadded -= added
2939 2937
2940 2938 for abs in deladded:
2941 2939 if repo.dirstate[abs] == 'a':
2942 2940 dsadded.add(abs)
2943 2941 deladded -= dsadded
2944 2942
2945 2943 # For files marked as removed, we check if an unknown file is present at
2946 2944 # the same path. If a such file exists it may need to be backed up.
2947 2945 # Making the distinction at this stage helps have simpler backup
2948 2946 # logic.
2949 2947 removunk = set()
2950 2948 for abs in removed:
2951 2949 target = repo.wjoin(abs)
2952 2950 if os.path.lexists(target):
2953 2951 removunk.add(abs)
2954 2952 removed -= removunk
2955 2953
2956 2954 dsremovunk = set()
2957 2955 for abs in dsremoved:
2958 2956 target = repo.wjoin(abs)
2959 2957 if os.path.lexists(target):
2960 2958 dsremovunk.add(abs)
2961 2959 dsremoved -= dsremovunk
2962 2960
2963 2961 # action to be actually performed by revert
2964 2962 # (<list of file>, message>) tuple
2965 2963 actions = {'revert': ([], _('reverting %s\n')),
2966 2964 'add': ([], _('adding %s\n')),
2967 2965 'remove': ([], _('removing %s\n')),
2968 2966 'drop': ([], _('removing %s\n')),
2969 2967 'forget': ([], _('forgetting %s\n')),
2970 2968 'undelete': ([], _('undeleting %s\n')),
2971 2969 'noop': (None, _('no changes needed to %s\n')),
2972 2970 'unknown': (None, _('file not managed: %s\n')),
2973 2971 }
2974 2972
2975 2973 # "constant" that convey the backup strategy.
2976 2974 # All set to `discard` if `no-backup` is set do avoid checking
2977 2975 # no_backup lower in the code.
2978 2976 # These values are ordered for comparison purposes
2979 2977 backup = 2 # unconditionally do backup
2980 2978 check = 1 # check if the existing file differs from target
2981 2979 discard = 0 # never do backup
2982 2980 if opts.get('no_backup'):
2983 2981 backup = check = discard
2984 2982
2985 2983 backupanddel = actions['remove']
2986 2984 if not opts.get('no_backup'):
2987 2985 backupanddel = actions['drop']
2988 2986
2989 2987 disptable = (
2990 2988 # dispatch table:
2991 2989 # file state
2992 2990 # action
2993 2991 # make backup
2994 2992
2995 2993 ## Sets that results that will change file on disk
2996 2994 # Modified compared to target, no local change
2997 2995 (modified, actions['revert'], discard),
2998 2996 # Modified compared to target, but local file is deleted
2999 2997 (deleted, actions['revert'], discard),
3000 2998 # Modified compared to target, local change
3001 2999 (dsmodified, actions['revert'], backup),
3002 3000 # Added since target
3003 3001 (added, actions['remove'], discard),
3004 3002 # Added in working directory
3005 3003 (dsadded, actions['forget'], discard),
3006 3004 # Added since target, have local modification
3007 3005 (modadded, backupanddel, backup),
3008 3006 # Added since target but file is missing in working directory
3009 3007 (deladded, actions['drop'], discard),
3010 3008 # Removed since target, before working copy parent
3011 3009 (removed, actions['add'], discard),
3012 3010 # Same as `removed` but an unknown file exists at the same path
3013 3011 (removunk, actions['add'], check),
3014 3012 # Removed since targe, marked as such in working copy parent
3015 3013 (dsremoved, actions['undelete'], discard),
3016 3014 # Same as `dsremoved` but an unknown file exists at the same path
3017 3015 (dsremovunk, actions['undelete'], check),
3018 3016 ## the following sets does not result in any file changes
3019 3017 # File with no modification
3020 3018 (clean, actions['noop'], discard),
3021 3019 # Existing file, not tracked anywhere
3022 3020 (unknown, actions['unknown'], discard),
3023 3021 )
3024 3022
3025 3023 for abs, (rel, exact) in sorted(names.items()):
3026 3024 # target file to be touch on disk (relative to cwd)
3027 3025 target = repo.wjoin(abs)
3028 3026 # search the entry in the dispatch table.
3029 3027 # if the file is in any of these sets, it was touched in the working
3030 3028 # directory parent and we are sure it needs to be reverted.
3031 3029 for table, (xlist, msg), dobackup in disptable:
3032 3030 if abs not in table:
3033 3031 continue
3034 3032 if xlist is not None:
3035 3033 xlist.append(abs)
3036 3034 if dobackup and (backup <= dobackup
3037 3035 or wctx[abs].cmp(ctx[abs])):
3038 3036 bakname = "%s.orig" % rel
3039 3037 ui.note(_('saving current version of %s as %s\n') %
3040 3038 (rel, bakname))
3041 3039 if not opts.get('dry_run'):
3042 3040 if interactive:
3043 3041 util.copyfile(target, bakname)
3044 3042 else:
3045 3043 util.rename(target, bakname)
3046 3044 if ui.verbose or not exact:
3047 3045 if not isinstance(msg, basestring):
3048 3046 msg = msg(abs)
3049 3047 ui.status(msg % rel)
3050 3048 elif exact:
3051 3049 ui.warn(msg % rel)
3052 3050 break
3053 3051
3054 3052 if not opts.get('dry_run'):
3055 3053 needdata = ('revert', 'add', 'undelete')
3056 3054 _revertprefetch(repo, ctx, *[actions[name][0] for name in needdata])
3057 3055 _performrevert(repo, parents, ctx, actions, interactive)
3058 3056
3059 3057 if targetsubs:
3060 3058 # Revert the subrepos on the revert list
3061 3059 for sub in targetsubs:
3062 3060 try:
3063 3061 wctx.sub(sub).revert(ctx.substate[sub], *pats, **opts)
3064 3062 except KeyError:
3065 3063 raise util.Abort("subrepository '%s' does not exist in %s!"
3066 3064 % (sub, short(ctx.node())))
3067 3065 finally:
3068 3066 wlock.release()
3069 3067
3070 3068 def _revertprefetch(repo, ctx, *files):
3071 3069 """Let extension changing the storage layer prefetch content"""
3072 3070 pass
3073 3071
3074 3072 def _performrevert(repo, parents, ctx, actions, interactive=False):
3075 3073 """function that actually perform all the actions computed for revert
3076 3074
3077 3075 This is an independent function to let extension to plug in and react to
3078 3076 the imminent revert.
3079 3077
3080 3078 Make sure you have the working directory locked when calling this function.
3081 3079 """
3082 3080 parent, p2 = parents
3083 3081 node = ctx.node()
3084 3082 def checkout(f):
3085 3083 fc = ctx[f]
3086 3084 repo.wwrite(f, fc.data(), fc.flags())
3087 3085
3088 3086 audit_path = pathutil.pathauditor(repo.root)
3089 3087 for f in actions['forget'][0]:
3090 3088 repo.dirstate.drop(f)
3091 3089 for f in actions['remove'][0]:
3092 3090 audit_path(f)
3093 3091 try:
3094 3092 util.unlinkpath(repo.wjoin(f))
3095 3093 except OSError:
3096 3094 pass
3097 3095 repo.dirstate.remove(f)
3098 3096 for f in actions['drop'][0]:
3099 3097 audit_path(f)
3100 3098 repo.dirstate.remove(f)
3101 3099
3102 3100 normal = None
3103 3101 if node == parent:
3104 3102 # We're reverting to our parent. If possible, we'd like status
3105 3103 # to report the file as clean. We have to use normallookup for
3106 3104 # merges to avoid losing information about merged/dirty files.
3107 3105 if p2 != nullid:
3108 3106 normal = repo.dirstate.normallookup
3109 3107 else:
3110 3108 normal = repo.dirstate.normal
3111 3109
3112 3110 newlyaddedandmodifiedfiles = set()
3113 3111 if interactive:
3114 3112 # Prompt the user for changes to revert
3115 3113 torevert = [repo.wjoin(f) for f in actions['revert'][0]]
3116 3114 m = scmutil.match(ctx, torevert, {})
3117 3115 diffopts = patch.difffeatureopts(repo.ui, whitespace=True)
3118 3116 diffopts.nodates = True
3119 3117 diffopts.git = True
3120 3118 reversehunks = repo.ui.configbool('experimental',
3121 3119 'revertalternateinteractivemode',
3122 3120 True)
3123 3121 if reversehunks:
3124 3122 diff = patch.diff(repo, ctx.node(), None, m, opts=diffopts)
3125 3123 else:
3126 3124 diff = patch.diff(repo, None, ctx.node(), m, opts=diffopts)
3127 3125 originalchunks = patch.parsepatch(diff)
3128 3126
3129 3127 try:
3130 3128
3131 3129 chunks = recordfilter(repo.ui, originalchunks)
3132 3130 if reversehunks:
3133 3131 chunks = patch.reversehunks(chunks)
3134 3132
3135 3133 except patch.PatchError as err:
3136 3134 raise util.Abort(_('error parsing patch: %s') % err)
3137 3135
3138 3136 newlyaddedandmodifiedfiles = newandmodified(chunks, originalchunks)
3139 3137 # Apply changes
3140 3138 fp = cStringIO.StringIO()
3141 3139 for c in chunks:
3142 3140 c.write(fp)
3143 3141 dopatch = fp.tell()
3144 3142 fp.seek(0)
3145 3143 if dopatch:
3146 3144 try:
3147 3145 patch.internalpatch(repo.ui, repo, fp, 1, eolmode=None)
3148 3146 except patch.PatchError as err:
3149 3147 raise util.Abort(str(err))
3150 3148 del fp
3151 3149 else:
3152 3150 for f in actions['revert'][0]:
3153 3151 checkout(f)
3154 3152 if normal:
3155 3153 normal(f)
3156 3154
3157 3155 for f in actions['add'][0]:
3158 3156 # Don't checkout modified files, they are already created by the diff
3159 3157 if f not in newlyaddedandmodifiedfiles:
3160 3158 checkout(f)
3161 3159 repo.dirstate.add(f)
3162 3160
3163 3161 normal = repo.dirstate.normallookup
3164 3162 if node == parent and p2 == nullid:
3165 3163 normal = repo.dirstate.normal
3166 3164 for f in actions['undelete'][0]:
3167 3165 checkout(f)
3168 3166 normal(f)
3169 3167
3170 3168 copied = copies.pathcopies(repo[parent], ctx)
3171 3169
3172 3170 for f in actions['add'][0] + actions['undelete'][0] + actions['revert'][0]:
3173 3171 if f in copied:
3174 3172 repo.dirstate.copy(copied[f], f)
3175 3173
3176 3174 def command(table):
3177 3175 """Returns a function object to be used as a decorator for making commands.
3178 3176
3179 3177 This function receives a command table as its argument. The table should
3180 3178 be a dict.
3181 3179
3182 3180 The returned function can be used as a decorator for adding commands
3183 3181 to that command table. This function accepts multiple arguments to define
3184 3182 a command.
3185 3183
3186 3184 The first argument is the command name.
3187 3185
3188 3186 The options argument is an iterable of tuples defining command arguments.
3189 3187 See ``mercurial.fancyopts.fancyopts()`` for the format of each tuple.
3190 3188
3191 3189 The synopsis argument defines a short, one line summary of how to use the
3192 3190 command. This shows up in the help output.
3193 3191
3194 3192 The norepo argument defines whether the command does not require a
3195 3193 local repository. Most commands operate against a repository, thus the
3196 3194 default is False.
3197 3195
3198 3196 The optionalrepo argument defines whether the command optionally requires
3199 3197 a local repository.
3200 3198
3201 3199 The inferrepo argument defines whether to try to find a repository from the
3202 3200 command line arguments. If True, arguments will be examined for potential
3203 3201 repository locations. See ``findrepo()``. If a repository is found, it
3204 3202 will be used.
3205 3203 """
3206 3204 def cmd(name, options=(), synopsis=None, norepo=False, optionalrepo=False,
3207 3205 inferrepo=False):
3208 3206 def decorator(func):
3209 3207 if synopsis:
3210 3208 table[name] = func, list(options), synopsis
3211 3209 else:
3212 3210 table[name] = func, list(options)
3213 3211
3214 3212 if norepo:
3215 3213 # Avoid import cycle.
3216 3214 import commands
3217 3215 commands.norepo += ' %s' % ' '.join(parsealiases(name))
3218 3216
3219 3217 if optionalrepo:
3220 3218 import commands
3221 3219 commands.optionalrepo += ' %s' % ' '.join(parsealiases(name))
3222 3220
3223 3221 if inferrepo:
3224 3222 import commands
3225 3223 commands.inferrepo += ' %s' % ' '.join(parsealiases(name))
3226 3224
3227 3225 return func
3228 3226 return decorator
3229 3227
3230 3228 return cmd
3231 3229
3232 3230 # a list of (ui, repo, otherpeer, opts, missing) functions called by
3233 3231 # commands.outgoing. "missing" is "missing" of the result of
3234 3232 # "findcommonoutgoing()"
3235 3233 outgoinghooks = util.hooks()
3236 3234
3237 3235 # a list of (ui, repo) functions called by commands.summary
3238 3236 summaryhooks = util.hooks()
3239 3237
3240 3238 # a list of (ui, repo, opts, changes) functions called by commands.summary.
3241 3239 #
3242 3240 # functions should return tuple of booleans below, if 'changes' is None:
3243 3241 # (whether-incomings-are-needed, whether-outgoings-are-needed)
3244 3242 #
3245 3243 # otherwise, 'changes' is a tuple of tuples below:
3246 3244 # - (sourceurl, sourcebranch, sourcepeer, incoming)
3247 3245 # - (desturl, destbranch, destpeer, outgoing)
3248 3246 summaryremotehooks = util.hooks()
3249 3247
3250 3248 # A list of state files kept by multistep operations like graft.
3251 3249 # Since graft cannot be aborted, it is considered 'clearable' by update.
3252 3250 # note: bisect is intentionally excluded
3253 3251 # (state file, clearable, allowcommit, error, hint)
3254 3252 unfinishedstates = [
3255 3253 ('graftstate', True, False, _('graft in progress'),
3256 3254 _("use 'hg graft --continue' or 'hg update' to abort")),
3257 3255 ('updatestate', True, False, _('last update was interrupted'),
3258 3256 _("use 'hg update' to get a consistent checkout"))
3259 3257 ]
3260 3258
3261 3259 def checkunfinished(repo, commit=False):
3262 3260 '''Look for an unfinished multistep operation, like graft, and abort
3263 3261 if found. It's probably good to check this right before
3264 3262 bailifchanged().
3265 3263 '''
3266 3264 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3267 3265 if commit and allowcommit:
3268 3266 continue
3269 3267 if repo.vfs.exists(f):
3270 3268 raise util.Abort(msg, hint=hint)
3271 3269
3272 3270 def clearunfinished(repo):
3273 3271 '''Check for unfinished operations (as above), and clear the ones
3274 3272 that are clearable.
3275 3273 '''
3276 3274 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3277 3275 if not clearable and repo.vfs.exists(f):
3278 3276 raise util.Abort(msg, hint=hint)
3279 3277 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3280 3278 if clearable and repo.vfs.exists(f):
3281 3279 util.unlink(repo.join(f))
3282 3280
3283 3281 class dirstateguard(object):
3284 3282 '''Restore dirstate at unexpected failure.
3285 3283
3286 3284 At the construction, this class does:
3287 3285
3288 3286 - write current ``repo.dirstate`` out, and
3289 3287 - save ``.hg/dirstate`` into the backup file
3290 3288
3291 3289 This restores ``.hg/dirstate`` from backup file, if ``release()``
3292 3290 is invoked before ``close()``.
3293 3291
3294 3292 This just removes the backup file at ``close()`` before ``release()``.
3295 3293 '''
3296 3294
3297 3295 def __init__(self, repo, name):
3298 3296 repo.dirstate.write()
3299 3297 self._repo = repo
3300 3298 self._filename = 'dirstate.backup.%s.%d' % (name, id(self))
3301 3299 repo.vfs.write(self._filename, repo.vfs.tryread('dirstate'))
3302 3300 self._active = True
3303 3301 self._closed = False
3304 3302
3305 3303 def __del__(self):
3306 3304 if self._active: # still active
3307 3305 # this may occur, even if this class is used correctly:
3308 3306 # for example, releasing other resources like transaction
3309 3307 # may raise exception before ``dirstateguard.release`` in
3310 3308 # ``release(tr, ....)``.
3311 3309 self._abort()
3312 3310
3313 3311 def close(self):
3314 3312 if not self._active: # already inactivated
3315 3313 msg = (_("can't close already inactivated backup: %s")
3316 3314 % self._filename)
3317 3315 raise util.Abort(msg)
3318 3316
3319 3317 self._repo.vfs.unlink(self._filename)
3320 3318 self._active = False
3321 3319 self._closed = True
3322 3320
3323 3321 def _abort(self):
3324 3322 # this "invalidate()" prevents "wlock.release()" from writing
3325 3323 # changes of dirstate out after restoring to original status
3326 3324 self._repo.dirstate.invalidate()
3327 3325
3328 3326 self._repo.vfs.rename(self._filename, 'dirstate')
3329 3327 self._active = False
3330 3328
3331 3329 def release(self):
3332 3330 if not self._closed:
3333 3331 if not self._active: # already inactivated
3334 3332 msg = (_("can't release already inactivated backup: %s")
3335 3333 % self._filename)
3336 3334 raise util.Abort(msg)
3337 3335 self._abort()
@@ -1,241 +1,241 b''
1 1 $ hg init a
2 2 $ cd a
3 3 $ echo a > a
4 4 $ hg add -n
5 5 adding a
6 6 $ hg st
7 7 ? a
8 8 $ hg add
9 9 adding a
10 10 $ hg st
11 11 A a
12 12 $ hg forget a
13 13 $ hg add
14 14 adding a
15 15 $ hg st
16 16 A a
17 17
18 18 $ echo b > b
19 19 $ hg add -n b
20 20 $ hg st
21 21 A a
22 22 ? b
23 23 $ hg add b
24 24 $ hg st
25 25 A a
26 26 A b
27 27
28 28 should fail
29 29
30 30 $ hg add b
31 31 b already tracked!
32 32 $ hg st
33 33 A a
34 34 A b
35 35
36 36 #if no-windows
37 37 $ echo foo > con.xml
38 38 $ hg --config ui.portablefilenames=jump add con.xml
39 39 abort: ui.portablefilenames value is invalid ('jump')
40 40 [255]
41 41 $ hg --config ui.portablefilenames=abort add con.xml
42 42 abort: filename contains 'con', which is reserved on Windows: 'con.xml'
43 43 [255]
44 44 $ hg st
45 45 A a
46 46 A b
47 47 ? con.xml
48 48 $ hg add con.xml
49 49 warning: filename contains 'con', which is reserved on Windows: 'con.xml'
50 50 $ hg st
51 51 A a
52 52 A b
53 53 A con.xml
54 54 $ hg forget con.xml
55 55 $ rm con.xml
56 56 #endif
57 57
58 58 #if eol-in-paths
59 59 $ echo bla > 'hello:world'
60 60 $ hg --config ui.portablefilenames=abort add
61 61 adding hello:world
62 62 abort: filename contains ':', which is reserved on Windows: 'hello:world'
63 63 [255]
64 64 $ hg st
65 65 A a
66 66 A b
67 67 ? hello:world
68 68 $ hg --config ui.portablefilenames=ignore add
69 69 adding hello:world
70 70 $ hg st
71 71 A a
72 72 A b
73 73 A hello:world
74 74 #endif
75 75
76 76 $ hg ci -m 0 --traceback
77 77
78 78 $ hg log -r "heads(. or wdir() & file('**'))"
79 79 changeset: 0:* (glob)
80 80 tag: tip
81 81 user: test
82 82 date: Thu Jan 01 00:00:00 1970 +0000
83 83 summary: 0
84 84
85 85 should fail
86 86
87 87 $ hg add a
88 88 a already tracked!
89 89
90 90 $ echo aa > a
91 91 $ hg ci -m 1
92 92 $ hg up 0
93 93 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
94 94 $ echo aaa > a
95 95 $ hg ci -m 2
96 96 created new head
97 97
98 98 $ hg merge
99 99 merging a
100 100 warning: conflicts during merge.
101 101 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
102 102 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
103 103 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
104 104 [1]
105 105 $ hg st
106 106 M a
107 107 ? a.orig
108 108
109 109 wdir doesn't cause a crash, and can be dynamically selected if dirty
110 110
111 111 $ hg log -r "heads(. or wdir() & file('**'))"
112 changeset: 2:*+ (glob)
112 changeset: 2147483647:ffffffffffff
113 113 parent: 2:* (glob)
114 114 parent: 1:* (glob)
115 115 user: test
116 116 date: * (glob)
117 117
118 118 should fail
119 119
120 120 $ hg add a
121 121 a already tracked!
122 122 $ hg st
123 123 M a
124 124 ? a.orig
125 125 $ hg resolve -m a
126 126 (no more unresolved files)
127 127 $ hg ci -m merge
128 128
129 129 Issue683: peculiarity with hg revert of an removed then added file
130 130
131 131 $ hg forget a
132 132 $ hg add a
133 133 $ hg st
134 134 ? a.orig
135 135 $ hg rm a
136 136 $ hg st
137 137 R a
138 138 ? a.orig
139 139 $ echo a > a
140 140 $ hg add a
141 141 $ hg st
142 142 M a
143 143 ? a.orig
144 144
145 145 Forgotten file can be added back (as either clean or modified)
146 146
147 147 $ hg forget b
148 148 $ hg add b
149 149 $ hg st -A b
150 150 C b
151 151 $ hg forget b
152 152 $ echo modified > b
153 153 $ hg add b
154 154 $ hg st -A b
155 155 M b
156 156 $ hg revert -qC b
157 157
158 158 $ hg add c && echo "unexpected addition of missing file"
159 159 c: * (glob)
160 160 [1]
161 161 $ echo c > c
162 162 $ hg add d c && echo "unexpected addition of missing file"
163 163 d: * (glob)
164 164 [1]
165 165 $ hg st
166 166 M a
167 167 A c
168 168 ? a.orig
169 169 $ hg up -C
170 170 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
171 171
172 172 forget and get should have the right order: added but missing dir should be
173 173 forgotten before file with same name is added
174 174
175 175 $ echo file d > d
176 176 $ hg add d
177 177 $ hg ci -md
178 178 $ hg rm d
179 179 $ mkdir d
180 180 $ echo a > d/a
181 181 $ hg add d/a
182 182 $ rm -r d
183 183 $ hg up -C
184 184 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
185 185 $ cat d
186 186 file d
187 187
188 188 Test that adding a directory doesn't require case matching (issue4578)
189 189 #if icasefs
190 190 $ mkdir -p CapsDir1/CapsDir
191 191 $ echo abc > CapsDir1/CapsDir/AbC.txt
192 192 $ mkdir CapsDir1/CapsDir/SubDir
193 193 $ echo def > CapsDir1/CapsDir/SubDir/Def.txt
194 194
195 195 $ hg add capsdir1/capsdir
196 196 adding CapsDir1/CapsDir/AbC.txt (glob)
197 197 adding CapsDir1/CapsDir/SubDir/Def.txt (glob)
198 198
199 199 $ hg forget capsdir1/capsdir/abc.txt
200 200 removing CapsDir1/CapsDir/AbC.txt (glob)
201 201
202 202 $ hg forget capsdir1/capsdir
203 203 removing CapsDir1/CapsDir/SubDir/Def.txt (glob)
204 204
205 205 $ hg add capsdir1
206 206 adding CapsDir1/CapsDir/AbC.txt (glob)
207 207 adding CapsDir1/CapsDir/SubDir/Def.txt (glob)
208 208
209 209 $ hg ci -m "AbCDef" capsdir1/capsdir
210 210
211 211 $ hg status -A capsdir1/capsdir
212 212 C CapsDir1/CapsDir/AbC.txt
213 213 C CapsDir1/CapsDir/SubDir/Def.txt
214 214
215 215 $ hg files capsdir1/capsdir
216 216 CapsDir1/CapsDir/AbC.txt (glob)
217 217 CapsDir1/CapsDir/SubDir/Def.txt (glob)
218 218
219 219 $ echo xyz > CapsDir1/CapsDir/SubDir/Def.txt
220 220 $ hg ci -m xyz capsdir1/capsdir/subdir/def.txt
221 221
222 222 $ hg revert -r '.^' capsdir1/capsdir
223 223 reverting CapsDir1/CapsDir/SubDir/Def.txt (glob)
224 224
225 225 The conditional tests above mean the hash on the diff line differs on Windows
226 226 and OS X
227 227 $ hg diff capsdir1/capsdir
228 228 diff -r * CapsDir1/CapsDir/SubDir/Def.txt (glob)
229 229 --- a/CapsDir1/CapsDir/SubDir/Def.txt Thu Jan 01 00:00:00 1970 +0000
230 230 +++ b/CapsDir1/CapsDir/SubDir/Def.txt * +0000 (glob)
231 231 @@ -1,1 +1,1 @@
232 232 -xyz
233 233 +def
234 234
235 235 $ hg remove -f 'glob:**.txt' -X capsdir1/capsdir
236 236 $ hg remove -f 'glob:**.txt' -I capsdir1/capsdir
237 237 removing CapsDir1/CapsDir/AbC.txt (glob)
238 238 removing CapsDir1/CapsDir/SubDir/Def.txt (glob)
239 239 #endif
240 240
241 241 $ cd ..
@@ -1,3385 +1,3405 b''
1 1 $ hg init a
2 2 $ cd a
3 3 $ echo a > a
4 4 $ hg add a
5 5 $ echo line 1 > b
6 6 $ echo line 2 >> b
7 7 $ hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
8 8
9 9 $ hg add b
10 10 $ echo other 1 > c
11 11 $ echo other 2 >> c
12 12 $ echo >> c
13 13 $ echo other 3 >> c
14 14 $ hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
15 15
16 16 $ hg add c
17 17 $ hg commit -m 'no person' -d '1200000 0' -u 'other@place'
18 18 $ echo c >> c
19 19 $ hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
20 20
21 21 $ echo foo > .hg/branch
22 22 $ hg commit -m 'new branch' -d '1400000 0' -u 'person'
23 23
24 24 $ hg co -q 3
25 25 $ echo other 4 >> d
26 26 $ hg add d
27 27 $ hg commit -m 'new head' -d '1500000 0' -u 'person'
28 28
29 29 $ hg merge -q foo
30 30 $ hg commit -m 'merge' -d '1500001 0' -u 'person'
31 31
32 32 Second branch starting at nullrev:
33 33
34 34 $ hg update null
35 35 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
36 36 $ echo second > second
37 37 $ hg add second
38 38 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
39 39 created new head
40 40
41 41 $ echo third > third
42 42 $ hg add third
43 43 $ hg mv second fourth
44 44 $ hg commit -m third -d "2020-01-01 10:01"
45 45
46 46 $ hg log --template '{join(file_copies, ",\n")}\n' -r .
47 47 fourth (second)
48 48 $ hg log -T '{file_copies % "{source} -> {name}\n"}' -r .
49 49 second -> fourth
50 50 $ hg log -T '{rev} {ifcontains("fourth", file_copies, "t", "f")}\n' -r .:7
51 51 8 t
52 52 7 f
53 53
54 54 Working-directory revision has special identifiers, though they are still
55 55 experimental:
56 56
57 57 $ hg log -r 'wdir()' -T '{rev}:{node}\n'
58 58 2147483647:ffffffffffffffffffffffffffffffffffffffff
59 59
60 60 Some keywords are invalid for working-directory revision, but they should
61 61 never cause crash:
62 62
63 63 $ hg log -r 'wdir()' -T '{manifest}\n'
64 64
65 65
66 66 Quoting for ui.logtemplate
67 67
68 68 $ hg tip --config "ui.logtemplate={rev}\n"
69 69 8
70 70 $ hg tip --config "ui.logtemplate='{rev}\n'"
71 71 8
72 72 $ hg tip --config 'ui.logtemplate="{rev}\n"'
73 73 8
74 74
75 75 Make sure user/global hgrc does not affect tests
76 76
77 77 $ echo '[ui]' > .hg/hgrc
78 78 $ echo 'logtemplate =' >> .hg/hgrc
79 79 $ echo 'style =' >> .hg/hgrc
80 80
81 81 Add some simple styles to settings
82 82
83 83 $ echo '[templates]' >> .hg/hgrc
84 84 $ printf 'simple = "{rev}\\n"\n' >> .hg/hgrc
85 85 $ printf 'simple2 = {rev}\\n\n' >> .hg/hgrc
86 86
87 87 $ hg log -l1 -Tsimple
88 88 8
89 89 $ hg log -l1 -Tsimple2
90 90 8
91 91
92 92 Test templates and style maps in files:
93 93
94 94 $ echo "{rev}" > tmpl
95 95 $ hg log -l1 -T./tmpl
96 96 8
97 97 $ hg log -l1 -Tblah/blah
98 98 blah/blah (no-eol)
99 99
100 100 $ printf 'changeset = "{rev}\\n"\n' > map-simple
101 101 $ hg log -l1 -T./map-simple
102 102 8
103 103
104 104 Template should precede style option
105 105
106 106 $ hg log -l1 --style default -T '{rev}\n'
107 107 8
108 108
109 109 Add a commit with empty description, to ensure that the templates
110 110 below will omit the description line.
111 111
112 112 $ echo c >> c
113 113 $ hg add c
114 114 $ hg commit -qm ' '
115 115
116 116 Default style is like normal output. Phases style should be the same
117 117 as default style, except for extra phase lines.
118 118
119 119 $ hg log > log.out
120 120 $ hg log --style default > style.out
121 121 $ cmp log.out style.out || diff -u log.out style.out
122 122 $ hg log -T phases > phases.out
123 123 $ diff -U 0 log.out phases.out | grep -v '^---\|^+++'
124 124 @@ -2,0 +3 @@
125 125 +phase: draft
126 126 @@ -6,0 +8 @@
127 127 +phase: draft
128 128 @@ -11,0 +14 @@
129 129 +phase: draft
130 130 @@ -17,0 +21 @@
131 131 +phase: draft
132 132 @@ -24,0 +29 @@
133 133 +phase: draft
134 134 @@ -31,0 +37 @@
135 135 +phase: draft
136 136 @@ -36,0 +43 @@
137 137 +phase: draft
138 138 @@ -41,0 +49 @@
139 139 +phase: draft
140 140 @@ -46,0 +55 @@
141 141 +phase: draft
142 142 @@ -51,0 +61 @@
143 143 +phase: draft
144 144
145 145 $ hg log -v > log.out
146 146 $ hg log -v --style default > style.out
147 147 $ cmp log.out style.out || diff -u log.out style.out
148 148 $ hg log -v -T phases > phases.out
149 149 $ diff -U 0 log.out phases.out | grep -v '^---\|^+++'
150 150 @@ -2,0 +3 @@
151 151 +phase: draft
152 152 @@ -7,0 +9 @@
153 153 +phase: draft
154 154 @@ -15,0 +18 @@
155 155 +phase: draft
156 156 @@ -24,0 +28 @@
157 157 +phase: draft
158 158 @@ -33,0 +38 @@
159 159 +phase: draft
160 160 @@ -43,0 +49 @@
161 161 +phase: draft
162 162 @@ -50,0 +57 @@
163 163 +phase: draft
164 164 @@ -58,0 +66 @@
165 165 +phase: draft
166 166 @@ -66,0 +75 @@
167 167 +phase: draft
168 168 @@ -77,0 +87 @@
169 169 +phase: draft
170 170
171 171 $ hg log -q > log.out
172 172 $ hg log -q --style default > style.out
173 173 $ cmp log.out style.out || diff -u log.out style.out
174 174 $ hg log -q -T phases > phases.out
175 175 $ cmp log.out phases.out || diff -u log.out phases.out
176 176
177 177 $ hg log --debug > log.out
178 178 $ hg log --debug --style default > style.out
179 179 $ cmp log.out style.out || diff -u log.out style.out
180 180 $ hg log --debug -T phases > phases.out
181 181 $ cmp log.out phases.out || diff -u log.out phases.out
182 182
183 Default style of working-directory revision should also be the same (but
184 date may change while running tests):
185
186 $ hg log -r 'wdir()' | sed 's|^date:.*|date:|' > log.out
187 $ hg log -r 'wdir()' --style default | sed 's|^date:.*|date:|' > style.out
188 $ cmp log.out style.out || diff -u log.out style.out
189
190 $ hg log -r 'wdir()' -v | sed 's|^date:.*|date:|' > log.out
191 $ hg log -r 'wdir()' -v --style default | sed 's|^date:.*|date:|' > style.out
192 $ cmp log.out style.out || diff -u log.out style.out
193
194 $ hg log -r 'wdir()' -q > log.out
195 $ hg log -r 'wdir()' -q --style default > style.out
196 $ cmp log.out style.out || diff -u log.out style.out
197
198 $ hg log -r 'wdir()' --debug | sed 's|^date:.*|date:|' > log.out
199 $ hg log -r 'wdir()' --debug --style default \
200 > | sed 's|^date:.*|date:|' > style.out
201 $ cmp log.out style.out || diff -u log.out style.out
202
183 203 Default style should also preserve color information (issue2866):
184 204
185 205 $ cp $HGRCPATH $HGRCPATH-bak
186 206 $ cat <<EOF >> $HGRCPATH
187 207 > [extensions]
188 208 > color=
189 209 > EOF
190 210
191 211 $ hg --color=debug log > log.out
192 212 $ hg --color=debug log --style default > style.out
193 213 $ cmp log.out style.out || diff -u log.out style.out
194 214 $ hg --color=debug log -T phases > phases.out
195 215 $ diff -U 0 log.out phases.out | grep -v '^---\|^+++'
196 216 @@ -2,0 +3 @@
197 217 +[log.phase|phase: draft]
198 218 @@ -6,0 +8 @@
199 219 +[log.phase|phase: draft]
200 220 @@ -11,0 +14 @@
201 221 +[log.phase|phase: draft]
202 222 @@ -17,0 +21 @@
203 223 +[log.phase|phase: draft]
204 224 @@ -24,0 +29 @@
205 225 +[log.phase|phase: draft]
206 226 @@ -31,0 +37 @@
207 227 +[log.phase|phase: draft]
208 228 @@ -36,0 +43 @@
209 229 +[log.phase|phase: draft]
210 230 @@ -41,0 +49 @@
211 231 +[log.phase|phase: draft]
212 232 @@ -46,0 +55 @@
213 233 +[log.phase|phase: draft]
214 234 @@ -51,0 +61 @@
215 235 +[log.phase|phase: draft]
216 236
217 237 $ hg --color=debug -v log > log.out
218 238 $ hg --color=debug -v log --style default > style.out
219 239 $ cmp log.out style.out || diff -u log.out style.out
220 240 $ hg --color=debug -v log -T phases > phases.out
221 241 $ diff -U 0 log.out phases.out | grep -v '^---\|^+++'
222 242 @@ -2,0 +3 @@
223 243 +[log.phase|phase: draft]
224 244 @@ -7,0 +9 @@
225 245 +[log.phase|phase: draft]
226 246 @@ -15,0 +18 @@
227 247 +[log.phase|phase: draft]
228 248 @@ -24,0 +28 @@
229 249 +[log.phase|phase: draft]
230 250 @@ -33,0 +38 @@
231 251 +[log.phase|phase: draft]
232 252 @@ -43,0 +49 @@
233 253 +[log.phase|phase: draft]
234 254 @@ -50,0 +57 @@
235 255 +[log.phase|phase: draft]
236 256 @@ -58,0 +66 @@
237 257 +[log.phase|phase: draft]
238 258 @@ -66,0 +75 @@
239 259 +[log.phase|phase: draft]
240 260 @@ -77,0 +87 @@
241 261 +[log.phase|phase: draft]
242 262
243 263 $ hg --color=debug -q log > log.out
244 264 $ hg --color=debug -q log --style default > style.out
245 265 $ cmp log.out style.out || diff -u log.out style.out
246 266 $ hg --color=debug -q log -T phases > phases.out
247 267 $ cmp log.out phases.out || diff -u log.out phases.out
248 268
249 269 $ hg --color=debug --debug log > log.out
250 270 $ hg --color=debug --debug log --style default > style.out
251 271 $ cmp log.out style.out || diff -u log.out style.out
252 272 $ hg --color=debug --debug log -T phases > phases.out
253 273 $ cmp log.out phases.out || diff -u log.out phases.out
254 274
255 275 $ mv $HGRCPATH-bak $HGRCPATH
256 276
257 277 Remove commit with empty commit message, so as to not pollute further
258 278 tests.
259 279
260 280 $ hg --config extensions.strip= strip -q .
261 281
262 282 Revision with no copies (used to print a traceback):
263 283
264 284 $ hg tip -v --template '\n'
265 285
266 286
267 287 Compact style works:
268 288
269 289 $ hg log -Tcompact
270 290 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
271 291 third
272 292
273 293 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
274 294 second
275 295
276 296 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
277 297 merge
278 298
279 299 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
280 300 new head
281 301
282 302 4 bbe44766e73d 1970-01-17 04:53 +0000 person
283 303 new branch
284 304
285 305 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
286 306 no user, no domain
287 307
288 308 2 97054abb4ab8 1970-01-14 21:20 +0000 other
289 309 no person
290 310
291 311 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
292 312 other 1
293 313
294 314 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
295 315 line 1
296 316
297 317
298 318 $ hg log -v --style compact
299 319 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
300 320 third
301 321
302 322 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
303 323 second
304 324
305 325 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
306 326 merge
307 327
308 328 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
309 329 new head
310 330
311 331 4 bbe44766e73d 1970-01-17 04:53 +0000 person
312 332 new branch
313 333
314 334 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
315 335 no user, no domain
316 336
317 337 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
318 338 no person
319 339
320 340 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
321 341 other 1
322 342 other 2
323 343
324 344 other 3
325 345
326 346 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
327 347 line 1
328 348 line 2
329 349
330 350
331 351 $ hg log --debug --style compact
332 352 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
333 353 third
334 354
335 355 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
336 356 second
337 357
338 358 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
339 359 merge
340 360
341 361 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
342 362 new head
343 363
344 364 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
345 365 new branch
346 366
347 367 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
348 368 no user, no domain
349 369
350 370 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
351 371 no person
352 372
353 373 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
354 374 other 1
355 375 other 2
356 376
357 377 other 3
358 378
359 379 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
360 380 line 1
361 381 line 2
362 382
363 383
364 384 Test xml styles:
365 385
366 386 $ hg log --style xml
367 387 <?xml version="1.0"?>
368 388 <log>
369 389 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
370 390 <tag>tip</tag>
371 391 <author email="test">test</author>
372 392 <date>2020-01-01T10:01:00+00:00</date>
373 393 <msg xml:space="preserve">third</msg>
374 394 </logentry>
375 395 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
376 396 <parent revision="-1" node="0000000000000000000000000000000000000000" />
377 397 <author email="user@hostname">User Name</author>
378 398 <date>1970-01-12T13:46:40+00:00</date>
379 399 <msg xml:space="preserve">second</msg>
380 400 </logentry>
381 401 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
382 402 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
383 403 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
384 404 <author email="person">person</author>
385 405 <date>1970-01-18T08:40:01+00:00</date>
386 406 <msg xml:space="preserve">merge</msg>
387 407 </logentry>
388 408 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
389 409 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
390 410 <author email="person">person</author>
391 411 <date>1970-01-18T08:40:00+00:00</date>
392 412 <msg xml:space="preserve">new head</msg>
393 413 </logentry>
394 414 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
395 415 <branch>foo</branch>
396 416 <author email="person">person</author>
397 417 <date>1970-01-17T04:53:20+00:00</date>
398 418 <msg xml:space="preserve">new branch</msg>
399 419 </logentry>
400 420 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
401 421 <author email="person">person</author>
402 422 <date>1970-01-16T01:06:40+00:00</date>
403 423 <msg xml:space="preserve">no user, no domain</msg>
404 424 </logentry>
405 425 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
406 426 <author email="other@place">other</author>
407 427 <date>1970-01-14T21:20:00+00:00</date>
408 428 <msg xml:space="preserve">no person</msg>
409 429 </logentry>
410 430 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
411 431 <author email="other@place">A. N. Other</author>
412 432 <date>1970-01-13T17:33:20+00:00</date>
413 433 <msg xml:space="preserve">other 1
414 434 other 2
415 435
416 436 other 3</msg>
417 437 </logentry>
418 438 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
419 439 <author email="user@hostname">User Name</author>
420 440 <date>1970-01-12T13:46:40+00:00</date>
421 441 <msg xml:space="preserve">line 1
422 442 line 2</msg>
423 443 </logentry>
424 444 </log>
425 445
426 446 $ hg log -v --style xml
427 447 <?xml version="1.0"?>
428 448 <log>
429 449 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
430 450 <tag>tip</tag>
431 451 <author email="test">test</author>
432 452 <date>2020-01-01T10:01:00+00:00</date>
433 453 <msg xml:space="preserve">third</msg>
434 454 <paths>
435 455 <path action="A">fourth</path>
436 456 <path action="A">third</path>
437 457 <path action="R">second</path>
438 458 </paths>
439 459 <copies>
440 460 <copy source="second">fourth</copy>
441 461 </copies>
442 462 </logentry>
443 463 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
444 464 <parent revision="-1" node="0000000000000000000000000000000000000000" />
445 465 <author email="user@hostname">User Name</author>
446 466 <date>1970-01-12T13:46:40+00:00</date>
447 467 <msg xml:space="preserve">second</msg>
448 468 <paths>
449 469 <path action="A">second</path>
450 470 </paths>
451 471 </logentry>
452 472 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
453 473 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
454 474 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
455 475 <author email="person">person</author>
456 476 <date>1970-01-18T08:40:01+00:00</date>
457 477 <msg xml:space="preserve">merge</msg>
458 478 <paths>
459 479 </paths>
460 480 </logentry>
461 481 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
462 482 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
463 483 <author email="person">person</author>
464 484 <date>1970-01-18T08:40:00+00:00</date>
465 485 <msg xml:space="preserve">new head</msg>
466 486 <paths>
467 487 <path action="A">d</path>
468 488 </paths>
469 489 </logentry>
470 490 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
471 491 <branch>foo</branch>
472 492 <author email="person">person</author>
473 493 <date>1970-01-17T04:53:20+00:00</date>
474 494 <msg xml:space="preserve">new branch</msg>
475 495 <paths>
476 496 </paths>
477 497 </logentry>
478 498 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
479 499 <author email="person">person</author>
480 500 <date>1970-01-16T01:06:40+00:00</date>
481 501 <msg xml:space="preserve">no user, no domain</msg>
482 502 <paths>
483 503 <path action="M">c</path>
484 504 </paths>
485 505 </logentry>
486 506 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
487 507 <author email="other@place">other</author>
488 508 <date>1970-01-14T21:20:00+00:00</date>
489 509 <msg xml:space="preserve">no person</msg>
490 510 <paths>
491 511 <path action="A">c</path>
492 512 </paths>
493 513 </logentry>
494 514 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
495 515 <author email="other@place">A. N. Other</author>
496 516 <date>1970-01-13T17:33:20+00:00</date>
497 517 <msg xml:space="preserve">other 1
498 518 other 2
499 519
500 520 other 3</msg>
501 521 <paths>
502 522 <path action="A">b</path>
503 523 </paths>
504 524 </logentry>
505 525 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
506 526 <author email="user@hostname">User Name</author>
507 527 <date>1970-01-12T13:46:40+00:00</date>
508 528 <msg xml:space="preserve">line 1
509 529 line 2</msg>
510 530 <paths>
511 531 <path action="A">a</path>
512 532 </paths>
513 533 </logentry>
514 534 </log>
515 535
516 536 $ hg log --debug --style xml
517 537 <?xml version="1.0"?>
518 538 <log>
519 539 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
520 540 <tag>tip</tag>
521 541 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
522 542 <parent revision="-1" node="0000000000000000000000000000000000000000" />
523 543 <author email="test">test</author>
524 544 <date>2020-01-01T10:01:00+00:00</date>
525 545 <msg xml:space="preserve">third</msg>
526 546 <paths>
527 547 <path action="A">fourth</path>
528 548 <path action="A">third</path>
529 549 <path action="R">second</path>
530 550 </paths>
531 551 <copies>
532 552 <copy source="second">fourth</copy>
533 553 </copies>
534 554 <extra key="branch">default</extra>
535 555 </logentry>
536 556 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
537 557 <parent revision="-1" node="0000000000000000000000000000000000000000" />
538 558 <parent revision="-1" node="0000000000000000000000000000000000000000" />
539 559 <author email="user@hostname">User Name</author>
540 560 <date>1970-01-12T13:46:40+00:00</date>
541 561 <msg xml:space="preserve">second</msg>
542 562 <paths>
543 563 <path action="A">second</path>
544 564 </paths>
545 565 <extra key="branch">default</extra>
546 566 </logentry>
547 567 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
548 568 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
549 569 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
550 570 <author email="person">person</author>
551 571 <date>1970-01-18T08:40:01+00:00</date>
552 572 <msg xml:space="preserve">merge</msg>
553 573 <paths>
554 574 </paths>
555 575 <extra key="branch">default</extra>
556 576 </logentry>
557 577 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
558 578 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
559 579 <parent revision="-1" node="0000000000000000000000000000000000000000" />
560 580 <author email="person">person</author>
561 581 <date>1970-01-18T08:40:00+00:00</date>
562 582 <msg xml:space="preserve">new head</msg>
563 583 <paths>
564 584 <path action="A">d</path>
565 585 </paths>
566 586 <extra key="branch">default</extra>
567 587 </logentry>
568 588 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
569 589 <branch>foo</branch>
570 590 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
571 591 <parent revision="-1" node="0000000000000000000000000000000000000000" />
572 592 <author email="person">person</author>
573 593 <date>1970-01-17T04:53:20+00:00</date>
574 594 <msg xml:space="preserve">new branch</msg>
575 595 <paths>
576 596 </paths>
577 597 <extra key="branch">foo</extra>
578 598 </logentry>
579 599 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
580 600 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
581 601 <parent revision="-1" node="0000000000000000000000000000000000000000" />
582 602 <author email="person">person</author>
583 603 <date>1970-01-16T01:06:40+00:00</date>
584 604 <msg xml:space="preserve">no user, no domain</msg>
585 605 <paths>
586 606 <path action="M">c</path>
587 607 </paths>
588 608 <extra key="branch">default</extra>
589 609 </logentry>
590 610 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
591 611 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
592 612 <parent revision="-1" node="0000000000000000000000000000000000000000" />
593 613 <author email="other@place">other</author>
594 614 <date>1970-01-14T21:20:00+00:00</date>
595 615 <msg xml:space="preserve">no person</msg>
596 616 <paths>
597 617 <path action="A">c</path>
598 618 </paths>
599 619 <extra key="branch">default</extra>
600 620 </logentry>
601 621 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
602 622 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
603 623 <parent revision="-1" node="0000000000000000000000000000000000000000" />
604 624 <author email="other@place">A. N. Other</author>
605 625 <date>1970-01-13T17:33:20+00:00</date>
606 626 <msg xml:space="preserve">other 1
607 627 other 2
608 628
609 629 other 3</msg>
610 630 <paths>
611 631 <path action="A">b</path>
612 632 </paths>
613 633 <extra key="branch">default</extra>
614 634 </logentry>
615 635 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
616 636 <parent revision="-1" node="0000000000000000000000000000000000000000" />
617 637 <parent revision="-1" node="0000000000000000000000000000000000000000" />
618 638 <author email="user@hostname">User Name</author>
619 639 <date>1970-01-12T13:46:40+00:00</date>
620 640 <msg xml:space="preserve">line 1
621 641 line 2</msg>
622 642 <paths>
623 643 <path action="A">a</path>
624 644 </paths>
625 645 <extra key="branch">default</extra>
626 646 </logentry>
627 647 </log>
628 648
629 649
630 650 Test JSON style:
631 651
632 652 $ hg log -k nosuch -Tjson
633 653 []
634 654
635 655 $ hg log -qr . -Tjson
636 656 [
637 657 {
638 658 "rev": 8,
639 659 "node": "95c24699272ef57d062b8bccc32c878bf841784a"
640 660 }
641 661 ]
642 662
643 663 $ hg log -vpr . -Tjson --stat
644 664 [
645 665 {
646 666 "rev": 8,
647 667 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
648 668 "branch": "default",
649 669 "phase": "draft",
650 670 "user": "test",
651 671 "date": [1577872860, 0],
652 672 "desc": "third",
653 673 "bookmarks": [],
654 674 "tags": ["tip"],
655 675 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
656 676 "files": ["fourth", "second", "third"],
657 677 "diffstat": " fourth | 1 +\n second | 1 -\n third | 1 +\n 3 files changed, 2 insertions(+), 1 deletions(-)\n",
658 678 "diff": "diff -r 29114dbae42b -r 95c24699272e fourth\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/fourth\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+second\ndiff -r 29114dbae42b -r 95c24699272e second\n--- a/second\tMon Jan 12 13:46:40 1970 +0000\n+++ /dev/null\tThu Jan 01 00:00:00 1970 +0000\n@@ -1,1 +0,0 @@\n-second\ndiff -r 29114dbae42b -r 95c24699272e third\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/third\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+third\n"
659 679 }
660 680 ]
661 681
662 682 honor --git but not format-breaking diffopts
663 683 $ hg --config diff.noprefix=True log --git -vpr . -Tjson
664 684 [
665 685 {
666 686 "rev": 8,
667 687 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
668 688 "branch": "default",
669 689 "phase": "draft",
670 690 "user": "test",
671 691 "date": [1577872860, 0],
672 692 "desc": "third",
673 693 "bookmarks": [],
674 694 "tags": ["tip"],
675 695 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
676 696 "files": ["fourth", "second", "third"],
677 697 "diff": "diff --git a/second b/fourth\nrename from second\nrename to fourth\ndiff --git a/third b/third\nnew file mode 100644\n--- /dev/null\n+++ b/third\n@@ -0,0 +1,1 @@\n+third\n"
678 698 }
679 699 ]
680 700
681 701 $ hg log -T json
682 702 [
683 703 {
684 704 "rev": 8,
685 705 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
686 706 "branch": "default",
687 707 "phase": "draft",
688 708 "user": "test",
689 709 "date": [1577872860, 0],
690 710 "desc": "third",
691 711 "bookmarks": [],
692 712 "tags": ["tip"],
693 713 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"]
694 714 },
695 715 {
696 716 "rev": 7,
697 717 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
698 718 "branch": "default",
699 719 "phase": "draft",
700 720 "user": "User Name <user@hostname>",
701 721 "date": [1000000, 0],
702 722 "desc": "second",
703 723 "bookmarks": [],
704 724 "tags": [],
705 725 "parents": ["0000000000000000000000000000000000000000"]
706 726 },
707 727 {
708 728 "rev": 6,
709 729 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
710 730 "branch": "default",
711 731 "phase": "draft",
712 732 "user": "person",
713 733 "date": [1500001, 0],
714 734 "desc": "merge",
715 735 "bookmarks": [],
716 736 "tags": [],
717 737 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"]
718 738 },
719 739 {
720 740 "rev": 5,
721 741 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
722 742 "branch": "default",
723 743 "phase": "draft",
724 744 "user": "person",
725 745 "date": [1500000, 0],
726 746 "desc": "new head",
727 747 "bookmarks": [],
728 748 "tags": [],
729 749 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
730 750 },
731 751 {
732 752 "rev": 4,
733 753 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
734 754 "branch": "foo",
735 755 "phase": "draft",
736 756 "user": "person",
737 757 "date": [1400000, 0],
738 758 "desc": "new branch",
739 759 "bookmarks": [],
740 760 "tags": [],
741 761 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
742 762 },
743 763 {
744 764 "rev": 3,
745 765 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
746 766 "branch": "default",
747 767 "phase": "draft",
748 768 "user": "person",
749 769 "date": [1300000, 0],
750 770 "desc": "no user, no domain",
751 771 "bookmarks": [],
752 772 "tags": [],
753 773 "parents": ["97054abb4ab824450e9164180baf491ae0078465"]
754 774 },
755 775 {
756 776 "rev": 2,
757 777 "node": "97054abb4ab824450e9164180baf491ae0078465",
758 778 "branch": "default",
759 779 "phase": "draft",
760 780 "user": "other@place",
761 781 "date": [1200000, 0],
762 782 "desc": "no person",
763 783 "bookmarks": [],
764 784 "tags": [],
765 785 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"]
766 786 },
767 787 {
768 788 "rev": 1,
769 789 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
770 790 "branch": "default",
771 791 "phase": "draft",
772 792 "user": "A. N. Other <other@place>",
773 793 "date": [1100000, 0],
774 794 "desc": "other 1\nother 2\n\nother 3",
775 795 "bookmarks": [],
776 796 "tags": [],
777 797 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"]
778 798 },
779 799 {
780 800 "rev": 0,
781 801 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
782 802 "branch": "default",
783 803 "phase": "draft",
784 804 "user": "User Name <user@hostname>",
785 805 "date": [1000000, 0],
786 806 "desc": "line 1\nline 2",
787 807 "bookmarks": [],
788 808 "tags": [],
789 809 "parents": ["0000000000000000000000000000000000000000"]
790 810 }
791 811 ]
792 812
793 813 $ hg heads -v -Tjson
794 814 [
795 815 {
796 816 "rev": 8,
797 817 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
798 818 "branch": "default",
799 819 "phase": "draft",
800 820 "user": "test",
801 821 "date": [1577872860, 0],
802 822 "desc": "third",
803 823 "bookmarks": [],
804 824 "tags": ["tip"],
805 825 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
806 826 "files": ["fourth", "second", "third"]
807 827 },
808 828 {
809 829 "rev": 6,
810 830 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
811 831 "branch": "default",
812 832 "phase": "draft",
813 833 "user": "person",
814 834 "date": [1500001, 0],
815 835 "desc": "merge",
816 836 "bookmarks": [],
817 837 "tags": [],
818 838 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
819 839 "files": []
820 840 },
821 841 {
822 842 "rev": 4,
823 843 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
824 844 "branch": "foo",
825 845 "phase": "draft",
826 846 "user": "person",
827 847 "date": [1400000, 0],
828 848 "desc": "new branch",
829 849 "bookmarks": [],
830 850 "tags": [],
831 851 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
832 852 "files": []
833 853 }
834 854 ]
835 855
836 856 $ hg log --debug -Tjson
837 857 [
838 858 {
839 859 "rev": 8,
840 860 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
841 861 "branch": "default",
842 862 "phase": "draft",
843 863 "user": "test",
844 864 "date": [1577872860, 0],
845 865 "desc": "third",
846 866 "bookmarks": [],
847 867 "tags": ["tip"],
848 868 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
849 869 "manifest": "94961b75a2da554b4df6fb599e5bfc7d48de0c64",
850 870 "extra": {"branch": "default"},
851 871 "modified": [],
852 872 "added": ["fourth", "third"],
853 873 "removed": ["second"]
854 874 },
855 875 {
856 876 "rev": 7,
857 877 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
858 878 "branch": "default",
859 879 "phase": "draft",
860 880 "user": "User Name <user@hostname>",
861 881 "date": [1000000, 0],
862 882 "desc": "second",
863 883 "bookmarks": [],
864 884 "tags": [],
865 885 "parents": ["0000000000000000000000000000000000000000"],
866 886 "manifest": "f2dbc354b94e5ec0b4f10680ee0cee816101d0bf",
867 887 "extra": {"branch": "default"},
868 888 "modified": [],
869 889 "added": ["second"],
870 890 "removed": []
871 891 },
872 892 {
873 893 "rev": 6,
874 894 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
875 895 "branch": "default",
876 896 "phase": "draft",
877 897 "user": "person",
878 898 "date": [1500001, 0],
879 899 "desc": "merge",
880 900 "bookmarks": [],
881 901 "tags": [],
882 902 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
883 903 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
884 904 "extra": {"branch": "default"},
885 905 "modified": [],
886 906 "added": [],
887 907 "removed": []
888 908 },
889 909 {
890 910 "rev": 5,
891 911 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
892 912 "branch": "default",
893 913 "phase": "draft",
894 914 "user": "person",
895 915 "date": [1500000, 0],
896 916 "desc": "new head",
897 917 "bookmarks": [],
898 918 "tags": [],
899 919 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
900 920 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
901 921 "extra": {"branch": "default"},
902 922 "modified": [],
903 923 "added": ["d"],
904 924 "removed": []
905 925 },
906 926 {
907 927 "rev": 4,
908 928 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
909 929 "branch": "foo",
910 930 "phase": "draft",
911 931 "user": "person",
912 932 "date": [1400000, 0],
913 933 "desc": "new branch",
914 934 "bookmarks": [],
915 935 "tags": [],
916 936 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
917 937 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
918 938 "extra": {"branch": "foo"},
919 939 "modified": [],
920 940 "added": [],
921 941 "removed": []
922 942 },
923 943 {
924 944 "rev": 3,
925 945 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
926 946 "branch": "default",
927 947 "phase": "draft",
928 948 "user": "person",
929 949 "date": [1300000, 0],
930 950 "desc": "no user, no domain",
931 951 "bookmarks": [],
932 952 "tags": [],
933 953 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
934 954 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
935 955 "extra": {"branch": "default"},
936 956 "modified": ["c"],
937 957 "added": [],
938 958 "removed": []
939 959 },
940 960 {
941 961 "rev": 2,
942 962 "node": "97054abb4ab824450e9164180baf491ae0078465",
943 963 "branch": "default",
944 964 "phase": "draft",
945 965 "user": "other@place",
946 966 "date": [1200000, 0],
947 967 "desc": "no person",
948 968 "bookmarks": [],
949 969 "tags": [],
950 970 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
951 971 "manifest": "6e0e82995c35d0d57a52aca8da4e56139e06b4b1",
952 972 "extra": {"branch": "default"},
953 973 "modified": [],
954 974 "added": ["c"],
955 975 "removed": []
956 976 },
957 977 {
958 978 "rev": 1,
959 979 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
960 980 "branch": "default",
961 981 "phase": "draft",
962 982 "user": "A. N. Other <other@place>",
963 983 "date": [1100000, 0],
964 984 "desc": "other 1\nother 2\n\nother 3",
965 985 "bookmarks": [],
966 986 "tags": [],
967 987 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
968 988 "manifest": "4e8d705b1e53e3f9375e0e60dc7b525d8211fe55",
969 989 "extra": {"branch": "default"},
970 990 "modified": [],
971 991 "added": ["b"],
972 992 "removed": []
973 993 },
974 994 {
975 995 "rev": 0,
976 996 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
977 997 "branch": "default",
978 998 "phase": "draft",
979 999 "user": "User Name <user@hostname>",
980 1000 "date": [1000000, 0],
981 1001 "desc": "line 1\nline 2",
982 1002 "bookmarks": [],
983 1003 "tags": [],
984 1004 "parents": ["0000000000000000000000000000000000000000"],
985 1005 "manifest": "a0c8bcbbb45c63b90b70ad007bf38961f64f2af0",
986 1006 "extra": {"branch": "default"},
987 1007 "modified": [],
988 1008 "added": ["a"],
989 1009 "removed": []
990 1010 }
991 1011 ]
992 1012
993 1013 Error if style not readable:
994 1014
995 1015 #if unix-permissions no-root
996 1016 $ touch q
997 1017 $ chmod 0 q
998 1018 $ hg log --style ./q
999 1019 abort: Permission denied: ./q
1000 1020 [255]
1001 1021 #endif
1002 1022
1003 1023 Error if no style:
1004 1024
1005 1025 $ hg log --style notexist
1006 1026 abort: style 'notexist' not found
1007 1027 (available styles: bisect, changelog, compact, default, phases, status, xml)
1008 1028 [255]
1009 1029
1010 1030 $ hg log -T list
1011 1031 available styles: bisect, changelog, compact, default, phases, status, xml
1012 1032 abort: specify a template
1013 1033 [255]
1014 1034
1015 1035 Error if style missing key:
1016 1036
1017 1037 $ echo 'q = q' > t
1018 1038 $ hg log --style ./t
1019 1039 abort: "changeset" not in template map
1020 1040 [255]
1021 1041
1022 1042 Error if style missing value:
1023 1043
1024 1044 $ echo 'changeset =' > t
1025 1045 $ hg log --style t
1026 1046 abort: t:1: missing value
1027 1047 [255]
1028 1048
1029 1049 Error if include fails:
1030 1050
1031 1051 $ echo 'changeset = q' >> t
1032 1052 #if unix-permissions no-root
1033 1053 $ hg log --style ./t
1034 1054 abort: template file ./q: Permission denied
1035 1055 [255]
1036 1056 $ rm q
1037 1057 #endif
1038 1058
1039 1059 Include works:
1040 1060
1041 1061 $ echo '{rev}' > q
1042 1062 $ hg log --style ./t
1043 1063 8
1044 1064 7
1045 1065 6
1046 1066 5
1047 1067 4
1048 1068 3
1049 1069 2
1050 1070 1
1051 1071 0
1052 1072
1053 1073 Check that {phase} works correctly on parents:
1054 1074
1055 1075 $ cat << EOF > parentphase
1056 1076 > changeset_debug = '{rev} ({phase}):{parents}\n'
1057 1077 > parent = ' {rev} ({phase})'
1058 1078 > EOF
1059 1079 $ hg phase -r 5 --public
1060 1080 $ hg phase -r 7 --secret --force
1061 1081 $ hg log --debug -G --style ./parentphase
1062 1082 @ 8 (secret): 7 (secret) -1 (public)
1063 1083 |
1064 1084 o 7 (secret): -1 (public) -1 (public)
1065 1085
1066 1086 o 6 (draft): 5 (public) 4 (draft)
1067 1087 |\
1068 1088 | o 5 (public): 3 (public) -1 (public)
1069 1089 | |
1070 1090 o | 4 (draft): 3 (public) -1 (public)
1071 1091 |/
1072 1092 o 3 (public): 2 (public) -1 (public)
1073 1093 |
1074 1094 o 2 (public): 1 (public) -1 (public)
1075 1095 |
1076 1096 o 1 (public): 0 (public) -1 (public)
1077 1097 |
1078 1098 o 0 (public): -1 (public) -1 (public)
1079 1099
1080 1100
1081 1101 Missing non-standard names give no error (backward compatibility):
1082 1102
1083 1103 $ echo "changeset = '{c}'" > t
1084 1104 $ hg log --style ./t
1085 1105
1086 1106 Defining non-standard name works:
1087 1107
1088 1108 $ cat <<EOF > t
1089 1109 > changeset = '{c}'
1090 1110 > c = q
1091 1111 > EOF
1092 1112 $ hg log --style ./t
1093 1113 8
1094 1114 7
1095 1115 6
1096 1116 5
1097 1117 4
1098 1118 3
1099 1119 2
1100 1120 1
1101 1121 0
1102 1122
1103 1123 ui.style works:
1104 1124
1105 1125 $ echo '[ui]' > .hg/hgrc
1106 1126 $ echo 'style = t' >> .hg/hgrc
1107 1127 $ hg log
1108 1128 8
1109 1129 7
1110 1130 6
1111 1131 5
1112 1132 4
1113 1133 3
1114 1134 2
1115 1135 1
1116 1136 0
1117 1137
1118 1138
1119 1139 Issue338:
1120 1140
1121 1141 $ hg log --style=changelog > changelog
1122 1142
1123 1143 $ cat changelog
1124 1144 2020-01-01 test <test>
1125 1145
1126 1146 * fourth, second, third:
1127 1147 third
1128 1148 [95c24699272e] [tip]
1129 1149
1130 1150 1970-01-12 User Name <user@hostname>
1131 1151
1132 1152 * second:
1133 1153 second
1134 1154 [29114dbae42b]
1135 1155
1136 1156 1970-01-18 person <person>
1137 1157
1138 1158 * merge
1139 1159 [d41e714fe50d]
1140 1160
1141 1161 * d:
1142 1162 new head
1143 1163 [13207e5a10d9]
1144 1164
1145 1165 1970-01-17 person <person>
1146 1166
1147 1167 * new branch
1148 1168 [bbe44766e73d] <foo>
1149 1169
1150 1170 1970-01-16 person <person>
1151 1171
1152 1172 * c:
1153 1173 no user, no domain
1154 1174 [10e46f2dcbf4]
1155 1175
1156 1176 1970-01-14 other <other@place>
1157 1177
1158 1178 * c:
1159 1179 no person
1160 1180 [97054abb4ab8]
1161 1181
1162 1182 1970-01-13 A. N. Other <other@place>
1163 1183
1164 1184 * b:
1165 1185 other 1 other 2
1166 1186
1167 1187 other 3
1168 1188 [b608e9d1a3f0]
1169 1189
1170 1190 1970-01-12 User Name <user@hostname>
1171 1191
1172 1192 * a:
1173 1193 line 1 line 2
1174 1194 [1e4e1b8f71e0]
1175 1195
1176 1196
1177 1197 Issue2130: xml output for 'hg heads' is malformed
1178 1198
1179 1199 $ hg heads --style changelog
1180 1200 2020-01-01 test <test>
1181 1201
1182 1202 * fourth, second, third:
1183 1203 third
1184 1204 [95c24699272e] [tip]
1185 1205
1186 1206 1970-01-18 person <person>
1187 1207
1188 1208 * merge
1189 1209 [d41e714fe50d]
1190 1210
1191 1211 1970-01-17 person <person>
1192 1212
1193 1213 * new branch
1194 1214 [bbe44766e73d] <foo>
1195 1215
1196 1216
1197 1217 Keys work:
1198 1218
1199 1219 $ for key in author branch branches date desc file_adds file_dels file_mods \
1200 1220 > file_copies file_copies_switch files \
1201 1221 > manifest node parents rev tags diffstat extras \
1202 1222 > p1rev p2rev p1node p2node; do
1203 1223 > for mode in '' --verbose --debug; do
1204 1224 > hg log $mode --template "$key$mode: {$key}\n"
1205 1225 > done
1206 1226 > done
1207 1227 author: test
1208 1228 author: User Name <user@hostname>
1209 1229 author: person
1210 1230 author: person
1211 1231 author: person
1212 1232 author: person
1213 1233 author: other@place
1214 1234 author: A. N. Other <other@place>
1215 1235 author: User Name <user@hostname>
1216 1236 author--verbose: test
1217 1237 author--verbose: User Name <user@hostname>
1218 1238 author--verbose: person
1219 1239 author--verbose: person
1220 1240 author--verbose: person
1221 1241 author--verbose: person
1222 1242 author--verbose: other@place
1223 1243 author--verbose: A. N. Other <other@place>
1224 1244 author--verbose: User Name <user@hostname>
1225 1245 author--debug: test
1226 1246 author--debug: User Name <user@hostname>
1227 1247 author--debug: person
1228 1248 author--debug: person
1229 1249 author--debug: person
1230 1250 author--debug: person
1231 1251 author--debug: other@place
1232 1252 author--debug: A. N. Other <other@place>
1233 1253 author--debug: User Name <user@hostname>
1234 1254 branch: default
1235 1255 branch: default
1236 1256 branch: default
1237 1257 branch: default
1238 1258 branch: foo
1239 1259 branch: default
1240 1260 branch: default
1241 1261 branch: default
1242 1262 branch: default
1243 1263 branch--verbose: default
1244 1264 branch--verbose: default
1245 1265 branch--verbose: default
1246 1266 branch--verbose: default
1247 1267 branch--verbose: foo
1248 1268 branch--verbose: default
1249 1269 branch--verbose: default
1250 1270 branch--verbose: default
1251 1271 branch--verbose: default
1252 1272 branch--debug: default
1253 1273 branch--debug: default
1254 1274 branch--debug: default
1255 1275 branch--debug: default
1256 1276 branch--debug: foo
1257 1277 branch--debug: default
1258 1278 branch--debug: default
1259 1279 branch--debug: default
1260 1280 branch--debug: default
1261 1281 branches:
1262 1282 branches:
1263 1283 branches:
1264 1284 branches:
1265 1285 branches: foo
1266 1286 branches:
1267 1287 branches:
1268 1288 branches:
1269 1289 branches:
1270 1290 branches--verbose:
1271 1291 branches--verbose:
1272 1292 branches--verbose:
1273 1293 branches--verbose:
1274 1294 branches--verbose: foo
1275 1295 branches--verbose:
1276 1296 branches--verbose:
1277 1297 branches--verbose:
1278 1298 branches--verbose:
1279 1299 branches--debug:
1280 1300 branches--debug:
1281 1301 branches--debug:
1282 1302 branches--debug:
1283 1303 branches--debug: foo
1284 1304 branches--debug:
1285 1305 branches--debug:
1286 1306 branches--debug:
1287 1307 branches--debug:
1288 1308 date: 1577872860.00
1289 1309 date: 1000000.00
1290 1310 date: 1500001.00
1291 1311 date: 1500000.00
1292 1312 date: 1400000.00
1293 1313 date: 1300000.00
1294 1314 date: 1200000.00
1295 1315 date: 1100000.00
1296 1316 date: 1000000.00
1297 1317 date--verbose: 1577872860.00
1298 1318 date--verbose: 1000000.00
1299 1319 date--verbose: 1500001.00
1300 1320 date--verbose: 1500000.00
1301 1321 date--verbose: 1400000.00
1302 1322 date--verbose: 1300000.00
1303 1323 date--verbose: 1200000.00
1304 1324 date--verbose: 1100000.00
1305 1325 date--verbose: 1000000.00
1306 1326 date--debug: 1577872860.00
1307 1327 date--debug: 1000000.00
1308 1328 date--debug: 1500001.00
1309 1329 date--debug: 1500000.00
1310 1330 date--debug: 1400000.00
1311 1331 date--debug: 1300000.00
1312 1332 date--debug: 1200000.00
1313 1333 date--debug: 1100000.00
1314 1334 date--debug: 1000000.00
1315 1335 desc: third
1316 1336 desc: second
1317 1337 desc: merge
1318 1338 desc: new head
1319 1339 desc: new branch
1320 1340 desc: no user, no domain
1321 1341 desc: no person
1322 1342 desc: other 1
1323 1343 other 2
1324 1344
1325 1345 other 3
1326 1346 desc: line 1
1327 1347 line 2
1328 1348 desc--verbose: third
1329 1349 desc--verbose: second
1330 1350 desc--verbose: merge
1331 1351 desc--verbose: new head
1332 1352 desc--verbose: new branch
1333 1353 desc--verbose: no user, no domain
1334 1354 desc--verbose: no person
1335 1355 desc--verbose: other 1
1336 1356 other 2
1337 1357
1338 1358 other 3
1339 1359 desc--verbose: line 1
1340 1360 line 2
1341 1361 desc--debug: third
1342 1362 desc--debug: second
1343 1363 desc--debug: merge
1344 1364 desc--debug: new head
1345 1365 desc--debug: new branch
1346 1366 desc--debug: no user, no domain
1347 1367 desc--debug: no person
1348 1368 desc--debug: other 1
1349 1369 other 2
1350 1370
1351 1371 other 3
1352 1372 desc--debug: line 1
1353 1373 line 2
1354 1374 file_adds: fourth third
1355 1375 file_adds: second
1356 1376 file_adds:
1357 1377 file_adds: d
1358 1378 file_adds:
1359 1379 file_adds:
1360 1380 file_adds: c
1361 1381 file_adds: b
1362 1382 file_adds: a
1363 1383 file_adds--verbose: fourth third
1364 1384 file_adds--verbose: second
1365 1385 file_adds--verbose:
1366 1386 file_adds--verbose: d
1367 1387 file_adds--verbose:
1368 1388 file_adds--verbose:
1369 1389 file_adds--verbose: c
1370 1390 file_adds--verbose: b
1371 1391 file_adds--verbose: a
1372 1392 file_adds--debug: fourth third
1373 1393 file_adds--debug: second
1374 1394 file_adds--debug:
1375 1395 file_adds--debug: d
1376 1396 file_adds--debug:
1377 1397 file_adds--debug:
1378 1398 file_adds--debug: c
1379 1399 file_adds--debug: b
1380 1400 file_adds--debug: a
1381 1401 file_dels: second
1382 1402 file_dels:
1383 1403 file_dels:
1384 1404 file_dels:
1385 1405 file_dels:
1386 1406 file_dels:
1387 1407 file_dels:
1388 1408 file_dels:
1389 1409 file_dels:
1390 1410 file_dels--verbose: second
1391 1411 file_dels--verbose:
1392 1412 file_dels--verbose:
1393 1413 file_dels--verbose:
1394 1414 file_dels--verbose:
1395 1415 file_dels--verbose:
1396 1416 file_dels--verbose:
1397 1417 file_dels--verbose:
1398 1418 file_dels--verbose:
1399 1419 file_dels--debug: second
1400 1420 file_dels--debug:
1401 1421 file_dels--debug:
1402 1422 file_dels--debug:
1403 1423 file_dels--debug:
1404 1424 file_dels--debug:
1405 1425 file_dels--debug:
1406 1426 file_dels--debug:
1407 1427 file_dels--debug:
1408 1428 file_mods:
1409 1429 file_mods:
1410 1430 file_mods:
1411 1431 file_mods:
1412 1432 file_mods:
1413 1433 file_mods: c
1414 1434 file_mods:
1415 1435 file_mods:
1416 1436 file_mods:
1417 1437 file_mods--verbose:
1418 1438 file_mods--verbose:
1419 1439 file_mods--verbose:
1420 1440 file_mods--verbose:
1421 1441 file_mods--verbose:
1422 1442 file_mods--verbose: c
1423 1443 file_mods--verbose:
1424 1444 file_mods--verbose:
1425 1445 file_mods--verbose:
1426 1446 file_mods--debug:
1427 1447 file_mods--debug:
1428 1448 file_mods--debug:
1429 1449 file_mods--debug:
1430 1450 file_mods--debug:
1431 1451 file_mods--debug: c
1432 1452 file_mods--debug:
1433 1453 file_mods--debug:
1434 1454 file_mods--debug:
1435 1455 file_copies: fourth (second)
1436 1456 file_copies:
1437 1457 file_copies:
1438 1458 file_copies:
1439 1459 file_copies:
1440 1460 file_copies:
1441 1461 file_copies:
1442 1462 file_copies:
1443 1463 file_copies:
1444 1464 file_copies--verbose: fourth (second)
1445 1465 file_copies--verbose:
1446 1466 file_copies--verbose:
1447 1467 file_copies--verbose:
1448 1468 file_copies--verbose:
1449 1469 file_copies--verbose:
1450 1470 file_copies--verbose:
1451 1471 file_copies--verbose:
1452 1472 file_copies--verbose:
1453 1473 file_copies--debug: fourth (second)
1454 1474 file_copies--debug:
1455 1475 file_copies--debug:
1456 1476 file_copies--debug:
1457 1477 file_copies--debug:
1458 1478 file_copies--debug:
1459 1479 file_copies--debug:
1460 1480 file_copies--debug:
1461 1481 file_copies--debug:
1462 1482 file_copies_switch:
1463 1483 file_copies_switch:
1464 1484 file_copies_switch:
1465 1485 file_copies_switch:
1466 1486 file_copies_switch:
1467 1487 file_copies_switch:
1468 1488 file_copies_switch:
1469 1489 file_copies_switch:
1470 1490 file_copies_switch:
1471 1491 file_copies_switch--verbose:
1472 1492 file_copies_switch--verbose:
1473 1493 file_copies_switch--verbose:
1474 1494 file_copies_switch--verbose:
1475 1495 file_copies_switch--verbose:
1476 1496 file_copies_switch--verbose:
1477 1497 file_copies_switch--verbose:
1478 1498 file_copies_switch--verbose:
1479 1499 file_copies_switch--verbose:
1480 1500 file_copies_switch--debug:
1481 1501 file_copies_switch--debug:
1482 1502 file_copies_switch--debug:
1483 1503 file_copies_switch--debug:
1484 1504 file_copies_switch--debug:
1485 1505 file_copies_switch--debug:
1486 1506 file_copies_switch--debug:
1487 1507 file_copies_switch--debug:
1488 1508 file_copies_switch--debug:
1489 1509 files: fourth second third
1490 1510 files: second
1491 1511 files:
1492 1512 files: d
1493 1513 files:
1494 1514 files: c
1495 1515 files: c
1496 1516 files: b
1497 1517 files: a
1498 1518 files--verbose: fourth second third
1499 1519 files--verbose: second
1500 1520 files--verbose:
1501 1521 files--verbose: d
1502 1522 files--verbose:
1503 1523 files--verbose: c
1504 1524 files--verbose: c
1505 1525 files--verbose: b
1506 1526 files--verbose: a
1507 1527 files--debug: fourth second third
1508 1528 files--debug: second
1509 1529 files--debug:
1510 1530 files--debug: d
1511 1531 files--debug:
1512 1532 files--debug: c
1513 1533 files--debug: c
1514 1534 files--debug: b
1515 1535 files--debug: a
1516 1536 manifest: 6:94961b75a2da
1517 1537 manifest: 5:f2dbc354b94e
1518 1538 manifest: 4:4dc3def4f9b4
1519 1539 manifest: 4:4dc3def4f9b4
1520 1540 manifest: 3:cb5a1327723b
1521 1541 manifest: 3:cb5a1327723b
1522 1542 manifest: 2:6e0e82995c35
1523 1543 manifest: 1:4e8d705b1e53
1524 1544 manifest: 0:a0c8bcbbb45c
1525 1545 manifest--verbose: 6:94961b75a2da
1526 1546 manifest--verbose: 5:f2dbc354b94e
1527 1547 manifest--verbose: 4:4dc3def4f9b4
1528 1548 manifest--verbose: 4:4dc3def4f9b4
1529 1549 manifest--verbose: 3:cb5a1327723b
1530 1550 manifest--verbose: 3:cb5a1327723b
1531 1551 manifest--verbose: 2:6e0e82995c35
1532 1552 manifest--verbose: 1:4e8d705b1e53
1533 1553 manifest--verbose: 0:a0c8bcbbb45c
1534 1554 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
1535 1555 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
1536 1556 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1537 1557 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1538 1558 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1539 1559 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1540 1560 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
1541 1561 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
1542 1562 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
1543 1563 node: 95c24699272ef57d062b8bccc32c878bf841784a
1544 1564 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1545 1565 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1546 1566 node: 13207e5a10d9fd28ec424934298e176197f2c67f
1547 1567 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1548 1568 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1549 1569 node: 97054abb4ab824450e9164180baf491ae0078465
1550 1570 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1551 1571 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1552 1572 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
1553 1573 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1554 1574 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1555 1575 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1556 1576 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1557 1577 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1558 1578 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1559 1579 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1560 1580 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1561 1581 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
1562 1582 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1563 1583 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1564 1584 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1565 1585 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1566 1586 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1567 1587 node--debug: 97054abb4ab824450e9164180baf491ae0078465
1568 1588 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1569 1589 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1570 1590 parents:
1571 1591 parents: -1:000000000000
1572 1592 parents: 5:13207e5a10d9 4:bbe44766e73d
1573 1593 parents: 3:10e46f2dcbf4
1574 1594 parents:
1575 1595 parents:
1576 1596 parents:
1577 1597 parents:
1578 1598 parents:
1579 1599 parents--verbose:
1580 1600 parents--verbose: -1:000000000000
1581 1601 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
1582 1602 parents--verbose: 3:10e46f2dcbf4
1583 1603 parents--verbose:
1584 1604 parents--verbose:
1585 1605 parents--verbose:
1586 1606 parents--verbose:
1587 1607 parents--verbose:
1588 1608 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
1589 1609 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1590 1610 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
1591 1611 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1592 1612 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1593 1613 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
1594 1614 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
1595 1615 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
1596 1616 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1597 1617 rev: 8
1598 1618 rev: 7
1599 1619 rev: 6
1600 1620 rev: 5
1601 1621 rev: 4
1602 1622 rev: 3
1603 1623 rev: 2
1604 1624 rev: 1
1605 1625 rev: 0
1606 1626 rev--verbose: 8
1607 1627 rev--verbose: 7
1608 1628 rev--verbose: 6
1609 1629 rev--verbose: 5
1610 1630 rev--verbose: 4
1611 1631 rev--verbose: 3
1612 1632 rev--verbose: 2
1613 1633 rev--verbose: 1
1614 1634 rev--verbose: 0
1615 1635 rev--debug: 8
1616 1636 rev--debug: 7
1617 1637 rev--debug: 6
1618 1638 rev--debug: 5
1619 1639 rev--debug: 4
1620 1640 rev--debug: 3
1621 1641 rev--debug: 2
1622 1642 rev--debug: 1
1623 1643 rev--debug: 0
1624 1644 tags: tip
1625 1645 tags:
1626 1646 tags:
1627 1647 tags:
1628 1648 tags:
1629 1649 tags:
1630 1650 tags:
1631 1651 tags:
1632 1652 tags:
1633 1653 tags--verbose: tip
1634 1654 tags--verbose:
1635 1655 tags--verbose:
1636 1656 tags--verbose:
1637 1657 tags--verbose:
1638 1658 tags--verbose:
1639 1659 tags--verbose:
1640 1660 tags--verbose:
1641 1661 tags--verbose:
1642 1662 tags--debug: tip
1643 1663 tags--debug:
1644 1664 tags--debug:
1645 1665 tags--debug:
1646 1666 tags--debug:
1647 1667 tags--debug:
1648 1668 tags--debug:
1649 1669 tags--debug:
1650 1670 tags--debug:
1651 1671 diffstat: 3: +2/-1
1652 1672 diffstat: 1: +1/-0
1653 1673 diffstat: 0: +0/-0
1654 1674 diffstat: 1: +1/-0
1655 1675 diffstat: 0: +0/-0
1656 1676 diffstat: 1: +1/-0
1657 1677 diffstat: 1: +4/-0
1658 1678 diffstat: 1: +2/-0
1659 1679 diffstat: 1: +1/-0
1660 1680 diffstat--verbose: 3: +2/-1
1661 1681 diffstat--verbose: 1: +1/-0
1662 1682 diffstat--verbose: 0: +0/-0
1663 1683 diffstat--verbose: 1: +1/-0
1664 1684 diffstat--verbose: 0: +0/-0
1665 1685 diffstat--verbose: 1: +1/-0
1666 1686 diffstat--verbose: 1: +4/-0
1667 1687 diffstat--verbose: 1: +2/-0
1668 1688 diffstat--verbose: 1: +1/-0
1669 1689 diffstat--debug: 3: +2/-1
1670 1690 diffstat--debug: 1: +1/-0
1671 1691 diffstat--debug: 0: +0/-0
1672 1692 diffstat--debug: 1: +1/-0
1673 1693 diffstat--debug: 0: +0/-0
1674 1694 diffstat--debug: 1: +1/-0
1675 1695 diffstat--debug: 1: +4/-0
1676 1696 diffstat--debug: 1: +2/-0
1677 1697 diffstat--debug: 1: +1/-0
1678 1698 extras: branch=default
1679 1699 extras: branch=default
1680 1700 extras: branch=default
1681 1701 extras: branch=default
1682 1702 extras: branch=foo
1683 1703 extras: branch=default
1684 1704 extras: branch=default
1685 1705 extras: branch=default
1686 1706 extras: branch=default
1687 1707 extras--verbose: branch=default
1688 1708 extras--verbose: branch=default
1689 1709 extras--verbose: branch=default
1690 1710 extras--verbose: branch=default
1691 1711 extras--verbose: branch=foo
1692 1712 extras--verbose: branch=default
1693 1713 extras--verbose: branch=default
1694 1714 extras--verbose: branch=default
1695 1715 extras--verbose: branch=default
1696 1716 extras--debug: branch=default
1697 1717 extras--debug: branch=default
1698 1718 extras--debug: branch=default
1699 1719 extras--debug: branch=default
1700 1720 extras--debug: branch=foo
1701 1721 extras--debug: branch=default
1702 1722 extras--debug: branch=default
1703 1723 extras--debug: branch=default
1704 1724 extras--debug: branch=default
1705 1725 p1rev: 7
1706 1726 p1rev: -1
1707 1727 p1rev: 5
1708 1728 p1rev: 3
1709 1729 p1rev: 3
1710 1730 p1rev: 2
1711 1731 p1rev: 1
1712 1732 p1rev: 0
1713 1733 p1rev: -1
1714 1734 p1rev--verbose: 7
1715 1735 p1rev--verbose: -1
1716 1736 p1rev--verbose: 5
1717 1737 p1rev--verbose: 3
1718 1738 p1rev--verbose: 3
1719 1739 p1rev--verbose: 2
1720 1740 p1rev--verbose: 1
1721 1741 p1rev--verbose: 0
1722 1742 p1rev--verbose: -1
1723 1743 p1rev--debug: 7
1724 1744 p1rev--debug: -1
1725 1745 p1rev--debug: 5
1726 1746 p1rev--debug: 3
1727 1747 p1rev--debug: 3
1728 1748 p1rev--debug: 2
1729 1749 p1rev--debug: 1
1730 1750 p1rev--debug: 0
1731 1751 p1rev--debug: -1
1732 1752 p2rev: -1
1733 1753 p2rev: -1
1734 1754 p2rev: 4
1735 1755 p2rev: -1
1736 1756 p2rev: -1
1737 1757 p2rev: -1
1738 1758 p2rev: -1
1739 1759 p2rev: -1
1740 1760 p2rev: -1
1741 1761 p2rev--verbose: -1
1742 1762 p2rev--verbose: -1
1743 1763 p2rev--verbose: 4
1744 1764 p2rev--verbose: -1
1745 1765 p2rev--verbose: -1
1746 1766 p2rev--verbose: -1
1747 1767 p2rev--verbose: -1
1748 1768 p2rev--verbose: -1
1749 1769 p2rev--verbose: -1
1750 1770 p2rev--debug: -1
1751 1771 p2rev--debug: -1
1752 1772 p2rev--debug: 4
1753 1773 p2rev--debug: -1
1754 1774 p2rev--debug: -1
1755 1775 p2rev--debug: -1
1756 1776 p2rev--debug: -1
1757 1777 p2rev--debug: -1
1758 1778 p2rev--debug: -1
1759 1779 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1760 1780 p1node: 0000000000000000000000000000000000000000
1761 1781 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
1762 1782 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1763 1783 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1764 1784 p1node: 97054abb4ab824450e9164180baf491ae0078465
1765 1785 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1766 1786 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1767 1787 p1node: 0000000000000000000000000000000000000000
1768 1788 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1769 1789 p1node--verbose: 0000000000000000000000000000000000000000
1770 1790 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1771 1791 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1772 1792 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1773 1793 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1774 1794 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1775 1795 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1776 1796 p1node--verbose: 0000000000000000000000000000000000000000
1777 1797 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1778 1798 p1node--debug: 0000000000000000000000000000000000000000
1779 1799 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1780 1800 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1781 1801 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1782 1802 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
1783 1803 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1784 1804 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1785 1805 p1node--debug: 0000000000000000000000000000000000000000
1786 1806 p2node: 0000000000000000000000000000000000000000
1787 1807 p2node: 0000000000000000000000000000000000000000
1788 1808 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1789 1809 p2node: 0000000000000000000000000000000000000000
1790 1810 p2node: 0000000000000000000000000000000000000000
1791 1811 p2node: 0000000000000000000000000000000000000000
1792 1812 p2node: 0000000000000000000000000000000000000000
1793 1813 p2node: 0000000000000000000000000000000000000000
1794 1814 p2node: 0000000000000000000000000000000000000000
1795 1815 p2node--verbose: 0000000000000000000000000000000000000000
1796 1816 p2node--verbose: 0000000000000000000000000000000000000000
1797 1817 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1798 1818 p2node--verbose: 0000000000000000000000000000000000000000
1799 1819 p2node--verbose: 0000000000000000000000000000000000000000
1800 1820 p2node--verbose: 0000000000000000000000000000000000000000
1801 1821 p2node--verbose: 0000000000000000000000000000000000000000
1802 1822 p2node--verbose: 0000000000000000000000000000000000000000
1803 1823 p2node--verbose: 0000000000000000000000000000000000000000
1804 1824 p2node--debug: 0000000000000000000000000000000000000000
1805 1825 p2node--debug: 0000000000000000000000000000000000000000
1806 1826 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1807 1827 p2node--debug: 0000000000000000000000000000000000000000
1808 1828 p2node--debug: 0000000000000000000000000000000000000000
1809 1829 p2node--debug: 0000000000000000000000000000000000000000
1810 1830 p2node--debug: 0000000000000000000000000000000000000000
1811 1831 p2node--debug: 0000000000000000000000000000000000000000
1812 1832 p2node--debug: 0000000000000000000000000000000000000000
1813 1833
1814 1834 Filters work:
1815 1835
1816 1836 $ hg log --template '{author|domain}\n'
1817 1837
1818 1838 hostname
1819 1839
1820 1840
1821 1841
1822 1842
1823 1843 place
1824 1844 place
1825 1845 hostname
1826 1846
1827 1847 $ hg log --template '{author|person}\n'
1828 1848 test
1829 1849 User Name
1830 1850 person
1831 1851 person
1832 1852 person
1833 1853 person
1834 1854 other
1835 1855 A. N. Other
1836 1856 User Name
1837 1857
1838 1858 $ hg log --template '{author|user}\n'
1839 1859 test
1840 1860 user
1841 1861 person
1842 1862 person
1843 1863 person
1844 1864 person
1845 1865 other
1846 1866 other
1847 1867 user
1848 1868
1849 1869 $ hg log --template '{date|date}\n'
1850 1870 Wed Jan 01 10:01:00 2020 +0000
1851 1871 Mon Jan 12 13:46:40 1970 +0000
1852 1872 Sun Jan 18 08:40:01 1970 +0000
1853 1873 Sun Jan 18 08:40:00 1970 +0000
1854 1874 Sat Jan 17 04:53:20 1970 +0000
1855 1875 Fri Jan 16 01:06:40 1970 +0000
1856 1876 Wed Jan 14 21:20:00 1970 +0000
1857 1877 Tue Jan 13 17:33:20 1970 +0000
1858 1878 Mon Jan 12 13:46:40 1970 +0000
1859 1879
1860 1880 $ hg log --template '{date|isodate}\n'
1861 1881 2020-01-01 10:01 +0000
1862 1882 1970-01-12 13:46 +0000
1863 1883 1970-01-18 08:40 +0000
1864 1884 1970-01-18 08:40 +0000
1865 1885 1970-01-17 04:53 +0000
1866 1886 1970-01-16 01:06 +0000
1867 1887 1970-01-14 21:20 +0000
1868 1888 1970-01-13 17:33 +0000
1869 1889 1970-01-12 13:46 +0000
1870 1890
1871 1891 $ hg log --template '{date|isodatesec}\n'
1872 1892 2020-01-01 10:01:00 +0000
1873 1893 1970-01-12 13:46:40 +0000
1874 1894 1970-01-18 08:40:01 +0000
1875 1895 1970-01-18 08:40:00 +0000
1876 1896 1970-01-17 04:53:20 +0000
1877 1897 1970-01-16 01:06:40 +0000
1878 1898 1970-01-14 21:20:00 +0000
1879 1899 1970-01-13 17:33:20 +0000
1880 1900 1970-01-12 13:46:40 +0000
1881 1901
1882 1902 $ hg log --template '{date|rfc822date}\n'
1883 1903 Wed, 01 Jan 2020 10:01:00 +0000
1884 1904 Mon, 12 Jan 1970 13:46:40 +0000
1885 1905 Sun, 18 Jan 1970 08:40:01 +0000
1886 1906 Sun, 18 Jan 1970 08:40:00 +0000
1887 1907 Sat, 17 Jan 1970 04:53:20 +0000
1888 1908 Fri, 16 Jan 1970 01:06:40 +0000
1889 1909 Wed, 14 Jan 1970 21:20:00 +0000
1890 1910 Tue, 13 Jan 1970 17:33:20 +0000
1891 1911 Mon, 12 Jan 1970 13:46:40 +0000
1892 1912
1893 1913 $ hg log --template '{desc|firstline}\n'
1894 1914 third
1895 1915 second
1896 1916 merge
1897 1917 new head
1898 1918 new branch
1899 1919 no user, no domain
1900 1920 no person
1901 1921 other 1
1902 1922 line 1
1903 1923
1904 1924 $ hg log --template '{node|short}\n'
1905 1925 95c24699272e
1906 1926 29114dbae42b
1907 1927 d41e714fe50d
1908 1928 13207e5a10d9
1909 1929 bbe44766e73d
1910 1930 10e46f2dcbf4
1911 1931 97054abb4ab8
1912 1932 b608e9d1a3f0
1913 1933 1e4e1b8f71e0
1914 1934
1915 1935 $ hg log --template '<changeset author="{author|xmlescape}"/>\n'
1916 1936 <changeset author="test"/>
1917 1937 <changeset author="User Name &lt;user@hostname&gt;"/>
1918 1938 <changeset author="person"/>
1919 1939 <changeset author="person"/>
1920 1940 <changeset author="person"/>
1921 1941 <changeset author="person"/>
1922 1942 <changeset author="other@place"/>
1923 1943 <changeset author="A. N. Other &lt;other@place&gt;"/>
1924 1944 <changeset author="User Name &lt;user@hostname&gt;"/>
1925 1945
1926 1946 $ hg log --template '{rev}: {children}\n'
1927 1947 8:
1928 1948 7: 8:95c24699272e
1929 1949 6:
1930 1950 5: 6:d41e714fe50d
1931 1951 4: 6:d41e714fe50d
1932 1952 3: 4:bbe44766e73d 5:13207e5a10d9
1933 1953 2: 3:10e46f2dcbf4
1934 1954 1: 2:97054abb4ab8
1935 1955 0: 1:b608e9d1a3f0
1936 1956
1937 1957 Formatnode filter works:
1938 1958
1939 1959 $ hg -q log -r 0 --template '{node|formatnode}\n'
1940 1960 1e4e1b8f71e0
1941 1961
1942 1962 $ hg log -r 0 --template '{node|formatnode}\n'
1943 1963 1e4e1b8f71e0
1944 1964
1945 1965 $ hg -v log -r 0 --template '{node|formatnode}\n'
1946 1966 1e4e1b8f71e0
1947 1967
1948 1968 $ hg --debug log -r 0 --template '{node|formatnode}\n'
1949 1969 1e4e1b8f71e05681d422154f5421e385fec3454f
1950 1970
1951 1971 Age filter:
1952 1972
1953 1973 $ hg init unstable-hash
1954 1974 $ cd unstable-hash
1955 1975 $ hg log --template '{date|age}\n' > /dev/null || exit 1
1956 1976
1957 1977 >>> from datetime import datetime, timedelta
1958 1978 >>> fp = open('a', 'w')
1959 1979 >>> n = datetime.now() + timedelta(366 * 7)
1960 1980 >>> fp.write('%d-%d-%d 00:00' % (n.year, n.month, n.day))
1961 1981 >>> fp.close()
1962 1982 $ hg add a
1963 1983 $ hg commit -m future -d "`cat a`"
1964 1984
1965 1985 $ hg log -l1 --template '{date|age}\n'
1966 1986 7 years from now
1967 1987
1968 1988 $ cd ..
1969 1989 $ rm -rf unstable-hash
1970 1990
1971 1991 Add a dummy commit to make up for the instability of the above:
1972 1992
1973 1993 $ echo a > a
1974 1994 $ hg add a
1975 1995 $ hg ci -m future
1976 1996
1977 1997 Count filter:
1978 1998
1979 1999 $ hg log -l1 --template '{node|count} {node|short|count}\n'
1980 2000 40 12
1981 2001
1982 2002 $ hg log -l1 --template '{revset("null^")|count} {revset(".")|count} {revset("0::3")|count}\n'
1983 2003 0 1 4
1984 2004
1985 2005 $ hg log -G --template '{rev}: children: {children|count}, \
1986 2006 > tags: {tags|count}, file_adds: {file_adds|count}, \
1987 2007 > ancestors: {revset("ancestors(%s)", rev)|count}'
1988 2008 @ 9: children: 0, tags: 1, file_adds: 1, ancestors: 3
1989 2009 |
1990 2010 o 8: children: 1, tags: 0, file_adds: 2, ancestors: 2
1991 2011 |
1992 2012 o 7: children: 1, tags: 0, file_adds: 1, ancestors: 1
1993 2013
1994 2014 o 6: children: 0, tags: 0, file_adds: 0, ancestors: 7
1995 2015 |\
1996 2016 | o 5: children: 1, tags: 0, file_adds: 1, ancestors: 5
1997 2017 | |
1998 2018 o | 4: children: 1, tags: 0, file_adds: 0, ancestors: 5
1999 2019 |/
2000 2020 o 3: children: 2, tags: 0, file_adds: 0, ancestors: 4
2001 2021 |
2002 2022 o 2: children: 1, tags: 0, file_adds: 1, ancestors: 3
2003 2023 |
2004 2024 o 1: children: 1, tags: 0, file_adds: 1, ancestors: 2
2005 2025 |
2006 2026 o 0: children: 1, tags: 0, file_adds: 1, ancestors: 1
2007 2027
2008 2028
2009 2029 Upper/lower filters:
2010 2030
2011 2031 $ hg log -r0 --template '{branch|upper}\n'
2012 2032 DEFAULT
2013 2033 $ hg log -r0 --template '{author|lower}\n'
2014 2034 user name <user@hostname>
2015 2035 $ hg log -r0 --template '{date|upper}\n'
2016 2036 abort: template filter 'upper' is not compatible with keyword 'date'
2017 2037 [255]
2018 2038
2019 2039 Add a commit that does all possible modifications at once
2020 2040
2021 2041 $ echo modify >> third
2022 2042 $ touch b
2023 2043 $ hg add b
2024 2044 $ hg mv fourth fifth
2025 2045 $ hg rm a
2026 2046 $ hg ci -m "Modify, add, remove, rename"
2027 2047
2028 2048 Check the status template
2029 2049
2030 2050 $ cat <<EOF >> $HGRCPATH
2031 2051 > [extensions]
2032 2052 > color=
2033 2053 > EOF
2034 2054
2035 2055 $ hg log -T status -r 10
2036 2056 changeset: 10:0f9759ec227a
2037 2057 tag: tip
2038 2058 user: test
2039 2059 date: Thu Jan 01 00:00:00 1970 +0000
2040 2060 summary: Modify, add, remove, rename
2041 2061 files:
2042 2062 M third
2043 2063 A b
2044 2064 A fifth
2045 2065 R a
2046 2066 R fourth
2047 2067
2048 2068 $ hg log -T status -C -r 10
2049 2069 changeset: 10:0f9759ec227a
2050 2070 tag: tip
2051 2071 user: test
2052 2072 date: Thu Jan 01 00:00:00 1970 +0000
2053 2073 summary: Modify, add, remove, rename
2054 2074 files:
2055 2075 M third
2056 2076 A b
2057 2077 A fifth
2058 2078 fourth
2059 2079 R a
2060 2080 R fourth
2061 2081
2062 2082 $ hg log -T status -C -r 10 -v
2063 2083 changeset: 10:0f9759ec227a
2064 2084 tag: tip
2065 2085 user: test
2066 2086 date: Thu Jan 01 00:00:00 1970 +0000
2067 2087 description:
2068 2088 Modify, add, remove, rename
2069 2089
2070 2090 files:
2071 2091 M third
2072 2092 A b
2073 2093 A fifth
2074 2094 fourth
2075 2095 R a
2076 2096 R fourth
2077 2097
2078 2098 $ hg log -T status -C -r 10 --debug
2079 2099 changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c
2080 2100 tag: tip
2081 2101 phase: secret
2082 2102 parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066
2083 2103 parent: -1:0000000000000000000000000000000000000000
2084 2104 manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567
2085 2105 user: test
2086 2106 date: Thu Jan 01 00:00:00 1970 +0000
2087 2107 extra: branch=default
2088 2108 description:
2089 2109 Modify, add, remove, rename
2090 2110
2091 2111 files:
2092 2112 M third
2093 2113 A b
2094 2114 A fifth
2095 2115 fourth
2096 2116 R a
2097 2117 R fourth
2098 2118
2099 2119 $ hg log -T status -C -r 10 --quiet
2100 2120 10:0f9759ec227a
2101 2121 $ hg --color=debug log -T status -r 10
2102 2122 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2103 2123 [log.tag|tag: tip]
2104 2124 [log.user|user: test]
2105 2125 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2106 2126 [log.summary|summary: Modify, add, remove, rename]
2107 2127 [ui.note log.files|files:]
2108 2128 [status.modified|M third]
2109 2129 [status.added|A b]
2110 2130 [status.added|A fifth]
2111 2131 [status.removed|R a]
2112 2132 [status.removed|R fourth]
2113 2133
2114 2134 $ hg --color=debug log -T status -C -r 10
2115 2135 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2116 2136 [log.tag|tag: tip]
2117 2137 [log.user|user: test]
2118 2138 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2119 2139 [log.summary|summary: Modify, add, remove, rename]
2120 2140 [ui.note log.files|files:]
2121 2141 [status.modified|M third]
2122 2142 [status.added|A b]
2123 2143 [status.added|A fifth]
2124 2144 [status.copied| fourth]
2125 2145 [status.removed|R a]
2126 2146 [status.removed|R fourth]
2127 2147
2128 2148 $ hg --color=debug log -T status -C -r 10 -v
2129 2149 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2130 2150 [log.tag|tag: tip]
2131 2151 [log.user|user: test]
2132 2152 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2133 2153 [ui.note log.description|description:]
2134 2154 [ui.note log.description|Modify, add, remove, rename]
2135 2155
2136 2156 [ui.note log.files|files:]
2137 2157 [status.modified|M third]
2138 2158 [status.added|A b]
2139 2159 [status.added|A fifth]
2140 2160 [status.copied| fourth]
2141 2161 [status.removed|R a]
2142 2162 [status.removed|R fourth]
2143 2163
2144 2164 $ hg --color=debug log -T status -C -r 10 --debug
2145 2165 [log.changeset changeset.secret|changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c]
2146 2166 [log.tag|tag: tip]
2147 2167 [log.phase|phase: secret]
2148 2168 [log.parent changeset.secret|parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066]
2149 2169 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2150 2170 [ui.debug log.manifest|manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567]
2151 2171 [log.user|user: test]
2152 2172 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2153 2173 [ui.debug log.extra|extra: branch=default]
2154 2174 [ui.note log.description|description:]
2155 2175 [ui.note log.description|Modify, add, remove, rename]
2156 2176
2157 2177 [ui.note log.files|files:]
2158 2178 [status.modified|M third]
2159 2179 [status.added|A b]
2160 2180 [status.added|A fifth]
2161 2181 [status.copied| fourth]
2162 2182 [status.removed|R a]
2163 2183 [status.removed|R fourth]
2164 2184
2165 2185 $ hg --color=debug log -T status -C -r 10 --quiet
2166 2186 [log.node|10:0f9759ec227a]
2167 2187
2168 2188 Check the bisect template
2169 2189
2170 2190 $ hg bisect -g 1
2171 2191 $ hg bisect -b 3 --noupdate
2172 2192 Testing changeset 2:97054abb4ab8 (2 changesets remaining, ~1 tests)
2173 2193 $ hg log -T bisect -r 0:4
2174 2194 changeset: 0:1e4e1b8f71e0
2175 2195 bisect: good (implicit)
2176 2196 user: User Name <user@hostname>
2177 2197 date: Mon Jan 12 13:46:40 1970 +0000
2178 2198 summary: line 1
2179 2199
2180 2200 changeset: 1:b608e9d1a3f0
2181 2201 bisect: good
2182 2202 user: A. N. Other <other@place>
2183 2203 date: Tue Jan 13 17:33:20 1970 +0000
2184 2204 summary: other 1
2185 2205
2186 2206 changeset: 2:97054abb4ab8
2187 2207 bisect: untested
2188 2208 user: other@place
2189 2209 date: Wed Jan 14 21:20:00 1970 +0000
2190 2210 summary: no person
2191 2211
2192 2212 changeset: 3:10e46f2dcbf4
2193 2213 bisect: bad
2194 2214 user: person
2195 2215 date: Fri Jan 16 01:06:40 1970 +0000
2196 2216 summary: no user, no domain
2197 2217
2198 2218 changeset: 4:bbe44766e73d
2199 2219 bisect: bad (implicit)
2200 2220 branch: foo
2201 2221 user: person
2202 2222 date: Sat Jan 17 04:53:20 1970 +0000
2203 2223 summary: new branch
2204 2224
2205 2225 $ hg log --debug -T bisect -r 0:4
2206 2226 changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2207 2227 bisect: good (implicit)
2208 2228 phase: public
2209 2229 parent: -1:0000000000000000000000000000000000000000
2210 2230 parent: -1:0000000000000000000000000000000000000000
2211 2231 manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
2212 2232 user: User Name <user@hostname>
2213 2233 date: Mon Jan 12 13:46:40 1970 +0000
2214 2234 files+: a
2215 2235 extra: branch=default
2216 2236 description:
2217 2237 line 1
2218 2238 line 2
2219 2239
2220 2240
2221 2241 changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2222 2242 bisect: good
2223 2243 phase: public
2224 2244 parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2225 2245 parent: -1:0000000000000000000000000000000000000000
2226 2246 manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
2227 2247 user: A. N. Other <other@place>
2228 2248 date: Tue Jan 13 17:33:20 1970 +0000
2229 2249 files+: b
2230 2250 extra: branch=default
2231 2251 description:
2232 2252 other 1
2233 2253 other 2
2234 2254
2235 2255 other 3
2236 2256
2237 2257
2238 2258 changeset: 2:97054abb4ab824450e9164180baf491ae0078465
2239 2259 bisect: untested
2240 2260 phase: public
2241 2261 parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2242 2262 parent: -1:0000000000000000000000000000000000000000
2243 2263 manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
2244 2264 user: other@place
2245 2265 date: Wed Jan 14 21:20:00 1970 +0000
2246 2266 files+: c
2247 2267 extra: branch=default
2248 2268 description:
2249 2269 no person
2250 2270
2251 2271
2252 2272 changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2253 2273 bisect: bad
2254 2274 phase: public
2255 2275 parent: 2:97054abb4ab824450e9164180baf491ae0078465
2256 2276 parent: -1:0000000000000000000000000000000000000000
2257 2277 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2258 2278 user: person
2259 2279 date: Fri Jan 16 01:06:40 1970 +0000
2260 2280 files: c
2261 2281 extra: branch=default
2262 2282 description:
2263 2283 no user, no domain
2264 2284
2265 2285
2266 2286 changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
2267 2287 bisect: bad (implicit)
2268 2288 branch: foo
2269 2289 phase: draft
2270 2290 parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2271 2291 parent: -1:0000000000000000000000000000000000000000
2272 2292 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2273 2293 user: person
2274 2294 date: Sat Jan 17 04:53:20 1970 +0000
2275 2295 extra: branch=foo
2276 2296 description:
2277 2297 new branch
2278 2298
2279 2299
2280 2300 $ hg log -v -T bisect -r 0:4
2281 2301 changeset: 0:1e4e1b8f71e0
2282 2302 bisect: good (implicit)
2283 2303 user: User Name <user@hostname>
2284 2304 date: Mon Jan 12 13:46:40 1970 +0000
2285 2305 files: a
2286 2306 description:
2287 2307 line 1
2288 2308 line 2
2289 2309
2290 2310
2291 2311 changeset: 1:b608e9d1a3f0
2292 2312 bisect: good
2293 2313 user: A. N. Other <other@place>
2294 2314 date: Tue Jan 13 17:33:20 1970 +0000
2295 2315 files: b
2296 2316 description:
2297 2317 other 1
2298 2318 other 2
2299 2319
2300 2320 other 3
2301 2321
2302 2322
2303 2323 changeset: 2:97054abb4ab8
2304 2324 bisect: untested
2305 2325 user: other@place
2306 2326 date: Wed Jan 14 21:20:00 1970 +0000
2307 2327 files: c
2308 2328 description:
2309 2329 no person
2310 2330
2311 2331
2312 2332 changeset: 3:10e46f2dcbf4
2313 2333 bisect: bad
2314 2334 user: person
2315 2335 date: Fri Jan 16 01:06:40 1970 +0000
2316 2336 files: c
2317 2337 description:
2318 2338 no user, no domain
2319 2339
2320 2340
2321 2341 changeset: 4:bbe44766e73d
2322 2342 bisect: bad (implicit)
2323 2343 branch: foo
2324 2344 user: person
2325 2345 date: Sat Jan 17 04:53:20 1970 +0000
2326 2346 description:
2327 2347 new branch
2328 2348
2329 2349
2330 2350 $ hg --color=debug log -T bisect -r 0:4
2331 2351 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2332 2352 [log.bisect bisect.good|bisect: good (implicit)]
2333 2353 [log.user|user: User Name <user@hostname>]
2334 2354 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2335 2355 [log.summary|summary: line 1]
2336 2356
2337 2357 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2338 2358 [log.bisect bisect.good|bisect: good]
2339 2359 [log.user|user: A. N. Other <other@place>]
2340 2360 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2341 2361 [log.summary|summary: other 1]
2342 2362
2343 2363 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2344 2364 [log.bisect bisect.untested|bisect: untested]
2345 2365 [log.user|user: other@place]
2346 2366 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2347 2367 [log.summary|summary: no person]
2348 2368
2349 2369 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2350 2370 [log.bisect bisect.bad|bisect: bad]
2351 2371 [log.user|user: person]
2352 2372 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2353 2373 [log.summary|summary: no user, no domain]
2354 2374
2355 2375 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2356 2376 [log.bisect bisect.bad|bisect: bad (implicit)]
2357 2377 [log.branch|branch: foo]
2358 2378 [log.user|user: person]
2359 2379 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2360 2380 [log.summary|summary: new branch]
2361 2381
2362 2382 $ hg --color=debug log --debug -T bisect -r 0:4
2363 2383 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2364 2384 [log.bisect bisect.good|bisect: good (implicit)]
2365 2385 [log.phase|phase: public]
2366 2386 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2367 2387 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2368 2388 [ui.debug log.manifest|manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0]
2369 2389 [log.user|user: User Name <user@hostname>]
2370 2390 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2371 2391 [ui.debug log.files|files+: a]
2372 2392 [ui.debug log.extra|extra: branch=default]
2373 2393 [ui.note log.description|description:]
2374 2394 [ui.note log.description|line 1
2375 2395 line 2]
2376 2396
2377 2397
2378 2398 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2379 2399 [log.bisect bisect.good|bisect: good]
2380 2400 [log.phase|phase: public]
2381 2401 [log.parent changeset.public|parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2382 2402 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2383 2403 [ui.debug log.manifest|manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55]
2384 2404 [log.user|user: A. N. Other <other@place>]
2385 2405 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2386 2406 [ui.debug log.files|files+: b]
2387 2407 [ui.debug log.extra|extra: branch=default]
2388 2408 [ui.note log.description|description:]
2389 2409 [ui.note log.description|other 1
2390 2410 other 2
2391 2411
2392 2412 other 3]
2393 2413
2394 2414
2395 2415 [log.changeset changeset.public|changeset: 2:97054abb4ab824450e9164180baf491ae0078465]
2396 2416 [log.bisect bisect.untested|bisect: untested]
2397 2417 [log.phase|phase: public]
2398 2418 [log.parent changeset.public|parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2399 2419 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2400 2420 [ui.debug log.manifest|manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1]
2401 2421 [log.user|user: other@place]
2402 2422 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2403 2423 [ui.debug log.files|files+: c]
2404 2424 [ui.debug log.extra|extra: branch=default]
2405 2425 [ui.note log.description|description:]
2406 2426 [ui.note log.description|no person]
2407 2427
2408 2428
2409 2429 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2410 2430 [log.bisect bisect.bad|bisect: bad]
2411 2431 [log.phase|phase: public]
2412 2432 [log.parent changeset.public|parent: 2:97054abb4ab824450e9164180baf491ae0078465]
2413 2433 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2414 2434 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2415 2435 [log.user|user: person]
2416 2436 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2417 2437 [ui.debug log.files|files: c]
2418 2438 [ui.debug log.extra|extra: branch=default]
2419 2439 [ui.note log.description|description:]
2420 2440 [ui.note log.description|no user, no domain]
2421 2441
2422 2442
2423 2443 [log.changeset changeset.draft|changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74]
2424 2444 [log.bisect bisect.bad|bisect: bad (implicit)]
2425 2445 [log.branch|branch: foo]
2426 2446 [log.phase|phase: draft]
2427 2447 [log.parent changeset.public|parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2428 2448 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2429 2449 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2430 2450 [log.user|user: person]
2431 2451 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2432 2452 [ui.debug log.extra|extra: branch=foo]
2433 2453 [ui.note log.description|description:]
2434 2454 [ui.note log.description|new branch]
2435 2455
2436 2456
2437 2457 $ hg --color=debug log -v -T bisect -r 0:4
2438 2458 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2439 2459 [log.bisect bisect.good|bisect: good (implicit)]
2440 2460 [log.user|user: User Name <user@hostname>]
2441 2461 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2442 2462 [ui.note log.files|files: a]
2443 2463 [ui.note log.description|description:]
2444 2464 [ui.note log.description|line 1
2445 2465 line 2]
2446 2466
2447 2467
2448 2468 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2449 2469 [log.bisect bisect.good|bisect: good]
2450 2470 [log.user|user: A. N. Other <other@place>]
2451 2471 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2452 2472 [ui.note log.files|files: b]
2453 2473 [ui.note log.description|description:]
2454 2474 [ui.note log.description|other 1
2455 2475 other 2
2456 2476
2457 2477 other 3]
2458 2478
2459 2479
2460 2480 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2461 2481 [log.bisect bisect.untested|bisect: untested]
2462 2482 [log.user|user: other@place]
2463 2483 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2464 2484 [ui.note log.files|files: c]
2465 2485 [ui.note log.description|description:]
2466 2486 [ui.note log.description|no person]
2467 2487
2468 2488
2469 2489 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2470 2490 [log.bisect bisect.bad|bisect: bad]
2471 2491 [log.user|user: person]
2472 2492 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2473 2493 [ui.note log.files|files: c]
2474 2494 [ui.note log.description|description:]
2475 2495 [ui.note log.description|no user, no domain]
2476 2496
2477 2497
2478 2498 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2479 2499 [log.bisect bisect.bad|bisect: bad (implicit)]
2480 2500 [log.branch|branch: foo]
2481 2501 [log.user|user: person]
2482 2502 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2483 2503 [ui.note log.description|description:]
2484 2504 [ui.note log.description|new branch]
2485 2505
2486 2506
2487 2507 $ hg bisect --reset
2488 2508
2489 2509 Error on syntax:
2490 2510
2491 2511 $ echo 'x = "f' >> t
2492 2512 $ hg log
2493 2513 abort: t:3: unmatched quotes
2494 2514 [255]
2495 2515
2496 2516 Behind the scenes, this will throw TypeError
2497 2517
2498 2518 $ hg log -l 3 --template '{date|obfuscate}\n'
2499 2519 abort: template filter 'obfuscate' is not compatible with keyword 'date'
2500 2520 [255]
2501 2521
2502 2522 Behind the scenes, this will throw a ValueError
2503 2523
2504 2524 $ hg log -l 3 --template 'line: {desc|shortdate}\n'
2505 2525 abort: template filter 'shortdate' is not compatible with keyword 'desc'
2506 2526 [255]
2507 2527
2508 2528 Behind the scenes, this will throw AttributeError
2509 2529
2510 2530 $ hg log -l 3 --template 'line: {date|escape}\n'
2511 2531 abort: template filter 'escape' is not compatible with keyword 'date'
2512 2532 [255]
2513 2533
2514 2534 Behind the scenes, this will throw ValueError
2515 2535
2516 2536 $ hg tip --template '{author|email|date}\n'
2517 2537 abort: template filter 'datefilter' is not compatible with keyword 'author'
2518 2538 [255]
2519 2539
2520 2540 Thrown an error if a template function doesn't exist
2521 2541
2522 2542 $ hg tip --template '{foo()}\n'
2523 2543 hg: parse error: unknown function 'foo'
2524 2544 [255]
2525 2545
2526 2546 Pass generator object created by template function to filter
2527 2547
2528 2548 $ hg log -l 1 --template '{if(author, author)|user}\n'
2529 2549 test
2530 2550
2531 2551 Test diff function:
2532 2552
2533 2553 $ hg diff -c 8
2534 2554 diff -r 29114dbae42b -r 95c24699272e fourth
2535 2555 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2536 2556 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2537 2557 @@ -0,0 +1,1 @@
2538 2558 +second
2539 2559 diff -r 29114dbae42b -r 95c24699272e second
2540 2560 --- a/second Mon Jan 12 13:46:40 1970 +0000
2541 2561 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2542 2562 @@ -1,1 +0,0 @@
2543 2563 -second
2544 2564 diff -r 29114dbae42b -r 95c24699272e third
2545 2565 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2546 2566 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2547 2567 @@ -0,0 +1,1 @@
2548 2568 +third
2549 2569
2550 2570 $ hg log -r 8 -T "{diff()}"
2551 2571 diff -r 29114dbae42b -r 95c24699272e fourth
2552 2572 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2553 2573 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2554 2574 @@ -0,0 +1,1 @@
2555 2575 +second
2556 2576 diff -r 29114dbae42b -r 95c24699272e second
2557 2577 --- a/second Mon Jan 12 13:46:40 1970 +0000
2558 2578 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2559 2579 @@ -1,1 +0,0 @@
2560 2580 -second
2561 2581 diff -r 29114dbae42b -r 95c24699272e third
2562 2582 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2563 2583 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2564 2584 @@ -0,0 +1,1 @@
2565 2585 +third
2566 2586
2567 2587 $ hg log -r 8 -T "{diff('glob:f*')}"
2568 2588 diff -r 29114dbae42b -r 95c24699272e fourth
2569 2589 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2570 2590 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2571 2591 @@ -0,0 +1,1 @@
2572 2592 +second
2573 2593
2574 2594 $ hg log -r 8 -T "{diff('', 'glob:f*')}"
2575 2595 diff -r 29114dbae42b -r 95c24699272e second
2576 2596 --- a/second Mon Jan 12 13:46:40 1970 +0000
2577 2597 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2578 2598 @@ -1,1 +0,0 @@
2579 2599 -second
2580 2600 diff -r 29114dbae42b -r 95c24699272e third
2581 2601 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2582 2602 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2583 2603 @@ -0,0 +1,1 @@
2584 2604 +third
2585 2605
2586 2606 $ hg log -r 8 -T "{diff('FOURTH'|lower)}"
2587 2607 diff -r 29114dbae42b -r 95c24699272e fourth
2588 2608 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2589 2609 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2590 2610 @@ -0,0 +1,1 @@
2591 2611 +second
2592 2612
2593 2613 $ cd ..
2594 2614
2595 2615
2596 2616 latesttag:
2597 2617
2598 2618 $ hg init latesttag
2599 2619 $ cd latesttag
2600 2620
2601 2621 $ echo a > file
2602 2622 $ hg ci -Am a -d '0 0'
2603 2623 adding file
2604 2624
2605 2625 $ echo b >> file
2606 2626 $ hg ci -m b -d '1 0'
2607 2627
2608 2628 $ echo c >> head1
2609 2629 $ hg ci -Am h1c -d '2 0'
2610 2630 adding head1
2611 2631
2612 2632 $ hg update -q 1
2613 2633 $ echo d >> head2
2614 2634 $ hg ci -Am h2d -d '3 0'
2615 2635 adding head2
2616 2636 created new head
2617 2637
2618 2638 $ echo e >> head2
2619 2639 $ hg ci -m h2e -d '4 0'
2620 2640
2621 2641 $ hg merge -q
2622 2642 $ hg ci -m merge -d '5 -3600'
2623 2643
2624 2644 No tag set:
2625 2645
2626 2646 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2627 2647 5: null+5
2628 2648 4: null+4
2629 2649 3: null+3
2630 2650 2: null+3
2631 2651 1: null+2
2632 2652 0: null+1
2633 2653
2634 2654 One common tag: longest path wins:
2635 2655
2636 2656 $ hg tag -r 1 -m t1 -d '6 0' t1
2637 2657 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2638 2658 6: t1+4
2639 2659 5: t1+3
2640 2660 4: t1+2
2641 2661 3: t1+1
2642 2662 2: t1+1
2643 2663 1: t1+0
2644 2664 0: null+1
2645 2665
2646 2666 One ancestor tag: more recent wins:
2647 2667
2648 2668 $ hg tag -r 2 -m t2 -d '7 0' t2
2649 2669 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2650 2670 7: t2+3
2651 2671 6: t2+2
2652 2672 5: t2+1
2653 2673 4: t1+2
2654 2674 3: t1+1
2655 2675 2: t2+0
2656 2676 1: t1+0
2657 2677 0: null+1
2658 2678
2659 2679 Two branch tags: more recent wins:
2660 2680
2661 2681 $ hg tag -r 3 -m t3 -d '8 0' t3
2662 2682 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2663 2683 8: t3+5
2664 2684 7: t3+4
2665 2685 6: t3+3
2666 2686 5: t3+2
2667 2687 4: t3+1
2668 2688 3: t3+0
2669 2689 2: t2+0
2670 2690 1: t1+0
2671 2691 0: null+1
2672 2692
2673 2693 Merged tag overrides:
2674 2694
2675 2695 $ hg tag -r 5 -m t5 -d '9 0' t5
2676 2696 $ hg tag -r 3 -m at3 -d '10 0' at3
2677 2697 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2678 2698 10: t5+5
2679 2699 9: t5+4
2680 2700 8: t5+3
2681 2701 7: t5+2
2682 2702 6: t5+1
2683 2703 5: t5+0
2684 2704 4: at3:t3+1
2685 2705 3: at3:t3+0
2686 2706 2: t2+0
2687 2707 1: t1+0
2688 2708 0: null+1
2689 2709
2690 2710 $ cd ..
2691 2711
2692 2712
2693 2713 Style path expansion: issue1948 - ui.style option doesn't work on OSX
2694 2714 if it is a relative path
2695 2715
2696 2716 $ mkdir -p home/styles
2697 2717
2698 2718 $ cat > home/styles/teststyle <<EOF
2699 2719 > changeset = 'test {rev}:{node|short}\n'
2700 2720 > EOF
2701 2721
2702 2722 $ HOME=`pwd`/home; export HOME
2703 2723
2704 2724 $ cat > latesttag/.hg/hgrc <<EOF
2705 2725 > [ui]
2706 2726 > style = ~/styles/teststyle
2707 2727 > EOF
2708 2728
2709 2729 $ hg -R latesttag tip
2710 2730 test 10:9b4a630e5f5f
2711 2731
2712 2732 Test recursive showlist template (issue1989):
2713 2733
2714 2734 $ cat > style1989 <<EOF
2715 2735 > changeset = '{file_mods}{manifest}{extras}'
2716 2736 > file_mod = 'M|{author|person}\n'
2717 2737 > manifest = '{rev},{author}\n'
2718 2738 > extra = '{key}: {author}\n'
2719 2739 > EOF
2720 2740
2721 2741 $ hg -R latesttag log -r tip --style=style1989
2722 2742 M|test
2723 2743 10,test
2724 2744 branch: test
2725 2745
2726 2746 Test new-style inline templating:
2727 2747
2728 2748 $ hg log -R latesttag -r tip --template 'modified files: {file_mods % " {file}\n"}\n'
2729 2749 modified files: .hgtags
2730 2750
2731 2751 Test the sub function of templating for expansion:
2732 2752
2733 2753 $ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n'
2734 2754 xx
2735 2755
2736 2756 Test the strip function with chars specified:
2737 2757
2738 2758 $ hg log -R latesttag --template '{desc}\n'
2739 2759 at3
2740 2760 t5
2741 2761 t3
2742 2762 t2
2743 2763 t1
2744 2764 merge
2745 2765 h2e
2746 2766 h2d
2747 2767 h1c
2748 2768 b
2749 2769 a
2750 2770
2751 2771 $ hg log -R latesttag --template '{strip(desc, "te")}\n'
2752 2772 at3
2753 2773 5
2754 2774 3
2755 2775 2
2756 2776 1
2757 2777 merg
2758 2778 h2
2759 2779 h2d
2760 2780 h1c
2761 2781 b
2762 2782 a
2763 2783
2764 2784 Test date format:
2765 2785
2766 2786 $ hg log -R latesttag --template 'date: {date(date, "%y %m %d %S %z")}\n'
2767 2787 date: 70 01 01 10 +0000
2768 2788 date: 70 01 01 09 +0000
2769 2789 date: 70 01 01 08 +0000
2770 2790 date: 70 01 01 07 +0000
2771 2791 date: 70 01 01 06 +0000
2772 2792 date: 70 01 01 05 +0100
2773 2793 date: 70 01 01 04 +0000
2774 2794 date: 70 01 01 03 +0000
2775 2795 date: 70 01 01 02 +0000
2776 2796 date: 70 01 01 01 +0000
2777 2797 date: 70 01 01 00 +0000
2778 2798
2779 2799 Test invalid date:
2780 2800
2781 2801 $ hg log -R latesttag -T '{date(rev)}\n'
2782 2802 hg: parse error: date expects a date information
2783 2803 [255]
2784 2804
2785 2805 Test integer literal:
2786 2806
2787 2807 $ hg log -Ra -r0 -T '{(0)}\n'
2788 2808 0
2789 2809 $ hg log -Ra -r0 -T '{(123)}\n'
2790 2810 123
2791 2811 $ hg log -Ra -r0 -T '{(-4)}\n'
2792 2812 -4
2793 2813 $ hg log -Ra -r0 -T '{(-)}\n'
2794 2814 hg: parse error at 2: integer literal without digits
2795 2815 [255]
2796 2816 $ hg log -Ra -r0 -T '{(-a)}\n'
2797 2817 hg: parse error at 2: integer literal without digits
2798 2818 [255]
2799 2819
2800 2820 top-level integer literal is interpreted as symbol (i.e. variable name):
2801 2821
2802 2822 $ hg log -Ra -r0 -T '{1}\n'
2803 2823
2804 2824 $ hg log -Ra -r0 -T '{if("t", "{1}")}\n'
2805 2825
2806 2826 $ hg log -Ra -r0 -T '{1|stringify}\n'
2807 2827
2808 2828
2809 2829 unless explicit symbol is expected:
2810 2830
2811 2831 $ hg log -Ra -r0 -T '{desc|1}\n'
2812 2832 hg: parse error: expected a symbol, got 'integer'
2813 2833 [255]
2814 2834 $ hg log -Ra -r0 -T '{1()}\n'
2815 2835 hg: parse error: expected a symbol, got 'integer'
2816 2836 [255]
2817 2837
2818 2838 Test string literal:
2819 2839
2820 2840 $ hg log -Ra -r0 -T '{"string with no template fragment"}\n'
2821 2841 string with no template fragment
2822 2842 $ hg log -Ra -r0 -T '{"template: {rev}"}\n'
2823 2843 template: 0
2824 2844 $ hg log -Ra -r0 -T '{r"rawstring: {rev}"}\n'
2825 2845 rawstring: {rev}
2826 2846
2827 2847 because map operation requires template, raw string can't be used
2828 2848
2829 2849 $ hg log -Ra -r0 -T '{files % r"rawstring"}\n'
2830 2850 hg: parse error: expected template specifier
2831 2851 [255]
2832 2852
2833 2853 Test string escaping:
2834 2854
2835 2855 $ hg log -R latesttag -r 0 --template '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2836 2856 >
2837 2857 <>\n<[>
2838 2858 <>\n<]>
2839 2859 <>\n<
2840 2860
2841 2861 $ hg log -R latesttag -r 0 \
2842 2862 > --config ui.logtemplate='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2843 2863 >
2844 2864 <>\n<[>
2845 2865 <>\n<]>
2846 2866 <>\n<
2847 2867
2848 2868 $ hg log -R latesttag -r 0 -T esc \
2849 2869 > --config templates.esc='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2850 2870 >
2851 2871 <>\n<[>
2852 2872 <>\n<]>
2853 2873 <>\n<
2854 2874
2855 2875 $ cat <<'EOF' > esctmpl
2856 2876 > changeset = '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2857 2877 > EOF
2858 2878 $ hg log -R latesttag -r 0 --style ./esctmpl
2859 2879 >
2860 2880 <>\n<[>
2861 2881 <>\n<]>
2862 2882 <>\n<
2863 2883
2864 2884 Test string escaping of quotes:
2865 2885
2866 2886 $ hg log -Ra -r0 -T '{"\""}\n'
2867 2887 "
2868 2888 $ hg log -Ra -r0 -T '{"\\\""}\n'
2869 2889 \"
2870 2890 $ hg log -Ra -r0 -T '{r"\""}\n'
2871 2891 \"
2872 2892 $ hg log -Ra -r0 -T '{r"\\\""}\n'
2873 2893 \\\"
2874 2894
2875 2895
2876 2896 $ hg log -Ra -r0 -T '{"\""}\n'
2877 2897 "
2878 2898 $ hg log -Ra -r0 -T '{"\\\""}\n'
2879 2899 \"
2880 2900 $ hg log -Ra -r0 -T '{r"\""}\n'
2881 2901 \"
2882 2902 $ hg log -Ra -r0 -T '{r"\\\""}\n'
2883 2903 \\\"
2884 2904
2885 2905 Test exception in quoted template. single backslash before quotation mark is
2886 2906 stripped before parsing:
2887 2907
2888 2908 $ cat <<'EOF' > escquotetmpl
2889 2909 > changeset = "\" \\" \\\" \\\\" {files % \"{file}\"}\n"
2890 2910 > EOF
2891 2911 $ cd latesttag
2892 2912 $ hg log -r 2 --style ../escquotetmpl
2893 2913 " \" \" \\" head1
2894 2914
2895 2915 $ hg log -r 2 -T esc --config templates.esc='"{\"valid\"}\n"'
2896 2916 valid
2897 2917 $ hg log -r 2 -T esc --config templates.esc="'"'{\'"'"'valid\'"'"'}\n'"'"
2898 2918 valid
2899 2919
2900 2920 Test compatibility with 2.9.2-3.4 of escaped quoted strings in nested
2901 2921 _evalifliteral() templates (issue4733):
2902 2922
2903 2923 $ hg log -r 2 -T '{if(rev, "\"{rev}")}\n'
2904 2924 "2
2905 2925 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\"{rev}\")}")}\n'
2906 2926 "2
2907 2927 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\"{rev}\\\")}\")}")}\n'
2908 2928 "2
2909 2929
2910 2930 $ hg log -r 2 -T '{if(rev, "\\\"")}\n'
2911 2931 \"
2912 2932 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\\\\\"\")}")}\n'
2913 2933 \"
2914 2934 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
2915 2935 \"
2916 2936
2917 2937 $ hg log -r 2 -T '{if(rev, r"\\\"")}\n'
2918 2938 \\\"
2919 2939 $ hg log -r 2 -T '{if(rev, "{if(rev, r\"\\\\\\\"\")}")}\n'
2920 2940 \\\"
2921 2941 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, r\\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
2922 2942 \\\"
2923 2943
2924 2944 escaped single quotes and errors:
2925 2945
2926 2946 $ hg log -r 2 -T "{if(rev, '{if(rev, \'foo\')}')}"'\n'
2927 2947 foo
2928 2948 $ hg log -r 2 -T "{if(rev, '{if(rev, r\'foo\')}')}"'\n'
2929 2949 foo
2930 2950 $ hg log -r 2 -T '{if(rev, "{if(rev, \")}")}\n'
2931 2951 hg: parse error at 11: unterminated string
2932 2952 [255]
2933 2953 $ hg log -r 2 -T '{if(rev, \"\\"")}\n'
2934 2954 hg: parse error at 11: syntax error
2935 2955 [255]
2936 2956 $ hg log -r 2 -T '{if(rev, r\"\\"")}\n'
2937 2957 hg: parse error at 12: syntax error
2938 2958 [255]
2939 2959
2940 2960 $ cd ..
2941 2961
2942 2962 Test leading backslashes:
2943 2963
2944 2964 $ cd latesttag
2945 2965 $ hg log -r 2 -T '\{rev} {files % "\{file}"}\n'
2946 2966 {rev} {file}
2947 2967 $ hg log -r 2 -T '\\{rev} {files % "\\{file}"}\n'
2948 2968 \2 \head1
2949 2969 $ hg log -r 2 -T '\\\{rev} {files % "\\\{file}"}\n'
2950 2970 \{rev} \{file}
2951 2971 $ cd ..
2952 2972
2953 2973 Test leading backslashes in "if" expression (issue4714):
2954 2974
2955 2975 $ cd latesttag
2956 2976 $ hg log -r 2 -T '{if("1", "\{rev}")} {if("1", r"\{rev}")}\n'
2957 2977 {rev} \{rev}
2958 2978 $ hg log -r 2 -T '{if("1", "\\{rev}")} {if("1", r"\\{rev}")}\n'
2959 2979 \2 \\{rev}
2960 2980 $ hg log -r 2 -T '{if("1", "\\\{rev}")} {if("1", r"\\\{rev}")}\n'
2961 2981 \{rev} \\\{rev}
2962 2982 $ cd ..
2963 2983
2964 2984 "string-escape"-ed "\x5c\x786e" becomes r"\x6e" (once) or r"n" (twice)
2965 2985
2966 2986 $ hg log -R a -r 0 --template '{if("1", "\x5c\x786e", "NG")}\n'
2967 2987 \x6e
2968 2988 $ hg log -R a -r 0 --template '{if("1", r"\x5c\x786e", "NG")}\n'
2969 2989 \x5c\x786e
2970 2990 $ hg log -R a -r 0 --template '{if("", "NG", "\x5c\x786e")}\n'
2971 2991 \x6e
2972 2992 $ hg log -R a -r 0 --template '{if("", "NG", r"\x5c\x786e")}\n'
2973 2993 \x5c\x786e
2974 2994
2975 2995 $ hg log -R a -r 2 --template '{ifeq("no perso\x6e", desc, "\x5c\x786e", "NG")}\n'
2976 2996 \x6e
2977 2997 $ hg log -R a -r 2 --template '{ifeq(r"no perso\x6e", desc, "NG", r"\x5c\x786e")}\n'
2978 2998 \x5c\x786e
2979 2999 $ hg log -R a -r 2 --template '{ifeq(desc, "no perso\x6e", "\x5c\x786e", "NG")}\n'
2980 3000 \x6e
2981 3001 $ hg log -R a -r 2 --template '{ifeq(desc, r"no perso\x6e", "NG", r"\x5c\x786e")}\n'
2982 3002 \x5c\x786e
2983 3003
2984 3004 $ hg log -R a -r 8 --template '{join(files, "\n")}\n'
2985 3005 fourth
2986 3006 second
2987 3007 third
2988 3008 $ hg log -R a -r 8 --template '{join(files, r"\n")}\n'
2989 3009 fourth\nsecond\nthird
2990 3010
2991 3011 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", "htm\x6c")}'
2992 3012 <p>
2993 3013 1st
2994 3014 </p>
2995 3015 <p>
2996 3016 2nd
2997 3017 </p>
2998 3018 $ hg log -R a -r 2 --template '{rstdoc(r"1st\n\n2nd", "html")}'
2999 3019 <p>
3000 3020 1st\n\n2nd
3001 3021 </p>
3002 3022 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", r"htm\x6c")}'
3003 3023 1st
3004 3024
3005 3025 2nd
3006 3026
3007 3027 $ hg log -R a -r 2 --template '{strip(desc, "\x6e")}\n'
3008 3028 o perso
3009 3029 $ hg log -R a -r 2 --template '{strip(desc, r"\x6e")}\n'
3010 3030 no person
3011 3031 $ hg log -R a -r 2 --template '{strip("no perso\x6e", "\x6e")}\n'
3012 3032 o perso
3013 3033 $ hg log -R a -r 2 --template '{strip(r"no perso\x6e", r"\x6e")}\n'
3014 3034 no perso
3015 3035
3016 3036 $ hg log -R a -r 2 --template '{sub("\\x6e", "\x2d", desc)}\n'
3017 3037 -o perso-
3018 3038 $ hg log -R a -r 2 --template '{sub(r"\\x6e", "-", desc)}\n'
3019 3039 no person
3020 3040 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", desc)}\n'
3021 3041 \x2do perso\x2d
3022 3042 $ hg log -R a -r 2 --template '{sub("n", "\x2d", "no perso\x6e")}\n'
3023 3043 -o perso-
3024 3044 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", r"no perso\x6e")}\n'
3025 3045 \x2do perso\x6e
3026 3046
3027 3047 $ hg log -R a -r 8 --template '{files % "{file}\n"}'
3028 3048 fourth
3029 3049 second
3030 3050 third
3031 3051
3032 3052 Test string escaping in nested expression:
3033 3053
3034 3054 $ hg log -R a -r 8 --template '{ifeq(r"\x6e", if("1", "\x5c\x786e"), join(files, "\x5c\x786e"))}\n'
3035 3055 fourth\x6esecond\x6ethird
3036 3056 $ hg log -R a -r 8 --template '{ifeq(if("1", r"\x6e"), "\x5c\x786e", join(files, "\x5c\x786e"))}\n'
3037 3057 fourth\x6esecond\x6ethird
3038 3058
3039 3059 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", "\x5c\x786e"))}\n'
3040 3060 fourth\x6esecond\x6ethird
3041 3061 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", r"\x5c\x786e"))}\n'
3042 3062 fourth\x5c\x786esecond\x5c\x786ethird
3043 3063
3044 3064 $ hg log -R a -r 3:4 --template '{rev}:{sub(if("1", "\x6e"), ifeq(branch, "foo", r"\x5c\x786e", "\x5c\x786e"), desc)}\n'
3045 3065 3:\x6eo user, \x6eo domai\x6e
3046 3066 4:\x5c\x786eew bra\x5c\x786ech
3047 3067
3048 3068 Test recursive evaluation:
3049 3069
3050 3070 $ hg init r
3051 3071 $ cd r
3052 3072 $ echo a > a
3053 3073 $ hg ci -Am '{rev}'
3054 3074 adding a
3055 3075 $ hg log -r 0 --template '{if(rev, desc)}\n'
3056 3076 {rev}
3057 3077 $ hg log -r 0 --template '{if(rev, "{author} {rev}")}\n'
3058 3078 test 0
3059 3079
3060 3080 $ hg branch -q 'text.{rev}'
3061 3081 $ echo aa >> aa
3062 3082 $ hg ci -u '{node|short}' -m 'desc to be wrapped desc to be wrapped'
3063 3083
3064 3084 $ hg log -l1 --template '{fill(desc, "20", author, branch)}'
3065 3085 {node|short}desc to
3066 3086 text.{rev}be wrapped
3067 3087 text.{rev}desc to be
3068 3088 text.{rev}wrapped (no-eol)
3069 3089 $ hg log -l1 --template '{fill(desc, "20", "{node|short}:", "text.{rev}:")}'
3070 3090 bcc7ff960b8e:desc to
3071 3091 text.1:be wrapped
3072 3092 text.1:desc to be
3073 3093 text.1:wrapped (no-eol)
3074 3094
3075 3095 $ hg log -l 1 --template '{sub(r"[0-9]", "-", author)}'
3076 3096 {node|short} (no-eol)
3077 3097 $ hg log -l 1 --template '{sub(r"[0-9]", "-", "{node|short}")}'
3078 3098 bcc-ff---b-e (no-eol)
3079 3099
3080 3100 $ cat >> .hg/hgrc <<EOF
3081 3101 > [extensions]
3082 3102 > color=
3083 3103 > [color]
3084 3104 > mode=ansi
3085 3105 > text.{rev} = red
3086 3106 > text.1 = green
3087 3107 > EOF
3088 3108 $ hg log --color=always -l 1 --template '{label(branch, "text\n")}'
3089 3109 \x1b[0;31mtext\x1b[0m (esc)
3090 3110 $ hg log --color=always -l 1 --template '{label("text.{rev}", "text\n")}'
3091 3111 \x1b[0;32mtext\x1b[0m (esc)
3092 3112
3093 3113 Test branches inside if statement:
3094 3114
3095 3115 $ hg log -r 0 --template '{if(branches, "yes", "no")}\n'
3096 3116 no
3097 3117
3098 3118 Test get function:
3099 3119
3100 3120 $ hg log -r 0 --template '{get(extras, "branch")}\n'
3101 3121 default
3102 3122 $ hg log -r 0 --template '{get(files, "should_fail")}\n'
3103 3123 hg: parse error: get() expects a dict as first argument
3104 3124 [255]
3105 3125
3106 3126 Test shortest(node) function:
3107 3127
3108 3128 $ echo b > b
3109 3129 $ hg ci -qAm b
3110 3130 $ hg log --template '{shortest(node)}\n'
3111 3131 e777
3112 3132 bcc7
3113 3133 f776
3114 3134 $ hg log --template '{shortest(node, 10)}\n'
3115 3135 e777603221
3116 3136 bcc7ff960b
3117 3137 f7769ec2ab
3118 3138
3119 3139 Test pad function
3120 3140
3121 3141 $ hg log --template '{pad(rev, 20)} {author|user}\n'
3122 3142 2 test
3123 3143 1 {node|short}
3124 3144 0 test
3125 3145
3126 3146 $ hg log --template '{pad(rev, 20, " ", True)} {author|user}\n'
3127 3147 2 test
3128 3148 1 {node|short}
3129 3149 0 test
3130 3150
3131 3151 $ hg log --template '{pad(rev, 20, "-", False)} {author|user}\n'
3132 3152 2------------------- test
3133 3153 1------------------- {node|short}
3134 3154 0------------------- test
3135 3155
3136 3156 Test template string in pad function
3137 3157
3138 3158 $ hg log -r 0 -T '{pad("\{{rev}}", 10)} {author|user}\n'
3139 3159 {0} test
3140 3160
3141 3161 $ hg log -r 0 -T '{pad(r"\{rev}", 10)} {author|user}\n'
3142 3162 \{rev} test
3143 3163
3144 3164 Test ifcontains function
3145 3165
3146 3166 $ hg log --template '{rev} {ifcontains(rev, "2 two 0", "is in the string", "is not")}\n'
3147 3167 2 is in the string
3148 3168 1 is not
3149 3169 0 is in the string
3150 3170
3151 3171 $ hg log --template '{rev} {ifcontains("a", file_adds, "added a", "did not add a")}\n'
3152 3172 2 did not add a
3153 3173 1 did not add a
3154 3174 0 added a
3155 3175
3156 3176 Test revset function
3157 3177
3158 3178 $ hg log --template '{rev} {ifcontains(rev, revset("."), "current rev", "not current rev")}\n'
3159 3179 2 current rev
3160 3180 1 not current rev
3161 3181 0 not current rev
3162 3182
3163 3183 $ hg log --template '{rev} {ifcontains(rev, revset(". + .^"), "match rev", "not match rev")}\n'
3164 3184 2 match rev
3165 3185 1 match rev
3166 3186 0 not match rev
3167 3187
3168 3188 $ hg log --template '{rev} Parents: {revset("parents(%s)", rev)}\n'
3169 3189 2 Parents: 1
3170 3190 1 Parents: 0
3171 3191 0 Parents:
3172 3192
3173 3193 $ cat >> .hg/hgrc <<EOF
3174 3194 > [revsetalias]
3175 3195 > myparents(\$1) = parents(\$1)
3176 3196 > EOF
3177 3197 $ hg log --template '{rev} Parents: {revset("myparents(%s)", rev)}\n'
3178 3198 2 Parents: 1
3179 3199 1 Parents: 0
3180 3200 0 Parents:
3181 3201
3182 3202 $ hg log --template 'Rev: {rev}\n{revset("::%s", rev) % "Ancestor: {revision}\n"}\n'
3183 3203 Rev: 2
3184 3204 Ancestor: 0
3185 3205 Ancestor: 1
3186 3206 Ancestor: 2
3187 3207
3188 3208 Rev: 1
3189 3209 Ancestor: 0
3190 3210 Ancestor: 1
3191 3211
3192 3212 Rev: 0
3193 3213 Ancestor: 0
3194 3214
3195 3215 $ hg log --template '{revset("TIP"|lower)}\n' -l1
3196 3216 2
3197 3217
3198 3218 Test active bookmark templating
3199 3219
3200 3220 $ hg book foo
3201 3221 $ hg book bar
3202 3222 $ hg log --template "{rev} {bookmarks % '{bookmark}{ifeq(bookmark, active, \"*\")} '}\n"
3203 3223 2 bar* foo
3204 3224 1
3205 3225 0
3206 3226 $ hg log --template "{rev} {activebookmark}\n"
3207 3227 2 bar
3208 3228 1
3209 3229 0
3210 3230 $ hg bookmarks --inactive bar
3211 3231 $ hg log --template "{rev} {activebookmark}\n"
3212 3232 2
3213 3233 1
3214 3234 0
3215 3235 $ hg book -r1 baz
3216 3236 $ hg log --template "{rev} {join(bookmarks, ' ')}\n"
3217 3237 2 bar foo
3218 3238 1 baz
3219 3239 0
3220 3240 $ hg log --template "{rev} {ifcontains('foo', bookmarks, 't', 'f')}\n"
3221 3241 2 t
3222 3242 1 f
3223 3243 0 f
3224 3244
3225 3245 Test stringify on sub expressions
3226 3246
3227 3247 $ cd ..
3228 3248 $ hg log -R a -r 8 --template '{join(files, if("1", if("1", ", ")))}\n'
3229 3249 fourth, second, third
3230 3250 $ hg log -R a -r 8 --template '{strip(if("1", if("1", "-abc-")), if("1", if("1", "-")))}\n'
3231 3251 abc
3232 3252
3233 3253 Test splitlines
3234 3254
3235 3255 $ hg log -Gv -R a --template "{splitlines(desc) % 'foo {line}\n'}"
3236 3256 @ foo Modify, add, remove, rename
3237 3257 |
3238 3258 o foo future
3239 3259 |
3240 3260 o foo third
3241 3261 |
3242 3262 o foo second
3243 3263
3244 3264 o foo merge
3245 3265 |\
3246 3266 | o foo new head
3247 3267 | |
3248 3268 o | foo new branch
3249 3269 |/
3250 3270 o foo no user, no domain
3251 3271 |
3252 3272 o foo no person
3253 3273 |
3254 3274 o foo other 1
3255 3275 | foo other 2
3256 3276 | foo
3257 3277 | foo other 3
3258 3278 o foo line 1
3259 3279 foo line 2
3260 3280
3261 3281 Test startswith
3262 3282 $ hg log -Gv -R a --template "{startswith(desc)}"
3263 3283 hg: parse error: startswith expects two arguments
3264 3284 [255]
3265 3285
3266 3286 $ hg log -Gv -R a --template "{startswith('line', desc)}"
3267 3287 @
3268 3288 |
3269 3289 o
3270 3290 |
3271 3291 o
3272 3292 |
3273 3293 o
3274 3294
3275 3295 o
3276 3296 |\
3277 3297 | o
3278 3298 | |
3279 3299 o |
3280 3300 |/
3281 3301 o
3282 3302 |
3283 3303 o
3284 3304 |
3285 3305 o
3286 3306 |
3287 3307 o line 1
3288 3308 line 2
3289 3309
3290 3310 Test bad template with better error message
3291 3311
3292 3312 $ hg log -Gv -R a --template '{desc|user()}'
3293 3313 hg: parse error: expected a symbol, got 'func'
3294 3314 [255]
3295 3315
3296 3316 Test word function (including index out of bounds graceful failure)
3297 3317
3298 3318 $ hg log -Gv -R a --template "{word('1', desc)}"
3299 3319 @ add,
3300 3320 |
3301 3321 o
3302 3322 |
3303 3323 o
3304 3324 |
3305 3325 o
3306 3326
3307 3327 o
3308 3328 |\
3309 3329 | o head
3310 3330 | |
3311 3331 o | branch
3312 3332 |/
3313 3333 o user,
3314 3334 |
3315 3335 o person
3316 3336 |
3317 3337 o 1
3318 3338 |
3319 3339 o 1
3320 3340
3321 3341
3322 3342 Test word third parameter used as splitter
3323 3343
3324 3344 $ hg log -Gv -R a --template "{word('0', desc, 'o')}"
3325 3345 @ M
3326 3346 |
3327 3347 o future
3328 3348 |
3329 3349 o third
3330 3350 |
3331 3351 o sec
3332 3352
3333 3353 o merge
3334 3354 |\
3335 3355 | o new head
3336 3356 | |
3337 3357 o | new branch
3338 3358 |/
3339 3359 o n
3340 3360 |
3341 3361 o n
3342 3362 |
3343 3363 o
3344 3364 |
3345 3365 o line 1
3346 3366 line 2
3347 3367
3348 3368 Test word error messages for not enough and too many arguments
3349 3369
3350 3370 $ hg log -Gv -R a --template "{word('0')}"
3351 3371 hg: parse error: word expects two or three arguments, got 1
3352 3372 [255]
3353 3373
3354 3374 $ hg log -Gv -R a --template "{word('0', desc, 'o', 'h', 'b', 'o', 'y')}"
3355 3375 hg: parse error: word expects two or three arguments, got 7
3356 3376 [255]
3357 3377
3358 3378 Test word for integer literal
3359 3379
3360 3380 $ hg log -R a --template "{word(2, desc)}\n" -r0
3361 3381 line
3362 3382
3363 3383 Test word for invalid numbers
3364 3384
3365 3385 $ hg log -Gv -R a --template "{word('a', desc)}"
3366 3386 hg: parse error: word expects an integer index
3367 3387 [255]
3368 3388
3369 3389 Test indent and not adding to empty lines
3370 3390
3371 3391 $ hg log -T "-----\n{indent(desc, '>> ', ' > ')}\n" -r 0:1 -R a
3372 3392 -----
3373 3393 > line 1
3374 3394 >> line 2
3375 3395 -----
3376 3396 > other 1
3377 3397 >> other 2
3378 3398
3379 3399 >> other 3
3380 3400
3381 3401 Test with non-strings like dates
3382 3402
3383 3403 $ hg log -T "{indent(date, ' ')}\n" -r 2:3 -R a
3384 3404 1200000.00
3385 3405 1300000.00
@@ -1,2053 +1,2053 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 The g is crafted to have 2 filelog topological heads in a linear
19 19 changeset graph
20 20
21 21 $ hg init a
22 22 $ cd a
23 23 $ echo a > a
24 24 $ echo f > f
25 25 $ hg ci -Ama -d '1 0'
26 26 adding a
27 27 adding f
28 28
29 29 $ hg cp a b
30 30 $ hg cp f g
31 31 $ hg ci -mb -d '2 0'
32 32
33 33 $ mkdir dir
34 34 $ hg mv b dir
35 35 $ echo g >> g
36 36 $ echo f >> f
37 37 $ hg ci -mc -d '3 0'
38 38
39 39 $ hg mv a b
40 40 $ hg cp -f f g
41 41 $ echo a > d
42 42 $ hg add d
43 43 $ hg ci -md -d '4 0'
44 44
45 45 $ hg mv dir/b e
46 46 $ hg ci -me -d '5 0'
47 47
48 48 Make sure largefiles doesn't interfere with logging a regular file
49 49 $ hg --debug log a -T '{rev}: {desc}\n' --config extensions.largefiles=
50 50 updated patterns: ['.hglf/a', 'a']
51 51 0: a
52 52 $ hg log a
53 53 changeset: 0:9161b9aeaf16
54 54 user: test
55 55 date: Thu Jan 01 00:00:01 1970 +0000
56 56 summary: a
57 57
58 58 $ hg log glob:a*
59 59 changeset: 3:2ca5ba701980
60 60 user: test
61 61 date: Thu Jan 01 00:00:04 1970 +0000
62 62 summary: d
63 63
64 64 changeset: 0:9161b9aeaf16
65 65 user: test
66 66 date: Thu Jan 01 00:00:01 1970 +0000
67 67 summary: a
68 68
69 69 $ hg --debug log glob:a* -T '{rev}: {desc}\n' --config extensions.largefiles=
70 70 updated patterns: ['glob:.hglf/a*', 'glob:a*']
71 71 3: d
72 72 0: a
73 73
74 74 log on directory
75 75
76 76 $ hg log dir
77 77 changeset: 4:7e4639b4691b
78 78 tag: tip
79 79 user: test
80 80 date: Thu Jan 01 00:00:05 1970 +0000
81 81 summary: e
82 82
83 83 changeset: 2:f8954cd4dc1f
84 84 user: test
85 85 date: Thu Jan 01 00:00:03 1970 +0000
86 86 summary: c
87 87
88 88 $ hg log somethingthatdoesntexist dir
89 89 changeset: 4:7e4639b4691b
90 90 tag: tip
91 91 user: test
92 92 date: Thu Jan 01 00:00:05 1970 +0000
93 93 summary: e
94 94
95 95 changeset: 2:f8954cd4dc1f
96 96 user: test
97 97 date: Thu Jan 01 00:00:03 1970 +0000
98 98 summary: c
99 99
100 100
101 101 -f, non-existent directory
102 102
103 103 $ hg log -f dir
104 104 abort: cannot follow file not in parent revision: "dir"
105 105 [255]
106 106
107 107 -f, directory
108 108
109 109 $ hg up -q 3
110 110 $ hg log -f dir
111 111 changeset: 2:f8954cd4dc1f
112 112 user: test
113 113 date: Thu Jan 01 00:00:03 1970 +0000
114 114 summary: c
115 115
116 116 -f, directory with --patch
117 117
118 118 $ hg log -f dir -p
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 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
125 125 --- /dev/null* (glob)
126 126 +++ b/dir/b* (glob)
127 127 @@ -0,0 +1,1 @@
128 128 +a
129 129
130 130
131 131 -f, pattern
132 132
133 133 $ hg log -f -I 'dir**' -p
134 134 changeset: 2:f8954cd4dc1f
135 135 user: test
136 136 date: Thu Jan 01 00:00:03 1970 +0000
137 137 summary: c
138 138
139 139 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
140 140 --- /dev/null* (glob)
141 141 +++ b/dir/b* (glob)
142 142 @@ -0,0 +1,1 @@
143 143 +a
144 144
145 145 $ hg up -q 4
146 146
147 147 -f, a wrong style
148 148
149 149 $ hg log -f -l1 --style something
150 150 abort: style 'something' not found
151 151 (available styles: bisect, changelog, compact, default, phases, status, xml)
152 152 [255]
153 153
154 154 -f, phases style
155 155
156 156
157 157 $ hg log -f -l1 --style phases
158 158 changeset: 4:7e4639b4691b
159 159 tag: tip
160 160 phase: draft
161 161 user: test
162 162 date: Thu Jan 01 00:00:05 1970 +0000
163 163 summary: e
164 164
165 165
166 166 $ hg log -f -l1 --style phases -q
167 167 4:7e4639b4691b
168 168
169 169 -f, but no args
170 170
171 171 $ hg log -f
172 172 changeset: 4:7e4639b4691b
173 173 tag: tip
174 174 user: test
175 175 date: Thu Jan 01 00:00:05 1970 +0000
176 176 summary: e
177 177
178 178 changeset: 3:2ca5ba701980
179 179 user: test
180 180 date: Thu Jan 01 00:00:04 1970 +0000
181 181 summary: d
182 182
183 183 changeset: 2:f8954cd4dc1f
184 184 user: test
185 185 date: Thu Jan 01 00:00:03 1970 +0000
186 186 summary: c
187 187
188 188 changeset: 1:d89b0a12d229
189 189 user: test
190 190 date: Thu Jan 01 00:00:02 1970 +0000
191 191 summary: b
192 192
193 193 changeset: 0:9161b9aeaf16
194 194 user: test
195 195 date: Thu Jan 01 00:00:01 1970 +0000
196 196 summary: a
197 197
198 198
199 199 one rename
200 200
201 201 $ hg up -q 2
202 202 $ hg log -vf a
203 203 changeset: 0:9161b9aeaf16
204 204 user: test
205 205 date: Thu Jan 01 00:00:01 1970 +0000
206 206 files: a f
207 207 description:
208 208 a
209 209
210 210
211 211
212 212 many renames
213 213
214 214 $ hg up -q tip
215 215 $ hg log -vf e
216 216 changeset: 4:7e4639b4691b
217 217 tag: tip
218 218 user: test
219 219 date: Thu Jan 01 00:00:05 1970 +0000
220 220 files: dir/b e
221 221 description:
222 222 e
223 223
224 224
225 225 changeset: 2:f8954cd4dc1f
226 226 user: test
227 227 date: Thu Jan 01 00:00:03 1970 +0000
228 228 files: b dir/b f g
229 229 description:
230 230 c
231 231
232 232
233 233 changeset: 1:d89b0a12d229
234 234 user: test
235 235 date: Thu Jan 01 00:00:02 1970 +0000
236 236 files: b g
237 237 description:
238 238 b
239 239
240 240
241 241 changeset: 0:9161b9aeaf16
242 242 user: test
243 243 date: Thu Jan 01 00:00:01 1970 +0000
244 244 files: a f
245 245 description:
246 246 a
247 247
248 248
249 249
250 250
251 251 log -pf dir/b
252 252
253 253 $ hg up -q 3
254 254 $ hg log -pf dir/b
255 255 changeset: 2:f8954cd4dc1f
256 256 user: test
257 257 date: Thu Jan 01 00:00:03 1970 +0000
258 258 summary: c
259 259
260 260 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
261 261 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
262 262 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
263 263 @@ -0,0 +1,1 @@
264 264 +a
265 265
266 266 changeset: 1:d89b0a12d229
267 267 user: test
268 268 date: Thu Jan 01 00:00:02 1970 +0000
269 269 summary: b
270 270
271 271 diff -r 9161b9aeaf16 -r d89b0a12d229 b
272 272 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
273 273 +++ b/b Thu Jan 01 00:00:02 1970 +0000
274 274 @@ -0,0 +1,1 @@
275 275 +a
276 276
277 277 changeset: 0:9161b9aeaf16
278 278 user: test
279 279 date: Thu Jan 01 00:00:01 1970 +0000
280 280 summary: a
281 281
282 282 diff -r 000000000000 -r 9161b9aeaf16 a
283 283 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
284 284 +++ b/a Thu Jan 01 00:00:01 1970 +0000
285 285 @@ -0,0 +1,1 @@
286 286 +a
287 287
288 288
289 289 log -pf b inside dir
290 290
291 291 $ hg --cwd=dir log -pf b
292 292 changeset: 2:f8954cd4dc1f
293 293 user: test
294 294 date: Thu Jan 01 00:00:03 1970 +0000
295 295 summary: c
296 296
297 297 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
298 298 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
299 299 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
300 300 @@ -0,0 +1,1 @@
301 301 +a
302 302
303 303 changeset: 1:d89b0a12d229
304 304 user: test
305 305 date: Thu Jan 01 00:00:02 1970 +0000
306 306 summary: b
307 307
308 308 diff -r 9161b9aeaf16 -r d89b0a12d229 b
309 309 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
310 310 +++ b/b Thu Jan 01 00:00:02 1970 +0000
311 311 @@ -0,0 +1,1 @@
312 312 +a
313 313
314 314 changeset: 0:9161b9aeaf16
315 315 user: test
316 316 date: Thu Jan 01 00:00:01 1970 +0000
317 317 summary: a
318 318
319 319 diff -r 000000000000 -r 9161b9aeaf16 a
320 320 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
321 321 +++ b/a Thu Jan 01 00:00:01 1970 +0000
322 322 @@ -0,0 +1,1 @@
323 323 +a
324 324
325 325
326 326 log -pf, but no args
327 327
328 328 $ hg log -pf
329 329 changeset: 3:2ca5ba701980
330 330 user: test
331 331 date: Thu Jan 01 00:00:04 1970 +0000
332 332 summary: d
333 333
334 334 diff -r f8954cd4dc1f -r 2ca5ba701980 a
335 335 --- a/a Thu Jan 01 00:00:03 1970 +0000
336 336 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
337 337 @@ -1,1 +0,0 @@
338 338 -a
339 339 diff -r f8954cd4dc1f -r 2ca5ba701980 b
340 340 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
341 341 +++ b/b Thu Jan 01 00:00:04 1970 +0000
342 342 @@ -0,0 +1,1 @@
343 343 +a
344 344 diff -r f8954cd4dc1f -r 2ca5ba701980 d
345 345 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
346 346 +++ b/d Thu Jan 01 00:00:04 1970 +0000
347 347 @@ -0,0 +1,1 @@
348 348 +a
349 349 diff -r f8954cd4dc1f -r 2ca5ba701980 g
350 350 --- a/g Thu Jan 01 00:00:03 1970 +0000
351 351 +++ b/g Thu Jan 01 00:00:04 1970 +0000
352 352 @@ -1,2 +1,2 @@
353 353 f
354 354 -g
355 355 +f
356 356
357 357 changeset: 2:f8954cd4dc1f
358 358 user: test
359 359 date: Thu Jan 01 00:00:03 1970 +0000
360 360 summary: c
361 361
362 362 diff -r d89b0a12d229 -r f8954cd4dc1f b
363 363 --- a/b Thu Jan 01 00:00:02 1970 +0000
364 364 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
365 365 @@ -1,1 +0,0 @@
366 366 -a
367 367 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
368 368 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
369 369 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
370 370 @@ -0,0 +1,1 @@
371 371 +a
372 372 diff -r d89b0a12d229 -r f8954cd4dc1f f
373 373 --- a/f Thu Jan 01 00:00:02 1970 +0000
374 374 +++ b/f Thu Jan 01 00:00:03 1970 +0000
375 375 @@ -1,1 +1,2 @@
376 376 f
377 377 +f
378 378 diff -r d89b0a12d229 -r f8954cd4dc1f g
379 379 --- a/g Thu Jan 01 00:00:02 1970 +0000
380 380 +++ b/g Thu Jan 01 00:00:03 1970 +0000
381 381 @@ -1,1 +1,2 @@
382 382 f
383 383 +g
384 384
385 385 changeset: 1:d89b0a12d229
386 386 user: test
387 387 date: Thu Jan 01 00:00:02 1970 +0000
388 388 summary: b
389 389
390 390 diff -r 9161b9aeaf16 -r d89b0a12d229 b
391 391 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
392 392 +++ b/b Thu Jan 01 00:00:02 1970 +0000
393 393 @@ -0,0 +1,1 @@
394 394 +a
395 395 diff -r 9161b9aeaf16 -r d89b0a12d229 g
396 396 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
397 397 +++ b/g Thu Jan 01 00:00:02 1970 +0000
398 398 @@ -0,0 +1,1 @@
399 399 +f
400 400
401 401 changeset: 0:9161b9aeaf16
402 402 user: test
403 403 date: Thu Jan 01 00:00:01 1970 +0000
404 404 summary: a
405 405
406 406 diff -r 000000000000 -r 9161b9aeaf16 a
407 407 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
408 408 +++ b/a Thu Jan 01 00:00:01 1970 +0000
409 409 @@ -0,0 +1,1 @@
410 410 +a
411 411 diff -r 000000000000 -r 9161b9aeaf16 f
412 412 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
413 413 +++ b/f Thu Jan 01 00:00:01 1970 +0000
414 414 @@ -0,0 +1,1 @@
415 415 +f
416 416
417 417
418 418 log -vf dir/b
419 419
420 420 $ hg log -vf dir/b
421 421 changeset: 2:f8954cd4dc1f
422 422 user: test
423 423 date: Thu Jan 01 00:00:03 1970 +0000
424 424 files: b dir/b f g
425 425 description:
426 426 c
427 427
428 428
429 429 changeset: 1:d89b0a12d229
430 430 user: test
431 431 date: Thu Jan 01 00:00:02 1970 +0000
432 432 files: b g
433 433 description:
434 434 b
435 435
436 436
437 437 changeset: 0:9161b9aeaf16
438 438 user: test
439 439 date: Thu Jan 01 00:00:01 1970 +0000
440 440 files: a f
441 441 description:
442 442 a
443 443
444 444
445 445
446 446
447 447 -f and multiple filelog heads
448 448
449 449 $ hg up -q 2
450 450 $ hg log -f g --template '{rev}\n'
451 451 2
452 452 1
453 453 0
454 454 $ hg up -q tip
455 455 $ hg log -f g --template '{rev}\n'
456 456 3
457 457 2
458 458 0
459 459
460 460
461 461 log copies with --copies
462 462
463 463 $ hg log -vC --template '{rev} {file_copies}\n'
464 464 4 e (dir/b)
465 465 3 b (a)g (f)
466 466 2 dir/b (b)
467 467 1 b (a)g (f)
468 468 0
469 469
470 470 log copies switch without --copies, with old filecopy template
471 471
472 472 $ hg log -v --template '{rev} {file_copies_switch%filecopy}\n'
473 473 4
474 474 3
475 475 2
476 476 1
477 477 0
478 478
479 479 log copies switch with --copies
480 480
481 481 $ hg log -vC --template '{rev} {file_copies_switch}\n'
482 482 4 e (dir/b)
483 483 3 b (a)g (f)
484 484 2 dir/b (b)
485 485 1 b (a)g (f)
486 486 0
487 487
488 488
489 489 log copies with hardcoded style and with --style=default
490 490
491 491 $ hg log -vC -r4
492 492 changeset: 4:7e4639b4691b
493 493 tag: tip
494 494 user: test
495 495 date: Thu Jan 01 00:00:05 1970 +0000
496 496 files: dir/b e
497 497 copies: e (dir/b)
498 498 description:
499 499 e
500 500
501 501
502 502 $ hg log -vC -r4 --style=default
503 503 changeset: 4:7e4639b4691b
504 504 tag: tip
505 505 user: test
506 506 date: Thu Jan 01 00:00:05 1970 +0000
507 507 files: dir/b e
508 508 copies: e (dir/b)
509 509 description:
510 510 e
511 511
512 512
513 513 $ hg log -vC -r4 -Tjson
514 514 [
515 515 {
516 516 "rev": 4,
517 517 "node": "7e4639b4691b9f84b81036a8d4fb218ce3c5e3a3",
518 518 "branch": "default",
519 519 "phase": "draft",
520 520 "user": "test",
521 521 "date": [5, 0],
522 522 "desc": "e",
523 523 "bookmarks": [],
524 524 "tags": ["tip"],
525 525 "parents": ["2ca5ba7019804f1f597249caddf22a64d34df0ba"],
526 526 "files": ["dir/b", "e"],
527 527 "copies": {"e": "dir/b"}
528 528 }
529 529 ]
530 530
531 531 log copies, non-linear manifest
532 532
533 533 $ hg up -C 3
534 534 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
535 535 $ hg mv dir/b e
536 536 $ echo foo > foo
537 537 $ hg ci -Ame2 -d '6 0'
538 538 adding foo
539 539 created new head
540 540 $ hg log -v --template '{rev} {file_copies}\n' -r 5
541 541 5 e (dir/b)
542 542
543 543
544 544 log copies, execute bit set
545 545
546 546 #if execbit
547 547 $ chmod +x e
548 548 $ hg ci -me3 -d '7 0'
549 549 $ hg log -v --template '{rev} {file_copies}\n' -r 6
550 550 6
551 551 #endif
552 552
553 553
554 554 log -p d
555 555
556 556 $ hg log -pv d
557 557 changeset: 3:2ca5ba701980
558 558 user: test
559 559 date: Thu Jan 01 00:00:04 1970 +0000
560 560 files: a b d g
561 561 description:
562 562 d
563 563
564 564
565 565 diff -r f8954cd4dc1f -r 2ca5ba701980 d
566 566 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
567 567 +++ b/d Thu Jan 01 00:00:04 1970 +0000
568 568 @@ -0,0 +1,1 @@
569 569 +a
570 570
571 571
572 572
573 573 log --removed file
574 574
575 575 $ hg log --removed -v a
576 576 changeset: 3:2ca5ba701980
577 577 user: test
578 578 date: Thu Jan 01 00:00:04 1970 +0000
579 579 files: a b d g
580 580 description:
581 581 d
582 582
583 583
584 584 changeset: 0:9161b9aeaf16
585 585 user: test
586 586 date: Thu Jan 01 00:00:01 1970 +0000
587 587 files: a f
588 588 description:
589 589 a
590 590
591 591
592 592
593 593 log --removed revrange file
594 594
595 595 $ hg log --removed -v -r0:2 a
596 596 changeset: 0:9161b9aeaf16
597 597 user: test
598 598 date: Thu Jan 01 00:00:01 1970 +0000
599 599 files: a f
600 600 description:
601 601 a
602 602
603 603
604 604 $ cd ..
605 605
606 606 log --follow tests
607 607
608 608 $ hg init follow
609 609 $ cd follow
610 610
611 611 $ echo base > base
612 612 $ hg ci -Ambase -d '1 0'
613 613 adding base
614 614
615 615 $ echo r1 >> base
616 616 $ hg ci -Amr1 -d '1 0'
617 617 $ echo r2 >> base
618 618 $ hg ci -Amr2 -d '1 0'
619 619
620 620 $ hg up -C 1
621 621 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
622 622 $ echo b1 > b1
623 623 $ hg ci -Amb1 -d '1 0'
624 624 adding b1
625 625 created new head
626 626
627 627
628 628 log -f
629 629
630 630 $ hg log -f
631 631 changeset: 3:e62f78d544b4
632 632 tag: tip
633 633 parent: 1:3d5bf5654eda
634 634 user: test
635 635 date: Thu Jan 01 00:00:01 1970 +0000
636 636 summary: b1
637 637
638 638 changeset: 1:3d5bf5654eda
639 639 user: test
640 640 date: Thu Jan 01 00:00:01 1970 +0000
641 641 summary: r1
642 642
643 643 changeset: 0:67e992f2c4f3
644 644 user: test
645 645 date: Thu Jan 01 00:00:01 1970 +0000
646 646 summary: base
647 647
648 648
649 649
650 650 log -f -r '1 + 4'
651 651
652 652 $ hg up -C 0
653 653 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
654 654 $ echo b2 > b2
655 655 $ hg ci -Amb2 -d '1 0'
656 656 adding b2
657 657 created new head
658 658 $ hg log -f -r '1 + 4'
659 659 changeset: 4:ddb82e70d1a1
660 660 tag: tip
661 661 parent: 0:67e992f2c4f3
662 662 user: test
663 663 date: Thu Jan 01 00:00:01 1970 +0000
664 664 summary: b2
665 665
666 666 changeset: 1:3d5bf5654eda
667 667 user: test
668 668 date: Thu Jan 01 00:00:01 1970 +0000
669 669 summary: r1
670 670
671 671 changeset: 0:67e992f2c4f3
672 672 user: test
673 673 date: Thu Jan 01 00:00:01 1970 +0000
674 674 summary: base
675 675
676 676 log -f -r null
677 677
678 678 $ hg log -f -r null
679 679 changeset: -1:000000000000
680 680 user:
681 681 date: Thu Jan 01 00:00:00 1970 +0000
682 682
683 683 $ hg log -f -r null -G
684 684 o changeset: -1:000000000000
685 685 user:
686 686 date: Thu Jan 01 00:00:00 1970 +0000
687 687
688 688
689 689
690 690 log -f with null parent
691 691
692 692 $ hg up -C null
693 693 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
694 694 $ hg log -f
695 695
696 696
697 697 log -r . with two parents
698 698
699 699 $ hg up -C 3
700 700 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
701 701 $ hg merge tip
702 702 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
703 703 (branch merge, don't forget to commit)
704 704 $ hg log -r .
705 705 changeset: 3:e62f78d544b4
706 706 parent: 1:3d5bf5654eda
707 707 user: test
708 708 date: Thu Jan 01 00:00:01 1970 +0000
709 709 summary: b1
710 710
711 711
712 712
713 713 log -r . with one parent
714 714
715 715 $ hg ci -mm12 -d '1 0'
716 716 $ hg log -r .
717 717 changeset: 5:302e9dd6890d
718 718 tag: tip
719 719 parent: 3:e62f78d544b4
720 720 parent: 4:ddb82e70d1a1
721 721 user: test
722 722 date: Thu Jan 01 00:00:01 1970 +0000
723 723 summary: m12
724 724
725 725
726 726 $ echo postm >> b1
727 727 $ hg ci -Amb1.1 -d'1 0'
728 728
729 729
730 730 log --follow-first
731 731
732 732 $ hg log --follow-first
733 733 changeset: 6:2404bbcab562
734 734 tag: tip
735 735 user: test
736 736 date: Thu Jan 01 00:00:01 1970 +0000
737 737 summary: b1.1
738 738
739 739 changeset: 5:302e9dd6890d
740 740 parent: 3:e62f78d544b4
741 741 parent: 4:ddb82e70d1a1
742 742 user: test
743 743 date: Thu Jan 01 00:00:01 1970 +0000
744 744 summary: m12
745 745
746 746 changeset: 3:e62f78d544b4
747 747 parent: 1:3d5bf5654eda
748 748 user: test
749 749 date: Thu Jan 01 00:00:01 1970 +0000
750 750 summary: b1
751 751
752 752 changeset: 1:3d5bf5654eda
753 753 user: test
754 754 date: Thu Jan 01 00:00:01 1970 +0000
755 755 summary: r1
756 756
757 757 changeset: 0:67e992f2c4f3
758 758 user: test
759 759 date: Thu Jan 01 00:00:01 1970 +0000
760 760 summary: base
761 761
762 762
763 763
764 764 log -P 2
765 765
766 766 $ hg log -P 2
767 767 changeset: 6:2404bbcab562
768 768 tag: tip
769 769 user: test
770 770 date: Thu Jan 01 00:00:01 1970 +0000
771 771 summary: b1.1
772 772
773 773 changeset: 5:302e9dd6890d
774 774 parent: 3:e62f78d544b4
775 775 parent: 4:ddb82e70d1a1
776 776 user: test
777 777 date: Thu Jan 01 00:00:01 1970 +0000
778 778 summary: m12
779 779
780 780 changeset: 4:ddb82e70d1a1
781 781 parent: 0:67e992f2c4f3
782 782 user: test
783 783 date: Thu Jan 01 00:00:01 1970 +0000
784 784 summary: b2
785 785
786 786 changeset: 3:e62f78d544b4
787 787 parent: 1:3d5bf5654eda
788 788 user: test
789 789 date: Thu Jan 01 00:00:01 1970 +0000
790 790 summary: b1
791 791
792 792
793 793
794 794 log -r tip -p --git
795 795
796 796 $ hg log -r tip -p --git
797 797 changeset: 6:2404bbcab562
798 798 tag: tip
799 799 user: test
800 800 date: Thu Jan 01 00:00:01 1970 +0000
801 801 summary: b1.1
802 802
803 803 diff --git a/b1 b/b1
804 804 --- a/b1
805 805 +++ b/b1
806 806 @@ -1,1 +1,2 @@
807 807 b1
808 808 +postm
809 809
810 810
811 811
812 812 log -r ""
813 813
814 814 $ hg log -r ''
815 815 hg: parse error: empty query
816 816 [255]
817 817
818 818 log -r <some unknown node id>
819 819
820 820 $ hg log -r 1000000000000000000000000000000000000000
821 821 abort: unknown revision '1000000000000000000000000000000000000000'!
822 822 [255]
823 823
824 824 log -k r1
825 825
826 826 $ hg log -k r1
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 log -p -l2 --color=always
833 833
834 834 $ hg --config extensions.color= --config color.mode=ansi \
835 835 > log -p -l2 --color=always
836 836 \x1b[0;33mchangeset: 6:2404bbcab562\x1b[0m (esc)
837 837 tag: tip
838 838 user: test
839 839 date: Thu Jan 01 00:00:01 1970 +0000
840 840 summary: b1.1
841 841
842 842 \x1b[0;1mdiff -r 302e9dd6890d -r 2404bbcab562 b1\x1b[0m (esc)
843 843 \x1b[0;31;1m--- a/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
844 844 \x1b[0;32;1m+++ b/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
845 845 \x1b[0;35m@@ -1,1 +1,2 @@\x1b[0m (esc)
846 846 b1
847 847 \x1b[0;32m+postm\x1b[0m (esc)
848 848
849 849 \x1b[0;33mchangeset: 5:302e9dd6890d\x1b[0m (esc)
850 850 parent: 3:e62f78d544b4
851 851 parent: 4:ddb82e70d1a1
852 852 user: test
853 853 date: Thu Jan 01 00:00:01 1970 +0000
854 854 summary: m12
855 855
856 856 \x1b[0;1mdiff -r e62f78d544b4 -r 302e9dd6890d b2\x1b[0m (esc)
857 857 \x1b[0;31;1m--- /dev/null Thu Jan 01 00:00:00 1970 +0000\x1b[0m (esc)
858 858 \x1b[0;32;1m+++ b/b2 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
859 859 \x1b[0;35m@@ -0,0 +1,1 @@\x1b[0m (esc)
860 860 \x1b[0;32m+b2\x1b[0m (esc)
861 861
862 862
863 863
864 864 log -r tip --stat
865 865
866 866 $ hg log -r tip --stat
867 867 changeset: 6:2404bbcab562
868 868 tag: tip
869 869 user: test
870 870 date: Thu Jan 01 00:00:01 1970 +0000
871 871 summary: b1.1
872 872
873 873 b1 | 1 +
874 874 1 files changed, 1 insertions(+), 0 deletions(-)
875 875
876 876
877 877 $ cd ..
878 878
879 879
880 880 User
881 881
882 882 $ hg init usertest
883 883 $ cd usertest
884 884
885 885 $ echo a > a
886 886 $ hg ci -A -m "a" -u "User One <user1@example.org>"
887 887 adding a
888 888 $ echo b > b
889 889 $ hg ci -A -m "b" -u "User Two <user2@example.org>"
890 890 adding b
891 891
892 892 $ hg log -u "User One <user1@example.org>"
893 893 changeset: 0:29a4c94f1924
894 894 user: User One <user1@example.org>
895 895 date: Thu Jan 01 00:00:00 1970 +0000
896 896 summary: a
897 897
898 898 $ hg log -u "user1" -u "user2"
899 899 changeset: 1:e834b5e69c0e
900 900 tag: tip
901 901 user: User Two <user2@example.org>
902 902 date: Thu Jan 01 00:00:00 1970 +0000
903 903 summary: b
904 904
905 905 changeset: 0:29a4c94f1924
906 906 user: User One <user1@example.org>
907 907 date: Thu Jan 01 00:00:00 1970 +0000
908 908 summary: a
909 909
910 910 $ hg log -u "user3"
911 911
912 912 $ cd ..
913 913
914 914 $ hg init branches
915 915 $ cd branches
916 916
917 917 $ echo a > a
918 918 $ hg ci -A -m "commit on default"
919 919 adding a
920 920 $ hg branch test
921 921 marked working directory as branch test
922 922 (branches are permanent and global, did you want a bookmark?)
923 923 $ echo b > b
924 924 $ hg ci -A -m "commit on test"
925 925 adding b
926 926
927 927 $ hg up default
928 928 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
929 929 $ echo c > c
930 930 $ hg ci -A -m "commit on default"
931 931 adding c
932 932 $ hg up test
933 933 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
934 934 $ echo c > c
935 935 $ hg ci -A -m "commit on test"
936 936 adding c
937 937
938 938
939 939 log -b default
940 940
941 941 $ hg log -b default
942 942 changeset: 2:c3a4f03cc9a7
943 943 parent: 0:24427303d56f
944 944 user: test
945 945 date: Thu Jan 01 00:00:00 1970 +0000
946 946 summary: commit on default
947 947
948 948 changeset: 0:24427303d56f
949 949 user: test
950 950 date: Thu Jan 01 00:00:00 1970 +0000
951 951 summary: commit on default
952 952
953 953
954 954
955 955 log -b test
956 956
957 957 $ hg log -b test
958 958 changeset: 3:f5d8de11c2e2
959 959 branch: test
960 960 tag: tip
961 961 parent: 1:d32277701ccb
962 962 user: test
963 963 date: Thu Jan 01 00:00:00 1970 +0000
964 964 summary: commit on test
965 965
966 966 changeset: 1:d32277701ccb
967 967 branch: test
968 968 user: test
969 969 date: Thu Jan 01 00:00:00 1970 +0000
970 970 summary: commit on test
971 971
972 972
973 973
974 974 log -b dummy
975 975
976 976 $ hg log -b dummy
977 977 abort: unknown revision 'dummy'!
978 978 [255]
979 979
980 980
981 981 log -b .
982 982
983 983 $ hg log -b .
984 984 changeset: 3:f5d8de11c2e2
985 985 branch: test
986 986 tag: tip
987 987 parent: 1:d32277701ccb
988 988 user: test
989 989 date: Thu Jan 01 00:00:00 1970 +0000
990 990 summary: commit on test
991 991
992 992 changeset: 1:d32277701ccb
993 993 branch: test
994 994 user: test
995 995 date: Thu Jan 01 00:00:00 1970 +0000
996 996 summary: commit on test
997 997
998 998
999 999
1000 1000 log -b default -b test
1001 1001
1002 1002 $ hg log -b default -b test
1003 1003 changeset: 3:f5d8de11c2e2
1004 1004 branch: test
1005 1005 tag: tip
1006 1006 parent: 1:d32277701ccb
1007 1007 user: test
1008 1008 date: Thu Jan 01 00:00:00 1970 +0000
1009 1009 summary: commit on test
1010 1010
1011 1011 changeset: 2:c3a4f03cc9a7
1012 1012 parent: 0:24427303d56f
1013 1013 user: test
1014 1014 date: Thu Jan 01 00:00:00 1970 +0000
1015 1015 summary: commit on default
1016 1016
1017 1017 changeset: 1:d32277701ccb
1018 1018 branch: test
1019 1019 user: test
1020 1020 date: Thu Jan 01 00:00:00 1970 +0000
1021 1021 summary: commit on test
1022 1022
1023 1023 changeset: 0:24427303d56f
1024 1024 user: test
1025 1025 date: Thu Jan 01 00:00:00 1970 +0000
1026 1026 summary: commit on default
1027 1027
1028 1028
1029 1029
1030 1030 log -b default -b .
1031 1031
1032 1032 $ hg log -b default -b .
1033 1033 changeset: 3:f5d8de11c2e2
1034 1034 branch: test
1035 1035 tag: tip
1036 1036 parent: 1:d32277701ccb
1037 1037 user: test
1038 1038 date: Thu Jan 01 00:00:00 1970 +0000
1039 1039 summary: commit on test
1040 1040
1041 1041 changeset: 2:c3a4f03cc9a7
1042 1042 parent: 0:24427303d56f
1043 1043 user: test
1044 1044 date: Thu Jan 01 00:00:00 1970 +0000
1045 1045 summary: commit on default
1046 1046
1047 1047 changeset: 1:d32277701ccb
1048 1048 branch: test
1049 1049 user: test
1050 1050 date: Thu Jan 01 00:00:00 1970 +0000
1051 1051 summary: commit on test
1052 1052
1053 1053 changeset: 0:24427303d56f
1054 1054 user: test
1055 1055 date: Thu Jan 01 00:00:00 1970 +0000
1056 1056 summary: commit on default
1057 1057
1058 1058
1059 1059
1060 1060 log -b . -b test
1061 1061
1062 1062 $ hg log -b . -b test
1063 1063 changeset: 3:f5d8de11c2e2
1064 1064 branch: test
1065 1065 tag: tip
1066 1066 parent: 1:d32277701ccb
1067 1067 user: test
1068 1068 date: Thu Jan 01 00:00:00 1970 +0000
1069 1069 summary: commit on test
1070 1070
1071 1071 changeset: 1:d32277701ccb
1072 1072 branch: test
1073 1073 user: test
1074 1074 date: Thu Jan 01 00:00:00 1970 +0000
1075 1075 summary: commit on test
1076 1076
1077 1077
1078 1078
1079 1079 log -b 2
1080 1080
1081 1081 $ hg log -b 2
1082 1082 changeset: 2:c3a4f03cc9a7
1083 1083 parent: 0:24427303d56f
1084 1084 user: test
1085 1085 date: Thu Jan 01 00:00:00 1970 +0000
1086 1086 summary: commit on default
1087 1087
1088 1088 changeset: 0:24427303d56f
1089 1089 user: test
1090 1090 date: Thu Jan 01 00:00:00 1970 +0000
1091 1091 summary: commit on default
1092 1092
1093 1093 #if gettext
1094 1094
1095 1095 Test that all log names are translated (e.g. branches, bookmarks, tags):
1096 1096
1097 1097 $ hg bookmark babar -r tip
1098 1098
1099 1099 $ HGENCODING=UTF-8 LANGUAGE=de hg log -r tip
1100 1100 \xc3\x84nderung: 3:f5d8de11c2e2 (esc)
1101 1101 Zweig: test
1102 1102 Lesezeichen: babar
1103 1103 Marke: tip
1104 1104 Vorg\xc3\xa4nger: 1:d32277701ccb (esc)
1105 1105 Nutzer: test
1106 1106 Datum: Thu Jan 01 00:00:00 1970 +0000
1107 1107 Zusammenfassung: commit on test
1108 1108
1109 1109 $ hg bookmark -d babar
1110 1110
1111 1111 #endif
1112 1112
1113 1113 log -p --cwd dir (in subdir)
1114 1114
1115 1115 $ mkdir dir
1116 1116 $ hg log -p --cwd dir
1117 1117 changeset: 3:f5d8de11c2e2
1118 1118 branch: test
1119 1119 tag: tip
1120 1120 parent: 1:d32277701ccb
1121 1121 user: test
1122 1122 date: Thu Jan 01 00:00:00 1970 +0000
1123 1123 summary: commit on test
1124 1124
1125 1125 diff -r d32277701ccb -r f5d8de11c2e2 c
1126 1126 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1127 1127 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1128 1128 @@ -0,0 +1,1 @@
1129 1129 +c
1130 1130
1131 1131 changeset: 2:c3a4f03cc9a7
1132 1132 parent: 0:24427303d56f
1133 1133 user: test
1134 1134 date: Thu Jan 01 00:00:00 1970 +0000
1135 1135 summary: commit on default
1136 1136
1137 1137 diff -r 24427303d56f -r c3a4f03cc9a7 c
1138 1138 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1139 1139 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1140 1140 @@ -0,0 +1,1 @@
1141 1141 +c
1142 1142
1143 1143 changeset: 1:d32277701ccb
1144 1144 branch: test
1145 1145 user: test
1146 1146 date: Thu Jan 01 00:00:00 1970 +0000
1147 1147 summary: commit on test
1148 1148
1149 1149 diff -r 24427303d56f -r d32277701ccb b
1150 1150 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1151 1151 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1152 1152 @@ -0,0 +1,1 @@
1153 1153 +b
1154 1154
1155 1155 changeset: 0:24427303d56f
1156 1156 user: test
1157 1157 date: Thu Jan 01 00:00:00 1970 +0000
1158 1158 summary: commit on default
1159 1159
1160 1160 diff -r 000000000000 -r 24427303d56f a
1161 1161 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1162 1162 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1163 1163 @@ -0,0 +1,1 @@
1164 1164 +a
1165 1165
1166 1166
1167 1167
1168 1168 log -p -R repo
1169 1169
1170 1170 $ cd dir
1171 1171 $ hg log -p -R .. ../a
1172 1172 changeset: 0:24427303d56f
1173 1173 user: test
1174 1174 date: Thu Jan 01 00:00:00 1970 +0000
1175 1175 summary: commit on default
1176 1176
1177 1177 diff -r 000000000000 -r 24427303d56f a
1178 1178 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1179 1179 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1180 1180 @@ -0,0 +1,1 @@
1181 1181 +a
1182 1182
1183 1183
1184 1184 $ cd ../..
1185 1185
1186 1186 $ hg init follow2
1187 1187 $ cd follow2
1188 1188
1189 1189 # Build the following history:
1190 1190 # tip - o - x - o - x - x
1191 1191 # \ /
1192 1192 # o - o - o - x
1193 1193 # \ /
1194 1194 # o
1195 1195 #
1196 1196 # Where "o" is a revision containing "foo" and
1197 1197 # "x" is a revision without "foo"
1198 1198
1199 1199 $ touch init
1200 1200 $ hg ci -A -m "init, unrelated"
1201 1201 adding init
1202 1202 $ echo 'foo' > init
1203 1203 $ hg ci -m "change, unrelated"
1204 1204 $ echo 'foo' > foo
1205 1205 $ hg ci -A -m "add unrelated old foo"
1206 1206 adding foo
1207 1207 $ hg rm foo
1208 1208 $ hg ci -m "delete foo, unrelated"
1209 1209 $ echo 'related' > foo
1210 1210 $ hg ci -A -m "add foo, related"
1211 1211 adding foo
1212 1212
1213 1213 $ hg up 0
1214 1214 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1215 1215 $ touch branch
1216 1216 $ hg ci -A -m "first branch, unrelated"
1217 1217 adding branch
1218 1218 created new head
1219 1219 $ touch foo
1220 1220 $ hg ci -A -m "create foo, related"
1221 1221 adding foo
1222 1222 $ echo 'change' > foo
1223 1223 $ hg ci -m "change foo, related"
1224 1224
1225 1225 $ hg up 6
1226 1226 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1227 1227 $ echo 'change foo in branch' > foo
1228 1228 $ hg ci -m "change foo in branch, related"
1229 1229 created new head
1230 1230 $ hg merge 7
1231 1231 merging foo
1232 1232 warning: conflicts during merge.
1233 1233 merging foo incomplete! (edit conflicts, then use 'hg resolve --mark')
1234 1234 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
1235 1235 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1236 1236 [1]
1237 1237 $ echo 'merge 1' > foo
1238 1238 $ hg resolve -m foo
1239 1239 (no more unresolved files)
1240 1240 $ hg ci -m "First merge, related"
1241 1241
1242 1242 $ hg merge 4
1243 1243 merging foo
1244 1244 warning: conflicts during merge.
1245 1245 merging foo incomplete! (edit conflicts, then use 'hg resolve --mark')
1246 1246 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
1247 1247 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1248 1248 [1]
1249 1249 $ echo 'merge 2' > foo
1250 1250 $ hg resolve -m foo
1251 1251 (no more unresolved files)
1252 1252 $ hg ci -m "Last merge, related"
1253 1253
1254 1254 $ hg log --graph
1255 1255 @ changeset: 10:4dae8563d2c5
1256 1256 |\ tag: tip
1257 1257 | | parent: 9:7b35701b003e
1258 1258 | | parent: 4:88176d361b69
1259 1259 | | user: test
1260 1260 | | date: Thu Jan 01 00:00:00 1970 +0000
1261 1261 | | summary: Last merge, related
1262 1262 | |
1263 1263 | o changeset: 9:7b35701b003e
1264 1264 | |\ parent: 8:e5416ad8a855
1265 1265 | | | parent: 7:87fe3144dcfa
1266 1266 | | | user: test
1267 1267 | | | date: Thu Jan 01 00:00:00 1970 +0000
1268 1268 | | | summary: First merge, related
1269 1269 | | |
1270 1270 | | o changeset: 8:e5416ad8a855
1271 1271 | | | parent: 6:dc6c325fe5ee
1272 1272 | | | user: test
1273 1273 | | | date: Thu Jan 01 00:00:00 1970 +0000
1274 1274 | | | summary: change foo in branch, related
1275 1275 | | |
1276 1276 | o | changeset: 7:87fe3144dcfa
1277 1277 | |/ user: test
1278 1278 | | date: Thu Jan 01 00:00:00 1970 +0000
1279 1279 | | summary: change foo, related
1280 1280 | |
1281 1281 | o changeset: 6:dc6c325fe5ee
1282 1282 | | user: test
1283 1283 | | date: Thu Jan 01 00:00:00 1970 +0000
1284 1284 | | summary: create foo, related
1285 1285 | |
1286 1286 | o changeset: 5:73db34516eb9
1287 1287 | | parent: 0:e87515fd044a
1288 1288 | | user: test
1289 1289 | | date: Thu Jan 01 00:00:00 1970 +0000
1290 1290 | | summary: first branch, unrelated
1291 1291 | |
1292 1292 o | changeset: 4:88176d361b69
1293 1293 | | user: test
1294 1294 | | date: Thu Jan 01 00:00:00 1970 +0000
1295 1295 | | summary: add foo, related
1296 1296 | |
1297 1297 o | changeset: 3:dd78ae4afb56
1298 1298 | | user: test
1299 1299 | | date: Thu Jan 01 00:00:00 1970 +0000
1300 1300 | | summary: delete foo, unrelated
1301 1301 | |
1302 1302 o | changeset: 2:c4c64aedf0f7
1303 1303 | | user: test
1304 1304 | | date: Thu Jan 01 00:00:00 1970 +0000
1305 1305 | | summary: add unrelated old foo
1306 1306 | |
1307 1307 o | changeset: 1:e5faa7440653
1308 1308 |/ user: test
1309 1309 | date: Thu Jan 01 00:00:00 1970 +0000
1310 1310 | summary: change, unrelated
1311 1311 |
1312 1312 o changeset: 0:e87515fd044a
1313 1313 user: test
1314 1314 date: Thu Jan 01 00:00:00 1970 +0000
1315 1315 summary: init, unrelated
1316 1316
1317 1317
1318 1318 $ hg --traceback log -f foo
1319 1319 changeset: 10:4dae8563d2c5
1320 1320 tag: tip
1321 1321 parent: 9:7b35701b003e
1322 1322 parent: 4:88176d361b69
1323 1323 user: test
1324 1324 date: Thu Jan 01 00:00:00 1970 +0000
1325 1325 summary: Last merge, related
1326 1326
1327 1327 changeset: 9:7b35701b003e
1328 1328 parent: 8:e5416ad8a855
1329 1329 parent: 7:87fe3144dcfa
1330 1330 user: test
1331 1331 date: Thu Jan 01 00:00:00 1970 +0000
1332 1332 summary: First merge, related
1333 1333
1334 1334 changeset: 8:e5416ad8a855
1335 1335 parent: 6:dc6c325fe5ee
1336 1336 user: test
1337 1337 date: Thu Jan 01 00:00:00 1970 +0000
1338 1338 summary: change foo in branch, related
1339 1339
1340 1340 changeset: 7:87fe3144dcfa
1341 1341 user: test
1342 1342 date: Thu Jan 01 00:00:00 1970 +0000
1343 1343 summary: change foo, related
1344 1344
1345 1345 changeset: 6:dc6c325fe5ee
1346 1346 user: test
1347 1347 date: Thu Jan 01 00:00:00 1970 +0000
1348 1348 summary: create foo, related
1349 1349
1350 1350 changeset: 4:88176d361b69
1351 1351 user: test
1352 1352 date: Thu Jan 01 00:00:00 1970 +0000
1353 1353 summary: add foo, related
1354 1354
1355 1355
1356 1356 Also check when maxrev < lastrevfilelog
1357 1357
1358 1358 $ hg --traceback log -f -r4 foo
1359 1359 changeset: 4:88176d361b69
1360 1360 user: test
1361 1361 date: Thu Jan 01 00:00:00 1970 +0000
1362 1362 summary: add foo, related
1363 1363
1364 1364 changeset: 2:c4c64aedf0f7
1365 1365 user: test
1366 1366 date: Thu Jan 01 00:00:00 1970 +0000
1367 1367 summary: add unrelated old foo
1368 1368
1369 1369 $ cd ..
1370 1370
1371 1371 Issue2383: hg log showing _less_ differences than hg diff
1372 1372
1373 1373 $ hg init issue2383
1374 1374 $ cd issue2383
1375 1375
1376 1376 Create a test repo:
1377 1377
1378 1378 $ echo a > a
1379 1379 $ hg ci -Am0
1380 1380 adding a
1381 1381 $ echo b > b
1382 1382 $ hg ci -Am1
1383 1383 adding b
1384 1384 $ hg co 0
1385 1385 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1386 1386 $ echo b > a
1387 1387 $ hg ci -m2
1388 1388 created new head
1389 1389
1390 1390 Merge:
1391 1391
1392 1392 $ hg merge
1393 1393 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1394 1394 (branch merge, don't forget to commit)
1395 1395
1396 1396 Make sure there's a file listed in the merge to trigger the bug:
1397 1397
1398 1398 $ echo c > a
1399 1399 $ hg ci -m3
1400 1400
1401 1401 Two files shown here in diff:
1402 1402
1403 1403 $ hg diff --rev 2:3
1404 1404 diff -r b09be438c43a -r 8e07aafe1edc a
1405 1405 --- a/a Thu Jan 01 00:00:00 1970 +0000
1406 1406 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1407 1407 @@ -1,1 +1,1 @@
1408 1408 -b
1409 1409 +c
1410 1410 diff -r b09be438c43a -r 8e07aafe1edc b
1411 1411 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1412 1412 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1413 1413 @@ -0,0 +1,1 @@
1414 1414 +b
1415 1415
1416 1416 Diff here should be the same:
1417 1417
1418 1418 $ hg log -vpr 3
1419 1419 changeset: 3:8e07aafe1edc
1420 1420 tag: tip
1421 1421 parent: 2:b09be438c43a
1422 1422 parent: 1:925d80f479bb
1423 1423 user: test
1424 1424 date: Thu Jan 01 00:00:00 1970 +0000
1425 1425 files: a
1426 1426 description:
1427 1427 3
1428 1428
1429 1429
1430 1430 diff -r b09be438c43a -r 8e07aafe1edc a
1431 1431 --- a/a Thu Jan 01 00:00:00 1970 +0000
1432 1432 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1433 1433 @@ -1,1 +1,1 @@
1434 1434 -b
1435 1435 +c
1436 1436 diff -r b09be438c43a -r 8e07aafe1edc b
1437 1437 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1438 1438 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1439 1439 @@ -0,0 +1,1 @@
1440 1440 +b
1441 1441
1442 1442 $ cd ..
1443 1443
1444 1444 'hg log -r rev fn' when last(filelog(fn)) != rev
1445 1445
1446 1446 $ hg init simplelog
1447 1447 $ cd simplelog
1448 1448 $ echo f > a
1449 1449 $ hg ci -Am'a' -d '0 0'
1450 1450 adding a
1451 1451 $ echo f >> a
1452 1452 $ hg ci -Am'a bis' -d '1 0'
1453 1453
1454 1454 $ hg log -r0 a
1455 1455 changeset: 0:9f758d63dcde
1456 1456 user: test
1457 1457 date: Thu Jan 01 00:00:00 1970 +0000
1458 1458 summary: a
1459 1459
1460 1460 enable obsolete to test hidden feature
1461 1461
1462 1462 $ cat >> $HGRCPATH << EOF
1463 1463 > [experimental]
1464 1464 > evolution=createmarkers
1465 1465 > EOF
1466 1466
1467 1467 $ hg log --template='{rev}:{node}\n'
1468 1468 1:a765632148dc55d38c35c4f247c618701886cb2f
1469 1469 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1470 1470 $ hg debugobsolete a765632148dc55d38c35c4f247c618701886cb2f
1471 1471 $ hg up null -q
1472 1472 $ hg log --template='{rev}:{node}\n'
1473 1473 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1474 1474 $ hg log --template='{rev}:{node}\n' --hidden
1475 1475 1:a765632148dc55d38c35c4f247c618701886cb2f
1476 1476 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1477 1477 $ hg log -r a
1478 1478 abort: hidden revision 'a'!
1479 1479 (use --hidden to access hidden revisions)
1480 1480 [255]
1481 1481
1482 1482 test that parent prevent a changeset to be hidden
1483 1483
1484 1484 $ hg up 1 -q --hidden
1485 1485 $ hg log --template='{rev}:{node}\n'
1486 1486 1:a765632148dc55d38c35c4f247c618701886cb2f
1487 1487 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1488 1488
1489 1489 test that second parent prevent a changeset to be hidden too
1490 1490
1491 1491 $ hg debugsetparents 0 1 # nothing suitable to merge here
1492 1492 $ hg log --template='{rev}:{node}\n'
1493 1493 1:a765632148dc55d38c35c4f247c618701886cb2f
1494 1494 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1495 1495 $ hg debugsetparents 1
1496 1496 $ hg up -q null
1497 1497
1498 1498 bookmarks prevent a changeset being hidden
1499 1499
1500 1500 $ hg bookmark --hidden -r 1 X
1501 1501 $ hg log --template '{rev}:{node}\n'
1502 1502 1:a765632148dc55d38c35c4f247c618701886cb2f
1503 1503 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1504 1504 $ hg bookmark -d X
1505 1505
1506 1506 divergent bookmarks are not hidden
1507 1507
1508 1508 $ hg bookmark --hidden -r 1 X@foo
1509 1509 $ hg log --template '{rev}:{node}\n'
1510 1510 1:a765632148dc55d38c35c4f247c618701886cb2f
1511 1511 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1512 1512
1513 1513 clear extensions configuration
1514 1514 $ echo '[extensions]' >> $HGRCPATH
1515 1515 $ echo "obs=!" >> $HGRCPATH
1516 1516 $ cd ..
1517 1517
1518 1518 test -u/-k for problematic encoding
1519 1519 # unicode: cp932:
1520 1520 # u30A2 0x83 0x41(= 'A')
1521 1521 # u30C2 0x83 0x61(= 'a')
1522 1522
1523 1523 $ hg init problematicencoding
1524 1524 $ cd problematicencoding
1525 1525
1526 1526 $ python > setup.sh <<EOF
1527 1527 > print u'''
1528 1528 > echo a > text
1529 1529 > hg add text
1530 1530 > hg --encoding utf-8 commit -u '\u30A2' -m none
1531 1531 > echo b > text
1532 1532 > hg --encoding utf-8 commit -u '\u30C2' -m none
1533 1533 > echo c > text
1534 1534 > hg --encoding utf-8 commit -u none -m '\u30A2'
1535 1535 > echo d > text
1536 1536 > hg --encoding utf-8 commit -u none -m '\u30C2'
1537 1537 > '''.encode('utf-8')
1538 1538 > EOF
1539 1539 $ sh < setup.sh
1540 1540
1541 1541 test in problematic encoding
1542 1542 $ python > test.sh <<EOF
1543 1543 > print u'''
1544 1544 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30A2'
1545 1545 > echo ====
1546 1546 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30C2'
1547 1547 > echo ====
1548 1548 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30A2'
1549 1549 > echo ====
1550 1550 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30C2'
1551 1551 > '''.encode('cp932')
1552 1552 > EOF
1553 1553 $ sh < test.sh
1554 1554 0
1555 1555 ====
1556 1556 1
1557 1557 ====
1558 1558 2
1559 1559 0
1560 1560 ====
1561 1561 3
1562 1562 1
1563 1563
1564 1564 $ cd ..
1565 1565
1566 1566 test hg log on non-existent files and on directories
1567 1567 $ hg init issue1340
1568 1568 $ cd issue1340
1569 1569 $ mkdir d1; mkdir D2; mkdir D3.i; mkdir d4.hg; mkdir d5.d; mkdir .d6
1570 1570 $ echo 1 > d1/f1
1571 1571 $ echo 1 > D2/f1
1572 1572 $ echo 1 > D3.i/f1
1573 1573 $ echo 1 > d4.hg/f1
1574 1574 $ echo 1 > d5.d/f1
1575 1575 $ echo 1 > .d6/f1
1576 1576 $ hg -q add .
1577 1577 $ hg commit -m "a bunch of weird directories"
1578 1578 $ hg log -l1 d1/f1 | grep changeset
1579 1579 changeset: 0:65624cd9070a
1580 1580 $ hg log -l1 f1
1581 1581 $ hg log -l1 . | grep changeset
1582 1582 changeset: 0:65624cd9070a
1583 1583 $ hg log -l1 ./ | grep changeset
1584 1584 changeset: 0:65624cd9070a
1585 1585 $ hg log -l1 d1 | grep changeset
1586 1586 changeset: 0:65624cd9070a
1587 1587 $ hg log -l1 D2 | grep changeset
1588 1588 changeset: 0:65624cd9070a
1589 1589 $ hg log -l1 D2/f1 | grep changeset
1590 1590 changeset: 0:65624cd9070a
1591 1591 $ hg log -l1 D3.i | grep changeset
1592 1592 changeset: 0:65624cd9070a
1593 1593 $ hg log -l1 D3.i/f1 | grep changeset
1594 1594 changeset: 0:65624cd9070a
1595 1595 $ hg log -l1 d4.hg | grep changeset
1596 1596 changeset: 0:65624cd9070a
1597 1597 $ hg log -l1 d4.hg/f1 | grep changeset
1598 1598 changeset: 0:65624cd9070a
1599 1599 $ hg log -l1 d5.d | grep changeset
1600 1600 changeset: 0:65624cd9070a
1601 1601 $ hg log -l1 d5.d/f1 | grep changeset
1602 1602 changeset: 0:65624cd9070a
1603 1603 $ hg log -l1 .d6 | grep changeset
1604 1604 changeset: 0:65624cd9070a
1605 1605 $ hg log -l1 .d6/f1 | grep changeset
1606 1606 changeset: 0:65624cd9070a
1607 1607
1608 1608 issue3772: hg log -r :null showing revision 0 as well
1609 1609
1610 1610 $ hg log -r :null
1611 1611 changeset: 0:65624cd9070a
1612 1612 tag: tip
1613 1613 user: test
1614 1614 date: Thu Jan 01 00:00:00 1970 +0000
1615 1615 summary: a bunch of weird directories
1616 1616
1617 1617 changeset: -1:000000000000
1618 1618 user:
1619 1619 date: Thu Jan 01 00:00:00 1970 +0000
1620 1620
1621 1621 $ hg log -r null:null
1622 1622 changeset: -1:000000000000
1623 1623 user:
1624 1624 date: Thu Jan 01 00:00:00 1970 +0000
1625 1625
1626 1626 working-directory revision requires special treatment
1627 1627
1628 1628 $ hg log -r 'wdir()'
1629 changeset: 0:65624cd9070a+
1629 changeset: 2147483647:ffffffffffff
1630 1630 parent: 0:65624cd9070a
1631 1631 user: test
1632 1632 date: [A-Za-z0-9:+ ]+ (re)
1633 1633
1634 1634 $ hg log -r 'wdir()' -q
1635 0:65624cd9070a+
1635 2147483647:ffffffffffff
1636 1636
1637 1637 $ hg log -r 'wdir()' --debug
1638 changeset: 0:65624cd9070a035fa7191a54f2b8af39f16b0c08+
1638 changeset: 2147483647:ffffffffffffffffffffffffffffffffffffffff
1639 1639 phase: draft
1640 1640 parent: 0:65624cd9070a035fa7191a54f2b8af39f16b0c08
1641 1641 parent: -1:0000000000000000000000000000000000000000
1642 1642 user: test
1643 1643 date: [A-Za-z0-9:+ ]+ (re)
1644 1644 extra: branch=default
1645 1645
1646 1646 $ hg log -r 'wdir()' -Tjson
1647 1647 [
1648 1648 {
1649 1649 "rev": null,
1650 1650 "node": null,
1651 1651 "branch": "default",
1652 1652 "phase": "draft",
1653 1653 "user": "test",
1654 1654 "date": [*, 0], (glob)
1655 1655 "desc": "",
1656 1656 "bookmarks": [],
1657 1657 "tags": [],
1658 1658 "parents": ["65624cd9070a035fa7191a54f2b8af39f16b0c08"]
1659 1659 }
1660 1660 ]
1661 1661
1662 1662 $ hg log -r 'wdir()' -Tjson -q
1663 1663 [
1664 1664 {
1665 1665 "rev": null,
1666 1666 "node": null
1667 1667 }
1668 1668 ]
1669 1669
1670 1670 $ hg log -r 'wdir()' -Tjson --debug
1671 1671 [
1672 1672 {
1673 1673 "rev": null,
1674 1674 "node": null,
1675 1675 "branch": "default",
1676 1676 "phase": "draft",
1677 1677 "user": "test",
1678 1678 "date": [*, 0], (glob)
1679 1679 "desc": "",
1680 1680 "bookmarks": [],
1681 1681 "tags": [],
1682 1682 "parents": ["65624cd9070a035fa7191a54f2b8af39f16b0c08"],
1683 1683 "manifest": null,
1684 1684 "extra": {"branch": "default"},
1685 1685 "modified": [],
1686 1686 "added": [],
1687 1687 "removed": []
1688 1688 }
1689 1689 ]
1690 1690
1691 1691 Check that adding an arbitrary name shows up in log automatically
1692 1692
1693 1693 $ cat > ../names.py <<EOF
1694 1694 > """A small extension to test adding arbitrary names to a repo"""
1695 1695 > from mercurial.namespaces import namespace
1696 1696 >
1697 1697 > def reposetup(ui, repo):
1698 1698 > foo = {'foo': repo[0].node()}
1699 1699 > names = lambda r: foo.keys()
1700 1700 > namemap = lambda r, name: foo.get(name)
1701 1701 > nodemap = lambda r, node: [name for name, n in foo.iteritems()
1702 1702 > if n == node]
1703 1703 > ns = namespace("bars", templatename="bar", logname="barlog",
1704 1704 > colorname="barcolor", listnames=names, namemap=namemap,
1705 1705 > nodemap=nodemap)
1706 1706 >
1707 1707 > repo.names.addnamespace(ns)
1708 1708 > EOF
1709 1709
1710 1710 $ hg --config extensions.names=../names.py log -r 0
1711 1711 changeset: 0:65624cd9070a
1712 1712 tag: tip
1713 1713 barlog: foo
1714 1714 user: test
1715 1715 date: Thu Jan 01 00:00:00 1970 +0000
1716 1716 summary: a bunch of weird directories
1717 1717
1718 1718 $ hg --config extensions.names=../names.py \
1719 1719 > --config extensions.color= --config color.log.barcolor=red \
1720 1720 > --color=always log -r 0
1721 1721 \x1b[0;33mchangeset: 0:65624cd9070a\x1b[0m (esc)
1722 1722 tag: tip
1723 1723 \x1b[0;31mbarlog: foo\x1b[0m (esc)
1724 1724 user: test
1725 1725 date: Thu Jan 01 00:00:00 1970 +0000
1726 1726 summary: a bunch of weird directories
1727 1727
1728 1728 $ hg --config extensions.names=../names.py log -r 0 --template '{bars}\n'
1729 1729 foo
1730 1730
1731 1731 $ cd ..
1732 1732
1733 1733 hg log -f dir across branches
1734 1734
1735 1735 $ hg init acrossbranches
1736 1736 $ cd acrossbranches
1737 1737 $ mkdir d
1738 1738 $ echo a > d/a && hg ci -Aqm a
1739 1739 $ echo b > d/a && hg ci -Aqm b
1740 1740 $ hg up -q 0
1741 1741 $ echo b > d/a && hg ci -Aqm c
1742 1742 $ hg log -f d -T '{desc}' -G
1743 1743 @ c
1744 1744 |
1745 1745 o a
1746 1746
1747 1747 Ensure that largefiles doesn't interfere with following a normal file
1748 1748 $ hg --config extensions.largefiles= log -f d -T '{desc}' -G
1749 1749 @ c
1750 1750 |
1751 1751 o a
1752 1752
1753 1753 $ hg log -f d/a -T '{desc}' -G
1754 1754 @ c
1755 1755 |
1756 1756 o a
1757 1757
1758 1758 $ cd ..
1759 1759
1760 1760 hg log -f with linkrev pointing to another branch
1761 1761 -------------------------------------------------
1762 1762
1763 1763 create history with a filerev whose linkrev points to another branch
1764 1764
1765 1765 $ hg init branchedlinkrev
1766 1766 $ cd branchedlinkrev
1767 1767 $ echo 1 > a
1768 1768 $ hg commit -Am 'content1'
1769 1769 adding a
1770 1770 $ echo 2 > a
1771 1771 $ hg commit -m 'content2'
1772 1772 $ hg up --rev 'desc(content1)'
1773 1773 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1774 1774 $ echo unrelated > unrelated
1775 1775 $ hg commit -Am 'unrelated'
1776 1776 adding unrelated
1777 1777 created new head
1778 1778 $ hg graft -r 'desc(content2)'
1779 1779 grafting 1:2294ae80ad84 "content2"
1780 1780 $ echo 3 > a
1781 1781 $ hg commit -m 'content3'
1782 1782 $ hg log -G
1783 1783 @ changeset: 4:50b9b36e9c5d
1784 1784 | tag: tip
1785 1785 | user: test
1786 1786 | date: Thu Jan 01 00:00:00 1970 +0000
1787 1787 | summary: content3
1788 1788 |
1789 1789 o changeset: 3:15b2327059e5
1790 1790 | user: test
1791 1791 | date: Thu Jan 01 00:00:00 1970 +0000
1792 1792 | summary: content2
1793 1793 |
1794 1794 o changeset: 2:2029acd1168c
1795 1795 | parent: 0:ae0a3c9f9e95
1796 1796 | user: test
1797 1797 | date: Thu Jan 01 00:00:00 1970 +0000
1798 1798 | summary: unrelated
1799 1799 |
1800 1800 | o changeset: 1:2294ae80ad84
1801 1801 |/ user: test
1802 1802 | date: Thu Jan 01 00:00:00 1970 +0000
1803 1803 | summary: content2
1804 1804 |
1805 1805 o changeset: 0:ae0a3c9f9e95
1806 1806 user: test
1807 1807 date: Thu Jan 01 00:00:00 1970 +0000
1808 1808 summary: content1
1809 1809
1810 1810
1811 1811 log -f on the file should list the graft result.
1812 1812
1813 1813 $ hg log -Gf a
1814 1814 @ changeset: 4:50b9b36e9c5d
1815 1815 | tag: tip
1816 1816 | user: test
1817 1817 | date: Thu Jan 01 00:00:00 1970 +0000
1818 1818 | summary: content3
1819 1819 |
1820 1820 o changeset: 3:15b2327059e5
1821 1821 | user: test
1822 1822 | date: Thu Jan 01 00:00:00 1970 +0000
1823 1823 | summary: content2
1824 1824 |
1825 1825 o changeset: 0:ae0a3c9f9e95
1826 1826 user: test
1827 1827 date: Thu Jan 01 00:00:00 1970 +0000
1828 1828 summary: content1
1829 1829
1830 1830
1831 1831 plain log lists the original version
1832 1832 (XXX we should probably list both)
1833 1833
1834 1834 $ hg log -G a
1835 1835 @ changeset: 4:50b9b36e9c5d
1836 1836 | tag: tip
1837 1837 | user: test
1838 1838 | date: Thu Jan 01 00:00:00 1970 +0000
1839 1839 | summary: content3
1840 1840 |
1841 1841 | o changeset: 1:2294ae80ad84
1842 1842 |/ user: test
1843 1843 | date: Thu Jan 01 00:00:00 1970 +0000
1844 1844 | summary: content2
1845 1845 |
1846 1846 o changeset: 0:ae0a3c9f9e95
1847 1847 user: test
1848 1848 date: Thu Jan 01 00:00:00 1970 +0000
1849 1849 summary: content1
1850 1850
1851 1851
1852 1852 hg log -f from the grafted changeset
1853 1853 (The bootstrap should properly take the topology in account)
1854 1854
1855 1855 $ hg up 'desc(content3)^'
1856 1856 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1857 1857 $ hg log -Gf a
1858 1858 @ changeset: 3:15b2327059e5
1859 1859 | user: test
1860 1860 | date: Thu Jan 01 00:00:00 1970 +0000
1861 1861 | summary: content2
1862 1862 |
1863 1863 o changeset: 0:ae0a3c9f9e95
1864 1864 user: test
1865 1865 date: Thu Jan 01 00:00:00 1970 +0000
1866 1866 summary: content1
1867 1867
1868 1868
1869 1869 Test that we use the first non-hidden changeset in that case.
1870 1870
1871 1871 (hide the changeset)
1872 1872
1873 1873 $ hg log -T '{node}\n' -r 1
1874 1874 2294ae80ad8447bc78383182eeac50cb049df623
1875 1875 $ hg debugobsolete 2294ae80ad8447bc78383182eeac50cb049df623
1876 1876 $ hg log -G
1877 1877 o changeset: 4:50b9b36e9c5d
1878 1878 | tag: tip
1879 1879 | user: test
1880 1880 | date: Thu Jan 01 00:00:00 1970 +0000
1881 1881 | summary: content3
1882 1882 |
1883 1883 @ changeset: 3:15b2327059e5
1884 1884 | user: test
1885 1885 | date: Thu Jan 01 00:00:00 1970 +0000
1886 1886 | summary: content2
1887 1887 |
1888 1888 o changeset: 2:2029acd1168c
1889 1889 | parent: 0:ae0a3c9f9e95
1890 1890 | user: test
1891 1891 | date: Thu Jan 01 00:00:00 1970 +0000
1892 1892 | summary: unrelated
1893 1893 |
1894 1894 o changeset: 0:ae0a3c9f9e95
1895 1895 user: test
1896 1896 date: Thu Jan 01 00:00:00 1970 +0000
1897 1897 summary: content1
1898 1898
1899 1899
1900 1900 Check that log on the file does not drop the file revision.
1901 1901
1902 1902 $ hg log -G a
1903 1903 o changeset: 4:50b9b36e9c5d
1904 1904 | tag: tip
1905 1905 | user: test
1906 1906 | date: Thu Jan 01 00:00:00 1970 +0000
1907 1907 | summary: content3
1908 1908 |
1909 1909 @ changeset: 3:15b2327059e5
1910 1910 | user: test
1911 1911 | date: Thu Jan 01 00:00:00 1970 +0000
1912 1912 | summary: content2
1913 1913 |
1914 1914 o changeset: 0:ae0a3c9f9e95
1915 1915 user: test
1916 1916 date: Thu Jan 01 00:00:00 1970 +0000
1917 1917 summary: content1
1918 1918
1919 1919
1920 1920 Even when a head revision is linkrev-shadowed.
1921 1921
1922 1922 $ hg log -T '{node}\n' -r 4
1923 1923 50b9b36e9c5df2c6fc6dcefa8ad0da929e84aed2
1924 1924 $ hg debugobsolete 50b9b36e9c5df2c6fc6dcefa8ad0da929e84aed2
1925 1925 $ hg log -G a
1926 1926 @ changeset: 3:15b2327059e5
1927 1927 | tag: tip
1928 1928 | user: test
1929 1929 | date: Thu Jan 01 00:00:00 1970 +0000
1930 1930 | summary: content2
1931 1931 |
1932 1932 o changeset: 0:ae0a3c9f9e95
1933 1933 user: test
1934 1934 date: Thu Jan 01 00:00:00 1970 +0000
1935 1935 summary: content1
1936 1936
1937 1937
1938 1938 $ cd ..
1939 1939
1940 1940 Even when the file revision is missing from some head:
1941 1941
1942 1942 $ hg init issue4490
1943 1943 $ cd issue4490
1944 1944 $ echo '[experimental]' >> .hg/hgrc
1945 1945 $ echo 'evolution=createmarkers' >> .hg/hgrc
1946 1946 $ echo a > a
1947 1947 $ hg ci -Am0
1948 1948 adding a
1949 1949 $ echo b > b
1950 1950 $ hg ci -Am1
1951 1951 adding b
1952 1952 $ echo B > b
1953 1953 $ hg ci --amend -m 1
1954 1954 $ hg up 0
1955 1955 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1956 1956 $ echo c > c
1957 1957 $ hg ci -Am2
1958 1958 adding c
1959 1959 created new head
1960 1960 $ hg up 'head() and not .'
1961 1961 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1962 1962 $ hg log -G
1963 1963 o changeset: 4:db815d6d32e6
1964 1964 | tag: tip
1965 1965 | parent: 0:f7b1eb17ad24
1966 1966 | user: test
1967 1967 | date: Thu Jan 01 00:00:00 1970 +0000
1968 1968 | summary: 2
1969 1969 |
1970 1970 | @ changeset: 3:9bc8ce7f9356
1971 1971 |/ parent: 0:f7b1eb17ad24
1972 1972 | user: test
1973 1973 | date: Thu Jan 01 00:00:00 1970 +0000
1974 1974 | summary: 1
1975 1975 |
1976 1976 o changeset: 0:f7b1eb17ad24
1977 1977 user: test
1978 1978 date: Thu Jan 01 00:00:00 1970 +0000
1979 1979 summary: 0
1980 1980
1981 1981 $ hg log -f -G b
1982 1982 @ changeset: 3:9bc8ce7f9356
1983 1983 | parent: 0:f7b1eb17ad24
1984 1984 | user: test
1985 1985 | date: Thu Jan 01 00:00:00 1970 +0000
1986 1986 | summary: 1
1987 1987 |
1988 1988 $ hg log -G b
1989 1989 @ changeset: 3:9bc8ce7f9356
1990 1990 | parent: 0:f7b1eb17ad24
1991 1991 | user: test
1992 1992 | date: Thu Jan 01 00:00:00 1970 +0000
1993 1993 | summary: 1
1994 1994 |
1995 1995 $ cd ..
1996 1996
1997 1997 Check proper report when the manifest changes but not the file issue4499
1998 1998 ------------------------------------------------------------------------
1999 1999
2000 2000 $ hg init issue4499
2001 2001 $ cd issue4499
2002 2002 $ 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
2003 2003 > echo 1 > $f;
2004 2004 > hg add $f;
2005 2005 > done
2006 2006 $ hg commit -m 'A1B1C1'
2007 2007 $ echo 2 > A
2008 2008 $ echo 2 > B
2009 2009 $ echo 2 > C
2010 2010 $ hg commit -m 'A2B2C2'
2011 2011 $ hg up 0
2012 2012 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
2013 2013 $ echo 3 > A
2014 2014 $ echo 2 > B
2015 2015 $ echo 2 > C
2016 2016 $ hg commit -m 'A3B2C2'
2017 2017 created new head
2018 2018
2019 2019 $ hg log -G
2020 2020 @ changeset: 2:fe5fc3d0eb17
2021 2021 | tag: tip
2022 2022 | parent: 0:abf4f0e38563
2023 2023 | user: test
2024 2024 | date: Thu Jan 01 00:00:00 1970 +0000
2025 2025 | summary: A3B2C2
2026 2026 |
2027 2027 | o changeset: 1:07dcc6b312c0
2028 2028 |/ user: test
2029 2029 | date: Thu Jan 01 00:00:00 1970 +0000
2030 2030 | summary: A2B2C2
2031 2031 |
2032 2032 o changeset: 0:abf4f0e38563
2033 2033 user: test
2034 2034 date: Thu Jan 01 00:00:00 1970 +0000
2035 2035 summary: A1B1C1
2036 2036
2037 2037
2038 2038 Log -f on B should reports current changesets
2039 2039
2040 2040 $ hg log -fG B
2041 2041 @ changeset: 2:fe5fc3d0eb17
2042 2042 | tag: tip
2043 2043 | parent: 0:abf4f0e38563
2044 2044 | user: test
2045 2045 | date: Thu Jan 01 00:00:00 1970 +0000
2046 2046 | summary: A3B2C2
2047 2047 |
2048 2048 o changeset: 0:abf4f0e38563
2049 2049 user: test
2050 2050 date: Thu Jan 01 00:00:00 1970 +0000
2051 2051 summary: A1B1C1
2052 2052
2053 2053 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now