##// END OF EJS Templates
context: make workingctx.matches() filter our removed files (API)...
Martin von Zweigbergk -
r38296:aaed058a default
parent child Browse files
Show More
@@ -1,2533 +1,2534 b''
1 # context.py - changeset and file context objects for mercurial
1 # context.py - changeset and file context objects for mercurial
2 #
2 #
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import errno
10 import errno
11 import filecmp
11 import filecmp
12 import os
12 import os
13 import stat
13 import stat
14
14
15 from .i18n import _
15 from .i18n import _
16 from .node import (
16 from .node import (
17 addednodeid,
17 addednodeid,
18 bin,
18 bin,
19 hex,
19 hex,
20 modifiednodeid,
20 modifiednodeid,
21 nullid,
21 nullid,
22 nullrev,
22 nullrev,
23 short,
23 short,
24 wdirfilenodeids,
24 wdirfilenodeids,
25 wdirid,
25 wdirid,
26 )
26 )
27 from . import (
27 from . import (
28 dagop,
28 dagop,
29 encoding,
29 encoding,
30 error,
30 error,
31 fileset,
31 fileset,
32 match as matchmod,
32 match as matchmod,
33 obsolete as obsmod,
33 obsolete as obsmod,
34 patch,
34 patch,
35 pathutil,
35 pathutil,
36 phases,
36 phases,
37 pycompat,
37 pycompat,
38 repoview,
38 repoview,
39 revlog,
39 revlog,
40 scmutil,
40 scmutil,
41 sparse,
41 sparse,
42 subrepo,
42 subrepo,
43 subrepoutil,
43 subrepoutil,
44 util,
44 util,
45 )
45 )
46 from .utils import (
46 from .utils import (
47 dateutil,
47 dateutil,
48 stringutil,
48 stringutil,
49 )
49 )
50
50
51 propertycache = util.propertycache
51 propertycache = util.propertycache
52
52
53 class basectx(object):
53 class basectx(object):
54 """A basectx object represents the common logic for its children:
54 """A basectx object represents the common logic for its children:
55 changectx: read-only context that is already present in the repo,
55 changectx: read-only context that is already present in the repo,
56 workingctx: a context that represents the working directory and can
56 workingctx: a context that represents the working directory and can
57 be committed,
57 be committed,
58 memctx: a context that represents changes in-memory and can also
58 memctx: a context that represents changes in-memory and can also
59 be committed."""
59 be committed."""
60
60
61 def __init__(self, repo):
61 def __init__(self, repo):
62 self._repo = repo
62 self._repo = repo
63
63
64 def __bytes__(self):
64 def __bytes__(self):
65 return short(self.node())
65 return short(self.node())
66
66
67 __str__ = encoding.strmethod(__bytes__)
67 __str__ = encoding.strmethod(__bytes__)
68
68
69 def __repr__(self):
69 def __repr__(self):
70 return r"<%s %s>" % (type(self).__name__, str(self))
70 return r"<%s %s>" % (type(self).__name__, str(self))
71
71
72 def __eq__(self, other):
72 def __eq__(self, other):
73 try:
73 try:
74 return type(self) == type(other) and self._rev == other._rev
74 return type(self) == type(other) and self._rev == other._rev
75 except AttributeError:
75 except AttributeError:
76 return False
76 return False
77
77
78 def __ne__(self, other):
78 def __ne__(self, other):
79 return not (self == other)
79 return not (self == other)
80
80
81 def __contains__(self, key):
81 def __contains__(self, key):
82 return key in self._manifest
82 return key in self._manifest
83
83
84 def __getitem__(self, key):
84 def __getitem__(self, key):
85 return self.filectx(key)
85 return self.filectx(key)
86
86
87 def __iter__(self):
87 def __iter__(self):
88 return iter(self._manifest)
88 return iter(self._manifest)
89
89
90 def _buildstatusmanifest(self, status):
90 def _buildstatusmanifest(self, status):
91 """Builds a manifest that includes the given status results, if this is
91 """Builds a manifest that includes the given status results, if this is
92 a working copy context. For non-working copy contexts, it just returns
92 a working copy context. For non-working copy contexts, it just returns
93 the normal manifest."""
93 the normal manifest."""
94 return self.manifest()
94 return self.manifest()
95
95
96 def _matchstatus(self, other, match):
96 def _matchstatus(self, other, match):
97 """This internal method provides a way for child objects to override the
97 """This internal method provides a way for child objects to override the
98 match operator.
98 match operator.
99 """
99 """
100 return match
100 return match
101
101
102 def _buildstatus(self, other, s, match, listignored, listclean,
102 def _buildstatus(self, other, s, match, listignored, listclean,
103 listunknown):
103 listunknown):
104 """build a status with respect to another context"""
104 """build a status with respect to another context"""
105 # Load earliest manifest first for caching reasons. More specifically,
105 # Load earliest manifest first for caching reasons. More specifically,
106 # if you have revisions 1000 and 1001, 1001 is probably stored as a
106 # if you have revisions 1000 and 1001, 1001 is probably stored as a
107 # delta against 1000. Thus, if you read 1000 first, we'll reconstruct
107 # delta against 1000. Thus, if you read 1000 first, we'll reconstruct
108 # 1000 and cache it so that when you read 1001, we just need to apply a
108 # 1000 and cache it so that when you read 1001, we just need to apply a
109 # delta to what's in the cache. So that's one full reconstruction + one
109 # delta to what's in the cache. So that's one full reconstruction + one
110 # delta application.
110 # delta application.
111 mf2 = None
111 mf2 = None
112 if self.rev() is not None and self.rev() < other.rev():
112 if self.rev() is not None and self.rev() < other.rev():
113 mf2 = self._buildstatusmanifest(s)
113 mf2 = self._buildstatusmanifest(s)
114 mf1 = other._buildstatusmanifest(s)
114 mf1 = other._buildstatusmanifest(s)
115 if mf2 is None:
115 if mf2 is None:
116 mf2 = self._buildstatusmanifest(s)
116 mf2 = self._buildstatusmanifest(s)
117
117
118 modified, added = [], []
118 modified, added = [], []
119 removed = []
119 removed = []
120 clean = []
120 clean = []
121 deleted, unknown, ignored = s.deleted, s.unknown, s.ignored
121 deleted, unknown, ignored = s.deleted, s.unknown, s.ignored
122 deletedset = set(deleted)
122 deletedset = set(deleted)
123 d = mf1.diff(mf2, match=match, clean=listclean)
123 d = mf1.diff(mf2, match=match, clean=listclean)
124 for fn, value in d.iteritems():
124 for fn, value in d.iteritems():
125 if fn in deletedset:
125 if fn in deletedset:
126 continue
126 continue
127 if value is None:
127 if value is None:
128 clean.append(fn)
128 clean.append(fn)
129 continue
129 continue
130 (node1, flag1), (node2, flag2) = value
130 (node1, flag1), (node2, flag2) = value
131 if node1 is None:
131 if node1 is None:
132 added.append(fn)
132 added.append(fn)
133 elif node2 is None:
133 elif node2 is None:
134 removed.append(fn)
134 removed.append(fn)
135 elif flag1 != flag2:
135 elif flag1 != flag2:
136 modified.append(fn)
136 modified.append(fn)
137 elif node2 not in wdirfilenodeids:
137 elif node2 not in wdirfilenodeids:
138 # When comparing files between two commits, we save time by
138 # When comparing files between two commits, we save time by
139 # not comparing the file contents when the nodeids differ.
139 # not comparing the file contents when the nodeids differ.
140 # Note that this means we incorrectly report a reverted change
140 # Note that this means we incorrectly report a reverted change
141 # to a file as a modification.
141 # to a file as a modification.
142 modified.append(fn)
142 modified.append(fn)
143 elif self[fn].cmp(other[fn]):
143 elif self[fn].cmp(other[fn]):
144 modified.append(fn)
144 modified.append(fn)
145 else:
145 else:
146 clean.append(fn)
146 clean.append(fn)
147
147
148 if removed:
148 if removed:
149 # need to filter files if they are already reported as removed
149 # need to filter files if they are already reported as removed
150 unknown = [fn for fn in unknown if fn not in mf1 and
150 unknown = [fn for fn in unknown if fn not in mf1 and
151 (not match or match(fn))]
151 (not match or match(fn))]
152 ignored = [fn for fn in ignored if fn not in mf1 and
152 ignored = [fn for fn in ignored if fn not in mf1 and
153 (not match or match(fn))]
153 (not match or match(fn))]
154 # if they're deleted, don't report them as removed
154 # if they're deleted, don't report them as removed
155 removed = [fn for fn in removed if fn not in deletedset]
155 removed = [fn for fn in removed if fn not in deletedset]
156
156
157 return scmutil.status(modified, added, removed, deleted, unknown,
157 return scmutil.status(modified, added, removed, deleted, unknown,
158 ignored, clean)
158 ignored, clean)
159
159
160 @propertycache
160 @propertycache
161 def substate(self):
161 def substate(self):
162 return subrepoutil.state(self, self._repo.ui)
162 return subrepoutil.state(self, self._repo.ui)
163
163
164 def subrev(self, subpath):
164 def subrev(self, subpath):
165 return self.substate[subpath][1]
165 return self.substate[subpath][1]
166
166
167 def rev(self):
167 def rev(self):
168 return self._rev
168 return self._rev
169 def node(self):
169 def node(self):
170 return self._node
170 return self._node
171 def hex(self):
171 def hex(self):
172 return hex(self.node())
172 return hex(self.node())
173 def manifest(self):
173 def manifest(self):
174 return self._manifest
174 return self._manifest
175 def manifestctx(self):
175 def manifestctx(self):
176 return self._manifestctx
176 return self._manifestctx
177 def repo(self):
177 def repo(self):
178 return self._repo
178 return self._repo
179 def phasestr(self):
179 def phasestr(self):
180 return phases.phasenames[self.phase()]
180 return phases.phasenames[self.phase()]
181 def mutable(self):
181 def mutable(self):
182 return self.phase() > phases.public
182 return self.phase() > phases.public
183
183
184 def getfileset(self, expr):
184 def getfileset(self, expr):
185 return fileset.getfileset(self, expr)
185 return fileset.getfileset(self, expr)
186
186
187 def obsolete(self):
187 def obsolete(self):
188 """True if the changeset is obsolete"""
188 """True if the changeset is obsolete"""
189 return self.rev() in obsmod.getrevs(self._repo, 'obsolete')
189 return self.rev() in obsmod.getrevs(self._repo, 'obsolete')
190
190
191 def extinct(self):
191 def extinct(self):
192 """True if the changeset is extinct"""
192 """True if the changeset is extinct"""
193 return self.rev() in obsmod.getrevs(self._repo, 'extinct')
193 return self.rev() in obsmod.getrevs(self._repo, 'extinct')
194
194
195 def orphan(self):
195 def orphan(self):
196 """True if the changeset is not obsolete but it's ancestor are"""
196 """True if the changeset is not obsolete but it's ancestor are"""
197 return self.rev() in obsmod.getrevs(self._repo, 'orphan')
197 return self.rev() in obsmod.getrevs(self._repo, 'orphan')
198
198
199 def phasedivergent(self):
199 def phasedivergent(self):
200 """True if the changeset try to be a successor of a public changeset
200 """True if the changeset try to be a successor of a public changeset
201
201
202 Only non-public and non-obsolete changesets may be bumped.
202 Only non-public and non-obsolete changesets may be bumped.
203 """
203 """
204 return self.rev() in obsmod.getrevs(self._repo, 'phasedivergent')
204 return self.rev() in obsmod.getrevs(self._repo, 'phasedivergent')
205
205
206 def contentdivergent(self):
206 def contentdivergent(self):
207 """Is a successors of a changeset with multiple possible successors set
207 """Is a successors of a changeset with multiple possible successors set
208
208
209 Only non-public and non-obsolete changesets may be divergent.
209 Only non-public and non-obsolete changesets may be divergent.
210 """
210 """
211 return self.rev() in obsmod.getrevs(self._repo, 'contentdivergent')
211 return self.rev() in obsmod.getrevs(self._repo, 'contentdivergent')
212
212
213 def isunstable(self):
213 def isunstable(self):
214 """True if the changeset is either unstable, bumped or divergent"""
214 """True if the changeset is either unstable, bumped or divergent"""
215 return self.orphan() or self.phasedivergent() or self.contentdivergent()
215 return self.orphan() or self.phasedivergent() or self.contentdivergent()
216
216
217 def instabilities(self):
217 def instabilities(self):
218 """return the list of instabilities affecting this changeset.
218 """return the list of instabilities affecting this changeset.
219
219
220 Instabilities are returned as strings. possible values are:
220 Instabilities are returned as strings. possible values are:
221 - orphan,
221 - orphan,
222 - phase-divergent,
222 - phase-divergent,
223 - content-divergent.
223 - content-divergent.
224 """
224 """
225 instabilities = []
225 instabilities = []
226 if self.orphan():
226 if self.orphan():
227 instabilities.append('orphan')
227 instabilities.append('orphan')
228 if self.phasedivergent():
228 if self.phasedivergent():
229 instabilities.append('phase-divergent')
229 instabilities.append('phase-divergent')
230 if self.contentdivergent():
230 if self.contentdivergent():
231 instabilities.append('content-divergent')
231 instabilities.append('content-divergent')
232 return instabilities
232 return instabilities
233
233
234 def parents(self):
234 def parents(self):
235 """return contexts for each parent changeset"""
235 """return contexts for each parent changeset"""
236 return self._parents
236 return self._parents
237
237
238 def p1(self):
238 def p1(self):
239 return self._parents[0]
239 return self._parents[0]
240
240
241 def p2(self):
241 def p2(self):
242 parents = self._parents
242 parents = self._parents
243 if len(parents) == 2:
243 if len(parents) == 2:
244 return parents[1]
244 return parents[1]
245 return changectx(self._repo, nullrev)
245 return changectx(self._repo, nullrev)
246
246
247 def _fileinfo(self, path):
247 def _fileinfo(self, path):
248 if r'_manifest' in self.__dict__:
248 if r'_manifest' in self.__dict__:
249 try:
249 try:
250 return self._manifest[path], self._manifest.flags(path)
250 return self._manifest[path], self._manifest.flags(path)
251 except KeyError:
251 except KeyError:
252 raise error.ManifestLookupError(self._node, path,
252 raise error.ManifestLookupError(self._node, path,
253 _('not found in manifest'))
253 _('not found in manifest'))
254 if r'_manifestdelta' in self.__dict__ or path in self.files():
254 if r'_manifestdelta' in self.__dict__ or path in self.files():
255 if path in self._manifestdelta:
255 if path in self._manifestdelta:
256 return (self._manifestdelta[path],
256 return (self._manifestdelta[path],
257 self._manifestdelta.flags(path))
257 self._manifestdelta.flags(path))
258 mfl = self._repo.manifestlog
258 mfl = self._repo.manifestlog
259 try:
259 try:
260 node, flag = mfl[self._changeset.manifest].find(path)
260 node, flag = mfl[self._changeset.manifest].find(path)
261 except KeyError:
261 except KeyError:
262 raise error.ManifestLookupError(self._node, path,
262 raise error.ManifestLookupError(self._node, path,
263 _('not found in manifest'))
263 _('not found in manifest'))
264
264
265 return node, flag
265 return node, flag
266
266
267 def filenode(self, path):
267 def filenode(self, path):
268 return self._fileinfo(path)[0]
268 return self._fileinfo(path)[0]
269
269
270 def flags(self, path):
270 def flags(self, path):
271 try:
271 try:
272 return self._fileinfo(path)[1]
272 return self._fileinfo(path)[1]
273 except error.LookupError:
273 except error.LookupError:
274 return ''
274 return ''
275
275
276 def sub(self, path, allowcreate=True):
276 def sub(self, path, allowcreate=True):
277 '''return a subrepo for the stored revision of path, never wdir()'''
277 '''return a subrepo for the stored revision of path, never wdir()'''
278 return subrepo.subrepo(self, path, allowcreate=allowcreate)
278 return subrepo.subrepo(self, path, allowcreate=allowcreate)
279
279
280 def nullsub(self, path, pctx):
280 def nullsub(self, path, pctx):
281 return subrepo.nullsubrepo(self, path, pctx)
281 return subrepo.nullsubrepo(self, path, pctx)
282
282
283 def workingsub(self, path):
283 def workingsub(self, path):
284 '''return a subrepo for the stored revision, or wdir if this is a wdir
284 '''return a subrepo for the stored revision, or wdir if this is a wdir
285 context.
285 context.
286 '''
286 '''
287 return subrepo.subrepo(self, path, allowwdir=True)
287 return subrepo.subrepo(self, path, allowwdir=True)
288
288
289 def match(self, pats=None, include=None, exclude=None, default='glob',
289 def match(self, pats=None, include=None, exclude=None, default='glob',
290 listsubrepos=False, badfn=None):
290 listsubrepos=False, badfn=None):
291 r = self._repo
291 r = self._repo
292 return matchmod.match(r.root, r.getcwd(), pats,
292 return matchmod.match(r.root, r.getcwd(), pats,
293 include, exclude, default,
293 include, exclude, default,
294 auditor=r.nofsauditor, ctx=self,
294 auditor=r.nofsauditor, ctx=self,
295 listsubrepos=listsubrepos, badfn=badfn)
295 listsubrepos=listsubrepos, badfn=badfn)
296
296
297 def diff(self, ctx2=None, match=None, **opts):
297 def diff(self, ctx2=None, match=None, **opts):
298 """Returns a diff generator for the given contexts and matcher"""
298 """Returns a diff generator for the given contexts and matcher"""
299 if ctx2 is None:
299 if ctx2 is None:
300 ctx2 = self.p1()
300 ctx2 = self.p1()
301 if ctx2 is not None:
301 if ctx2 is not None:
302 ctx2 = self._repo[ctx2]
302 ctx2 = self._repo[ctx2]
303 diffopts = patch.diffopts(self._repo.ui, pycompat.byteskwargs(opts))
303 diffopts = patch.diffopts(self._repo.ui, pycompat.byteskwargs(opts))
304 return patch.diff(self._repo, ctx2, self, match=match, opts=diffopts)
304 return patch.diff(self._repo, ctx2, self, match=match, opts=diffopts)
305
305
306 def dirs(self):
306 def dirs(self):
307 return self._manifest.dirs()
307 return self._manifest.dirs()
308
308
309 def hasdir(self, dir):
309 def hasdir(self, dir):
310 return self._manifest.hasdir(dir)
310 return self._manifest.hasdir(dir)
311
311
312 def status(self, other=None, match=None, listignored=False,
312 def status(self, other=None, match=None, listignored=False,
313 listclean=False, listunknown=False, listsubrepos=False):
313 listclean=False, listunknown=False, listsubrepos=False):
314 """return status of files between two nodes or node and working
314 """return status of files between two nodes or node and working
315 directory.
315 directory.
316
316
317 If other is None, compare this node with working directory.
317 If other is None, compare this node with working directory.
318
318
319 returns (modified, added, removed, deleted, unknown, ignored, clean)
319 returns (modified, added, removed, deleted, unknown, ignored, clean)
320 """
320 """
321
321
322 ctx1 = self
322 ctx1 = self
323 ctx2 = self._repo[other]
323 ctx2 = self._repo[other]
324
324
325 # This next code block is, admittedly, fragile logic that tests for
325 # This next code block is, admittedly, fragile logic that tests for
326 # reversing the contexts and wouldn't need to exist if it weren't for
326 # reversing the contexts and wouldn't need to exist if it weren't for
327 # the fast (and common) code path of comparing the working directory
327 # the fast (and common) code path of comparing the working directory
328 # with its first parent.
328 # with its first parent.
329 #
329 #
330 # What we're aiming for here is the ability to call:
330 # What we're aiming for here is the ability to call:
331 #
331 #
332 # workingctx.status(parentctx)
332 # workingctx.status(parentctx)
333 #
333 #
334 # If we always built the manifest for each context and compared those,
334 # If we always built the manifest for each context and compared those,
335 # then we'd be done. But the special case of the above call means we
335 # then we'd be done. But the special case of the above call means we
336 # just copy the manifest of the parent.
336 # just copy the manifest of the parent.
337 reversed = False
337 reversed = False
338 if (not isinstance(ctx1, changectx)
338 if (not isinstance(ctx1, changectx)
339 and isinstance(ctx2, changectx)):
339 and isinstance(ctx2, changectx)):
340 reversed = True
340 reversed = True
341 ctx1, ctx2 = ctx2, ctx1
341 ctx1, ctx2 = ctx2, ctx1
342
342
343 match = match or matchmod.always(self._repo.root, self._repo.getcwd())
343 match = match or matchmod.always(self._repo.root, self._repo.getcwd())
344 match = ctx2._matchstatus(ctx1, match)
344 match = ctx2._matchstatus(ctx1, match)
345 r = scmutil.status([], [], [], [], [], [], [])
345 r = scmutil.status([], [], [], [], [], [], [])
346 r = ctx2._buildstatus(ctx1, r, match, listignored, listclean,
346 r = ctx2._buildstatus(ctx1, r, match, listignored, listclean,
347 listunknown)
347 listunknown)
348
348
349 if reversed:
349 if reversed:
350 # Reverse added and removed. Clear deleted, unknown and ignored as
350 # Reverse added and removed. Clear deleted, unknown and ignored as
351 # these make no sense to reverse.
351 # these make no sense to reverse.
352 r = scmutil.status(r.modified, r.removed, r.added, [], [], [],
352 r = scmutil.status(r.modified, r.removed, r.added, [], [], [],
353 r.clean)
353 r.clean)
354
354
355 if listsubrepos:
355 if listsubrepos:
356 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
356 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
357 try:
357 try:
358 rev2 = ctx2.subrev(subpath)
358 rev2 = ctx2.subrev(subpath)
359 except KeyError:
359 except KeyError:
360 # A subrepo that existed in node1 was deleted between
360 # A subrepo that existed in node1 was deleted between
361 # node1 and node2 (inclusive). Thus, ctx2's substate
361 # node1 and node2 (inclusive). Thus, ctx2's substate
362 # won't contain that subpath. The best we can do ignore it.
362 # won't contain that subpath. The best we can do ignore it.
363 rev2 = None
363 rev2 = None
364 submatch = matchmod.subdirmatcher(subpath, match)
364 submatch = matchmod.subdirmatcher(subpath, match)
365 s = sub.status(rev2, match=submatch, ignored=listignored,
365 s = sub.status(rev2, match=submatch, ignored=listignored,
366 clean=listclean, unknown=listunknown,
366 clean=listclean, unknown=listunknown,
367 listsubrepos=True)
367 listsubrepos=True)
368 for rfiles, sfiles in zip(r, s):
368 for rfiles, sfiles in zip(r, s):
369 rfiles.extend("%s/%s" % (subpath, f) for f in sfiles)
369 rfiles.extend("%s/%s" % (subpath, f) for f in sfiles)
370
370
371 for l in r:
371 for l in r:
372 l.sort()
372 l.sort()
373
373
374 return r
374 return r
375
375
376 class changectx(basectx):
376 class changectx(basectx):
377 """A changecontext object makes access to data related to a particular
377 """A changecontext object makes access to data related to a particular
378 changeset convenient. It represents a read-only context already present in
378 changeset convenient. It represents a read-only context already present in
379 the repo."""
379 the repo."""
380 def __init__(self, repo, changeid='.'):
380 def __init__(self, repo, changeid='.'):
381 """changeid is a revision number, node, or tag"""
381 """changeid is a revision number, node, or tag"""
382 super(changectx, self).__init__(repo)
382 super(changectx, self).__init__(repo)
383
383
384 try:
384 try:
385 if isinstance(changeid, int):
385 if isinstance(changeid, int):
386 self._node = repo.changelog.node(changeid)
386 self._node = repo.changelog.node(changeid)
387 self._rev = changeid
387 self._rev = changeid
388 return
388 return
389 elif changeid == 'null':
389 elif changeid == 'null':
390 self._node = nullid
390 self._node = nullid
391 self._rev = nullrev
391 self._rev = nullrev
392 return
392 return
393 elif changeid == 'tip':
393 elif changeid == 'tip':
394 self._node = repo.changelog.tip()
394 self._node = repo.changelog.tip()
395 self._rev = repo.changelog.rev(self._node)
395 self._rev = repo.changelog.rev(self._node)
396 return
396 return
397 elif (changeid == '.'
397 elif (changeid == '.'
398 or repo.local() and changeid == repo.dirstate.p1()):
398 or repo.local() and changeid == repo.dirstate.p1()):
399 # this is a hack to delay/avoid loading obsmarkers
399 # this is a hack to delay/avoid loading obsmarkers
400 # when we know that '.' won't be hidden
400 # when we know that '.' won't be hidden
401 self._node = repo.dirstate.p1()
401 self._node = repo.dirstate.p1()
402 self._rev = repo.unfiltered().changelog.rev(self._node)
402 self._rev = repo.unfiltered().changelog.rev(self._node)
403 return
403 return
404 elif len(changeid) == 20:
404 elif len(changeid) == 20:
405 try:
405 try:
406 self._node = changeid
406 self._node = changeid
407 self._rev = repo.changelog.rev(changeid)
407 self._rev = repo.changelog.rev(changeid)
408 return
408 return
409 except error.FilteredLookupError:
409 except error.FilteredLookupError:
410 raise
410 raise
411 except LookupError:
411 except LookupError:
412 # check if it might have come from damaged dirstate
412 # check if it might have come from damaged dirstate
413 #
413 #
414 # XXX we could avoid the unfiltered if we had a recognizable
414 # XXX we could avoid the unfiltered if we had a recognizable
415 # exception for filtered changeset access
415 # exception for filtered changeset access
416 if (repo.local()
416 if (repo.local()
417 and changeid in repo.unfiltered().dirstate.parents()):
417 and changeid in repo.unfiltered().dirstate.parents()):
418 msg = _("working directory has unknown parent '%s'!")
418 msg = _("working directory has unknown parent '%s'!")
419 raise error.Abort(msg % short(changeid))
419 raise error.Abort(msg % short(changeid))
420 changeid = hex(changeid) # for the error message
420 changeid = hex(changeid) # for the error message
421
421
422 elif len(changeid) == 40:
422 elif len(changeid) == 40:
423 try:
423 try:
424 self._node = bin(changeid)
424 self._node = bin(changeid)
425 self._rev = repo.changelog.rev(self._node)
425 self._rev = repo.changelog.rev(self._node)
426 return
426 return
427 except error.FilteredLookupError:
427 except error.FilteredLookupError:
428 raise
428 raise
429 except (TypeError, LookupError):
429 except (TypeError, LookupError):
430 pass
430 pass
431
431
432 # lookup failed
432 # lookup failed
433 except (error.FilteredIndexError, error.FilteredLookupError):
433 except (error.FilteredIndexError, error.FilteredLookupError):
434 raise error.FilteredRepoLookupError(_("filtered revision '%s'")
434 raise error.FilteredRepoLookupError(_("filtered revision '%s'")
435 % pycompat.bytestr(changeid))
435 % pycompat.bytestr(changeid))
436 except error.FilteredRepoLookupError:
436 except error.FilteredRepoLookupError:
437 raise
437 raise
438 except IndexError:
438 except IndexError:
439 pass
439 pass
440 raise error.RepoLookupError(
440 raise error.RepoLookupError(
441 _("unknown revision '%s'") % changeid)
441 _("unknown revision '%s'") % changeid)
442
442
443 def __hash__(self):
443 def __hash__(self):
444 try:
444 try:
445 return hash(self._rev)
445 return hash(self._rev)
446 except AttributeError:
446 except AttributeError:
447 return id(self)
447 return id(self)
448
448
449 def __nonzero__(self):
449 def __nonzero__(self):
450 return self._rev != nullrev
450 return self._rev != nullrev
451
451
452 __bool__ = __nonzero__
452 __bool__ = __nonzero__
453
453
454 @propertycache
454 @propertycache
455 def _changeset(self):
455 def _changeset(self):
456 return self._repo.changelog.changelogrevision(self.rev())
456 return self._repo.changelog.changelogrevision(self.rev())
457
457
458 @propertycache
458 @propertycache
459 def _manifest(self):
459 def _manifest(self):
460 return self._manifestctx.read()
460 return self._manifestctx.read()
461
461
462 @property
462 @property
463 def _manifestctx(self):
463 def _manifestctx(self):
464 return self._repo.manifestlog[self._changeset.manifest]
464 return self._repo.manifestlog[self._changeset.manifest]
465
465
466 @propertycache
466 @propertycache
467 def _manifestdelta(self):
467 def _manifestdelta(self):
468 return self._manifestctx.readdelta()
468 return self._manifestctx.readdelta()
469
469
470 @propertycache
470 @propertycache
471 def _parents(self):
471 def _parents(self):
472 repo = self._repo
472 repo = self._repo
473 p1, p2 = repo.changelog.parentrevs(self._rev)
473 p1, p2 = repo.changelog.parentrevs(self._rev)
474 if p2 == nullrev:
474 if p2 == nullrev:
475 return [changectx(repo, p1)]
475 return [changectx(repo, p1)]
476 return [changectx(repo, p1), changectx(repo, p2)]
476 return [changectx(repo, p1), changectx(repo, p2)]
477
477
478 def changeset(self):
478 def changeset(self):
479 c = self._changeset
479 c = self._changeset
480 return (
480 return (
481 c.manifest,
481 c.manifest,
482 c.user,
482 c.user,
483 c.date,
483 c.date,
484 c.files,
484 c.files,
485 c.description,
485 c.description,
486 c.extra,
486 c.extra,
487 )
487 )
488 def manifestnode(self):
488 def manifestnode(self):
489 return self._changeset.manifest
489 return self._changeset.manifest
490
490
491 def user(self):
491 def user(self):
492 return self._changeset.user
492 return self._changeset.user
493 def date(self):
493 def date(self):
494 return self._changeset.date
494 return self._changeset.date
495 def files(self):
495 def files(self):
496 return self._changeset.files
496 return self._changeset.files
497 def description(self):
497 def description(self):
498 return self._changeset.description
498 return self._changeset.description
499 def branch(self):
499 def branch(self):
500 return encoding.tolocal(self._changeset.extra.get("branch"))
500 return encoding.tolocal(self._changeset.extra.get("branch"))
501 def closesbranch(self):
501 def closesbranch(self):
502 return 'close' in self._changeset.extra
502 return 'close' in self._changeset.extra
503 def extra(self):
503 def extra(self):
504 """Return a dict of extra information."""
504 """Return a dict of extra information."""
505 return self._changeset.extra
505 return self._changeset.extra
506 def tags(self):
506 def tags(self):
507 """Return a list of byte tag names"""
507 """Return a list of byte tag names"""
508 return self._repo.nodetags(self._node)
508 return self._repo.nodetags(self._node)
509 def bookmarks(self):
509 def bookmarks(self):
510 """Return a list of byte bookmark names."""
510 """Return a list of byte bookmark names."""
511 return self._repo.nodebookmarks(self._node)
511 return self._repo.nodebookmarks(self._node)
512 def phase(self):
512 def phase(self):
513 return self._repo._phasecache.phase(self._repo, self._rev)
513 return self._repo._phasecache.phase(self._repo, self._rev)
514 def hidden(self):
514 def hidden(self):
515 return self._rev in repoview.filterrevs(self._repo, 'visible')
515 return self._rev in repoview.filterrevs(self._repo, 'visible')
516
516
517 def isinmemory(self):
517 def isinmemory(self):
518 return False
518 return False
519
519
520 def children(self):
520 def children(self):
521 """return list of changectx contexts for each child changeset.
521 """return list of changectx contexts for each child changeset.
522
522
523 This returns only the immediate child changesets. Use descendants() to
523 This returns only the immediate child changesets. Use descendants() to
524 recursively walk children.
524 recursively walk children.
525 """
525 """
526 c = self._repo.changelog.children(self._node)
526 c = self._repo.changelog.children(self._node)
527 return [changectx(self._repo, x) for x in c]
527 return [changectx(self._repo, x) for x in c]
528
528
529 def ancestors(self):
529 def ancestors(self):
530 for a in self._repo.changelog.ancestors([self._rev]):
530 for a in self._repo.changelog.ancestors([self._rev]):
531 yield changectx(self._repo, a)
531 yield changectx(self._repo, a)
532
532
533 def descendants(self):
533 def descendants(self):
534 """Recursively yield all children of the changeset.
534 """Recursively yield all children of the changeset.
535
535
536 For just the immediate children, use children()
536 For just the immediate children, use children()
537 """
537 """
538 for d in self._repo.changelog.descendants([self._rev]):
538 for d in self._repo.changelog.descendants([self._rev]):
539 yield changectx(self._repo, d)
539 yield changectx(self._repo, d)
540
540
541 def filectx(self, path, fileid=None, filelog=None):
541 def filectx(self, path, fileid=None, filelog=None):
542 """get a file context from this changeset"""
542 """get a file context from this changeset"""
543 if fileid is None:
543 if fileid is None:
544 fileid = self.filenode(path)
544 fileid = self.filenode(path)
545 return filectx(self._repo, path, fileid=fileid,
545 return filectx(self._repo, path, fileid=fileid,
546 changectx=self, filelog=filelog)
546 changectx=self, filelog=filelog)
547
547
548 def ancestor(self, c2, warn=False):
548 def ancestor(self, c2, warn=False):
549 """return the "best" ancestor context of self and c2
549 """return the "best" ancestor context of self and c2
550
550
551 If there are multiple candidates, it will show a message and check
551 If there are multiple candidates, it will show a message and check
552 merge.preferancestor configuration before falling back to the
552 merge.preferancestor configuration before falling back to the
553 revlog ancestor."""
553 revlog ancestor."""
554 # deal with workingctxs
554 # deal with workingctxs
555 n2 = c2._node
555 n2 = c2._node
556 if n2 is None:
556 if n2 is None:
557 n2 = c2._parents[0]._node
557 n2 = c2._parents[0]._node
558 cahs = self._repo.changelog.commonancestorsheads(self._node, n2)
558 cahs = self._repo.changelog.commonancestorsheads(self._node, n2)
559 if not cahs:
559 if not cahs:
560 anc = nullid
560 anc = nullid
561 elif len(cahs) == 1:
561 elif len(cahs) == 1:
562 anc = cahs[0]
562 anc = cahs[0]
563 else:
563 else:
564 # experimental config: merge.preferancestor
564 # experimental config: merge.preferancestor
565 for r in self._repo.ui.configlist('merge', 'preferancestor'):
565 for r in self._repo.ui.configlist('merge', 'preferancestor'):
566 try:
566 try:
567 ctx = scmutil.revsymbol(self._repo, r)
567 ctx = scmutil.revsymbol(self._repo, r)
568 except error.RepoLookupError:
568 except error.RepoLookupError:
569 continue
569 continue
570 anc = ctx.node()
570 anc = ctx.node()
571 if anc in cahs:
571 if anc in cahs:
572 break
572 break
573 else:
573 else:
574 anc = self._repo.changelog.ancestor(self._node, n2)
574 anc = self._repo.changelog.ancestor(self._node, n2)
575 if warn:
575 if warn:
576 self._repo.ui.status(
576 self._repo.ui.status(
577 (_("note: using %s as ancestor of %s and %s\n") %
577 (_("note: using %s as ancestor of %s and %s\n") %
578 (short(anc), short(self._node), short(n2))) +
578 (short(anc), short(self._node), short(n2))) +
579 ''.join(_(" alternatively, use --config "
579 ''.join(_(" alternatively, use --config "
580 "merge.preferancestor=%s\n") %
580 "merge.preferancestor=%s\n") %
581 short(n) for n in sorted(cahs) if n != anc))
581 short(n) for n in sorted(cahs) if n != anc))
582 return changectx(self._repo, anc)
582 return changectx(self._repo, anc)
583
583
584 def descendant(self, other):
584 def descendant(self, other):
585 """True if other is descendant of this changeset"""
585 """True if other is descendant of this changeset"""
586 return self._repo.changelog.descendant(self._rev, other._rev)
586 return self._repo.changelog.descendant(self._rev, other._rev)
587
587
588 def walk(self, match):
588 def walk(self, match):
589 '''Generates matching file names.'''
589 '''Generates matching file names.'''
590
590
591 # Wrap match.bad method to have message with nodeid
591 # Wrap match.bad method to have message with nodeid
592 def bad(fn, msg):
592 def bad(fn, msg):
593 # The manifest doesn't know about subrepos, so don't complain about
593 # The manifest doesn't know about subrepos, so don't complain about
594 # paths into valid subrepos.
594 # paths into valid subrepos.
595 if any(fn == s or fn.startswith(s + '/')
595 if any(fn == s or fn.startswith(s + '/')
596 for s in self.substate):
596 for s in self.substate):
597 return
597 return
598 match.bad(fn, _('no such file in rev %s') % self)
598 match.bad(fn, _('no such file in rev %s') % self)
599
599
600 m = matchmod.badmatch(match, bad)
600 m = matchmod.badmatch(match, bad)
601 return self._manifest.walk(m)
601 return self._manifest.walk(m)
602
602
603 def matches(self, match):
603 def matches(self, match):
604 return self.walk(match)
604 return self.walk(match)
605
605
606 class basefilectx(object):
606 class basefilectx(object):
607 """A filecontext object represents the common logic for its children:
607 """A filecontext object represents the common logic for its children:
608 filectx: read-only access to a filerevision that is already present
608 filectx: read-only access to a filerevision that is already present
609 in the repo,
609 in the repo,
610 workingfilectx: a filecontext that represents files from the working
610 workingfilectx: a filecontext that represents files from the working
611 directory,
611 directory,
612 memfilectx: a filecontext that represents files in-memory,
612 memfilectx: a filecontext that represents files in-memory,
613 overlayfilectx: duplicate another filecontext with some fields overridden.
613 overlayfilectx: duplicate another filecontext with some fields overridden.
614 """
614 """
615 @propertycache
615 @propertycache
616 def _filelog(self):
616 def _filelog(self):
617 return self._repo.file(self._path)
617 return self._repo.file(self._path)
618
618
619 @propertycache
619 @propertycache
620 def _changeid(self):
620 def _changeid(self):
621 if r'_changeid' in self.__dict__:
621 if r'_changeid' in self.__dict__:
622 return self._changeid
622 return self._changeid
623 elif r'_changectx' in self.__dict__:
623 elif r'_changectx' in self.__dict__:
624 return self._changectx.rev()
624 return self._changectx.rev()
625 elif r'_descendantrev' in self.__dict__:
625 elif r'_descendantrev' in self.__dict__:
626 # this file context was created from a revision with a known
626 # this file context was created from a revision with a known
627 # descendant, we can (lazily) correct for linkrev aliases
627 # descendant, we can (lazily) correct for linkrev aliases
628 return self._adjustlinkrev(self._descendantrev)
628 return self._adjustlinkrev(self._descendantrev)
629 else:
629 else:
630 return self._filelog.linkrev(self._filerev)
630 return self._filelog.linkrev(self._filerev)
631
631
632 @propertycache
632 @propertycache
633 def _filenode(self):
633 def _filenode(self):
634 if r'_fileid' in self.__dict__:
634 if r'_fileid' in self.__dict__:
635 return self._filelog.lookup(self._fileid)
635 return self._filelog.lookup(self._fileid)
636 else:
636 else:
637 return self._changectx.filenode(self._path)
637 return self._changectx.filenode(self._path)
638
638
639 @propertycache
639 @propertycache
640 def _filerev(self):
640 def _filerev(self):
641 return self._filelog.rev(self._filenode)
641 return self._filelog.rev(self._filenode)
642
642
643 @propertycache
643 @propertycache
644 def _repopath(self):
644 def _repopath(self):
645 return self._path
645 return self._path
646
646
647 def __nonzero__(self):
647 def __nonzero__(self):
648 try:
648 try:
649 self._filenode
649 self._filenode
650 return True
650 return True
651 except error.LookupError:
651 except error.LookupError:
652 # file is missing
652 # file is missing
653 return False
653 return False
654
654
655 __bool__ = __nonzero__
655 __bool__ = __nonzero__
656
656
657 def __bytes__(self):
657 def __bytes__(self):
658 try:
658 try:
659 return "%s@%s" % (self.path(), self._changectx)
659 return "%s@%s" % (self.path(), self._changectx)
660 except error.LookupError:
660 except error.LookupError:
661 return "%s@???" % self.path()
661 return "%s@???" % self.path()
662
662
663 __str__ = encoding.strmethod(__bytes__)
663 __str__ = encoding.strmethod(__bytes__)
664
664
665 def __repr__(self):
665 def __repr__(self):
666 return r"<%s %s>" % (type(self).__name__, str(self))
666 return r"<%s %s>" % (type(self).__name__, str(self))
667
667
668 def __hash__(self):
668 def __hash__(self):
669 try:
669 try:
670 return hash((self._path, self._filenode))
670 return hash((self._path, self._filenode))
671 except AttributeError:
671 except AttributeError:
672 return id(self)
672 return id(self)
673
673
674 def __eq__(self, other):
674 def __eq__(self, other):
675 try:
675 try:
676 return (type(self) == type(other) and self._path == other._path
676 return (type(self) == type(other) and self._path == other._path
677 and self._filenode == other._filenode)
677 and self._filenode == other._filenode)
678 except AttributeError:
678 except AttributeError:
679 return False
679 return False
680
680
681 def __ne__(self, other):
681 def __ne__(self, other):
682 return not (self == other)
682 return not (self == other)
683
683
684 def filerev(self):
684 def filerev(self):
685 return self._filerev
685 return self._filerev
686 def filenode(self):
686 def filenode(self):
687 return self._filenode
687 return self._filenode
688 @propertycache
688 @propertycache
689 def _flags(self):
689 def _flags(self):
690 return self._changectx.flags(self._path)
690 return self._changectx.flags(self._path)
691 def flags(self):
691 def flags(self):
692 return self._flags
692 return self._flags
693 def filelog(self):
693 def filelog(self):
694 return self._filelog
694 return self._filelog
695 def rev(self):
695 def rev(self):
696 return self._changeid
696 return self._changeid
697 def linkrev(self):
697 def linkrev(self):
698 return self._filelog.linkrev(self._filerev)
698 return self._filelog.linkrev(self._filerev)
699 def node(self):
699 def node(self):
700 return self._changectx.node()
700 return self._changectx.node()
701 def hex(self):
701 def hex(self):
702 return self._changectx.hex()
702 return self._changectx.hex()
703 def user(self):
703 def user(self):
704 return self._changectx.user()
704 return self._changectx.user()
705 def date(self):
705 def date(self):
706 return self._changectx.date()
706 return self._changectx.date()
707 def files(self):
707 def files(self):
708 return self._changectx.files()
708 return self._changectx.files()
709 def description(self):
709 def description(self):
710 return self._changectx.description()
710 return self._changectx.description()
711 def branch(self):
711 def branch(self):
712 return self._changectx.branch()
712 return self._changectx.branch()
713 def extra(self):
713 def extra(self):
714 return self._changectx.extra()
714 return self._changectx.extra()
715 def phase(self):
715 def phase(self):
716 return self._changectx.phase()
716 return self._changectx.phase()
717 def phasestr(self):
717 def phasestr(self):
718 return self._changectx.phasestr()
718 return self._changectx.phasestr()
719 def obsolete(self):
719 def obsolete(self):
720 return self._changectx.obsolete()
720 return self._changectx.obsolete()
721 def instabilities(self):
721 def instabilities(self):
722 return self._changectx.instabilities()
722 return self._changectx.instabilities()
723 def manifest(self):
723 def manifest(self):
724 return self._changectx.manifest()
724 return self._changectx.manifest()
725 def changectx(self):
725 def changectx(self):
726 return self._changectx
726 return self._changectx
727 def renamed(self):
727 def renamed(self):
728 return self._copied
728 return self._copied
729 def repo(self):
729 def repo(self):
730 return self._repo
730 return self._repo
731 def size(self):
731 def size(self):
732 return len(self.data())
732 return len(self.data())
733
733
734 def path(self):
734 def path(self):
735 return self._path
735 return self._path
736
736
737 def isbinary(self):
737 def isbinary(self):
738 try:
738 try:
739 return stringutil.binary(self.data())
739 return stringutil.binary(self.data())
740 except IOError:
740 except IOError:
741 return False
741 return False
742 def isexec(self):
742 def isexec(self):
743 return 'x' in self.flags()
743 return 'x' in self.flags()
744 def islink(self):
744 def islink(self):
745 return 'l' in self.flags()
745 return 'l' in self.flags()
746
746
747 def isabsent(self):
747 def isabsent(self):
748 """whether this filectx represents a file not in self._changectx
748 """whether this filectx represents a file not in self._changectx
749
749
750 This is mainly for merge code to detect change/delete conflicts. This is
750 This is mainly for merge code to detect change/delete conflicts. This is
751 expected to be True for all subclasses of basectx."""
751 expected to be True for all subclasses of basectx."""
752 return False
752 return False
753
753
754 _customcmp = False
754 _customcmp = False
755 def cmp(self, fctx):
755 def cmp(self, fctx):
756 """compare with other file context
756 """compare with other file context
757
757
758 returns True if different than fctx.
758 returns True if different than fctx.
759 """
759 """
760 if fctx._customcmp:
760 if fctx._customcmp:
761 return fctx.cmp(self)
761 return fctx.cmp(self)
762
762
763 if (fctx._filenode is None
763 if (fctx._filenode is None
764 and (self._repo._encodefilterpats
764 and (self._repo._encodefilterpats
765 # if file data starts with '\1\n', empty metadata block is
765 # if file data starts with '\1\n', empty metadata block is
766 # prepended, which adds 4 bytes to filelog.size().
766 # prepended, which adds 4 bytes to filelog.size().
767 or self.size() - 4 == fctx.size())
767 or self.size() - 4 == fctx.size())
768 or self.size() == fctx.size()):
768 or self.size() == fctx.size()):
769 return self._filelog.cmp(self._filenode, fctx.data())
769 return self._filelog.cmp(self._filenode, fctx.data())
770
770
771 return True
771 return True
772
772
773 def _adjustlinkrev(self, srcrev, inclusive=False):
773 def _adjustlinkrev(self, srcrev, inclusive=False):
774 """return the first ancestor of <srcrev> introducing <fnode>
774 """return the first ancestor of <srcrev> introducing <fnode>
775
775
776 If the linkrev of the file revision does not point to an ancestor of
776 If the linkrev of the file revision does not point to an ancestor of
777 srcrev, we'll walk down the ancestors until we find one introducing
777 srcrev, we'll walk down the ancestors until we find one introducing
778 this file revision.
778 this file revision.
779
779
780 :srcrev: the changeset revision we search ancestors from
780 :srcrev: the changeset revision we search ancestors from
781 :inclusive: if true, the src revision will also be checked
781 :inclusive: if true, the src revision will also be checked
782 """
782 """
783 repo = self._repo
783 repo = self._repo
784 cl = repo.unfiltered().changelog
784 cl = repo.unfiltered().changelog
785 mfl = repo.manifestlog
785 mfl = repo.manifestlog
786 # fetch the linkrev
786 # fetch the linkrev
787 lkr = self.linkrev()
787 lkr = self.linkrev()
788 # hack to reuse ancestor computation when searching for renames
788 # hack to reuse ancestor computation when searching for renames
789 memberanc = getattr(self, '_ancestrycontext', None)
789 memberanc = getattr(self, '_ancestrycontext', None)
790 iteranc = None
790 iteranc = None
791 if srcrev is None:
791 if srcrev is None:
792 # wctx case, used by workingfilectx during mergecopy
792 # wctx case, used by workingfilectx during mergecopy
793 revs = [p.rev() for p in self._repo[None].parents()]
793 revs = [p.rev() for p in self._repo[None].parents()]
794 inclusive = True # we skipped the real (revless) source
794 inclusive = True # we skipped the real (revless) source
795 else:
795 else:
796 revs = [srcrev]
796 revs = [srcrev]
797 if memberanc is None:
797 if memberanc is None:
798 memberanc = iteranc = cl.ancestors(revs, lkr,
798 memberanc = iteranc = cl.ancestors(revs, lkr,
799 inclusive=inclusive)
799 inclusive=inclusive)
800 # check if this linkrev is an ancestor of srcrev
800 # check if this linkrev is an ancestor of srcrev
801 if lkr not in memberanc:
801 if lkr not in memberanc:
802 if iteranc is None:
802 if iteranc is None:
803 iteranc = cl.ancestors(revs, lkr, inclusive=inclusive)
803 iteranc = cl.ancestors(revs, lkr, inclusive=inclusive)
804 fnode = self._filenode
804 fnode = self._filenode
805 path = self._path
805 path = self._path
806 for a in iteranc:
806 for a in iteranc:
807 ac = cl.read(a) # get changeset data (we avoid object creation)
807 ac = cl.read(a) # get changeset data (we avoid object creation)
808 if path in ac[3]: # checking the 'files' field.
808 if path in ac[3]: # checking the 'files' field.
809 # The file has been touched, check if the content is
809 # The file has been touched, check if the content is
810 # similar to the one we search for.
810 # similar to the one we search for.
811 if fnode == mfl[ac[0]].readfast().get(path):
811 if fnode == mfl[ac[0]].readfast().get(path):
812 return a
812 return a
813 # In theory, we should never get out of that loop without a result.
813 # In theory, we should never get out of that loop without a result.
814 # But if manifest uses a buggy file revision (not children of the
814 # But if manifest uses a buggy file revision (not children of the
815 # one it replaces) we could. Such a buggy situation will likely
815 # one it replaces) we could. Such a buggy situation will likely
816 # result is crash somewhere else at to some point.
816 # result is crash somewhere else at to some point.
817 return lkr
817 return lkr
818
818
819 def introrev(self):
819 def introrev(self):
820 """return the rev of the changeset which introduced this file revision
820 """return the rev of the changeset which introduced this file revision
821
821
822 This method is different from linkrev because it take into account the
822 This method is different from linkrev because it take into account the
823 changeset the filectx was created from. It ensures the returned
823 changeset the filectx was created from. It ensures the returned
824 revision is one of its ancestors. This prevents bugs from
824 revision is one of its ancestors. This prevents bugs from
825 'linkrev-shadowing' when a file revision is used by multiple
825 'linkrev-shadowing' when a file revision is used by multiple
826 changesets.
826 changesets.
827 """
827 """
828 lkr = self.linkrev()
828 lkr = self.linkrev()
829 attrs = vars(self)
829 attrs = vars(self)
830 noctx = not (r'_changeid' in attrs or r'_changectx' in attrs)
830 noctx = not (r'_changeid' in attrs or r'_changectx' in attrs)
831 if noctx or self.rev() == lkr:
831 if noctx or self.rev() == lkr:
832 return self.linkrev()
832 return self.linkrev()
833 return self._adjustlinkrev(self.rev(), inclusive=True)
833 return self._adjustlinkrev(self.rev(), inclusive=True)
834
834
835 def introfilectx(self):
835 def introfilectx(self):
836 """Return filectx having identical contents, but pointing to the
836 """Return filectx having identical contents, but pointing to the
837 changeset revision where this filectx was introduced"""
837 changeset revision where this filectx was introduced"""
838 introrev = self.introrev()
838 introrev = self.introrev()
839 if self.rev() == introrev:
839 if self.rev() == introrev:
840 return self
840 return self
841 return self.filectx(self.filenode(), changeid=introrev)
841 return self.filectx(self.filenode(), changeid=introrev)
842
842
843 def _parentfilectx(self, path, fileid, filelog):
843 def _parentfilectx(self, path, fileid, filelog):
844 """create parent filectx keeping ancestry info for _adjustlinkrev()"""
844 """create parent filectx keeping ancestry info for _adjustlinkrev()"""
845 fctx = filectx(self._repo, path, fileid=fileid, filelog=filelog)
845 fctx = filectx(self._repo, path, fileid=fileid, filelog=filelog)
846 if r'_changeid' in vars(self) or r'_changectx' in vars(self):
846 if r'_changeid' in vars(self) or r'_changectx' in vars(self):
847 # If self is associated with a changeset (probably explicitly
847 # If self is associated with a changeset (probably explicitly
848 # fed), ensure the created filectx is associated with a
848 # fed), ensure the created filectx is associated with a
849 # changeset that is an ancestor of self.changectx.
849 # changeset that is an ancestor of self.changectx.
850 # This lets us later use _adjustlinkrev to get a correct link.
850 # This lets us later use _adjustlinkrev to get a correct link.
851 fctx._descendantrev = self.rev()
851 fctx._descendantrev = self.rev()
852 fctx._ancestrycontext = getattr(self, '_ancestrycontext', None)
852 fctx._ancestrycontext = getattr(self, '_ancestrycontext', None)
853 elif r'_descendantrev' in vars(self):
853 elif r'_descendantrev' in vars(self):
854 # Otherwise propagate _descendantrev if we have one associated.
854 # Otherwise propagate _descendantrev if we have one associated.
855 fctx._descendantrev = self._descendantrev
855 fctx._descendantrev = self._descendantrev
856 fctx._ancestrycontext = getattr(self, '_ancestrycontext', None)
856 fctx._ancestrycontext = getattr(self, '_ancestrycontext', None)
857 return fctx
857 return fctx
858
858
859 def parents(self):
859 def parents(self):
860 _path = self._path
860 _path = self._path
861 fl = self._filelog
861 fl = self._filelog
862 parents = self._filelog.parents(self._filenode)
862 parents = self._filelog.parents(self._filenode)
863 pl = [(_path, node, fl) for node in parents if node != nullid]
863 pl = [(_path, node, fl) for node in parents if node != nullid]
864
864
865 r = fl.renamed(self._filenode)
865 r = fl.renamed(self._filenode)
866 if r:
866 if r:
867 # - In the simple rename case, both parent are nullid, pl is empty.
867 # - In the simple rename case, both parent are nullid, pl is empty.
868 # - In case of merge, only one of the parent is null id and should
868 # - In case of merge, only one of the parent is null id and should
869 # be replaced with the rename information. This parent is -always-
869 # be replaced with the rename information. This parent is -always-
870 # the first one.
870 # the first one.
871 #
871 #
872 # As null id have always been filtered out in the previous list
872 # As null id have always been filtered out in the previous list
873 # comprehension, inserting to 0 will always result in "replacing
873 # comprehension, inserting to 0 will always result in "replacing
874 # first nullid parent with rename information.
874 # first nullid parent with rename information.
875 pl.insert(0, (r[0], r[1], self._repo.file(r[0])))
875 pl.insert(0, (r[0], r[1], self._repo.file(r[0])))
876
876
877 return [self._parentfilectx(path, fnode, l) for path, fnode, l in pl]
877 return [self._parentfilectx(path, fnode, l) for path, fnode, l in pl]
878
878
879 def p1(self):
879 def p1(self):
880 return self.parents()[0]
880 return self.parents()[0]
881
881
882 def p2(self):
882 def p2(self):
883 p = self.parents()
883 p = self.parents()
884 if len(p) == 2:
884 if len(p) == 2:
885 return p[1]
885 return p[1]
886 return filectx(self._repo, self._path, fileid=-1, filelog=self._filelog)
886 return filectx(self._repo, self._path, fileid=-1, filelog=self._filelog)
887
887
888 def annotate(self, follow=False, skiprevs=None, diffopts=None):
888 def annotate(self, follow=False, skiprevs=None, diffopts=None):
889 """Returns a list of annotateline objects for each line in the file
889 """Returns a list of annotateline objects for each line in the file
890
890
891 - line.fctx is the filectx of the node where that line was last changed
891 - line.fctx is the filectx of the node where that line was last changed
892 - line.lineno is the line number at the first appearance in the managed
892 - line.lineno is the line number at the first appearance in the managed
893 file
893 file
894 - line.text is the data on that line (including newline character)
894 - line.text is the data on that line (including newline character)
895 """
895 """
896 getlog = util.lrucachefunc(lambda x: self._repo.file(x))
896 getlog = util.lrucachefunc(lambda x: self._repo.file(x))
897
897
898 def parents(f):
898 def parents(f):
899 # Cut _descendantrev here to mitigate the penalty of lazy linkrev
899 # Cut _descendantrev here to mitigate the penalty of lazy linkrev
900 # adjustment. Otherwise, p._adjustlinkrev() would walk changelog
900 # adjustment. Otherwise, p._adjustlinkrev() would walk changelog
901 # from the topmost introrev (= srcrev) down to p.linkrev() if it
901 # from the topmost introrev (= srcrev) down to p.linkrev() if it
902 # isn't an ancestor of the srcrev.
902 # isn't an ancestor of the srcrev.
903 f._changeid
903 f._changeid
904 pl = f.parents()
904 pl = f.parents()
905
905
906 # Don't return renamed parents if we aren't following.
906 # Don't return renamed parents if we aren't following.
907 if not follow:
907 if not follow:
908 pl = [p for p in pl if p.path() == f.path()]
908 pl = [p for p in pl if p.path() == f.path()]
909
909
910 # renamed filectx won't have a filelog yet, so set it
910 # renamed filectx won't have a filelog yet, so set it
911 # from the cache to save time
911 # from the cache to save time
912 for p in pl:
912 for p in pl:
913 if not r'_filelog' in p.__dict__:
913 if not r'_filelog' in p.__dict__:
914 p._filelog = getlog(p.path())
914 p._filelog = getlog(p.path())
915
915
916 return pl
916 return pl
917
917
918 # use linkrev to find the first changeset where self appeared
918 # use linkrev to find the first changeset where self appeared
919 base = self.introfilectx()
919 base = self.introfilectx()
920 if getattr(base, '_ancestrycontext', None) is None:
920 if getattr(base, '_ancestrycontext', None) is None:
921 cl = self._repo.changelog
921 cl = self._repo.changelog
922 if base.rev() is None:
922 if base.rev() is None:
923 # wctx is not inclusive, but works because _ancestrycontext
923 # wctx is not inclusive, but works because _ancestrycontext
924 # is used to test filelog revisions
924 # is used to test filelog revisions
925 ac = cl.ancestors([p.rev() for p in base.parents()],
925 ac = cl.ancestors([p.rev() for p in base.parents()],
926 inclusive=True)
926 inclusive=True)
927 else:
927 else:
928 ac = cl.ancestors([base.rev()], inclusive=True)
928 ac = cl.ancestors([base.rev()], inclusive=True)
929 base._ancestrycontext = ac
929 base._ancestrycontext = ac
930
930
931 return dagop.annotate(base, parents, skiprevs=skiprevs,
931 return dagop.annotate(base, parents, skiprevs=skiprevs,
932 diffopts=diffopts)
932 diffopts=diffopts)
933
933
934 def ancestors(self, followfirst=False):
934 def ancestors(self, followfirst=False):
935 visit = {}
935 visit = {}
936 c = self
936 c = self
937 if followfirst:
937 if followfirst:
938 cut = 1
938 cut = 1
939 else:
939 else:
940 cut = None
940 cut = None
941
941
942 while True:
942 while True:
943 for parent in c.parents()[:cut]:
943 for parent in c.parents()[:cut]:
944 visit[(parent.linkrev(), parent.filenode())] = parent
944 visit[(parent.linkrev(), parent.filenode())] = parent
945 if not visit:
945 if not visit:
946 break
946 break
947 c = visit.pop(max(visit))
947 c = visit.pop(max(visit))
948 yield c
948 yield c
949
949
950 def decodeddata(self):
950 def decodeddata(self):
951 """Returns `data()` after running repository decoding filters.
951 """Returns `data()` after running repository decoding filters.
952
952
953 This is often equivalent to how the data would be expressed on disk.
953 This is often equivalent to how the data would be expressed on disk.
954 """
954 """
955 return self._repo.wwritedata(self.path(), self.data())
955 return self._repo.wwritedata(self.path(), self.data())
956
956
957 class filectx(basefilectx):
957 class filectx(basefilectx):
958 """A filecontext object makes access to data related to a particular
958 """A filecontext object makes access to data related to a particular
959 filerevision convenient."""
959 filerevision convenient."""
960 def __init__(self, repo, path, changeid=None, fileid=None,
960 def __init__(self, repo, path, changeid=None, fileid=None,
961 filelog=None, changectx=None):
961 filelog=None, changectx=None):
962 """changeid can be a changeset revision, node, or tag.
962 """changeid can be a changeset revision, node, or tag.
963 fileid can be a file revision or node."""
963 fileid can be a file revision or node."""
964 self._repo = repo
964 self._repo = repo
965 self._path = path
965 self._path = path
966
966
967 assert (changeid is not None
967 assert (changeid is not None
968 or fileid is not None
968 or fileid is not None
969 or changectx is not None), \
969 or changectx is not None), \
970 ("bad args: changeid=%r, fileid=%r, changectx=%r"
970 ("bad args: changeid=%r, fileid=%r, changectx=%r"
971 % (changeid, fileid, changectx))
971 % (changeid, fileid, changectx))
972
972
973 if filelog is not None:
973 if filelog is not None:
974 self._filelog = filelog
974 self._filelog = filelog
975
975
976 if changeid is not None:
976 if changeid is not None:
977 self._changeid = changeid
977 self._changeid = changeid
978 if changectx is not None:
978 if changectx is not None:
979 self._changectx = changectx
979 self._changectx = changectx
980 if fileid is not None:
980 if fileid is not None:
981 self._fileid = fileid
981 self._fileid = fileid
982
982
983 @propertycache
983 @propertycache
984 def _changectx(self):
984 def _changectx(self):
985 try:
985 try:
986 return changectx(self._repo, self._changeid)
986 return changectx(self._repo, self._changeid)
987 except error.FilteredRepoLookupError:
987 except error.FilteredRepoLookupError:
988 # Linkrev may point to any revision in the repository. When the
988 # Linkrev may point to any revision in the repository. When the
989 # repository is filtered this may lead to `filectx` trying to build
989 # repository is filtered this may lead to `filectx` trying to build
990 # `changectx` for filtered revision. In such case we fallback to
990 # `changectx` for filtered revision. In such case we fallback to
991 # creating `changectx` on the unfiltered version of the reposition.
991 # creating `changectx` on the unfiltered version of the reposition.
992 # This fallback should not be an issue because `changectx` from
992 # This fallback should not be an issue because `changectx` from
993 # `filectx` are not used in complex operations that care about
993 # `filectx` are not used in complex operations that care about
994 # filtering.
994 # filtering.
995 #
995 #
996 # This fallback is a cheap and dirty fix that prevent several
996 # This fallback is a cheap and dirty fix that prevent several
997 # crashes. It does not ensure the behavior is correct. However the
997 # crashes. It does not ensure the behavior is correct. However the
998 # behavior was not correct before filtering either and "incorrect
998 # behavior was not correct before filtering either and "incorrect
999 # behavior" is seen as better as "crash"
999 # behavior" is seen as better as "crash"
1000 #
1000 #
1001 # Linkrevs have several serious troubles with filtering that are
1001 # Linkrevs have several serious troubles with filtering that are
1002 # complicated to solve. Proper handling of the issue here should be
1002 # complicated to solve. Proper handling of the issue here should be
1003 # considered when solving linkrev issue are on the table.
1003 # considered when solving linkrev issue are on the table.
1004 return changectx(self._repo.unfiltered(), self._changeid)
1004 return changectx(self._repo.unfiltered(), self._changeid)
1005
1005
1006 def filectx(self, fileid, changeid=None):
1006 def filectx(self, fileid, changeid=None):
1007 '''opens an arbitrary revision of the file without
1007 '''opens an arbitrary revision of the file without
1008 opening a new filelog'''
1008 opening a new filelog'''
1009 return filectx(self._repo, self._path, fileid=fileid,
1009 return filectx(self._repo, self._path, fileid=fileid,
1010 filelog=self._filelog, changeid=changeid)
1010 filelog=self._filelog, changeid=changeid)
1011
1011
1012 def rawdata(self):
1012 def rawdata(self):
1013 return self._filelog.revision(self._filenode, raw=True)
1013 return self._filelog.revision(self._filenode, raw=True)
1014
1014
1015 def rawflags(self):
1015 def rawflags(self):
1016 """low-level revlog flags"""
1016 """low-level revlog flags"""
1017 return self._filelog.flags(self._filerev)
1017 return self._filelog.flags(self._filerev)
1018
1018
1019 def data(self):
1019 def data(self):
1020 try:
1020 try:
1021 return self._filelog.read(self._filenode)
1021 return self._filelog.read(self._filenode)
1022 except error.CensoredNodeError:
1022 except error.CensoredNodeError:
1023 if self._repo.ui.config("censor", "policy") == "ignore":
1023 if self._repo.ui.config("censor", "policy") == "ignore":
1024 return ""
1024 return ""
1025 raise error.Abort(_("censored node: %s") % short(self._filenode),
1025 raise error.Abort(_("censored node: %s") % short(self._filenode),
1026 hint=_("set censor.policy to ignore errors"))
1026 hint=_("set censor.policy to ignore errors"))
1027
1027
1028 def size(self):
1028 def size(self):
1029 return self._filelog.size(self._filerev)
1029 return self._filelog.size(self._filerev)
1030
1030
1031 @propertycache
1031 @propertycache
1032 def _copied(self):
1032 def _copied(self):
1033 """check if file was actually renamed in this changeset revision
1033 """check if file was actually renamed in this changeset revision
1034
1034
1035 If rename logged in file revision, we report copy for changeset only
1035 If rename logged in file revision, we report copy for changeset only
1036 if file revisions linkrev points back to the changeset in question
1036 if file revisions linkrev points back to the changeset in question
1037 or both changeset parents contain different file revisions.
1037 or both changeset parents contain different file revisions.
1038 """
1038 """
1039
1039
1040 renamed = self._filelog.renamed(self._filenode)
1040 renamed = self._filelog.renamed(self._filenode)
1041 if not renamed:
1041 if not renamed:
1042 return renamed
1042 return renamed
1043
1043
1044 if self.rev() == self.linkrev():
1044 if self.rev() == self.linkrev():
1045 return renamed
1045 return renamed
1046
1046
1047 name = self.path()
1047 name = self.path()
1048 fnode = self._filenode
1048 fnode = self._filenode
1049 for p in self._changectx.parents():
1049 for p in self._changectx.parents():
1050 try:
1050 try:
1051 if fnode == p.filenode(name):
1051 if fnode == p.filenode(name):
1052 return None
1052 return None
1053 except error.LookupError:
1053 except error.LookupError:
1054 pass
1054 pass
1055 return renamed
1055 return renamed
1056
1056
1057 def children(self):
1057 def children(self):
1058 # hard for renames
1058 # hard for renames
1059 c = self._filelog.children(self._filenode)
1059 c = self._filelog.children(self._filenode)
1060 return [filectx(self._repo, self._path, fileid=x,
1060 return [filectx(self._repo, self._path, fileid=x,
1061 filelog=self._filelog) for x in c]
1061 filelog=self._filelog) for x in c]
1062
1062
1063 class committablectx(basectx):
1063 class committablectx(basectx):
1064 """A committablectx object provides common functionality for a context that
1064 """A committablectx object provides common functionality for a context that
1065 wants the ability to commit, e.g. workingctx or memctx."""
1065 wants the ability to commit, e.g. workingctx or memctx."""
1066 def __init__(self, repo, text="", user=None, date=None, extra=None,
1066 def __init__(self, repo, text="", user=None, date=None, extra=None,
1067 changes=None):
1067 changes=None):
1068 super(committablectx, self).__init__(repo)
1068 super(committablectx, self).__init__(repo)
1069 self._rev = None
1069 self._rev = None
1070 self._node = None
1070 self._node = None
1071 self._text = text
1071 self._text = text
1072 if date:
1072 if date:
1073 self._date = dateutil.parsedate(date)
1073 self._date = dateutil.parsedate(date)
1074 if user:
1074 if user:
1075 self._user = user
1075 self._user = user
1076 if changes:
1076 if changes:
1077 self._status = changes
1077 self._status = changes
1078
1078
1079 self._extra = {}
1079 self._extra = {}
1080 if extra:
1080 if extra:
1081 self._extra = extra.copy()
1081 self._extra = extra.copy()
1082 if 'branch' not in self._extra:
1082 if 'branch' not in self._extra:
1083 try:
1083 try:
1084 branch = encoding.fromlocal(self._repo.dirstate.branch())
1084 branch = encoding.fromlocal(self._repo.dirstate.branch())
1085 except UnicodeDecodeError:
1085 except UnicodeDecodeError:
1086 raise error.Abort(_('branch name not in UTF-8!'))
1086 raise error.Abort(_('branch name not in UTF-8!'))
1087 self._extra['branch'] = branch
1087 self._extra['branch'] = branch
1088 if self._extra['branch'] == '':
1088 if self._extra['branch'] == '':
1089 self._extra['branch'] = 'default'
1089 self._extra['branch'] = 'default'
1090
1090
1091 def __bytes__(self):
1091 def __bytes__(self):
1092 return bytes(self._parents[0]) + "+"
1092 return bytes(self._parents[0]) + "+"
1093
1093
1094 __str__ = encoding.strmethod(__bytes__)
1094 __str__ = encoding.strmethod(__bytes__)
1095
1095
1096 def __nonzero__(self):
1096 def __nonzero__(self):
1097 return True
1097 return True
1098
1098
1099 __bool__ = __nonzero__
1099 __bool__ = __nonzero__
1100
1100
1101 def _buildflagfunc(self):
1101 def _buildflagfunc(self):
1102 # Create a fallback function for getting file flags when the
1102 # Create a fallback function for getting file flags when the
1103 # filesystem doesn't support them
1103 # filesystem doesn't support them
1104
1104
1105 copiesget = self._repo.dirstate.copies().get
1105 copiesget = self._repo.dirstate.copies().get
1106 parents = self.parents()
1106 parents = self.parents()
1107 if len(parents) < 2:
1107 if len(parents) < 2:
1108 # when we have one parent, it's easy: copy from parent
1108 # when we have one parent, it's easy: copy from parent
1109 man = parents[0].manifest()
1109 man = parents[0].manifest()
1110 def func(f):
1110 def func(f):
1111 f = copiesget(f, f)
1111 f = copiesget(f, f)
1112 return man.flags(f)
1112 return man.flags(f)
1113 else:
1113 else:
1114 # merges are tricky: we try to reconstruct the unstored
1114 # merges are tricky: we try to reconstruct the unstored
1115 # result from the merge (issue1802)
1115 # result from the merge (issue1802)
1116 p1, p2 = parents
1116 p1, p2 = parents
1117 pa = p1.ancestor(p2)
1117 pa = p1.ancestor(p2)
1118 m1, m2, ma = p1.manifest(), p2.manifest(), pa.manifest()
1118 m1, m2, ma = p1.manifest(), p2.manifest(), pa.manifest()
1119
1119
1120 def func(f):
1120 def func(f):
1121 f = copiesget(f, f) # may be wrong for merges with copies
1121 f = copiesget(f, f) # may be wrong for merges with copies
1122 fl1, fl2, fla = m1.flags(f), m2.flags(f), ma.flags(f)
1122 fl1, fl2, fla = m1.flags(f), m2.flags(f), ma.flags(f)
1123 if fl1 == fl2:
1123 if fl1 == fl2:
1124 return fl1
1124 return fl1
1125 if fl1 == fla:
1125 if fl1 == fla:
1126 return fl2
1126 return fl2
1127 if fl2 == fla:
1127 if fl2 == fla:
1128 return fl1
1128 return fl1
1129 return '' # punt for conflicts
1129 return '' # punt for conflicts
1130
1130
1131 return func
1131 return func
1132
1132
1133 @propertycache
1133 @propertycache
1134 def _flagfunc(self):
1134 def _flagfunc(self):
1135 return self._repo.dirstate.flagfunc(self._buildflagfunc)
1135 return self._repo.dirstate.flagfunc(self._buildflagfunc)
1136
1136
1137 @propertycache
1137 @propertycache
1138 def _status(self):
1138 def _status(self):
1139 return self._repo.status()
1139 return self._repo.status()
1140
1140
1141 @propertycache
1141 @propertycache
1142 def _user(self):
1142 def _user(self):
1143 return self._repo.ui.username()
1143 return self._repo.ui.username()
1144
1144
1145 @propertycache
1145 @propertycache
1146 def _date(self):
1146 def _date(self):
1147 ui = self._repo.ui
1147 ui = self._repo.ui
1148 date = ui.configdate('devel', 'default-date')
1148 date = ui.configdate('devel', 'default-date')
1149 if date is None:
1149 if date is None:
1150 date = dateutil.makedate()
1150 date = dateutil.makedate()
1151 return date
1151 return date
1152
1152
1153 def subrev(self, subpath):
1153 def subrev(self, subpath):
1154 return None
1154 return None
1155
1155
1156 def manifestnode(self):
1156 def manifestnode(self):
1157 return None
1157 return None
1158 def user(self):
1158 def user(self):
1159 return self._user or self._repo.ui.username()
1159 return self._user or self._repo.ui.username()
1160 def date(self):
1160 def date(self):
1161 return self._date
1161 return self._date
1162 def description(self):
1162 def description(self):
1163 return self._text
1163 return self._text
1164 def files(self):
1164 def files(self):
1165 return sorted(self._status.modified + self._status.added +
1165 return sorted(self._status.modified + self._status.added +
1166 self._status.removed)
1166 self._status.removed)
1167
1167
1168 def modified(self):
1168 def modified(self):
1169 return self._status.modified
1169 return self._status.modified
1170 def added(self):
1170 def added(self):
1171 return self._status.added
1171 return self._status.added
1172 def removed(self):
1172 def removed(self):
1173 return self._status.removed
1173 return self._status.removed
1174 def deleted(self):
1174 def deleted(self):
1175 return self._status.deleted
1175 return self._status.deleted
1176 def branch(self):
1176 def branch(self):
1177 return encoding.tolocal(self._extra['branch'])
1177 return encoding.tolocal(self._extra['branch'])
1178 def closesbranch(self):
1178 def closesbranch(self):
1179 return 'close' in self._extra
1179 return 'close' in self._extra
1180 def extra(self):
1180 def extra(self):
1181 return self._extra
1181 return self._extra
1182
1182
1183 def isinmemory(self):
1183 def isinmemory(self):
1184 return False
1184 return False
1185
1185
1186 def tags(self):
1186 def tags(self):
1187 return []
1187 return []
1188
1188
1189 def bookmarks(self):
1189 def bookmarks(self):
1190 b = []
1190 b = []
1191 for p in self.parents():
1191 for p in self.parents():
1192 b.extend(p.bookmarks())
1192 b.extend(p.bookmarks())
1193 return b
1193 return b
1194
1194
1195 def phase(self):
1195 def phase(self):
1196 phase = phases.draft # default phase to draft
1196 phase = phases.draft # default phase to draft
1197 for p in self.parents():
1197 for p in self.parents():
1198 phase = max(phase, p.phase())
1198 phase = max(phase, p.phase())
1199 return phase
1199 return phase
1200
1200
1201 def hidden(self):
1201 def hidden(self):
1202 return False
1202 return False
1203
1203
1204 def children(self):
1204 def children(self):
1205 return []
1205 return []
1206
1206
1207 def flags(self, path):
1207 def flags(self, path):
1208 if r'_manifest' in self.__dict__:
1208 if r'_manifest' in self.__dict__:
1209 try:
1209 try:
1210 return self._manifest.flags(path)
1210 return self._manifest.flags(path)
1211 except KeyError:
1211 except KeyError:
1212 return ''
1212 return ''
1213
1213
1214 try:
1214 try:
1215 return self._flagfunc(path)
1215 return self._flagfunc(path)
1216 except OSError:
1216 except OSError:
1217 return ''
1217 return ''
1218
1218
1219 def ancestor(self, c2):
1219 def ancestor(self, c2):
1220 """return the "best" ancestor context of self and c2"""
1220 """return the "best" ancestor context of self and c2"""
1221 return self._parents[0].ancestor(c2) # punt on two parents for now
1221 return self._parents[0].ancestor(c2) # punt on two parents for now
1222
1222
1223 def walk(self, match):
1223 def walk(self, match):
1224 '''Generates matching file names.'''
1224 '''Generates matching file names.'''
1225 return sorted(self._repo.dirstate.walk(match,
1225 return sorted(self._repo.dirstate.walk(match,
1226 subrepos=sorted(self.substate),
1226 subrepos=sorted(self.substate),
1227 unknown=True, ignored=False))
1227 unknown=True, ignored=False))
1228
1228
1229 def matches(self, match):
1229 def matches(self, match):
1230 return sorted(self._repo.dirstate.matches(match))
1230 ds = self._repo.dirstate
1231 return sorted(f for f in ds.matches(match) if ds[f] != 'r')
1231
1232
1232 def ancestors(self):
1233 def ancestors(self):
1233 for p in self._parents:
1234 for p in self._parents:
1234 yield p
1235 yield p
1235 for a in self._repo.changelog.ancestors(
1236 for a in self._repo.changelog.ancestors(
1236 [p.rev() for p in self._parents]):
1237 [p.rev() for p in self._parents]):
1237 yield changectx(self._repo, a)
1238 yield changectx(self._repo, a)
1238
1239
1239 def markcommitted(self, node):
1240 def markcommitted(self, node):
1240 """Perform post-commit cleanup necessary after committing this ctx
1241 """Perform post-commit cleanup necessary after committing this ctx
1241
1242
1242 Specifically, this updates backing stores this working context
1243 Specifically, this updates backing stores this working context
1243 wraps to reflect the fact that the changes reflected by this
1244 wraps to reflect the fact that the changes reflected by this
1244 workingctx have been committed. For example, it marks
1245 workingctx have been committed. For example, it marks
1245 modified and added files as normal in the dirstate.
1246 modified and added files as normal in the dirstate.
1246
1247
1247 """
1248 """
1248
1249
1249 with self._repo.dirstate.parentchange():
1250 with self._repo.dirstate.parentchange():
1250 for f in self.modified() + self.added():
1251 for f in self.modified() + self.added():
1251 self._repo.dirstate.normal(f)
1252 self._repo.dirstate.normal(f)
1252 for f in self.removed():
1253 for f in self.removed():
1253 self._repo.dirstate.drop(f)
1254 self._repo.dirstate.drop(f)
1254 self._repo.dirstate.setparents(node)
1255 self._repo.dirstate.setparents(node)
1255
1256
1256 # write changes out explicitly, because nesting wlock at
1257 # write changes out explicitly, because nesting wlock at
1257 # runtime may prevent 'wlock.release()' in 'repo.commit()'
1258 # runtime may prevent 'wlock.release()' in 'repo.commit()'
1258 # from immediately doing so for subsequent changing files
1259 # from immediately doing so for subsequent changing files
1259 self._repo.dirstate.write(self._repo.currenttransaction())
1260 self._repo.dirstate.write(self._repo.currenttransaction())
1260
1261
1261 def dirty(self, missing=False, merge=True, branch=True):
1262 def dirty(self, missing=False, merge=True, branch=True):
1262 return False
1263 return False
1263
1264
1264 class workingctx(committablectx):
1265 class workingctx(committablectx):
1265 """A workingctx object makes access to data related to
1266 """A workingctx object makes access to data related to
1266 the current working directory convenient.
1267 the current working directory convenient.
1267 date - any valid date string or (unixtime, offset), or None.
1268 date - any valid date string or (unixtime, offset), or None.
1268 user - username string, or None.
1269 user - username string, or None.
1269 extra - a dictionary of extra values, or None.
1270 extra - a dictionary of extra values, or None.
1270 changes - a list of file lists as returned by localrepo.status()
1271 changes - a list of file lists as returned by localrepo.status()
1271 or None to use the repository status.
1272 or None to use the repository status.
1272 """
1273 """
1273 def __init__(self, repo, text="", user=None, date=None, extra=None,
1274 def __init__(self, repo, text="", user=None, date=None, extra=None,
1274 changes=None):
1275 changes=None):
1275 super(workingctx, self).__init__(repo, text, user, date, extra, changes)
1276 super(workingctx, self).__init__(repo, text, user, date, extra, changes)
1276
1277
1277 def __iter__(self):
1278 def __iter__(self):
1278 d = self._repo.dirstate
1279 d = self._repo.dirstate
1279 for f in d:
1280 for f in d:
1280 if d[f] != 'r':
1281 if d[f] != 'r':
1281 yield f
1282 yield f
1282
1283
1283 def __contains__(self, key):
1284 def __contains__(self, key):
1284 return self._repo.dirstate[key] not in "?r"
1285 return self._repo.dirstate[key] not in "?r"
1285
1286
1286 def hex(self):
1287 def hex(self):
1287 return hex(wdirid)
1288 return hex(wdirid)
1288
1289
1289 @propertycache
1290 @propertycache
1290 def _parents(self):
1291 def _parents(self):
1291 p = self._repo.dirstate.parents()
1292 p = self._repo.dirstate.parents()
1292 if p[1] == nullid:
1293 if p[1] == nullid:
1293 p = p[:-1]
1294 p = p[:-1]
1294 return [changectx(self._repo, x) for x in p]
1295 return [changectx(self._repo, x) for x in p]
1295
1296
1296 def _fileinfo(self, path):
1297 def _fileinfo(self, path):
1297 # populate __dict__['_manifest'] as workingctx has no _manifestdelta
1298 # populate __dict__['_manifest'] as workingctx has no _manifestdelta
1298 self._manifest
1299 self._manifest
1299 return super(workingctx, self)._fileinfo(path)
1300 return super(workingctx, self)._fileinfo(path)
1300
1301
1301 def filectx(self, path, filelog=None):
1302 def filectx(self, path, filelog=None):
1302 """get a file context from the working directory"""
1303 """get a file context from the working directory"""
1303 return workingfilectx(self._repo, path, workingctx=self,
1304 return workingfilectx(self._repo, path, workingctx=self,
1304 filelog=filelog)
1305 filelog=filelog)
1305
1306
1306 def dirty(self, missing=False, merge=True, branch=True):
1307 def dirty(self, missing=False, merge=True, branch=True):
1307 "check whether a working directory is modified"
1308 "check whether a working directory is modified"
1308 # check subrepos first
1309 # check subrepos first
1309 for s in sorted(self.substate):
1310 for s in sorted(self.substate):
1310 if self.sub(s).dirty(missing=missing):
1311 if self.sub(s).dirty(missing=missing):
1311 return True
1312 return True
1312 # check current working dir
1313 # check current working dir
1313 return ((merge and self.p2()) or
1314 return ((merge and self.p2()) or
1314 (branch and self.branch() != self.p1().branch()) or
1315 (branch and self.branch() != self.p1().branch()) or
1315 self.modified() or self.added() or self.removed() or
1316 self.modified() or self.added() or self.removed() or
1316 (missing and self.deleted()))
1317 (missing and self.deleted()))
1317
1318
1318 def add(self, list, prefix=""):
1319 def add(self, list, prefix=""):
1319 with self._repo.wlock():
1320 with self._repo.wlock():
1320 ui, ds = self._repo.ui, self._repo.dirstate
1321 ui, ds = self._repo.ui, self._repo.dirstate
1321 uipath = lambda f: ds.pathto(pathutil.join(prefix, f))
1322 uipath = lambda f: ds.pathto(pathutil.join(prefix, f))
1322 rejected = []
1323 rejected = []
1323 lstat = self._repo.wvfs.lstat
1324 lstat = self._repo.wvfs.lstat
1324 for f in list:
1325 for f in list:
1325 # ds.pathto() returns an absolute file when this is invoked from
1326 # ds.pathto() returns an absolute file when this is invoked from
1326 # the keyword extension. That gets flagged as non-portable on
1327 # the keyword extension. That gets flagged as non-portable on
1327 # Windows, since it contains the drive letter and colon.
1328 # Windows, since it contains the drive letter and colon.
1328 scmutil.checkportable(ui, os.path.join(prefix, f))
1329 scmutil.checkportable(ui, os.path.join(prefix, f))
1329 try:
1330 try:
1330 st = lstat(f)
1331 st = lstat(f)
1331 except OSError:
1332 except OSError:
1332 ui.warn(_("%s does not exist!\n") % uipath(f))
1333 ui.warn(_("%s does not exist!\n") % uipath(f))
1333 rejected.append(f)
1334 rejected.append(f)
1334 continue
1335 continue
1335 if st.st_size > 10000000:
1336 if st.st_size > 10000000:
1336 ui.warn(_("%s: up to %d MB of RAM may be required "
1337 ui.warn(_("%s: up to %d MB of RAM may be required "
1337 "to manage this file\n"
1338 "to manage this file\n"
1338 "(use 'hg revert %s' to cancel the "
1339 "(use 'hg revert %s' to cancel the "
1339 "pending addition)\n")
1340 "pending addition)\n")
1340 % (f, 3 * st.st_size // 1000000, uipath(f)))
1341 % (f, 3 * st.st_size // 1000000, uipath(f)))
1341 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
1342 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
1342 ui.warn(_("%s not added: only files and symlinks "
1343 ui.warn(_("%s not added: only files and symlinks "
1343 "supported currently\n") % uipath(f))
1344 "supported currently\n") % uipath(f))
1344 rejected.append(f)
1345 rejected.append(f)
1345 elif ds[f] in 'amn':
1346 elif ds[f] in 'amn':
1346 ui.warn(_("%s already tracked!\n") % uipath(f))
1347 ui.warn(_("%s already tracked!\n") % uipath(f))
1347 elif ds[f] == 'r':
1348 elif ds[f] == 'r':
1348 ds.normallookup(f)
1349 ds.normallookup(f)
1349 else:
1350 else:
1350 ds.add(f)
1351 ds.add(f)
1351 return rejected
1352 return rejected
1352
1353
1353 def forget(self, files, prefix=""):
1354 def forget(self, files, prefix=""):
1354 with self._repo.wlock():
1355 with self._repo.wlock():
1355 ds = self._repo.dirstate
1356 ds = self._repo.dirstate
1356 uipath = lambda f: ds.pathto(pathutil.join(prefix, f))
1357 uipath = lambda f: ds.pathto(pathutil.join(prefix, f))
1357 rejected = []
1358 rejected = []
1358 for f in files:
1359 for f in files:
1359 if f not in self._repo.dirstate:
1360 if f not in self._repo.dirstate:
1360 self._repo.ui.warn(_("%s not tracked!\n") % uipath(f))
1361 self._repo.ui.warn(_("%s not tracked!\n") % uipath(f))
1361 rejected.append(f)
1362 rejected.append(f)
1362 elif self._repo.dirstate[f] != 'a':
1363 elif self._repo.dirstate[f] != 'a':
1363 self._repo.dirstate.remove(f)
1364 self._repo.dirstate.remove(f)
1364 else:
1365 else:
1365 self._repo.dirstate.drop(f)
1366 self._repo.dirstate.drop(f)
1366 return rejected
1367 return rejected
1367
1368
1368 def undelete(self, list):
1369 def undelete(self, list):
1369 pctxs = self.parents()
1370 pctxs = self.parents()
1370 with self._repo.wlock():
1371 with self._repo.wlock():
1371 ds = self._repo.dirstate
1372 ds = self._repo.dirstate
1372 for f in list:
1373 for f in list:
1373 if self._repo.dirstate[f] != 'r':
1374 if self._repo.dirstate[f] != 'r':
1374 self._repo.ui.warn(_("%s not removed!\n") % ds.pathto(f))
1375 self._repo.ui.warn(_("%s not removed!\n") % ds.pathto(f))
1375 else:
1376 else:
1376 fctx = f in pctxs[0] and pctxs[0][f] or pctxs[1][f]
1377 fctx = f in pctxs[0] and pctxs[0][f] or pctxs[1][f]
1377 t = fctx.data()
1378 t = fctx.data()
1378 self._repo.wwrite(f, t, fctx.flags())
1379 self._repo.wwrite(f, t, fctx.flags())
1379 self._repo.dirstate.normal(f)
1380 self._repo.dirstate.normal(f)
1380
1381
1381 def copy(self, source, dest):
1382 def copy(self, source, dest):
1382 try:
1383 try:
1383 st = self._repo.wvfs.lstat(dest)
1384 st = self._repo.wvfs.lstat(dest)
1384 except OSError as err:
1385 except OSError as err:
1385 if err.errno != errno.ENOENT:
1386 if err.errno != errno.ENOENT:
1386 raise
1387 raise
1387 self._repo.ui.warn(_("%s does not exist!\n")
1388 self._repo.ui.warn(_("%s does not exist!\n")
1388 % self._repo.dirstate.pathto(dest))
1389 % self._repo.dirstate.pathto(dest))
1389 return
1390 return
1390 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
1391 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
1391 self._repo.ui.warn(_("copy failed: %s is not a file or a "
1392 self._repo.ui.warn(_("copy failed: %s is not a file or a "
1392 "symbolic link\n")
1393 "symbolic link\n")
1393 % self._repo.dirstate.pathto(dest))
1394 % self._repo.dirstate.pathto(dest))
1394 else:
1395 else:
1395 with self._repo.wlock():
1396 with self._repo.wlock():
1396 if self._repo.dirstate[dest] in '?':
1397 if self._repo.dirstate[dest] in '?':
1397 self._repo.dirstate.add(dest)
1398 self._repo.dirstate.add(dest)
1398 elif self._repo.dirstate[dest] in 'r':
1399 elif self._repo.dirstate[dest] in 'r':
1399 self._repo.dirstate.normallookup(dest)
1400 self._repo.dirstate.normallookup(dest)
1400 self._repo.dirstate.copy(source, dest)
1401 self._repo.dirstate.copy(source, dest)
1401
1402
1402 def match(self, pats=None, include=None, exclude=None, default='glob',
1403 def match(self, pats=None, include=None, exclude=None, default='glob',
1403 listsubrepos=False, badfn=None):
1404 listsubrepos=False, badfn=None):
1404 r = self._repo
1405 r = self._repo
1405
1406
1406 # Only a case insensitive filesystem needs magic to translate user input
1407 # Only a case insensitive filesystem needs magic to translate user input
1407 # to actual case in the filesystem.
1408 # to actual case in the filesystem.
1408 icasefs = not util.fscasesensitive(r.root)
1409 icasefs = not util.fscasesensitive(r.root)
1409 return matchmod.match(r.root, r.getcwd(), pats, include, exclude,
1410 return matchmod.match(r.root, r.getcwd(), pats, include, exclude,
1410 default, auditor=r.auditor, ctx=self,
1411 default, auditor=r.auditor, ctx=self,
1411 listsubrepos=listsubrepos, badfn=badfn,
1412 listsubrepos=listsubrepos, badfn=badfn,
1412 icasefs=icasefs)
1413 icasefs=icasefs)
1413
1414
1414 def _filtersuspectsymlink(self, files):
1415 def _filtersuspectsymlink(self, files):
1415 if not files or self._repo.dirstate._checklink:
1416 if not files or self._repo.dirstate._checklink:
1416 return files
1417 return files
1417
1418
1418 # Symlink placeholders may get non-symlink-like contents
1419 # Symlink placeholders may get non-symlink-like contents
1419 # via user error or dereferencing by NFS or Samba servers,
1420 # via user error or dereferencing by NFS or Samba servers,
1420 # so we filter out any placeholders that don't look like a
1421 # so we filter out any placeholders that don't look like a
1421 # symlink
1422 # symlink
1422 sane = []
1423 sane = []
1423 for f in files:
1424 for f in files:
1424 if self.flags(f) == 'l':
1425 if self.flags(f) == 'l':
1425 d = self[f].data()
1426 d = self[f].data()
1426 if (d == '' or len(d) >= 1024 or '\n' in d
1427 if (d == '' or len(d) >= 1024 or '\n' in d
1427 or stringutil.binary(d)):
1428 or stringutil.binary(d)):
1428 self._repo.ui.debug('ignoring suspect symlink placeholder'
1429 self._repo.ui.debug('ignoring suspect symlink placeholder'
1429 ' "%s"\n' % f)
1430 ' "%s"\n' % f)
1430 continue
1431 continue
1431 sane.append(f)
1432 sane.append(f)
1432 return sane
1433 return sane
1433
1434
1434 def _checklookup(self, files):
1435 def _checklookup(self, files):
1435 # check for any possibly clean files
1436 # check for any possibly clean files
1436 if not files:
1437 if not files:
1437 return [], [], []
1438 return [], [], []
1438
1439
1439 modified = []
1440 modified = []
1440 deleted = []
1441 deleted = []
1441 fixup = []
1442 fixup = []
1442 pctx = self._parents[0]
1443 pctx = self._parents[0]
1443 # do a full compare of any files that might have changed
1444 # do a full compare of any files that might have changed
1444 for f in sorted(files):
1445 for f in sorted(files):
1445 try:
1446 try:
1446 # This will return True for a file that got replaced by a
1447 # This will return True for a file that got replaced by a
1447 # directory in the interim, but fixing that is pretty hard.
1448 # directory in the interim, but fixing that is pretty hard.
1448 if (f not in pctx or self.flags(f) != pctx.flags(f)
1449 if (f not in pctx or self.flags(f) != pctx.flags(f)
1449 or pctx[f].cmp(self[f])):
1450 or pctx[f].cmp(self[f])):
1450 modified.append(f)
1451 modified.append(f)
1451 else:
1452 else:
1452 fixup.append(f)
1453 fixup.append(f)
1453 except (IOError, OSError):
1454 except (IOError, OSError):
1454 # A file become inaccessible in between? Mark it as deleted,
1455 # A file become inaccessible in between? Mark it as deleted,
1455 # matching dirstate behavior (issue5584).
1456 # matching dirstate behavior (issue5584).
1456 # The dirstate has more complex behavior around whether a
1457 # The dirstate has more complex behavior around whether a
1457 # missing file matches a directory, etc, but we don't need to
1458 # missing file matches a directory, etc, but we don't need to
1458 # bother with that: if f has made it to this point, we're sure
1459 # bother with that: if f has made it to this point, we're sure
1459 # it's in the dirstate.
1460 # it's in the dirstate.
1460 deleted.append(f)
1461 deleted.append(f)
1461
1462
1462 return modified, deleted, fixup
1463 return modified, deleted, fixup
1463
1464
1464 def _poststatusfixup(self, status, fixup):
1465 def _poststatusfixup(self, status, fixup):
1465 """update dirstate for files that are actually clean"""
1466 """update dirstate for files that are actually clean"""
1466 poststatus = self._repo.postdsstatus()
1467 poststatus = self._repo.postdsstatus()
1467 if fixup or poststatus:
1468 if fixup or poststatus:
1468 try:
1469 try:
1469 oldid = self._repo.dirstate.identity()
1470 oldid = self._repo.dirstate.identity()
1470
1471
1471 # updating the dirstate is optional
1472 # updating the dirstate is optional
1472 # so we don't wait on the lock
1473 # so we don't wait on the lock
1473 # wlock can invalidate the dirstate, so cache normal _after_
1474 # wlock can invalidate the dirstate, so cache normal _after_
1474 # taking the lock
1475 # taking the lock
1475 with self._repo.wlock(False):
1476 with self._repo.wlock(False):
1476 if self._repo.dirstate.identity() == oldid:
1477 if self._repo.dirstate.identity() == oldid:
1477 if fixup:
1478 if fixup:
1478 normal = self._repo.dirstate.normal
1479 normal = self._repo.dirstate.normal
1479 for f in fixup:
1480 for f in fixup:
1480 normal(f)
1481 normal(f)
1481 # write changes out explicitly, because nesting
1482 # write changes out explicitly, because nesting
1482 # wlock at runtime may prevent 'wlock.release()'
1483 # wlock at runtime may prevent 'wlock.release()'
1483 # after this block from doing so for subsequent
1484 # after this block from doing so for subsequent
1484 # changing files
1485 # changing files
1485 tr = self._repo.currenttransaction()
1486 tr = self._repo.currenttransaction()
1486 self._repo.dirstate.write(tr)
1487 self._repo.dirstate.write(tr)
1487
1488
1488 if poststatus:
1489 if poststatus:
1489 for ps in poststatus:
1490 for ps in poststatus:
1490 ps(self, status)
1491 ps(self, status)
1491 else:
1492 else:
1492 # in this case, writing changes out breaks
1493 # in this case, writing changes out breaks
1493 # consistency, because .hg/dirstate was
1494 # consistency, because .hg/dirstate was
1494 # already changed simultaneously after last
1495 # already changed simultaneously after last
1495 # caching (see also issue5584 for detail)
1496 # caching (see also issue5584 for detail)
1496 self._repo.ui.debug('skip updating dirstate: '
1497 self._repo.ui.debug('skip updating dirstate: '
1497 'identity mismatch\n')
1498 'identity mismatch\n')
1498 except error.LockError:
1499 except error.LockError:
1499 pass
1500 pass
1500 finally:
1501 finally:
1501 # Even if the wlock couldn't be grabbed, clear out the list.
1502 # Even if the wlock couldn't be grabbed, clear out the list.
1502 self._repo.clearpostdsstatus()
1503 self._repo.clearpostdsstatus()
1503
1504
1504 def _dirstatestatus(self, match, ignored=False, clean=False, unknown=False):
1505 def _dirstatestatus(self, match, ignored=False, clean=False, unknown=False):
1505 '''Gets the status from the dirstate -- internal use only.'''
1506 '''Gets the status from the dirstate -- internal use only.'''
1506 subrepos = []
1507 subrepos = []
1507 if '.hgsub' in self:
1508 if '.hgsub' in self:
1508 subrepos = sorted(self.substate)
1509 subrepos = sorted(self.substate)
1509 cmp, s = self._repo.dirstate.status(match, subrepos, ignored=ignored,
1510 cmp, s = self._repo.dirstate.status(match, subrepos, ignored=ignored,
1510 clean=clean, unknown=unknown)
1511 clean=clean, unknown=unknown)
1511
1512
1512 # check for any possibly clean files
1513 # check for any possibly clean files
1513 fixup = []
1514 fixup = []
1514 if cmp:
1515 if cmp:
1515 modified2, deleted2, fixup = self._checklookup(cmp)
1516 modified2, deleted2, fixup = self._checklookup(cmp)
1516 s.modified.extend(modified2)
1517 s.modified.extend(modified2)
1517 s.deleted.extend(deleted2)
1518 s.deleted.extend(deleted2)
1518
1519
1519 if fixup and clean:
1520 if fixup and clean:
1520 s.clean.extend(fixup)
1521 s.clean.extend(fixup)
1521
1522
1522 self._poststatusfixup(s, fixup)
1523 self._poststatusfixup(s, fixup)
1523
1524
1524 if match.always():
1525 if match.always():
1525 # cache for performance
1526 # cache for performance
1526 if s.unknown or s.ignored or s.clean:
1527 if s.unknown or s.ignored or s.clean:
1527 # "_status" is cached with list*=False in the normal route
1528 # "_status" is cached with list*=False in the normal route
1528 self._status = scmutil.status(s.modified, s.added, s.removed,
1529 self._status = scmutil.status(s.modified, s.added, s.removed,
1529 s.deleted, [], [], [])
1530 s.deleted, [], [], [])
1530 else:
1531 else:
1531 self._status = s
1532 self._status = s
1532
1533
1533 return s
1534 return s
1534
1535
1535 @propertycache
1536 @propertycache
1536 def _manifest(self):
1537 def _manifest(self):
1537 """generate a manifest corresponding to the values in self._status
1538 """generate a manifest corresponding to the values in self._status
1538
1539
1539 This reuse the file nodeid from parent, but we use special node
1540 This reuse the file nodeid from parent, but we use special node
1540 identifiers for added and modified files. This is used by manifests
1541 identifiers for added and modified files. This is used by manifests
1541 merge to see that files are different and by update logic to avoid
1542 merge to see that files are different and by update logic to avoid
1542 deleting newly added files.
1543 deleting newly added files.
1543 """
1544 """
1544 return self._buildstatusmanifest(self._status)
1545 return self._buildstatusmanifest(self._status)
1545
1546
1546 def _buildstatusmanifest(self, status):
1547 def _buildstatusmanifest(self, status):
1547 """Builds a manifest that includes the given status results."""
1548 """Builds a manifest that includes the given status results."""
1548 parents = self.parents()
1549 parents = self.parents()
1549
1550
1550 man = parents[0].manifest().copy()
1551 man = parents[0].manifest().copy()
1551
1552
1552 ff = self._flagfunc
1553 ff = self._flagfunc
1553 for i, l in ((addednodeid, status.added),
1554 for i, l in ((addednodeid, status.added),
1554 (modifiednodeid, status.modified)):
1555 (modifiednodeid, status.modified)):
1555 for f in l:
1556 for f in l:
1556 man[f] = i
1557 man[f] = i
1557 try:
1558 try:
1558 man.setflag(f, ff(f))
1559 man.setflag(f, ff(f))
1559 except OSError:
1560 except OSError:
1560 pass
1561 pass
1561
1562
1562 for f in status.deleted + status.removed:
1563 for f in status.deleted + status.removed:
1563 if f in man:
1564 if f in man:
1564 del man[f]
1565 del man[f]
1565
1566
1566 return man
1567 return man
1567
1568
1568 def _buildstatus(self, other, s, match, listignored, listclean,
1569 def _buildstatus(self, other, s, match, listignored, listclean,
1569 listunknown):
1570 listunknown):
1570 """build a status with respect to another context
1571 """build a status with respect to another context
1571
1572
1572 This includes logic for maintaining the fast path of status when
1573 This includes logic for maintaining the fast path of status when
1573 comparing the working directory against its parent, which is to skip
1574 comparing the working directory against its parent, which is to skip
1574 building a new manifest if self (working directory) is not comparing
1575 building a new manifest if self (working directory) is not comparing
1575 against its parent (repo['.']).
1576 against its parent (repo['.']).
1576 """
1577 """
1577 s = self._dirstatestatus(match, listignored, listclean, listunknown)
1578 s = self._dirstatestatus(match, listignored, listclean, listunknown)
1578 # Filter out symlinks that, in the case of FAT32 and NTFS filesystems,
1579 # Filter out symlinks that, in the case of FAT32 and NTFS filesystems,
1579 # might have accidentally ended up with the entire contents of the file
1580 # might have accidentally ended up with the entire contents of the file
1580 # they are supposed to be linking to.
1581 # they are supposed to be linking to.
1581 s.modified[:] = self._filtersuspectsymlink(s.modified)
1582 s.modified[:] = self._filtersuspectsymlink(s.modified)
1582 if other != self._repo['.']:
1583 if other != self._repo['.']:
1583 s = super(workingctx, self)._buildstatus(other, s, match,
1584 s = super(workingctx, self)._buildstatus(other, s, match,
1584 listignored, listclean,
1585 listignored, listclean,
1585 listunknown)
1586 listunknown)
1586 return s
1587 return s
1587
1588
1588 def _matchstatus(self, other, match):
1589 def _matchstatus(self, other, match):
1589 """override the match method with a filter for directory patterns
1590 """override the match method with a filter for directory patterns
1590
1591
1591 We use inheritance to customize the match.bad method only in cases of
1592 We use inheritance to customize the match.bad method only in cases of
1592 workingctx since it belongs only to the working directory when
1593 workingctx since it belongs only to the working directory when
1593 comparing against the parent changeset.
1594 comparing against the parent changeset.
1594
1595
1595 If we aren't comparing against the working directory's parent, then we
1596 If we aren't comparing against the working directory's parent, then we
1596 just use the default match object sent to us.
1597 just use the default match object sent to us.
1597 """
1598 """
1598 if other != self._repo['.']:
1599 if other != self._repo['.']:
1599 def bad(f, msg):
1600 def bad(f, msg):
1600 # 'f' may be a directory pattern from 'match.files()',
1601 # 'f' may be a directory pattern from 'match.files()',
1601 # so 'f not in ctx1' is not enough
1602 # so 'f not in ctx1' is not enough
1602 if f not in other and not other.hasdir(f):
1603 if f not in other and not other.hasdir(f):
1603 self._repo.ui.warn('%s: %s\n' %
1604 self._repo.ui.warn('%s: %s\n' %
1604 (self._repo.dirstate.pathto(f), msg))
1605 (self._repo.dirstate.pathto(f), msg))
1605 match.bad = bad
1606 match.bad = bad
1606 return match
1607 return match
1607
1608
1608 def markcommitted(self, node):
1609 def markcommitted(self, node):
1609 super(workingctx, self).markcommitted(node)
1610 super(workingctx, self).markcommitted(node)
1610
1611
1611 sparse.aftercommit(self._repo, node)
1612 sparse.aftercommit(self._repo, node)
1612
1613
1613 class committablefilectx(basefilectx):
1614 class committablefilectx(basefilectx):
1614 """A committablefilectx provides common functionality for a file context
1615 """A committablefilectx provides common functionality for a file context
1615 that wants the ability to commit, e.g. workingfilectx or memfilectx."""
1616 that wants the ability to commit, e.g. workingfilectx or memfilectx."""
1616 def __init__(self, repo, path, filelog=None, ctx=None):
1617 def __init__(self, repo, path, filelog=None, ctx=None):
1617 self._repo = repo
1618 self._repo = repo
1618 self._path = path
1619 self._path = path
1619 self._changeid = None
1620 self._changeid = None
1620 self._filerev = self._filenode = None
1621 self._filerev = self._filenode = None
1621
1622
1622 if filelog is not None:
1623 if filelog is not None:
1623 self._filelog = filelog
1624 self._filelog = filelog
1624 if ctx:
1625 if ctx:
1625 self._changectx = ctx
1626 self._changectx = ctx
1626
1627
1627 def __nonzero__(self):
1628 def __nonzero__(self):
1628 return True
1629 return True
1629
1630
1630 __bool__ = __nonzero__
1631 __bool__ = __nonzero__
1631
1632
1632 def linkrev(self):
1633 def linkrev(self):
1633 # linked to self._changectx no matter if file is modified or not
1634 # linked to self._changectx no matter if file is modified or not
1634 return self.rev()
1635 return self.rev()
1635
1636
1636 def parents(self):
1637 def parents(self):
1637 '''return parent filectxs, following copies if necessary'''
1638 '''return parent filectxs, following copies if necessary'''
1638 def filenode(ctx, path):
1639 def filenode(ctx, path):
1639 return ctx._manifest.get(path, nullid)
1640 return ctx._manifest.get(path, nullid)
1640
1641
1641 path = self._path
1642 path = self._path
1642 fl = self._filelog
1643 fl = self._filelog
1643 pcl = self._changectx._parents
1644 pcl = self._changectx._parents
1644 renamed = self.renamed()
1645 renamed = self.renamed()
1645
1646
1646 if renamed:
1647 if renamed:
1647 pl = [renamed + (None,)]
1648 pl = [renamed + (None,)]
1648 else:
1649 else:
1649 pl = [(path, filenode(pcl[0], path), fl)]
1650 pl = [(path, filenode(pcl[0], path), fl)]
1650
1651
1651 for pc in pcl[1:]:
1652 for pc in pcl[1:]:
1652 pl.append((path, filenode(pc, path), fl))
1653 pl.append((path, filenode(pc, path), fl))
1653
1654
1654 return [self._parentfilectx(p, fileid=n, filelog=l)
1655 return [self._parentfilectx(p, fileid=n, filelog=l)
1655 for p, n, l in pl if n != nullid]
1656 for p, n, l in pl if n != nullid]
1656
1657
1657 def children(self):
1658 def children(self):
1658 return []
1659 return []
1659
1660
1660 class workingfilectx(committablefilectx):
1661 class workingfilectx(committablefilectx):
1661 """A workingfilectx object makes access to data related to a particular
1662 """A workingfilectx object makes access to data related to a particular
1662 file in the working directory convenient."""
1663 file in the working directory convenient."""
1663 def __init__(self, repo, path, filelog=None, workingctx=None):
1664 def __init__(self, repo, path, filelog=None, workingctx=None):
1664 super(workingfilectx, self).__init__(repo, path, filelog, workingctx)
1665 super(workingfilectx, self).__init__(repo, path, filelog, workingctx)
1665
1666
1666 @propertycache
1667 @propertycache
1667 def _changectx(self):
1668 def _changectx(self):
1668 return workingctx(self._repo)
1669 return workingctx(self._repo)
1669
1670
1670 def data(self):
1671 def data(self):
1671 return self._repo.wread(self._path)
1672 return self._repo.wread(self._path)
1672 def renamed(self):
1673 def renamed(self):
1673 rp = self._repo.dirstate.copied(self._path)
1674 rp = self._repo.dirstate.copied(self._path)
1674 if not rp:
1675 if not rp:
1675 return None
1676 return None
1676 return rp, self._changectx._parents[0]._manifest.get(rp, nullid)
1677 return rp, self._changectx._parents[0]._manifest.get(rp, nullid)
1677
1678
1678 def size(self):
1679 def size(self):
1679 return self._repo.wvfs.lstat(self._path).st_size
1680 return self._repo.wvfs.lstat(self._path).st_size
1680 def date(self):
1681 def date(self):
1681 t, tz = self._changectx.date()
1682 t, tz = self._changectx.date()
1682 try:
1683 try:
1683 return (self._repo.wvfs.lstat(self._path)[stat.ST_MTIME], tz)
1684 return (self._repo.wvfs.lstat(self._path)[stat.ST_MTIME], tz)
1684 except OSError as err:
1685 except OSError as err:
1685 if err.errno != errno.ENOENT:
1686 if err.errno != errno.ENOENT:
1686 raise
1687 raise
1687 return (t, tz)
1688 return (t, tz)
1688
1689
1689 def exists(self):
1690 def exists(self):
1690 return self._repo.wvfs.exists(self._path)
1691 return self._repo.wvfs.exists(self._path)
1691
1692
1692 def lexists(self):
1693 def lexists(self):
1693 return self._repo.wvfs.lexists(self._path)
1694 return self._repo.wvfs.lexists(self._path)
1694
1695
1695 def audit(self):
1696 def audit(self):
1696 return self._repo.wvfs.audit(self._path)
1697 return self._repo.wvfs.audit(self._path)
1697
1698
1698 def cmp(self, fctx):
1699 def cmp(self, fctx):
1699 """compare with other file context
1700 """compare with other file context
1700
1701
1701 returns True if different than fctx.
1702 returns True if different than fctx.
1702 """
1703 """
1703 # fctx should be a filectx (not a workingfilectx)
1704 # fctx should be a filectx (not a workingfilectx)
1704 # invert comparison to reuse the same code path
1705 # invert comparison to reuse the same code path
1705 return fctx.cmp(self)
1706 return fctx.cmp(self)
1706
1707
1707 def remove(self, ignoremissing=False):
1708 def remove(self, ignoremissing=False):
1708 """wraps unlink for a repo's working directory"""
1709 """wraps unlink for a repo's working directory"""
1709 self._repo.wvfs.unlinkpath(self._path, ignoremissing=ignoremissing)
1710 self._repo.wvfs.unlinkpath(self._path, ignoremissing=ignoremissing)
1710
1711
1711 def write(self, data, flags, backgroundclose=False, **kwargs):
1712 def write(self, data, flags, backgroundclose=False, **kwargs):
1712 """wraps repo.wwrite"""
1713 """wraps repo.wwrite"""
1713 self._repo.wwrite(self._path, data, flags,
1714 self._repo.wwrite(self._path, data, flags,
1714 backgroundclose=backgroundclose,
1715 backgroundclose=backgroundclose,
1715 **kwargs)
1716 **kwargs)
1716
1717
1717 def markcopied(self, src):
1718 def markcopied(self, src):
1718 """marks this file a copy of `src`"""
1719 """marks this file a copy of `src`"""
1719 if self._repo.dirstate[self._path] in "nma":
1720 if self._repo.dirstate[self._path] in "nma":
1720 self._repo.dirstate.copy(src, self._path)
1721 self._repo.dirstate.copy(src, self._path)
1721
1722
1722 def clearunknown(self):
1723 def clearunknown(self):
1723 """Removes conflicting items in the working directory so that
1724 """Removes conflicting items in the working directory so that
1724 ``write()`` can be called successfully.
1725 ``write()`` can be called successfully.
1725 """
1726 """
1726 wvfs = self._repo.wvfs
1727 wvfs = self._repo.wvfs
1727 f = self._path
1728 f = self._path
1728 wvfs.audit(f)
1729 wvfs.audit(f)
1729 if wvfs.isdir(f) and not wvfs.islink(f):
1730 if wvfs.isdir(f) and not wvfs.islink(f):
1730 wvfs.rmtree(f, forcibly=True)
1731 wvfs.rmtree(f, forcibly=True)
1731 if self._repo.ui.configbool('experimental', 'merge.checkpathconflicts'):
1732 if self._repo.ui.configbool('experimental', 'merge.checkpathconflicts'):
1732 for p in reversed(list(util.finddirs(f))):
1733 for p in reversed(list(util.finddirs(f))):
1733 if wvfs.isfileorlink(p):
1734 if wvfs.isfileorlink(p):
1734 wvfs.unlink(p)
1735 wvfs.unlink(p)
1735 break
1736 break
1736
1737
1737 def setflags(self, l, x):
1738 def setflags(self, l, x):
1738 self._repo.wvfs.setflags(self._path, l, x)
1739 self._repo.wvfs.setflags(self._path, l, x)
1739
1740
1740 class overlayworkingctx(committablectx):
1741 class overlayworkingctx(committablectx):
1741 """Wraps another mutable context with a write-back cache that can be
1742 """Wraps another mutable context with a write-back cache that can be
1742 converted into a commit context.
1743 converted into a commit context.
1743
1744
1744 self._cache[path] maps to a dict with keys: {
1745 self._cache[path] maps to a dict with keys: {
1745 'exists': bool?
1746 'exists': bool?
1746 'date': date?
1747 'date': date?
1747 'data': str?
1748 'data': str?
1748 'flags': str?
1749 'flags': str?
1749 'copied': str? (path or None)
1750 'copied': str? (path or None)
1750 }
1751 }
1751 If `exists` is True, `flags` must be non-None and 'date' is non-None. If it
1752 If `exists` is True, `flags` must be non-None and 'date' is non-None. If it
1752 is `False`, the file was deleted.
1753 is `False`, the file was deleted.
1753 """
1754 """
1754
1755
1755 def __init__(self, repo):
1756 def __init__(self, repo):
1756 super(overlayworkingctx, self).__init__(repo)
1757 super(overlayworkingctx, self).__init__(repo)
1757 self.clean()
1758 self.clean()
1758
1759
1759 def setbase(self, wrappedctx):
1760 def setbase(self, wrappedctx):
1760 self._wrappedctx = wrappedctx
1761 self._wrappedctx = wrappedctx
1761 self._parents = [wrappedctx]
1762 self._parents = [wrappedctx]
1762 # Drop old manifest cache as it is now out of date.
1763 # Drop old manifest cache as it is now out of date.
1763 # This is necessary when, e.g., rebasing several nodes with one
1764 # This is necessary when, e.g., rebasing several nodes with one
1764 # ``overlayworkingctx`` (e.g. with --collapse).
1765 # ``overlayworkingctx`` (e.g. with --collapse).
1765 util.clearcachedproperty(self, '_manifest')
1766 util.clearcachedproperty(self, '_manifest')
1766
1767
1767 def data(self, path):
1768 def data(self, path):
1768 if self.isdirty(path):
1769 if self.isdirty(path):
1769 if self._cache[path]['exists']:
1770 if self._cache[path]['exists']:
1770 if self._cache[path]['data']:
1771 if self._cache[path]['data']:
1771 return self._cache[path]['data']
1772 return self._cache[path]['data']
1772 else:
1773 else:
1773 # Must fallback here, too, because we only set flags.
1774 # Must fallback here, too, because we only set flags.
1774 return self._wrappedctx[path].data()
1775 return self._wrappedctx[path].data()
1775 else:
1776 else:
1776 raise error.ProgrammingError("No such file or directory: %s" %
1777 raise error.ProgrammingError("No such file or directory: %s" %
1777 path)
1778 path)
1778 else:
1779 else:
1779 return self._wrappedctx[path].data()
1780 return self._wrappedctx[path].data()
1780
1781
1781 @propertycache
1782 @propertycache
1782 def _manifest(self):
1783 def _manifest(self):
1783 parents = self.parents()
1784 parents = self.parents()
1784 man = parents[0].manifest().copy()
1785 man = parents[0].manifest().copy()
1785
1786
1786 flag = self._flagfunc
1787 flag = self._flagfunc
1787 for path in self.added():
1788 for path in self.added():
1788 man[path] = addednodeid
1789 man[path] = addednodeid
1789 man.setflag(path, flag(path))
1790 man.setflag(path, flag(path))
1790 for path in self.modified():
1791 for path in self.modified():
1791 man[path] = modifiednodeid
1792 man[path] = modifiednodeid
1792 man.setflag(path, flag(path))
1793 man.setflag(path, flag(path))
1793 for path in self.removed():
1794 for path in self.removed():
1794 del man[path]
1795 del man[path]
1795 return man
1796 return man
1796
1797
1797 @propertycache
1798 @propertycache
1798 def _flagfunc(self):
1799 def _flagfunc(self):
1799 def f(path):
1800 def f(path):
1800 return self._cache[path]['flags']
1801 return self._cache[path]['flags']
1801 return f
1802 return f
1802
1803
1803 def files(self):
1804 def files(self):
1804 return sorted(self.added() + self.modified() + self.removed())
1805 return sorted(self.added() + self.modified() + self.removed())
1805
1806
1806 def modified(self):
1807 def modified(self):
1807 return [f for f in self._cache.keys() if self._cache[f]['exists'] and
1808 return [f for f in self._cache.keys() if self._cache[f]['exists'] and
1808 self._existsinparent(f)]
1809 self._existsinparent(f)]
1809
1810
1810 def added(self):
1811 def added(self):
1811 return [f for f in self._cache.keys() if self._cache[f]['exists'] and
1812 return [f for f in self._cache.keys() if self._cache[f]['exists'] and
1812 not self._existsinparent(f)]
1813 not self._existsinparent(f)]
1813
1814
1814 def removed(self):
1815 def removed(self):
1815 return [f for f in self._cache.keys() if
1816 return [f for f in self._cache.keys() if
1816 not self._cache[f]['exists'] and self._existsinparent(f)]
1817 not self._cache[f]['exists'] and self._existsinparent(f)]
1817
1818
1818 def isinmemory(self):
1819 def isinmemory(self):
1819 return True
1820 return True
1820
1821
1821 def filedate(self, path):
1822 def filedate(self, path):
1822 if self.isdirty(path):
1823 if self.isdirty(path):
1823 return self._cache[path]['date']
1824 return self._cache[path]['date']
1824 else:
1825 else:
1825 return self._wrappedctx[path].date()
1826 return self._wrappedctx[path].date()
1826
1827
1827 def markcopied(self, path, origin):
1828 def markcopied(self, path, origin):
1828 if self.isdirty(path):
1829 if self.isdirty(path):
1829 self._cache[path]['copied'] = origin
1830 self._cache[path]['copied'] = origin
1830 else:
1831 else:
1831 raise error.ProgrammingError('markcopied() called on clean context')
1832 raise error.ProgrammingError('markcopied() called on clean context')
1832
1833
1833 def copydata(self, path):
1834 def copydata(self, path):
1834 if self.isdirty(path):
1835 if self.isdirty(path):
1835 return self._cache[path]['copied']
1836 return self._cache[path]['copied']
1836 else:
1837 else:
1837 raise error.ProgrammingError('copydata() called on clean context')
1838 raise error.ProgrammingError('copydata() called on clean context')
1838
1839
1839 def flags(self, path):
1840 def flags(self, path):
1840 if self.isdirty(path):
1841 if self.isdirty(path):
1841 if self._cache[path]['exists']:
1842 if self._cache[path]['exists']:
1842 return self._cache[path]['flags']
1843 return self._cache[path]['flags']
1843 else:
1844 else:
1844 raise error.ProgrammingError("No such file or directory: %s" %
1845 raise error.ProgrammingError("No such file or directory: %s" %
1845 self._path)
1846 self._path)
1846 else:
1847 else:
1847 return self._wrappedctx[path].flags()
1848 return self._wrappedctx[path].flags()
1848
1849
1849 def _existsinparent(self, path):
1850 def _existsinparent(self, path):
1850 try:
1851 try:
1851 # ``commitctx` raises a ``ManifestLookupError`` if a path does not
1852 # ``commitctx` raises a ``ManifestLookupError`` if a path does not
1852 # exist, unlike ``workingctx``, which returns a ``workingfilectx``
1853 # exist, unlike ``workingctx``, which returns a ``workingfilectx``
1853 # with an ``exists()`` function.
1854 # with an ``exists()`` function.
1854 self._wrappedctx[path]
1855 self._wrappedctx[path]
1855 return True
1856 return True
1856 except error.ManifestLookupError:
1857 except error.ManifestLookupError:
1857 return False
1858 return False
1858
1859
1859 def _auditconflicts(self, path):
1860 def _auditconflicts(self, path):
1860 """Replicates conflict checks done by wvfs.write().
1861 """Replicates conflict checks done by wvfs.write().
1861
1862
1862 Since we never write to the filesystem and never call `applyupdates` in
1863 Since we never write to the filesystem and never call `applyupdates` in
1863 IMM, we'll never check that a path is actually writable -- e.g., because
1864 IMM, we'll never check that a path is actually writable -- e.g., because
1864 it adds `a/foo`, but `a` is actually a file in the other commit.
1865 it adds `a/foo`, but `a` is actually a file in the other commit.
1865 """
1866 """
1866 def fail(path, component):
1867 def fail(path, component):
1867 # p1() is the base and we're receiving "writes" for p2()'s
1868 # p1() is the base and we're receiving "writes" for p2()'s
1868 # files.
1869 # files.
1869 if 'l' in self.p1()[component].flags():
1870 if 'l' in self.p1()[component].flags():
1870 raise error.Abort("error: %s conflicts with symlink %s "
1871 raise error.Abort("error: %s conflicts with symlink %s "
1871 "in %s." % (path, component,
1872 "in %s." % (path, component,
1872 self.p1().rev()))
1873 self.p1().rev()))
1873 else:
1874 else:
1874 raise error.Abort("error: '%s' conflicts with file '%s' in "
1875 raise error.Abort("error: '%s' conflicts with file '%s' in "
1875 "%s." % (path, component,
1876 "%s." % (path, component,
1876 self.p1().rev()))
1877 self.p1().rev()))
1877
1878
1878 # Test that each new directory to be created to write this path from p2
1879 # Test that each new directory to be created to write this path from p2
1879 # is not a file in p1.
1880 # is not a file in p1.
1880 components = path.split('/')
1881 components = path.split('/')
1881 for i in xrange(len(components)):
1882 for i in xrange(len(components)):
1882 component = "/".join(components[0:i])
1883 component = "/".join(components[0:i])
1883 if component in self.p1():
1884 if component in self.p1():
1884 fail(path, component)
1885 fail(path, component)
1885
1886
1886 # Test the other direction -- that this path from p2 isn't a directory
1887 # Test the other direction -- that this path from p2 isn't a directory
1887 # in p1 (test that p1 doesn't any paths matching `path/*`).
1888 # in p1 (test that p1 doesn't any paths matching `path/*`).
1888 match = matchmod.match('/', '', [path + '/'], default=b'relpath')
1889 match = matchmod.match('/', '', [path + '/'], default=b'relpath')
1889 matches = self.p1().manifest().matches(match)
1890 matches = self.p1().manifest().matches(match)
1890 if len(matches) > 0:
1891 if len(matches) > 0:
1891 if len(matches) == 1 and matches.keys()[0] == path:
1892 if len(matches) == 1 and matches.keys()[0] == path:
1892 return
1893 return
1893 raise error.Abort("error: file '%s' cannot be written because "
1894 raise error.Abort("error: file '%s' cannot be written because "
1894 " '%s/' is a folder in %s (containing %d "
1895 " '%s/' is a folder in %s (containing %d "
1895 "entries: %s)"
1896 "entries: %s)"
1896 % (path, path, self.p1(), len(matches),
1897 % (path, path, self.p1(), len(matches),
1897 ', '.join(matches.keys())))
1898 ', '.join(matches.keys())))
1898
1899
1899 def write(self, path, data, flags='', **kwargs):
1900 def write(self, path, data, flags='', **kwargs):
1900 if data is None:
1901 if data is None:
1901 raise error.ProgrammingError("data must be non-None")
1902 raise error.ProgrammingError("data must be non-None")
1902 self._auditconflicts(path)
1903 self._auditconflicts(path)
1903 self._markdirty(path, exists=True, data=data, date=dateutil.makedate(),
1904 self._markdirty(path, exists=True, data=data, date=dateutil.makedate(),
1904 flags=flags)
1905 flags=flags)
1905
1906
1906 def setflags(self, path, l, x):
1907 def setflags(self, path, l, x):
1907 self._markdirty(path, exists=True, date=dateutil.makedate(),
1908 self._markdirty(path, exists=True, date=dateutil.makedate(),
1908 flags=(l and 'l' or '') + (x and 'x' or ''))
1909 flags=(l and 'l' or '') + (x and 'x' or ''))
1909
1910
1910 def remove(self, path):
1911 def remove(self, path):
1911 self._markdirty(path, exists=False)
1912 self._markdirty(path, exists=False)
1912
1913
1913 def exists(self, path):
1914 def exists(self, path):
1914 """exists behaves like `lexists`, but needs to follow symlinks and
1915 """exists behaves like `lexists`, but needs to follow symlinks and
1915 return False if they are broken.
1916 return False if they are broken.
1916 """
1917 """
1917 if self.isdirty(path):
1918 if self.isdirty(path):
1918 # If this path exists and is a symlink, "follow" it by calling
1919 # If this path exists and is a symlink, "follow" it by calling
1919 # exists on the destination path.
1920 # exists on the destination path.
1920 if (self._cache[path]['exists'] and
1921 if (self._cache[path]['exists'] and
1921 'l' in self._cache[path]['flags']):
1922 'l' in self._cache[path]['flags']):
1922 return self.exists(self._cache[path]['data'].strip())
1923 return self.exists(self._cache[path]['data'].strip())
1923 else:
1924 else:
1924 return self._cache[path]['exists']
1925 return self._cache[path]['exists']
1925
1926
1926 return self._existsinparent(path)
1927 return self._existsinparent(path)
1927
1928
1928 def lexists(self, path):
1929 def lexists(self, path):
1929 """lexists returns True if the path exists"""
1930 """lexists returns True if the path exists"""
1930 if self.isdirty(path):
1931 if self.isdirty(path):
1931 return self._cache[path]['exists']
1932 return self._cache[path]['exists']
1932
1933
1933 return self._existsinparent(path)
1934 return self._existsinparent(path)
1934
1935
1935 def size(self, path):
1936 def size(self, path):
1936 if self.isdirty(path):
1937 if self.isdirty(path):
1937 if self._cache[path]['exists']:
1938 if self._cache[path]['exists']:
1938 return len(self._cache[path]['data'])
1939 return len(self._cache[path]['data'])
1939 else:
1940 else:
1940 raise error.ProgrammingError("No such file or directory: %s" %
1941 raise error.ProgrammingError("No such file or directory: %s" %
1941 self._path)
1942 self._path)
1942 return self._wrappedctx[path].size()
1943 return self._wrappedctx[path].size()
1943
1944
1944 def tomemctx(self, text, branch=None, extra=None, date=None, parents=None,
1945 def tomemctx(self, text, branch=None, extra=None, date=None, parents=None,
1945 user=None, editor=None):
1946 user=None, editor=None):
1946 """Converts this ``overlayworkingctx`` into a ``memctx`` ready to be
1947 """Converts this ``overlayworkingctx`` into a ``memctx`` ready to be
1947 committed.
1948 committed.
1948
1949
1949 ``text`` is the commit message.
1950 ``text`` is the commit message.
1950 ``parents`` (optional) are rev numbers.
1951 ``parents`` (optional) are rev numbers.
1951 """
1952 """
1952 # Default parents to the wrapped contexts' if not passed.
1953 # Default parents to the wrapped contexts' if not passed.
1953 if parents is None:
1954 if parents is None:
1954 parents = self._wrappedctx.parents()
1955 parents = self._wrappedctx.parents()
1955 if len(parents) == 1:
1956 if len(parents) == 1:
1956 parents = (parents[0], None)
1957 parents = (parents[0], None)
1957
1958
1958 # ``parents`` is passed as rev numbers; convert to ``commitctxs``.
1959 # ``parents`` is passed as rev numbers; convert to ``commitctxs``.
1959 if parents[1] is None:
1960 if parents[1] is None:
1960 parents = (self._repo[parents[0]], None)
1961 parents = (self._repo[parents[0]], None)
1961 else:
1962 else:
1962 parents = (self._repo[parents[0]], self._repo[parents[1]])
1963 parents = (self._repo[parents[0]], self._repo[parents[1]])
1963
1964
1964 files = self._cache.keys()
1965 files = self._cache.keys()
1965 def getfile(repo, memctx, path):
1966 def getfile(repo, memctx, path):
1966 if self._cache[path]['exists']:
1967 if self._cache[path]['exists']:
1967 return memfilectx(repo, memctx, path,
1968 return memfilectx(repo, memctx, path,
1968 self._cache[path]['data'],
1969 self._cache[path]['data'],
1969 'l' in self._cache[path]['flags'],
1970 'l' in self._cache[path]['flags'],
1970 'x' in self._cache[path]['flags'],
1971 'x' in self._cache[path]['flags'],
1971 self._cache[path]['copied'])
1972 self._cache[path]['copied'])
1972 else:
1973 else:
1973 # Returning None, but including the path in `files`, is
1974 # Returning None, but including the path in `files`, is
1974 # necessary for memctx to register a deletion.
1975 # necessary for memctx to register a deletion.
1975 return None
1976 return None
1976 return memctx(self._repo, parents, text, files, getfile, date=date,
1977 return memctx(self._repo, parents, text, files, getfile, date=date,
1977 extra=extra, user=user, branch=branch, editor=editor)
1978 extra=extra, user=user, branch=branch, editor=editor)
1978
1979
1979 def isdirty(self, path):
1980 def isdirty(self, path):
1980 return path in self._cache
1981 return path in self._cache
1981
1982
1982 def isempty(self):
1983 def isempty(self):
1983 # We need to discard any keys that are actually clean before the empty
1984 # We need to discard any keys that are actually clean before the empty
1984 # commit check.
1985 # commit check.
1985 self._compact()
1986 self._compact()
1986 return len(self._cache) == 0
1987 return len(self._cache) == 0
1987
1988
1988 def clean(self):
1989 def clean(self):
1989 self._cache = {}
1990 self._cache = {}
1990
1991
1991 def _compact(self):
1992 def _compact(self):
1992 """Removes keys from the cache that are actually clean, by comparing
1993 """Removes keys from the cache that are actually clean, by comparing
1993 them with the underlying context.
1994 them with the underlying context.
1994
1995
1995 This can occur during the merge process, e.g. by passing --tool :local
1996 This can occur during the merge process, e.g. by passing --tool :local
1996 to resolve a conflict.
1997 to resolve a conflict.
1997 """
1998 """
1998 keys = []
1999 keys = []
1999 for path in self._cache.keys():
2000 for path in self._cache.keys():
2000 cache = self._cache[path]
2001 cache = self._cache[path]
2001 try:
2002 try:
2002 underlying = self._wrappedctx[path]
2003 underlying = self._wrappedctx[path]
2003 if (underlying.data() == cache['data'] and
2004 if (underlying.data() == cache['data'] and
2004 underlying.flags() == cache['flags']):
2005 underlying.flags() == cache['flags']):
2005 keys.append(path)
2006 keys.append(path)
2006 except error.ManifestLookupError:
2007 except error.ManifestLookupError:
2007 # Path not in the underlying manifest (created).
2008 # Path not in the underlying manifest (created).
2008 continue
2009 continue
2009
2010
2010 for path in keys:
2011 for path in keys:
2011 del self._cache[path]
2012 del self._cache[path]
2012 return keys
2013 return keys
2013
2014
2014 def _markdirty(self, path, exists, data=None, date=None, flags=''):
2015 def _markdirty(self, path, exists, data=None, date=None, flags=''):
2015 self._cache[path] = {
2016 self._cache[path] = {
2016 'exists': exists,
2017 'exists': exists,
2017 'data': data,
2018 'data': data,
2018 'date': date,
2019 'date': date,
2019 'flags': flags,
2020 'flags': flags,
2020 'copied': None,
2021 'copied': None,
2021 }
2022 }
2022
2023
2023 def filectx(self, path, filelog=None):
2024 def filectx(self, path, filelog=None):
2024 return overlayworkingfilectx(self._repo, path, parent=self,
2025 return overlayworkingfilectx(self._repo, path, parent=self,
2025 filelog=filelog)
2026 filelog=filelog)
2026
2027
2027 class overlayworkingfilectx(committablefilectx):
2028 class overlayworkingfilectx(committablefilectx):
2028 """Wrap a ``workingfilectx`` but intercepts all writes into an in-memory
2029 """Wrap a ``workingfilectx`` but intercepts all writes into an in-memory
2029 cache, which can be flushed through later by calling ``flush()``."""
2030 cache, which can be flushed through later by calling ``flush()``."""
2030
2031
2031 def __init__(self, repo, path, filelog=None, parent=None):
2032 def __init__(self, repo, path, filelog=None, parent=None):
2032 super(overlayworkingfilectx, self).__init__(repo, path, filelog,
2033 super(overlayworkingfilectx, self).__init__(repo, path, filelog,
2033 parent)
2034 parent)
2034 self._repo = repo
2035 self._repo = repo
2035 self._parent = parent
2036 self._parent = parent
2036 self._path = path
2037 self._path = path
2037
2038
2038 def cmp(self, fctx):
2039 def cmp(self, fctx):
2039 return self.data() != fctx.data()
2040 return self.data() != fctx.data()
2040
2041
2041 def changectx(self):
2042 def changectx(self):
2042 return self._parent
2043 return self._parent
2043
2044
2044 def data(self):
2045 def data(self):
2045 return self._parent.data(self._path)
2046 return self._parent.data(self._path)
2046
2047
2047 def date(self):
2048 def date(self):
2048 return self._parent.filedate(self._path)
2049 return self._parent.filedate(self._path)
2049
2050
2050 def exists(self):
2051 def exists(self):
2051 return self.lexists()
2052 return self.lexists()
2052
2053
2053 def lexists(self):
2054 def lexists(self):
2054 return self._parent.exists(self._path)
2055 return self._parent.exists(self._path)
2055
2056
2056 def renamed(self):
2057 def renamed(self):
2057 path = self._parent.copydata(self._path)
2058 path = self._parent.copydata(self._path)
2058 if not path:
2059 if not path:
2059 return None
2060 return None
2060 return path, self._changectx._parents[0]._manifest.get(path, nullid)
2061 return path, self._changectx._parents[0]._manifest.get(path, nullid)
2061
2062
2062 def size(self):
2063 def size(self):
2063 return self._parent.size(self._path)
2064 return self._parent.size(self._path)
2064
2065
2065 def markcopied(self, origin):
2066 def markcopied(self, origin):
2066 self._parent.markcopied(self._path, origin)
2067 self._parent.markcopied(self._path, origin)
2067
2068
2068 def audit(self):
2069 def audit(self):
2069 pass
2070 pass
2070
2071
2071 def flags(self):
2072 def flags(self):
2072 return self._parent.flags(self._path)
2073 return self._parent.flags(self._path)
2073
2074
2074 def setflags(self, islink, isexec):
2075 def setflags(self, islink, isexec):
2075 return self._parent.setflags(self._path, islink, isexec)
2076 return self._parent.setflags(self._path, islink, isexec)
2076
2077
2077 def write(self, data, flags, backgroundclose=False, **kwargs):
2078 def write(self, data, flags, backgroundclose=False, **kwargs):
2078 return self._parent.write(self._path, data, flags, **kwargs)
2079 return self._parent.write(self._path, data, flags, **kwargs)
2079
2080
2080 def remove(self, ignoremissing=False):
2081 def remove(self, ignoremissing=False):
2081 return self._parent.remove(self._path)
2082 return self._parent.remove(self._path)
2082
2083
2083 def clearunknown(self):
2084 def clearunknown(self):
2084 pass
2085 pass
2085
2086
2086 class workingcommitctx(workingctx):
2087 class workingcommitctx(workingctx):
2087 """A workingcommitctx object makes access to data related to
2088 """A workingcommitctx object makes access to data related to
2088 the revision being committed convenient.
2089 the revision being committed convenient.
2089
2090
2090 This hides changes in the working directory, if they aren't
2091 This hides changes in the working directory, if they aren't
2091 committed in this context.
2092 committed in this context.
2092 """
2093 """
2093 def __init__(self, repo, changes,
2094 def __init__(self, repo, changes,
2094 text="", user=None, date=None, extra=None):
2095 text="", user=None, date=None, extra=None):
2095 super(workingctx, self).__init__(repo, text, user, date, extra,
2096 super(workingctx, self).__init__(repo, text, user, date, extra,
2096 changes)
2097 changes)
2097
2098
2098 def _dirstatestatus(self, match, ignored=False, clean=False, unknown=False):
2099 def _dirstatestatus(self, match, ignored=False, clean=False, unknown=False):
2099 """Return matched files only in ``self._status``
2100 """Return matched files only in ``self._status``
2100
2101
2101 Uncommitted files appear "clean" via this context, even if
2102 Uncommitted files appear "clean" via this context, even if
2102 they aren't actually so in the working directory.
2103 they aren't actually so in the working directory.
2103 """
2104 """
2104 if clean:
2105 if clean:
2105 clean = [f for f in self._manifest if f not in self._changedset]
2106 clean = [f for f in self._manifest if f not in self._changedset]
2106 else:
2107 else:
2107 clean = []
2108 clean = []
2108 return scmutil.status([f for f in self._status.modified if match(f)],
2109 return scmutil.status([f for f in self._status.modified if match(f)],
2109 [f for f in self._status.added if match(f)],
2110 [f for f in self._status.added if match(f)],
2110 [f for f in self._status.removed if match(f)],
2111 [f for f in self._status.removed if match(f)],
2111 [], [], [], clean)
2112 [], [], [], clean)
2112
2113
2113 @propertycache
2114 @propertycache
2114 def _changedset(self):
2115 def _changedset(self):
2115 """Return the set of files changed in this context
2116 """Return the set of files changed in this context
2116 """
2117 """
2117 changed = set(self._status.modified)
2118 changed = set(self._status.modified)
2118 changed.update(self._status.added)
2119 changed.update(self._status.added)
2119 changed.update(self._status.removed)
2120 changed.update(self._status.removed)
2120 return changed
2121 return changed
2121
2122
2122 def makecachingfilectxfn(func):
2123 def makecachingfilectxfn(func):
2123 """Create a filectxfn that caches based on the path.
2124 """Create a filectxfn that caches based on the path.
2124
2125
2125 We can't use util.cachefunc because it uses all arguments as the cache
2126 We can't use util.cachefunc because it uses all arguments as the cache
2126 key and this creates a cycle since the arguments include the repo and
2127 key and this creates a cycle since the arguments include the repo and
2127 memctx.
2128 memctx.
2128 """
2129 """
2129 cache = {}
2130 cache = {}
2130
2131
2131 def getfilectx(repo, memctx, path):
2132 def getfilectx(repo, memctx, path):
2132 if path not in cache:
2133 if path not in cache:
2133 cache[path] = func(repo, memctx, path)
2134 cache[path] = func(repo, memctx, path)
2134 return cache[path]
2135 return cache[path]
2135
2136
2136 return getfilectx
2137 return getfilectx
2137
2138
2138 def memfilefromctx(ctx):
2139 def memfilefromctx(ctx):
2139 """Given a context return a memfilectx for ctx[path]
2140 """Given a context return a memfilectx for ctx[path]
2140
2141
2141 This is a convenience method for building a memctx based on another
2142 This is a convenience method for building a memctx based on another
2142 context.
2143 context.
2143 """
2144 """
2144 def getfilectx(repo, memctx, path):
2145 def getfilectx(repo, memctx, path):
2145 fctx = ctx[path]
2146 fctx = ctx[path]
2146 # this is weird but apparently we only keep track of one parent
2147 # this is weird but apparently we only keep track of one parent
2147 # (why not only store that instead of a tuple?)
2148 # (why not only store that instead of a tuple?)
2148 copied = fctx.renamed()
2149 copied = fctx.renamed()
2149 if copied:
2150 if copied:
2150 copied = copied[0]
2151 copied = copied[0]
2151 return memfilectx(repo, memctx, path, fctx.data(),
2152 return memfilectx(repo, memctx, path, fctx.data(),
2152 islink=fctx.islink(), isexec=fctx.isexec(),
2153 islink=fctx.islink(), isexec=fctx.isexec(),
2153 copied=copied)
2154 copied=copied)
2154
2155
2155 return getfilectx
2156 return getfilectx
2156
2157
2157 def memfilefrompatch(patchstore):
2158 def memfilefrompatch(patchstore):
2158 """Given a patch (e.g. patchstore object) return a memfilectx
2159 """Given a patch (e.g. patchstore object) return a memfilectx
2159
2160
2160 This is a convenience method for building a memctx based on a patchstore.
2161 This is a convenience method for building a memctx based on a patchstore.
2161 """
2162 """
2162 def getfilectx(repo, memctx, path):
2163 def getfilectx(repo, memctx, path):
2163 data, mode, copied = patchstore.getfile(path)
2164 data, mode, copied = patchstore.getfile(path)
2164 if data is None:
2165 if data is None:
2165 return None
2166 return None
2166 islink, isexec = mode
2167 islink, isexec = mode
2167 return memfilectx(repo, memctx, path, data, islink=islink,
2168 return memfilectx(repo, memctx, path, data, islink=islink,
2168 isexec=isexec, copied=copied)
2169 isexec=isexec, copied=copied)
2169
2170
2170 return getfilectx
2171 return getfilectx
2171
2172
2172 class memctx(committablectx):
2173 class memctx(committablectx):
2173 """Use memctx to perform in-memory commits via localrepo.commitctx().
2174 """Use memctx to perform in-memory commits via localrepo.commitctx().
2174
2175
2175 Revision information is supplied at initialization time while
2176 Revision information is supplied at initialization time while
2176 related files data and is made available through a callback
2177 related files data and is made available through a callback
2177 mechanism. 'repo' is the current localrepo, 'parents' is a
2178 mechanism. 'repo' is the current localrepo, 'parents' is a
2178 sequence of two parent revisions identifiers (pass None for every
2179 sequence of two parent revisions identifiers (pass None for every
2179 missing parent), 'text' is the commit message and 'files' lists
2180 missing parent), 'text' is the commit message and 'files' lists
2180 names of files touched by the revision (normalized and relative to
2181 names of files touched by the revision (normalized and relative to
2181 repository root).
2182 repository root).
2182
2183
2183 filectxfn(repo, memctx, path) is a callable receiving the
2184 filectxfn(repo, memctx, path) is a callable receiving the
2184 repository, the current memctx object and the normalized path of
2185 repository, the current memctx object and the normalized path of
2185 requested file, relative to repository root. It is fired by the
2186 requested file, relative to repository root. It is fired by the
2186 commit function for every file in 'files', but calls order is
2187 commit function for every file in 'files', but calls order is
2187 undefined. If the file is available in the revision being
2188 undefined. If the file is available in the revision being
2188 committed (updated or added), filectxfn returns a memfilectx
2189 committed (updated or added), filectxfn returns a memfilectx
2189 object. If the file was removed, filectxfn return None for recent
2190 object. If the file was removed, filectxfn return None for recent
2190 Mercurial. Moved files are represented by marking the source file
2191 Mercurial. Moved files are represented by marking the source file
2191 removed and the new file added with copy information (see
2192 removed and the new file added with copy information (see
2192 memfilectx).
2193 memfilectx).
2193
2194
2194 user receives the committer name and defaults to current
2195 user receives the committer name and defaults to current
2195 repository username, date is the commit date in any format
2196 repository username, date is the commit date in any format
2196 supported by dateutil.parsedate() and defaults to current date, extra
2197 supported by dateutil.parsedate() and defaults to current date, extra
2197 is a dictionary of metadata or is left empty.
2198 is a dictionary of metadata or is left empty.
2198 """
2199 """
2199
2200
2200 # Mercurial <= 3.1 expects the filectxfn to raise IOError for missing files.
2201 # Mercurial <= 3.1 expects the filectxfn to raise IOError for missing files.
2201 # Extensions that need to retain compatibility across Mercurial 3.1 can use
2202 # Extensions that need to retain compatibility across Mercurial 3.1 can use
2202 # this field to determine what to do in filectxfn.
2203 # this field to determine what to do in filectxfn.
2203 _returnnoneformissingfiles = True
2204 _returnnoneformissingfiles = True
2204
2205
2205 def __init__(self, repo, parents, text, files, filectxfn, user=None,
2206 def __init__(self, repo, parents, text, files, filectxfn, user=None,
2206 date=None, extra=None, branch=None, editor=False):
2207 date=None, extra=None, branch=None, editor=False):
2207 super(memctx, self).__init__(repo, text, user, date, extra)
2208 super(memctx, self).__init__(repo, text, user, date, extra)
2208 self._rev = None
2209 self._rev = None
2209 self._node = None
2210 self._node = None
2210 parents = [(p or nullid) for p in parents]
2211 parents = [(p or nullid) for p in parents]
2211 p1, p2 = parents
2212 p1, p2 = parents
2212 self._parents = [self._repo[p] for p in (p1, p2)]
2213 self._parents = [self._repo[p] for p in (p1, p2)]
2213 files = sorted(set(files))
2214 files = sorted(set(files))
2214 self._files = files
2215 self._files = files
2215 if branch is not None:
2216 if branch is not None:
2216 self._extra['branch'] = encoding.fromlocal(branch)
2217 self._extra['branch'] = encoding.fromlocal(branch)
2217 self.substate = {}
2218 self.substate = {}
2218
2219
2219 if isinstance(filectxfn, patch.filestore):
2220 if isinstance(filectxfn, patch.filestore):
2220 filectxfn = memfilefrompatch(filectxfn)
2221 filectxfn = memfilefrompatch(filectxfn)
2221 elif not callable(filectxfn):
2222 elif not callable(filectxfn):
2222 # if store is not callable, wrap it in a function
2223 # if store is not callable, wrap it in a function
2223 filectxfn = memfilefromctx(filectxfn)
2224 filectxfn = memfilefromctx(filectxfn)
2224
2225
2225 # memoizing increases performance for e.g. vcs convert scenarios.
2226 # memoizing increases performance for e.g. vcs convert scenarios.
2226 self._filectxfn = makecachingfilectxfn(filectxfn)
2227 self._filectxfn = makecachingfilectxfn(filectxfn)
2227
2228
2228 if editor:
2229 if editor:
2229 self._text = editor(self._repo, self, [])
2230 self._text = editor(self._repo, self, [])
2230 self._repo.savecommitmessage(self._text)
2231 self._repo.savecommitmessage(self._text)
2231
2232
2232 def filectx(self, path, filelog=None):
2233 def filectx(self, path, filelog=None):
2233 """get a file context from the working directory
2234 """get a file context from the working directory
2234
2235
2235 Returns None if file doesn't exist and should be removed."""
2236 Returns None if file doesn't exist and should be removed."""
2236 return self._filectxfn(self._repo, self, path)
2237 return self._filectxfn(self._repo, self, path)
2237
2238
2238 def commit(self):
2239 def commit(self):
2239 """commit context to the repo"""
2240 """commit context to the repo"""
2240 return self._repo.commitctx(self)
2241 return self._repo.commitctx(self)
2241
2242
2242 @propertycache
2243 @propertycache
2243 def _manifest(self):
2244 def _manifest(self):
2244 """generate a manifest based on the return values of filectxfn"""
2245 """generate a manifest based on the return values of filectxfn"""
2245
2246
2246 # keep this simple for now; just worry about p1
2247 # keep this simple for now; just worry about p1
2247 pctx = self._parents[0]
2248 pctx = self._parents[0]
2248 man = pctx.manifest().copy()
2249 man = pctx.manifest().copy()
2249
2250
2250 for f in self._status.modified:
2251 for f in self._status.modified:
2251 p1node = nullid
2252 p1node = nullid
2252 p2node = nullid
2253 p2node = nullid
2253 p = pctx[f].parents() # if file isn't in pctx, check p2?
2254 p = pctx[f].parents() # if file isn't in pctx, check p2?
2254 if len(p) > 0:
2255 if len(p) > 0:
2255 p1node = p[0].filenode()
2256 p1node = p[0].filenode()
2256 if len(p) > 1:
2257 if len(p) > 1:
2257 p2node = p[1].filenode()
2258 p2node = p[1].filenode()
2258 man[f] = revlog.hash(self[f].data(), p1node, p2node)
2259 man[f] = revlog.hash(self[f].data(), p1node, p2node)
2259
2260
2260 for f in self._status.added:
2261 for f in self._status.added:
2261 man[f] = revlog.hash(self[f].data(), nullid, nullid)
2262 man[f] = revlog.hash(self[f].data(), nullid, nullid)
2262
2263
2263 for f in self._status.removed:
2264 for f in self._status.removed:
2264 if f in man:
2265 if f in man:
2265 del man[f]
2266 del man[f]
2266
2267
2267 return man
2268 return man
2268
2269
2269 @propertycache
2270 @propertycache
2270 def _status(self):
2271 def _status(self):
2271 """Calculate exact status from ``files`` specified at construction
2272 """Calculate exact status from ``files`` specified at construction
2272 """
2273 """
2273 man1 = self.p1().manifest()
2274 man1 = self.p1().manifest()
2274 p2 = self._parents[1]
2275 p2 = self._parents[1]
2275 # "1 < len(self._parents)" can't be used for checking
2276 # "1 < len(self._parents)" can't be used for checking
2276 # existence of the 2nd parent, because "memctx._parents" is
2277 # existence of the 2nd parent, because "memctx._parents" is
2277 # explicitly initialized by the list, of which length is 2.
2278 # explicitly initialized by the list, of which length is 2.
2278 if p2.node() != nullid:
2279 if p2.node() != nullid:
2279 man2 = p2.manifest()
2280 man2 = p2.manifest()
2280 managing = lambda f: f in man1 or f in man2
2281 managing = lambda f: f in man1 or f in man2
2281 else:
2282 else:
2282 managing = lambda f: f in man1
2283 managing = lambda f: f in man1
2283
2284
2284 modified, added, removed = [], [], []
2285 modified, added, removed = [], [], []
2285 for f in self._files:
2286 for f in self._files:
2286 if not managing(f):
2287 if not managing(f):
2287 added.append(f)
2288 added.append(f)
2288 elif self[f]:
2289 elif self[f]:
2289 modified.append(f)
2290 modified.append(f)
2290 else:
2291 else:
2291 removed.append(f)
2292 removed.append(f)
2292
2293
2293 return scmutil.status(modified, added, removed, [], [], [], [])
2294 return scmutil.status(modified, added, removed, [], [], [], [])
2294
2295
2295 class memfilectx(committablefilectx):
2296 class memfilectx(committablefilectx):
2296 """memfilectx represents an in-memory file to commit.
2297 """memfilectx represents an in-memory file to commit.
2297
2298
2298 See memctx and committablefilectx for more details.
2299 See memctx and committablefilectx for more details.
2299 """
2300 """
2300 def __init__(self, repo, changectx, path, data, islink=False,
2301 def __init__(self, repo, changectx, path, data, islink=False,
2301 isexec=False, copied=None):
2302 isexec=False, copied=None):
2302 """
2303 """
2303 path is the normalized file path relative to repository root.
2304 path is the normalized file path relative to repository root.
2304 data is the file content as a string.
2305 data is the file content as a string.
2305 islink is True if the file is a symbolic link.
2306 islink is True if the file is a symbolic link.
2306 isexec is True if the file is executable.
2307 isexec is True if the file is executable.
2307 copied is the source file path if current file was copied in the
2308 copied is the source file path if current file was copied in the
2308 revision being committed, or None."""
2309 revision being committed, or None."""
2309 super(memfilectx, self).__init__(repo, path, None, changectx)
2310 super(memfilectx, self).__init__(repo, path, None, changectx)
2310 self._data = data
2311 self._data = data
2311 self._flags = (islink and 'l' or '') + (isexec and 'x' or '')
2312 self._flags = (islink and 'l' or '') + (isexec and 'x' or '')
2312 self._copied = None
2313 self._copied = None
2313 if copied:
2314 if copied:
2314 self._copied = (copied, nullid)
2315 self._copied = (copied, nullid)
2315
2316
2316 def data(self):
2317 def data(self):
2317 return self._data
2318 return self._data
2318
2319
2319 def remove(self, ignoremissing=False):
2320 def remove(self, ignoremissing=False):
2320 """wraps unlink for a repo's working directory"""
2321 """wraps unlink for a repo's working directory"""
2321 # need to figure out what to do here
2322 # need to figure out what to do here
2322 del self._changectx[self._path]
2323 del self._changectx[self._path]
2323
2324
2324 def write(self, data, flags, **kwargs):
2325 def write(self, data, flags, **kwargs):
2325 """wraps repo.wwrite"""
2326 """wraps repo.wwrite"""
2326 self._data = data
2327 self._data = data
2327
2328
2328 class overlayfilectx(committablefilectx):
2329 class overlayfilectx(committablefilectx):
2329 """Like memfilectx but take an original filectx and optional parameters to
2330 """Like memfilectx but take an original filectx and optional parameters to
2330 override parts of it. This is useful when fctx.data() is expensive (i.e.
2331 override parts of it. This is useful when fctx.data() is expensive (i.e.
2331 flag processor is expensive) and raw data, flags, and filenode could be
2332 flag processor is expensive) and raw data, flags, and filenode could be
2332 reused (ex. rebase or mode-only amend a REVIDX_EXTSTORED file).
2333 reused (ex. rebase or mode-only amend a REVIDX_EXTSTORED file).
2333 """
2334 """
2334
2335
2335 def __init__(self, originalfctx, datafunc=None, path=None, flags=None,
2336 def __init__(self, originalfctx, datafunc=None, path=None, flags=None,
2336 copied=None, ctx=None):
2337 copied=None, ctx=None):
2337 """originalfctx: filecontext to duplicate
2338 """originalfctx: filecontext to duplicate
2338
2339
2339 datafunc: None or a function to override data (file content). It is a
2340 datafunc: None or a function to override data (file content). It is a
2340 function to be lazy. path, flags, copied, ctx: None or overridden value
2341 function to be lazy. path, flags, copied, ctx: None or overridden value
2341
2342
2342 copied could be (path, rev), or False. copied could also be just path,
2343 copied could be (path, rev), or False. copied could also be just path,
2343 and will be converted to (path, nullid). This simplifies some callers.
2344 and will be converted to (path, nullid). This simplifies some callers.
2344 """
2345 """
2345
2346
2346 if path is None:
2347 if path is None:
2347 path = originalfctx.path()
2348 path = originalfctx.path()
2348 if ctx is None:
2349 if ctx is None:
2349 ctx = originalfctx.changectx()
2350 ctx = originalfctx.changectx()
2350 ctxmatch = lambda: True
2351 ctxmatch = lambda: True
2351 else:
2352 else:
2352 ctxmatch = lambda: ctx == originalfctx.changectx()
2353 ctxmatch = lambda: ctx == originalfctx.changectx()
2353
2354
2354 repo = originalfctx.repo()
2355 repo = originalfctx.repo()
2355 flog = originalfctx.filelog()
2356 flog = originalfctx.filelog()
2356 super(overlayfilectx, self).__init__(repo, path, flog, ctx)
2357 super(overlayfilectx, self).__init__(repo, path, flog, ctx)
2357
2358
2358 if copied is None:
2359 if copied is None:
2359 copied = originalfctx.renamed()
2360 copied = originalfctx.renamed()
2360 copiedmatch = lambda: True
2361 copiedmatch = lambda: True
2361 else:
2362 else:
2362 if copied and not isinstance(copied, tuple):
2363 if copied and not isinstance(copied, tuple):
2363 # repo._filecommit will recalculate copyrev so nullid is okay
2364 # repo._filecommit will recalculate copyrev so nullid is okay
2364 copied = (copied, nullid)
2365 copied = (copied, nullid)
2365 copiedmatch = lambda: copied == originalfctx.renamed()
2366 copiedmatch = lambda: copied == originalfctx.renamed()
2366
2367
2367 # When data, copied (could affect data), ctx (could affect filelog
2368 # When data, copied (could affect data), ctx (could affect filelog
2368 # parents) are not overridden, rawdata, rawflags, and filenode may be
2369 # parents) are not overridden, rawdata, rawflags, and filenode may be
2369 # reused (repo._filecommit should double check filelog parents).
2370 # reused (repo._filecommit should double check filelog parents).
2370 #
2371 #
2371 # path, flags are not hashed in filelog (but in manifestlog) so they do
2372 # path, flags are not hashed in filelog (but in manifestlog) so they do
2372 # not affect reusable here.
2373 # not affect reusable here.
2373 #
2374 #
2374 # If ctx or copied is overridden to a same value with originalfctx,
2375 # If ctx or copied is overridden to a same value with originalfctx,
2375 # still consider it's reusable. originalfctx.renamed() may be a bit
2376 # still consider it's reusable. originalfctx.renamed() may be a bit
2376 # expensive so it's not called unless necessary. Assuming datafunc is
2377 # expensive so it's not called unless necessary. Assuming datafunc is
2377 # always expensive, do not call it for this "reusable" test.
2378 # always expensive, do not call it for this "reusable" test.
2378 reusable = datafunc is None and ctxmatch() and copiedmatch()
2379 reusable = datafunc is None and ctxmatch() and copiedmatch()
2379
2380
2380 if datafunc is None:
2381 if datafunc is None:
2381 datafunc = originalfctx.data
2382 datafunc = originalfctx.data
2382 if flags is None:
2383 if flags is None:
2383 flags = originalfctx.flags()
2384 flags = originalfctx.flags()
2384
2385
2385 self._datafunc = datafunc
2386 self._datafunc = datafunc
2386 self._flags = flags
2387 self._flags = flags
2387 self._copied = copied
2388 self._copied = copied
2388
2389
2389 if reusable:
2390 if reusable:
2390 # copy extra fields from originalfctx
2391 # copy extra fields from originalfctx
2391 attrs = ['rawdata', 'rawflags', '_filenode', '_filerev']
2392 attrs = ['rawdata', 'rawflags', '_filenode', '_filerev']
2392 for attr_ in attrs:
2393 for attr_ in attrs:
2393 if util.safehasattr(originalfctx, attr_):
2394 if util.safehasattr(originalfctx, attr_):
2394 setattr(self, attr_, getattr(originalfctx, attr_))
2395 setattr(self, attr_, getattr(originalfctx, attr_))
2395
2396
2396 def data(self):
2397 def data(self):
2397 return self._datafunc()
2398 return self._datafunc()
2398
2399
2399 class metadataonlyctx(committablectx):
2400 class metadataonlyctx(committablectx):
2400 """Like memctx but it's reusing the manifest of different commit.
2401 """Like memctx but it's reusing the manifest of different commit.
2401 Intended to be used by lightweight operations that are creating
2402 Intended to be used by lightweight operations that are creating
2402 metadata-only changes.
2403 metadata-only changes.
2403
2404
2404 Revision information is supplied at initialization time. 'repo' is the
2405 Revision information is supplied at initialization time. 'repo' is the
2405 current localrepo, 'ctx' is original revision which manifest we're reuisng
2406 current localrepo, 'ctx' is original revision which manifest we're reuisng
2406 'parents' is a sequence of two parent revisions identifiers (pass None for
2407 'parents' is a sequence of two parent revisions identifiers (pass None for
2407 every missing parent), 'text' is the commit.
2408 every missing parent), 'text' is the commit.
2408
2409
2409 user receives the committer name and defaults to current repository
2410 user receives the committer name and defaults to current repository
2410 username, date is the commit date in any format supported by
2411 username, date is the commit date in any format supported by
2411 dateutil.parsedate() and defaults to current date, extra is a dictionary of
2412 dateutil.parsedate() and defaults to current date, extra is a dictionary of
2412 metadata or is left empty.
2413 metadata or is left empty.
2413 """
2414 """
2414 def __init__(self, repo, originalctx, parents=None, text=None, user=None,
2415 def __init__(self, repo, originalctx, parents=None, text=None, user=None,
2415 date=None, extra=None, editor=False):
2416 date=None, extra=None, editor=False):
2416 if text is None:
2417 if text is None:
2417 text = originalctx.description()
2418 text = originalctx.description()
2418 super(metadataonlyctx, self).__init__(repo, text, user, date, extra)
2419 super(metadataonlyctx, self).__init__(repo, text, user, date, extra)
2419 self._rev = None
2420 self._rev = None
2420 self._node = None
2421 self._node = None
2421 self._originalctx = originalctx
2422 self._originalctx = originalctx
2422 self._manifestnode = originalctx.manifestnode()
2423 self._manifestnode = originalctx.manifestnode()
2423 if parents is None:
2424 if parents is None:
2424 parents = originalctx.parents()
2425 parents = originalctx.parents()
2425 else:
2426 else:
2426 parents = [repo[p] for p in parents if p is not None]
2427 parents = [repo[p] for p in parents if p is not None]
2427 parents = parents[:]
2428 parents = parents[:]
2428 while len(parents) < 2:
2429 while len(parents) < 2:
2429 parents.append(repo[nullid])
2430 parents.append(repo[nullid])
2430 p1, p2 = self._parents = parents
2431 p1, p2 = self._parents = parents
2431
2432
2432 # sanity check to ensure that the reused manifest parents are
2433 # sanity check to ensure that the reused manifest parents are
2433 # manifests of our commit parents
2434 # manifests of our commit parents
2434 mp1, mp2 = self.manifestctx().parents
2435 mp1, mp2 = self.manifestctx().parents
2435 if p1 != nullid and p1.manifestnode() != mp1:
2436 if p1 != nullid and p1.manifestnode() != mp1:
2436 raise RuntimeError('can\'t reuse the manifest: '
2437 raise RuntimeError('can\'t reuse the manifest: '
2437 'its p1 doesn\'t match the new ctx p1')
2438 'its p1 doesn\'t match the new ctx p1')
2438 if p2 != nullid and p2.manifestnode() != mp2:
2439 if p2 != nullid and p2.manifestnode() != mp2:
2439 raise RuntimeError('can\'t reuse the manifest: '
2440 raise RuntimeError('can\'t reuse the manifest: '
2440 'its p2 doesn\'t match the new ctx p2')
2441 'its p2 doesn\'t match the new ctx p2')
2441
2442
2442 self._files = originalctx.files()
2443 self._files = originalctx.files()
2443 self.substate = {}
2444 self.substate = {}
2444
2445
2445 if editor:
2446 if editor:
2446 self._text = editor(self._repo, self, [])
2447 self._text = editor(self._repo, self, [])
2447 self._repo.savecommitmessage(self._text)
2448 self._repo.savecommitmessage(self._text)
2448
2449
2449 def manifestnode(self):
2450 def manifestnode(self):
2450 return self._manifestnode
2451 return self._manifestnode
2451
2452
2452 @property
2453 @property
2453 def _manifestctx(self):
2454 def _manifestctx(self):
2454 return self._repo.manifestlog[self._manifestnode]
2455 return self._repo.manifestlog[self._manifestnode]
2455
2456
2456 def filectx(self, path, filelog=None):
2457 def filectx(self, path, filelog=None):
2457 return self._originalctx.filectx(path, filelog=filelog)
2458 return self._originalctx.filectx(path, filelog=filelog)
2458
2459
2459 def commit(self):
2460 def commit(self):
2460 """commit context to the repo"""
2461 """commit context to the repo"""
2461 return self._repo.commitctx(self)
2462 return self._repo.commitctx(self)
2462
2463
2463 @property
2464 @property
2464 def _manifest(self):
2465 def _manifest(self):
2465 return self._originalctx.manifest()
2466 return self._originalctx.manifest()
2466
2467
2467 @propertycache
2468 @propertycache
2468 def _status(self):
2469 def _status(self):
2469 """Calculate exact status from ``files`` specified in the ``origctx``
2470 """Calculate exact status from ``files`` specified in the ``origctx``
2470 and parents manifests.
2471 and parents manifests.
2471 """
2472 """
2472 man1 = self.p1().manifest()
2473 man1 = self.p1().manifest()
2473 p2 = self._parents[1]
2474 p2 = self._parents[1]
2474 # "1 < len(self._parents)" can't be used for checking
2475 # "1 < len(self._parents)" can't be used for checking
2475 # existence of the 2nd parent, because "metadataonlyctx._parents" is
2476 # existence of the 2nd parent, because "metadataonlyctx._parents" is
2476 # explicitly initialized by the list, of which length is 2.
2477 # explicitly initialized by the list, of which length is 2.
2477 if p2.node() != nullid:
2478 if p2.node() != nullid:
2478 man2 = p2.manifest()
2479 man2 = p2.manifest()
2479 managing = lambda f: f in man1 or f in man2
2480 managing = lambda f: f in man1 or f in man2
2480 else:
2481 else:
2481 managing = lambda f: f in man1
2482 managing = lambda f: f in man1
2482
2483
2483 modified, added, removed = [], [], []
2484 modified, added, removed = [], [], []
2484 for f in self._files:
2485 for f in self._files:
2485 if not managing(f):
2486 if not managing(f):
2486 added.append(f)
2487 added.append(f)
2487 elif f in self:
2488 elif f in self:
2488 modified.append(f)
2489 modified.append(f)
2489 else:
2490 else:
2490 removed.append(f)
2491 removed.append(f)
2491
2492
2492 return scmutil.status(modified, added, removed, [], [], [], [])
2493 return scmutil.status(modified, added, removed, [], [], [], [])
2493
2494
2494 class arbitraryfilectx(object):
2495 class arbitraryfilectx(object):
2495 """Allows you to use filectx-like functions on a file in an arbitrary
2496 """Allows you to use filectx-like functions on a file in an arbitrary
2496 location on disk, possibly not in the working directory.
2497 location on disk, possibly not in the working directory.
2497 """
2498 """
2498 def __init__(self, path, repo=None):
2499 def __init__(self, path, repo=None):
2499 # Repo is optional because contrib/simplemerge uses this class.
2500 # Repo is optional because contrib/simplemerge uses this class.
2500 self._repo = repo
2501 self._repo = repo
2501 self._path = path
2502 self._path = path
2502
2503
2503 def cmp(self, fctx):
2504 def cmp(self, fctx):
2504 # filecmp follows symlinks whereas `cmp` should not, so skip the fast
2505 # filecmp follows symlinks whereas `cmp` should not, so skip the fast
2505 # path if either side is a symlink.
2506 # path if either side is a symlink.
2506 symlinks = ('l' in self.flags() or 'l' in fctx.flags())
2507 symlinks = ('l' in self.flags() or 'l' in fctx.flags())
2507 if not symlinks and isinstance(fctx, workingfilectx) and self._repo:
2508 if not symlinks and isinstance(fctx, workingfilectx) and self._repo:
2508 # Add a fast-path for merge if both sides are disk-backed.
2509 # Add a fast-path for merge if both sides are disk-backed.
2509 # Note that filecmp uses the opposite return values (True if same)
2510 # Note that filecmp uses the opposite return values (True if same)
2510 # from our cmp functions (True if different).
2511 # from our cmp functions (True if different).
2511 return not filecmp.cmp(self.path(), self._repo.wjoin(fctx.path()))
2512 return not filecmp.cmp(self.path(), self._repo.wjoin(fctx.path()))
2512 return self.data() != fctx.data()
2513 return self.data() != fctx.data()
2513
2514
2514 def path(self):
2515 def path(self):
2515 return self._path
2516 return self._path
2516
2517
2517 def flags(self):
2518 def flags(self):
2518 return ''
2519 return ''
2519
2520
2520 def data(self):
2521 def data(self):
2521 return util.readfile(self._path)
2522 return util.readfile(self._path)
2522
2523
2523 def decodeddata(self):
2524 def decodeddata(self):
2524 with open(self._path, "rb") as f:
2525 with open(self._path, "rb") as f:
2525 return f.read()
2526 return f.read()
2526
2527
2527 def remove(self):
2528 def remove(self):
2528 util.unlink(self._path)
2529 util.unlink(self._path)
2529
2530
2530 def write(self, data, flags, **kwargs):
2531 def write(self, data, flags, **kwargs):
2531 assert not flags
2532 assert not flags
2532 with open(self._path, "w") as f:
2533 with open(self._path, "w") as f:
2533 f.write(data)
2534 f.write(data)
@@ -1,4968 +1,4974 b''
1 $ hg init a
1 $ hg init a
2 $ cd a
2 $ cd a
3 $ echo a > a
3 $ echo a > a
4 $ hg add a
4 $ hg add a
5 $ echo line 1 > b
5 $ echo line 1 > b
6 $ echo line 2 >> b
6 $ echo line 2 >> b
7 $ hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
7 $ hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
8
8
9 $ hg add b
9 $ hg add b
10 $ echo other 1 > c
10 $ echo other 1 > c
11 $ echo other 2 >> c
11 $ echo other 2 >> c
12 $ echo >> c
12 $ echo >> c
13 $ echo other 3 >> c
13 $ echo other 3 >> c
14 $ hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
14 $ hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
15
15
16 $ hg add c
16 $ hg add c
17 $ hg commit -m 'no person' -d '1200000 0' -u 'other@place'
17 $ hg commit -m 'no person' -d '1200000 0' -u 'other@place'
18 $ echo c >> c
18 $ echo c >> c
19 $ hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
19 $ hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
20
20
21 $ echo foo > .hg/branch
21 $ echo foo > .hg/branch
22 $ hg commit -m 'new branch' -d '1400000 0' -u 'person'
22 $ hg commit -m 'new branch' -d '1400000 0' -u 'person'
23
23
24 $ hg co -q 3
24 $ hg co -q 3
25 $ echo other 4 >> d
25 $ echo other 4 >> d
26 $ hg add d
26 $ hg add d
27 $ hg commit -m 'new head' -d '1500000 0' -u 'person'
27 $ hg commit -m 'new head' -d '1500000 0' -u 'person'
28
28
29 $ hg merge -q foo
29 $ hg merge -q foo
30 $ hg commit -m 'merge' -d '1500001 0' -u 'person'
30 $ hg commit -m 'merge' -d '1500001 0' -u 'person'
31
31
32 Test arithmetic operators have the right precedence:
32 Test arithmetic operators have the right precedence:
33
33
34 $ hg log -l 1 -T '{date(date, "%Y") + 5 * 10} {date(date, "%Y") - 2 * 3}\n'
34 $ hg log -l 1 -T '{date(date, "%Y") + 5 * 10} {date(date, "%Y") - 2 * 3}\n'
35 2020 1964
35 2020 1964
36 $ hg log -l 1 -T '{date(date, "%Y") * 5 + 10} {date(date, "%Y") * 3 - 2}\n'
36 $ hg log -l 1 -T '{date(date, "%Y") * 5 + 10} {date(date, "%Y") * 3 - 2}\n'
37 9860 5908
37 9860 5908
38
38
39 Test division:
39 Test division:
40
40
41 $ hg debugtemplate -r0 -v '{5 / 2} {mod(5, 2)}\n'
41 $ hg debugtemplate -r0 -v '{5 / 2} {mod(5, 2)}\n'
42 (template
42 (template
43 (/
43 (/
44 (integer '5')
44 (integer '5')
45 (integer '2'))
45 (integer '2'))
46 (string ' ')
46 (string ' ')
47 (func
47 (func
48 (symbol 'mod')
48 (symbol 'mod')
49 (list
49 (list
50 (integer '5')
50 (integer '5')
51 (integer '2')))
51 (integer '2')))
52 (string '\n'))
52 (string '\n'))
53 2 1
53 2 1
54 $ hg debugtemplate -r0 -v '{5 / -2} {mod(5, -2)}\n'
54 $ hg debugtemplate -r0 -v '{5 / -2} {mod(5, -2)}\n'
55 (template
55 (template
56 (/
56 (/
57 (integer '5')
57 (integer '5')
58 (negate
58 (negate
59 (integer '2')))
59 (integer '2')))
60 (string ' ')
60 (string ' ')
61 (func
61 (func
62 (symbol 'mod')
62 (symbol 'mod')
63 (list
63 (list
64 (integer '5')
64 (integer '5')
65 (negate
65 (negate
66 (integer '2'))))
66 (integer '2'))))
67 (string '\n'))
67 (string '\n'))
68 -3 -1
68 -3 -1
69 $ hg debugtemplate -r0 -v '{-5 / 2} {mod(-5, 2)}\n'
69 $ hg debugtemplate -r0 -v '{-5 / 2} {mod(-5, 2)}\n'
70 (template
70 (template
71 (/
71 (/
72 (negate
72 (negate
73 (integer '5'))
73 (integer '5'))
74 (integer '2'))
74 (integer '2'))
75 (string ' ')
75 (string ' ')
76 (func
76 (func
77 (symbol 'mod')
77 (symbol 'mod')
78 (list
78 (list
79 (negate
79 (negate
80 (integer '5'))
80 (integer '5'))
81 (integer '2')))
81 (integer '2')))
82 (string '\n'))
82 (string '\n'))
83 -3 1
83 -3 1
84 $ hg debugtemplate -r0 -v '{-5 / -2} {mod(-5, -2)}\n'
84 $ hg debugtemplate -r0 -v '{-5 / -2} {mod(-5, -2)}\n'
85 (template
85 (template
86 (/
86 (/
87 (negate
87 (negate
88 (integer '5'))
88 (integer '5'))
89 (negate
89 (negate
90 (integer '2')))
90 (integer '2')))
91 (string ' ')
91 (string ' ')
92 (func
92 (func
93 (symbol 'mod')
93 (symbol 'mod')
94 (list
94 (list
95 (negate
95 (negate
96 (integer '5'))
96 (integer '5'))
97 (negate
97 (negate
98 (integer '2'))))
98 (integer '2'))))
99 (string '\n'))
99 (string '\n'))
100 2 -1
100 2 -1
101
101
102 Filters bind closer than arithmetic:
102 Filters bind closer than arithmetic:
103
103
104 $ hg debugtemplate -r0 -v '{revset(".")|count - 1}\n'
104 $ hg debugtemplate -r0 -v '{revset(".")|count - 1}\n'
105 (template
105 (template
106 (-
106 (-
107 (|
107 (|
108 (func
108 (func
109 (symbol 'revset')
109 (symbol 'revset')
110 (string '.'))
110 (string '.'))
111 (symbol 'count'))
111 (symbol 'count'))
112 (integer '1'))
112 (integer '1'))
113 (string '\n'))
113 (string '\n'))
114 0
114 0
115
115
116 But negate binds closer still:
116 But negate binds closer still:
117
117
118 $ hg debugtemplate -r0 -v '{1-3|stringify}\n'
118 $ hg debugtemplate -r0 -v '{1-3|stringify}\n'
119 (template
119 (template
120 (-
120 (-
121 (integer '1')
121 (integer '1')
122 (|
122 (|
123 (integer '3')
123 (integer '3')
124 (symbol 'stringify')))
124 (symbol 'stringify')))
125 (string '\n'))
125 (string '\n'))
126 hg: parse error: arithmetic only defined on integers
126 hg: parse error: arithmetic only defined on integers
127 [255]
127 [255]
128 $ hg debugtemplate -r0 -v '{-3|stringify}\n'
128 $ hg debugtemplate -r0 -v '{-3|stringify}\n'
129 (template
129 (template
130 (|
130 (|
131 (negate
131 (negate
132 (integer '3'))
132 (integer '3'))
133 (symbol 'stringify'))
133 (symbol 'stringify'))
134 (string '\n'))
134 (string '\n'))
135 -3
135 -3
136
136
137 Filters bind as close as map operator:
137 Filters bind as close as map operator:
138
138
139 $ hg debugtemplate -r0 -v '{desc|splitlines % "{line}\n"}'
139 $ hg debugtemplate -r0 -v '{desc|splitlines % "{line}\n"}'
140 (template
140 (template
141 (%
141 (%
142 (|
142 (|
143 (symbol 'desc')
143 (symbol 'desc')
144 (symbol 'splitlines'))
144 (symbol 'splitlines'))
145 (template
145 (template
146 (symbol 'line')
146 (symbol 'line')
147 (string '\n'))))
147 (string '\n'))))
148 line 1
148 line 1
149 line 2
149 line 2
150
150
151 Keyword arguments:
151 Keyword arguments:
152
152
153 $ hg debugtemplate -r0 -v '{foo=bar|baz}'
153 $ hg debugtemplate -r0 -v '{foo=bar|baz}'
154 (template
154 (template
155 (keyvalue
155 (keyvalue
156 (symbol 'foo')
156 (symbol 'foo')
157 (|
157 (|
158 (symbol 'bar')
158 (symbol 'bar')
159 (symbol 'baz'))))
159 (symbol 'baz'))))
160 hg: parse error: can't use a key-value pair in this context
160 hg: parse error: can't use a key-value pair in this context
161 [255]
161 [255]
162
162
163 $ hg debugtemplate '{pad("foo", width=10, left=true)}\n'
163 $ hg debugtemplate '{pad("foo", width=10, left=true)}\n'
164 foo
164 foo
165
165
166 Call function which takes named arguments by filter syntax:
166 Call function which takes named arguments by filter syntax:
167
167
168 $ hg debugtemplate '{" "|separate}'
168 $ hg debugtemplate '{" "|separate}'
169 $ hg debugtemplate '{("not", "an", "argument", "list")|separate}'
169 $ hg debugtemplate '{("not", "an", "argument", "list")|separate}'
170 hg: parse error: unknown method 'list'
170 hg: parse error: unknown method 'list'
171 [255]
171 [255]
172
172
173 Second branch starting at nullrev:
173 Second branch starting at nullrev:
174
174
175 $ hg update null
175 $ hg update null
176 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
176 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
177 $ echo second > second
177 $ echo second > second
178 $ hg add second
178 $ hg add second
179 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
179 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
180 created new head
180 created new head
181
181
182 $ echo third > third
182 $ echo third > third
183 $ hg add third
183 $ hg add third
184 $ hg mv second fourth
184 $ hg mv second fourth
185 $ hg commit -m third -d "2020-01-01 10:01"
185 $ hg commit -m third -d "2020-01-01 10:01"
186
186
187 $ hg log --template '{join(file_copies, ",\n")}\n' -r .
187 $ hg log --template '{join(file_copies, ",\n")}\n' -r .
188 fourth (second)
188 fourth (second)
189 $ hg log -T '{file_copies % "{source} -> {name}\n"}' -r .
189 $ hg log -T '{file_copies % "{source} -> {name}\n"}' -r .
190 second -> fourth
190 second -> fourth
191 $ hg log -T '{rev} {ifcontains("fourth", file_copies, "t", "f")}\n' -r .:7
191 $ hg log -T '{rev} {ifcontains("fourth", file_copies, "t", "f")}\n' -r .:7
192 8 t
192 8 t
193 7 f
193 7 f
194
194
195 Working-directory revision has special identifiers, though they are still
195 Working-directory revision has special identifiers, though they are still
196 experimental:
196 experimental:
197
197
198 $ hg log -r 'wdir()' -T '{rev}:{node}\n'
198 $ hg log -r 'wdir()' -T '{rev}:{node}\n'
199 2147483647:ffffffffffffffffffffffffffffffffffffffff
199 2147483647:ffffffffffffffffffffffffffffffffffffffff
200
200
201 Some keywords are invalid for working-directory revision, but they should
201 Some keywords are invalid for working-directory revision, but they should
202 never cause crash:
202 never cause crash:
203
203
204 $ hg log -r 'wdir()' -T '{manifest}\n'
204 $ hg log -r 'wdir()' -T '{manifest}\n'
205
205
206
206
207 Internal resources shouldn't be exposed (issue5699):
207 Internal resources shouldn't be exposed (issue5699):
208
208
209 $ hg log -r. -T '{cache}{ctx}{repo}{revcache}{templ}{ui}'
209 $ hg log -r. -T '{cache}{ctx}{repo}{revcache}{templ}{ui}'
210
210
211 Never crash on internal resource not available:
211 Never crash on internal resource not available:
212
212
213 $ hg --cwd .. debugtemplate '{"c0bebeef"|shortest}\n'
213 $ hg --cwd .. debugtemplate '{"c0bebeef"|shortest}\n'
214 abort: template resource not available: ctx
214 abort: template resource not available: ctx
215 [255]
215 [255]
216
216
217 $ hg config -T '{author}'
217 $ hg config -T '{author}'
218
218
219 Quoting for ui.logtemplate
219 Quoting for ui.logtemplate
220
220
221 $ hg tip --config "ui.logtemplate={rev}\n"
221 $ hg tip --config "ui.logtemplate={rev}\n"
222 8
222 8
223 $ hg tip --config "ui.logtemplate='{rev}\n'"
223 $ hg tip --config "ui.logtemplate='{rev}\n'"
224 8
224 8
225 $ hg tip --config 'ui.logtemplate="{rev}\n"'
225 $ hg tip --config 'ui.logtemplate="{rev}\n"'
226 8
226 8
227 $ hg tip --config 'ui.logtemplate=n{rev}\n'
227 $ hg tip --config 'ui.logtemplate=n{rev}\n'
228 n8
228 n8
229
229
230 Make sure user/global hgrc does not affect tests
230 Make sure user/global hgrc does not affect tests
231
231
232 $ echo '[ui]' > .hg/hgrc
232 $ echo '[ui]' > .hg/hgrc
233 $ echo 'logtemplate =' >> .hg/hgrc
233 $ echo 'logtemplate =' >> .hg/hgrc
234 $ echo 'style =' >> .hg/hgrc
234 $ echo 'style =' >> .hg/hgrc
235
235
236 Add some simple styles to settings
236 Add some simple styles to settings
237
237
238 $ cat <<'EOF' >> .hg/hgrc
238 $ cat <<'EOF' >> .hg/hgrc
239 > [templates]
239 > [templates]
240 > simple = "{rev}\n"
240 > simple = "{rev}\n"
241 > simple2 = {rev}\n
241 > simple2 = {rev}\n
242 > rev = "should not precede {rev} keyword\n"
242 > rev = "should not precede {rev} keyword\n"
243 > EOF
243 > EOF
244
244
245 $ hg log -l1 -Tsimple
245 $ hg log -l1 -Tsimple
246 8
246 8
247 $ hg log -l1 -Tsimple2
247 $ hg log -l1 -Tsimple2
248 8
248 8
249 $ hg log -l1 -Trev
249 $ hg log -l1 -Trev
250 should not precede 8 keyword
250 should not precede 8 keyword
251 $ hg log -l1 -T '{simple}'
251 $ hg log -l1 -T '{simple}'
252 8
252 8
253
253
254 Map file shouldn't see user templates:
254 Map file shouldn't see user templates:
255
255
256 $ cat <<EOF > tmpl
256 $ cat <<EOF > tmpl
257 > changeset = 'nothing expanded:{simple}\n'
257 > changeset = 'nothing expanded:{simple}\n'
258 > EOF
258 > EOF
259 $ hg log -l1 --style ./tmpl
259 $ hg log -l1 --style ./tmpl
260 nothing expanded:
260 nothing expanded:
261
261
262 Test templates and style maps in files:
262 Test templates and style maps in files:
263
263
264 $ echo "{rev}" > tmpl
264 $ echo "{rev}" > tmpl
265 $ hg log -l1 -T./tmpl
265 $ hg log -l1 -T./tmpl
266 8
266 8
267 $ hg log -l1 -Tblah/blah
267 $ hg log -l1 -Tblah/blah
268 blah/blah (no-eol)
268 blah/blah (no-eol)
269
269
270 $ printf 'changeset = "{rev}\\n"\n' > map-simple
270 $ printf 'changeset = "{rev}\\n"\n' > map-simple
271 $ hg log -l1 -T./map-simple
271 $ hg log -l1 -T./map-simple
272 8
272 8
273
273
274 a map file may have [templates] and [templatealias] sections:
274 a map file may have [templates] and [templatealias] sections:
275
275
276 $ cat <<'EOF' > map-simple
276 $ cat <<'EOF' > map-simple
277 > [templates]
277 > [templates]
278 > changeset = "{a}\n"
278 > changeset = "{a}\n"
279 > [templatealias]
279 > [templatealias]
280 > a = rev
280 > a = rev
281 > EOF
281 > EOF
282 $ hg log -l1 -T./map-simple
282 $ hg log -l1 -T./map-simple
283 8
283 8
284
284
285 so it can be included in hgrc
285 so it can be included in hgrc
286
286
287 $ cat <<EOF > myhgrc
287 $ cat <<EOF > myhgrc
288 > %include $HGRCPATH
288 > %include $HGRCPATH
289 > %include map-simple
289 > %include map-simple
290 > [templates]
290 > [templates]
291 > foo = "{changeset}"
291 > foo = "{changeset}"
292 > EOF
292 > EOF
293 $ HGRCPATH=./myhgrc hg log -l1 -Tfoo
293 $ HGRCPATH=./myhgrc hg log -l1 -Tfoo
294 8
294 8
295 $ HGRCPATH=./myhgrc hg log -l1 -T'{a}\n'
295 $ HGRCPATH=./myhgrc hg log -l1 -T'{a}\n'
296 8
296 8
297
297
298 Test template map inheritance
298 Test template map inheritance
299
299
300 $ echo "__base__ = map-cmdline.default" > map-simple
300 $ echo "__base__ = map-cmdline.default" > map-simple
301 $ printf 'cset = "changeset: ***{rev}***\\n"\n' >> map-simple
301 $ printf 'cset = "changeset: ***{rev}***\\n"\n' >> map-simple
302 $ hg log -l1 -T./map-simple
302 $ hg log -l1 -T./map-simple
303 changeset: ***8***
303 changeset: ***8***
304 tag: tip
304 tag: tip
305 user: test
305 user: test
306 date: Wed Jan 01 10:01:00 2020 +0000
306 date: Wed Jan 01 10:01:00 2020 +0000
307 summary: third
307 summary: third
308
308
309
309
310 Test docheader, docfooter and separator in template map
310 Test docheader, docfooter and separator in template map
311
311
312 $ cat <<'EOF' > map-myjson
312 $ cat <<'EOF' > map-myjson
313 > docheader = '\{\n'
313 > docheader = '\{\n'
314 > docfooter = '\n}\n'
314 > docfooter = '\n}\n'
315 > separator = ',\n'
315 > separator = ',\n'
316 > changeset = ' {dict(rev, node|short)|json}'
316 > changeset = ' {dict(rev, node|short)|json}'
317 > EOF
317 > EOF
318 $ hg log -l2 -T./map-myjson
318 $ hg log -l2 -T./map-myjson
319 {
319 {
320 {"node": "95c24699272e", "rev": 8},
320 {"node": "95c24699272e", "rev": 8},
321 {"node": "29114dbae42b", "rev": 7}
321 {"node": "29114dbae42b", "rev": 7}
322 }
322 }
323
323
324 Test docheader, docfooter and separator in [templates] section
324 Test docheader, docfooter and separator in [templates] section
325
325
326 $ cat <<'EOF' >> .hg/hgrc
326 $ cat <<'EOF' >> .hg/hgrc
327 > [templates]
327 > [templates]
328 > myjson = ' {dict(rev, node|short)|json}'
328 > myjson = ' {dict(rev, node|short)|json}'
329 > myjson:docheader = '\{\n'
329 > myjson:docheader = '\{\n'
330 > myjson:docfooter = '\n}\n'
330 > myjson:docfooter = '\n}\n'
331 > myjson:separator = ',\n'
331 > myjson:separator = ',\n'
332 > :docheader = 'should not be selected as a docheader for literal templates\n'
332 > :docheader = 'should not be selected as a docheader for literal templates\n'
333 > EOF
333 > EOF
334 $ hg log -l2 -Tmyjson
334 $ hg log -l2 -Tmyjson
335 {
335 {
336 {"node": "95c24699272e", "rev": 8},
336 {"node": "95c24699272e", "rev": 8},
337 {"node": "29114dbae42b", "rev": 7}
337 {"node": "29114dbae42b", "rev": 7}
338 }
338 }
339 $ hg log -l1 -T'{rev}\n'
339 $ hg log -l1 -T'{rev}\n'
340 8
340 8
341
341
342 Template should precede style option
342 Template should precede style option
343
343
344 $ hg log -l1 --style default -T '{rev}\n'
344 $ hg log -l1 --style default -T '{rev}\n'
345 8
345 8
346
346
347 Add a commit with empty description, to ensure that the templates
347 Add a commit with empty description, to ensure that the templates
348 below will omit the description line.
348 below will omit the description line.
349
349
350 $ echo c >> c
350 $ echo c >> c
351 $ hg add c
351 $ hg add c
352 $ hg commit -qm ' '
352 $ hg commit -qm ' '
353
353
354 Default style is like normal output. Phases style should be the same
354 Default style is like normal output. Phases style should be the same
355 as default style, except for extra phase lines.
355 as default style, except for extra phase lines.
356
356
357 $ hg log > log.out
357 $ hg log > log.out
358 $ hg log --style default > style.out
358 $ hg log --style default > style.out
359 $ cmp log.out style.out || diff -u log.out style.out
359 $ cmp log.out style.out || diff -u log.out style.out
360 $ hg log -T phases > phases.out
360 $ hg log -T phases > phases.out
361 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
361 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
362 +phase: draft
362 +phase: draft
363 +phase: draft
363 +phase: draft
364 +phase: draft
364 +phase: draft
365 +phase: draft
365 +phase: draft
366 +phase: draft
366 +phase: draft
367 +phase: draft
367 +phase: draft
368 +phase: draft
368 +phase: draft
369 +phase: draft
369 +phase: draft
370 +phase: draft
370 +phase: draft
371 +phase: draft
371 +phase: draft
372
372
373 $ hg log -v > log.out
373 $ hg log -v > log.out
374 $ hg log -v --style default > style.out
374 $ hg log -v --style default > style.out
375 $ cmp log.out style.out || diff -u log.out style.out
375 $ cmp log.out style.out || diff -u log.out style.out
376 $ hg log -v -T phases > phases.out
376 $ hg log -v -T phases > phases.out
377 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
377 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
378 +phase: draft
378 +phase: draft
379 +phase: draft
379 +phase: draft
380 +phase: draft
380 +phase: draft
381 +phase: draft
381 +phase: draft
382 +phase: draft
382 +phase: draft
383 +phase: draft
383 +phase: draft
384 +phase: draft
384 +phase: draft
385 +phase: draft
385 +phase: draft
386 +phase: draft
386 +phase: draft
387 +phase: draft
387 +phase: draft
388
388
389 $ hg log -q > log.out
389 $ hg log -q > log.out
390 $ hg log -q --style default > style.out
390 $ hg log -q --style default > style.out
391 $ cmp log.out style.out || diff -u log.out style.out
391 $ cmp log.out style.out || diff -u log.out style.out
392 $ hg log -q -T phases > phases.out
392 $ hg log -q -T phases > phases.out
393 $ cmp log.out phases.out || diff -u log.out phases.out
393 $ cmp log.out phases.out || diff -u log.out phases.out
394
394
395 $ hg log --debug > log.out
395 $ hg log --debug > log.out
396 $ hg log --debug --style default > style.out
396 $ hg log --debug --style default > style.out
397 $ cmp log.out style.out || diff -u log.out style.out
397 $ cmp log.out style.out || diff -u log.out style.out
398 $ hg log --debug -T phases > phases.out
398 $ hg log --debug -T phases > phases.out
399 $ cmp log.out phases.out || diff -u log.out phases.out
399 $ cmp log.out phases.out || diff -u log.out phases.out
400
400
401 Default style of working-directory revision should also be the same (but
401 Default style of working-directory revision should also be the same (but
402 date may change while running tests):
402 date may change while running tests):
403
403
404 $ hg log -r 'wdir()' | sed 's|^date:.*|date:|' > log.out
404 $ hg log -r 'wdir()' | sed 's|^date:.*|date:|' > log.out
405 $ hg log -r 'wdir()' --style default | sed 's|^date:.*|date:|' > style.out
405 $ hg log -r 'wdir()' --style default | sed 's|^date:.*|date:|' > style.out
406 $ cmp log.out style.out || diff -u log.out style.out
406 $ cmp log.out style.out || diff -u log.out style.out
407
407
408 $ hg log -r 'wdir()' -v | sed 's|^date:.*|date:|' > log.out
408 $ hg log -r 'wdir()' -v | sed 's|^date:.*|date:|' > log.out
409 $ hg log -r 'wdir()' -v --style default | sed 's|^date:.*|date:|' > style.out
409 $ hg log -r 'wdir()' -v --style default | sed 's|^date:.*|date:|' > style.out
410 $ cmp log.out style.out || diff -u log.out style.out
410 $ cmp log.out style.out || diff -u log.out style.out
411
411
412 $ hg log -r 'wdir()' -q > log.out
412 $ hg log -r 'wdir()' -q > log.out
413 $ hg log -r 'wdir()' -q --style default > style.out
413 $ hg log -r 'wdir()' -q --style default > style.out
414 $ cmp log.out style.out || diff -u log.out style.out
414 $ cmp log.out style.out || diff -u log.out style.out
415
415
416 $ hg log -r 'wdir()' --debug | sed 's|^date:.*|date:|' > log.out
416 $ hg log -r 'wdir()' --debug | sed 's|^date:.*|date:|' > log.out
417 $ hg log -r 'wdir()' --debug --style default \
417 $ hg log -r 'wdir()' --debug --style default \
418 > | sed 's|^date:.*|date:|' > style.out
418 > | sed 's|^date:.*|date:|' > style.out
419 $ cmp log.out style.out || diff -u log.out style.out
419 $ cmp log.out style.out || diff -u log.out style.out
420
420
421 Default style should also preserve color information (issue2866):
421 Default style should also preserve color information (issue2866):
422
422
423 $ cp $HGRCPATH $HGRCPATH-bak
423 $ cp $HGRCPATH $HGRCPATH-bak
424 $ cat <<EOF >> $HGRCPATH
424 $ cat <<EOF >> $HGRCPATH
425 > [extensions]
425 > [extensions]
426 > color=
426 > color=
427 > EOF
427 > EOF
428
428
429 $ hg --color=debug log > log.out
429 $ hg --color=debug log > log.out
430 $ hg --color=debug log --style default > style.out
430 $ hg --color=debug log --style default > style.out
431 $ cmp log.out style.out || diff -u log.out style.out
431 $ cmp log.out style.out || diff -u log.out style.out
432 $ hg --color=debug log -T phases > phases.out
432 $ hg --color=debug log -T phases > phases.out
433 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
433 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
434 +[log.phase|phase: draft]
434 +[log.phase|phase: draft]
435 +[log.phase|phase: draft]
435 +[log.phase|phase: draft]
436 +[log.phase|phase: draft]
436 +[log.phase|phase: draft]
437 +[log.phase|phase: draft]
437 +[log.phase|phase: draft]
438 +[log.phase|phase: draft]
438 +[log.phase|phase: draft]
439 +[log.phase|phase: draft]
439 +[log.phase|phase: draft]
440 +[log.phase|phase: draft]
440 +[log.phase|phase: draft]
441 +[log.phase|phase: draft]
441 +[log.phase|phase: draft]
442 +[log.phase|phase: draft]
442 +[log.phase|phase: draft]
443 +[log.phase|phase: draft]
443 +[log.phase|phase: draft]
444
444
445 $ hg --color=debug -v log > log.out
445 $ hg --color=debug -v log > log.out
446 $ hg --color=debug -v log --style default > style.out
446 $ hg --color=debug -v log --style default > style.out
447 $ cmp log.out style.out || diff -u log.out style.out
447 $ cmp log.out style.out || diff -u log.out style.out
448 $ hg --color=debug -v log -T phases > phases.out
448 $ hg --color=debug -v log -T phases > phases.out
449 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
449 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
450 +[log.phase|phase: draft]
450 +[log.phase|phase: draft]
451 +[log.phase|phase: draft]
451 +[log.phase|phase: draft]
452 +[log.phase|phase: draft]
452 +[log.phase|phase: draft]
453 +[log.phase|phase: draft]
453 +[log.phase|phase: draft]
454 +[log.phase|phase: draft]
454 +[log.phase|phase: draft]
455 +[log.phase|phase: draft]
455 +[log.phase|phase: draft]
456 +[log.phase|phase: draft]
456 +[log.phase|phase: draft]
457 +[log.phase|phase: draft]
457 +[log.phase|phase: draft]
458 +[log.phase|phase: draft]
458 +[log.phase|phase: draft]
459 +[log.phase|phase: draft]
459 +[log.phase|phase: draft]
460
460
461 $ hg --color=debug -q log > log.out
461 $ hg --color=debug -q log > log.out
462 $ hg --color=debug -q log --style default > style.out
462 $ hg --color=debug -q log --style default > style.out
463 $ cmp log.out style.out || diff -u log.out style.out
463 $ cmp log.out style.out || diff -u log.out style.out
464 $ hg --color=debug -q log -T phases > phases.out
464 $ hg --color=debug -q log -T phases > phases.out
465 $ cmp log.out phases.out || diff -u log.out phases.out
465 $ cmp log.out phases.out || diff -u log.out phases.out
466
466
467 $ hg --color=debug --debug log > log.out
467 $ hg --color=debug --debug log > log.out
468 $ hg --color=debug --debug log --style default > style.out
468 $ hg --color=debug --debug log --style default > style.out
469 $ cmp log.out style.out || diff -u log.out style.out
469 $ cmp log.out style.out || diff -u log.out style.out
470 $ hg --color=debug --debug log -T phases > phases.out
470 $ hg --color=debug --debug log -T phases > phases.out
471 $ cmp log.out phases.out || diff -u log.out phases.out
471 $ cmp log.out phases.out || diff -u log.out phases.out
472
472
473 $ mv $HGRCPATH-bak $HGRCPATH
473 $ mv $HGRCPATH-bak $HGRCPATH
474
474
475 Remove commit with empty commit message, so as to not pollute further
475 Remove commit with empty commit message, so as to not pollute further
476 tests.
476 tests.
477
477
478 $ hg --config extensions.strip= strip -q .
478 $ hg --config extensions.strip= strip -q .
479
479
480 Revision with no copies (used to print a traceback):
480 Revision with no copies (used to print a traceback):
481
481
482 $ hg tip -v --template '\n'
482 $ hg tip -v --template '\n'
483
483
484
484
485 Compact style works:
485 Compact style works:
486
486
487 $ hg log -Tcompact
487 $ hg log -Tcompact
488 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
488 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
489 third
489 third
490
490
491 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
491 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
492 second
492 second
493
493
494 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
494 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
495 merge
495 merge
496
496
497 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
497 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
498 new head
498 new head
499
499
500 4 bbe44766e73d 1970-01-17 04:53 +0000 person
500 4 bbe44766e73d 1970-01-17 04:53 +0000 person
501 new branch
501 new branch
502
502
503 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
503 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
504 no user, no domain
504 no user, no domain
505
505
506 2 97054abb4ab8 1970-01-14 21:20 +0000 other
506 2 97054abb4ab8 1970-01-14 21:20 +0000 other
507 no person
507 no person
508
508
509 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
509 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
510 other 1
510 other 1
511
511
512 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
512 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
513 line 1
513 line 1
514
514
515
515
516 $ hg log -v --style compact
516 $ hg log -v --style compact
517 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
517 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
518 third
518 third
519
519
520 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
520 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
521 second
521 second
522
522
523 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
523 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
524 merge
524 merge
525
525
526 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
526 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
527 new head
527 new head
528
528
529 4 bbe44766e73d 1970-01-17 04:53 +0000 person
529 4 bbe44766e73d 1970-01-17 04:53 +0000 person
530 new branch
530 new branch
531
531
532 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
532 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
533 no user, no domain
533 no user, no domain
534
534
535 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
535 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
536 no person
536 no person
537
537
538 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
538 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
539 other 1
539 other 1
540 other 2
540 other 2
541
541
542 other 3
542 other 3
543
543
544 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
544 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
545 line 1
545 line 1
546 line 2
546 line 2
547
547
548
548
549 $ hg log --debug --style compact
549 $ hg log --debug --style compact
550 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
550 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
551 third
551 third
552
552
553 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
553 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
554 second
554 second
555
555
556 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
556 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
557 merge
557 merge
558
558
559 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
559 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
560 new head
560 new head
561
561
562 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
562 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
563 new branch
563 new branch
564
564
565 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
565 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
566 no user, no domain
566 no user, no domain
567
567
568 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
568 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
569 no person
569 no person
570
570
571 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
571 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
572 other 1
572 other 1
573 other 2
573 other 2
574
574
575 other 3
575 other 3
576
576
577 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
577 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
578 line 1
578 line 1
579 line 2
579 line 2
580
580
581
581
582 Test xml styles:
582 Test xml styles:
583
583
584 $ hg log --style xml -r 'not all()'
584 $ hg log --style xml -r 'not all()'
585 <?xml version="1.0"?>
585 <?xml version="1.0"?>
586 <log>
586 <log>
587 </log>
587 </log>
588
588
589 $ hg log --style xml
589 $ hg log --style xml
590 <?xml version="1.0"?>
590 <?xml version="1.0"?>
591 <log>
591 <log>
592 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
592 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
593 <tag>tip</tag>
593 <tag>tip</tag>
594 <author email="test">test</author>
594 <author email="test">test</author>
595 <date>2020-01-01T10:01:00+00:00</date>
595 <date>2020-01-01T10:01:00+00:00</date>
596 <msg xml:space="preserve">third</msg>
596 <msg xml:space="preserve">third</msg>
597 </logentry>
597 </logentry>
598 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
598 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
599 <parent revision="-1" node="0000000000000000000000000000000000000000" />
599 <parent revision="-1" node="0000000000000000000000000000000000000000" />
600 <author email="user@hostname">User Name</author>
600 <author email="user@hostname">User Name</author>
601 <date>1970-01-12T13:46:40+00:00</date>
601 <date>1970-01-12T13:46:40+00:00</date>
602 <msg xml:space="preserve">second</msg>
602 <msg xml:space="preserve">second</msg>
603 </logentry>
603 </logentry>
604 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
604 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
605 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
605 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
606 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
606 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
607 <author email="person">person</author>
607 <author email="person">person</author>
608 <date>1970-01-18T08:40:01+00:00</date>
608 <date>1970-01-18T08:40:01+00:00</date>
609 <msg xml:space="preserve">merge</msg>
609 <msg xml:space="preserve">merge</msg>
610 </logentry>
610 </logentry>
611 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
611 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
612 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
612 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
613 <author email="person">person</author>
613 <author email="person">person</author>
614 <date>1970-01-18T08:40:00+00:00</date>
614 <date>1970-01-18T08:40:00+00:00</date>
615 <msg xml:space="preserve">new head</msg>
615 <msg xml:space="preserve">new head</msg>
616 </logentry>
616 </logentry>
617 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
617 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
618 <branch>foo</branch>
618 <branch>foo</branch>
619 <author email="person">person</author>
619 <author email="person">person</author>
620 <date>1970-01-17T04:53:20+00:00</date>
620 <date>1970-01-17T04:53:20+00:00</date>
621 <msg xml:space="preserve">new branch</msg>
621 <msg xml:space="preserve">new branch</msg>
622 </logentry>
622 </logentry>
623 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
623 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
624 <author email="person">person</author>
624 <author email="person">person</author>
625 <date>1970-01-16T01:06:40+00:00</date>
625 <date>1970-01-16T01:06:40+00:00</date>
626 <msg xml:space="preserve">no user, no domain</msg>
626 <msg xml:space="preserve">no user, no domain</msg>
627 </logentry>
627 </logentry>
628 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
628 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
629 <author email="other@place">other</author>
629 <author email="other@place">other</author>
630 <date>1970-01-14T21:20:00+00:00</date>
630 <date>1970-01-14T21:20:00+00:00</date>
631 <msg xml:space="preserve">no person</msg>
631 <msg xml:space="preserve">no person</msg>
632 </logentry>
632 </logentry>
633 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
633 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
634 <author email="other@place">A. N. Other</author>
634 <author email="other@place">A. N. Other</author>
635 <date>1970-01-13T17:33:20+00:00</date>
635 <date>1970-01-13T17:33:20+00:00</date>
636 <msg xml:space="preserve">other 1
636 <msg xml:space="preserve">other 1
637 other 2
637 other 2
638
638
639 other 3</msg>
639 other 3</msg>
640 </logentry>
640 </logentry>
641 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
641 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
642 <author email="user@hostname">User Name</author>
642 <author email="user@hostname">User Name</author>
643 <date>1970-01-12T13:46:40+00:00</date>
643 <date>1970-01-12T13:46:40+00:00</date>
644 <msg xml:space="preserve">line 1
644 <msg xml:space="preserve">line 1
645 line 2</msg>
645 line 2</msg>
646 </logentry>
646 </logentry>
647 </log>
647 </log>
648
648
649 $ hg log -v --style xml
649 $ hg log -v --style xml
650 <?xml version="1.0"?>
650 <?xml version="1.0"?>
651 <log>
651 <log>
652 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
652 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
653 <tag>tip</tag>
653 <tag>tip</tag>
654 <author email="test">test</author>
654 <author email="test">test</author>
655 <date>2020-01-01T10:01:00+00:00</date>
655 <date>2020-01-01T10:01:00+00:00</date>
656 <msg xml:space="preserve">third</msg>
656 <msg xml:space="preserve">third</msg>
657 <paths>
657 <paths>
658 <path action="A">fourth</path>
658 <path action="A">fourth</path>
659 <path action="A">third</path>
659 <path action="A">third</path>
660 <path action="R">second</path>
660 <path action="R">second</path>
661 </paths>
661 </paths>
662 <copies>
662 <copies>
663 <copy source="second">fourth</copy>
663 <copy source="second">fourth</copy>
664 </copies>
664 </copies>
665 </logentry>
665 </logentry>
666 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
666 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
667 <parent revision="-1" node="0000000000000000000000000000000000000000" />
667 <parent revision="-1" node="0000000000000000000000000000000000000000" />
668 <author email="user@hostname">User Name</author>
668 <author email="user@hostname">User Name</author>
669 <date>1970-01-12T13:46:40+00:00</date>
669 <date>1970-01-12T13:46:40+00:00</date>
670 <msg xml:space="preserve">second</msg>
670 <msg xml:space="preserve">second</msg>
671 <paths>
671 <paths>
672 <path action="A">second</path>
672 <path action="A">second</path>
673 </paths>
673 </paths>
674 </logentry>
674 </logentry>
675 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
675 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
676 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
676 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
677 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
677 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
678 <author email="person">person</author>
678 <author email="person">person</author>
679 <date>1970-01-18T08:40:01+00:00</date>
679 <date>1970-01-18T08:40:01+00:00</date>
680 <msg xml:space="preserve">merge</msg>
680 <msg xml:space="preserve">merge</msg>
681 <paths>
681 <paths>
682 </paths>
682 </paths>
683 </logentry>
683 </logentry>
684 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
684 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
685 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
685 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
686 <author email="person">person</author>
686 <author email="person">person</author>
687 <date>1970-01-18T08:40:00+00:00</date>
687 <date>1970-01-18T08:40:00+00:00</date>
688 <msg xml:space="preserve">new head</msg>
688 <msg xml:space="preserve">new head</msg>
689 <paths>
689 <paths>
690 <path action="A">d</path>
690 <path action="A">d</path>
691 </paths>
691 </paths>
692 </logentry>
692 </logentry>
693 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
693 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
694 <branch>foo</branch>
694 <branch>foo</branch>
695 <author email="person">person</author>
695 <author email="person">person</author>
696 <date>1970-01-17T04:53:20+00:00</date>
696 <date>1970-01-17T04:53:20+00:00</date>
697 <msg xml:space="preserve">new branch</msg>
697 <msg xml:space="preserve">new branch</msg>
698 <paths>
698 <paths>
699 </paths>
699 </paths>
700 </logentry>
700 </logentry>
701 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
701 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
702 <author email="person">person</author>
702 <author email="person">person</author>
703 <date>1970-01-16T01:06:40+00:00</date>
703 <date>1970-01-16T01:06:40+00:00</date>
704 <msg xml:space="preserve">no user, no domain</msg>
704 <msg xml:space="preserve">no user, no domain</msg>
705 <paths>
705 <paths>
706 <path action="M">c</path>
706 <path action="M">c</path>
707 </paths>
707 </paths>
708 </logentry>
708 </logentry>
709 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
709 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
710 <author email="other@place">other</author>
710 <author email="other@place">other</author>
711 <date>1970-01-14T21:20:00+00:00</date>
711 <date>1970-01-14T21:20:00+00:00</date>
712 <msg xml:space="preserve">no person</msg>
712 <msg xml:space="preserve">no person</msg>
713 <paths>
713 <paths>
714 <path action="A">c</path>
714 <path action="A">c</path>
715 </paths>
715 </paths>
716 </logentry>
716 </logentry>
717 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
717 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
718 <author email="other@place">A. N. Other</author>
718 <author email="other@place">A. N. Other</author>
719 <date>1970-01-13T17:33:20+00:00</date>
719 <date>1970-01-13T17:33:20+00:00</date>
720 <msg xml:space="preserve">other 1
720 <msg xml:space="preserve">other 1
721 other 2
721 other 2
722
722
723 other 3</msg>
723 other 3</msg>
724 <paths>
724 <paths>
725 <path action="A">b</path>
725 <path action="A">b</path>
726 </paths>
726 </paths>
727 </logentry>
727 </logentry>
728 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
728 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
729 <author email="user@hostname">User Name</author>
729 <author email="user@hostname">User Name</author>
730 <date>1970-01-12T13:46:40+00:00</date>
730 <date>1970-01-12T13:46:40+00:00</date>
731 <msg xml:space="preserve">line 1
731 <msg xml:space="preserve">line 1
732 line 2</msg>
732 line 2</msg>
733 <paths>
733 <paths>
734 <path action="A">a</path>
734 <path action="A">a</path>
735 </paths>
735 </paths>
736 </logentry>
736 </logentry>
737 </log>
737 </log>
738
738
739 $ hg log --debug --style xml
739 $ hg log --debug --style xml
740 <?xml version="1.0"?>
740 <?xml version="1.0"?>
741 <log>
741 <log>
742 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
742 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
743 <tag>tip</tag>
743 <tag>tip</tag>
744 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
744 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
745 <parent revision="-1" node="0000000000000000000000000000000000000000" />
745 <parent revision="-1" node="0000000000000000000000000000000000000000" />
746 <author email="test">test</author>
746 <author email="test">test</author>
747 <date>2020-01-01T10:01:00+00:00</date>
747 <date>2020-01-01T10:01:00+00:00</date>
748 <msg xml:space="preserve">third</msg>
748 <msg xml:space="preserve">third</msg>
749 <paths>
749 <paths>
750 <path action="A">fourth</path>
750 <path action="A">fourth</path>
751 <path action="A">third</path>
751 <path action="A">third</path>
752 <path action="R">second</path>
752 <path action="R">second</path>
753 </paths>
753 </paths>
754 <copies>
754 <copies>
755 <copy source="second">fourth</copy>
755 <copy source="second">fourth</copy>
756 </copies>
756 </copies>
757 <extra key="branch">default</extra>
757 <extra key="branch">default</extra>
758 </logentry>
758 </logentry>
759 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
759 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
760 <parent revision="-1" node="0000000000000000000000000000000000000000" />
760 <parent revision="-1" node="0000000000000000000000000000000000000000" />
761 <parent revision="-1" node="0000000000000000000000000000000000000000" />
761 <parent revision="-1" node="0000000000000000000000000000000000000000" />
762 <author email="user@hostname">User Name</author>
762 <author email="user@hostname">User Name</author>
763 <date>1970-01-12T13:46:40+00:00</date>
763 <date>1970-01-12T13:46:40+00:00</date>
764 <msg xml:space="preserve">second</msg>
764 <msg xml:space="preserve">second</msg>
765 <paths>
765 <paths>
766 <path action="A">second</path>
766 <path action="A">second</path>
767 </paths>
767 </paths>
768 <extra key="branch">default</extra>
768 <extra key="branch">default</extra>
769 </logentry>
769 </logentry>
770 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
770 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
771 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
771 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
772 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
772 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
773 <author email="person">person</author>
773 <author email="person">person</author>
774 <date>1970-01-18T08:40:01+00:00</date>
774 <date>1970-01-18T08:40:01+00:00</date>
775 <msg xml:space="preserve">merge</msg>
775 <msg xml:space="preserve">merge</msg>
776 <paths>
776 <paths>
777 </paths>
777 </paths>
778 <extra key="branch">default</extra>
778 <extra key="branch">default</extra>
779 </logentry>
779 </logentry>
780 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
780 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
781 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
781 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
782 <parent revision="-1" node="0000000000000000000000000000000000000000" />
782 <parent revision="-1" node="0000000000000000000000000000000000000000" />
783 <author email="person">person</author>
783 <author email="person">person</author>
784 <date>1970-01-18T08:40:00+00:00</date>
784 <date>1970-01-18T08:40:00+00:00</date>
785 <msg xml:space="preserve">new head</msg>
785 <msg xml:space="preserve">new head</msg>
786 <paths>
786 <paths>
787 <path action="A">d</path>
787 <path action="A">d</path>
788 </paths>
788 </paths>
789 <extra key="branch">default</extra>
789 <extra key="branch">default</extra>
790 </logentry>
790 </logentry>
791 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
791 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
792 <branch>foo</branch>
792 <branch>foo</branch>
793 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
793 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
794 <parent revision="-1" node="0000000000000000000000000000000000000000" />
794 <parent revision="-1" node="0000000000000000000000000000000000000000" />
795 <author email="person">person</author>
795 <author email="person">person</author>
796 <date>1970-01-17T04:53:20+00:00</date>
796 <date>1970-01-17T04:53:20+00:00</date>
797 <msg xml:space="preserve">new branch</msg>
797 <msg xml:space="preserve">new branch</msg>
798 <paths>
798 <paths>
799 </paths>
799 </paths>
800 <extra key="branch">foo</extra>
800 <extra key="branch">foo</extra>
801 </logentry>
801 </logentry>
802 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
802 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
803 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
803 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
804 <parent revision="-1" node="0000000000000000000000000000000000000000" />
804 <parent revision="-1" node="0000000000000000000000000000000000000000" />
805 <author email="person">person</author>
805 <author email="person">person</author>
806 <date>1970-01-16T01:06:40+00:00</date>
806 <date>1970-01-16T01:06:40+00:00</date>
807 <msg xml:space="preserve">no user, no domain</msg>
807 <msg xml:space="preserve">no user, no domain</msg>
808 <paths>
808 <paths>
809 <path action="M">c</path>
809 <path action="M">c</path>
810 </paths>
810 </paths>
811 <extra key="branch">default</extra>
811 <extra key="branch">default</extra>
812 </logentry>
812 </logentry>
813 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
813 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
814 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
814 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
815 <parent revision="-1" node="0000000000000000000000000000000000000000" />
815 <parent revision="-1" node="0000000000000000000000000000000000000000" />
816 <author email="other@place">other</author>
816 <author email="other@place">other</author>
817 <date>1970-01-14T21:20:00+00:00</date>
817 <date>1970-01-14T21:20:00+00:00</date>
818 <msg xml:space="preserve">no person</msg>
818 <msg xml:space="preserve">no person</msg>
819 <paths>
819 <paths>
820 <path action="A">c</path>
820 <path action="A">c</path>
821 </paths>
821 </paths>
822 <extra key="branch">default</extra>
822 <extra key="branch">default</extra>
823 </logentry>
823 </logentry>
824 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
824 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
825 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
825 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
826 <parent revision="-1" node="0000000000000000000000000000000000000000" />
826 <parent revision="-1" node="0000000000000000000000000000000000000000" />
827 <author email="other@place">A. N. Other</author>
827 <author email="other@place">A. N. Other</author>
828 <date>1970-01-13T17:33:20+00:00</date>
828 <date>1970-01-13T17:33:20+00:00</date>
829 <msg xml:space="preserve">other 1
829 <msg xml:space="preserve">other 1
830 other 2
830 other 2
831
831
832 other 3</msg>
832 other 3</msg>
833 <paths>
833 <paths>
834 <path action="A">b</path>
834 <path action="A">b</path>
835 </paths>
835 </paths>
836 <extra key="branch">default</extra>
836 <extra key="branch">default</extra>
837 </logentry>
837 </logentry>
838 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
838 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
839 <parent revision="-1" node="0000000000000000000000000000000000000000" />
839 <parent revision="-1" node="0000000000000000000000000000000000000000" />
840 <parent revision="-1" node="0000000000000000000000000000000000000000" />
840 <parent revision="-1" node="0000000000000000000000000000000000000000" />
841 <author email="user@hostname">User Name</author>
841 <author email="user@hostname">User Name</author>
842 <date>1970-01-12T13:46:40+00:00</date>
842 <date>1970-01-12T13:46:40+00:00</date>
843 <msg xml:space="preserve">line 1
843 <msg xml:space="preserve">line 1
844 line 2</msg>
844 line 2</msg>
845 <paths>
845 <paths>
846 <path action="A">a</path>
846 <path action="A">a</path>
847 </paths>
847 </paths>
848 <extra key="branch">default</extra>
848 <extra key="branch">default</extra>
849 </logentry>
849 </logentry>
850 </log>
850 </log>
851
851
852
852
853 Test JSON style:
853 Test JSON style:
854
854
855 $ hg log -k nosuch -Tjson
855 $ hg log -k nosuch -Tjson
856 [
856 [
857 ]
857 ]
858
858
859 $ hg log -qr . -Tjson
859 $ hg log -qr . -Tjson
860 [
860 [
861 {
861 {
862 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
862 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
863 "rev": 8
863 "rev": 8
864 }
864 }
865 ]
865 ]
866
866
867 $ hg log -vpr . -Tjson --stat
867 $ hg log -vpr . -Tjson --stat
868 [
868 [
869 {
869 {
870 "bookmarks": [],
870 "bookmarks": [],
871 "branch": "default",
871 "branch": "default",
872 "date": [1577872860, 0],
872 "date": [1577872860, 0],
873 "desc": "third",
873 "desc": "third",
874 "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",
874 "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",
875 "diffstat": " fourth | 1 +\n second | 1 -\n third | 1 +\n 3 files changed, 2 insertions(+), 1 deletions(-)\n",
875 "diffstat": " fourth | 1 +\n second | 1 -\n third | 1 +\n 3 files changed, 2 insertions(+), 1 deletions(-)\n",
876 "files": ["fourth", "second", "third"],
876 "files": ["fourth", "second", "third"],
877 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
877 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
878 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
878 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
879 "phase": "draft",
879 "phase": "draft",
880 "rev": 8,
880 "rev": 8,
881 "tags": ["tip"],
881 "tags": ["tip"],
882 "user": "test"
882 "user": "test"
883 }
883 }
884 ]
884 ]
885
885
886 honor --git but not format-breaking diffopts
886 honor --git but not format-breaking diffopts
887 $ hg --config diff.noprefix=True log --git -vpr . -Tjson
887 $ hg --config diff.noprefix=True log --git -vpr . -Tjson
888 [
888 [
889 {
889 {
890 "bookmarks": [],
890 "bookmarks": [],
891 "branch": "default",
891 "branch": "default",
892 "date": [1577872860, 0],
892 "date": [1577872860, 0],
893 "desc": "third",
893 "desc": "third",
894 "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",
894 "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",
895 "files": ["fourth", "second", "third"],
895 "files": ["fourth", "second", "third"],
896 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
896 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
897 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
897 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
898 "phase": "draft",
898 "phase": "draft",
899 "rev": 8,
899 "rev": 8,
900 "tags": ["tip"],
900 "tags": ["tip"],
901 "user": "test"
901 "user": "test"
902 }
902 }
903 ]
903 ]
904
904
905 $ hg log -T json
905 $ hg log -T json
906 [
906 [
907 {
907 {
908 "bookmarks": [],
908 "bookmarks": [],
909 "branch": "default",
909 "branch": "default",
910 "date": [1577872860, 0],
910 "date": [1577872860, 0],
911 "desc": "third",
911 "desc": "third",
912 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
912 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
913 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
913 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
914 "phase": "draft",
914 "phase": "draft",
915 "rev": 8,
915 "rev": 8,
916 "tags": ["tip"],
916 "tags": ["tip"],
917 "user": "test"
917 "user": "test"
918 },
918 },
919 {
919 {
920 "bookmarks": [],
920 "bookmarks": [],
921 "branch": "default",
921 "branch": "default",
922 "date": [1000000, 0],
922 "date": [1000000, 0],
923 "desc": "second",
923 "desc": "second",
924 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
924 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
925 "parents": ["0000000000000000000000000000000000000000"],
925 "parents": ["0000000000000000000000000000000000000000"],
926 "phase": "draft",
926 "phase": "draft",
927 "rev": 7,
927 "rev": 7,
928 "tags": [],
928 "tags": [],
929 "user": "User Name <user@hostname>"
929 "user": "User Name <user@hostname>"
930 },
930 },
931 {
931 {
932 "bookmarks": [],
932 "bookmarks": [],
933 "branch": "default",
933 "branch": "default",
934 "date": [1500001, 0],
934 "date": [1500001, 0],
935 "desc": "merge",
935 "desc": "merge",
936 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
936 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
937 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
937 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
938 "phase": "draft",
938 "phase": "draft",
939 "rev": 6,
939 "rev": 6,
940 "tags": [],
940 "tags": [],
941 "user": "person"
941 "user": "person"
942 },
942 },
943 {
943 {
944 "bookmarks": [],
944 "bookmarks": [],
945 "branch": "default",
945 "branch": "default",
946 "date": [1500000, 0],
946 "date": [1500000, 0],
947 "desc": "new head",
947 "desc": "new head",
948 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
948 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
949 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
949 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
950 "phase": "draft",
950 "phase": "draft",
951 "rev": 5,
951 "rev": 5,
952 "tags": [],
952 "tags": [],
953 "user": "person"
953 "user": "person"
954 },
954 },
955 {
955 {
956 "bookmarks": [],
956 "bookmarks": [],
957 "branch": "foo",
957 "branch": "foo",
958 "date": [1400000, 0],
958 "date": [1400000, 0],
959 "desc": "new branch",
959 "desc": "new branch",
960 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
960 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
961 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
961 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
962 "phase": "draft",
962 "phase": "draft",
963 "rev": 4,
963 "rev": 4,
964 "tags": [],
964 "tags": [],
965 "user": "person"
965 "user": "person"
966 },
966 },
967 {
967 {
968 "bookmarks": [],
968 "bookmarks": [],
969 "branch": "default",
969 "branch": "default",
970 "date": [1300000, 0],
970 "date": [1300000, 0],
971 "desc": "no user, no domain",
971 "desc": "no user, no domain",
972 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
972 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
973 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
973 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
974 "phase": "draft",
974 "phase": "draft",
975 "rev": 3,
975 "rev": 3,
976 "tags": [],
976 "tags": [],
977 "user": "person"
977 "user": "person"
978 },
978 },
979 {
979 {
980 "bookmarks": [],
980 "bookmarks": [],
981 "branch": "default",
981 "branch": "default",
982 "date": [1200000, 0],
982 "date": [1200000, 0],
983 "desc": "no person",
983 "desc": "no person",
984 "node": "97054abb4ab824450e9164180baf491ae0078465",
984 "node": "97054abb4ab824450e9164180baf491ae0078465",
985 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
985 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
986 "phase": "draft",
986 "phase": "draft",
987 "rev": 2,
987 "rev": 2,
988 "tags": [],
988 "tags": [],
989 "user": "other@place"
989 "user": "other@place"
990 },
990 },
991 {
991 {
992 "bookmarks": [],
992 "bookmarks": [],
993 "branch": "default",
993 "branch": "default",
994 "date": [1100000, 0],
994 "date": [1100000, 0],
995 "desc": "other 1\nother 2\n\nother 3",
995 "desc": "other 1\nother 2\n\nother 3",
996 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
996 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
997 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
997 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
998 "phase": "draft",
998 "phase": "draft",
999 "rev": 1,
999 "rev": 1,
1000 "tags": [],
1000 "tags": [],
1001 "user": "A. N. Other <other@place>"
1001 "user": "A. N. Other <other@place>"
1002 },
1002 },
1003 {
1003 {
1004 "bookmarks": [],
1004 "bookmarks": [],
1005 "branch": "default",
1005 "branch": "default",
1006 "date": [1000000, 0],
1006 "date": [1000000, 0],
1007 "desc": "line 1\nline 2",
1007 "desc": "line 1\nline 2",
1008 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
1008 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
1009 "parents": ["0000000000000000000000000000000000000000"],
1009 "parents": ["0000000000000000000000000000000000000000"],
1010 "phase": "draft",
1010 "phase": "draft",
1011 "rev": 0,
1011 "rev": 0,
1012 "tags": [],
1012 "tags": [],
1013 "user": "User Name <user@hostname>"
1013 "user": "User Name <user@hostname>"
1014 }
1014 }
1015 ]
1015 ]
1016
1016
1017 $ hg heads -v -Tjson
1017 $ hg heads -v -Tjson
1018 [
1018 [
1019 {
1019 {
1020 "bookmarks": [],
1020 "bookmarks": [],
1021 "branch": "default",
1021 "branch": "default",
1022 "date": [1577872860, 0],
1022 "date": [1577872860, 0],
1023 "desc": "third",
1023 "desc": "third",
1024 "files": ["fourth", "second", "third"],
1024 "files": ["fourth", "second", "third"],
1025 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
1025 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
1026 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
1026 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
1027 "phase": "draft",
1027 "phase": "draft",
1028 "rev": 8,
1028 "rev": 8,
1029 "tags": ["tip"],
1029 "tags": ["tip"],
1030 "user": "test"
1030 "user": "test"
1031 },
1031 },
1032 {
1032 {
1033 "bookmarks": [],
1033 "bookmarks": [],
1034 "branch": "default",
1034 "branch": "default",
1035 "date": [1500001, 0],
1035 "date": [1500001, 0],
1036 "desc": "merge",
1036 "desc": "merge",
1037 "files": [],
1037 "files": [],
1038 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
1038 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
1039 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
1039 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
1040 "phase": "draft",
1040 "phase": "draft",
1041 "rev": 6,
1041 "rev": 6,
1042 "tags": [],
1042 "tags": [],
1043 "user": "person"
1043 "user": "person"
1044 },
1044 },
1045 {
1045 {
1046 "bookmarks": [],
1046 "bookmarks": [],
1047 "branch": "foo",
1047 "branch": "foo",
1048 "date": [1400000, 0],
1048 "date": [1400000, 0],
1049 "desc": "new branch",
1049 "desc": "new branch",
1050 "files": [],
1050 "files": [],
1051 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
1051 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
1052 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1052 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1053 "phase": "draft",
1053 "phase": "draft",
1054 "rev": 4,
1054 "rev": 4,
1055 "tags": [],
1055 "tags": [],
1056 "user": "person"
1056 "user": "person"
1057 }
1057 }
1058 ]
1058 ]
1059
1059
1060 $ hg log --debug -Tjson
1060 $ hg log --debug -Tjson
1061 [
1061 [
1062 {
1062 {
1063 "added": ["fourth", "third"],
1063 "added": ["fourth", "third"],
1064 "bookmarks": [],
1064 "bookmarks": [],
1065 "branch": "default",
1065 "branch": "default",
1066 "date": [1577872860, 0],
1066 "date": [1577872860, 0],
1067 "desc": "third",
1067 "desc": "third",
1068 "extra": {"branch": "default"},
1068 "extra": {"branch": "default"},
1069 "manifest": "94961b75a2da554b4df6fb599e5bfc7d48de0c64",
1069 "manifest": "94961b75a2da554b4df6fb599e5bfc7d48de0c64",
1070 "modified": [],
1070 "modified": [],
1071 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
1071 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
1072 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
1072 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
1073 "phase": "draft",
1073 "phase": "draft",
1074 "removed": ["second"],
1074 "removed": ["second"],
1075 "rev": 8,
1075 "rev": 8,
1076 "tags": ["tip"],
1076 "tags": ["tip"],
1077 "user": "test"
1077 "user": "test"
1078 },
1078 },
1079 {
1079 {
1080 "added": ["second"],
1080 "added": ["second"],
1081 "bookmarks": [],
1081 "bookmarks": [],
1082 "branch": "default",
1082 "branch": "default",
1083 "date": [1000000, 0],
1083 "date": [1000000, 0],
1084 "desc": "second",
1084 "desc": "second",
1085 "extra": {"branch": "default"},
1085 "extra": {"branch": "default"},
1086 "manifest": "f2dbc354b94e5ec0b4f10680ee0cee816101d0bf",
1086 "manifest": "f2dbc354b94e5ec0b4f10680ee0cee816101d0bf",
1087 "modified": [],
1087 "modified": [],
1088 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
1088 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
1089 "parents": ["0000000000000000000000000000000000000000"],
1089 "parents": ["0000000000000000000000000000000000000000"],
1090 "phase": "draft",
1090 "phase": "draft",
1091 "removed": [],
1091 "removed": [],
1092 "rev": 7,
1092 "rev": 7,
1093 "tags": [],
1093 "tags": [],
1094 "user": "User Name <user@hostname>"
1094 "user": "User Name <user@hostname>"
1095 },
1095 },
1096 {
1096 {
1097 "added": [],
1097 "added": [],
1098 "bookmarks": [],
1098 "bookmarks": [],
1099 "branch": "default",
1099 "branch": "default",
1100 "date": [1500001, 0],
1100 "date": [1500001, 0],
1101 "desc": "merge",
1101 "desc": "merge",
1102 "extra": {"branch": "default"},
1102 "extra": {"branch": "default"},
1103 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1103 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1104 "modified": [],
1104 "modified": [],
1105 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
1105 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
1106 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
1106 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
1107 "phase": "draft",
1107 "phase": "draft",
1108 "removed": [],
1108 "removed": [],
1109 "rev": 6,
1109 "rev": 6,
1110 "tags": [],
1110 "tags": [],
1111 "user": "person"
1111 "user": "person"
1112 },
1112 },
1113 {
1113 {
1114 "added": ["d"],
1114 "added": ["d"],
1115 "bookmarks": [],
1115 "bookmarks": [],
1116 "branch": "default",
1116 "branch": "default",
1117 "date": [1500000, 0],
1117 "date": [1500000, 0],
1118 "desc": "new head",
1118 "desc": "new head",
1119 "extra": {"branch": "default"},
1119 "extra": {"branch": "default"},
1120 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1120 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1121 "modified": [],
1121 "modified": [],
1122 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
1122 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
1123 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1123 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1124 "phase": "draft",
1124 "phase": "draft",
1125 "removed": [],
1125 "removed": [],
1126 "rev": 5,
1126 "rev": 5,
1127 "tags": [],
1127 "tags": [],
1128 "user": "person"
1128 "user": "person"
1129 },
1129 },
1130 {
1130 {
1131 "added": [],
1131 "added": [],
1132 "bookmarks": [],
1132 "bookmarks": [],
1133 "branch": "foo",
1133 "branch": "foo",
1134 "date": [1400000, 0],
1134 "date": [1400000, 0],
1135 "desc": "new branch",
1135 "desc": "new branch",
1136 "extra": {"branch": "foo"},
1136 "extra": {"branch": "foo"},
1137 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1137 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1138 "modified": [],
1138 "modified": [],
1139 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
1139 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
1140 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1140 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1141 "phase": "draft",
1141 "phase": "draft",
1142 "removed": [],
1142 "removed": [],
1143 "rev": 4,
1143 "rev": 4,
1144 "tags": [],
1144 "tags": [],
1145 "user": "person"
1145 "user": "person"
1146 },
1146 },
1147 {
1147 {
1148 "added": [],
1148 "added": [],
1149 "bookmarks": [],
1149 "bookmarks": [],
1150 "branch": "default",
1150 "branch": "default",
1151 "date": [1300000, 0],
1151 "date": [1300000, 0],
1152 "desc": "no user, no domain",
1152 "desc": "no user, no domain",
1153 "extra": {"branch": "default"},
1153 "extra": {"branch": "default"},
1154 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1154 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1155 "modified": ["c"],
1155 "modified": ["c"],
1156 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
1156 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
1157 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
1157 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
1158 "phase": "draft",
1158 "phase": "draft",
1159 "removed": [],
1159 "removed": [],
1160 "rev": 3,
1160 "rev": 3,
1161 "tags": [],
1161 "tags": [],
1162 "user": "person"
1162 "user": "person"
1163 },
1163 },
1164 {
1164 {
1165 "added": ["c"],
1165 "added": ["c"],
1166 "bookmarks": [],
1166 "bookmarks": [],
1167 "branch": "default",
1167 "branch": "default",
1168 "date": [1200000, 0],
1168 "date": [1200000, 0],
1169 "desc": "no person",
1169 "desc": "no person",
1170 "extra": {"branch": "default"},
1170 "extra": {"branch": "default"},
1171 "manifest": "6e0e82995c35d0d57a52aca8da4e56139e06b4b1",
1171 "manifest": "6e0e82995c35d0d57a52aca8da4e56139e06b4b1",
1172 "modified": [],
1172 "modified": [],
1173 "node": "97054abb4ab824450e9164180baf491ae0078465",
1173 "node": "97054abb4ab824450e9164180baf491ae0078465",
1174 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
1174 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
1175 "phase": "draft",
1175 "phase": "draft",
1176 "removed": [],
1176 "removed": [],
1177 "rev": 2,
1177 "rev": 2,
1178 "tags": [],
1178 "tags": [],
1179 "user": "other@place"
1179 "user": "other@place"
1180 },
1180 },
1181 {
1181 {
1182 "added": ["b"],
1182 "added": ["b"],
1183 "bookmarks": [],
1183 "bookmarks": [],
1184 "branch": "default",
1184 "branch": "default",
1185 "date": [1100000, 0],
1185 "date": [1100000, 0],
1186 "desc": "other 1\nother 2\n\nother 3",
1186 "desc": "other 1\nother 2\n\nother 3",
1187 "extra": {"branch": "default"},
1187 "extra": {"branch": "default"},
1188 "manifest": "4e8d705b1e53e3f9375e0e60dc7b525d8211fe55",
1188 "manifest": "4e8d705b1e53e3f9375e0e60dc7b525d8211fe55",
1189 "modified": [],
1189 "modified": [],
1190 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
1190 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
1191 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
1191 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
1192 "phase": "draft",
1192 "phase": "draft",
1193 "removed": [],
1193 "removed": [],
1194 "rev": 1,
1194 "rev": 1,
1195 "tags": [],
1195 "tags": [],
1196 "user": "A. N. Other <other@place>"
1196 "user": "A. N. Other <other@place>"
1197 },
1197 },
1198 {
1198 {
1199 "added": ["a"],
1199 "added": ["a"],
1200 "bookmarks": [],
1200 "bookmarks": [],
1201 "branch": "default",
1201 "branch": "default",
1202 "date": [1000000, 0],
1202 "date": [1000000, 0],
1203 "desc": "line 1\nline 2",
1203 "desc": "line 1\nline 2",
1204 "extra": {"branch": "default"},
1204 "extra": {"branch": "default"},
1205 "manifest": "a0c8bcbbb45c63b90b70ad007bf38961f64f2af0",
1205 "manifest": "a0c8bcbbb45c63b90b70ad007bf38961f64f2af0",
1206 "modified": [],
1206 "modified": [],
1207 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
1207 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
1208 "parents": ["0000000000000000000000000000000000000000"],
1208 "parents": ["0000000000000000000000000000000000000000"],
1209 "phase": "draft",
1209 "phase": "draft",
1210 "removed": [],
1210 "removed": [],
1211 "rev": 0,
1211 "rev": 0,
1212 "tags": [],
1212 "tags": [],
1213 "user": "User Name <user@hostname>"
1213 "user": "User Name <user@hostname>"
1214 }
1214 }
1215 ]
1215 ]
1216
1216
1217 Error if style not readable:
1217 Error if style not readable:
1218
1218
1219 #if unix-permissions no-root
1219 #if unix-permissions no-root
1220 $ touch q
1220 $ touch q
1221 $ chmod 0 q
1221 $ chmod 0 q
1222 $ hg log --style ./q
1222 $ hg log --style ./q
1223 abort: Permission denied: ./q
1223 abort: Permission denied: ./q
1224 [255]
1224 [255]
1225 #endif
1225 #endif
1226
1226
1227 Error if no style:
1227 Error if no style:
1228
1228
1229 $ hg log --style notexist
1229 $ hg log --style notexist
1230 abort: style 'notexist' not found
1230 abort: style 'notexist' not found
1231 (available styles: bisect, changelog, compact, default, phases, show, status, xml)
1231 (available styles: bisect, changelog, compact, default, phases, show, status, xml)
1232 [255]
1232 [255]
1233
1233
1234 $ hg log -T list
1234 $ hg log -T list
1235 available styles: bisect, changelog, compact, default, phases, show, status, xml
1235 available styles: bisect, changelog, compact, default, phases, show, status, xml
1236 abort: specify a template
1236 abort: specify a template
1237 [255]
1237 [255]
1238
1238
1239 Error if style missing key:
1239 Error if style missing key:
1240
1240
1241 $ echo 'q = q' > t
1241 $ echo 'q = q' > t
1242 $ hg log --style ./t
1242 $ hg log --style ./t
1243 abort: "changeset" not in template map
1243 abort: "changeset" not in template map
1244 [255]
1244 [255]
1245
1245
1246 Error if style missing value:
1246 Error if style missing value:
1247
1247
1248 $ echo 'changeset =' > t
1248 $ echo 'changeset =' > t
1249 $ hg log --style t
1249 $ hg log --style t
1250 hg: parse error at t:1: missing value
1250 hg: parse error at t:1: missing value
1251 [255]
1251 [255]
1252
1252
1253 Error if include fails:
1253 Error if include fails:
1254
1254
1255 $ echo 'changeset = q' >> t
1255 $ echo 'changeset = q' >> t
1256 #if unix-permissions no-root
1256 #if unix-permissions no-root
1257 $ hg log --style ./t
1257 $ hg log --style ./t
1258 abort: template file ./q: Permission denied
1258 abort: template file ./q: Permission denied
1259 [255]
1259 [255]
1260 $ rm -f q
1260 $ rm -f q
1261 #endif
1261 #endif
1262
1262
1263 Include works:
1263 Include works:
1264
1264
1265 $ echo '{rev}' > q
1265 $ echo '{rev}' > q
1266 $ hg log --style ./t
1266 $ hg log --style ./t
1267 8
1267 8
1268 7
1268 7
1269 6
1269 6
1270 5
1270 5
1271 4
1271 4
1272 3
1272 3
1273 2
1273 2
1274 1
1274 1
1275 0
1275 0
1276
1276
1277 Check that recursive reference does not fall into RuntimeError (issue4758):
1277 Check that recursive reference does not fall into RuntimeError (issue4758):
1278
1278
1279 common mistake:
1279 common mistake:
1280
1280
1281 $ cat << EOF > issue4758
1281 $ cat << EOF > issue4758
1282 > changeset = '{changeset}\n'
1282 > changeset = '{changeset}\n'
1283 > EOF
1283 > EOF
1284 $ hg log --style ./issue4758
1284 $ hg log --style ./issue4758
1285 abort: recursive reference 'changeset' in template
1285 abort: recursive reference 'changeset' in template
1286 [255]
1286 [255]
1287
1287
1288 circular reference:
1288 circular reference:
1289
1289
1290 $ cat << EOF > issue4758
1290 $ cat << EOF > issue4758
1291 > changeset = '{foo}'
1291 > changeset = '{foo}'
1292 > foo = '{changeset}'
1292 > foo = '{changeset}'
1293 > EOF
1293 > EOF
1294 $ hg log --style ./issue4758
1294 $ hg log --style ./issue4758
1295 abort: recursive reference 'foo' in template
1295 abort: recursive reference 'foo' in template
1296 [255]
1296 [255]
1297
1297
1298 buildmap() -> gettemplate(), where no thunk was made:
1298 buildmap() -> gettemplate(), where no thunk was made:
1299
1299
1300 $ cat << EOF > issue4758
1300 $ cat << EOF > issue4758
1301 > changeset = '{files % changeset}\n'
1301 > changeset = '{files % changeset}\n'
1302 > EOF
1302 > EOF
1303 $ hg log --style ./issue4758
1303 $ hg log --style ./issue4758
1304 abort: recursive reference 'changeset' in template
1304 abort: recursive reference 'changeset' in template
1305 [255]
1305 [255]
1306
1306
1307 not a recursion if a keyword of the same name exists:
1307 not a recursion if a keyword of the same name exists:
1308
1308
1309 $ cat << EOF > issue4758
1309 $ cat << EOF > issue4758
1310 > changeset = '{tags % rev}'
1310 > changeset = '{tags % rev}'
1311 > rev = '{rev} {tag}\n'
1311 > rev = '{rev} {tag}\n'
1312 > EOF
1312 > EOF
1313 $ hg log --style ./issue4758 -r tip
1313 $ hg log --style ./issue4758 -r tip
1314 8 tip
1314 8 tip
1315
1315
1316 Check that {phase} works correctly on parents:
1316 Check that {phase} works correctly on parents:
1317
1317
1318 $ cat << EOF > parentphase
1318 $ cat << EOF > parentphase
1319 > changeset_debug = '{rev} ({phase}):{parents}\n'
1319 > changeset_debug = '{rev} ({phase}):{parents}\n'
1320 > parent = ' {rev} ({phase})'
1320 > parent = ' {rev} ({phase})'
1321 > EOF
1321 > EOF
1322 $ hg phase -r 5 --public
1322 $ hg phase -r 5 --public
1323 $ hg phase -r 7 --secret --force
1323 $ hg phase -r 7 --secret --force
1324 $ hg log --debug -G --style ./parentphase
1324 $ hg log --debug -G --style ./parentphase
1325 @ 8 (secret): 7 (secret) -1 (public)
1325 @ 8 (secret): 7 (secret) -1 (public)
1326 |
1326 |
1327 o 7 (secret): -1 (public) -1 (public)
1327 o 7 (secret): -1 (public) -1 (public)
1328
1328
1329 o 6 (draft): 5 (public) 4 (draft)
1329 o 6 (draft): 5 (public) 4 (draft)
1330 |\
1330 |\
1331 | o 5 (public): 3 (public) -1 (public)
1331 | o 5 (public): 3 (public) -1 (public)
1332 | |
1332 | |
1333 o | 4 (draft): 3 (public) -1 (public)
1333 o | 4 (draft): 3 (public) -1 (public)
1334 |/
1334 |/
1335 o 3 (public): 2 (public) -1 (public)
1335 o 3 (public): 2 (public) -1 (public)
1336 |
1336 |
1337 o 2 (public): 1 (public) -1 (public)
1337 o 2 (public): 1 (public) -1 (public)
1338 |
1338 |
1339 o 1 (public): 0 (public) -1 (public)
1339 o 1 (public): 0 (public) -1 (public)
1340 |
1340 |
1341 o 0 (public): -1 (public) -1 (public)
1341 o 0 (public): -1 (public) -1 (public)
1342
1342
1343
1343
1344 Missing non-standard names give no error (backward compatibility):
1344 Missing non-standard names give no error (backward compatibility):
1345
1345
1346 $ echo "changeset = '{c}'" > t
1346 $ echo "changeset = '{c}'" > t
1347 $ hg log --style ./t
1347 $ hg log --style ./t
1348
1348
1349 Defining non-standard name works:
1349 Defining non-standard name works:
1350
1350
1351 $ cat <<EOF > t
1351 $ cat <<EOF > t
1352 > changeset = '{c}'
1352 > changeset = '{c}'
1353 > c = q
1353 > c = q
1354 > EOF
1354 > EOF
1355 $ hg log --style ./t
1355 $ hg log --style ./t
1356 8
1356 8
1357 7
1357 7
1358 6
1358 6
1359 5
1359 5
1360 4
1360 4
1361 3
1361 3
1362 2
1362 2
1363 1
1363 1
1364 0
1364 0
1365
1365
1366 ui.style works:
1366 ui.style works:
1367
1367
1368 $ echo '[ui]' > .hg/hgrc
1368 $ echo '[ui]' > .hg/hgrc
1369 $ echo 'style = t' >> .hg/hgrc
1369 $ echo 'style = t' >> .hg/hgrc
1370 $ hg log
1370 $ hg log
1371 8
1371 8
1372 7
1372 7
1373 6
1373 6
1374 5
1374 5
1375 4
1375 4
1376 3
1376 3
1377 2
1377 2
1378 1
1378 1
1379 0
1379 0
1380
1380
1381
1381
1382 Issue338:
1382 Issue338:
1383
1383
1384 $ hg log --style=changelog > changelog
1384 $ hg log --style=changelog > changelog
1385
1385
1386 $ cat changelog
1386 $ cat changelog
1387 2020-01-01 test <test>
1387 2020-01-01 test <test>
1388
1388
1389 * fourth, second, third:
1389 * fourth, second, third:
1390 third
1390 third
1391 [95c24699272e] [tip]
1391 [95c24699272e] [tip]
1392
1392
1393 1970-01-12 User Name <user@hostname>
1393 1970-01-12 User Name <user@hostname>
1394
1394
1395 * second:
1395 * second:
1396 second
1396 second
1397 [29114dbae42b]
1397 [29114dbae42b]
1398
1398
1399 1970-01-18 person <person>
1399 1970-01-18 person <person>
1400
1400
1401 * merge
1401 * merge
1402 [d41e714fe50d]
1402 [d41e714fe50d]
1403
1403
1404 * d:
1404 * d:
1405 new head
1405 new head
1406 [13207e5a10d9]
1406 [13207e5a10d9]
1407
1407
1408 1970-01-17 person <person>
1408 1970-01-17 person <person>
1409
1409
1410 * new branch
1410 * new branch
1411 [bbe44766e73d] <foo>
1411 [bbe44766e73d] <foo>
1412
1412
1413 1970-01-16 person <person>
1413 1970-01-16 person <person>
1414
1414
1415 * c:
1415 * c:
1416 no user, no domain
1416 no user, no domain
1417 [10e46f2dcbf4]
1417 [10e46f2dcbf4]
1418
1418
1419 1970-01-14 other <other@place>
1419 1970-01-14 other <other@place>
1420
1420
1421 * c:
1421 * c:
1422 no person
1422 no person
1423 [97054abb4ab8]
1423 [97054abb4ab8]
1424
1424
1425 1970-01-13 A. N. Other <other@place>
1425 1970-01-13 A. N. Other <other@place>
1426
1426
1427 * b:
1427 * b:
1428 other 1 other 2
1428 other 1 other 2
1429
1429
1430 other 3
1430 other 3
1431 [b608e9d1a3f0]
1431 [b608e9d1a3f0]
1432
1432
1433 1970-01-12 User Name <user@hostname>
1433 1970-01-12 User Name <user@hostname>
1434
1434
1435 * a:
1435 * a:
1436 line 1 line 2
1436 line 1 line 2
1437 [1e4e1b8f71e0]
1437 [1e4e1b8f71e0]
1438
1438
1439
1439
1440 Issue2130: xml output for 'hg heads' is malformed
1440 Issue2130: xml output for 'hg heads' is malformed
1441
1441
1442 $ hg heads --style changelog
1442 $ hg heads --style changelog
1443 2020-01-01 test <test>
1443 2020-01-01 test <test>
1444
1444
1445 * fourth, second, third:
1445 * fourth, second, third:
1446 third
1446 third
1447 [95c24699272e] [tip]
1447 [95c24699272e] [tip]
1448
1448
1449 1970-01-18 person <person>
1449 1970-01-18 person <person>
1450
1450
1451 * merge
1451 * merge
1452 [d41e714fe50d]
1452 [d41e714fe50d]
1453
1453
1454 1970-01-17 person <person>
1454 1970-01-17 person <person>
1455
1455
1456 * new branch
1456 * new branch
1457 [bbe44766e73d] <foo>
1457 [bbe44766e73d] <foo>
1458
1458
1459
1459
1460 Keys work:
1460 Keys work:
1461
1461
1462 $ for key in author branch branches date desc file_adds file_dels file_mods \
1462 $ for key in author branch branches date desc file_adds file_dels file_mods \
1463 > file_copies file_copies_switch files \
1463 > file_copies file_copies_switch files \
1464 > manifest node parents rev tags diffstat extras \
1464 > manifest node parents rev tags diffstat extras \
1465 > p1rev p2rev p1node p2node; do
1465 > p1rev p2rev p1node p2node; do
1466 > for mode in '' --verbose --debug; do
1466 > for mode in '' --verbose --debug; do
1467 > hg log $mode --template "$key$mode: {$key}\n"
1467 > hg log $mode --template "$key$mode: {$key}\n"
1468 > done
1468 > done
1469 > done
1469 > done
1470 author: test
1470 author: test
1471 author: User Name <user@hostname>
1471 author: User Name <user@hostname>
1472 author: person
1472 author: person
1473 author: person
1473 author: person
1474 author: person
1474 author: person
1475 author: person
1475 author: person
1476 author: other@place
1476 author: other@place
1477 author: A. N. Other <other@place>
1477 author: A. N. Other <other@place>
1478 author: User Name <user@hostname>
1478 author: User Name <user@hostname>
1479 author--verbose: test
1479 author--verbose: test
1480 author--verbose: User Name <user@hostname>
1480 author--verbose: User Name <user@hostname>
1481 author--verbose: person
1481 author--verbose: person
1482 author--verbose: person
1482 author--verbose: person
1483 author--verbose: person
1483 author--verbose: person
1484 author--verbose: person
1484 author--verbose: person
1485 author--verbose: other@place
1485 author--verbose: other@place
1486 author--verbose: A. N. Other <other@place>
1486 author--verbose: A. N. Other <other@place>
1487 author--verbose: User Name <user@hostname>
1487 author--verbose: User Name <user@hostname>
1488 author--debug: test
1488 author--debug: test
1489 author--debug: User Name <user@hostname>
1489 author--debug: User Name <user@hostname>
1490 author--debug: person
1490 author--debug: person
1491 author--debug: person
1491 author--debug: person
1492 author--debug: person
1492 author--debug: person
1493 author--debug: person
1493 author--debug: person
1494 author--debug: other@place
1494 author--debug: other@place
1495 author--debug: A. N. Other <other@place>
1495 author--debug: A. N. Other <other@place>
1496 author--debug: User Name <user@hostname>
1496 author--debug: User Name <user@hostname>
1497 branch: default
1497 branch: default
1498 branch: default
1498 branch: default
1499 branch: default
1499 branch: default
1500 branch: default
1500 branch: default
1501 branch: foo
1501 branch: foo
1502 branch: default
1502 branch: default
1503 branch: default
1503 branch: default
1504 branch: default
1504 branch: default
1505 branch: default
1505 branch: default
1506 branch--verbose: default
1506 branch--verbose: default
1507 branch--verbose: default
1507 branch--verbose: default
1508 branch--verbose: default
1508 branch--verbose: default
1509 branch--verbose: default
1509 branch--verbose: default
1510 branch--verbose: foo
1510 branch--verbose: foo
1511 branch--verbose: default
1511 branch--verbose: default
1512 branch--verbose: default
1512 branch--verbose: default
1513 branch--verbose: default
1513 branch--verbose: default
1514 branch--verbose: default
1514 branch--verbose: default
1515 branch--debug: default
1515 branch--debug: default
1516 branch--debug: default
1516 branch--debug: default
1517 branch--debug: default
1517 branch--debug: default
1518 branch--debug: default
1518 branch--debug: default
1519 branch--debug: foo
1519 branch--debug: foo
1520 branch--debug: default
1520 branch--debug: default
1521 branch--debug: default
1521 branch--debug: default
1522 branch--debug: default
1522 branch--debug: default
1523 branch--debug: default
1523 branch--debug: default
1524 branches:
1524 branches:
1525 branches:
1525 branches:
1526 branches:
1526 branches:
1527 branches:
1527 branches:
1528 branches: foo
1528 branches: foo
1529 branches:
1529 branches:
1530 branches:
1530 branches:
1531 branches:
1531 branches:
1532 branches:
1532 branches:
1533 branches--verbose:
1533 branches--verbose:
1534 branches--verbose:
1534 branches--verbose:
1535 branches--verbose:
1535 branches--verbose:
1536 branches--verbose:
1536 branches--verbose:
1537 branches--verbose: foo
1537 branches--verbose: foo
1538 branches--verbose:
1538 branches--verbose:
1539 branches--verbose:
1539 branches--verbose:
1540 branches--verbose:
1540 branches--verbose:
1541 branches--verbose:
1541 branches--verbose:
1542 branches--debug:
1542 branches--debug:
1543 branches--debug:
1543 branches--debug:
1544 branches--debug:
1544 branches--debug:
1545 branches--debug:
1545 branches--debug:
1546 branches--debug: foo
1546 branches--debug: foo
1547 branches--debug:
1547 branches--debug:
1548 branches--debug:
1548 branches--debug:
1549 branches--debug:
1549 branches--debug:
1550 branches--debug:
1550 branches--debug:
1551 date: 1577872860.00
1551 date: 1577872860.00
1552 date: 1000000.00
1552 date: 1000000.00
1553 date: 1500001.00
1553 date: 1500001.00
1554 date: 1500000.00
1554 date: 1500000.00
1555 date: 1400000.00
1555 date: 1400000.00
1556 date: 1300000.00
1556 date: 1300000.00
1557 date: 1200000.00
1557 date: 1200000.00
1558 date: 1100000.00
1558 date: 1100000.00
1559 date: 1000000.00
1559 date: 1000000.00
1560 date--verbose: 1577872860.00
1560 date--verbose: 1577872860.00
1561 date--verbose: 1000000.00
1561 date--verbose: 1000000.00
1562 date--verbose: 1500001.00
1562 date--verbose: 1500001.00
1563 date--verbose: 1500000.00
1563 date--verbose: 1500000.00
1564 date--verbose: 1400000.00
1564 date--verbose: 1400000.00
1565 date--verbose: 1300000.00
1565 date--verbose: 1300000.00
1566 date--verbose: 1200000.00
1566 date--verbose: 1200000.00
1567 date--verbose: 1100000.00
1567 date--verbose: 1100000.00
1568 date--verbose: 1000000.00
1568 date--verbose: 1000000.00
1569 date--debug: 1577872860.00
1569 date--debug: 1577872860.00
1570 date--debug: 1000000.00
1570 date--debug: 1000000.00
1571 date--debug: 1500001.00
1571 date--debug: 1500001.00
1572 date--debug: 1500000.00
1572 date--debug: 1500000.00
1573 date--debug: 1400000.00
1573 date--debug: 1400000.00
1574 date--debug: 1300000.00
1574 date--debug: 1300000.00
1575 date--debug: 1200000.00
1575 date--debug: 1200000.00
1576 date--debug: 1100000.00
1576 date--debug: 1100000.00
1577 date--debug: 1000000.00
1577 date--debug: 1000000.00
1578 desc: third
1578 desc: third
1579 desc: second
1579 desc: second
1580 desc: merge
1580 desc: merge
1581 desc: new head
1581 desc: new head
1582 desc: new branch
1582 desc: new branch
1583 desc: no user, no domain
1583 desc: no user, no domain
1584 desc: no person
1584 desc: no person
1585 desc: other 1
1585 desc: other 1
1586 other 2
1586 other 2
1587
1587
1588 other 3
1588 other 3
1589 desc: line 1
1589 desc: line 1
1590 line 2
1590 line 2
1591 desc--verbose: third
1591 desc--verbose: third
1592 desc--verbose: second
1592 desc--verbose: second
1593 desc--verbose: merge
1593 desc--verbose: merge
1594 desc--verbose: new head
1594 desc--verbose: new head
1595 desc--verbose: new branch
1595 desc--verbose: new branch
1596 desc--verbose: no user, no domain
1596 desc--verbose: no user, no domain
1597 desc--verbose: no person
1597 desc--verbose: no person
1598 desc--verbose: other 1
1598 desc--verbose: other 1
1599 other 2
1599 other 2
1600
1600
1601 other 3
1601 other 3
1602 desc--verbose: line 1
1602 desc--verbose: line 1
1603 line 2
1603 line 2
1604 desc--debug: third
1604 desc--debug: third
1605 desc--debug: second
1605 desc--debug: second
1606 desc--debug: merge
1606 desc--debug: merge
1607 desc--debug: new head
1607 desc--debug: new head
1608 desc--debug: new branch
1608 desc--debug: new branch
1609 desc--debug: no user, no domain
1609 desc--debug: no user, no domain
1610 desc--debug: no person
1610 desc--debug: no person
1611 desc--debug: other 1
1611 desc--debug: other 1
1612 other 2
1612 other 2
1613
1613
1614 other 3
1614 other 3
1615 desc--debug: line 1
1615 desc--debug: line 1
1616 line 2
1616 line 2
1617 file_adds: fourth third
1617 file_adds: fourth third
1618 file_adds: second
1618 file_adds: second
1619 file_adds:
1619 file_adds:
1620 file_adds: d
1620 file_adds: d
1621 file_adds:
1621 file_adds:
1622 file_adds:
1622 file_adds:
1623 file_adds: c
1623 file_adds: c
1624 file_adds: b
1624 file_adds: b
1625 file_adds: a
1625 file_adds: a
1626 file_adds--verbose: fourth third
1626 file_adds--verbose: fourth third
1627 file_adds--verbose: second
1627 file_adds--verbose: second
1628 file_adds--verbose:
1628 file_adds--verbose:
1629 file_adds--verbose: d
1629 file_adds--verbose: d
1630 file_adds--verbose:
1630 file_adds--verbose:
1631 file_adds--verbose:
1631 file_adds--verbose:
1632 file_adds--verbose: c
1632 file_adds--verbose: c
1633 file_adds--verbose: b
1633 file_adds--verbose: b
1634 file_adds--verbose: a
1634 file_adds--verbose: a
1635 file_adds--debug: fourth third
1635 file_adds--debug: fourth third
1636 file_adds--debug: second
1636 file_adds--debug: second
1637 file_adds--debug:
1637 file_adds--debug:
1638 file_adds--debug: d
1638 file_adds--debug: d
1639 file_adds--debug:
1639 file_adds--debug:
1640 file_adds--debug:
1640 file_adds--debug:
1641 file_adds--debug: c
1641 file_adds--debug: c
1642 file_adds--debug: b
1642 file_adds--debug: b
1643 file_adds--debug: a
1643 file_adds--debug: a
1644 file_dels: second
1644 file_dels: second
1645 file_dels:
1645 file_dels:
1646 file_dels:
1646 file_dels:
1647 file_dels:
1647 file_dels:
1648 file_dels:
1648 file_dels:
1649 file_dels:
1649 file_dels:
1650 file_dels:
1650 file_dels:
1651 file_dels:
1651 file_dels:
1652 file_dels:
1652 file_dels:
1653 file_dels--verbose: second
1653 file_dels--verbose: second
1654 file_dels--verbose:
1654 file_dels--verbose:
1655 file_dels--verbose:
1655 file_dels--verbose:
1656 file_dels--verbose:
1656 file_dels--verbose:
1657 file_dels--verbose:
1657 file_dels--verbose:
1658 file_dels--verbose:
1658 file_dels--verbose:
1659 file_dels--verbose:
1659 file_dels--verbose:
1660 file_dels--verbose:
1660 file_dels--verbose:
1661 file_dels--verbose:
1661 file_dels--verbose:
1662 file_dels--debug: second
1662 file_dels--debug: second
1663 file_dels--debug:
1663 file_dels--debug:
1664 file_dels--debug:
1664 file_dels--debug:
1665 file_dels--debug:
1665 file_dels--debug:
1666 file_dels--debug:
1666 file_dels--debug:
1667 file_dels--debug:
1667 file_dels--debug:
1668 file_dels--debug:
1668 file_dels--debug:
1669 file_dels--debug:
1669 file_dels--debug:
1670 file_dels--debug:
1670 file_dels--debug:
1671 file_mods:
1671 file_mods:
1672 file_mods:
1672 file_mods:
1673 file_mods:
1673 file_mods:
1674 file_mods:
1674 file_mods:
1675 file_mods:
1675 file_mods:
1676 file_mods: c
1676 file_mods: c
1677 file_mods:
1677 file_mods:
1678 file_mods:
1678 file_mods:
1679 file_mods:
1679 file_mods:
1680 file_mods--verbose:
1680 file_mods--verbose:
1681 file_mods--verbose:
1681 file_mods--verbose:
1682 file_mods--verbose:
1682 file_mods--verbose:
1683 file_mods--verbose:
1683 file_mods--verbose:
1684 file_mods--verbose:
1684 file_mods--verbose:
1685 file_mods--verbose: c
1685 file_mods--verbose: c
1686 file_mods--verbose:
1686 file_mods--verbose:
1687 file_mods--verbose:
1687 file_mods--verbose:
1688 file_mods--verbose:
1688 file_mods--verbose:
1689 file_mods--debug:
1689 file_mods--debug:
1690 file_mods--debug:
1690 file_mods--debug:
1691 file_mods--debug:
1691 file_mods--debug:
1692 file_mods--debug:
1692 file_mods--debug:
1693 file_mods--debug:
1693 file_mods--debug:
1694 file_mods--debug: c
1694 file_mods--debug: c
1695 file_mods--debug:
1695 file_mods--debug:
1696 file_mods--debug:
1696 file_mods--debug:
1697 file_mods--debug:
1697 file_mods--debug:
1698 file_copies: fourth (second)
1698 file_copies: fourth (second)
1699 file_copies:
1699 file_copies:
1700 file_copies:
1700 file_copies:
1701 file_copies:
1701 file_copies:
1702 file_copies:
1702 file_copies:
1703 file_copies:
1703 file_copies:
1704 file_copies:
1704 file_copies:
1705 file_copies:
1705 file_copies:
1706 file_copies:
1706 file_copies:
1707 file_copies--verbose: fourth (second)
1707 file_copies--verbose: fourth (second)
1708 file_copies--verbose:
1708 file_copies--verbose:
1709 file_copies--verbose:
1709 file_copies--verbose:
1710 file_copies--verbose:
1710 file_copies--verbose:
1711 file_copies--verbose:
1711 file_copies--verbose:
1712 file_copies--verbose:
1712 file_copies--verbose:
1713 file_copies--verbose:
1713 file_copies--verbose:
1714 file_copies--verbose:
1714 file_copies--verbose:
1715 file_copies--verbose:
1715 file_copies--verbose:
1716 file_copies--debug: fourth (second)
1716 file_copies--debug: fourth (second)
1717 file_copies--debug:
1717 file_copies--debug:
1718 file_copies--debug:
1718 file_copies--debug:
1719 file_copies--debug:
1719 file_copies--debug:
1720 file_copies--debug:
1720 file_copies--debug:
1721 file_copies--debug:
1721 file_copies--debug:
1722 file_copies--debug:
1722 file_copies--debug:
1723 file_copies--debug:
1723 file_copies--debug:
1724 file_copies--debug:
1724 file_copies--debug:
1725 file_copies_switch:
1725 file_copies_switch:
1726 file_copies_switch:
1726 file_copies_switch:
1727 file_copies_switch:
1727 file_copies_switch:
1728 file_copies_switch:
1728 file_copies_switch:
1729 file_copies_switch:
1729 file_copies_switch:
1730 file_copies_switch:
1730 file_copies_switch:
1731 file_copies_switch:
1731 file_copies_switch:
1732 file_copies_switch:
1732 file_copies_switch:
1733 file_copies_switch:
1733 file_copies_switch:
1734 file_copies_switch--verbose:
1734 file_copies_switch--verbose:
1735 file_copies_switch--verbose:
1735 file_copies_switch--verbose:
1736 file_copies_switch--verbose:
1736 file_copies_switch--verbose:
1737 file_copies_switch--verbose:
1737 file_copies_switch--verbose:
1738 file_copies_switch--verbose:
1738 file_copies_switch--verbose:
1739 file_copies_switch--verbose:
1739 file_copies_switch--verbose:
1740 file_copies_switch--verbose:
1740 file_copies_switch--verbose:
1741 file_copies_switch--verbose:
1741 file_copies_switch--verbose:
1742 file_copies_switch--verbose:
1742 file_copies_switch--verbose:
1743 file_copies_switch--debug:
1743 file_copies_switch--debug:
1744 file_copies_switch--debug:
1744 file_copies_switch--debug:
1745 file_copies_switch--debug:
1745 file_copies_switch--debug:
1746 file_copies_switch--debug:
1746 file_copies_switch--debug:
1747 file_copies_switch--debug:
1747 file_copies_switch--debug:
1748 file_copies_switch--debug:
1748 file_copies_switch--debug:
1749 file_copies_switch--debug:
1749 file_copies_switch--debug:
1750 file_copies_switch--debug:
1750 file_copies_switch--debug:
1751 file_copies_switch--debug:
1751 file_copies_switch--debug:
1752 files: fourth second third
1752 files: fourth second third
1753 files: second
1753 files: second
1754 files:
1754 files:
1755 files: d
1755 files: d
1756 files:
1756 files:
1757 files: c
1757 files: c
1758 files: c
1758 files: c
1759 files: b
1759 files: b
1760 files: a
1760 files: a
1761 files--verbose: fourth second third
1761 files--verbose: fourth second third
1762 files--verbose: second
1762 files--verbose: second
1763 files--verbose:
1763 files--verbose:
1764 files--verbose: d
1764 files--verbose: d
1765 files--verbose:
1765 files--verbose:
1766 files--verbose: c
1766 files--verbose: c
1767 files--verbose: c
1767 files--verbose: c
1768 files--verbose: b
1768 files--verbose: b
1769 files--verbose: a
1769 files--verbose: a
1770 files--debug: fourth second third
1770 files--debug: fourth second third
1771 files--debug: second
1771 files--debug: second
1772 files--debug:
1772 files--debug:
1773 files--debug: d
1773 files--debug: d
1774 files--debug:
1774 files--debug:
1775 files--debug: c
1775 files--debug: c
1776 files--debug: c
1776 files--debug: c
1777 files--debug: b
1777 files--debug: b
1778 files--debug: a
1778 files--debug: a
1779 manifest: 6:94961b75a2da
1779 manifest: 6:94961b75a2da
1780 manifest: 5:f2dbc354b94e
1780 manifest: 5:f2dbc354b94e
1781 manifest: 4:4dc3def4f9b4
1781 manifest: 4:4dc3def4f9b4
1782 manifest: 4:4dc3def4f9b4
1782 manifest: 4:4dc3def4f9b4
1783 manifest: 3:cb5a1327723b
1783 manifest: 3:cb5a1327723b
1784 manifest: 3:cb5a1327723b
1784 manifest: 3:cb5a1327723b
1785 manifest: 2:6e0e82995c35
1785 manifest: 2:6e0e82995c35
1786 manifest: 1:4e8d705b1e53
1786 manifest: 1:4e8d705b1e53
1787 manifest: 0:a0c8bcbbb45c
1787 manifest: 0:a0c8bcbbb45c
1788 manifest--verbose: 6:94961b75a2da
1788 manifest--verbose: 6:94961b75a2da
1789 manifest--verbose: 5:f2dbc354b94e
1789 manifest--verbose: 5:f2dbc354b94e
1790 manifest--verbose: 4:4dc3def4f9b4
1790 manifest--verbose: 4:4dc3def4f9b4
1791 manifest--verbose: 4:4dc3def4f9b4
1791 manifest--verbose: 4:4dc3def4f9b4
1792 manifest--verbose: 3:cb5a1327723b
1792 manifest--verbose: 3:cb5a1327723b
1793 manifest--verbose: 3:cb5a1327723b
1793 manifest--verbose: 3:cb5a1327723b
1794 manifest--verbose: 2:6e0e82995c35
1794 manifest--verbose: 2:6e0e82995c35
1795 manifest--verbose: 1:4e8d705b1e53
1795 manifest--verbose: 1:4e8d705b1e53
1796 manifest--verbose: 0:a0c8bcbbb45c
1796 manifest--verbose: 0:a0c8bcbbb45c
1797 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
1797 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
1798 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
1798 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
1799 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1799 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1800 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1800 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1801 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1801 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1802 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1802 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1803 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
1803 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
1804 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
1804 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
1805 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
1805 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
1806 node: 95c24699272ef57d062b8bccc32c878bf841784a
1806 node: 95c24699272ef57d062b8bccc32c878bf841784a
1807 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1807 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1808 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1808 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1809 node: 13207e5a10d9fd28ec424934298e176197f2c67f
1809 node: 13207e5a10d9fd28ec424934298e176197f2c67f
1810 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1810 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1811 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1811 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1812 node: 97054abb4ab824450e9164180baf491ae0078465
1812 node: 97054abb4ab824450e9164180baf491ae0078465
1813 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1813 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1814 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1814 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1815 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
1815 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
1816 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1816 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1817 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1817 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1818 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1818 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1819 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1819 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1820 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1820 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1821 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1821 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1822 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1822 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1823 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1823 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1824 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
1824 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
1825 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1825 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1826 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1826 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1827 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1827 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1828 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1828 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1829 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1829 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1830 node--debug: 97054abb4ab824450e9164180baf491ae0078465
1830 node--debug: 97054abb4ab824450e9164180baf491ae0078465
1831 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1831 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1832 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1832 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1833 parents:
1833 parents:
1834 parents: -1:000000000000
1834 parents: -1:000000000000
1835 parents: 5:13207e5a10d9 4:bbe44766e73d
1835 parents: 5:13207e5a10d9 4:bbe44766e73d
1836 parents: 3:10e46f2dcbf4
1836 parents: 3:10e46f2dcbf4
1837 parents:
1837 parents:
1838 parents:
1838 parents:
1839 parents:
1839 parents:
1840 parents:
1840 parents:
1841 parents:
1841 parents:
1842 parents--verbose:
1842 parents--verbose:
1843 parents--verbose: -1:000000000000
1843 parents--verbose: -1:000000000000
1844 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
1844 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
1845 parents--verbose: 3:10e46f2dcbf4
1845 parents--verbose: 3:10e46f2dcbf4
1846 parents--verbose:
1846 parents--verbose:
1847 parents--verbose:
1847 parents--verbose:
1848 parents--verbose:
1848 parents--verbose:
1849 parents--verbose:
1849 parents--verbose:
1850 parents--verbose:
1850 parents--verbose:
1851 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
1851 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
1852 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1852 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1853 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
1853 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
1854 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1854 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1855 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1855 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1856 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
1856 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
1857 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
1857 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
1858 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
1858 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
1859 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1859 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1860 rev: 8
1860 rev: 8
1861 rev: 7
1861 rev: 7
1862 rev: 6
1862 rev: 6
1863 rev: 5
1863 rev: 5
1864 rev: 4
1864 rev: 4
1865 rev: 3
1865 rev: 3
1866 rev: 2
1866 rev: 2
1867 rev: 1
1867 rev: 1
1868 rev: 0
1868 rev: 0
1869 rev--verbose: 8
1869 rev--verbose: 8
1870 rev--verbose: 7
1870 rev--verbose: 7
1871 rev--verbose: 6
1871 rev--verbose: 6
1872 rev--verbose: 5
1872 rev--verbose: 5
1873 rev--verbose: 4
1873 rev--verbose: 4
1874 rev--verbose: 3
1874 rev--verbose: 3
1875 rev--verbose: 2
1875 rev--verbose: 2
1876 rev--verbose: 1
1876 rev--verbose: 1
1877 rev--verbose: 0
1877 rev--verbose: 0
1878 rev--debug: 8
1878 rev--debug: 8
1879 rev--debug: 7
1879 rev--debug: 7
1880 rev--debug: 6
1880 rev--debug: 6
1881 rev--debug: 5
1881 rev--debug: 5
1882 rev--debug: 4
1882 rev--debug: 4
1883 rev--debug: 3
1883 rev--debug: 3
1884 rev--debug: 2
1884 rev--debug: 2
1885 rev--debug: 1
1885 rev--debug: 1
1886 rev--debug: 0
1886 rev--debug: 0
1887 tags: tip
1887 tags: tip
1888 tags:
1888 tags:
1889 tags:
1889 tags:
1890 tags:
1890 tags:
1891 tags:
1891 tags:
1892 tags:
1892 tags:
1893 tags:
1893 tags:
1894 tags:
1894 tags:
1895 tags:
1895 tags:
1896 tags--verbose: tip
1896 tags--verbose: tip
1897 tags--verbose:
1897 tags--verbose:
1898 tags--verbose:
1898 tags--verbose:
1899 tags--verbose:
1899 tags--verbose:
1900 tags--verbose:
1900 tags--verbose:
1901 tags--verbose:
1901 tags--verbose:
1902 tags--verbose:
1902 tags--verbose:
1903 tags--verbose:
1903 tags--verbose:
1904 tags--verbose:
1904 tags--verbose:
1905 tags--debug: tip
1905 tags--debug: tip
1906 tags--debug:
1906 tags--debug:
1907 tags--debug:
1907 tags--debug:
1908 tags--debug:
1908 tags--debug:
1909 tags--debug:
1909 tags--debug:
1910 tags--debug:
1910 tags--debug:
1911 tags--debug:
1911 tags--debug:
1912 tags--debug:
1912 tags--debug:
1913 tags--debug:
1913 tags--debug:
1914 diffstat: 3: +2/-1
1914 diffstat: 3: +2/-1
1915 diffstat: 1: +1/-0
1915 diffstat: 1: +1/-0
1916 diffstat: 0: +0/-0
1916 diffstat: 0: +0/-0
1917 diffstat: 1: +1/-0
1917 diffstat: 1: +1/-0
1918 diffstat: 0: +0/-0
1918 diffstat: 0: +0/-0
1919 diffstat: 1: +1/-0
1919 diffstat: 1: +1/-0
1920 diffstat: 1: +4/-0
1920 diffstat: 1: +4/-0
1921 diffstat: 1: +2/-0
1921 diffstat: 1: +2/-0
1922 diffstat: 1: +1/-0
1922 diffstat: 1: +1/-0
1923 diffstat--verbose: 3: +2/-1
1923 diffstat--verbose: 3: +2/-1
1924 diffstat--verbose: 1: +1/-0
1924 diffstat--verbose: 1: +1/-0
1925 diffstat--verbose: 0: +0/-0
1925 diffstat--verbose: 0: +0/-0
1926 diffstat--verbose: 1: +1/-0
1926 diffstat--verbose: 1: +1/-0
1927 diffstat--verbose: 0: +0/-0
1927 diffstat--verbose: 0: +0/-0
1928 diffstat--verbose: 1: +1/-0
1928 diffstat--verbose: 1: +1/-0
1929 diffstat--verbose: 1: +4/-0
1929 diffstat--verbose: 1: +4/-0
1930 diffstat--verbose: 1: +2/-0
1930 diffstat--verbose: 1: +2/-0
1931 diffstat--verbose: 1: +1/-0
1931 diffstat--verbose: 1: +1/-0
1932 diffstat--debug: 3: +2/-1
1932 diffstat--debug: 3: +2/-1
1933 diffstat--debug: 1: +1/-0
1933 diffstat--debug: 1: +1/-0
1934 diffstat--debug: 0: +0/-0
1934 diffstat--debug: 0: +0/-0
1935 diffstat--debug: 1: +1/-0
1935 diffstat--debug: 1: +1/-0
1936 diffstat--debug: 0: +0/-0
1936 diffstat--debug: 0: +0/-0
1937 diffstat--debug: 1: +1/-0
1937 diffstat--debug: 1: +1/-0
1938 diffstat--debug: 1: +4/-0
1938 diffstat--debug: 1: +4/-0
1939 diffstat--debug: 1: +2/-0
1939 diffstat--debug: 1: +2/-0
1940 diffstat--debug: 1: +1/-0
1940 diffstat--debug: 1: +1/-0
1941 extras: branch=default
1941 extras: branch=default
1942 extras: branch=default
1942 extras: branch=default
1943 extras: branch=default
1943 extras: branch=default
1944 extras: branch=default
1944 extras: branch=default
1945 extras: branch=foo
1945 extras: branch=foo
1946 extras: branch=default
1946 extras: branch=default
1947 extras: branch=default
1947 extras: branch=default
1948 extras: branch=default
1948 extras: branch=default
1949 extras: branch=default
1949 extras: branch=default
1950 extras--verbose: branch=default
1950 extras--verbose: branch=default
1951 extras--verbose: branch=default
1951 extras--verbose: branch=default
1952 extras--verbose: branch=default
1952 extras--verbose: branch=default
1953 extras--verbose: branch=default
1953 extras--verbose: branch=default
1954 extras--verbose: branch=foo
1954 extras--verbose: branch=foo
1955 extras--verbose: branch=default
1955 extras--verbose: branch=default
1956 extras--verbose: branch=default
1956 extras--verbose: branch=default
1957 extras--verbose: branch=default
1957 extras--verbose: branch=default
1958 extras--verbose: branch=default
1958 extras--verbose: branch=default
1959 extras--debug: branch=default
1959 extras--debug: branch=default
1960 extras--debug: branch=default
1960 extras--debug: branch=default
1961 extras--debug: branch=default
1961 extras--debug: branch=default
1962 extras--debug: branch=default
1962 extras--debug: branch=default
1963 extras--debug: branch=foo
1963 extras--debug: branch=foo
1964 extras--debug: branch=default
1964 extras--debug: branch=default
1965 extras--debug: branch=default
1965 extras--debug: branch=default
1966 extras--debug: branch=default
1966 extras--debug: branch=default
1967 extras--debug: branch=default
1967 extras--debug: branch=default
1968 p1rev: 7
1968 p1rev: 7
1969 p1rev: -1
1969 p1rev: -1
1970 p1rev: 5
1970 p1rev: 5
1971 p1rev: 3
1971 p1rev: 3
1972 p1rev: 3
1972 p1rev: 3
1973 p1rev: 2
1973 p1rev: 2
1974 p1rev: 1
1974 p1rev: 1
1975 p1rev: 0
1975 p1rev: 0
1976 p1rev: -1
1976 p1rev: -1
1977 p1rev--verbose: 7
1977 p1rev--verbose: 7
1978 p1rev--verbose: -1
1978 p1rev--verbose: -1
1979 p1rev--verbose: 5
1979 p1rev--verbose: 5
1980 p1rev--verbose: 3
1980 p1rev--verbose: 3
1981 p1rev--verbose: 3
1981 p1rev--verbose: 3
1982 p1rev--verbose: 2
1982 p1rev--verbose: 2
1983 p1rev--verbose: 1
1983 p1rev--verbose: 1
1984 p1rev--verbose: 0
1984 p1rev--verbose: 0
1985 p1rev--verbose: -1
1985 p1rev--verbose: -1
1986 p1rev--debug: 7
1986 p1rev--debug: 7
1987 p1rev--debug: -1
1987 p1rev--debug: -1
1988 p1rev--debug: 5
1988 p1rev--debug: 5
1989 p1rev--debug: 3
1989 p1rev--debug: 3
1990 p1rev--debug: 3
1990 p1rev--debug: 3
1991 p1rev--debug: 2
1991 p1rev--debug: 2
1992 p1rev--debug: 1
1992 p1rev--debug: 1
1993 p1rev--debug: 0
1993 p1rev--debug: 0
1994 p1rev--debug: -1
1994 p1rev--debug: -1
1995 p2rev: -1
1995 p2rev: -1
1996 p2rev: -1
1996 p2rev: -1
1997 p2rev: 4
1997 p2rev: 4
1998 p2rev: -1
1998 p2rev: -1
1999 p2rev: -1
1999 p2rev: -1
2000 p2rev: -1
2000 p2rev: -1
2001 p2rev: -1
2001 p2rev: -1
2002 p2rev: -1
2002 p2rev: -1
2003 p2rev: -1
2003 p2rev: -1
2004 p2rev--verbose: -1
2004 p2rev--verbose: -1
2005 p2rev--verbose: -1
2005 p2rev--verbose: -1
2006 p2rev--verbose: 4
2006 p2rev--verbose: 4
2007 p2rev--verbose: -1
2007 p2rev--verbose: -1
2008 p2rev--verbose: -1
2008 p2rev--verbose: -1
2009 p2rev--verbose: -1
2009 p2rev--verbose: -1
2010 p2rev--verbose: -1
2010 p2rev--verbose: -1
2011 p2rev--verbose: -1
2011 p2rev--verbose: -1
2012 p2rev--verbose: -1
2012 p2rev--verbose: -1
2013 p2rev--debug: -1
2013 p2rev--debug: -1
2014 p2rev--debug: -1
2014 p2rev--debug: -1
2015 p2rev--debug: 4
2015 p2rev--debug: 4
2016 p2rev--debug: -1
2016 p2rev--debug: -1
2017 p2rev--debug: -1
2017 p2rev--debug: -1
2018 p2rev--debug: -1
2018 p2rev--debug: -1
2019 p2rev--debug: -1
2019 p2rev--debug: -1
2020 p2rev--debug: -1
2020 p2rev--debug: -1
2021 p2rev--debug: -1
2021 p2rev--debug: -1
2022 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2022 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2023 p1node: 0000000000000000000000000000000000000000
2023 p1node: 0000000000000000000000000000000000000000
2024 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
2024 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
2025 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2025 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2026 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2026 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2027 p1node: 97054abb4ab824450e9164180baf491ae0078465
2027 p1node: 97054abb4ab824450e9164180baf491ae0078465
2028 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2028 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2029 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
2029 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
2030 p1node: 0000000000000000000000000000000000000000
2030 p1node: 0000000000000000000000000000000000000000
2031 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2031 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2032 p1node--verbose: 0000000000000000000000000000000000000000
2032 p1node--verbose: 0000000000000000000000000000000000000000
2033 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
2033 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
2034 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2034 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2035 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2035 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2036 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
2036 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
2037 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2037 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2038 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
2038 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
2039 p1node--verbose: 0000000000000000000000000000000000000000
2039 p1node--verbose: 0000000000000000000000000000000000000000
2040 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2040 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2041 p1node--debug: 0000000000000000000000000000000000000000
2041 p1node--debug: 0000000000000000000000000000000000000000
2042 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
2042 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
2043 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2043 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2044 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2044 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2045 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
2045 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
2046 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2046 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2047 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
2047 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
2048 p1node--debug: 0000000000000000000000000000000000000000
2048 p1node--debug: 0000000000000000000000000000000000000000
2049 p2node: 0000000000000000000000000000000000000000
2049 p2node: 0000000000000000000000000000000000000000
2050 p2node: 0000000000000000000000000000000000000000
2050 p2node: 0000000000000000000000000000000000000000
2051 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2051 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2052 p2node: 0000000000000000000000000000000000000000
2052 p2node: 0000000000000000000000000000000000000000
2053 p2node: 0000000000000000000000000000000000000000
2053 p2node: 0000000000000000000000000000000000000000
2054 p2node: 0000000000000000000000000000000000000000
2054 p2node: 0000000000000000000000000000000000000000
2055 p2node: 0000000000000000000000000000000000000000
2055 p2node: 0000000000000000000000000000000000000000
2056 p2node: 0000000000000000000000000000000000000000
2056 p2node: 0000000000000000000000000000000000000000
2057 p2node: 0000000000000000000000000000000000000000
2057 p2node: 0000000000000000000000000000000000000000
2058 p2node--verbose: 0000000000000000000000000000000000000000
2058 p2node--verbose: 0000000000000000000000000000000000000000
2059 p2node--verbose: 0000000000000000000000000000000000000000
2059 p2node--verbose: 0000000000000000000000000000000000000000
2060 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2060 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2061 p2node--verbose: 0000000000000000000000000000000000000000
2061 p2node--verbose: 0000000000000000000000000000000000000000
2062 p2node--verbose: 0000000000000000000000000000000000000000
2062 p2node--verbose: 0000000000000000000000000000000000000000
2063 p2node--verbose: 0000000000000000000000000000000000000000
2063 p2node--verbose: 0000000000000000000000000000000000000000
2064 p2node--verbose: 0000000000000000000000000000000000000000
2064 p2node--verbose: 0000000000000000000000000000000000000000
2065 p2node--verbose: 0000000000000000000000000000000000000000
2065 p2node--verbose: 0000000000000000000000000000000000000000
2066 p2node--verbose: 0000000000000000000000000000000000000000
2066 p2node--verbose: 0000000000000000000000000000000000000000
2067 p2node--debug: 0000000000000000000000000000000000000000
2067 p2node--debug: 0000000000000000000000000000000000000000
2068 p2node--debug: 0000000000000000000000000000000000000000
2068 p2node--debug: 0000000000000000000000000000000000000000
2069 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2069 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2070 p2node--debug: 0000000000000000000000000000000000000000
2070 p2node--debug: 0000000000000000000000000000000000000000
2071 p2node--debug: 0000000000000000000000000000000000000000
2071 p2node--debug: 0000000000000000000000000000000000000000
2072 p2node--debug: 0000000000000000000000000000000000000000
2072 p2node--debug: 0000000000000000000000000000000000000000
2073 p2node--debug: 0000000000000000000000000000000000000000
2073 p2node--debug: 0000000000000000000000000000000000000000
2074 p2node--debug: 0000000000000000000000000000000000000000
2074 p2node--debug: 0000000000000000000000000000000000000000
2075 p2node--debug: 0000000000000000000000000000000000000000
2075 p2node--debug: 0000000000000000000000000000000000000000
2076
2076
2077 Filters work:
2077 Filters work:
2078
2078
2079 $ hg log --template '{author|domain}\n'
2079 $ hg log --template '{author|domain}\n'
2080
2080
2081 hostname
2081 hostname
2082
2082
2083
2083
2084
2084
2085
2085
2086 place
2086 place
2087 place
2087 place
2088 hostname
2088 hostname
2089
2089
2090 $ hg log --template '{author|person}\n'
2090 $ hg log --template '{author|person}\n'
2091 test
2091 test
2092 User Name
2092 User Name
2093 person
2093 person
2094 person
2094 person
2095 person
2095 person
2096 person
2096 person
2097 other
2097 other
2098 A. N. Other
2098 A. N. Other
2099 User Name
2099 User Name
2100
2100
2101 $ hg log --template '{author|user}\n'
2101 $ hg log --template '{author|user}\n'
2102 test
2102 test
2103 user
2103 user
2104 person
2104 person
2105 person
2105 person
2106 person
2106 person
2107 person
2107 person
2108 other
2108 other
2109 other
2109 other
2110 user
2110 user
2111
2111
2112 $ hg log --template '{date|date}\n'
2112 $ hg log --template '{date|date}\n'
2113 Wed Jan 01 10:01:00 2020 +0000
2113 Wed Jan 01 10:01:00 2020 +0000
2114 Mon Jan 12 13:46:40 1970 +0000
2114 Mon Jan 12 13:46:40 1970 +0000
2115 Sun Jan 18 08:40:01 1970 +0000
2115 Sun Jan 18 08:40:01 1970 +0000
2116 Sun Jan 18 08:40:00 1970 +0000
2116 Sun Jan 18 08:40:00 1970 +0000
2117 Sat Jan 17 04:53:20 1970 +0000
2117 Sat Jan 17 04:53:20 1970 +0000
2118 Fri Jan 16 01:06:40 1970 +0000
2118 Fri Jan 16 01:06:40 1970 +0000
2119 Wed Jan 14 21:20:00 1970 +0000
2119 Wed Jan 14 21:20:00 1970 +0000
2120 Tue Jan 13 17:33:20 1970 +0000
2120 Tue Jan 13 17:33:20 1970 +0000
2121 Mon Jan 12 13:46:40 1970 +0000
2121 Mon Jan 12 13:46:40 1970 +0000
2122
2122
2123 $ hg log --template '{date|isodate}\n'
2123 $ hg log --template '{date|isodate}\n'
2124 2020-01-01 10:01 +0000
2124 2020-01-01 10:01 +0000
2125 1970-01-12 13:46 +0000
2125 1970-01-12 13:46 +0000
2126 1970-01-18 08:40 +0000
2126 1970-01-18 08:40 +0000
2127 1970-01-18 08:40 +0000
2127 1970-01-18 08:40 +0000
2128 1970-01-17 04:53 +0000
2128 1970-01-17 04:53 +0000
2129 1970-01-16 01:06 +0000
2129 1970-01-16 01:06 +0000
2130 1970-01-14 21:20 +0000
2130 1970-01-14 21:20 +0000
2131 1970-01-13 17:33 +0000
2131 1970-01-13 17:33 +0000
2132 1970-01-12 13:46 +0000
2132 1970-01-12 13:46 +0000
2133
2133
2134 $ hg log --template '{date|isodatesec}\n'
2134 $ hg log --template '{date|isodatesec}\n'
2135 2020-01-01 10:01:00 +0000
2135 2020-01-01 10:01:00 +0000
2136 1970-01-12 13:46:40 +0000
2136 1970-01-12 13:46:40 +0000
2137 1970-01-18 08:40:01 +0000
2137 1970-01-18 08:40:01 +0000
2138 1970-01-18 08:40:00 +0000
2138 1970-01-18 08:40:00 +0000
2139 1970-01-17 04:53:20 +0000
2139 1970-01-17 04:53:20 +0000
2140 1970-01-16 01:06:40 +0000
2140 1970-01-16 01:06:40 +0000
2141 1970-01-14 21:20:00 +0000
2141 1970-01-14 21:20:00 +0000
2142 1970-01-13 17:33:20 +0000
2142 1970-01-13 17:33:20 +0000
2143 1970-01-12 13:46:40 +0000
2143 1970-01-12 13:46:40 +0000
2144
2144
2145 $ hg log --template '{date|rfc822date}\n'
2145 $ hg log --template '{date|rfc822date}\n'
2146 Wed, 01 Jan 2020 10:01:00 +0000
2146 Wed, 01 Jan 2020 10:01:00 +0000
2147 Mon, 12 Jan 1970 13:46:40 +0000
2147 Mon, 12 Jan 1970 13:46:40 +0000
2148 Sun, 18 Jan 1970 08:40:01 +0000
2148 Sun, 18 Jan 1970 08:40:01 +0000
2149 Sun, 18 Jan 1970 08:40:00 +0000
2149 Sun, 18 Jan 1970 08:40:00 +0000
2150 Sat, 17 Jan 1970 04:53:20 +0000
2150 Sat, 17 Jan 1970 04:53:20 +0000
2151 Fri, 16 Jan 1970 01:06:40 +0000
2151 Fri, 16 Jan 1970 01:06:40 +0000
2152 Wed, 14 Jan 1970 21:20:00 +0000
2152 Wed, 14 Jan 1970 21:20:00 +0000
2153 Tue, 13 Jan 1970 17:33:20 +0000
2153 Tue, 13 Jan 1970 17:33:20 +0000
2154 Mon, 12 Jan 1970 13:46:40 +0000
2154 Mon, 12 Jan 1970 13:46:40 +0000
2155
2155
2156 $ hg log --template '{desc|firstline}\n'
2156 $ hg log --template '{desc|firstline}\n'
2157 third
2157 third
2158 second
2158 second
2159 merge
2159 merge
2160 new head
2160 new head
2161 new branch
2161 new branch
2162 no user, no domain
2162 no user, no domain
2163 no person
2163 no person
2164 other 1
2164 other 1
2165 line 1
2165 line 1
2166
2166
2167 $ hg log --template '{node|short}\n'
2167 $ hg log --template '{node|short}\n'
2168 95c24699272e
2168 95c24699272e
2169 29114dbae42b
2169 29114dbae42b
2170 d41e714fe50d
2170 d41e714fe50d
2171 13207e5a10d9
2171 13207e5a10d9
2172 bbe44766e73d
2172 bbe44766e73d
2173 10e46f2dcbf4
2173 10e46f2dcbf4
2174 97054abb4ab8
2174 97054abb4ab8
2175 b608e9d1a3f0
2175 b608e9d1a3f0
2176 1e4e1b8f71e0
2176 1e4e1b8f71e0
2177
2177
2178 $ hg log --template '<changeset author="{author|xmlescape}"/>\n'
2178 $ hg log --template '<changeset author="{author|xmlescape}"/>\n'
2179 <changeset author="test"/>
2179 <changeset author="test"/>
2180 <changeset author="User Name &lt;user@hostname&gt;"/>
2180 <changeset author="User Name &lt;user@hostname&gt;"/>
2181 <changeset author="person"/>
2181 <changeset author="person"/>
2182 <changeset author="person"/>
2182 <changeset author="person"/>
2183 <changeset author="person"/>
2183 <changeset author="person"/>
2184 <changeset author="person"/>
2184 <changeset author="person"/>
2185 <changeset author="other@place"/>
2185 <changeset author="other@place"/>
2186 <changeset author="A. N. Other &lt;other@place&gt;"/>
2186 <changeset author="A. N. Other &lt;other@place&gt;"/>
2187 <changeset author="User Name &lt;user@hostname&gt;"/>
2187 <changeset author="User Name &lt;user@hostname&gt;"/>
2188
2188
2189 $ hg log --template '{rev}: {children}\n'
2189 $ hg log --template '{rev}: {children}\n'
2190 8:
2190 8:
2191 7: 8:95c24699272e
2191 7: 8:95c24699272e
2192 6:
2192 6:
2193 5: 6:d41e714fe50d
2193 5: 6:d41e714fe50d
2194 4: 6:d41e714fe50d
2194 4: 6:d41e714fe50d
2195 3: 4:bbe44766e73d 5:13207e5a10d9
2195 3: 4:bbe44766e73d 5:13207e5a10d9
2196 2: 3:10e46f2dcbf4
2196 2: 3:10e46f2dcbf4
2197 1: 2:97054abb4ab8
2197 1: 2:97054abb4ab8
2198 0: 1:b608e9d1a3f0
2198 0: 1:b608e9d1a3f0
2199
2199
2200 Formatnode filter works:
2200 Formatnode filter works:
2201
2201
2202 $ hg -q log -r 0 --template '{node|formatnode}\n'
2202 $ hg -q log -r 0 --template '{node|formatnode}\n'
2203 1e4e1b8f71e0
2203 1e4e1b8f71e0
2204
2204
2205 $ hg log -r 0 --template '{node|formatnode}\n'
2205 $ hg log -r 0 --template '{node|formatnode}\n'
2206 1e4e1b8f71e0
2206 1e4e1b8f71e0
2207
2207
2208 $ hg -v log -r 0 --template '{node|formatnode}\n'
2208 $ hg -v log -r 0 --template '{node|formatnode}\n'
2209 1e4e1b8f71e0
2209 1e4e1b8f71e0
2210
2210
2211 $ hg --debug log -r 0 --template '{node|formatnode}\n'
2211 $ hg --debug log -r 0 --template '{node|formatnode}\n'
2212 1e4e1b8f71e05681d422154f5421e385fec3454f
2212 1e4e1b8f71e05681d422154f5421e385fec3454f
2213
2213
2214 Age filter:
2214 Age filter:
2215
2215
2216 $ hg init unstable-hash
2216 $ hg init unstable-hash
2217 $ cd unstable-hash
2217 $ cd unstable-hash
2218 $ hg log --template '{date|age}\n' > /dev/null || exit 1
2218 $ hg log --template '{date|age}\n' > /dev/null || exit 1
2219
2219
2220 >>> from __future__ import absolute_import
2220 >>> from __future__ import absolute_import
2221 >>> import datetime
2221 >>> import datetime
2222 >>> fp = open('a', 'wb')
2222 >>> fp = open('a', 'wb')
2223 >>> n = datetime.datetime.now() + datetime.timedelta(366 * 7)
2223 >>> n = datetime.datetime.now() + datetime.timedelta(366 * 7)
2224 >>> fp.write(b'%d-%d-%d 00:00' % (n.year, n.month, n.day)) and None
2224 >>> fp.write(b'%d-%d-%d 00:00' % (n.year, n.month, n.day)) and None
2225 >>> fp.close()
2225 >>> fp.close()
2226 $ hg add a
2226 $ hg add a
2227 $ hg commit -m future -d "`cat a`"
2227 $ hg commit -m future -d "`cat a`"
2228
2228
2229 $ hg log -l1 --template '{date|age}\n'
2229 $ hg log -l1 --template '{date|age}\n'
2230 7 years from now
2230 7 years from now
2231
2231
2232 $ cd ..
2232 $ cd ..
2233 $ rm -rf unstable-hash
2233 $ rm -rf unstable-hash
2234
2234
2235 Filename filters:
2235 Filename filters:
2236
2236
2237 $ hg debugtemplate '{"foo/bar"|basename}|{"foo/"|basename}|{"foo"|basename}|\n'
2237 $ hg debugtemplate '{"foo/bar"|basename}|{"foo/"|basename}|{"foo"|basename}|\n'
2238 bar||foo|
2238 bar||foo|
2239 $ hg debugtemplate '{"foo/bar"|dirname}|{"foo/"|dirname}|{"foo"|dirname}|\n'
2239 $ hg debugtemplate '{"foo/bar"|dirname}|{"foo/"|dirname}|{"foo"|dirname}|\n'
2240 foo|foo||
2240 foo|foo||
2241 $ hg debugtemplate '{"foo/bar"|stripdir}|{"foo/"|stripdir}|{"foo"|stripdir}|\n'
2241 $ hg debugtemplate '{"foo/bar"|stripdir}|{"foo/"|stripdir}|{"foo"|stripdir}|\n'
2242 foo|foo|foo|
2242 foo|foo|foo|
2243
2243
2244 Add a dummy commit to make up for the instability of the above:
2244 Add a dummy commit to make up for the instability of the above:
2245
2245
2246 $ echo a > a
2246 $ echo a > a
2247 $ hg add a
2247 $ hg add a
2248 $ hg ci -m future
2248 $ hg ci -m future
2249
2249
2250 Count filter:
2250 Count filter:
2251
2251
2252 $ hg log -l1 --template '{node|count} {node|short|count}\n'
2252 $ hg log -l1 --template '{node|count} {node|short|count}\n'
2253 40 12
2253 40 12
2254
2254
2255 $ hg log -l1 --template '{revset("null^")|count} {revset(".")|count} {revset("0::3")|count}\n'
2255 $ hg log -l1 --template '{revset("null^")|count} {revset(".")|count} {revset("0::3")|count}\n'
2256 0 1 4
2256 0 1 4
2257
2257
2258 $ hg log -G --template '{rev}: children: {children|count}, \
2258 $ hg log -G --template '{rev}: children: {children|count}, \
2259 > tags: {tags|count}, file_adds: {file_adds|count}, \
2259 > tags: {tags|count}, file_adds: {file_adds|count}, \
2260 > ancestors: {revset("ancestors(%s)", rev)|count}'
2260 > ancestors: {revset("ancestors(%s)", rev)|count}'
2261 @ 9: children: 0, tags: 1, file_adds: 1, ancestors: 3
2261 @ 9: children: 0, tags: 1, file_adds: 1, ancestors: 3
2262 |
2262 |
2263 o 8: children: 1, tags: 0, file_adds: 2, ancestors: 2
2263 o 8: children: 1, tags: 0, file_adds: 2, ancestors: 2
2264 |
2264 |
2265 o 7: children: 1, tags: 0, file_adds: 1, ancestors: 1
2265 o 7: children: 1, tags: 0, file_adds: 1, ancestors: 1
2266
2266
2267 o 6: children: 0, tags: 0, file_adds: 0, ancestors: 7
2267 o 6: children: 0, tags: 0, file_adds: 0, ancestors: 7
2268 |\
2268 |\
2269 | o 5: children: 1, tags: 0, file_adds: 1, ancestors: 5
2269 | o 5: children: 1, tags: 0, file_adds: 1, ancestors: 5
2270 | |
2270 | |
2271 o | 4: children: 1, tags: 0, file_adds: 0, ancestors: 5
2271 o | 4: children: 1, tags: 0, file_adds: 0, ancestors: 5
2272 |/
2272 |/
2273 o 3: children: 2, tags: 0, file_adds: 0, ancestors: 4
2273 o 3: children: 2, tags: 0, file_adds: 0, ancestors: 4
2274 |
2274 |
2275 o 2: children: 1, tags: 0, file_adds: 1, ancestors: 3
2275 o 2: children: 1, tags: 0, file_adds: 1, ancestors: 3
2276 |
2276 |
2277 o 1: children: 1, tags: 0, file_adds: 1, ancestors: 2
2277 o 1: children: 1, tags: 0, file_adds: 1, ancestors: 2
2278 |
2278 |
2279 o 0: children: 1, tags: 0, file_adds: 1, ancestors: 1
2279 o 0: children: 1, tags: 0, file_adds: 1, ancestors: 1
2280
2280
2281
2281
2282 $ hg log -l1 -T '{termwidth|count}\n'
2282 $ hg log -l1 -T '{termwidth|count}\n'
2283 hg: parse error: not countable
2283 hg: parse error: not countable
2284 (template filter 'count' is not compatible with keyword 'termwidth')
2284 (template filter 'count' is not compatible with keyword 'termwidth')
2285 [255]
2285 [255]
2286
2286
2287 Upper/lower filters:
2287 Upper/lower filters:
2288
2288
2289 $ hg log -r0 --template '{branch|upper}\n'
2289 $ hg log -r0 --template '{branch|upper}\n'
2290 DEFAULT
2290 DEFAULT
2291 $ hg log -r0 --template '{author|lower}\n'
2291 $ hg log -r0 --template '{author|lower}\n'
2292 user name <user@hostname>
2292 user name <user@hostname>
2293 $ hg log -r0 --template '{date|upper}\n'
2293 $ hg log -r0 --template '{date|upper}\n'
2294 1000000.00
2294 1000000.00
2295
2295
2296 Add a commit that does all possible modifications at once
2296 Add a commit that does all possible modifications at once
2297
2297
2298 $ echo modify >> third
2298 $ echo modify >> third
2299 $ touch b
2299 $ touch b
2300 $ hg add b
2300 $ hg add b
2301 $ hg mv fourth fifth
2301 $ hg mv fourth fifth
2302 $ hg rm a
2302 $ hg rm a
2303 $ hg ci -m "Modify, add, remove, rename"
2303 $ hg ci -m "Modify, add, remove, rename"
2304
2304
2305 Check the status template
2305 Check the status template
2306
2306
2307 $ cat <<EOF >> $HGRCPATH
2307 $ cat <<EOF >> $HGRCPATH
2308 > [extensions]
2308 > [extensions]
2309 > color=
2309 > color=
2310 > EOF
2310 > EOF
2311
2311
2312 $ hg log -T status -r 10
2312 $ hg log -T status -r 10
2313 changeset: 10:0f9759ec227a
2313 changeset: 10:0f9759ec227a
2314 tag: tip
2314 tag: tip
2315 user: test
2315 user: test
2316 date: Thu Jan 01 00:00:00 1970 +0000
2316 date: Thu Jan 01 00:00:00 1970 +0000
2317 summary: Modify, add, remove, rename
2317 summary: Modify, add, remove, rename
2318 files:
2318 files:
2319 M third
2319 M third
2320 A b
2320 A b
2321 A fifth
2321 A fifth
2322 R a
2322 R a
2323 R fourth
2323 R fourth
2324
2324
2325 $ hg log -T status -C -r 10
2325 $ hg log -T status -C -r 10
2326 changeset: 10:0f9759ec227a
2326 changeset: 10:0f9759ec227a
2327 tag: tip
2327 tag: tip
2328 user: test
2328 user: test
2329 date: Thu Jan 01 00:00:00 1970 +0000
2329 date: Thu Jan 01 00:00:00 1970 +0000
2330 summary: Modify, add, remove, rename
2330 summary: Modify, add, remove, rename
2331 files:
2331 files:
2332 M third
2332 M third
2333 A b
2333 A b
2334 A fifth
2334 A fifth
2335 fourth
2335 fourth
2336 R a
2336 R a
2337 R fourth
2337 R fourth
2338
2338
2339 $ hg log -T status -C -r 10 -v
2339 $ hg log -T status -C -r 10 -v
2340 changeset: 10:0f9759ec227a
2340 changeset: 10:0f9759ec227a
2341 tag: tip
2341 tag: tip
2342 user: test
2342 user: test
2343 date: Thu Jan 01 00:00:00 1970 +0000
2343 date: Thu Jan 01 00:00:00 1970 +0000
2344 description:
2344 description:
2345 Modify, add, remove, rename
2345 Modify, add, remove, rename
2346
2346
2347 files:
2347 files:
2348 M third
2348 M third
2349 A b
2349 A b
2350 A fifth
2350 A fifth
2351 fourth
2351 fourth
2352 R a
2352 R a
2353 R fourth
2353 R fourth
2354
2354
2355 $ hg log -T status -C -r 10 --debug
2355 $ hg log -T status -C -r 10 --debug
2356 changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c
2356 changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c
2357 tag: tip
2357 tag: tip
2358 phase: secret
2358 phase: secret
2359 parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066
2359 parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066
2360 parent: -1:0000000000000000000000000000000000000000
2360 parent: -1:0000000000000000000000000000000000000000
2361 manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567
2361 manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567
2362 user: test
2362 user: test
2363 date: Thu Jan 01 00:00:00 1970 +0000
2363 date: Thu Jan 01 00:00:00 1970 +0000
2364 extra: branch=default
2364 extra: branch=default
2365 description:
2365 description:
2366 Modify, add, remove, rename
2366 Modify, add, remove, rename
2367
2367
2368 files:
2368 files:
2369 M third
2369 M third
2370 A b
2370 A b
2371 A fifth
2371 A fifth
2372 fourth
2372 fourth
2373 R a
2373 R a
2374 R fourth
2374 R fourth
2375
2375
2376 $ hg log -T status -C -r 10 --quiet
2376 $ hg log -T status -C -r 10 --quiet
2377 10:0f9759ec227a
2377 10:0f9759ec227a
2378 $ hg --color=debug log -T status -r 10
2378 $ hg --color=debug log -T status -r 10
2379 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2379 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2380 [log.tag|tag: tip]
2380 [log.tag|tag: tip]
2381 [log.user|user: test]
2381 [log.user|user: test]
2382 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2382 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2383 [log.summary|summary: Modify, add, remove, rename]
2383 [log.summary|summary: Modify, add, remove, rename]
2384 [ui.note log.files|files:]
2384 [ui.note log.files|files:]
2385 [status.modified|M third]
2385 [status.modified|M third]
2386 [status.added|A b]
2386 [status.added|A b]
2387 [status.added|A fifth]
2387 [status.added|A fifth]
2388 [status.removed|R a]
2388 [status.removed|R a]
2389 [status.removed|R fourth]
2389 [status.removed|R fourth]
2390
2390
2391 $ hg --color=debug log -T status -C -r 10
2391 $ hg --color=debug log -T status -C -r 10
2392 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2392 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2393 [log.tag|tag: tip]
2393 [log.tag|tag: tip]
2394 [log.user|user: test]
2394 [log.user|user: test]
2395 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2395 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2396 [log.summary|summary: Modify, add, remove, rename]
2396 [log.summary|summary: Modify, add, remove, rename]
2397 [ui.note log.files|files:]
2397 [ui.note log.files|files:]
2398 [status.modified|M third]
2398 [status.modified|M third]
2399 [status.added|A b]
2399 [status.added|A b]
2400 [status.added|A fifth]
2400 [status.added|A fifth]
2401 [status.copied| fourth]
2401 [status.copied| fourth]
2402 [status.removed|R a]
2402 [status.removed|R a]
2403 [status.removed|R fourth]
2403 [status.removed|R fourth]
2404
2404
2405 $ hg --color=debug log -T status -C -r 10 -v
2405 $ hg --color=debug log -T status -C -r 10 -v
2406 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2406 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2407 [log.tag|tag: tip]
2407 [log.tag|tag: tip]
2408 [log.user|user: test]
2408 [log.user|user: test]
2409 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2409 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2410 [ui.note log.description|description:]
2410 [ui.note log.description|description:]
2411 [ui.note log.description|Modify, add, remove, rename]
2411 [ui.note log.description|Modify, add, remove, rename]
2412
2412
2413 [ui.note log.files|files:]
2413 [ui.note log.files|files:]
2414 [status.modified|M third]
2414 [status.modified|M third]
2415 [status.added|A b]
2415 [status.added|A b]
2416 [status.added|A fifth]
2416 [status.added|A fifth]
2417 [status.copied| fourth]
2417 [status.copied| fourth]
2418 [status.removed|R a]
2418 [status.removed|R a]
2419 [status.removed|R fourth]
2419 [status.removed|R fourth]
2420
2420
2421 $ hg --color=debug log -T status -C -r 10 --debug
2421 $ hg --color=debug log -T status -C -r 10 --debug
2422 [log.changeset changeset.secret|changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c]
2422 [log.changeset changeset.secret|changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c]
2423 [log.tag|tag: tip]
2423 [log.tag|tag: tip]
2424 [log.phase|phase: secret]
2424 [log.phase|phase: secret]
2425 [log.parent changeset.secret|parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066]
2425 [log.parent changeset.secret|parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066]
2426 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2426 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2427 [ui.debug log.manifest|manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567]
2427 [ui.debug log.manifest|manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567]
2428 [log.user|user: test]
2428 [log.user|user: test]
2429 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2429 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2430 [ui.debug log.extra|extra: branch=default]
2430 [ui.debug log.extra|extra: branch=default]
2431 [ui.note log.description|description:]
2431 [ui.note log.description|description:]
2432 [ui.note log.description|Modify, add, remove, rename]
2432 [ui.note log.description|Modify, add, remove, rename]
2433
2433
2434 [ui.note log.files|files:]
2434 [ui.note log.files|files:]
2435 [status.modified|M third]
2435 [status.modified|M third]
2436 [status.added|A b]
2436 [status.added|A b]
2437 [status.added|A fifth]
2437 [status.added|A fifth]
2438 [status.copied| fourth]
2438 [status.copied| fourth]
2439 [status.removed|R a]
2439 [status.removed|R a]
2440 [status.removed|R fourth]
2440 [status.removed|R fourth]
2441
2441
2442 $ hg --color=debug log -T status -C -r 10 --quiet
2442 $ hg --color=debug log -T status -C -r 10 --quiet
2443 [log.node|10:0f9759ec227a]
2443 [log.node|10:0f9759ec227a]
2444
2444
2445 Check the bisect template
2445 Check the bisect template
2446
2446
2447 $ hg bisect -g 1
2447 $ hg bisect -g 1
2448 $ hg bisect -b 3 --noupdate
2448 $ hg bisect -b 3 --noupdate
2449 Testing changeset 2:97054abb4ab8 (2 changesets remaining, ~1 tests)
2449 Testing changeset 2:97054abb4ab8 (2 changesets remaining, ~1 tests)
2450 $ hg log -T bisect -r 0:4
2450 $ hg log -T bisect -r 0:4
2451 changeset: 0:1e4e1b8f71e0
2451 changeset: 0:1e4e1b8f71e0
2452 bisect: good (implicit)
2452 bisect: good (implicit)
2453 user: User Name <user@hostname>
2453 user: User Name <user@hostname>
2454 date: Mon Jan 12 13:46:40 1970 +0000
2454 date: Mon Jan 12 13:46:40 1970 +0000
2455 summary: line 1
2455 summary: line 1
2456
2456
2457 changeset: 1:b608e9d1a3f0
2457 changeset: 1:b608e9d1a3f0
2458 bisect: good
2458 bisect: good
2459 user: A. N. Other <other@place>
2459 user: A. N. Other <other@place>
2460 date: Tue Jan 13 17:33:20 1970 +0000
2460 date: Tue Jan 13 17:33:20 1970 +0000
2461 summary: other 1
2461 summary: other 1
2462
2462
2463 changeset: 2:97054abb4ab8
2463 changeset: 2:97054abb4ab8
2464 bisect: untested
2464 bisect: untested
2465 user: other@place
2465 user: other@place
2466 date: Wed Jan 14 21:20:00 1970 +0000
2466 date: Wed Jan 14 21:20:00 1970 +0000
2467 summary: no person
2467 summary: no person
2468
2468
2469 changeset: 3:10e46f2dcbf4
2469 changeset: 3:10e46f2dcbf4
2470 bisect: bad
2470 bisect: bad
2471 user: person
2471 user: person
2472 date: Fri Jan 16 01:06:40 1970 +0000
2472 date: Fri Jan 16 01:06:40 1970 +0000
2473 summary: no user, no domain
2473 summary: no user, no domain
2474
2474
2475 changeset: 4:bbe44766e73d
2475 changeset: 4:bbe44766e73d
2476 bisect: bad (implicit)
2476 bisect: bad (implicit)
2477 branch: foo
2477 branch: foo
2478 user: person
2478 user: person
2479 date: Sat Jan 17 04:53:20 1970 +0000
2479 date: Sat Jan 17 04:53:20 1970 +0000
2480 summary: new branch
2480 summary: new branch
2481
2481
2482 $ hg log --debug -T bisect -r 0:4
2482 $ hg log --debug -T bisect -r 0:4
2483 changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2483 changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2484 bisect: good (implicit)
2484 bisect: good (implicit)
2485 phase: public
2485 phase: public
2486 parent: -1:0000000000000000000000000000000000000000
2486 parent: -1:0000000000000000000000000000000000000000
2487 parent: -1:0000000000000000000000000000000000000000
2487 parent: -1:0000000000000000000000000000000000000000
2488 manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
2488 manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
2489 user: User Name <user@hostname>
2489 user: User Name <user@hostname>
2490 date: Mon Jan 12 13:46:40 1970 +0000
2490 date: Mon Jan 12 13:46:40 1970 +0000
2491 files+: a
2491 files+: a
2492 extra: branch=default
2492 extra: branch=default
2493 description:
2493 description:
2494 line 1
2494 line 1
2495 line 2
2495 line 2
2496
2496
2497
2497
2498 changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2498 changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2499 bisect: good
2499 bisect: good
2500 phase: public
2500 phase: public
2501 parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2501 parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2502 parent: -1:0000000000000000000000000000000000000000
2502 parent: -1:0000000000000000000000000000000000000000
2503 manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
2503 manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
2504 user: A. N. Other <other@place>
2504 user: A. N. Other <other@place>
2505 date: Tue Jan 13 17:33:20 1970 +0000
2505 date: Tue Jan 13 17:33:20 1970 +0000
2506 files+: b
2506 files+: b
2507 extra: branch=default
2507 extra: branch=default
2508 description:
2508 description:
2509 other 1
2509 other 1
2510 other 2
2510 other 2
2511
2511
2512 other 3
2512 other 3
2513
2513
2514
2514
2515 changeset: 2:97054abb4ab824450e9164180baf491ae0078465
2515 changeset: 2:97054abb4ab824450e9164180baf491ae0078465
2516 bisect: untested
2516 bisect: untested
2517 phase: public
2517 phase: public
2518 parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2518 parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2519 parent: -1:0000000000000000000000000000000000000000
2519 parent: -1:0000000000000000000000000000000000000000
2520 manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
2520 manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
2521 user: other@place
2521 user: other@place
2522 date: Wed Jan 14 21:20:00 1970 +0000
2522 date: Wed Jan 14 21:20:00 1970 +0000
2523 files+: c
2523 files+: c
2524 extra: branch=default
2524 extra: branch=default
2525 description:
2525 description:
2526 no person
2526 no person
2527
2527
2528
2528
2529 changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2529 changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2530 bisect: bad
2530 bisect: bad
2531 phase: public
2531 phase: public
2532 parent: 2:97054abb4ab824450e9164180baf491ae0078465
2532 parent: 2:97054abb4ab824450e9164180baf491ae0078465
2533 parent: -1:0000000000000000000000000000000000000000
2533 parent: -1:0000000000000000000000000000000000000000
2534 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2534 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2535 user: person
2535 user: person
2536 date: Fri Jan 16 01:06:40 1970 +0000
2536 date: Fri Jan 16 01:06:40 1970 +0000
2537 files: c
2537 files: c
2538 extra: branch=default
2538 extra: branch=default
2539 description:
2539 description:
2540 no user, no domain
2540 no user, no domain
2541
2541
2542
2542
2543 changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
2543 changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
2544 bisect: bad (implicit)
2544 bisect: bad (implicit)
2545 branch: foo
2545 branch: foo
2546 phase: draft
2546 phase: draft
2547 parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2547 parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2548 parent: -1:0000000000000000000000000000000000000000
2548 parent: -1:0000000000000000000000000000000000000000
2549 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2549 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2550 user: person
2550 user: person
2551 date: Sat Jan 17 04:53:20 1970 +0000
2551 date: Sat Jan 17 04:53:20 1970 +0000
2552 extra: branch=foo
2552 extra: branch=foo
2553 description:
2553 description:
2554 new branch
2554 new branch
2555
2555
2556
2556
2557 $ hg log -v -T bisect -r 0:4
2557 $ hg log -v -T bisect -r 0:4
2558 changeset: 0:1e4e1b8f71e0
2558 changeset: 0:1e4e1b8f71e0
2559 bisect: good (implicit)
2559 bisect: good (implicit)
2560 user: User Name <user@hostname>
2560 user: User Name <user@hostname>
2561 date: Mon Jan 12 13:46:40 1970 +0000
2561 date: Mon Jan 12 13:46:40 1970 +0000
2562 files: a
2562 files: a
2563 description:
2563 description:
2564 line 1
2564 line 1
2565 line 2
2565 line 2
2566
2566
2567
2567
2568 changeset: 1:b608e9d1a3f0
2568 changeset: 1:b608e9d1a3f0
2569 bisect: good
2569 bisect: good
2570 user: A. N. Other <other@place>
2570 user: A. N. Other <other@place>
2571 date: Tue Jan 13 17:33:20 1970 +0000
2571 date: Tue Jan 13 17:33:20 1970 +0000
2572 files: b
2572 files: b
2573 description:
2573 description:
2574 other 1
2574 other 1
2575 other 2
2575 other 2
2576
2576
2577 other 3
2577 other 3
2578
2578
2579
2579
2580 changeset: 2:97054abb4ab8
2580 changeset: 2:97054abb4ab8
2581 bisect: untested
2581 bisect: untested
2582 user: other@place
2582 user: other@place
2583 date: Wed Jan 14 21:20:00 1970 +0000
2583 date: Wed Jan 14 21:20:00 1970 +0000
2584 files: c
2584 files: c
2585 description:
2585 description:
2586 no person
2586 no person
2587
2587
2588
2588
2589 changeset: 3:10e46f2dcbf4
2589 changeset: 3:10e46f2dcbf4
2590 bisect: bad
2590 bisect: bad
2591 user: person
2591 user: person
2592 date: Fri Jan 16 01:06:40 1970 +0000
2592 date: Fri Jan 16 01:06:40 1970 +0000
2593 files: c
2593 files: c
2594 description:
2594 description:
2595 no user, no domain
2595 no user, no domain
2596
2596
2597
2597
2598 changeset: 4:bbe44766e73d
2598 changeset: 4:bbe44766e73d
2599 bisect: bad (implicit)
2599 bisect: bad (implicit)
2600 branch: foo
2600 branch: foo
2601 user: person
2601 user: person
2602 date: Sat Jan 17 04:53:20 1970 +0000
2602 date: Sat Jan 17 04:53:20 1970 +0000
2603 description:
2603 description:
2604 new branch
2604 new branch
2605
2605
2606
2606
2607 $ hg --color=debug log -T bisect -r 0:4
2607 $ hg --color=debug log -T bisect -r 0:4
2608 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2608 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2609 [log.bisect bisect.good|bisect: good (implicit)]
2609 [log.bisect bisect.good|bisect: good (implicit)]
2610 [log.user|user: User Name <user@hostname>]
2610 [log.user|user: User Name <user@hostname>]
2611 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2611 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2612 [log.summary|summary: line 1]
2612 [log.summary|summary: line 1]
2613
2613
2614 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2614 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2615 [log.bisect bisect.good|bisect: good]
2615 [log.bisect bisect.good|bisect: good]
2616 [log.user|user: A. N. Other <other@place>]
2616 [log.user|user: A. N. Other <other@place>]
2617 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2617 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2618 [log.summary|summary: other 1]
2618 [log.summary|summary: other 1]
2619
2619
2620 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2620 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2621 [log.bisect bisect.untested|bisect: untested]
2621 [log.bisect bisect.untested|bisect: untested]
2622 [log.user|user: other@place]
2622 [log.user|user: other@place]
2623 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2623 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2624 [log.summary|summary: no person]
2624 [log.summary|summary: no person]
2625
2625
2626 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2626 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2627 [log.bisect bisect.bad|bisect: bad]
2627 [log.bisect bisect.bad|bisect: bad]
2628 [log.user|user: person]
2628 [log.user|user: person]
2629 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2629 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2630 [log.summary|summary: no user, no domain]
2630 [log.summary|summary: no user, no domain]
2631
2631
2632 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2632 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2633 [log.bisect bisect.bad|bisect: bad (implicit)]
2633 [log.bisect bisect.bad|bisect: bad (implicit)]
2634 [log.branch|branch: foo]
2634 [log.branch|branch: foo]
2635 [log.user|user: person]
2635 [log.user|user: person]
2636 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2636 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2637 [log.summary|summary: new branch]
2637 [log.summary|summary: new branch]
2638
2638
2639 $ hg --color=debug log --debug -T bisect -r 0:4
2639 $ hg --color=debug log --debug -T bisect -r 0:4
2640 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2640 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2641 [log.bisect bisect.good|bisect: good (implicit)]
2641 [log.bisect bisect.good|bisect: good (implicit)]
2642 [log.phase|phase: public]
2642 [log.phase|phase: public]
2643 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2643 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2644 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2644 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2645 [ui.debug log.manifest|manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0]
2645 [ui.debug log.manifest|manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0]
2646 [log.user|user: User Name <user@hostname>]
2646 [log.user|user: User Name <user@hostname>]
2647 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2647 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2648 [ui.debug log.files|files+: a]
2648 [ui.debug log.files|files+: a]
2649 [ui.debug log.extra|extra: branch=default]
2649 [ui.debug log.extra|extra: branch=default]
2650 [ui.note log.description|description:]
2650 [ui.note log.description|description:]
2651 [ui.note log.description|line 1
2651 [ui.note log.description|line 1
2652 line 2]
2652 line 2]
2653
2653
2654
2654
2655 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2655 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2656 [log.bisect bisect.good|bisect: good]
2656 [log.bisect bisect.good|bisect: good]
2657 [log.phase|phase: public]
2657 [log.phase|phase: public]
2658 [log.parent changeset.public|parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2658 [log.parent changeset.public|parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2659 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2659 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2660 [ui.debug log.manifest|manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55]
2660 [ui.debug log.manifest|manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55]
2661 [log.user|user: A. N. Other <other@place>]
2661 [log.user|user: A. N. Other <other@place>]
2662 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2662 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2663 [ui.debug log.files|files+: b]
2663 [ui.debug log.files|files+: b]
2664 [ui.debug log.extra|extra: branch=default]
2664 [ui.debug log.extra|extra: branch=default]
2665 [ui.note log.description|description:]
2665 [ui.note log.description|description:]
2666 [ui.note log.description|other 1
2666 [ui.note log.description|other 1
2667 other 2
2667 other 2
2668
2668
2669 other 3]
2669 other 3]
2670
2670
2671
2671
2672 [log.changeset changeset.public|changeset: 2:97054abb4ab824450e9164180baf491ae0078465]
2672 [log.changeset changeset.public|changeset: 2:97054abb4ab824450e9164180baf491ae0078465]
2673 [log.bisect bisect.untested|bisect: untested]
2673 [log.bisect bisect.untested|bisect: untested]
2674 [log.phase|phase: public]
2674 [log.phase|phase: public]
2675 [log.parent changeset.public|parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2675 [log.parent changeset.public|parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2676 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2676 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2677 [ui.debug log.manifest|manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1]
2677 [ui.debug log.manifest|manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1]
2678 [log.user|user: other@place]
2678 [log.user|user: other@place]
2679 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2679 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2680 [ui.debug log.files|files+: c]
2680 [ui.debug log.files|files+: c]
2681 [ui.debug log.extra|extra: branch=default]
2681 [ui.debug log.extra|extra: branch=default]
2682 [ui.note log.description|description:]
2682 [ui.note log.description|description:]
2683 [ui.note log.description|no person]
2683 [ui.note log.description|no person]
2684
2684
2685
2685
2686 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2686 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2687 [log.bisect bisect.bad|bisect: bad]
2687 [log.bisect bisect.bad|bisect: bad]
2688 [log.phase|phase: public]
2688 [log.phase|phase: public]
2689 [log.parent changeset.public|parent: 2:97054abb4ab824450e9164180baf491ae0078465]
2689 [log.parent changeset.public|parent: 2:97054abb4ab824450e9164180baf491ae0078465]
2690 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2690 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2691 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2691 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2692 [log.user|user: person]
2692 [log.user|user: person]
2693 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2693 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2694 [ui.debug log.files|files: c]
2694 [ui.debug log.files|files: c]
2695 [ui.debug log.extra|extra: branch=default]
2695 [ui.debug log.extra|extra: branch=default]
2696 [ui.note log.description|description:]
2696 [ui.note log.description|description:]
2697 [ui.note log.description|no user, no domain]
2697 [ui.note log.description|no user, no domain]
2698
2698
2699
2699
2700 [log.changeset changeset.draft|changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74]
2700 [log.changeset changeset.draft|changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74]
2701 [log.bisect bisect.bad|bisect: bad (implicit)]
2701 [log.bisect bisect.bad|bisect: bad (implicit)]
2702 [log.branch|branch: foo]
2702 [log.branch|branch: foo]
2703 [log.phase|phase: draft]
2703 [log.phase|phase: draft]
2704 [log.parent changeset.public|parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2704 [log.parent changeset.public|parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2705 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2705 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2706 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2706 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2707 [log.user|user: person]
2707 [log.user|user: person]
2708 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2708 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2709 [ui.debug log.extra|extra: branch=foo]
2709 [ui.debug log.extra|extra: branch=foo]
2710 [ui.note log.description|description:]
2710 [ui.note log.description|description:]
2711 [ui.note log.description|new branch]
2711 [ui.note log.description|new branch]
2712
2712
2713
2713
2714 $ hg --color=debug log -v -T bisect -r 0:4
2714 $ hg --color=debug log -v -T bisect -r 0:4
2715 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2715 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2716 [log.bisect bisect.good|bisect: good (implicit)]
2716 [log.bisect bisect.good|bisect: good (implicit)]
2717 [log.user|user: User Name <user@hostname>]
2717 [log.user|user: User Name <user@hostname>]
2718 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2718 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2719 [ui.note log.files|files: a]
2719 [ui.note log.files|files: a]
2720 [ui.note log.description|description:]
2720 [ui.note log.description|description:]
2721 [ui.note log.description|line 1
2721 [ui.note log.description|line 1
2722 line 2]
2722 line 2]
2723
2723
2724
2724
2725 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2725 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2726 [log.bisect bisect.good|bisect: good]
2726 [log.bisect bisect.good|bisect: good]
2727 [log.user|user: A. N. Other <other@place>]
2727 [log.user|user: A. N. Other <other@place>]
2728 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2728 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2729 [ui.note log.files|files: b]
2729 [ui.note log.files|files: b]
2730 [ui.note log.description|description:]
2730 [ui.note log.description|description:]
2731 [ui.note log.description|other 1
2731 [ui.note log.description|other 1
2732 other 2
2732 other 2
2733
2733
2734 other 3]
2734 other 3]
2735
2735
2736
2736
2737 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2737 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2738 [log.bisect bisect.untested|bisect: untested]
2738 [log.bisect bisect.untested|bisect: untested]
2739 [log.user|user: other@place]
2739 [log.user|user: other@place]
2740 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2740 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2741 [ui.note log.files|files: c]
2741 [ui.note log.files|files: c]
2742 [ui.note log.description|description:]
2742 [ui.note log.description|description:]
2743 [ui.note log.description|no person]
2743 [ui.note log.description|no person]
2744
2744
2745
2745
2746 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2746 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2747 [log.bisect bisect.bad|bisect: bad]
2747 [log.bisect bisect.bad|bisect: bad]
2748 [log.user|user: person]
2748 [log.user|user: person]
2749 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2749 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2750 [ui.note log.files|files: c]
2750 [ui.note log.files|files: c]
2751 [ui.note log.description|description:]
2751 [ui.note log.description|description:]
2752 [ui.note log.description|no user, no domain]
2752 [ui.note log.description|no user, no domain]
2753
2753
2754
2754
2755 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2755 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2756 [log.bisect bisect.bad|bisect: bad (implicit)]
2756 [log.bisect bisect.bad|bisect: bad (implicit)]
2757 [log.branch|branch: foo]
2757 [log.branch|branch: foo]
2758 [log.user|user: person]
2758 [log.user|user: person]
2759 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2759 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2760 [ui.note log.description|description:]
2760 [ui.note log.description|description:]
2761 [ui.note log.description|new branch]
2761 [ui.note log.description|new branch]
2762
2762
2763
2763
2764 $ hg bisect --reset
2764 $ hg bisect --reset
2765
2765
2766 Error on syntax:
2766 Error on syntax:
2767
2767
2768 $ echo 'x = "f' >> t
2768 $ echo 'x = "f' >> t
2769 $ hg log
2769 $ hg log
2770 hg: parse error at t:3: unmatched quotes
2770 hg: parse error at t:3: unmatched quotes
2771 [255]
2771 [255]
2772
2772
2773 $ hg log -T '{date'
2773 $ hg log -T '{date'
2774 hg: parse error at 1: unterminated template expansion
2774 hg: parse error at 1: unterminated template expansion
2775 ({date
2775 ({date
2776 ^ here)
2776 ^ here)
2777 [255]
2777 [255]
2778 $ hg log -T '{date(}'
2778 $ hg log -T '{date(}'
2779 hg: parse error at 6: not a prefix: end
2779 hg: parse error at 6: not a prefix: end
2780 ({date(}
2780 ({date(}
2781 ^ here)
2781 ^ here)
2782 [255]
2782 [255]
2783 $ hg log -T '{date)}'
2783 $ hg log -T '{date)}'
2784 hg: parse error at 5: invalid token
2784 hg: parse error at 5: invalid token
2785 ({date)}
2785 ({date)}
2786 ^ here)
2786 ^ here)
2787 [255]
2787 [255]
2788 $ hg log -T '{date date}'
2788 $ hg log -T '{date date}'
2789 hg: parse error at 6: invalid token
2789 hg: parse error at 6: invalid token
2790 ({date date}
2790 ({date date}
2791 ^ here)
2791 ^ here)
2792 [255]
2792 [255]
2793
2793
2794 $ hg log -T '{}'
2794 $ hg log -T '{}'
2795 hg: parse error at 1: not a prefix: end
2795 hg: parse error at 1: not a prefix: end
2796 ({}
2796 ({}
2797 ^ here)
2797 ^ here)
2798 [255]
2798 [255]
2799 $ hg debugtemplate -v '{()}'
2799 $ hg debugtemplate -v '{()}'
2800 (template
2800 (template
2801 (group
2801 (group
2802 None))
2802 None))
2803 hg: parse error: missing argument
2803 hg: parse error: missing argument
2804 [255]
2804 [255]
2805
2805
2806 Behind the scenes, this would throw TypeError without intype=bytes
2806 Behind the scenes, this would throw TypeError without intype=bytes
2807
2807
2808 $ hg log -l 3 --template '{date|obfuscate}\n'
2808 $ hg log -l 3 --template '{date|obfuscate}\n'
2809 &#48;&#46;&#48;&#48;
2809 &#48;&#46;&#48;&#48;
2810 &#48;&#46;&#48;&#48;
2810 &#48;&#46;&#48;&#48;
2811 &#49;&#53;&#55;&#55;&#56;&#55;&#50;&#56;&#54;&#48;&#46;&#48;&#48;
2811 &#49;&#53;&#55;&#55;&#56;&#55;&#50;&#56;&#54;&#48;&#46;&#48;&#48;
2812
2812
2813 Behind the scenes, this will throw a ValueError
2813 Behind the scenes, this will throw a ValueError
2814
2814
2815 $ hg log -l 3 --template 'line: {desc|shortdate}\n'
2815 $ hg log -l 3 --template 'line: {desc|shortdate}\n'
2816 hg: parse error: invalid date: 'Modify, add, remove, rename'
2816 hg: parse error: invalid date: 'Modify, add, remove, rename'
2817 (template filter 'shortdate' is not compatible with keyword 'desc')
2817 (template filter 'shortdate' is not compatible with keyword 'desc')
2818 [255]
2818 [255]
2819
2819
2820 Behind the scenes, this would throw AttributeError without intype=bytes
2820 Behind the scenes, this would throw AttributeError without intype=bytes
2821
2821
2822 $ hg log -l 3 --template 'line: {date|escape}\n'
2822 $ hg log -l 3 --template 'line: {date|escape}\n'
2823 line: 0.00
2823 line: 0.00
2824 line: 0.00
2824 line: 0.00
2825 line: 1577872860.00
2825 line: 1577872860.00
2826
2826
2827 $ hg log -l 3 --template 'line: {extras|localdate}\n'
2827 $ hg log -l 3 --template 'line: {extras|localdate}\n'
2828 hg: parse error: localdate expects a date information
2828 hg: parse error: localdate expects a date information
2829 [255]
2829 [255]
2830
2830
2831 Behind the scenes, this will throw ValueError
2831 Behind the scenes, this will throw ValueError
2832
2832
2833 $ hg tip --template '{author|email|date}\n'
2833 $ hg tip --template '{author|email|date}\n'
2834 hg: parse error: date expects a date information
2834 hg: parse error: date expects a date information
2835 [255]
2835 [255]
2836
2836
2837 $ hg tip -T '{author|email|shortdate}\n'
2837 $ hg tip -T '{author|email|shortdate}\n'
2838 hg: parse error: invalid date: 'test'
2838 hg: parse error: invalid date: 'test'
2839 (template filter 'shortdate' is not compatible with keyword 'author')
2839 (template filter 'shortdate' is not compatible with keyword 'author')
2840 [255]
2840 [255]
2841
2841
2842 $ hg tip -T '{get(extras, "branch")|shortdate}\n'
2842 $ hg tip -T '{get(extras, "branch")|shortdate}\n'
2843 hg: parse error: invalid date: 'default'
2843 hg: parse error: invalid date: 'default'
2844 (incompatible use of template filter 'shortdate')
2844 (incompatible use of template filter 'shortdate')
2845 [255]
2845 [255]
2846
2846
2847 Error in nested template:
2847 Error in nested template:
2848
2848
2849 $ hg log -T '{"date'
2849 $ hg log -T '{"date'
2850 hg: parse error at 2: unterminated string
2850 hg: parse error at 2: unterminated string
2851 ({"date
2851 ({"date
2852 ^ here)
2852 ^ here)
2853 [255]
2853 [255]
2854
2854
2855 $ hg log -T '{"foo{date|?}"}'
2855 $ hg log -T '{"foo{date|?}"}'
2856 hg: parse error at 11: syntax error
2856 hg: parse error at 11: syntax error
2857 ({"foo{date|?}"}
2857 ({"foo{date|?}"}
2858 ^ here)
2858 ^ here)
2859 [255]
2859 [255]
2860
2860
2861 Thrown an error if a template function doesn't exist
2861 Thrown an error if a template function doesn't exist
2862
2862
2863 $ hg tip --template '{foo()}\n'
2863 $ hg tip --template '{foo()}\n'
2864 hg: parse error: unknown function 'foo'
2864 hg: parse error: unknown function 'foo'
2865 [255]
2865 [255]
2866
2866
2867 Pass generator object created by template function to filter
2867 Pass generator object created by template function to filter
2868
2868
2869 $ hg log -l 1 --template '{if(author, author)|user}\n'
2869 $ hg log -l 1 --template '{if(author, author)|user}\n'
2870 test
2870 test
2871
2871
2872 Test index keyword:
2872 Test index keyword:
2873
2873
2874 $ hg log -l 2 -T '{index + 10}{files % " {index}:{file}"}\n'
2874 $ hg log -l 2 -T '{index + 10}{files % " {index}:{file}"}\n'
2875 10 0:a 1:b 2:fifth 3:fourth 4:third
2875 10 0:a 1:b 2:fifth 3:fourth 4:third
2876 11 0:a
2876 11 0:a
2877
2877
2878 $ hg branches -T '{index} {branch}\n'
2878 $ hg branches -T '{index} {branch}\n'
2879 0 default
2879 0 default
2880 1 foo
2880 1 foo
2881
2881
2882 Test diff function:
2882 Test diff function:
2883
2883
2884 $ hg diff -c 8
2884 $ hg diff -c 8
2885 diff -r 29114dbae42b -r 95c24699272e fourth
2885 diff -r 29114dbae42b -r 95c24699272e fourth
2886 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2886 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2887 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2887 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2888 @@ -0,0 +1,1 @@
2888 @@ -0,0 +1,1 @@
2889 +second
2889 +second
2890 diff -r 29114dbae42b -r 95c24699272e second
2890 diff -r 29114dbae42b -r 95c24699272e second
2891 --- a/second Mon Jan 12 13:46:40 1970 +0000
2891 --- a/second Mon Jan 12 13:46:40 1970 +0000
2892 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2892 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2893 @@ -1,1 +0,0 @@
2893 @@ -1,1 +0,0 @@
2894 -second
2894 -second
2895 diff -r 29114dbae42b -r 95c24699272e third
2895 diff -r 29114dbae42b -r 95c24699272e third
2896 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2896 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2897 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2897 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2898 @@ -0,0 +1,1 @@
2898 @@ -0,0 +1,1 @@
2899 +third
2899 +third
2900
2900
2901 $ hg log -r 8 -T "{diff()}"
2901 $ hg log -r 8 -T "{diff()}"
2902 diff -r 29114dbae42b -r 95c24699272e fourth
2902 diff -r 29114dbae42b -r 95c24699272e fourth
2903 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2903 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2904 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2904 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2905 @@ -0,0 +1,1 @@
2905 @@ -0,0 +1,1 @@
2906 +second
2906 +second
2907 diff -r 29114dbae42b -r 95c24699272e second
2907 diff -r 29114dbae42b -r 95c24699272e second
2908 --- a/second Mon Jan 12 13:46:40 1970 +0000
2908 --- a/second Mon Jan 12 13:46:40 1970 +0000
2909 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2909 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2910 @@ -1,1 +0,0 @@
2910 @@ -1,1 +0,0 @@
2911 -second
2911 -second
2912 diff -r 29114dbae42b -r 95c24699272e third
2912 diff -r 29114dbae42b -r 95c24699272e third
2913 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2913 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2914 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2914 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2915 @@ -0,0 +1,1 @@
2915 @@ -0,0 +1,1 @@
2916 +third
2916 +third
2917
2917
2918 $ hg log -r 8 -T "{diff('glob:f*')}"
2918 $ hg log -r 8 -T "{diff('glob:f*')}"
2919 diff -r 29114dbae42b -r 95c24699272e fourth
2919 diff -r 29114dbae42b -r 95c24699272e fourth
2920 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2920 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2921 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2921 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2922 @@ -0,0 +1,1 @@
2922 @@ -0,0 +1,1 @@
2923 +second
2923 +second
2924
2924
2925 $ hg log -r 8 -T "{diff('', 'glob:f*')}"
2925 $ hg log -r 8 -T "{diff('', 'glob:f*')}"
2926 diff -r 29114dbae42b -r 95c24699272e second
2926 diff -r 29114dbae42b -r 95c24699272e second
2927 --- a/second Mon Jan 12 13:46:40 1970 +0000
2927 --- a/second Mon Jan 12 13:46:40 1970 +0000
2928 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2928 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2929 @@ -1,1 +0,0 @@
2929 @@ -1,1 +0,0 @@
2930 -second
2930 -second
2931 diff -r 29114dbae42b -r 95c24699272e third
2931 diff -r 29114dbae42b -r 95c24699272e third
2932 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2932 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2933 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2933 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2934 @@ -0,0 +1,1 @@
2934 @@ -0,0 +1,1 @@
2935 +third
2935 +third
2936
2936
2937 $ hg log -r 8 -T "{diff('FOURTH'|lower)}"
2937 $ hg log -r 8 -T "{diff('FOURTH'|lower)}"
2938 diff -r 29114dbae42b -r 95c24699272e fourth
2938 diff -r 29114dbae42b -r 95c24699272e fourth
2939 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2939 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2940 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2940 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2941 @@ -0,0 +1,1 @@
2941 @@ -0,0 +1,1 @@
2942 +second
2942 +second
2943
2943
2944 ui verbosity:
2944 ui verbosity:
2945
2945
2946 $ hg log -l1 -T '{verbosity}\n'
2946 $ hg log -l1 -T '{verbosity}\n'
2947
2947
2948 $ hg log -l1 -T '{verbosity}\n' --debug
2948 $ hg log -l1 -T '{verbosity}\n' --debug
2949 debug
2949 debug
2950 $ hg log -l1 -T '{verbosity}\n' --quiet
2950 $ hg log -l1 -T '{verbosity}\n' --quiet
2951 quiet
2951 quiet
2952 $ hg log -l1 -T '{verbosity}\n' --verbose
2952 $ hg log -l1 -T '{verbosity}\n' --verbose
2953 verbose
2953 verbose
2954
2954
2955 $ cd ..
2955 $ cd ..
2956
2956
2957
2957
2958 latesttag:
2958 latesttag:
2959
2959
2960 $ hg init latesttag
2960 $ hg init latesttag
2961 $ cd latesttag
2961 $ cd latesttag
2962
2962
2963 $ echo a > file
2963 $ echo a > file
2964 $ hg ci -Am a -d '0 0'
2964 $ hg ci -Am a -d '0 0'
2965 adding file
2965 adding file
2966
2966
2967 $ echo b >> file
2967 $ echo b >> file
2968 $ hg ci -m b -d '1 0'
2968 $ hg ci -m b -d '1 0'
2969
2969
2970 $ echo c >> head1
2970 $ echo c >> head1
2971 $ hg ci -Am h1c -d '2 0'
2971 $ hg ci -Am h1c -d '2 0'
2972 adding head1
2972 adding head1
2973
2973
2974 $ hg update -q 1
2974 $ hg update -q 1
2975 $ echo d >> head2
2975 $ echo d >> head2
2976 $ hg ci -Am h2d -d '3 0'
2976 $ hg ci -Am h2d -d '3 0'
2977 adding head2
2977 adding head2
2978 created new head
2978 created new head
2979
2979
2980 $ echo e >> head2
2980 $ echo e >> head2
2981 $ hg ci -m h2e -d '4 0'
2981 $ hg ci -m h2e -d '4 0'
2982
2982
2983 $ hg merge -q
2983 $ hg merge -q
2984 $ hg ci -m merge -d '5 -3600'
2984 $ hg ci -m merge -d '5 -3600'
2985
2985
2986 No tag set:
2986 No tag set:
2987
2987
2988 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
2988 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
2989 @ 5: null+5
2989 @ 5: null+5
2990 |\
2990 |\
2991 | o 4: null+4
2991 | o 4: null+4
2992 | |
2992 | |
2993 | o 3: null+3
2993 | o 3: null+3
2994 | |
2994 | |
2995 o | 2: null+3
2995 o | 2: null+3
2996 |/
2996 |/
2997 o 1: null+2
2997 o 1: null+2
2998 |
2998 |
2999 o 0: null+1
2999 o 0: null+1
3000
3000
3001
3001
3002 One common tag: longest path wins for {latesttagdistance}:
3002 One common tag: longest path wins for {latesttagdistance}:
3003
3003
3004 $ hg tag -r 1 -m t1 -d '6 0' t1
3004 $ hg tag -r 1 -m t1 -d '6 0' t1
3005 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3005 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3006 @ 6: t1+4
3006 @ 6: t1+4
3007 |
3007 |
3008 o 5: t1+3
3008 o 5: t1+3
3009 |\
3009 |\
3010 | o 4: t1+2
3010 | o 4: t1+2
3011 | |
3011 | |
3012 | o 3: t1+1
3012 | o 3: t1+1
3013 | |
3013 | |
3014 o | 2: t1+1
3014 o | 2: t1+1
3015 |/
3015 |/
3016 o 1: t1+0
3016 o 1: t1+0
3017 |
3017 |
3018 o 0: null+1
3018 o 0: null+1
3019
3019
3020
3020
3021 One ancestor tag: closest wins:
3021 One ancestor tag: closest wins:
3022
3022
3023 $ hg tag -r 2 -m t2 -d '7 0' t2
3023 $ hg tag -r 2 -m t2 -d '7 0' t2
3024 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3024 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3025 @ 7: t2+3
3025 @ 7: t2+3
3026 |
3026 |
3027 o 6: t2+2
3027 o 6: t2+2
3028 |
3028 |
3029 o 5: t2+1
3029 o 5: t2+1
3030 |\
3030 |\
3031 | o 4: t1+2
3031 | o 4: t1+2
3032 | |
3032 | |
3033 | o 3: t1+1
3033 | o 3: t1+1
3034 | |
3034 | |
3035 o | 2: t2+0
3035 o | 2: t2+0
3036 |/
3036 |/
3037 o 1: t1+0
3037 o 1: t1+0
3038 |
3038 |
3039 o 0: null+1
3039 o 0: null+1
3040
3040
3041
3041
3042 Two branch tags: more recent wins if same number of changes:
3042 Two branch tags: more recent wins if same number of changes:
3043
3043
3044 $ hg tag -r 3 -m t3 -d '8 0' t3
3044 $ hg tag -r 3 -m t3 -d '8 0' t3
3045 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3045 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3046 @ 8: t3+5
3046 @ 8: t3+5
3047 |
3047 |
3048 o 7: t3+4
3048 o 7: t3+4
3049 |
3049 |
3050 o 6: t3+3
3050 o 6: t3+3
3051 |
3051 |
3052 o 5: t3+2
3052 o 5: t3+2
3053 |\
3053 |\
3054 | o 4: t3+1
3054 | o 4: t3+1
3055 | |
3055 | |
3056 | o 3: t3+0
3056 | o 3: t3+0
3057 | |
3057 | |
3058 o | 2: t2+0
3058 o | 2: t2+0
3059 |/
3059 |/
3060 o 1: t1+0
3060 o 1: t1+0
3061 |
3061 |
3062 o 0: null+1
3062 o 0: null+1
3063
3063
3064
3064
3065 Two branch tags: fewest changes wins:
3065 Two branch tags: fewest changes wins:
3066
3066
3067 $ hg tag -r 4 -m t4 -d '4 0' t4 # older than t2, but should not matter
3067 $ hg tag -r 4 -m t4 -d '4 0' t4 # older than t2, but should not matter
3068 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
3068 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
3069 @ 9: t4+5,6
3069 @ 9: t4+5,6
3070 |
3070 |
3071 o 8: t4+4,5
3071 o 8: t4+4,5
3072 |
3072 |
3073 o 7: t4+3,4
3073 o 7: t4+3,4
3074 |
3074 |
3075 o 6: t4+2,3
3075 o 6: t4+2,3
3076 |
3076 |
3077 o 5: t4+1,2
3077 o 5: t4+1,2
3078 |\
3078 |\
3079 | o 4: t4+0,0
3079 | o 4: t4+0,0
3080 | |
3080 | |
3081 | o 3: t3+0,0
3081 | o 3: t3+0,0
3082 | |
3082 | |
3083 o | 2: t2+0,0
3083 o | 2: t2+0,0
3084 |/
3084 |/
3085 o 1: t1+0,0
3085 o 1: t1+0,0
3086 |
3086 |
3087 o 0: null+1,1
3087 o 0: null+1,1
3088
3088
3089
3089
3090 Merged tag overrides:
3090 Merged tag overrides:
3091
3091
3092 $ hg tag -r 5 -m t5 -d '9 0' t5
3092 $ hg tag -r 5 -m t5 -d '9 0' t5
3093 $ hg tag -r 3 -m at3 -d '10 0' at3
3093 $ hg tag -r 3 -m at3 -d '10 0' at3
3094 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3094 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3095 @ 11: t5+6
3095 @ 11: t5+6
3096 |
3096 |
3097 o 10: t5+5
3097 o 10: t5+5
3098 |
3098 |
3099 o 9: t5+4
3099 o 9: t5+4
3100 |
3100 |
3101 o 8: t5+3
3101 o 8: t5+3
3102 |
3102 |
3103 o 7: t5+2
3103 o 7: t5+2
3104 |
3104 |
3105 o 6: t5+1
3105 o 6: t5+1
3106 |
3106 |
3107 o 5: t5+0
3107 o 5: t5+0
3108 |\
3108 |\
3109 | o 4: t4+0
3109 | o 4: t4+0
3110 | |
3110 | |
3111 | o 3: at3:t3+0
3111 | o 3: at3:t3+0
3112 | |
3112 | |
3113 o | 2: t2+0
3113 o | 2: t2+0
3114 |/
3114 |/
3115 o 1: t1+0
3115 o 1: t1+0
3116 |
3116 |
3117 o 0: null+1
3117 o 0: null+1
3118
3118
3119
3119
3120 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
3120 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
3121 @ 11: t5+6,6
3121 @ 11: t5+6,6
3122 |
3122 |
3123 o 10: t5+5,5
3123 o 10: t5+5,5
3124 |
3124 |
3125 o 9: t5+4,4
3125 o 9: t5+4,4
3126 |
3126 |
3127 o 8: t5+3,3
3127 o 8: t5+3,3
3128 |
3128 |
3129 o 7: t5+2,2
3129 o 7: t5+2,2
3130 |
3130 |
3131 o 6: t5+1,1
3131 o 6: t5+1,1
3132 |
3132 |
3133 o 5: t5+0,0
3133 o 5: t5+0,0
3134 |\
3134 |\
3135 | o 4: t4+0,0
3135 | o 4: t4+0,0
3136 | |
3136 | |
3137 | o 3: at3+0,0 t3+0,0
3137 | o 3: at3+0,0 t3+0,0
3138 | |
3138 | |
3139 o | 2: t2+0,0
3139 o | 2: t2+0,0
3140 |/
3140 |/
3141 o 1: t1+0,0
3141 o 1: t1+0,0
3142 |
3142 |
3143 o 0: null+1,1
3143 o 0: null+1,1
3144
3144
3145
3145
3146 $ hg log -G --template "{rev}: {latesttag('re:^t[13]$') % '{tag}, C: {changes}, D: {distance}'}\n"
3146 $ hg log -G --template "{rev}: {latesttag('re:^t[13]$') % '{tag}, C: {changes}, D: {distance}'}\n"
3147 @ 11: t3, C: 9, D: 8
3147 @ 11: t3, C: 9, D: 8
3148 |
3148 |
3149 o 10: t3, C: 8, D: 7
3149 o 10: t3, C: 8, D: 7
3150 |
3150 |
3151 o 9: t3, C: 7, D: 6
3151 o 9: t3, C: 7, D: 6
3152 |
3152 |
3153 o 8: t3, C: 6, D: 5
3153 o 8: t3, C: 6, D: 5
3154 |
3154 |
3155 o 7: t3, C: 5, D: 4
3155 o 7: t3, C: 5, D: 4
3156 |
3156 |
3157 o 6: t3, C: 4, D: 3
3157 o 6: t3, C: 4, D: 3
3158 |
3158 |
3159 o 5: t3, C: 3, D: 2
3159 o 5: t3, C: 3, D: 2
3160 |\
3160 |\
3161 | o 4: t3, C: 1, D: 1
3161 | o 4: t3, C: 1, D: 1
3162 | |
3162 | |
3163 | o 3: t3, C: 0, D: 0
3163 | o 3: t3, C: 0, D: 0
3164 | |
3164 | |
3165 o | 2: t1, C: 1, D: 1
3165 o | 2: t1, C: 1, D: 1
3166 |/
3166 |/
3167 o 1: t1, C: 0, D: 0
3167 o 1: t1, C: 0, D: 0
3168 |
3168 |
3169 o 0: null, C: 1, D: 1
3169 o 0: null, C: 1, D: 1
3170
3170
3171
3171
3172 $ cd ..
3172 $ cd ..
3173
3173
3174
3174
3175 Style path expansion: issue1948 - ui.style option doesn't work on OSX
3175 Style path expansion: issue1948 - ui.style option doesn't work on OSX
3176 if it is a relative path
3176 if it is a relative path
3177
3177
3178 $ mkdir -p home/styles
3178 $ mkdir -p home/styles
3179
3179
3180 $ cat > home/styles/teststyle <<EOF
3180 $ cat > home/styles/teststyle <<EOF
3181 > changeset = 'test {rev}:{node|short}\n'
3181 > changeset = 'test {rev}:{node|short}\n'
3182 > EOF
3182 > EOF
3183
3183
3184 $ HOME=`pwd`/home; export HOME
3184 $ HOME=`pwd`/home; export HOME
3185
3185
3186 $ cat > latesttag/.hg/hgrc <<EOF
3186 $ cat > latesttag/.hg/hgrc <<EOF
3187 > [ui]
3187 > [ui]
3188 > style = ~/styles/teststyle
3188 > style = ~/styles/teststyle
3189 > EOF
3189 > EOF
3190
3190
3191 $ hg -R latesttag tip
3191 $ hg -R latesttag tip
3192 test 11:97e5943b523a
3192 test 11:97e5943b523a
3193
3193
3194 Test recursive showlist template (issue1989):
3194 Test recursive showlist template (issue1989):
3195
3195
3196 $ cat > style1989 <<EOF
3196 $ cat > style1989 <<EOF
3197 > changeset = '{file_mods}{manifest}{extras}'
3197 > changeset = '{file_mods}{manifest}{extras}'
3198 > file_mod = 'M|{author|person}\n'
3198 > file_mod = 'M|{author|person}\n'
3199 > manifest = '{rev},{author}\n'
3199 > manifest = '{rev},{author}\n'
3200 > extra = '{key}: {author}\n'
3200 > extra = '{key}: {author}\n'
3201 > EOF
3201 > EOF
3202
3202
3203 $ hg -R latesttag log -r tip --style=style1989
3203 $ hg -R latesttag log -r tip --style=style1989
3204 M|test
3204 M|test
3205 11,test
3205 11,test
3206 branch: test
3206 branch: test
3207
3207
3208 Test new-style inline templating:
3208 Test new-style inline templating:
3209
3209
3210 $ hg log -R latesttag -r tip --template 'modified files: {file_mods % " {file}\n"}\n'
3210 $ hg log -R latesttag -r tip --template 'modified files: {file_mods % " {file}\n"}\n'
3211 modified files: .hgtags
3211 modified files: .hgtags
3212
3212
3213
3213
3214 $ hg log -R latesttag -r tip -T '{rev % "a"}\n'
3214 $ hg log -R latesttag -r tip -T '{rev % "a"}\n'
3215 hg: parse error: 11 is not iterable of mappings
3215 hg: parse error: 11 is not iterable of mappings
3216 (keyword 'rev' does not support map operation)
3216 (keyword 'rev' does not support map operation)
3217 [255]
3217 [255]
3218 $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "a"}\n'
3218 $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "a"}\n'
3219 hg: parse error: None is not iterable of mappings
3219 hg: parse error: None is not iterable of mappings
3220 [255]
3220 [255]
3221 $ hg log -R latesttag -r tip -T '{extras % "{key}\n" % "{key}\n"}'
3221 $ hg log -R latesttag -r tip -T '{extras % "{key}\n" % "{key}\n"}'
3222 hg: parse error: list of strings is not mappable
3222 hg: parse error: list of strings is not mappable
3223 [255]
3223 [255]
3224
3224
3225 Test new-style inline templating of non-list/dict type:
3225 Test new-style inline templating of non-list/dict type:
3226
3226
3227 $ hg log -R latesttag -r tip -T '{manifest}\n'
3227 $ hg log -R latesttag -r tip -T '{manifest}\n'
3228 11:2bc6e9006ce2
3228 11:2bc6e9006ce2
3229 $ hg log -R latesttag -r tip -T 'string length: {manifest|count}\n'
3229 $ hg log -R latesttag -r tip -T 'string length: {manifest|count}\n'
3230 string length: 15
3230 string length: 15
3231 $ hg log -R latesttag -r tip -T '{manifest % "{rev}:{node}"}\n'
3231 $ hg log -R latesttag -r tip -T '{manifest % "{rev}:{node}"}\n'
3232 11:2bc6e9006ce29882383a22d39fd1f4e66dd3e2fc
3232 11:2bc6e9006ce29882383a22d39fd1f4e66dd3e2fc
3233
3233
3234 $ hg log -R latesttag -r tip -T '{get(extras, "branch") % "{key}: {value}\n"}'
3234 $ hg log -R latesttag -r tip -T '{get(extras, "branch") % "{key}: {value}\n"}'
3235 branch: default
3235 branch: default
3236 $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "{key}\n"}'
3236 $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "{key}\n"}'
3237 hg: parse error: None is not iterable of mappings
3237 hg: parse error: None is not iterable of mappings
3238 [255]
3238 [255]
3239 $ hg log -R latesttag -r tip -T '{min(extras) % "{key}: {value}\n"}'
3239 $ hg log -R latesttag -r tip -T '{min(extras) % "{key}: {value}\n"}'
3240 branch: default
3240 branch: default
3241 $ hg log -R latesttag -l1 -T '{min(revset("0:9")) % "{rev}:{node|short}\n"}'
3241 $ hg log -R latesttag -l1 -T '{min(revset("0:9")) % "{rev}:{node|short}\n"}'
3242 0:ce3cec86e6c2
3242 0:ce3cec86e6c2
3243 $ hg log -R latesttag -l1 -T '{max(revset("0:9")) % "{rev}:{node|short}\n"}'
3243 $ hg log -R latesttag -l1 -T '{max(revset("0:9")) % "{rev}:{node|short}\n"}'
3244 9:fbc7cd862e9c
3244 9:fbc7cd862e9c
3245
3245
3246 Test manifest/get() can be join()-ed as string, though it's silly:
3246 Test manifest/get() can be join()-ed as string, though it's silly:
3247
3247
3248 $ hg log -R latesttag -r tip -T '{join(manifest, ".")}\n'
3248 $ hg log -R latesttag -r tip -T '{join(manifest, ".")}\n'
3249 1.1.:.2.b.c.6.e.9.0.0.6.c.e.2
3249 1.1.:.2.b.c.6.e.9.0.0.6.c.e.2
3250 $ hg log -R latesttag -r tip -T '{join(get(extras, "branch"), ".")}\n'
3250 $ hg log -R latesttag -r tip -T '{join(get(extras, "branch"), ".")}\n'
3251 d.e.f.a.u.l.t
3251 d.e.f.a.u.l.t
3252
3252
3253 Test join() over string
3253 Test join() over string
3254
3254
3255 $ hg log -R latesttag -r tip -T '{join(rev|stringify, ".")}\n'
3255 $ hg log -R latesttag -r tip -T '{join(rev|stringify, ".")}\n'
3256 1.1
3256 1.1
3257
3257
3258 Test join() over uniterable
3258 Test join() over uniterable
3259
3259
3260 $ hg log -R latesttag -r tip -T '{join(rev, "")}\n'
3260 $ hg log -R latesttag -r tip -T '{join(rev, "")}\n'
3261 hg: parse error: 11 is not iterable
3261 hg: parse error: 11 is not iterable
3262 [255]
3262 [255]
3263
3263
3264 Test min/max of integers
3264 Test min/max of integers
3265
3265
3266 $ hg log -R latesttag -l1 -T '{min(revset("9:10"))}\n'
3266 $ hg log -R latesttag -l1 -T '{min(revset("9:10"))}\n'
3267 9
3267 9
3268 $ hg log -R latesttag -l1 -T '{max(revset("9:10"))}\n'
3268 $ hg log -R latesttag -l1 -T '{max(revset("9:10"))}\n'
3269 10
3269 10
3270
3270
3271 Test min/max over map operation:
3271 Test min/max over map operation:
3272
3272
3273 $ hg log -R latesttag -r3 -T '{min(tags % "{tag}")}\n'
3273 $ hg log -R latesttag -r3 -T '{min(tags % "{tag}")}\n'
3274 at3
3274 at3
3275 $ hg log -R latesttag -r3 -T '{max(tags % "{tag}")}\n'
3275 $ hg log -R latesttag -r3 -T '{max(tags % "{tag}")}\n'
3276 t3
3276 t3
3277
3277
3278 Test min/max of strings:
3278 Test min/max of strings:
3279
3279
3280 $ hg log -R latesttag -l1 -T '{min(desc)}\n'
3280 $ hg log -R latesttag -l1 -T '{min(desc)}\n'
3281 3
3281 3
3282 $ hg log -R latesttag -l1 -T '{max(desc)}\n'
3282 $ hg log -R latesttag -l1 -T '{max(desc)}\n'
3283 t
3283 t
3284
3284
3285 Test min/max of non-iterable:
3285 Test min/max of non-iterable:
3286
3286
3287 $ hg debugtemplate '{min(1)}'
3287 $ hg debugtemplate '{min(1)}'
3288 hg: parse error: 1 is not iterable
3288 hg: parse error: 1 is not iterable
3289 (min first argument should be an iterable)
3289 (min first argument should be an iterable)
3290 [255]
3290 [255]
3291 $ hg debugtemplate '{max(2)}'
3291 $ hg debugtemplate '{max(2)}'
3292 hg: parse error: 2 is not iterable
3292 hg: parse error: 2 is not iterable
3293 (max first argument should be an iterable)
3293 (max first argument should be an iterable)
3294 [255]
3294 [255]
3295
3295
3296 Test min/max of empty sequence:
3296 Test min/max of empty sequence:
3297
3297
3298 $ hg debugtemplate '{min("")}'
3298 $ hg debugtemplate '{min("")}'
3299 hg: parse error: empty string
3299 hg: parse error: empty string
3300 (min first argument should be an iterable)
3300 (min first argument should be an iterable)
3301 [255]
3301 [255]
3302 $ hg debugtemplate '{max("")}'
3302 $ hg debugtemplate '{max("")}'
3303 hg: parse error: empty string
3303 hg: parse error: empty string
3304 (max first argument should be an iterable)
3304 (max first argument should be an iterable)
3305 [255]
3305 [255]
3306 $ hg debugtemplate '{min(dict())}'
3306 $ hg debugtemplate '{min(dict())}'
3307 hg: parse error: empty sequence
3307 hg: parse error: empty sequence
3308 (min first argument should be an iterable)
3308 (min first argument should be an iterable)
3309 [255]
3309 [255]
3310 $ hg debugtemplate '{max(dict())}'
3310 $ hg debugtemplate '{max(dict())}'
3311 hg: parse error: empty sequence
3311 hg: parse error: empty sequence
3312 (max first argument should be an iterable)
3312 (max first argument should be an iterable)
3313 [255]
3313 [255]
3314 $ hg debugtemplate '{min(dict() % "")}'
3314 $ hg debugtemplate '{min(dict() % "")}'
3315 hg: parse error: empty sequence
3315 hg: parse error: empty sequence
3316 (min first argument should be an iterable)
3316 (min first argument should be an iterable)
3317 [255]
3317 [255]
3318 $ hg debugtemplate '{max(dict() % "")}'
3318 $ hg debugtemplate '{max(dict() % "")}'
3319 hg: parse error: empty sequence
3319 hg: parse error: empty sequence
3320 (max first argument should be an iterable)
3320 (max first argument should be an iterable)
3321 [255]
3321 [255]
3322
3322
3323 Test min/max of if() result
3323 Test min/max of if() result
3324
3324
3325 $ cd latesttag
3325 $ cd latesttag
3326 $ hg log -l1 -T '{min(if(true, revset("9:10"), ""))}\n'
3326 $ hg log -l1 -T '{min(if(true, revset("9:10"), ""))}\n'
3327 9
3327 9
3328 $ hg log -l1 -T '{max(if(false, "", revset("9:10")))}\n'
3328 $ hg log -l1 -T '{max(if(false, "", revset("9:10")))}\n'
3329 10
3329 10
3330 $ hg log -l1 -T '{min(ifcontains("a", "aa", revset("9:10"), ""))}\n'
3330 $ hg log -l1 -T '{min(ifcontains("a", "aa", revset("9:10"), ""))}\n'
3331 9
3331 9
3332 $ hg log -l1 -T '{max(ifcontains("a", "bb", "", revset("9:10")))}\n'
3332 $ hg log -l1 -T '{max(ifcontains("a", "bb", "", revset("9:10")))}\n'
3333 10
3333 10
3334 $ hg log -l1 -T '{min(ifeq(0, 0, revset("9:10"), ""))}\n'
3334 $ hg log -l1 -T '{min(ifeq(0, 0, revset("9:10"), ""))}\n'
3335 9
3335 9
3336 $ hg log -l1 -T '{max(ifeq(0, 1, "", revset("9:10")))}\n'
3336 $ hg log -l1 -T '{max(ifeq(0, 1, "", revset("9:10")))}\n'
3337 10
3337 10
3338 $ cd ..
3338 $ cd ..
3339
3339
3340 Test laziness of if() then/else clause
3340 Test laziness of if() then/else clause
3341
3341
3342 $ hg debugtemplate '{count(0)}'
3342 $ hg debugtemplate '{count(0)}'
3343 hg: parse error: not countable
3343 hg: parse error: not countable
3344 (incompatible use of template filter 'count')
3344 (incompatible use of template filter 'count')
3345 [255]
3345 [255]
3346 $ hg debugtemplate '{if(true, "", count(0))}'
3346 $ hg debugtemplate '{if(true, "", count(0))}'
3347 $ hg debugtemplate '{if(false, count(0), "")}'
3347 $ hg debugtemplate '{if(false, count(0), "")}'
3348 $ hg debugtemplate '{ifcontains("a", "aa", "", count(0))}'
3348 $ hg debugtemplate '{ifcontains("a", "aa", "", count(0))}'
3349 $ hg debugtemplate '{ifcontains("a", "bb", count(0), "")}'
3349 $ hg debugtemplate '{ifcontains("a", "bb", count(0), "")}'
3350 $ hg debugtemplate '{ifeq(0, 0, "", count(0))}'
3350 $ hg debugtemplate '{ifeq(0, 0, "", count(0))}'
3351 $ hg debugtemplate '{ifeq(0, 1, count(0), "")}'
3351 $ hg debugtemplate '{ifeq(0, 1, count(0), "")}'
3352
3352
3353 Test dot operator precedence:
3353 Test dot operator precedence:
3354
3354
3355 $ hg debugtemplate -R latesttag -r0 -v '{manifest.node|short}\n'
3355 $ hg debugtemplate -R latesttag -r0 -v '{manifest.node|short}\n'
3356 (template
3356 (template
3357 (|
3357 (|
3358 (.
3358 (.
3359 (symbol 'manifest')
3359 (symbol 'manifest')
3360 (symbol 'node'))
3360 (symbol 'node'))
3361 (symbol 'short'))
3361 (symbol 'short'))
3362 (string '\n'))
3362 (string '\n'))
3363 89f4071fec70
3363 89f4071fec70
3364
3364
3365 (the following examples are invalid, but seem natural in parsing POV)
3365 (the following examples are invalid, but seem natural in parsing POV)
3366
3366
3367 $ hg debugtemplate -R latesttag -r0 -v '{foo|bar.baz}\n' 2> /dev/null
3367 $ hg debugtemplate -R latesttag -r0 -v '{foo|bar.baz}\n' 2> /dev/null
3368 (template
3368 (template
3369 (|
3369 (|
3370 (symbol 'foo')
3370 (symbol 'foo')
3371 (.
3371 (.
3372 (symbol 'bar')
3372 (symbol 'bar')
3373 (symbol 'baz')))
3373 (symbol 'baz')))
3374 (string '\n'))
3374 (string '\n'))
3375 [255]
3375 [255]
3376 $ hg debugtemplate -R latesttag -r0 -v '{foo.bar()}\n' 2> /dev/null
3376 $ hg debugtemplate -R latesttag -r0 -v '{foo.bar()}\n' 2> /dev/null
3377 (template
3377 (template
3378 (.
3378 (.
3379 (symbol 'foo')
3379 (symbol 'foo')
3380 (func
3380 (func
3381 (symbol 'bar')
3381 (symbol 'bar')
3382 None))
3382 None))
3383 (string '\n'))
3383 (string '\n'))
3384 [255]
3384 [255]
3385
3385
3386 Test evaluation of dot operator:
3386 Test evaluation of dot operator:
3387
3387
3388 $ hg log -R latesttag -l1 -T '{min(revset("0:9")).node}\n'
3388 $ hg log -R latesttag -l1 -T '{min(revset("0:9")).node}\n'
3389 ce3cec86e6c26bd9bdfc590a6b92abc9680f1796
3389 ce3cec86e6c26bd9bdfc590a6b92abc9680f1796
3390 $ hg log -R latesttag -r0 -T '{extras.branch}\n'
3390 $ hg log -R latesttag -r0 -T '{extras.branch}\n'
3391 default
3391 default
3392
3392
3393 $ hg log -R latesttag -l1 -T '{author.invalid}\n'
3393 $ hg log -R latesttag -l1 -T '{author.invalid}\n'
3394 hg: parse error: 'test' is not a dictionary
3394 hg: parse error: 'test' is not a dictionary
3395 (keyword 'author' does not support member operation)
3395 (keyword 'author' does not support member operation)
3396 [255]
3396 [255]
3397 $ hg log -R latesttag -l1 -T '{min("abc").invalid}\n'
3397 $ hg log -R latesttag -l1 -T '{min("abc").invalid}\n'
3398 hg: parse error: 'a' is not a dictionary
3398 hg: parse error: 'a' is not a dictionary
3399 [255]
3399 [255]
3400
3400
3401 Test the sub function of templating for expansion:
3401 Test the sub function of templating for expansion:
3402
3402
3403 $ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n'
3403 $ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n'
3404 xx
3404 xx
3405
3405
3406 $ hg log -R latesttag -r 10 -T '{sub("[", "x", rev)}\n'
3406 $ hg log -R latesttag -r 10 -T '{sub("[", "x", rev)}\n'
3407 hg: parse error: sub got an invalid pattern: [
3407 hg: parse error: sub got an invalid pattern: [
3408 [255]
3408 [255]
3409 $ hg log -R latesttag -r 10 -T '{sub("[0-9]", r"\1", rev)}\n'
3409 $ hg log -R latesttag -r 10 -T '{sub("[0-9]", r"\1", rev)}\n'
3410 hg: parse error: sub got an invalid replacement: \1
3410 hg: parse error: sub got an invalid replacement: \1
3411 [255]
3411 [255]
3412
3412
3413 Test the strip function with chars specified:
3413 Test the strip function with chars specified:
3414
3414
3415 $ hg log -R latesttag --template '{desc}\n'
3415 $ hg log -R latesttag --template '{desc}\n'
3416 at3
3416 at3
3417 t5
3417 t5
3418 t4
3418 t4
3419 t3
3419 t3
3420 t2
3420 t2
3421 t1
3421 t1
3422 merge
3422 merge
3423 h2e
3423 h2e
3424 h2d
3424 h2d
3425 h1c
3425 h1c
3426 b
3426 b
3427 a
3427 a
3428
3428
3429 $ hg log -R latesttag --template '{strip(desc, "te")}\n'
3429 $ hg log -R latesttag --template '{strip(desc, "te")}\n'
3430 at3
3430 at3
3431 5
3431 5
3432 4
3432 4
3433 3
3433 3
3434 2
3434 2
3435 1
3435 1
3436 merg
3436 merg
3437 h2
3437 h2
3438 h2d
3438 h2d
3439 h1c
3439 h1c
3440 b
3440 b
3441 a
3441 a
3442
3442
3443 Test date format:
3443 Test date format:
3444
3444
3445 $ hg log -R latesttag --template 'date: {date(date, "%y %m %d %S %z")}\n'
3445 $ hg log -R latesttag --template 'date: {date(date, "%y %m %d %S %z")}\n'
3446 date: 70 01 01 10 +0000
3446 date: 70 01 01 10 +0000
3447 date: 70 01 01 09 +0000
3447 date: 70 01 01 09 +0000
3448 date: 70 01 01 04 +0000
3448 date: 70 01 01 04 +0000
3449 date: 70 01 01 08 +0000
3449 date: 70 01 01 08 +0000
3450 date: 70 01 01 07 +0000
3450 date: 70 01 01 07 +0000
3451 date: 70 01 01 06 +0000
3451 date: 70 01 01 06 +0000
3452 date: 70 01 01 05 +0100
3452 date: 70 01 01 05 +0100
3453 date: 70 01 01 04 +0000
3453 date: 70 01 01 04 +0000
3454 date: 70 01 01 03 +0000
3454 date: 70 01 01 03 +0000
3455 date: 70 01 01 02 +0000
3455 date: 70 01 01 02 +0000
3456 date: 70 01 01 01 +0000
3456 date: 70 01 01 01 +0000
3457 date: 70 01 01 00 +0000
3457 date: 70 01 01 00 +0000
3458
3458
3459 Test invalid date:
3459 Test invalid date:
3460
3460
3461 $ hg log -R latesttag -T '{date(rev)}\n'
3461 $ hg log -R latesttag -T '{date(rev)}\n'
3462 hg: parse error: date expects a date information
3462 hg: parse error: date expects a date information
3463 [255]
3463 [255]
3464
3464
3465 Test integer literal:
3465 Test integer literal:
3466
3466
3467 $ hg debugtemplate -v '{(0)}\n'
3467 $ hg debugtemplate -v '{(0)}\n'
3468 (template
3468 (template
3469 (group
3469 (group
3470 (integer '0'))
3470 (integer '0'))
3471 (string '\n'))
3471 (string '\n'))
3472 0
3472 0
3473 $ hg debugtemplate -v '{(123)}\n'
3473 $ hg debugtemplate -v '{(123)}\n'
3474 (template
3474 (template
3475 (group
3475 (group
3476 (integer '123'))
3476 (integer '123'))
3477 (string '\n'))
3477 (string '\n'))
3478 123
3478 123
3479 $ hg debugtemplate -v '{(-4)}\n'
3479 $ hg debugtemplate -v '{(-4)}\n'
3480 (template
3480 (template
3481 (group
3481 (group
3482 (negate
3482 (negate
3483 (integer '4')))
3483 (integer '4')))
3484 (string '\n'))
3484 (string '\n'))
3485 -4
3485 -4
3486 $ hg debugtemplate '{(-)}\n'
3486 $ hg debugtemplate '{(-)}\n'
3487 hg: parse error at 3: not a prefix: )
3487 hg: parse error at 3: not a prefix: )
3488 ({(-)}\n
3488 ({(-)}\n
3489 ^ here)
3489 ^ here)
3490 [255]
3490 [255]
3491 $ hg debugtemplate '{(-a)}\n'
3491 $ hg debugtemplate '{(-a)}\n'
3492 hg: parse error: negation needs an integer argument
3492 hg: parse error: negation needs an integer argument
3493 [255]
3493 [255]
3494
3494
3495 top-level integer literal is interpreted as symbol (i.e. variable name):
3495 top-level integer literal is interpreted as symbol (i.e. variable name):
3496
3496
3497 $ hg debugtemplate -D 1=one -v '{1}\n'
3497 $ hg debugtemplate -D 1=one -v '{1}\n'
3498 (template
3498 (template
3499 (integer '1')
3499 (integer '1')
3500 (string '\n'))
3500 (string '\n'))
3501 one
3501 one
3502 $ hg debugtemplate -D 1=one -v '{if("t", "{1}")}\n'
3502 $ hg debugtemplate -D 1=one -v '{if("t", "{1}")}\n'
3503 (template
3503 (template
3504 (func
3504 (func
3505 (symbol 'if')
3505 (symbol 'if')
3506 (list
3506 (list
3507 (string 't')
3507 (string 't')
3508 (template
3508 (template
3509 (integer '1'))))
3509 (integer '1'))))
3510 (string '\n'))
3510 (string '\n'))
3511 one
3511 one
3512 $ hg debugtemplate -D 1=one -v '{1|stringify}\n'
3512 $ hg debugtemplate -D 1=one -v '{1|stringify}\n'
3513 (template
3513 (template
3514 (|
3514 (|
3515 (integer '1')
3515 (integer '1')
3516 (symbol 'stringify'))
3516 (symbol 'stringify'))
3517 (string '\n'))
3517 (string '\n'))
3518 one
3518 one
3519
3519
3520 unless explicit symbol is expected:
3520 unless explicit symbol is expected:
3521
3521
3522 $ hg log -Ra -r0 -T '{desc|1}\n'
3522 $ hg log -Ra -r0 -T '{desc|1}\n'
3523 hg: parse error: expected a symbol, got 'integer'
3523 hg: parse error: expected a symbol, got 'integer'
3524 [255]
3524 [255]
3525 $ hg log -Ra -r0 -T '{1()}\n'
3525 $ hg log -Ra -r0 -T '{1()}\n'
3526 hg: parse error: expected a symbol, got 'integer'
3526 hg: parse error: expected a symbol, got 'integer'
3527 [255]
3527 [255]
3528
3528
3529 Test string literal:
3529 Test string literal:
3530
3530
3531 $ hg debugtemplate -Ra -r0 -v '{"string with no template fragment"}\n'
3531 $ hg debugtemplate -Ra -r0 -v '{"string with no template fragment"}\n'
3532 (template
3532 (template
3533 (string 'string with no template fragment')
3533 (string 'string with no template fragment')
3534 (string '\n'))
3534 (string '\n'))
3535 string with no template fragment
3535 string with no template fragment
3536 $ hg debugtemplate -Ra -r0 -v '{"template: {rev}"}\n'
3536 $ hg debugtemplate -Ra -r0 -v '{"template: {rev}"}\n'
3537 (template
3537 (template
3538 (template
3538 (template
3539 (string 'template: ')
3539 (string 'template: ')
3540 (symbol 'rev'))
3540 (symbol 'rev'))
3541 (string '\n'))
3541 (string '\n'))
3542 template: 0
3542 template: 0
3543 $ hg debugtemplate -Ra -r0 -v '{r"rawstring: {rev}"}\n'
3543 $ hg debugtemplate -Ra -r0 -v '{r"rawstring: {rev}"}\n'
3544 (template
3544 (template
3545 (string 'rawstring: {rev}')
3545 (string 'rawstring: {rev}')
3546 (string '\n'))
3546 (string '\n'))
3547 rawstring: {rev}
3547 rawstring: {rev}
3548 $ hg debugtemplate -Ra -r0 -v '{files % r"rawstring: {file}"}\n'
3548 $ hg debugtemplate -Ra -r0 -v '{files % r"rawstring: {file}"}\n'
3549 (template
3549 (template
3550 (%
3550 (%
3551 (symbol 'files')
3551 (symbol 'files')
3552 (string 'rawstring: {file}'))
3552 (string 'rawstring: {file}'))
3553 (string '\n'))
3553 (string '\n'))
3554 rawstring: {file}
3554 rawstring: {file}
3555
3555
3556 Test string escaping:
3556 Test string escaping:
3557
3557
3558 $ hg log -R latesttag -r 0 --template '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3558 $ hg log -R latesttag -r 0 --template '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3559 >
3559 >
3560 <>\n<[>
3560 <>\n<[>
3561 <>\n<]>
3561 <>\n<]>
3562 <>\n<
3562 <>\n<
3563
3563
3564 $ hg log -R latesttag -r 0 \
3564 $ hg log -R latesttag -r 0 \
3565 > --config ui.logtemplate='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3565 > --config ui.logtemplate='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3566 >
3566 >
3567 <>\n<[>
3567 <>\n<[>
3568 <>\n<]>
3568 <>\n<]>
3569 <>\n<
3569 <>\n<
3570
3570
3571 $ hg log -R latesttag -r 0 -T esc \
3571 $ hg log -R latesttag -r 0 -T esc \
3572 > --config templates.esc='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3572 > --config templates.esc='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3573 >
3573 >
3574 <>\n<[>
3574 <>\n<[>
3575 <>\n<]>
3575 <>\n<]>
3576 <>\n<
3576 <>\n<
3577
3577
3578 $ cat <<'EOF' > esctmpl
3578 $ cat <<'EOF' > esctmpl
3579 > changeset = '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3579 > changeset = '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3580 > EOF
3580 > EOF
3581 $ hg log -R latesttag -r 0 --style ./esctmpl
3581 $ hg log -R latesttag -r 0 --style ./esctmpl
3582 >
3582 >
3583 <>\n<[>
3583 <>\n<[>
3584 <>\n<]>
3584 <>\n<]>
3585 <>\n<
3585 <>\n<
3586
3586
3587 Test string escaping of quotes:
3587 Test string escaping of quotes:
3588
3588
3589 $ hg log -Ra -r0 -T '{"\""}\n'
3589 $ hg log -Ra -r0 -T '{"\""}\n'
3590 "
3590 "
3591 $ hg log -Ra -r0 -T '{"\\\""}\n'
3591 $ hg log -Ra -r0 -T '{"\\\""}\n'
3592 \"
3592 \"
3593 $ hg log -Ra -r0 -T '{r"\""}\n'
3593 $ hg log -Ra -r0 -T '{r"\""}\n'
3594 \"
3594 \"
3595 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3595 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3596 \\\"
3596 \\\"
3597
3597
3598
3598
3599 $ hg log -Ra -r0 -T '{"\""}\n'
3599 $ hg log -Ra -r0 -T '{"\""}\n'
3600 "
3600 "
3601 $ hg log -Ra -r0 -T '{"\\\""}\n'
3601 $ hg log -Ra -r0 -T '{"\\\""}\n'
3602 \"
3602 \"
3603 $ hg log -Ra -r0 -T '{r"\""}\n'
3603 $ hg log -Ra -r0 -T '{r"\""}\n'
3604 \"
3604 \"
3605 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3605 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3606 \\\"
3606 \\\"
3607
3607
3608 Test exception in quoted template. single backslash before quotation mark is
3608 Test exception in quoted template. single backslash before quotation mark is
3609 stripped before parsing:
3609 stripped before parsing:
3610
3610
3611 $ cat <<'EOF' > escquotetmpl
3611 $ cat <<'EOF' > escquotetmpl
3612 > changeset = "\" \\" \\\" \\\\" {files % \"{file}\"}\n"
3612 > changeset = "\" \\" \\\" \\\\" {files % \"{file}\"}\n"
3613 > EOF
3613 > EOF
3614 $ cd latesttag
3614 $ cd latesttag
3615 $ hg log -r 2 --style ../escquotetmpl
3615 $ hg log -r 2 --style ../escquotetmpl
3616 " \" \" \\" head1
3616 " \" \" \\" head1
3617
3617
3618 $ hg log -r 2 -T esc --config templates.esc='"{\"valid\"}\n"'
3618 $ hg log -r 2 -T esc --config templates.esc='"{\"valid\"}\n"'
3619 valid
3619 valid
3620 $ hg log -r 2 -T esc --config templates.esc="'"'{\'"'"'valid\'"'"'}\n'"'"
3620 $ hg log -r 2 -T esc --config templates.esc="'"'{\'"'"'valid\'"'"'}\n'"'"
3621 valid
3621 valid
3622
3622
3623 Test compatibility with 2.9.2-3.4 of escaped quoted strings in nested
3623 Test compatibility with 2.9.2-3.4 of escaped quoted strings in nested
3624 _evalifliteral() templates (issue4733):
3624 _evalifliteral() templates (issue4733):
3625
3625
3626 $ hg log -r 2 -T '{if(rev, "\"{rev}")}\n'
3626 $ hg log -r 2 -T '{if(rev, "\"{rev}")}\n'
3627 "2
3627 "2
3628 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\"{rev}\")}")}\n'
3628 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\"{rev}\")}")}\n'
3629 "2
3629 "2
3630 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\"{rev}\\\")}\")}")}\n'
3630 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\"{rev}\\\")}\")}")}\n'
3631 "2
3631 "2
3632
3632
3633 $ hg log -r 2 -T '{if(rev, "\\\"")}\n'
3633 $ hg log -r 2 -T '{if(rev, "\\\"")}\n'
3634 \"
3634 \"
3635 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\\\\\"\")}")}\n'
3635 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\\\\\"\")}")}\n'
3636 \"
3636 \"
3637 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3637 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3638 \"
3638 \"
3639
3639
3640 $ hg log -r 2 -T '{if(rev, r"\\\"")}\n'
3640 $ hg log -r 2 -T '{if(rev, r"\\\"")}\n'
3641 \\\"
3641 \\\"
3642 $ hg log -r 2 -T '{if(rev, "{if(rev, r\"\\\\\\\"\")}")}\n'
3642 $ hg log -r 2 -T '{if(rev, "{if(rev, r\"\\\\\\\"\")}")}\n'
3643 \\\"
3643 \\\"
3644 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, r\\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3644 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, r\\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3645 \\\"
3645 \\\"
3646
3646
3647 escaped single quotes and errors:
3647 escaped single quotes and errors:
3648
3648
3649 $ hg log -r 2 -T "{if(rev, '{if(rev, \'foo\')}')}"'\n'
3649 $ hg log -r 2 -T "{if(rev, '{if(rev, \'foo\')}')}"'\n'
3650 foo
3650 foo
3651 $ hg log -r 2 -T "{if(rev, '{if(rev, r\'foo\')}')}"'\n'
3651 $ hg log -r 2 -T "{if(rev, '{if(rev, r\'foo\')}')}"'\n'
3652 foo
3652 foo
3653 $ hg log -r 2 -T '{if(rev, "{if(rev, \")}")}\n'
3653 $ hg log -r 2 -T '{if(rev, "{if(rev, \")}")}\n'
3654 hg: parse error at 21: unterminated string
3654 hg: parse error at 21: unterminated string
3655 ({if(rev, "{if(rev, \")}")}\n
3655 ({if(rev, "{if(rev, \")}")}\n
3656 ^ here)
3656 ^ here)
3657 [255]
3657 [255]
3658 $ hg log -r 2 -T '{if(rev, \"\\"")}\n'
3658 $ hg log -r 2 -T '{if(rev, \"\\"")}\n'
3659 hg: parse error: trailing \ in string
3659 hg: parse error: trailing \ in string
3660 [255]
3660 [255]
3661 $ hg log -r 2 -T '{if(rev, r\"\\"")}\n'
3661 $ hg log -r 2 -T '{if(rev, r\"\\"")}\n'
3662 hg: parse error: trailing \ in string
3662 hg: parse error: trailing \ in string
3663 [255]
3663 [255]
3664
3664
3665 $ cd ..
3665 $ cd ..
3666
3666
3667 Test leading backslashes:
3667 Test leading backslashes:
3668
3668
3669 $ cd latesttag
3669 $ cd latesttag
3670 $ hg log -r 2 -T '\{rev} {files % "\{file}"}\n'
3670 $ hg log -r 2 -T '\{rev} {files % "\{file}"}\n'
3671 {rev} {file}
3671 {rev} {file}
3672 $ hg log -r 2 -T '\\{rev} {files % "\\{file}"}\n'
3672 $ hg log -r 2 -T '\\{rev} {files % "\\{file}"}\n'
3673 \2 \head1
3673 \2 \head1
3674 $ hg log -r 2 -T '\\\{rev} {files % "\\\{file}"}\n'
3674 $ hg log -r 2 -T '\\\{rev} {files % "\\\{file}"}\n'
3675 \{rev} \{file}
3675 \{rev} \{file}
3676 $ cd ..
3676 $ cd ..
3677
3677
3678 Test leading backslashes in "if" expression (issue4714):
3678 Test leading backslashes in "if" expression (issue4714):
3679
3679
3680 $ cd latesttag
3680 $ cd latesttag
3681 $ hg log -r 2 -T '{if("1", "\{rev}")} {if("1", r"\{rev}")}\n'
3681 $ hg log -r 2 -T '{if("1", "\{rev}")} {if("1", r"\{rev}")}\n'
3682 {rev} \{rev}
3682 {rev} \{rev}
3683 $ hg log -r 2 -T '{if("1", "\\{rev}")} {if("1", r"\\{rev}")}\n'
3683 $ hg log -r 2 -T '{if("1", "\\{rev}")} {if("1", r"\\{rev}")}\n'
3684 \2 \\{rev}
3684 \2 \\{rev}
3685 $ hg log -r 2 -T '{if("1", "\\\{rev}")} {if("1", r"\\\{rev}")}\n'
3685 $ hg log -r 2 -T '{if("1", "\\\{rev}")} {if("1", r"\\\{rev}")}\n'
3686 \{rev} \\\{rev}
3686 \{rev} \\\{rev}
3687 $ cd ..
3687 $ cd ..
3688
3688
3689 "string-escape"-ed "\x5c\x786e" becomes r"\x6e" (once) or r"n" (twice)
3689 "string-escape"-ed "\x5c\x786e" becomes r"\x6e" (once) or r"n" (twice)
3690
3690
3691 $ hg log -R a -r 0 --template '{if("1", "\x5c\x786e", "NG")}\n'
3691 $ hg log -R a -r 0 --template '{if("1", "\x5c\x786e", "NG")}\n'
3692 \x6e
3692 \x6e
3693 $ hg log -R a -r 0 --template '{if("1", r"\x5c\x786e", "NG")}\n'
3693 $ hg log -R a -r 0 --template '{if("1", r"\x5c\x786e", "NG")}\n'
3694 \x5c\x786e
3694 \x5c\x786e
3695 $ hg log -R a -r 0 --template '{if("", "NG", "\x5c\x786e")}\n'
3695 $ hg log -R a -r 0 --template '{if("", "NG", "\x5c\x786e")}\n'
3696 \x6e
3696 \x6e
3697 $ hg log -R a -r 0 --template '{if("", "NG", r"\x5c\x786e")}\n'
3697 $ hg log -R a -r 0 --template '{if("", "NG", r"\x5c\x786e")}\n'
3698 \x5c\x786e
3698 \x5c\x786e
3699
3699
3700 $ hg log -R a -r 2 --template '{ifeq("no perso\x6e", desc, "\x5c\x786e", "NG")}\n'
3700 $ hg log -R a -r 2 --template '{ifeq("no perso\x6e", desc, "\x5c\x786e", "NG")}\n'
3701 \x6e
3701 \x6e
3702 $ hg log -R a -r 2 --template '{ifeq(r"no perso\x6e", desc, "NG", r"\x5c\x786e")}\n'
3702 $ hg log -R a -r 2 --template '{ifeq(r"no perso\x6e", desc, "NG", r"\x5c\x786e")}\n'
3703 \x5c\x786e
3703 \x5c\x786e
3704 $ hg log -R a -r 2 --template '{ifeq(desc, "no perso\x6e", "\x5c\x786e", "NG")}\n'
3704 $ hg log -R a -r 2 --template '{ifeq(desc, "no perso\x6e", "\x5c\x786e", "NG")}\n'
3705 \x6e
3705 \x6e
3706 $ hg log -R a -r 2 --template '{ifeq(desc, r"no perso\x6e", "NG", r"\x5c\x786e")}\n'
3706 $ hg log -R a -r 2 --template '{ifeq(desc, r"no perso\x6e", "NG", r"\x5c\x786e")}\n'
3707 \x5c\x786e
3707 \x5c\x786e
3708
3708
3709 $ hg log -R a -r 8 --template '{join(files, "\n")}\n'
3709 $ hg log -R a -r 8 --template '{join(files, "\n")}\n'
3710 fourth
3710 fourth
3711 second
3711 second
3712 third
3712 third
3713 $ hg log -R a -r 8 --template '{join(files, r"\n")}\n'
3713 $ hg log -R a -r 8 --template '{join(files, r"\n")}\n'
3714 fourth\nsecond\nthird
3714 fourth\nsecond\nthird
3715
3715
3716 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", "htm\x6c")}'
3716 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", "htm\x6c")}'
3717 <p>
3717 <p>
3718 1st
3718 1st
3719 </p>
3719 </p>
3720 <p>
3720 <p>
3721 2nd
3721 2nd
3722 </p>
3722 </p>
3723 $ hg log -R a -r 2 --template '{rstdoc(r"1st\n\n2nd", "html")}'
3723 $ hg log -R a -r 2 --template '{rstdoc(r"1st\n\n2nd", "html")}'
3724 <p>
3724 <p>
3725 1st\n\n2nd
3725 1st\n\n2nd
3726 </p>
3726 </p>
3727 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", r"htm\x6c")}'
3727 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", r"htm\x6c")}'
3728 1st
3728 1st
3729
3729
3730 2nd
3730 2nd
3731
3731
3732 $ hg log -R a -r 2 --template '{strip(desc, "\x6e")}\n'
3732 $ hg log -R a -r 2 --template '{strip(desc, "\x6e")}\n'
3733 o perso
3733 o perso
3734 $ hg log -R a -r 2 --template '{strip(desc, r"\x6e")}\n'
3734 $ hg log -R a -r 2 --template '{strip(desc, r"\x6e")}\n'
3735 no person
3735 no person
3736 $ hg log -R a -r 2 --template '{strip("no perso\x6e", "\x6e")}\n'
3736 $ hg log -R a -r 2 --template '{strip("no perso\x6e", "\x6e")}\n'
3737 o perso
3737 o perso
3738 $ hg log -R a -r 2 --template '{strip(r"no perso\x6e", r"\x6e")}\n'
3738 $ hg log -R a -r 2 --template '{strip(r"no perso\x6e", r"\x6e")}\n'
3739 no perso
3739 no perso
3740
3740
3741 $ hg log -R a -r 2 --template '{sub("\\x6e", "\x2d", desc)}\n'
3741 $ hg log -R a -r 2 --template '{sub("\\x6e", "\x2d", desc)}\n'
3742 -o perso-
3742 -o perso-
3743 $ hg log -R a -r 2 --template '{sub(r"\\x6e", "-", desc)}\n'
3743 $ hg log -R a -r 2 --template '{sub(r"\\x6e", "-", desc)}\n'
3744 no person
3744 no person
3745 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", desc)}\n'
3745 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", desc)}\n'
3746 \x2do perso\x2d
3746 \x2do perso\x2d
3747 $ hg log -R a -r 2 --template '{sub("n", "\x2d", "no perso\x6e")}\n'
3747 $ hg log -R a -r 2 --template '{sub("n", "\x2d", "no perso\x6e")}\n'
3748 -o perso-
3748 -o perso-
3749 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", r"no perso\x6e")}\n'
3749 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", r"no perso\x6e")}\n'
3750 \x2do perso\x6e
3750 \x2do perso\x6e
3751
3751
3752 $ hg log -R a -r 8 --template '{files % "{file}\n"}'
3752 $ hg log -R a -r 8 --template '{files % "{file}\n"}'
3753 fourth
3753 fourth
3754 second
3754 second
3755 third
3755 third
3756
3756
3757 Test string escaping in nested expression:
3757 Test string escaping in nested expression:
3758
3758
3759 $ hg log -R a -r 8 --template '{ifeq(r"\x6e", if("1", "\x5c\x786e"), join(files, "\x5c\x786e"))}\n'
3759 $ hg log -R a -r 8 --template '{ifeq(r"\x6e", if("1", "\x5c\x786e"), join(files, "\x5c\x786e"))}\n'
3760 fourth\x6esecond\x6ethird
3760 fourth\x6esecond\x6ethird
3761 $ hg log -R a -r 8 --template '{ifeq(if("1", r"\x6e"), "\x5c\x786e", join(files, "\x5c\x786e"))}\n'
3761 $ hg log -R a -r 8 --template '{ifeq(if("1", r"\x6e"), "\x5c\x786e", join(files, "\x5c\x786e"))}\n'
3762 fourth\x6esecond\x6ethird
3762 fourth\x6esecond\x6ethird
3763
3763
3764 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", "\x5c\x786e"))}\n'
3764 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", "\x5c\x786e"))}\n'
3765 fourth\x6esecond\x6ethird
3765 fourth\x6esecond\x6ethird
3766 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", r"\x5c\x786e"))}\n'
3766 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", r"\x5c\x786e"))}\n'
3767 fourth\x5c\x786esecond\x5c\x786ethird
3767 fourth\x5c\x786esecond\x5c\x786ethird
3768
3768
3769 $ hg log -R a -r 3:4 --template '{rev}:{sub(if("1", "\x6e"), ifeq(branch, "foo", r"\x5c\x786e", "\x5c\x786e"), desc)}\n'
3769 $ hg log -R a -r 3:4 --template '{rev}:{sub(if("1", "\x6e"), ifeq(branch, "foo", r"\x5c\x786e", "\x5c\x786e"), desc)}\n'
3770 3:\x6eo user, \x6eo domai\x6e
3770 3:\x6eo user, \x6eo domai\x6e
3771 4:\x5c\x786eew bra\x5c\x786ech
3771 4:\x5c\x786eew bra\x5c\x786ech
3772
3772
3773 Test quotes in nested expression are evaluated just like a $(command)
3773 Test quotes in nested expression are evaluated just like a $(command)
3774 substitution in POSIX shells:
3774 substitution in POSIX shells:
3775
3775
3776 $ hg log -R a -r 8 -T '{"{"{rev}:{node|short}"}"}\n'
3776 $ hg log -R a -r 8 -T '{"{"{rev}:{node|short}"}"}\n'
3777 8:95c24699272e
3777 8:95c24699272e
3778 $ hg log -R a -r 8 -T '{"{"\{{rev}} \"{node|short}\""}"}\n'
3778 $ hg log -R a -r 8 -T '{"{"\{{rev}} \"{node|short}\""}"}\n'
3779 {8} "95c24699272e"
3779 {8} "95c24699272e"
3780
3780
3781 Test recursive evaluation:
3781 Test recursive evaluation:
3782
3782
3783 $ hg init r
3783 $ hg init r
3784 $ cd r
3784 $ cd r
3785 $ echo a > a
3785 $ echo a > a
3786 $ hg ci -Am '{rev}'
3786 $ hg ci -Am '{rev}'
3787 adding a
3787 adding a
3788 $ hg log -r 0 --template '{if(rev, desc)}\n'
3788 $ hg log -r 0 --template '{if(rev, desc)}\n'
3789 {rev}
3789 {rev}
3790 $ hg log -r 0 --template '{if(rev, "{author} {rev}")}\n'
3790 $ hg log -r 0 --template '{if(rev, "{author} {rev}")}\n'
3791 test 0
3791 test 0
3792
3792
3793 $ hg branch -q 'text.{rev}'
3793 $ hg branch -q 'text.{rev}'
3794 $ echo aa >> aa
3794 $ echo aa >> aa
3795 $ hg ci -u '{node|short}' -m 'desc to be wrapped desc to be wrapped'
3795 $ hg ci -u '{node|short}' -m 'desc to be wrapped desc to be wrapped'
3796
3796
3797 $ hg log -l1 --template '{fill(desc, "20", author, branch)}'
3797 $ hg log -l1 --template '{fill(desc, "20", author, branch)}'
3798 {node|short}desc to
3798 {node|short}desc to
3799 text.{rev}be wrapped
3799 text.{rev}be wrapped
3800 text.{rev}desc to be
3800 text.{rev}desc to be
3801 text.{rev}wrapped (no-eol)
3801 text.{rev}wrapped (no-eol)
3802 $ hg log -l1 --template '{fill(desc, "20", "{node|short}:", "text.{rev}:")}'
3802 $ hg log -l1 --template '{fill(desc, "20", "{node|short}:", "text.{rev}:")}'
3803 bcc7ff960b8e:desc to
3803 bcc7ff960b8e:desc to
3804 text.1:be wrapped
3804 text.1:be wrapped
3805 text.1:desc to be
3805 text.1:desc to be
3806 text.1:wrapped (no-eol)
3806 text.1:wrapped (no-eol)
3807 $ hg log -l1 -T '{fill(desc, date, "", "")}\n'
3807 $ hg log -l1 -T '{fill(desc, date, "", "")}\n'
3808 hg: parse error: fill expects an integer width
3808 hg: parse error: fill expects an integer width
3809 [255]
3809 [255]
3810
3810
3811 $ COLUMNS=25 hg log -l1 --template '{fill(desc, termwidth, "{node|short}:", "termwidth.{rev}:")}'
3811 $ COLUMNS=25 hg log -l1 --template '{fill(desc, termwidth, "{node|short}:", "termwidth.{rev}:")}'
3812 bcc7ff960b8e:desc to be
3812 bcc7ff960b8e:desc to be
3813 termwidth.1:wrapped desc
3813 termwidth.1:wrapped desc
3814 termwidth.1:to be wrapped (no-eol)
3814 termwidth.1:to be wrapped (no-eol)
3815
3815
3816 $ hg log -l 1 --template '{sub(r"[0-9]", "-", author)}'
3816 $ hg log -l 1 --template '{sub(r"[0-9]", "-", author)}'
3817 {node|short} (no-eol)
3817 {node|short} (no-eol)
3818 $ hg log -l 1 --template '{sub(r"[0-9]", "-", "{node|short}")}'
3818 $ hg log -l 1 --template '{sub(r"[0-9]", "-", "{node|short}")}'
3819 bcc-ff---b-e (no-eol)
3819 bcc-ff---b-e (no-eol)
3820
3820
3821 $ cat >> .hg/hgrc <<EOF
3821 $ cat >> .hg/hgrc <<EOF
3822 > [extensions]
3822 > [extensions]
3823 > color=
3823 > color=
3824 > [color]
3824 > [color]
3825 > mode=ansi
3825 > mode=ansi
3826 > text.{rev} = red
3826 > text.{rev} = red
3827 > text.1 = green
3827 > text.1 = green
3828 > EOF
3828 > EOF
3829 $ hg log --color=always -l 1 --template '{label(branch, "text\n")}'
3829 $ hg log --color=always -l 1 --template '{label(branch, "text\n")}'
3830 \x1b[0;31mtext\x1b[0m (esc)
3830 \x1b[0;31mtext\x1b[0m (esc)
3831 $ hg log --color=always -l 1 --template '{label("text.{rev}", "text\n")}'
3831 $ hg log --color=always -l 1 --template '{label("text.{rev}", "text\n")}'
3832 \x1b[0;32mtext\x1b[0m (esc)
3832 \x1b[0;32mtext\x1b[0m (esc)
3833
3833
3834 color effect can be specified without quoting:
3834 color effect can be specified without quoting:
3835
3835
3836 $ hg log --color=always -l 1 --template '{label(red, "text\n")}'
3836 $ hg log --color=always -l 1 --template '{label(red, "text\n")}'
3837 \x1b[0;31mtext\x1b[0m (esc)
3837 \x1b[0;31mtext\x1b[0m (esc)
3838
3838
3839 color effects can be nested (issue5413)
3839 color effects can be nested (issue5413)
3840
3840
3841 $ hg debugtemplate --color=always \
3841 $ hg debugtemplate --color=always \
3842 > '{label(red, "red{label(magenta, "ma{label(cyan, "cyan")}{label(yellow, "yellow")}genta")}")}\n'
3842 > '{label(red, "red{label(magenta, "ma{label(cyan, "cyan")}{label(yellow, "yellow")}genta")}")}\n'
3843 \x1b[0;31mred\x1b[0;35mma\x1b[0;36mcyan\x1b[0m\x1b[0;31m\x1b[0;35m\x1b[0;33myellow\x1b[0m\x1b[0;31m\x1b[0;35mgenta\x1b[0m (esc)
3843 \x1b[0;31mred\x1b[0;35mma\x1b[0;36mcyan\x1b[0m\x1b[0;31m\x1b[0;35m\x1b[0;33myellow\x1b[0m\x1b[0;31m\x1b[0;35mgenta\x1b[0m (esc)
3844
3844
3845 pad() should interact well with color codes (issue5416)
3845 pad() should interact well with color codes (issue5416)
3846
3846
3847 $ hg debugtemplate --color=always \
3847 $ hg debugtemplate --color=always \
3848 > '{pad(label(red, "red"), 5, label(cyan, "-"))}\n'
3848 > '{pad(label(red, "red"), 5, label(cyan, "-"))}\n'
3849 \x1b[0;31mred\x1b[0m\x1b[0;36m-\x1b[0m\x1b[0;36m-\x1b[0m (esc)
3849 \x1b[0;31mred\x1b[0m\x1b[0;36m-\x1b[0m\x1b[0;36m-\x1b[0m (esc)
3850
3850
3851 label should be no-op if color is disabled:
3851 label should be no-op if color is disabled:
3852
3852
3853 $ hg log --color=never -l 1 --template '{label(red, "text\n")}'
3853 $ hg log --color=never -l 1 --template '{label(red, "text\n")}'
3854 text
3854 text
3855 $ hg log --config extensions.color=! -l 1 --template '{label(red, "text\n")}'
3855 $ hg log --config extensions.color=! -l 1 --template '{label(red, "text\n")}'
3856 text
3856 text
3857
3857
3858 Test branches inside if statement:
3858 Test branches inside if statement:
3859
3859
3860 $ hg log -r 0 --template '{if(branches, "yes", "no")}\n'
3860 $ hg log -r 0 --template '{if(branches, "yes", "no")}\n'
3861 no
3861 no
3862
3862
3863 Test dict constructor:
3863 Test dict constructor:
3864
3864
3865 $ hg log -r 0 -T '{dict(y=node|short, x=rev)}\n'
3865 $ hg log -r 0 -T '{dict(y=node|short, x=rev)}\n'
3866 y=f7769ec2ab97 x=0
3866 y=f7769ec2ab97 x=0
3867 $ hg log -r 0 -T '{dict(x=rev, y=node|short) % "{key}={value}\n"}'
3867 $ hg log -r 0 -T '{dict(x=rev, y=node|short) % "{key}={value}\n"}'
3868 x=0
3868 x=0
3869 y=f7769ec2ab97
3869 y=f7769ec2ab97
3870 $ hg log -r 0 -T '{dict(x=rev, y=node|short)|json}\n'
3870 $ hg log -r 0 -T '{dict(x=rev, y=node|short)|json}\n'
3871 {"x": 0, "y": "f7769ec2ab97"}
3871 {"x": 0, "y": "f7769ec2ab97"}
3872 $ hg log -r 0 -T '{dict()|json}\n'
3872 $ hg log -r 0 -T '{dict()|json}\n'
3873 {}
3873 {}
3874
3874
3875 $ hg log -r 0 -T '{dict(rev, node=node|short)}\n'
3875 $ hg log -r 0 -T '{dict(rev, node=node|short)}\n'
3876 rev=0 node=f7769ec2ab97
3876 rev=0 node=f7769ec2ab97
3877 $ hg log -r 0 -T '{dict(rev, node|short)}\n'
3877 $ hg log -r 0 -T '{dict(rev, node|short)}\n'
3878 rev=0 node=f7769ec2ab97
3878 rev=0 node=f7769ec2ab97
3879
3879
3880 $ hg log -r 0 -T '{dict(rev, rev=rev)}\n'
3880 $ hg log -r 0 -T '{dict(rev, rev=rev)}\n'
3881 hg: parse error: duplicated dict key 'rev' inferred
3881 hg: parse error: duplicated dict key 'rev' inferred
3882 [255]
3882 [255]
3883 $ hg log -r 0 -T '{dict(node, node|short)}\n'
3883 $ hg log -r 0 -T '{dict(node, node|short)}\n'
3884 hg: parse error: duplicated dict key 'node' inferred
3884 hg: parse error: duplicated dict key 'node' inferred
3885 [255]
3885 [255]
3886 $ hg log -r 0 -T '{dict(1 + 2)}'
3886 $ hg log -r 0 -T '{dict(1 + 2)}'
3887 hg: parse error: dict key cannot be inferred
3887 hg: parse error: dict key cannot be inferred
3888 [255]
3888 [255]
3889
3889
3890 $ hg log -r 0 -T '{dict(x=rev, x=node)}'
3890 $ hg log -r 0 -T '{dict(x=rev, x=node)}'
3891 hg: parse error: dict got multiple values for keyword argument 'x'
3891 hg: parse error: dict got multiple values for keyword argument 'x'
3892 [255]
3892 [255]
3893
3893
3894 Test get function:
3894 Test get function:
3895
3895
3896 $ hg log -r 0 --template '{get(extras, "branch")}\n'
3896 $ hg log -r 0 --template '{get(extras, "branch")}\n'
3897 default
3897 default
3898 $ hg log -r 0 --template '{get(extras, "br{"anch"}")}\n'
3898 $ hg log -r 0 --template '{get(extras, "br{"anch"}")}\n'
3899 default
3899 default
3900 $ hg log -r 0 --template '{get(files, "should_fail")}\n'
3900 $ hg log -r 0 --template '{get(files, "should_fail")}\n'
3901 hg: parse error: not a dictionary
3901 hg: parse error: not a dictionary
3902 (get() expects a dict as first argument)
3902 (get() expects a dict as first argument)
3903 [255]
3903 [255]
3904
3904
3905 Test json filter applied to hybrid object:
3905 Test json filter applied to hybrid object:
3906
3906
3907 $ hg log -r0 -T '{files|json}\n'
3907 $ hg log -r0 -T '{files|json}\n'
3908 ["a"]
3908 ["a"]
3909 $ hg log -r0 -T '{extras|json}\n'
3909 $ hg log -r0 -T '{extras|json}\n'
3910 {"branch": "default"}
3910 {"branch": "default"}
3911
3911
3912 Test json filter applied to map result:
3912 Test json filter applied to map result:
3913
3913
3914 $ hg log -r0 -T '{json(extras % "{key}")}\n'
3914 $ hg log -r0 -T '{json(extras % "{key}")}\n'
3915 ["branch"]
3915 ["branch"]
3916
3916
3917 Test localdate(date, tz) function:
3917 Test localdate(date, tz) function:
3918
3918
3919 $ TZ=JST-09 hg log -r0 -T '{date|localdate|isodate}\n'
3919 $ TZ=JST-09 hg log -r0 -T '{date|localdate|isodate}\n'
3920 1970-01-01 09:00 +0900
3920 1970-01-01 09:00 +0900
3921 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "UTC")|isodate}\n'
3921 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "UTC")|isodate}\n'
3922 1970-01-01 00:00 +0000
3922 1970-01-01 00:00 +0000
3923 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "blahUTC")|isodate}\n'
3923 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "blahUTC")|isodate}\n'
3924 hg: parse error: localdate expects a timezone
3924 hg: parse error: localdate expects a timezone
3925 [255]
3925 [255]
3926 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "+0200")|isodate}\n'
3926 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "+0200")|isodate}\n'
3927 1970-01-01 02:00 +0200
3927 1970-01-01 02:00 +0200
3928 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "0")|isodate}\n'
3928 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "0")|isodate}\n'
3929 1970-01-01 00:00 +0000
3929 1970-01-01 00:00 +0000
3930 $ TZ=JST-09 hg log -r0 -T '{localdate(date, 0)|isodate}\n'
3930 $ TZ=JST-09 hg log -r0 -T '{localdate(date, 0)|isodate}\n'
3931 1970-01-01 00:00 +0000
3931 1970-01-01 00:00 +0000
3932 $ hg log -r0 -T '{localdate(date, "invalid")|isodate}\n'
3932 $ hg log -r0 -T '{localdate(date, "invalid")|isodate}\n'
3933 hg: parse error: localdate expects a timezone
3933 hg: parse error: localdate expects a timezone
3934 [255]
3934 [255]
3935 $ hg log -r0 -T '{localdate(date, date)|isodate}\n'
3935 $ hg log -r0 -T '{localdate(date, date)|isodate}\n'
3936 hg: parse error: localdate expects a timezone
3936 hg: parse error: localdate expects a timezone
3937 [255]
3937 [255]
3938
3938
3939 Test shortest(node) function:
3939 Test shortest(node) function:
3940
3940
3941 $ echo b > b
3941 $ echo b > b
3942 $ hg ci -qAm b
3942 $ hg ci -qAm b
3943 $ hg log --template '{shortest(node)}\n'
3943 $ hg log --template '{shortest(node)}\n'
3944 e777
3944 e777
3945 bcc7
3945 bcc7
3946 f776
3946 f776
3947 $ hg log --template '{shortest(node, 10)}\n'
3947 $ hg log --template '{shortest(node, 10)}\n'
3948 e777603221
3948 e777603221
3949 bcc7ff960b
3949 bcc7ff960b
3950 f7769ec2ab
3950 f7769ec2ab
3951 $ hg log --template '{node|shortest}\n' -l1
3951 $ hg log --template '{node|shortest}\n' -l1
3952 e777
3952 e777
3953
3953
3954 $ hg log -r 0 -T '{shortest(node, "1{"0"}")}\n'
3954 $ hg log -r 0 -T '{shortest(node, "1{"0"}")}\n'
3955 f7769ec2ab
3955 f7769ec2ab
3956 $ hg log -r 0 -T '{shortest(node, "not an int")}\n'
3956 $ hg log -r 0 -T '{shortest(node, "not an int")}\n'
3957 hg: parse error: shortest() expects an integer minlength
3957 hg: parse error: shortest() expects an integer minlength
3958 [255]
3958 [255]
3959
3959
3960 $ hg log -r 'wdir()' -T '{node|shortest}\n'
3960 $ hg log -r 'wdir()' -T '{node|shortest}\n'
3961 ffff
3961 ffff
3962
3962
3963 $ hg log --template '{shortest("f")}\n' -l1
3963 $ hg log --template '{shortest("f")}\n' -l1
3964 f
3964 f
3965
3965
3966 $ hg log --template '{shortest("0123456789012345678901234567890123456789")}\n' -l1
3966 $ hg log --template '{shortest("0123456789012345678901234567890123456789")}\n' -l1
3967 0123456789012345678901234567890123456789
3967 0123456789012345678901234567890123456789
3968
3968
3969 $ hg log --template '{shortest("01234567890123456789012345678901234567890123456789")}\n' -l1
3969 $ hg log --template '{shortest("01234567890123456789012345678901234567890123456789")}\n' -l1
3970 01234567890123456789012345678901234567890123456789
3970 01234567890123456789012345678901234567890123456789
3971
3971
3972 $ hg log --template '{shortest("not a hex string")}\n' -l1
3972 $ hg log --template '{shortest("not a hex string")}\n' -l1
3973 not a hex string
3973 not a hex string
3974
3974
3975 $ hg log --template '{shortest("not a hex string, but it'\''s 40 bytes long")}\n' -l1
3975 $ hg log --template '{shortest("not a hex string, but it'\''s 40 bytes long")}\n' -l1
3976 not a hex string, but it's 40 bytes long
3976 not a hex string, but it's 40 bytes long
3977
3977
3978 $ hg log --template '{shortest("ffffffffffffffffffffffffffffffffffffffff")}\n' -l1
3978 $ hg log --template '{shortest("ffffffffffffffffffffffffffffffffffffffff")}\n' -l1
3979 ffff
3979 ffff
3980
3980
3981 $ hg log --template '{shortest("fffffff")}\n' -l1
3981 $ hg log --template '{shortest("fffffff")}\n' -l1
3982 ffff
3982 ffff
3983
3983
3984 $ hg log --template '{shortest("ff")}\n' -l1
3984 $ hg log --template '{shortest("ff")}\n' -l1
3985 ffff
3985 ffff
3986
3986
3987 $ cd ..
3987 $ cd ..
3988
3988
3989 Test shortest(node) with the repo having short hash collision:
3989 Test shortest(node) with the repo having short hash collision:
3990
3990
3991 $ hg init hashcollision
3991 $ hg init hashcollision
3992 $ cd hashcollision
3992 $ cd hashcollision
3993 $ cat <<EOF >> .hg/hgrc
3993 $ cat <<EOF >> .hg/hgrc
3994 > [experimental]
3994 > [experimental]
3995 > evolution.createmarkers=True
3995 > evolution.createmarkers=True
3996 > EOF
3996 > EOF
3997 $ echo 0 > a
3997 $ echo 0 > a
3998 $ hg ci -qAm 0
3998 $ hg ci -qAm 0
3999 $ for i in 17 129 248 242 480 580 617 1057 2857 4025; do
3999 $ for i in 17 129 248 242 480 580 617 1057 2857 4025; do
4000 > hg up -q 0
4000 > hg up -q 0
4001 > echo $i > a
4001 > echo $i > a
4002 > hg ci -qm $i
4002 > hg ci -qm $i
4003 > done
4003 > done
4004 $ hg up -q null
4004 $ hg up -q null
4005 $ hg log -r0: -T '{rev}:{node}\n'
4005 $ hg log -r0: -T '{rev}:{node}\n'
4006 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a
4006 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a
4007 1:11424df6dc1dd4ea255eae2b58eaca7831973bbc
4007 1:11424df6dc1dd4ea255eae2b58eaca7831973bbc
4008 2:11407b3f1b9c3e76a79c1ec5373924df096f0499
4008 2:11407b3f1b9c3e76a79c1ec5373924df096f0499
4009 3:11dd92fe0f39dfdaacdaa5f3997edc533875cfc4
4009 3:11dd92fe0f39dfdaacdaa5f3997edc533875cfc4
4010 4:10776689e627b465361ad5c296a20a487e153ca4
4010 4:10776689e627b465361ad5c296a20a487e153ca4
4011 5:a00be79088084cb3aff086ab799f8790e01a976b
4011 5:a00be79088084cb3aff086ab799f8790e01a976b
4012 6:a0b0acd79b4498d0052993d35a6a748dd51d13e6
4012 6:a0b0acd79b4498d0052993d35a6a748dd51d13e6
4013 7:a0457b3450b8e1b778f1163b31a435802987fe5d
4013 7:a0457b3450b8e1b778f1163b31a435802987fe5d
4014 8:c56256a09cd28e5764f32e8e2810d0f01e2e357a
4014 8:c56256a09cd28e5764f32e8e2810d0f01e2e357a
4015 9:c5623987d205cd6d9d8389bfc40fff9dbb670b48
4015 9:c5623987d205cd6d9d8389bfc40fff9dbb670b48
4016 10:c562ddd9c94164376c20b86b0b4991636a3bf84f
4016 10:c562ddd9c94164376c20b86b0b4991636a3bf84f
4017 $ hg debugobsolete a00be79088084cb3aff086ab799f8790e01a976b
4017 $ hg debugobsolete a00be79088084cb3aff086ab799f8790e01a976b
4018 obsoleted 1 changesets
4018 obsoleted 1 changesets
4019 $ hg debugobsolete c5623987d205cd6d9d8389bfc40fff9dbb670b48
4019 $ hg debugobsolete c5623987d205cd6d9d8389bfc40fff9dbb670b48
4020 obsoleted 1 changesets
4020 obsoleted 1 changesets
4021 $ hg debugobsolete c562ddd9c94164376c20b86b0b4991636a3bf84f
4021 $ hg debugobsolete c562ddd9c94164376c20b86b0b4991636a3bf84f
4022 obsoleted 1 changesets
4022 obsoleted 1 changesets
4023
4023
4024 nodes starting with '11' (we don't have the revision number '11' though)
4024 nodes starting with '11' (we don't have the revision number '11' though)
4025
4025
4026 $ hg log -r 1:3 -T '{rev}:{shortest(node, 0)}\n'
4026 $ hg log -r 1:3 -T '{rev}:{shortest(node, 0)}\n'
4027 1:1142
4027 1:1142
4028 2:1140
4028 2:1140
4029 3:11d
4029 3:11d
4030
4030
4031 '5:a00' is hidden, but still we have two nodes starting with 'a0'
4031 '5:a00' is hidden, but still we have two nodes starting with 'a0'
4032
4032
4033 $ hg log -r 6:7 -T '{rev}:{shortest(node, 0)}\n'
4033 $ hg log -r 6:7 -T '{rev}:{shortest(node, 0)}\n'
4034 6:a0b
4034 6:a0b
4035 7:a04
4035 7:a04
4036
4036
4037 node '10' conflicts with the revision number '10' even if it is hidden
4037 node '10' conflicts with the revision number '10' even if it is hidden
4038 (we could exclude hidden revision numbers, but currently we don't)
4038 (we could exclude hidden revision numbers, but currently we don't)
4039
4039
4040 $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n'
4040 $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n'
4041 4:107
4041 4:107
4042 $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n' --hidden
4042 $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n' --hidden
4043 4:107
4043 4:107
4044
4044
4045 node 'c562' should be unique if the other 'c562' nodes are hidden
4045 node 'c562' should be unique if the other 'c562' nodes are hidden
4046 (but we don't try the slow path to filter out hidden nodes for now)
4046 (but we don't try the slow path to filter out hidden nodes for now)
4047
4047
4048 $ hg log -r 8 -T '{rev}:{node|shortest}\n'
4048 $ hg log -r 8 -T '{rev}:{node|shortest}\n'
4049 8:c5625
4049 8:c5625
4050 $ hg log -r 8:10 -T '{rev}:{node|shortest}\n' --hidden
4050 $ hg log -r 8:10 -T '{rev}:{node|shortest}\n' --hidden
4051 8:c5625
4051 8:c5625
4052 9:c5623
4052 9:c5623
4053 10:c562d
4053 10:c562d
4054
4054
4055 $ cd ..
4055 $ cd ..
4056
4056
4057 Test pad function
4057 Test pad function
4058
4058
4059 $ cd r
4059 $ cd r
4060
4060
4061 $ hg log --template '{pad(rev, 20)} {author|user}\n'
4061 $ hg log --template '{pad(rev, 20)} {author|user}\n'
4062 2 test
4062 2 test
4063 1 {node|short}
4063 1 {node|short}
4064 0 test
4064 0 test
4065
4065
4066 $ hg log --template '{pad(rev, 20, " ", True)} {author|user}\n'
4066 $ hg log --template '{pad(rev, 20, " ", True)} {author|user}\n'
4067 2 test
4067 2 test
4068 1 {node|short}
4068 1 {node|short}
4069 0 test
4069 0 test
4070
4070
4071 $ hg log --template '{pad(rev, 20, "-", False)} {author|user}\n'
4071 $ hg log --template '{pad(rev, 20, "-", False)} {author|user}\n'
4072 2------------------- test
4072 2------------------- test
4073 1------------------- {node|short}
4073 1------------------- {node|short}
4074 0------------------- test
4074 0------------------- test
4075
4075
4076 Test template string in pad function
4076 Test template string in pad function
4077
4077
4078 $ hg log -r 0 -T '{pad("\{{rev}}", 10)} {author|user}\n'
4078 $ hg log -r 0 -T '{pad("\{{rev}}", 10)} {author|user}\n'
4079 {0} test
4079 {0} test
4080
4080
4081 $ hg log -r 0 -T '{pad(r"\{rev}", 10)} {author|user}\n'
4081 $ hg log -r 0 -T '{pad(r"\{rev}", 10)} {author|user}\n'
4082 \{rev} test
4082 \{rev} test
4083
4083
4084 Test width argument passed to pad function
4084 Test width argument passed to pad function
4085
4085
4086 $ hg log -r 0 -T '{pad(rev, "1{"0"}")} {author|user}\n'
4086 $ hg log -r 0 -T '{pad(rev, "1{"0"}")} {author|user}\n'
4087 0 test
4087 0 test
4088 $ hg log -r 0 -T '{pad(rev, "not an int")}\n'
4088 $ hg log -r 0 -T '{pad(rev, "not an int")}\n'
4089 hg: parse error: pad() expects an integer width
4089 hg: parse error: pad() expects an integer width
4090 [255]
4090 [255]
4091
4091
4092 Test invalid fillchar passed to pad function
4092 Test invalid fillchar passed to pad function
4093
4093
4094 $ hg log -r 0 -T '{pad(rev, 10, "")}\n'
4094 $ hg log -r 0 -T '{pad(rev, 10, "")}\n'
4095 hg: parse error: pad() expects a single fill character
4095 hg: parse error: pad() expects a single fill character
4096 [255]
4096 [255]
4097 $ hg log -r 0 -T '{pad(rev, 10, "--")}\n'
4097 $ hg log -r 0 -T '{pad(rev, 10, "--")}\n'
4098 hg: parse error: pad() expects a single fill character
4098 hg: parse error: pad() expects a single fill character
4099 [255]
4099 [255]
4100
4100
4101 Test boolean argument passed to pad function
4101 Test boolean argument passed to pad function
4102
4102
4103 no crash
4103 no crash
4104
4104
4105 $ hg log -r 0 -T '{pad(rev, 10, "-", "f{"oo"}")}\n'
4105 $ hg log -r 0 -T '{pad(rev, 10, "-", "f{"oo"}")}\n'
4106 ---------0
4106 ---------0
4107
4107
4108 string/literal
4108 string/literal
4109
4109
4110 $ hg log -r 0 -T '{pad(rev, 10, "-", "false")}\n'
4110 $ hg log -r 0 -T '{pad(rev, 10, "-", "false")}\n'
4111 ---------0
4111 ---------0
4112 $ hg log -r 0 -T '{pad(rev, 10, "-", false)}\n'
4112 $ hg log -r 0 -T '{pad(rev, 10, "-", false)}\n'
4113 0---------
4113 0---------
4114 $ hg log -r 0 -T '{pad(rev, 10, "-", "")}\n'
4114 $ hg log -r 0 -T '{pad(rev, 10, "-", "")}\n'
4115 0---------
4115 0---------
4116
4116
4117 unknown keyword is evaluated to ''
4117 unknown keyword is evaluated to ''
4118
4118
4119 $ hg log -r 0 -T '{pad(rev, 10, "-", unknownkeyword)}\n'
4119 $ hg log -r 0 -T '{pad(rev, 10, "-", unknownkeyword)}\n'
4120 0---------
4120 0---------
4121
4121
4122 Test separate function
4122 Test separate function
4123
4123
4124 $ hg log -r 0 -T '{separate("-", "", "a", "b", "", "", "c", "")}\n'
4124 $ hg log -r 0 -T '{separate("-", "", "a", "b", "", "", "c", "")}\n'
4125 a-b-c
4125 a-b-c
4126 $ hg log -r 0 -T '{separate(" ", "{rev}:{node|short}", author|user, branch)}\n'
4126 $ hg log -r 0 -T '{separate(" ", "{rev}:{node|short}", author|user, branch)}\n'
4127 0:f7769ec2ab97 test default
4127 0:f7769ec2ab97 test default
4128 $ hg log -r 0 --color=always -T '{separate(" ", "a", label(red, "b"), "c", label(red, ""), "d")}\n'
4128 $ hg log -r 0 --color=always -T '{separate(" ", "a", label(red, "b"), "c", label(red, ""), "d")}\n'
4129 a \x1b[0;31mb\x1b[0m c d (esc)
4129 a \x1b[0;31mb\x1b[0m c d (esc)
4130
4130
4131 Test boolean expression/literal passed to if function
4131 Test boolean expression/literal passed to if function
4132
4132
4133 $ hg log -r 0 -T '{if(rev, "rev 0 is True")}\n'
4133 $ hg log -r 0 -T '{if(rev, "rev 0 is True")}\n'
4134 rev 0 is True
4134 rev 0 is True
4135 $ hg log -r 0 -T '{if(0, "literal 0 is True as well")}\n'
4135 $ hg log -r 0 -T '{if(0, "literal 0 is True as well")}\n'
4136 literal 0 is True as well
4136 literal 0 is True as well
4137 $ hg log -r 0 -T '{if("", "", "empty string is False")}\n'
4137 $ hg log -r 0 -T '{if("", "", "empty string is False")}\n'
4138 empty string is False
4138 empty string is False
4139 $ hg log -r 0 -T '{if(revset(r"0 - 0"), "", "empty list is False")}\n'
4139 $ hg log -r 0 -T '{if(revset(r"0 - 0"), "", "empty list is False")}\n'
4140 empty list is False
4140 empty list is False
4141 $ hg log -r 0 -T '{if(true, "true is True")}\n'
4141 $ hg log -r 0 -T '{if(true, "true is True")}\n'
4142 true is True
4142 true is True
4143 $ hg log -r 0 -T '{if(false, "", "false is False")}\n'
4143 $ hg log -r 0 -T '{if(false, "", "false is False")}\n'
4144 false is False
4144 false is False
4145 $ hg log -r 0 -T '{if("false", "non-empty string is True")}\n'
4145 $ hg log -r 0 -T '{if("false", "non-empty string is True")}\n'
4146 non-empty string is True
4146 non-empty string is True
4147
4147
4148 Test ifcontains function
4148 Test ifcontains function
4149
4149
4150 $ hg log --template '{rev} {ifcontains(rev, "2 two 0", "is in the string", "is not")}\n'
4150 $ hg log --template '{rev} {ifcontains(rev, "2 two 0", "is in the string", "is not")}\n'
4151 2 is in the string
4151 2 is in the string
4152 1 is not
4152 1 is not
4153 0 is in the string
4153 0 is in the string
4154
4154
4155 $ hg log -T '{rev} {ifcontains(rev, "2 two{" 0"}", "is in the string", "is not")}\n'
4155 $ hg log -T '{rev} {ifcontains(rev, "2 two{" 0"}", "is in the string", "is not")}\n'
4156 2 is in the string
4156 2 is in the string
4157 1 is not
4157 1 is not
4158 0 is in the string
4158 0 is in the string
4159
4159
4160 $ hg log --template '{rev} {ifcontains("a", file_adds, "added a", "did not add a")}\n'
4160 $ hg log --template '{rev} {ifcontains("a", file_adds, "added a", "did not add a")}\n'
4161 2 did not add a
4161 2 did not add a
4162 1 did not add a
4162 1 did not add a
4163 0 added a
4163 0 added a
4164
4164
4165 $ hg log --debug -T '{rev}{ifcontains(1, parents, " is parent of 1")}\n'
4165 $ hg log --debug -T '{rev}{ifcontains(1, parents, " is parent of 1")}\n'
4166 2 is parent of 1
4166 2 is parent of 1
4167 1
4167 1
4168 0
4168 0
4169
4169
4170 $ hg log -l1 -T '{ifcontains("branch", extras, "t", "f")}\n'
4170 $ hg log -l1 -T '{ifcontains("branch", extras, "t", "f")}\n'
4171 t
4171 t
4172 $ hg log -l1 -T '{ifcontains("branch", extras % "{key}", "t", "f")}\n'
4172 $ hg log -l1 -T '{ifcontains("branch", extras % "{key}", "t", "f")}\n'
4173 t
4173 t
4174 $ hg log -l1 -T '{ifcontains("branc", extras % "{key}", "t", "f")}\n'
4174 $ hg log -l1 -T '{ifcontains("branc", extras % "{key}", "t", "f")}\n'
4175 f
4175 f
4176 $ hg log -l1 -T '{ifcontains("branc", stringify(extras % "{key}"), "t", "f")}\n'
4176 $ hg log -l1 -T '{ifcontains("branc", stringify(extras % "{key}"), "t", "f")}\n'
4177 t
4177 t
4178
4178
4179 Test revset function
4179 Test revset function
4180
4180
4181 $ hg log --template '{rev} {ifcontains(rev, revset("."), "current rev", "not current rev")}\n'
4181 $ hg log --template '{rev} {ifcontains(rev, revset("."), "current rev", "not current rev")}\n'
4182 2 current rev
4182 2 current rev
4183 1 not current rev
4183 1 not current rev
4184 0 not current rev
4184 0 not current rev
4185
4185
4186 $ hg log --template '{rev} {ifcontains(rev, revset(". + .^"), "match rev", "not match rev")}\n'
4186 $ hg log --template '{rev} {ifcontains(rev, revset(". + .^"), "match rev", "not match rev")}\n'
4187 2 match rev
4187 2 match rev
4188 1 match rev
4188 1 match rev
4189 0 not match rev
4189 0 not match rev
4190
4190
4191 $ hg log -T '{ifcontains(desc, revset(":"), "", "type not match")}\n' -l1
4191 $ hg log -T '{ifcontains(desc, revset(":"), "", "type not match")}\n' -l1
4192 type not match
4192 type not match
4193
4193
4194 $ hg log --template '{rev} Parents: {revset("parents(%s)", rev)}\n'
4194 $ hg log --template '{rev} Parents: {revset("parents(%s)", rev)}\n'
4195 2 Parents: 1
4195 2 Parents: 1
4196 1 Parents: 0
4196 1 Parents: 0
4197 0 Parents:
4197 0 Parents:
4198
4198
4199 $ cat >> .hg/hgrc <<EOF
4199 $ cat >> .hg/hgrc <<EOF
4200 > [revsetalias]
4200 > [revsetalias]
4201 > myparents(\$1) = parents(\$1)
4201 > myparents(\$1) = parents(\$1)
4202 > EOF
4202 > EOF
4203 $ hg log --template '{rev} Parents: {revset("myparents(%s)", rev)}\n'
4203 $ hg log --template '{rev} Parents: {revset("myparents(%s)", rev)}\n'
4204 2 Parents: 1
4204 2 Parents: 1
4205 1 Parents: 0
4205 1 Parents: 0
4206 0 Parents:
4206 0 Parents:
4207
4207
4208 $ hg log --template 'Rev: {rev}\n{revset("::%s", rev) % "Ancestor: {revision}\n"}\n'
4208 $ hg log --template 'Rev: {rev}\n{revset("::%s", rev) % "Ancestor: {revision}\n"}\n'
4209 Rev: 2
4209 Rev: 2
4210 Ancestor: 0
4210 Ancestor: 0
4211 Ancestor: 1
4211 Ancestor: 1
4212 Ancestor: 2
4212 Ancestor: 2
4213
4213
4214 Rev: 1
4214 Rev: 1
4215 Ancestor: 0
4215 Ancestor: 0
4216 Ancestor: 1
4216 Ancestor: 1
4217
4217
4218 Rev: 0
4218 Rev: 0
4219 Ancestor: 0
4219 Ancestor: 0
4220
4220
4221 $ hg log --template '{revset("TIP"|lower)}\n' -l1
4221 $ hg log --template '{revset("TIP"|lower)}\n' -l1
4222 2
4222 2
4223
4223
4224 $ hg log -T '{revset("%s", "t{"ip"}")}\n' -l1
4224 $ hg log -T '{revset("%s", "t{"ip"}")}\n' -l1
4225 2
4225 2
4226
4226
4227 a list template is evaluated for each item of revset/parents
4227 a list template is evaluated for each item of revset/parents
4228
4228
4229 $ hg log -T '{rev} p: {revset("p1(%s)", rev) % "{rev}:{node|short}"}\n'
4229 $ hg log -T '{rev} p: {revset("p1(%s)", rev) % "{rev}:{node|short}"}\n'
4230 2 p: 1:bcc7ff960b8e
4230 2 p: 1:bcc7ff960b8e
4231 1 p: 0:f7769ec2ab97
4231 1 p: 0:f7769ec2ab97
4232 0 p:
4232 0 p:
4233
4233
4234 $ hg log --debug -T '{rev} p:{parents % " {rev}:{node|short}"}\n'
4234 $ hg log --debug -T '{rev} p:{parents % " {rev}:{node|short}"}\n'
4235 2 p: 1:bcc7ff960b8e -1:000000000000
4235 2 p: 1:bcc7ff960b8e -1:000000000000
4236 1 p: 0:f7769ec2ab97 -1:000000000000
4236 1 p: 0:f7769ec2ab97 -1:000000000000
4237 0 p: -1:000000000000 -1:000000000000
4237 0 p: -1:000000000000 -1:000000000000
4238
4238
4239 therefore, 'revcache' should be recreated for each rev
4239 therefore, 'revcache' should be recreated for each rev
4240
4240
4241 $ hg log -T '{rev} {file_adds}\np {revset("p1(%s)", rev) % "{file_adds}"}\n'
4241 $ hg log -T '{rev} {file_adds}\np {revset("p1(%s)", rev) % "{file_adds}"}\n'
4242 2 aa b
4242 2 aa b
4243 p
4243 p
4244 1
4244 1
4245 p a
4245 p a
4246 0 a
4246 0 a
4247 p
4247 p
4248
4248
4249 $ hg log --debug -T '{rev} {file_adds}\np {parents % "{file_adds}"}\n'
4249 $ hg log --debug -T '{rev} {file_adds}\np {parents % "{file_adds}"}\n'
4250 2 aa b
4250 2 aa b
4251 p
4251 p
4252 1
4252 1
4253 p a
4253 p a
4254 0 a
4254 0 a
4255 p
4255 p
4256
4256
4257 a revset item must be evaluated as an integer revision, not an offset from tip
4257 a revset item must be evaluated as an integer revision, not an offset from tip
4258
4258
4259 $ hg log -l 1 -T '{revset("null") % "{rev}:{node|short}"}\n'
4259 $ hg log -l 1 -T '{revset("null") % "{rev}:{node|short}"}\n'
4260 -1:000000000000
4260 -1:000000000000
4261 $ hg log -l 1 -T '{revset("%s", "null") % "{rev}:{node|short}"}\n'
4261 $ hg log -l 1 -T '{revset("%s", "null") % "{rev}:{node|short}"}\n'
4262 -1:000000000000
4262 -1:000000000000
4263
4263
4264 join() should pick '{rev}' from revset items:
4264 join() should pick '{rev}' from revset items:
4265
4265
4266 $ hg log -R ../a -T '{join(revset("parents(%d)", rev), ", ")}\n' -r6
4266 $ hg log -R ../a -T '{join(revset("parents(%d)", rev), ", ")}\n' -r6
4267 4, 5
4267 4, 5
4268
4268
4269 on the other hand, parents are formatted as '{rev}:{node|formatnode}' by
4269 on the other hand, parents are formatted as '{rev}:{node|formatnode}' by
4270 default. join() should agree with the default formatting:
4270 default. join() should agree with the default formatting:
4271
4271
4272 $ hg log -R ../a -T '{join(parents, ", ")}\n' -r6
4272 $ hg log -R ../a -T '{join(parents, ", ")}\n' -r6
4273 5:13207e5a10d9, 4:bbe44766e73d
4273 5:13207e5a10d9, 4:bbe44766e73d
4274
4274
4275 $ hg log -R ../a -T '{join(parents, ",\n")}\n' -r6 --debug
4275 $ hg log -R ../a -T '{join(parents, ",\n")}\n' -r6 --debug
4276 5:13207e5a10d9fd28ec424934298e176197f2c67f,
4276 5:13207e5a10d9fd28ec424934298e176197f2c67f,
4277 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
4277 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
4278
4278
4279 Invalid arguments passed to revset()
4279 Invalid arguments passed to revset()
4280
4280
4281 $ hg log -T '{revset("%whatever", 0)}\n'
4281 $ hg log -T '{revset("%whatever", 0)}\n'
4282 hg: parse error: unexpected revspec format character w
4282 hg: parse error: unexpected revspec format character w
4283 [255]
4283 [255]
4284 $ hg log -T '{revset("%lwhatever", files)}\n'
4284 $ hg log -T '{revset("%lwhatever", files)}\n'
4285 hg: parse error: unexpected revspec format character w
4285 hg: parse error: unexpected revspec format character w
4286 [255]
4286 [255]
4287 $ hg log -T '{revset("%s %s", 0)}\n'
4287 $ hg log -T '{revset("%s %s", 0)}\n'
4288 hg: parse error: missing argument for revspec
4288 hg: parse error: missing argument for revspec
4289 [255]
4289 [255]
4290 $ hg log -T '{revset("", 0)}\n'
4290 $ hg log -T '{revset("", 0)}\n'
4291 hg: parse error: too many revspec arguments specified
4291 hg: parse error: too many revspec arguments specified
4292 [255]
4292 [255]
4293 $ hg log -T '{revset("%s", 0, 1)}\n'
4293 $ hg log -T '{revset("%s", 0, 1)}\n'
4294 hg: parse error: too many revspec arguments specified
4294 hg: parse error: too many revspec arguments specified
4295 [255]
4295 [255]
4296 $ hg log -T '{revset("%", 0)}\n'
4296 $ hg log -T '{revset("%", 0)}\n'
4297 hg: parse error: incomplete revspec format character
4297 hg: parse error: incomplete revspec format character
4298 [255]
4298 [255]
4299 $ hg log -T '{revset("%l", 0)}\n'
4299 $ hg log -T '{revset("%l", 0)}\n'
4300 hg: parse error: incomplete revspec format character
4300 hg: parse error: incomplete revspec format character
4301 [255]
4301 [255]
4302 $ hg log -T '{revset("%d", 'foo')}\n'
4302 $ hg log -T '{revset("%d", 'foo')}\n'
4303 hg: parse error: invalid argument for revspec
4303 hg: parse error: invalid argument for revspec
4304 [255]
4304 [255]
4305 $ hg log -T '{revset("%ld", files)}\n'
4305 $ hg log -T '{revset("%ld", files)}\n'
4306 hg: parse error: invalid argument for revspec
4306 hg: parse error: invalid argument for revspec
4307 [255]
4307 [255]
4308 $ hg log -T '{revset("%ls", 0)}\n'
4308 $ hg log -T '{revset("%ls", 0)}\n'
4309 hg: parse error: invalid argument for revspec
4309 hg: parse error: invalid argument for revspec
4310 [255]
4310 [255]
4311 $ hg log -T '{revset("%b", 'foo')}\n'
4311 $ hg log -T '{revset("%b", 'foo')}\n'
4312 hg: parse error: invalid argument for revspec
4312 hg: parse error: invalid argument for revspec
4313 [255]
4313 [255]
4314 $ hg log -T '{revset("%lb", files)}\n'
4314 $ hg log -T '{revset("%lb", files)}\n'
4315 hg: parse error: invalid argument for revspec
4315 hg: parse error: invalid argument for revspec
4316 [255]
4316 [255]
4317 $ hg log -T '{revset("%r", 0)}\n'
4317 $ hg log -T '{revset("%r", 0)}\n'
4318 hg: parse error: invalid argument for revspec
4318 hg: parse error: invalid argument for revspec
4319 [255]
4319 [255]
4320
4320
4321 Test 'originalnode'
4321 Test 'originalnode'
4322
4322
4323 $ hg log -r 1 -T '{revset("null") % "{node|short} {originalnode|short}"}\n'
4323 $ hg log -r 1 -T '{revset("null") % "{node|short} {originalnode|short}"}\n'
4324 000000000000 bcc7ff960b8e
4324 000000000000 bcc7ff960b8e
4325 $ hg log -r 0 -T '{manifest % "{node} {originalnode}"}\n'
4325 $ hg log -r 0 -T '{manifest % "{node} {originalnode}"}\n'
4326 a0c8bcbbb45c63b90b70ad007bf38961f64f2af0 f7769ec2ab975ad19684098ad1ffd9b81ecc71a1
4326 a0c8bcbbb45c63b90b70ad007bf38961f64f2af0 f7769ec2ab975ad19684098ad1ffd9b81ecc71a1
4327
4327
4328 Test files function
4328 Test files function
4329
4329
4330 $ hg log -T "{rev}\n{join(files('*'), '\n')}\n"
4330 $ hg log -T "{rev}\n{join(files('*'), '\n')}\n"
4331 2
4331 2
4332 a
4332 a
4333 aa
4333 aa
4334 b
4334 b
4335 1
4335 1
4336 a
4336 a
4337 0
4337 0
4338 a
4338 a
4339
4339
4340 $ hg log -T "{rev}\n{join(files('aa'), '\n')}\n"
4340 $ hg log -T "{rev}\n{join(files('aa'), '\n')}\n"
4341 2
4341 2
4342 aa
4342 aa
4343 1
4343 1
4344
4344
4345 0
4345 0
4346
4346
4347 $ hg rm a
4348 $ hg log -r "wdir()" -T "{rev}\n{join(files('*'), '\n')}\n"
4349 2147483647
4350 aa
4351 b
4352 $ hg revert a
4347
4353
4348 Test relpath function
4354 Test relpath function
4349
4355
4350 $ hg log -r0 -T '{files % "{file|relpath}\n"}'
4356 $ hg log -r0 -T '{files % "{file|relpath}\n"}'
4351 a
4357 a
4352 $ cd ..
4358 $ cd ..
4353 $ hg log -R r -r0 -T '{files % "{file|relpath}\n"}'
4359 $ hg log -R r -r0 -T '{files % "{file|relpath}\n"}'
4354 r/a
4360 r/a
4355 $ cd r
4361 $ cd r
4356
4362
4357 Test active bookmark templating
4363 Test active bookmark templating
4358
4364
4359 $ hg book foo
4365 $ hg book foo
4360 $ hg book bar
4366 $ hg book bar
4361 $ hg log --template "{rev} {bookmarks % '{bookmark}{ifeq(bookmark, active, \"*\")} '}\n"
4367 $ hg log --template "{rev} {bookmarks % '{bookmark}{ifeq(bookmark, active, \"*\")} '}\n"
4362 2 bar* foo
4368 2 bar* foo
4363 1
4369 1
4364 0
4370 0
4365 $ hg log --template "{rev} {activebookmark}\n"
4371 $ hg log --template "{rev} {activebookmark}\n"
4366 2 bar
4372 2 bar
4367 1
4373 1
4368 0
4374 0
4369 $ hg bookmarks --inactive bar
4375 $ hg bookmarks --inactive bar
4370 $ hg log --template "{rev} {activebookmark}\n"
4376 $ hg log --template "{rev} {activebookmark}\n"
4371 2
4377 2
4372 1
4378 1
4373 0
4379 0
4374 $ hg book -r1 baz
4380 $ hg book -r1 baz
4375 $ hg log --template "{rev} {join(bookmarks, ' ')}\n"
4381 $ hg log --template "{rev} {join(bookmarks, ' ')}\n"
4376 2 bar foo
4382 2 bar foo
4377 1 baz
4383 1 baz
4378 0
4384 0
4379 $ hg log --template "{rev} {ifcontains('foo', bookmarks, 't', 'f')}\n"
4385 $ hg log --template "{rev} {ifcontains('foo', bookmarks, 't', 'f')}\n"
4380 2 t
4386 2 t
4381 1 f
4387 1 f
4382 0 f
4388 0 f
4383
4389
4384 Test namespaces dict
4390 Test namespaces dict
4385
4391
4386 $ hg --config extensions.revnamesext=$TESTDIR/revnamesext.py log -T '{rev}\n{namespaces % " {namespace} color={colorname} builtin={builtin}\n {join(names, ",")}\n"}\n'
4392 $ hg --config extensions.revnamesext=$TESTDIR/revnamesext.py log -T '{rev}\n{namespaces % " {namespace} color={colorname} builtin={builtin}\n {join(names, ",")}\n"}\n'
4387 2
4393 2
4388 bookmarks color=bookmark builtin=True
4394 bookmarks color=bookmark builtin=True
4389 bar,foo
4395 bar,foo
4390 tags color=tag builtin=True
4396 tags color=tag builtin=True
4391 tip
4397 tip
4392 branches color=branch builtin=True
4398 branches color=branch builtin=True
4393 text.{rev}
4399 text.{rev}
4394 revnames color=revname builtin=False
4400 revnames color=revname builtin=False
4395 r2
4401 r2
4396
4402
4397 1
4403 1
4398 bookmarks color=bookmark builtin=True
4404 bookmarks color=bookmark builtin=True
4399 baz
4405 baz
4400 tags color=tag builtin=True
4406 tags color=tag builtin=True
4401
4407
4402 branches color=branch builtin=True
4408 branches color=branch builtin=True
4403 text.{rev}
4409 text.{rev}
4404 revnames color=revname builtin=False
4410 revnames color=revname builtin=False
4405 r1
4411 r1
4406
4412
4407 0
4413 0
4408 bookmarks color=bookmark builtin=True
4414 bookmarks color=bookmark builtin=True
4409
4415
4410 tags color=tag builtin=True
4416 tags color=tag builtin=True
4411
4417
4412 branches color=branch builtin=True
4418 branches color=branch builtin=True
4413 default
4419 default
4414 revnames color=revname builtin=False
4420 revnames color=revname builtin=False
4415 r0
4421 r0
4416
4422
4417 $ hg log -r2 -T '{namespaces % "{namespace}: {names}\n"}'
4423 $ hg log -r2 -T '{namespaces % "{namespace}: {names}\n"}'
4418 bookmarks: bar foo
4424 bookmarks: bar foo
4419 tags: tip
4425 tags: tip
4420 branches: text.{rev}
4426 branches: text.{rev}
4421 $ hg log -r2 -T '{namespaces % "{namespace}:\n{names % " {name}\n"}"}'
4427 $ hg log -r2 -T '{namespaces % "{namespace}:\n{names % " {name}\n"}"}'
4422 bookmarks:
4428 bookmarks:
4423 bar
4429 bar
4424 foo
4430 foo
4425 tags:
4431 tags:
4426 tip
4432 tip
4427 branches:
4433 branches:
4428 text.{rev}
4434 text.{rev}
4429 $ hg log -r2 -T '{get(namespaces, "bookmarks") % "{name}\n"}'
4435 $ hg log -r2 -T '{get(namespaces, "bookmarks") % "{name}\n"}'
4430 bar
4436 bar
4431 foo
4437 foo
4432 $ hg log -r2 -T '{namespaces.bookmarks % "{bookmark}\n"}'
4438 $ hg log -r2 -T '{namespaces.bookmarks % "{bookmark}\n"}'
4433 bar
4439 bar
4434 foo
4440 foo
4435
4441
4436 Test stringify on sub expressions
4442 Test stringify on sub expressions
4437
4443
4438 $ cd ..
4444 $ cd ..
4439 $ hg log -R a -r 8 --template '{join(files, if("1", if("1", ", ")))}\n'
4445 $ hg log -R a -r 8 --template '{join(files, if("1", if("1", ", ")))}\n'
4440 fourth, second, third
4446 fourth, second, third
4441 $ hg log -R a -r 8 --template '{strip(if("1", if("1", "-abc-")), if("1", if("1", "-")))}\n'
4447 $ hg log -R a -r 8 --template '{strip(if("1", if("1", "-abc-")), if("1", if("1", "-")))}\n'
4442 abc
4448 abc
4443
4449
4444 Test splitlines
4450 Test splitlines
4445
4451
4446 $ hg log -Gv -R a --template "{splitlines(desc) % 'foo {line}\n'}"
4452 $ hg log -Gv -R a --template "{splitlines(desc) % 'foo {line}\n'}"
4447 @ foo Modify, add, remove, rename
4453 @ foo Modify, add, remove, rename
4448 |
4454 |
4449 o foo future
4455 o foo future
4450 |
4456 |
4451 o foo third
4457 o foo third
4452 |
4458 |
4453 o foo second
4459 o foo second
4454
4460
4455 o foo merge
4461 o foo merge
4456 |\
4462 |\
4457 | o foo new head
4463 | o foo new head
4458 | |
4464 | |
4459 o | foo new branch
4465 o | foo new branch
4460 |/
4466 |/
4461 o foo no user, no domain
4467 o foo no user, no domain
4462 |
4468 |
4463 o foo no person
4469 o foo no person
4464 |
4470 |
4465 o foo other 1
4471 o foo other 1
4466 | foo other 2
4472 | foo other 2
4467 | foo
4473 | foo
4468 | foo other 3
4474 | foo other 3
4469 o foo line 1
4475 o foo line 1
4470 foo line 2
4476 foo line 2
4471
4477
4472 $ hg log -R a -r0 -T '{desc|splitlines}\n'
4478 $ hg log -R a -r0 -T '{desc|splitlines}\n'
4473 line 1 line 2
4479 line 1 line 2
4474 $ hg log -R a -r0 -T '{join(desc|splitlines, "|")}\n'
4480 $ hg log -R a -r0 -T '{join(desc|splitlines, "|")}\n'
4475 line 1|line 2
4481 line 1|line 2
4476
4482
4477 Test startswith
4483 Test startswith
4478 $ hg log -Gv -R a --template "{startswith(desc)}"
4484 $ hg log -Gv -R a --template "{startswith(desc)}"
4479 hg: parse error: startswith expects two arguments
4485 hg: parse error: startswith expects two arguments
4480 [255]
4486 [255]
4481
4487
4482 $ hg log -Gv -R a --template "{startswith('line', desc)}"
4488 $ hg log -Gv -R a --template "{startswith('line', desc)}"
4483 @
4489 @
4484 |
4490 |
4485 o
4491 o
4486 |
4492 |
4487 o
4493 o
4488 |
4494 |
4489 o
4495 o
4490
4496
4491 o
4497 o
4492 |\
4498 |\
4493 | o
4499 | o
4494 | |
4500 | |
4495 o |
4501 o |
4496 |/
4502 |/
4497 o
4503 o
4498 |
4504 |
4499 o
4505 o
4500 |
4506 |
4501 o
4507 o
4502 |
4508 |
4503 o line 1
4509 o line 1
4504 line 2
4510 line 2
4505
4511
4506 Test bad template with better error message
4512 Test bad template with better error message
4507
4513
4508 $ hg log -Gv -R a --template '{desc|user()}'
4514 $ hg log -Gv -R a --template '{desc|user()}'
4509 hg: parse error: expected a symbol, got 'func'
4515 hg: parse error: expected a symbol, got 'func'
4510 [255]
4516 [255]
4511
4517
4512 Test word function (including index out of bounds graceful failure)
4518 Test word function (including index out of bounds graceful failure)
4513
4519
4514 $ hg log -Gv -R a --template "{word('1', desc)}"
4520 $ hg log -Gv -R a --template "{word('1', desc)}"
4515 @ add,
4521 @ add,
4516 |
4522 |
4517 o
4523 o
4518 |
4524 |
4519 o
4525 o
4520 |
4526 |
4521 o
4527 o
4522
4528
4523 o
4529 o
4524 |\
4530 |\
4525 | o head
4531 | o head
4526 | |
4532 | |
4527 o | branch
4533 o | branch
4528 |/
4534 |/
4529 o user,
4535 o user,
4530 |
4536 |
4531 o person
4537 o person
4532 |
4538 |
4533 o 1
4539 o 1
4534 |
4540 |
4535 o 1
4541 o 1
4536
4542
4537
4543
4538 Test word third parameter used as splitter
4544 Test word third parameter used as splitter
4539
4545
4540 $ hg log -Gv -R a --template "{word('0', desc, 'o')}"
4546 $ hg log -Gv -R a --template "{word('0', desc, 'o')}"
4541 @ M
4547 @ M
4542 |
4548 |
4543 o future
4549 o future
4544 |
4550 |
4545 o third
4551 o third
4546 |
4552 |
4547 o sec
4553 o sec
4548
4554
4549 o merge
4555 o merge
4550 |\
4556 |\
4551 | o new head
4557 | o new head
4552 | |
4558 | |
4553 o | new branch
4559 o | new branch
4554 |/
4560 |/
4555 o n
4561 o n
4556 |
4562 |
4557 o n
4563 o n
4558 |
4564 |
4559 o
4565 o
4560 |
4566 |
4561 o line 1
4567 o line 1
4562 line 2
4568 line 2
4563
4569
4564 Test word error messages for not enough and too many arguments
4570 Test word error messages for not enough and too many arguments
4565
4571
4566 $ hg log -Gv -R a --template "{word('0')}"
4572 $ hg log -Gv -R a --template "{word('0')}"
4567 hg: parse error: word expects two or three arguments, got 1
4573 hg: parse error: word expects two or three arguments, got 1
4568 [255]
4574 [255]
4569
4575
4570 $ hg log -Gv -R a --template "{word('0', desc, 'o', 'h', 'b', 'o', 'y')}"
4576 $ hg log -Gv -R a --template "{word('0', desc, 'o', 'h', 'b', 'o', 'y')}"
4571 hg: parse error: word expects two or three arguments, got 7
4577 hg: parse error: word expects two or three arguments, got 7
4572 [255]
4578 [255]
4573
4579
4574 Test word for integer literal
4580 Test word for integer literal
4575
4581
4576 $ hg log -R a --template "{word(2, desc)}\n" -r0
4582 $ hg log -R a --template "{word(2, desc)}\n" -r0
4577 line
4583 line
4578
4584
4579 Test word for invalid numbers
4585 Test word for invalid numbers
4580
4586
4581 $ hg log -Gv -R a --template "{word('a', desc)}"
4587 $ hg log -Gv -R a --template "{word('a', desc)}"
4582 hg: parse error: word expects an integer index
4588 hg: parse error: word expects an integer index
4583 [255]
4589 [255]
4584
4590
4585 Test word for out of range
4591 Test word for out of range
4586
4592
4587 $ hg log -R a --template "{word(10000, desc)}"
4593 $ hg log -R a --template "{word(10000, desc)}"
4588 $ hg log -R a --template "{word(-10000, desc)}"
4594 $ hg log -R a --template "{word(-10000, desc)}"
4589
4595
4590 Test indent and not adding to empty lines
4596 Test indent and not adding to empty lines
4591
4597
4592 $ hg log -T "-----\n{indent(desc, '>> ', ' > ')}\n" -r 0:1 -R a
4598 $ hg log -T "-----\n{indent(desc, '>> ', ' > ')}\n" -r 0:1 -R a
4593 -----
4599 -----
4594 > line 1
4600 > line 1
4595 >> line 2
4601 >> line 2
4596 -----
4602 -----
4597 > other 1
4603 > other 1
4598 >> other 2
4604 >> other 2
4599
4605
4600 >> other 3
4606 >> other 3
4601
4607
4602 Test with non-strings like dates
4608 Test with non-strings like dates
4603
4609
4604 $ hg log -T "{indent(date, ' ')}\n" -r 2:3 -R a
4610 $ hg log -T "{indent(date, ' ')}\n" -r 2:3 -R a
4605 1200000.00
4611 1200000.00
4606 1300000.00
4612 1300000.00
4607
4613
4608 Test broken string escapes:
4614 Test broken string escapes:
4609
4615
4610 $ hg log -T "bogus\\" -R a
4616 $ hg log -T "bogus\\" -R a
4611 hg: parse error: trailing \ in string
4617 hg: parse error: trailing \ in string
4612 [255]
4618 [255]
4613 $ hg log -T "\\xy" -R a
4619 $ hg log -T "\\xy" -R a
4614 hg: parse error: invalid \x escape* (glob)
4620 hg: parse error: invalid \x escape* (glob)
4615 [255]
4621 [255]
4616
4622
4617 json filter should escape HTML tags so that the output can be embedded in hgweb:
4623 json filter should escape HTML tags so that the output can be embedded in hgweb:
4618
4624
4619 $ hg log -T "{'<foo@example.org>'|json}\n" -R a -l1
4625 $ hg log -T "{'<foo@example.org>'|json}\n" -R a -l1
4620 "\u003cfoo@example.org\u003e"
4626 "\u003cfoo@example.org\u003e"
4621
4627
4622 Templater supports aliases of symbol and func() styles:
4628 Templater supports aliases of symbol and func() styles:
4623
4629
4624 $ hg clone -q a aliases
4630 $ hg clone -q a aliases
4625 $ cd aliases
4631 $ cd aliases
4626 $ cat <<EOF >> .hg/hgrc
4632 $ cat <<EOF >> .hg/hgrc
4627 > [templatealias]
4633 > [templatealias]
4628 > r = rev
4634 > r = rev
4629 > rn = "{r}:{node|short}"
4635 > rn = "{r}:{node|short}"
4630 > status(c, files) = files % "{c} {file}\n"
4636 > status(c, files) = files % "{c} {file}\n"
4631 > utcdate(d) = localdate(d, "UTC")
4637 > utcdate(d) = localdate(d, "UTC")
4632 > EOF
4638 > EOF
4633
4639
4634 $ hg debugtemplate -vr0 '{rn} {utcdate(date)|isodate}\n'
4640 $ hg debugtemplate -vr0 '{rn} {utcdate(date)|isodate}\n'
4635 (template
4641 (template
4636 (symbol 'rn')
4642 (symbol 'rn')
4637 (string ' ')
4643 (string ' ')
4638 (|
4644 (|
4639 (func
4645 (func
4640 (symbol 'utcdate')
4646 (symbol 'utcdate')
4641 (symbol 'date'))
4647 (symbol 'date'))
4642 (symbol 'isodate'))
4648 (symbol 'isodate'))
4643 (string '\n'))
4649 (string '\n'))
4644 * expanded:
4650 * expanded:
4645 (template
4651 (template
4646 (template
4652 (template
4647 (symbol 'rev')
4653 (symbol 'rev')
4648 (string ':')
4654 (string ':')
4649 (|
4655 (|
4650 (symbol 'node')
4656 (symbol 'node')
4651 (symbol 'short')))
4657 (symbol 'short')))
4652 (string ' ')
4658 (string ' ')
4653 (|
4659 (|
4654 (func
4660 (func
4655 (symbol 'localdate')
4661 (symbol 'localdate')
4656 (list
4662 (list
4657 (symbol 'date')
4663 (symbol 'date')
4658 (string 'UTC')))
4664 (string 'UTC')))
4659 (symbol 'isodate'))
4665 (symbol 'isodate'))
4660 (string '\n'))
4666 (string '\n'))
4661 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4667 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4662
4668
4663 $ hg debugtemplate -vr0 '{status("A", file_adds)}'
4669 $ hg debugtemplate -vr0 '{status("A", file_adds)}'
4664 (template
4670 (template
4665 (func
4671 (func
4666 (symbol 'status')
4672 (symbol 'status')
4667 (list
4673 (list
4668 (string 'A')
4674 (string 'A')
4669 (symbol 'file_adds'))))
4675 (symbol 'file_adds'))))
4670 * expanded:
4676 * expanded:
4671 (template
4677 (template
4672 (%
4678 (%
4673 (symbol 'file_adds')
4679 (symbol 'file_adds')
4674 (template
4680 (template
4675 (string 'A')
4681 (string 'A')
4676 (string ' ')
4682 (string ' ')
4677 (symbol 'file')
4683 (symbol 'file')
4678 (string '\n'))))
4684 (string '\n'))))
4679 A a
4685 A a
4680
4686
4681 A unary function alias can be called as a filter:
4687 A unary function alias can be called as a filter:
4682
4688
4683 $ hg debugtemplate -vr0 '{date|utcdate|isodate}\n'
4689 $ hg debugtemplate -vr0 '{date|utcdate|isodate}\n'
4684 (template
4690 (template
4685 (|
4691 (|
4686 (|
4692 (|
4687 (symbol 'date')
4693 (symbol 'date')
4688 (symbol 'utcdate'))
4694 (symbol 'utcdate'))
4689 (symbol 'isodate'))
4695 (symbol 'isodate'))
4690 (string '\n'))
4696 (string '\n'))
4691 * expanded:
4697 * expanded:
4692 (template
4698 (template
4693 (|
4699 (|
4694 (func
4700 (func
4695 (symbol 'localdate')
4701 (symbol 'localdate')
4696 (list
4702 (list
4697 (symbol 'date')
4703 (symbol 'date')
4698 (string 'UTC')))
4704 (string 'UTC')))
4699 (symbol 'isodate'))
4705 (symbol 'isodate'))
4700 (string '\n'))
4706 (string '\n'))
4701 1970-01-12 13:46 +0000
4707 1970-01-12 13:46 +0000
4702
4708
4703 Aliases should be applied only to command arguments and templates in hgrc.
4709 Aliases should be applied only to command arguments and templates in hgrc.
4704 Otherwise, our stock styles and web templates could be corrupted:
4710 Otherwise, our stock styles and web templates could be corrupted:
4705
4711
4706 $ hg log -r0 -T '{rn} {utcdate(date)|isodate}\n'
4712 $ hg log -r0 -T '{rn} {utcdate(date)|isodate}\n'
4707 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4713 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4708
4714
4709 $ hg log -r0 --config ui.logtemplate='"{rn} {utcdate(date)|isodate}\n"'
4715 $ hg log -r0 --config ui.logtemplate='"{rn} {utcdate(date)|isodate}\n"'
4710 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4716 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4711
4717
4712 $ cat <<EOF > tmpl
4718 $ cat <<EOF > tmpl
4713 > changeset = 'nothing expanded:{rn}\n'
4719 > changeset = 'nothing expanded:{rn}\n'
4714 > EOF
4720 > EOF
4715 $ hg log -r0 --style ./tmpl
4721 $ hg log -r0 --style ./tmpl
4716 nothing expanded:
4722 nothing expanded:
4717
4723
4718 Aliases in formatter:
4724 Aliases in formatter:
4719
4725
4720 $ hg branches -T '{pad(branch, 7)} {rn}\n'
4726 $ hg branches -T '{pad(branch, 7)} {rn}\n'
4721 default 6:d41e714fe50d
4727 default 6:d41e714fe50d
4722 foo 4:bbe44766e73d
4728 foo 4:bbe44766e73d
4723
4729
4724 Aliases should honor HGPLAIN:
4730 Aliases should honor HGPLAIN:
4725
4731
4726 $ HGPLAIN= hg log -r0 -T 'nothing expanded:{rn}\n'
4732 $ HGPLAIN= hg log -r0 -T 'nothing expanded:{rn}\n'
4727 nothing expanded:
4733 nothing expanded:
4728 $ HGPLAINEXCEPT=templatealias hg log -r0 -T '{rn}\n'
4734 $ HGPLAINEXCEPT=templatealias hg log -r0 -T '{rn}\n'
4729 0:1e4e1b8f71e0
4735 0:1e4e1b8f71e0
4730
4736
4731 Unparsable alias:
4737 Unparsable alias:
4732
4738
4733 $ hg debugtemplate --config templatealias.bad='x(' -v '{bad}'
4739 $ hg debugtemplate --config templatealias.bad='x(' -v '{bad}'
4734 (template
4740 (template
4735 (symbol 'bad'))
4741 (symbol 'bad'))
4736 abort: bad definition of template alias "bad": at 2: not a prefix: end
4742 abort: bad definition of template alias "bad": at 2: not a prefix: end
4737 [255]
4743 [255]
4738 $ hg log --config templatealias.bad='x(' -T '{bad}'
4744 $ hg log --config templatealias.bad='x(' -T '{bad}'
4739 abort: bad definition of template alias "bad": at 2: not a prefix: end
4745 abort: bad definition of template alias "bad": at 2: not a prefix: end
4740 [255]
4746 [255]
4741
4747
4742 $ cd ..
4748 $ cd ..
4743
4749
4744 Set up repository for non-ascii encoding tests:
4750 Set up repository for non-ascii encoding tests:
4745
4751
4746 $ hg init nonascii
4752 $ hg init nonascii
4747 $ cd nonascii
4753 $ cd nonascii
4748 $ $PYTHON <<EOF
4754 $ $PYTHON <<EOF
4749 > open('latin1', 'wb').write(b'\xe9')
4755 > open('latin1', 'wb').write(b'\xe9')
4750 > open('utf-8', 'wb').write(b'\xc3\xa9')
4756 > open('utf-8', 'wb').write(b'\xc3\xa9')
4751 > EOF
4757 > EOF
4752 $ HGENCODING=utf-8 hg branch -q `cat utf-8`
4758 $ HGENCODING=utf-8 hg branch -q `cat utf-8`
4753 $ HGENCODING=utf-8 hg ci -qAm "non-ascii branch: `cat utf-8`" utf-8
4759 $ HGENCODING=utf-8 hg ci -qAm "non-ascii branch: `cat utf-8`" utf-8
4754
4760
4755 json filter should try round-trip conversion to utf-8:
4761 json filter should try round-trip conversion to utf-8:
4756
4762
4757 $ HGENCODING=ascii hg log -T "{branch|json}\n" -r0
4763 $ HGENCODING=ascii hg log -T "{branch|json}\n" -r0
4758 "\u00e9"
4764 "\u00e9"
4759 $ HGENCODING=ascii hg log -T "{desc|json}\n" -r0
4765 $ HGENCODING=ascii hg log -T "{desc|json}\n" -r0
4760 "non-ascii branch: \u00e9"
4766 "non-ascii branch: \u00e9"
4761
4767
4762 json filter should take input as utf-8 if it was converted from utf-8:
4768 json filter should take input as utf-8 if it was converted from utf-8:
4763
4769
4764 $ HGENCODING=latin-1 hg log -T "{branch|json}\n" -r0
4770 $ HGENCODING=latin-1 hg log -T "{branch|json}\n" -r0
4765 "\u00e9"
4771 "\u00e9"
4766 $ HGENCODING=latin-1 hg log -T "{desc|json}\n" -r0
4772 $ HGENCODING=latin-1 hg log -T "{desc|json}\n" -r0
4767 "non-ascii branch: \u00e9"
4773 "non-ascii branch: \u00e9"
4768
4774
4769 json filter takes input as utf-8b:
4775 json filter takes input as utf-8b:
4770
4776
4771 $ HGENCODING=ascii hg log -T "{'`cat utf-8`'|json}\n" -l1
4777 $ HGENCODING=ascii hg log -T "{'`cat utf-8`'|json}\n" -l1
4772 "\u00e9"
4778 "\u00e9"
4773 $ HGENCODING=ascii hg log -T "{'`cat latin1`'|json}\n" -l1
4779 $ HGENCODING=ascii hg log -T "{'`cat latin1`'|json}\n" -l1
4774 "\udce9"
4780 "\udce9"
4775
4781
4776 utf8 filter:
4782 utf8 filter:
4777
4783
4778 $ HGENCODING=ascii hg log -T "round-trip: {branch|utf8|hex}\n" -r0
4784 $ HGENCODING=ascii hg log -T "round-trip: {branch|utf8|hex}\n" -r0
4779 round-trip: c3a9
4785 round-trip: c3a9
4780 $ HGENCODING=latin1 hg log -T "decoded: {'`cat latin1`'|utf8|hex}\n" -l1
4786 $ HGENCODING=latin1 hg log -T "decoded: {'`cat latin1`'|utf8|hex}\n" -l1
4781 decoded: c3a9
4787 decoded: c3a9
4782 $ HGENCODING=ascii hg log -T "replaced: {'`cat latin1`'|utf8|hex}\n" -l1
4788 $ HGENCODING=ascii hg log -T "replaced: {'`cat latin1`'|utf8|hex}\n" -l1
4783 abort: decoding near * (glob)
4789 abort: decoding near * (glob)
4784 [255]
4790 [255]
4785 $ hg log -T "coerced to string: {rev|utf8}\n" -r0
4791 $ hg log -T "coerced to string: {rev|utf8}\n" -r0
4786 coerced to string: 0
4792 coerced to string: 0
4787
4793
4788 pad width:
4794 pad width:
4789
4795
4790 $ HGENCODING=utf-8 hg debugtemplate "{pad('`cat utf-8`', 2, '-')}\n"
4796 $ HGENCODING=utf-8 hg debugtemplate "{pad('`cat utf-8`', 2, '-')}\n"
4791 \xc3\xa9- (esc)
4797 \xc3\xa9- (esc)
4792
4798
4793 $ cd ..
4799 $ cd ..
4794
4800
4795 Test that template function in extension is registered as expected
4801 Test that template function in extension is registered as expected
4796
4802
4797 $ cd a
4803 $ cd a
4798
4804
4799 $ cat <<EOF > $TESTTMP/customfunc.py
4805 $ cat <<EOF > $TESTTMP/customfunc.py
4800 > from mercurial import registrar
4806 > from mercurial import registrar
4801 >
4807 >
4802 > templatefunc = registrar.templatefunc()
4808 > templatefunc = registrar.templatefunc()
4803 >
4809 >
4804 > @templatefunc(b'custom()')
4810 > @templatefunc(b'custom()')
4805 > def custom(context, mapping, args):
4811 > def custom(context, mapping, args):
4806 > return b'custom'
4812 > return b'custom'
4807 > EOF
4813 > EOF
4808 $ cat <<EOF > .hg/hgrc
4814 $ cat <<EOF > .hg/hgrc
4809 > [extensions]
4815 > [extensions]
4810 > customfunc = $TESTTMP/customfunc.py
4816 > customfunc = $TESTTMP/customfunc.py
4811 > EOF
4817 > EOF
4812
4818
4813 $ hg log -r . -T "{custom()}\n" --config customfunc.enabled=true
4819 $ hg log -r . -T "{custom()}\n" --config customfunc.enabled=true
4814 custom
4820 custom
4815
4821
4816 $ cd ..
4822 $ cd ..
4817
4823
4818 Test 'graphwidth' in 'hg log' on various topologies. The key here is that the
4824 Test 'graphwidth' in 'hg log' on various topologies. The key here is that the
4819 printed graphwidths 3, 5, 7, etc. should all line up in their respective
4825 printed graphwidths 3, 5, 7, etc. should all line up in their respective
4820 columns. We don't care about other aspects of the graph rendering here.
4826 columns. We don't care about other aspects of the graph rendering here.
4821
4827
4822 $ hg init graphwidth
4828 $ hg init graphwidth
4823 $ cd graphwidth
4829 $ cd graphwidth
4824
4830
4825 $ wrappabletext="a a a a a a a a a a a a"
4831 $ wrappabletext="a a a a a a a a a a a a"
4826
4832
4827 $ printf "first\n" > file
4833 $ printf "first\n" > file
4828 $ hg add file
4834 $ hg add file
4829 $ hg commit -m "$wrappabletext"
4835 $ hg commit -m "$wrappabletext"
4830
4836
4831 $ printf "first\nsecond\n" > file
4837 $ printf "first\nsecond\n" > file
4832 $ hg commit -m "$wrappabletext"
4838 $ hg commit -m "$wrappabletext"
4833
4839
4834 $ hg checkout 0
4840 $ hg checkout 0
4835 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4841 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4836 $ printf "third\nfirst\n" > file
4842 $ printf "third\nfirst\n" > file
4837 $ hg commit -m "$wrappabletext"
4843 $ hg commit -m "$wrappabletext"
4838 created new head
4844 created new head
4839
4845
4840 $ hg merge
4846 $ hg merge
4841 merging file
4847 merging file
4842 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
4848 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
4843 (branch merge, don't forget to commit)
4849 (branch merge, don't forget to commit)
4844
4850
4845 $ hg log --graph -T "{graphwidth}"
4851 $ hg log --graph -T "{graphwidth}"
4846 @ 3
4852 @ 3
4847 |
4853 |
4848 | @ 5
4854 | @ 5
4849 |/
4855 |/
4850 o 3
4856 o 3
4851
4857
4852 $ hg commit -m "$wrappabletext"
4858 $ hg commit -m "$wrappabletext"
4853
4859
4854 $ hg log --graph -T "{graphwidth}"
4860 $ hg log --graph -T "{graphwidth}"
4855 @ 5
4861 @ 5
4856 |\
4862 |\
4857 | o 5
4863 | o 5
4858 | |
4864 | |
4859 o | 5
4865 o | 5
4860 |/
4866 |/
4861 o 3
4867 o 3
4862
4868
4863
4869
4864 $ hg checkout 0
4870 $ hg checkout 0
4865 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4871 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4866 $ printf "third\nfirst\nsecond\n" > file
4872 $ printf "third\nfirst\nsecond\n" > file
4867 $ hg commit -m "$wrappabletext"
4873 $ hg commit -m "$wrappabletext"
4868 created new head
4874 created new head
4869
4875
4870 $ hg log --graph -T "{graphwidth}"
4876 $ hg log --graph -T "{graphwidth}"
4871 @ 3
4877 @ 3
4872 |
4878 |
4873 | o 7
4879 | o 7
4874 | |\
4880 | |\
4875 +---o 7
4881 +---o 7
4876 | |
4882 | |
4877 | o 5
4883 | o 5
4878 |/
4884 |/
4879 o 3
4885 o 3
4880
4886
4881
4887
4882 $ hg log --graph -T "{graphwidth}" -r 3
4888 $ hg log --graph -T "{graphwidth}" -r 3
4883 o 5
4889 o 5
4884 |\
4890 |\
4885 ~ ~
4891 ~ ~
4886
4892
4887 $ hg log --graph -T "{graphwidth}" -r 1
4893 $ hg log --graph -T "{graphwidth}" -r 1
4888 o 3
4894 o 3
4889 |
4895 |
4890 ~
4896 ~
4891
4897
4892 $ hg merge
4898 $ hg merge
4893 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4899 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4894 (branch merge, don't forget to commit)
4900 (branch merge, don't forget to commit)
4895 $ hg commit -m "$wrappabletext"
4901 $ hg commit -m "$wrappabletext"
4896
4902
4897 $ printf "seventh\n" >> file
4903 $ printf "seventh\n" >> file
4898 $ hg commit -m "$wrappabletext"
4904 $ hg commit -m "$wrappabletext"
4899
4905
4900 $ hg log --graph -T "{graphwidth}"
4906 $ hg log --graph -T "{graphwidth}"
4901 @ 3
4907 @ 3
4902 |
4908 |
4903 o 5
4909 o 5
4904 |\
4910 |\
4905 | o 5
4911 | o 5
4906 | |
4912 | |
4907 o | 7
4913 o | 7
4908 |\ \
4914 |\ \
4909 | o | 7
4915 | o | 7
4910 | |/
4916 | |/
4911 o / 5
4917 o / 5
4912 |/
4918 |/
4913 o 3
4919 o 3
4914
4920
4915
4921
4916 The point of graphwidth is to allow wrapping that accounts for the space taken
4922 The point of graphwidth is to allow wrapping that accounts for the space taken
4917 by the graph.
4923 by the graph.
4918
4924
4919 $ COLUMNS=10 hg log --graph -T "{fill(desc, termwidth - graphwidth)}"
4925 $ COLUMNS=10 hg log --graph -T "{fill(desc, termwidth - graphwidth)}"
4920 @ a a a a
4926 @ a a a a
4921 | a a a a
4927 | a a a a
4922 | a a a a
4928 | a a a a
4923 o a a a
4929 o a a a
4924 |\ a a a
4930 |\ a a a
4925 | | a a a
4931 | | a a a
4926 | | a a a
4932 | | a a a
4927 | o a a a
4933 | o a a a
4928 | | a a a
4934 | | a a a
4929 | | a a a
4935 | | a a a
4930 | | a a a
4936 | | a a a
4931 o | a a
4937 o | a a
4932 |\ \ a a
4938 |\ \ a a
4933 | | | a a
4939 | | | a a
4934 | | | a a
4940 | | | a a
4935 | | | a a
4941 | | | a a
4936 | | | a a
4942 | | | a a
4937 | o | a a
4943 | o | a a
4938 | |/ a a
4944 | |/ a a
4939 | | a a
4945 | | a a
4940 | | a a
4946 | | a a
4941 | | a a
4947 | | a a
4942 | | a a
4948 | | a a
4943 o | a a a
4949 o | a a a
4944 |/ a a a
4950 |/ a a a
4945 | a a a
4951 | a a a
4946 | a a a
4952 | a a a
4947 o a a a a
4953 o a a a a
4948 a a a a
4954 a a a a
4949 a a a a
4955 a a a a
4950
4956
4951 Something tricky happens when there are elided nodes; the next drawn row of
4957 Something tricky happens when there are elided nodes; the next drawn row of
4952 edges can be more than one column wider, but the graph width only increases by
4958 edges can be more than one column wider, but the graph width only increases by
4953 one column. The remaining columns are added in between the nodes.
4959 one column. The remaining columns are added in between the nodes.
4954
4960
4955 $ hg log --graph -T "{graphwidth}" -r "0|2|4|5"
4961 $ hg log --graph -T "{graphwidth}" -r "0|2|4|5"
4956 o 5
4962 o 5
4957 |\
4963 |\
4958 | \
4964 | \
4959 | :\
4965 | :\
4960 o : : 7
4966 o : : 7
4961 :/ /
4967 :/ /
4962 : o 5
4968 : o 5
4963 :/
4969 :/
4964 o 3
4970 o 3
4965
4971
4966
4972
4967 $ cd ..
4973 $ cd ..
4968
4974
General Comments 0
You need to be logged in to leave comments. Login now