##// END OF EJS Templates
revset: make follow() accept multiple startrevs...
Yuya Nishihara -
r35299:921680c3 default
parent child Browse files
Show More
@@ -1,2221 +1,2221
1 # revset.py - revision set queries for mercurial
1 # revset.py - revision set queries for mercurial
2 #
2 #
3 # Copyright 2010 Matt Mackall <mpm@selenic.com>
3 # Copyright 2010 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 re
10 import re
11
11
12 from .i18n import _
12 from .i18n import _
13 from . import (
13 from . import (
14 dagop,
14 dagop,
15 destutil,
15 destutil,
16 encoding,
16 encoding,
17 error,
17 error,
18 hbisect,
18 hbisect,
19 match as matchmod,
19 match as matchmod,
20 node,
20 node,
21 obsolete as obsmod,
21 obsolete as obsmod,
22 obsutil,
22 obsutil,
23 pathutil,
23 pathutil,
24 phases,
24 phases,
25 registrar,
25 registrar,
26 repoview,
26 repoview,
27 revsetlang,
27 revsetlang,
28 scmutil,
28 scmutil,
29 smartset,
29 smartset,
30 util,
30 util,
31 )
31 )
32
32
33 # helpers for processing parsed tree
33 # helpers for processing parsed tree
34 getsymbol = revsetlang.getsymbol
34 getsymbol = revsetlang.getsymbol
35 getstring = revsetlang.getstring
35 getstring = revsetlang.getstring
36 getinteger = revsetlang.getinteger
36 getinteger = revsetlang.getinteger
37 getboolean = revsetlang.getboolean
37 getboolean = revsetlang.getboolean
38 getlist = revsetlang.getlist
38 getlist = revsetlang.getlist
39 getrange = revsetlang.getrange
39 getrange = revsetlang.getrange
40 getargs = revsetlang.getargs
40 getargs = revsetlang.getargs
41 getargsdict = revsetlang.getargsdict
41 getargsdict = revsetlang.getargsdict
42
42
43 baseset = smartset.baseset
43 baseset = smartset.baseset
44 generatorset = smartset.generatorset
44 generatorset = smartset.generatorset
45 spanset = smartset.spanset
45 spanset = smartset.spanset
46 fullreposet = smartset.fullreposet
46 fullreposet = smartset.fullreposet
47
47
48 # Constants for ordering requirement, used in getset():
48 # Constants for ordering requirement, used in getset():
49 #
49 #
50 # If 'define', any nested functions and operations MAY change the ordering of
50 # If 'define', any nested functions and operations MAY change the ordering of
51 # the entries in the set (but if changes the ordering, it MUST ALWAYS change
51 # the entries in the set (but if changes the ordering, it MUST ALWAYS change
52 # it). If 'follow', any nested functions and operations MUST take the ordering
52 # it). If 'follow', any nested functions and operations MUST take the ordering
53 # specified by the first operand to the '&' operator.
53 # specified by the first operand to the '&' operator.
54 #
54 #
55 # For instance,
55 # For instance,
56 #
56 #
57 # X & (Y | Z)
57 # X & (Y | Z)
58 # ^ ^^^^^^^
58 # ^ ^^^^^^^
59 # | follow
59 # | follow
60 # define
60 # define
61 #
61 #
62 # will be evaluated as 'or(y(x()), z(x()))', where 'x()' can change the order
62 # will be evaluated as 'or(y(x()), z(x()))', where 'x()' can change the order
63 # of the entries in the set, but 'y()', 'z()' and 'or()' shouldn't.
63 # of the entries in the set, but 'y()', 'z()' and 'or()' shouldn't.
64 #
64 #
65 # 'any' means the order doesn't matter. For instance,
65 # 'any' means the order doesn't matter. For instance,
66 #
66 #
67 # (X & !Y) | ancestors(Z)
67 # (X & !Y) | ancestors(Z)
68 # ^ ^
68 # ^ ^
69 # any any
69 # any any
70 #
70 #
71 # For 'X & !Y', 'X' decides the order and 'Y' is subtracted from 'X', so the
71 # For 'X & !Y', 'X' decides the order and 'Y' is subtracted from 'X', so the
72 # order of 'Y' does not matter. For 'ancestors(Z)', Z's order does not matter
72 # order of 'Y' does not matter. For 'ancestors(Z)', Z's order does not matter
73 # since 'ancestors' does not care about the order of its argument.
73 # since 'ancestors' does not care about the order of its argument.
74 #
74 #
75 # Currently, most revsets do not care about the order, so 'define' is
75 # Currently, most revsets do not care about the order, so 'define' is
76 # equivalent to 'follow' for them, and the resulting order is based on the
76 # equivalent to 'follow' for them, and the resulting order is based on the
77 # 'subset' parameter passed down to them:
77 # 'subset' parameter passed down to them:
78 #
78 #
79 # m = revset.match(...)
79 # m = revset.match(...)
80 # m(repo, subset, order=defineorder)
80 # m(repo, subset, order=defineorder)
81 # ^^^^^^
81 # ^^^^^^
82 # For most revsets, 'define' means using the order this subset provides
82 # For most revsets, 'define' means using the order this subset provides
83 #
83 #
84 # There are a few revsets that always redefine the order if 'define' is
84 # There are a few revsets that always redefine the order if 'define' is
85 # specified: 'sort(X)', 'reverse(X)', 'x:y'.
85 # specified: 'sort(X)', 'reverse(X)', 'x:y'.
86 anyorder = 'any' # don't care the order, could be even random-shuffled
86 anyorder = 'any' # don't care the order, could be even random-shuffled
87 defineorder = 'define' # ALWAYS redefine, or ALWAYS follow the current order
87 defineorder = 'define' # ALWAYS redefine, or ALWAYS follow the current order
88 followorder = 'follow' # MUST follow the current order
88 followorder = 'follow' # MUST follow the current order
89
89
90 # helpers
90 # helpers
91
91
92 def getset(repo, subset, x, order=defineorder):
92 def getset(repo, subset, x, order=defineorder):
93 if not x:
93 if not x:
94 raise error.ParseError(_("missing argument"))
94 raise error.ParseError(_("missing argument"))
95 return methods[x[0]](repo, subset, *x[1:], order=order)
95 return methods[x[0]](repo, subset, *x[1:], order=order)
96
96
97 def _getrevsource(repo, r):
97 def _getrevsource(repo, r):
98 extra = repo[r].extra()
98 extra = repo[r].extra()
99 for label in ('source', 'transplant_source', 'rebase_source'):
99 for label in ('source', 'transplant_source', 'rebase_source'):
100 if label in extra:
100 if label in extra:
101 try:
101 try:
102 return repo[extra[label]].rev()
102 return repo[extra[label]].rev()
103 except error.RepoLookupError:
103 except error.RepoLookupError:
104 pass
104 pass
105 return None
105 return None
106
106
107 # operator methods
107 # operator methods
108
108
109 def stringset(repo, subset, x, order):
109 def stringset(repo, subset, x, order):
110 x = scmutil.intrev(repo[x])
110 x = scmutil.intrev(repo[x])
111 if (x in subset
111 if (x in subset
112 or x == node.nullrev and isinstance(subset, fullreposet)):
112 or x == node.nullrev and isinstance(subset, fullreposet)):
113 return baseset([x])
113 return baseset([x])
114 return baseset()
114 return baseset()
115
115
116 def rangeset(repo, subset, x, y, order):
116 def rangeset(repo, subset, x, y, order):
117 m = getset(repo, fullreposet(repo), x)
117 m = getset(repo, fullreposet(repo), x)
118 n = getset(repo, fullreposet(repo), y)
118 n = getset(repo, fullreposet(repo), y)
119
119
120 if not m or not n:
120 if not m or not n:
121 return baseset()
121 return baseset()
122 return _makerangeset(repo, subset, m.first(), n.last(), order)
122 return _makerangeset(repo, subset, m.first(), n.last(), order)
123
123
124 def rangeall(repo, subset, x, order):
124 def rangeall(repo, subset, x, order):
125 assert x is None
125 assert x is None
126 return _makerangeset(repo, subset, 0, len(repo) - 1, order)
126 return _makerangeset(repo, subset, 0, len(repo) - 1, order)
127
127
128 def rangepre(repo, subset, y, order):
128 def rangepre(repo, subset, y, order):
129 # ':y' can't be rewritten to '0:y' since '0' may be hidden
129 # ':y' can't be rewritten to '0:y' since '0' may be hidden
130 n = getset(repo, fullreposet(repo), y)
130 n = getset(repo, fullreposet(repo), y)
131 if not n:
131 if not n:
132 return baseset()
132 return baseset()
133 return _makerangeset(repo, subset, 0, n.last(), order)
133 return _makerangeset(repo, subset, 0, n.last(), order)
134
134
135 def rangepost(repo, subset, x, order):
135 def rangepost(repo, subset, x, order):
136 m = getset(repo, fullreposet(repo), x)
136 m = getset(repo, fullreposet(repo), x)
137 if not m:
137 if not m:
138 return baseset()
138 return baseset()
139 return _makerangeset(repo, subset, m.first(), len(repo) - 1, order)
139 return _makerangeset(repo, subset, m.first(), len(repo) - 1, order)
140
140
141 def _makerangeset(repo, subset, m, n, order):
141 def _makerangeset(repo, subset, m, n, order):
142 if m == n:
142 if m == n:
143 r = baseset([m])
143 r = baseset([m])
144 elif n == node.wdirrev:
144 elif n == node.wdirrev:
145 r = spanset(repo, m, len(repo)) + baseset([n])
145 r = spanset(repo, m, len(repo)) + baseset([n])
146 elif m == node.wdirrev:
146 elif m == node.wdirrev:
147 r = baseset([m]) + spanset(repo, len(repo) - 1, n - 1)
147 r = baseset([m]) + spanset(repo, len(repo) - 1, n - 1)
148 elif m < n:
148 elif m < n:
149 r = spanset(repo, m, n + 1)
149 r = spanset(repo, m, n + 1)
150 else:
150 else:
151 r = spanset(repo, m, n - 1)
151 r = spanset(repo, m, n - 1)
152
152
153 if order == defineorder:
153 if order == defineorder:
154 return r & subset
154 return r & subset
155 else:
155 else:
156 # carrying the sorting over when possible would be more efficient
156 # carrying the sorting over when possible would be more efficient
157 return subset & r
157 return subset & r
158
158
159 def dagrange(repo, subset, x, y, order):
159 def dagrange(repo, subset, x, y, order):
160 r = fullreposet(repo)
160 r = fullreposet(repo)
161 xs = dagop.reachableroots(repo, getset(repo, r, x), getset(repo, r, y),
161 xs = dagop.reachableroots(repo, getset(repo, r, x), getset(repo, r, y),
162 includepath=True)
162 includepath=True)
163 return subset & xs
163 return subset & xs
164
164
165 def andset(repo, subset, x, y, order):
165 def andset(repo, subset, x, y, order):
166 if order == anyorder:
166 if order == anyorder:
167 yorder = anyorder
167 yorder = anyorder
168 else:
168 else:
169 yorder = followorder
169 yorder = followorder
170 return getset(repo, getset(repo, subset, x, order), y, yorder)
170 return getset(repo, getset(repo, subset, x, order), y, yorder)
171
171
172 def andsmallyset(repo, subset, x, y, order):
172 def andsmallyset(repo, subset, x, y, order):
173 # 'andsmally(x, y)' is equivalent to 'and(x, y)', but faster when y is small
173 # 'andsmally(x, y)' is equivalent to 'and(x, y)', but faster when y is small
174 if order == anyorder:
174 if order == anyorder:
175 yorder = anyorder
175 yorder = anyorder
176 else:
176 else:
177 yorder = followorder
177 yorder = followorder
178 return getset(repo, getset(repo, subset, y, yorder), x, order)
178 return getset(repo, getset(repo, subset, y, yorder), x, order)
179
179
180 def differenceset(repo, subset, x, y, order):
180 def differenceset(repo, subset, x, y, order):
181 return getset(repo, subset, x, order) - getset(repo, subset, y, anyorder)
181 return getset(repo, subset, x, order) - getset(repo, subset, y, anyorder)
182
182
183 def _orsetlist(repo, subset, xs, order):
183 def _orsetlist(repo, subset, xs, order):
184 assert xs
184 assert xs
185 if len(xs) == 1:
185 if len(xs) == 1:
186 return getset(repo, subset, xs[0], order)
186 return getset(repo, subset, xs[0], order)
187 p = len(xs) // 2
187 p = len(xs) // 2
188 a = _orsetlist(repo, subset, xs[:p], order)
188 a = _orsetlist(repo, subset, xs[:p], order)
189 b = _orsetlist(repo, subset, xs[p:], order)
189 b = _orsetlist(repo, subset, xs[p:], order)
190 return a + b
190 return a + b
191
191
192 def orset(repo, subset, x, order):
192 def orset(repo, subset, x, order):
193 xs = getlist(x)
193 xs = getlist(x)
194 if order == followorder:
194 if order == followorder:
195 # slow path to take the subset order
195 # slow path to take the subset order
196 return subset & _orsetlist(repo, fullreposet(repo), xs, anyorder)
196 return subset & _orsetlist(repo, fullreposet(repo), xs, anyorder)
197 else:
197 else:
198 return _orsetlist(repo, subset, xs, order)
198 return _orsetlist(repo, subset, xs, order)
199
199
200 def notset(repo, subset, x, order):
200 def notset(repo, subset, x, order):
201 return subset - getset(repo, subset, x, anyorder)
201 return subset - getset(repo, subset, x, anyorder)
202
202
203 def relationset(repo, subset, x, y, order):
203 def relationset(repo, subset, x, y, order):
204 raise error.ParseError(_("can't use a relation in this context"))
204 raise error.ParseError(_("can't use a relation in this context"))
205
205
206 def relsubscriptset(repo, subset, x, y, z, order):
206 def relsubscriptset(repo, subset, x, y, z, order):
207 # this is pretty basic implementation of 'x#y[z]' operator, still
207 # this is pretty basic implementation of 'x#y[z]' operator, still
208 # experimental so undocumented. see the wiki for further ideas.
208 # experimental so undocumented. see the wiki for further ideas.
209 # https://www.mercurial-scm.org/wiki/RevsetOperatorPlan
209 # https://www.mercurial-scm.org/wiki/RevsetOperatorPlan
210 rel = getsymbol(y)
210 rel = getsymbol(y)
211 n = getinteger(z, _("relation subscript must be an integer"))
211 n = getinteger(z, _("relation subscript must be an integer"))
212
212
213 # TODO: perhaps this should be a table of relation functions
213 # TODO: perhaps this should be a table of relation functions
214 if rel in ('g', 'generations'):
214 if rel in ('g', 'generations'):
215 # TODO: support range, rewrite tests, and drop startdepth argument
215 # TODO: support range, rewrite tests, and drop startdepth argument
216 # from ancestors() and descendants() predicates
216 # from ancestors() and descendants() predicates
217 if n <= 0:
217 if n <= 0:
218 n = -n
218 n = -n
219 return _ancestors(repo, subset, x, startdepth=n, stopdepth=n + 1)
219 return _ancestors(repo, subset, x, startdepth=n, stopdepth=n + 1)
220 else:
220 else:
221 return _descendants(repo, subset, x, startdepth=n, stopdepth=n + 1)
221 return _descendants(repo, subset, x, startdepth=n, stopdepth=n + 1)
222
222
223 raise error.UnknownIdentifier(rel, ['generations'])
223 raise error.UnknownIdentifier(rel, ['generations'])
224
224
225 def subscriptset(repo, subset, x, y, order):
225 def subscriptset(repo, subset, x, y, order):
226 raise error.ParseError(_("can't use a subscript in this context"))
226 raise error.ParseError(_("can't use a subscript in this context"))
227
227
228 def listset(repo, subset, *xs, **opts):
228 def listset(repo, subset, *xs, **opts):
229 raise error.ParseError(_("can't use a list in this context"),
229 raise error.ParseError(_("can't use a list in this context"),
230 hint=_('see hg help "revsets.x or y"'))
230 hint=_('see hg help "revsets.x or y"'))
231
231
232 def keyvaluepair(repo, subset, k, v, order):
232 def keyvaluepair(repo, subset, k, v, order):
233 raise error.ParseError(_("can't use a key-value pair in this context"))
233 raise error.ParseError(_("can't use a key-value pair in this context"))
234
234
235 def func(repo, subset, a, b, order):
235 def func(repo, subset, a, b, order):
236 f = getsymbol(a)
236 f = getsymbol(a)
237 if f in symbols:
237 if f in symbols:
238 func = symbols[f]
238 func = symbols[f]
239 if getattr(func, '_takeorder', False):
239 if getattr(func, '_takeorder', False):
240 return func(repo, subset, b, order)
240 return func(repo, subset, b, order)
241 return func(repo, subset, b)
241 return func(repo, subset, b)
242
242
243 keep = lambda fn: getattr(fn, '__doc__', None) is not None
243 keep = lambda fn: getattr(fn, '__doc__', None) is not None
244
244
245 syms = [s for (s, fn) in symbols.items() if keep(fn)]
245 syms = [s for (s, fn) in symbols.items() if keep(fn)]
246 raise error.UnknownIdentifier(f, syms)
246 raise error.UnknownIdentifier(f, syms)
247
247
248 # functions
248 # functions
249
249
250 # symbols are callables like:
250 # symbols are callables like:
251 # fn(repo, subset, x)
251 # fn(repo, subset, x)
252 # with:
252 # with:
253 # repo - current repository instance
253 # repo - current repository instance
254 # subset - of revisions to be examined
254 # subset - of revisions to be examined
255 # x - argument in tree form
255 # x - argument in tree form
256 symbols = revsetlang.symbols
256 symbols = revsetlang.symbols
257
257
258 # symbols which can't be used for a DoS attack for any given input
258 # symbols which can't be used for a DoS attack for any given input
259 # (e.g. those which accept regexes as plain strings shouldn't be included)
259 # (e.g. those which accept regexes as plain strings shouldn't be included)
260 # functions that just return a lot of changesets (like all) don't count here
260 # functions that just return a lot of changesets (like all) don't count here
261 safesymbols = set()
261 safesymbols = set()
262
262
263 predicate = registrar.revsetpredicate()
263 predicate = registrar.revsetpredicate()
264
264
265 @predicate('_destupdate')
265 @predicate('_destupdate')
266 def _destupdate(repo, subset, x):
266 def _destupdate(repo, subset, x):
267 # experimental revset for update destination
267 # experimental revset for update destination
268 args = getargsdict(x, 'limit', 'clean')
268 args = getargsdict(x, 'limit', 'clean')
269 return subset & baseset([destutil.destupdate(repo, **args)[0]])
269 return subset & baseset([destutil.destupdate(repo, **args)[0]])
270
270
271 @predicate('_destmerge')
271 @predicate('_destmerge')
272 def _destmerge(repo, subset, x):
272 def _destmerge(repo, subset, x):
273 # experimental revset for merge destination
273 # experimental revset for merge destination
274 sourceset = None
274 sourceset = None
275 if x is not None:
275 if x is not None:
276 sourceset = getset(repo, fullreposet(repo), x)
276 sourceset = getset(repo, fullreposet(repo), x)
277 return subset & baseset([destutil.destmerge(repo, sourceset=sourceset)])
277 return subset & baseset([destutil.destmerge(repo, sourceset=sourceset)])
278
278
279 @predicate('adds(pattern)', safe=True, weight=30)
279 @predicate('adds(pattern)', safe=True, weight=30)
280 def adds(repo, subset, x):
280 def adds(repo, subset, x):
281 """Changesets that add a file matching pattern.
281 """Changesets that add a file matching pattern.
282
282
283 The pattern without explicit kind like ``glob:`` is expected to be
283 The pattern without explicit kind like ``glob:`` is expected to be
284 relative to the current directory and match against a file or a
284 relative to the current directory and match against a file or a
285 directory.
285 directory.
286 """
286 """
287 # i18n: "adds" is a keyword
287 # i18n: "adds" is a keyword
288 pat = getstring(x, _("adds requires a pattern"))
288 pat = getstring(x, _("adds requires a pattern"))
289 return checkstatus(repo, subset, pat, 1)
289 return checkstatus(repo, subset, pat, 1)
290
290
291 @predicate('ancestor(*changeset)', safe=True, weight=0.5)
291 @predicate('ancestor(*changeset)', safe=True, weight=0.5)
292 def ancestor(repo, subset, x):
292 def ancestor(repo, subset, x):
293 """A greatest common ancestor of the changesets.
293 """A greatest common ancestor of the changesets.
294
294
295 Accepts 0 or more changesets.
295 Accepts 0 or more changesets.
296 Will return empty list when passed no args.
296 Will return empty list when passed no args.
297 Greatest common ancestor of a single changeset is that changeset.
297 Greatest common ancestor of a single changeset is that changeset.
298 """
298 """
299 # i18n: "ancestor" is a keyword
299 # i18n: "ancestor" is a keyword
300 l = getlist(x)
300 l = getlist(x)
301 rl = fullreposet(repo)
301 rl = fullreposet(repo)
302 anc = None
302 anc = None
303
303
304 # (getset(repo, rl, i) for i in l) generates a list of lists
304 # (getset(repo, rl, i) for i in l) generates a list of lists
305 for revs in (getset(repo, rl, i) for i in l):
305 for revs in (getset(repo, rl, i) for i in l):
306 for r in revs:
306 for r in revs:
307 if anc is None:
307 if anc is None:
308 anc = repo[r]
308 anc = repo[r]
309 else:
309 else:
310 anc = anc.ancestor(repo[r])
310 anc = anc.ancestor(repo[r])
311
311
312 if anc is not None and anc.rev() in subset:
312 if anc is not None and anc.rev() in subset:
313 return baseset([anc.rev()])
313 return baseset([anc.rev()])
314 return baseset()
314 return baseset()
315
315
316 def _ancestors(repo, subset, x, followfirst=False, startdepth=None,
316 def _ancestors(repo, subset, x, followfirst=False, startdepth=None,
317 stopdepth=None):
317 stopdepth=None):
318 heads = getset(repo, fullreposet(repo), x)
318 heads = getset(repo, fullreposet(repo), x)
319 if not heads:
319 if not heads:
320 return baseset()
320 return baseset()
321 s = dagop.revancestors(repo, heads, followfirst, startdepth, stopdepth)
321 s = dagop.revancestors(repo, heads, followfirst, startdepth, stopdepth)
322 return subset & s
322 return subset & s
323
323
324 @predicate('ancestors(set[, depth])', safe=True)
324 @predicate('ancestors(set[, depth])', safe=True)
325 def ancestors(repo, subset, x):
325 def ancestors(repo, subset, x):
326 """Changesets that are ancestors of changesets in set, including the
326 """Changesets that are ancestors of changesets in set, including the
327 given changesets themselves.
327 given changesets themselves.
328
328
329 If depth is specified, the result only includes changesets up to
329 If depth is specified, the result only includes changesets up to
330 the specified generation.
330 the specified generation.
331 """
331 """
332 # startdepth is for internal use only until we can decide the UI
332 # startdepth is for internal use only until we can decide the UI
333 args = getargsdict(x, 'ancestors', 'set depth startdepth')
333 args = getargsdict(x, 'ancestors', 'set depth startdepth')
334 if 'set' not in args:
334 if 'set' not in args:
335 # i18n: "ancestors" is a keyword
335 # i18n: "ancestors" is a keyword
336 raise error.ParseError(_('ancestors takes at least 1 argument'))
336 raise error.ParseError(_('ancestors takes at least 1 argument'))
337 startdepth = stopdepth = None
337 startdepth = stopdepth = None
338 if 'startdepth' in args:
338 if 'startdepth' in args:
339 n = getinteger(args['startdepth'],
339 n = getinteger(args['startdepth'],
340 "ancestors expects an integer startdepth")
340 "ancestors expects an integer startdepth")
341 if n < 0:
341 if n < 0:
342 raise error.ParseError("negative startdepth")
342 raise error.ParseError("negative startdepth")
343 startdepth = n
343 startdepth = n
344 if 'depth' in args:
344 if 'depth' in args:
345 # i18n: "ancestors" is a keyword
345 # i18n: "ancestors" is a keyword
346 n = getinteger(args['depth'], _("ancestors expects an integer depth"))
346 n = getinteger(args['depth'], _("ancestors expects an integer depth"))
347 if n < 0:
347 if n < 0:
348 raise error.ParseError(_("negative depth"))
348 raise error.ParseError(_("negative depth"))
349 stopdepth = n + 1
349 stopdepth = n + 1
350 return _ancestors(repo, subset, args['set'],
350 return _ancestors(repo, subset, args['set'],
351 startdepth=startdepth, stopdepth=stopdepth)
351 startdepth=startdepth, stopdepth=stopdepth)
352
352
353 @predicate('_firstancestors', safe=True)
353 @predicate('_firstancestors', safe=True)
354 def _firstancestors(repo, subset, x):
354 def _firstancestors(repo, subset, x):
355 # ``_firstancestors(set)``
355 # ``_firstancestors(set)``
356 # Like ``ancestors(set)`` but follows only the first parents.
356 # Like ``ancestors(set)`` but follows only the first parents.
357 return _ancestors(repo, subset, x, followfirst=True)
357 return _ancestors(repo, subset, x, followfirst=True)
358
358
359 def _childrenspec(repo, subset, x, n, order):
359 def _childrenspec(repo, subset, x, n, order):
360 """Changesets that are the Nth child of a changeset
360 """Changesets that are the Nth child of a changeset
361 in set.
361 in set.
362 """
362 """
363 cs = set()
363 cs = set()
364 for r in getset(repo, fullreposet(repo), x):
364 for r in getset(repo, fullreposet(repo), x):
365 for i in range(n):
365 for i in range(n):
366 c = repo[r].children()
366 c = repo[r].children()
367 if len(c) == 0:
367 if len(c) == 0:
368 break
368 break
369 if len(c) > 1:
369 if len(c) > 1:
370 raise error.RepoLookupError(
370 raise error.RepoLookupError(
371 _("revision in set has more than one child"))
371 _("revision in set has more than one child"))
372 r = c[0].rev()
372 r = c[0].rev()
373 else:
373 else:
374 cs.add(r)
374 cs.add(r)
375 return subset & cs
375 return subset & cs
376
376
377 def ancestorspec(repo, subset, x, n, order):
377 def ancestorspec(repo, subset, x, n, order):
378 """``set~n``
378 """``set~n``
379 Changesets that are the Nth ancestor (first parents only) of a changeset
379 Changesets that are the Nth ancestor (first parents only) of a changeset
380 in set.
380 in set.
381 """
381 """
382 n = getinteger(n, _("~ expects a number"))
382 n = getinteger(n, _("~ expects a number"))
383 if n < 0:
383 if n < 0:
384 # children lookup
384 # children lookup
385 return _childrenspec(repo, subset, x, -n, order)
385 return _childrenspec(repo, subset, x, -n, order)
386 ps = set()
386 ps = set()
387 cl = repo.changelog
387 cl = repo.changelog
388 for r in getset(repo, fullreposet(repo), x):
388 for r in getset(repo, fullreposet(repo), x):
389 for i in range(n):
389 for i in range(n):
390 try:
390 try:
391 r = cl.parentrevs(r)[0]
391 r = cl.parentrevs(r)[0]
392 except error.WdirUnsupported:
392 except error.WdirUnsupported:
393 r = repo[r].parents()[0].rev()
393 r = repo[r].parents()[0].rev()
394 ps.add(r)
394 ps.add(r)
395 return subset & ps
395 return subset & ps
396
396
397 @predicate('author(string)', safe=True, weight=10)
397 @predicate('author(string)', safe=True, weight=10)
398 def author(repo, subset, x):
398 def author(repo, subset, x):
399 """Alias for ``user(string)``.
399 """Alias for ``user(string)``.
400 """
400 """
401 # i18n: "author" is a keyword
401 # i18n: "author" is a keyword
402 n = getstring(x, _("author requires a string"))
402 n = getstring(x, _("author requires a string"))
403 kind, pattern, matcher = _substringmatcher(n, casesensitive=False)
403 kind, pattern, matcher = _substringmatcher(n, casesensitive=False)
404 return subset.filter(lambda x: matcher(repo[x].user()),
404 return subset.filter(lambda x: matcher(repo[x].user()),
405 condrepr=('<user %r>', n))
405 condrepr=('<user %r>', n))
406
406
407 @predicate('bisect(string)', safe=True)
407 @predicate('bisect(string)', safe=True)
408 def bisect(repo, subset, x):
408 def bisect(repo, subset, x):
409 """Changesets marked in the specified bisect status:
409 """Changesets marked in the specified bisect status:
410
410
411 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
411 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
412 - ``goods``, ``bads`` : csets topologically good/bad
412 - ``goods``, ``bads`` : csets topologically good/bad
413 - ``range`` : csets taking part in the bisection
413 - ``range`` : csets taking part in the bisection
414 - ``pruned`` : csets that are goods, bads or skipped
414 - ``pruned`` : csets that are goods, bads or skipped
415 - ``untested`` : csets whose fate is yet unknown
415 - ``untested`` : csets whose fate is yet unknown
416 - ``ignored`` : csets ignored due to DAG topology
416 - ``ignored`` : csets ignored due to DAG topology
417 - ``current`` : the cset currently being bisected
417 - ``current`` : the cset currently being bisected
418 """
418 """
419 # i18n: "bisect" is a keyword
419 # i18n: "bisect" is a keyword
420 status = getstring(x, _("bisect requires a string")).lower()
420 status = getstring(x, _("bisect requires a string")).lower()
421 state = set(hbisect.get(repo, status))
421 state = set(hbisect.get(repo, status))
422 return subset & state
422 return subset & state
423
423
424 # Backward-compatibility
424 # Backward-compatibility
425 # - no help entry so that we do not advertise it any more
425 # - no help entry so that we do not advertise it any more
426 @predicate('bisected', safe=True)
426 @predicate('bisected', safe=True)
427 def bisected(repo, subset, x):
427 def bisected(repo, subset, x):
428 return bisect(repo, subset, x)
428 return bisect(repo, subset, x)
429
429
430 @predicate('bookmark([name])', safe=True)
430 @predicate('bookmark([name])', safe=True)
431 def bookmark(repo, subset, x):
431 def bookmark(repo, subset, x):
432 """The named bookmark or all bookmarks.
432 """The named bookmark or all bookmarks.
433
433
434 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`.
434 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`.
435 """
435 """
436 # i18n: "bookmark" is a keyword
436 # i18n: "bookmark" is a keyword
437 args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
437 args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
438 if args:
438 if args:
439 bm = getstring(args[0],
439 bm = getstring(args[0],
440 # i18n: "bookmark" is a keyword
440 # i18n: "bookmark" is a keyword
441 _('the argument to bookmark must be a string'))
441 _('the argument to bookmark must be a string'))
442 kind, pattern, matcher = util.stringmatcher(bm)
442 kind, pattern, matcher = util.stringmatcher(bm)
443 bms = set()
443 bms = set()
444 if kind == 'literal':
444 if kind == 'literal':
445 bmrev = repo._bookmarks.get(pattern, None)
445 bmrev = repo._bookmarks.get(pattern, None)
446 if not bmrev:
446 if not bmrev:
447 raise error.RepoLookupError(_("bookmark '%s' does not exist")
447 raise error.RepoLookupError(_("bookmark '%s' does not exist")
448 % pattern)
448 % pattern)
449 bms.add(repo[bmrev].rev())
449 bms.add(repo[bmrev].rev())
450 else:
450 else:
451 matchrevs = set()
451 matchrevs = set()
452 for name, bmrev in repo._bookmarks.iteritems():
452 for name, bmrev in repo._bookmarks.iteritems():
453 if matcher(name):
453 if matcher(name):
454 matchrevs.add(bmrev)
454 matchrevs.add(bmrev)
455 if not matchrevs:
455 if not matchrevs:
456 raise error.RepoLookupError(_("no bookmarks exist"
456 raise error.RepoLookupError(_("no bookmarks exist"
457 " that match '%s'") % pattern)
457 " that match '%s'") % pattern)
458 for bmrev in matchrevs:
458 for bmrev in matchrevs:
459 bms.add(repo[bmrev].rev())
459 bms.add(repo[bmrev].rev())
460 else:
460 else:
461 bms = {repo[r].rev() for r in repo._bookmarks.values()}
461 bms = {repo[r].rev() for r in repo._bookmarks.values()}
462 bms -= {node.nullrev}
462 bms -= {node.nullrev}
463 return subset & bms
463 return subset & bms
464
464
465 @predicate('branch(string or set)', safe=True, weight=10)
465 @predicate('branch(string or set)', safe=True, weight=10)
466 def branch(repo, subset, x):
466 def branch(repo, subset, x):
467 """
467 """
468 All changesets belonging to the given branch or the branches of the given
468 All changesets belonging to the given branch or the branches of the given
469 changesets.
469 changesets.
470
470
471 Pattern matching is supported for `string`. See
471 Pattern matching is supported for `string`. See
472 :hg:`help revisions.patterns`.
472 :hg:`help revisions.patterns`.
473 """
473 """
474 getbi = repo.revbranchcache().branchinfo
474 getbi = repo.revbranchcache().branchinfo
475 def getbranch(r):
475 def getbranch(r):
476 try:
476 try:
477 return getbi(r)[0]
477 return getbi(r)[0]
478 except error.WdirUnsupported:
478 except error.WdirUnsupported:
479 return repo[r].branch()
479 return repo[r].branch()
480
480
481 try:
481 try:
482 b = getstring(x, '')
482 b = getstring(x, '')
483 except error.ParseError:
483 except error.ParseError:
484 # not a string, but another revspec, e.g. tip()
484 # not a string, but another revspec, e.g. tip()
485 pass
485 pass
486 else:
486 else:
487 kind, pattern, matcher = util.stringmatcher(b)
487 kind, pattern, matcher = util.stringmatcher(b)
488 if kind == 'literal':
488 if kind == 'literal':
489 # note: falls through to the revspec case if no branch with
489 # note: falls through to the revspec case if no branch with
490 # this name exists and pattern kind is not specified explicitly
490 # this name exists and pattern kind is not specified explicitly
491 if pattern in repo.branchmap():
491 if pattern in repo.branchmap():
492 return subset.filter(lambda r: matcher(getbranch(r)),
492 return subset.filter(lambda r: matcher(getbranch(r)),
493 condrepr=('<branch %r>', b))
493 condrepr=('<branch %r>', b))
494 if b.startswith('literal:'):
494 if b.startswith('literal:'):
495 raise error.RepoLookupError(_("branch '%s' does not exist")
495 raise error.RepoLookupError(_("branch '%s' does not exist")
496 % pattern)
496 % pattern)
497 else:
497 else:
498 return subset.filter(lambda r: matcher(getbranch(r)),
498 return subset.filter(lambda r: matcher(getbranch(r)),
499 condrepr=('<branch %r>', b))
499 condrepr=('<branch %r>', b))
500
500
501 s = getset(repo, fullreposet(repo), x)
501 s = getset(repo, fullreposet(repo), x)
502 b = set()
502 b = set()
503 for r in s:
503 for r in s:
504 b.add(getbranch(r))
504 b.add(getbranch(r))
505 c = s.__contains__
505 c = s.__contains__
506 return subset.filter(lambda r: c(r) or getbranch(r) in b,
506 return subset.filter(lambda r: c(r) or getbranch(r) in b,
507 condrepr=lambda: '<branch %r>' % sorted(b))
507 condrepr=lambda: '<branch %r>' % sorted(b))
508
508
509 @predicate('bumped()', safe=True)
509 @predicate('bumped()', safe=True)
510 def bumped(repo, subset, x):
510 def bumped(repo, subset, x):
511 msg = ("'bumped()' is deprecated, "
511 msg = ("'bumped()' is deprecated, "
512 "use 'phasedivergent()'")
512 "use 'phasedivergent()'")
513 repo.ui.deprecwarn(msg, '4.4')
513 repo.ui.deprecwarn(msg, '4.4')
514
514
515 return phasedivergent(repo, subset, x)
515 return phasedivergent(repo, subset, x)
516
516
517 @predicate('phasedivergent()', safe=True)
517 @predicate('phasedivergent()', safe=True)
518 def phasedivergent(repo, subset, x):
518 def phasedivergent(repo, subset, x):
519 """Mutable changesets marked as successors of public changesets.
519 """Mutable changesets marked as successors of public changesets.
520
520
521 Only non-public and non-obsolete changesets can be `phasedivergent`.
521 Only non-public and non-obsolete changesets can be `phasedivergent`.
522 (EXPERIMENTAL)
522 (EXPERIMENTAL)
523 """
523 """
524 # i18n: "phasedivergent" is a keyword
524 # i18n: "phasedivergent" is a keyword
525 getargs(x, 0, 0, _("phasedivergent takes no arguments"))
525 getargs(x, 0, 0, _("phasedivergent takes no arguments"))
526 phasedivergent = obsmod.getrevs(repo, 'phasedivergent')
526 phasedivergent = obsmod.getrevs(repo, 'phasedivergent')
527 return subset & phasedivergent
527 return subset & phasedivergent
528
528
529 @predicate('bundle()', safe=True)
529 @predicate('bundle()', safe=True)
530 def bundle(repo, subset, x):
530 def bundle(repo, subset, x):
531 """Changesets in the bundle.
531 """Changesets in the bundle.
532
532
533 Bundle must be specified by the -R option."""
533 Bundle must be specified by the -R option."""
534
534
535 try:
535 try:
536 bundlerevs = repo.changelog.bundlerevs
536 bundlerevs = repo.changelog.bundlerevs
537 except AttributeError:
537 except AttributeError:
538 raise error.Abort(_("no bundle provided - specify with -R"))
538 raise error.Abort(_("no bundle provided - specify with -R"))
539 return subset & bundlerevs
539 return subset & bundlerevs
540
540
541 def checkstatus(repo, subset, pat, field):
541 def checkstatus(repo, subset, pat, field):
542 hasset = matchmod.patkind(pat) == 'set'
542 hasset = matchmod.patkind(pat) == 'set'
543
543
544 mcache = [None]
544 mcache = [None]
545 def matches(x):
545 def matches(x):
546 c = repo[x]
546 c = repo[x]
547 if not mcache[0] or hasset:
547 if not mcache[0] or hasset:
548 mcache[0] = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
548 mcache[0] = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
549 m = mcache[0]
549 m = mcache[0]
550 fname = None
550 fname = None
551 if not m.anypats() and len(m.files()) == 1:
551 if not m.anypats() and len(m.files()) == 1:
552 fname = m.files()[0]
552 fname = m.files()[0]
553 if fname is not None:
553 if fname is not None:
554 if fname not in c.files():
554 if fname not in c.files():
555 return False
555 return False
556 else:
556 else:
557 for f in c.files():
557 for f in c.files():
558 if m(f):
558 if m(f):
559 break
559 break
560 else:
560 else:
561 return False
561 return False
562 files = repo.status(c.p1().node(), c.node())[field]
562 files = repo.status(c.p1().node(), c.node())[field]
563 if fname is not None:
563 if fname is not None:
564 if fname in files:
564 if fname in files:
565 return True
565 return True
566 else:
566 else:
567 for f in files:
567 for f in files:
568 if m(f):
568 if m(f):
569 return True
569 return True
570
570
571 return subset.filter(matches, condrepr=('<status[%r] %r>', field, pat))
571 return subset.filter(matches, condrepr=('<status[%r] %r>', field, pat))
572
572
573 def _children(repo, subset, parentset):
573 def _children(repo, subset, parentset):
574 if not parentset:
574 if not parentset:
575 return baseset()
575 return baseset()
576 cs = set()
576 cs = set()
577 pr = repo.changelog.parentrevs
577 pr = repo.changelog.parentrevs
578 minrev = parentset.min()
578 minrev = parentset.min()
579 nullrev = node.nullrev
579 nullrev = node.nullrev
580 for r in subset:
580 for r in subset:
581 if r <= minrev:
581 if r <= minrev:
582 continue
582 continue
583 p1, p2 = pr(r)
583 p1, p2 = pr(r)
584 if p1 in parentset:
584 if p1 in parentset:
585 cs.add(r)
585 cs.add(r)
586 if p2 != nullrev and p2 in parentset:
586 if p2 != nullrev and p2 in parentset:
587 cs.add(r)
587 cs.add(r)
588 return baseset(cs)
588 return baseset(cs)
589
589
590 @predicate('children(set)', safe=True)
590 @predicate('children(set)', safe=True)
591 def children(repo, subset, x):
591 def children(repo, subset, x):
592 """Child changesets of changesets in set.
592 """Child changesets of changesets in set.
593 """
593 """
594 s = getset(repo, fullreposet(repo), x)
594 s = getset(repo, fullreposet(repo), x)
595 cs = _children(repo, subset, s)
595 cs = _children(repo, subset, s)
596 return subset & cs
596 return subset & cs
597
597
598 @predicate('closed()', safe=True, weight=10)
598 @predicate('closed()', safe=True, weight=10)
599 def closed(repo, subset, x):
599 def closed(repo, subset, x):
600 """Changeset is closed.
600 """Changeset is closed.
601 """
601 """
602 # i18n: "closed" is a keyword
602 # i18n: "closed" is a keyword
603 getargs(x, 0, 0, _("closed takes no arguments"))
603 getargs(x, 0, 0, _("closed takes no arguments"))
604 return subset.filter(lambda r: repo[r].closesbranch(),
604 return subset.filter(lambda r: repo[r].closesbranch(),
605 condrepr='<branch closed>')
605 condrepr='<branch closed>')
606
606
607 @predicate('contains(pattern)', weight=100)
607 @predicate('contains(pattern)', weight=100)
608 def contains(repo, subset, x):
608 def contains(repo, subset, x):
609 """The revision's manifest contains a file matching pattern (but might not
609 """The revision's manifest contains a file matching pattern (but might not
610 modify it). See :hg:`help patterns` for information about file patterns.
610 modify it). See :hg:`help patterns` for information about file patterns.
611
611
612 The pattern without explicit kind like ``glob:`` is expected to be
612 The pattern without explicit kind like ``glob:`` is expected to be
613 relative to the current directory and match against a file exactly
613 relative to the current directory and match against a file exactly
614 for efficiency.
614 for efficiency.
615 """
615 """
616 # i18n: "contains" is a keyword
616 # i18n: "contains" is a keyword
617 pat = getstring(x, _("contains requires a pattern"))
617 pat = getstring(x, _("contains requires a pattern"))
618
618
619 def matches(x):
619 def matches(x):
620 if not matchmod.patkind(pat):
620 if not matchmod.patkind(pat):
621 pats = pathutil.canonpath(repo.root, repo.getcwd(), pat)
621 pats = pathutil.canonpath(repo.root, repo.getcwd(), pat)
622 if pats in repo[x]:
622 if pats in repo[x]:
623 return True
623 return True
624 else:
624 else:
625 c = repo[x]
625 c = repo[x]
626 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
626 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
627 for f in c.manifest():
627 for f in c.manifest():
628 if m(f):
628 if m(f):
629 return True
629 return True
630 return False
630 return False
631
631
632 return subset.filter(matches, condrepr=('<contains %r>', pat))
632 return subset.filter(matches, condrepr=('<contains %r>', pat))
633
633
634 @predicate('converted([id])', safe=True)
634 @predicate('converted([id])', safe=True)
635 def converted(repo, subset, x):
635 def converted(repo, subset, x):
636 """Changesets converted from the given identifier in the old repository if
636 """Changesets converted from the given identifier in the old repository if
637 present, or all converted changesets if no identifier is specified.
637 present, or all converted changesets if no identifier is specified.
638 """
638 """
639
639
640 # There is exactly no chance of resolving the revision, so do a simple
640 # There is exactly no chance of resolving the revision, so do a simple
641 # string compare and hope for the best
641 # string compare and hope for the best
642
642
643 rev = None
643 rev = None
644 # i18n: "converted" is a keyword
644 # i18n: "converted" is a keyword
645 l = getargs(x, 0, 1, _('converted takes one or no arguments'))
645 l = getargs(x, 0, 1, _('converted takes one or no arguments'))
646 if l:
646 if l:
647 # i18n: "converted" is a keyword
647 # i18n: "converted" is a keyword
648 rev = getstring(l[0], _('converted requires a revision'))
648 rev = getstring(l[0], _('converted requires a revision'))
649
649
650 def _matchvalue(r):
650 def _matchvalue(r):
651 source = repo[r].extra().get('convert_revision', None)
651 source = repo[r].extra().get('convert_revision', None)
652 return source is not None and (rev is None or source.startswith(rev))
652 return source is not None and (rev is None or source.startswith(rev))
653
653
654 return subset.filter(lambda r: _matchvalue(r),
654 return subset.filter(lambda r: _matchvalue(r),
655 condrepr=('<converted %r>', rev))
655 condrepr=('<converted %r>', rev))
656
656
657 @predicate('date(interval)', safe=True, weight=10)
657 @predicate('date(interval)', safe=True, weight=10)
658 def date(repo, subset, x):
658 def date(repo, subset, x):
659 """Changesets within the interval, see :hg:`help dates`.
659 """Changesets within the interval, see :hg:`help dates`.
660 """
660 """
661 # i18n: "date" is a keyword
661 # i18n: "date" is a keyword
662 ds = getstring(x, _("date requires a string"))
662 ds = getstring(x, _("date requires a string"))
663 dm = util.matchdate(ds)
663 dm = util.matchdate(ds)
664 return subset.filter(lambda x: dm(repo[x].date()[0]),
664 return subset.filter(lambda x: dm(repo[x].date()[0]),
665 condrepr=('<date %r>', ds))
665 condrepr=('<date %r>', ds))
666
666
667 @predicate('desc(string)', safe=True, weight=10)
667 @predicate('desc(string)', safe=True, weight=10)
668 def desc(repo, subset, x):
668 def desc(repo, subset, x):
669 """Search commit message for string. The match is case-insensitive.
669 """Search commit message for string. The match is case-insensitive.
670
670
671 Pattern matching is supported for `string`. See
671 Pattern matching is supported for `string`. See
672 :hg:`help revisions.patterns`.
672 :hg:`help revisions.patterns`.
673 """
673 """
674 # i18n: "desc" is a keyword
674 # i18n: "desc" is a keyword
675 ds = getstring(x, _("desc requires a string"))
675 ds = getstring(x, _("desc requires a string"))
676
676
677 kind, pattern, matcher = _substringmatcher(ds, casesensitive=False)
677 kind, pattern, matcher = _substringmatcher(ds, casesensitive=False)
678
678
679 return subset.filter(lambda r: matcher(repo[r].description()),
679 return subset.filter(lambda r: matcher(repo[r].description()),
680 condrepr=('<desc %r>', ds))
680 condrepr=('<desc %r>', ds))
681
681
682 def _descendants(repo, subset, x, followfirst=False, startdepth=None,
682 def _descendants(repo, subset, x, followfirst=False, startdepth=None,
683 stopdepth=None):
683 stopdepth=None):
684 roots = getset(repo, fullreposet(repo), x)
684 roots = getset(repo, fullreposet(repo), x)
685 if not roots:
685 if not roots:
686 return baseset()
686 return baseset()
687 s = dagop.revdescendants(repo, roots, followfirst, startdepth, stopdepth)
687 s = dagop.revdescendants(repo, roots, followfirst, startdepth, stopdepth)
688 return subset & s
688 return subset & s
689
689
690 @predicate('descendants(set[, depth])', safe=True)
690 @predicate('descendants(set[, depth])', safe=True)
691 def descendants(repo, subset, x):
691 def descendants(repo, subset, x):
692 """Changesets which are descendants of changesets in set, including the
692 """Changesets which are descendants of changesets in set, including the
693 given changesets themselves.
693 given changesets themselves.
694
694
695 If depth is specified, the result only includes changesets up to
695 If depth is specified, the result only includes changesets up to
696 the specified generation.
696 the specified generation.
697 """
697 """
698 # startdepth is for internal use only until we can decide the UI
698 # startdepth is for internal use only until we can decide the UI
699 args = getargsdict(x, 'descendants', 'set depth startdepth')
699 args = getargsdict(x, 'descendants', 'set depth startdepth')
700 if 'set' not in args:
700 if 'set' not in args:
701 # i18n: "descendants" is a keyword
701 # i18n: "descendants" is a keyword
702 raise error.ParseError(_('descendants takes at least 1 argument'))
702 raise error.ParseError(_('descendants takes at least 1 argument'))
703 startdepth = stopdepth = None
703 startdepth = stopdepth = None
704 if 'startdepth' in args:
704 if 'startdepth' in args:
705 n = getinteger(args['startdepth'],
705 n = getinteger(args['startdepth'],
706 "descendants expects an integer startdepth")
706 "descendants expects an integer startdepth")
707 if n < 0:
707 if n < 0:
708 raise error.ParseError("negative startdepth")
708 raise error.ParseError("negative startdepth")
709 startdepth = n
709 startdepth = n
710 if 'depth' in args:
710 if 'depth' in args:
711 # i18n: "descendants" is a keyword
711 # i18n: "descendants" is a keyword
712 n = getinteger(args['depth'], _("descendants expects an integer depth"))
712 n = getinteger(args['depth'], _("descendants expects an integer depth"))
713 if n < 0:
713 if n < 0:
714 raise error.ParseError(_("negative depth"))
714 raise error.ParseError(_("negative depth"))
715 stopdepth = n + 1
715 stopdepth = n + 1
716 return _descendants(repo, subset, args['set'],
716 return _descendants(repo, subset, args['set'],
717 startdepth=startdepth, stopdepth=stopdepth)
717 startdepth=startdepth, stopdepth=stopdepth)
718
718
719 @predicate('_firstdescendants', safe=True)
719 @predicate('_firstdescendants', safe=True)
720 def _firstdescendants(repo, subset, x):
720 def _firstdescendants(repo, subset, x):
721 # ``_firstdescendants(set)``
721 # ``_firstdescendants(set)``
722 # Like ``descendants(set)`` but follows only the first parents.
722 # Like ``descendants(set)`` but follows only the first parents.
723 return _descendants(repo, subset, x, followfirst=True)
723 return _descendants(repo, subset, x, followfirst=True)
724
724
725 @predicate('destination([set])', safe=True, weight=10)
725 @predicate('destination([set])', safe=True, weight=10)
726 def destination(repo, subset, x):
726 def destination(repo, subset, x):
727 """Changesets that were created by a graft, transplant or rebase operation,
727 """Changesets that were created by a graft, transplant or rebase operation,
728 with the given revisions specified as the source. Omitting the optional set
728 with the given revisions specified as the source. Omitting the optional set
729 is the same as passing all().
729 is the same as passing all().
730 """
730 """
731 if x is not None:
731 if x is not None:
732 sources = getset(repo, fullreposet(repo), x)
732 sources = getset(repo, fullreposet(repo), x)
733 else:
733 else:
734 sources = fullreposet(repo)
734 sources = fullreposet(repo)
735
735
736 dests = set()
736 dests = set()
737
737
738 # subset contains all of the possible destinations that can be returned, so
738 # subset contains all of the possible destinations that can be returned, so
739 # iterate over them and see if their source(s) were provided in the arg set.
739 # iterate over them and see if their source(s) were provided in the arg set.
740 # Even if the immediate src of r is not in the arg set, src's source (or
740 # Even if the immediate src of r is not in the arg set, src's source (or
741 # further back) may be. Scanning back further than the immediate src allows
741 # further back) may be. Scanning back further than the immediate src allows
742 # transitive transplants and rebases to yield the same results as transitive
742 # transitive transplants and rebases to yield the same results as transitive
743 # grafts.
743 # grafts.
744 for r in subset:
744 for r in subset:
745 src = _getrevsource(repo, r)
745 src = _getrevsource(repo, r)
746 lineage = None
746 lineage = None
747
747
748 while src is not None:
748 while src is not None:
749 if lineage is None:
749 if lineage is None:
750 lineage = list()
750 lineage = list()
751
751
752 lineage.append(r)
752 lineage.append(r)
753
753
754 # The visited lineage is a match if the current source is in the arg
754 # The visited lineage is a match if the current source is in the arg
755 # set. Since every candidate dest is visited by way of iterating
755 # set. Since every candidate dest is visited by way of iterating
756 # subset, any dests further back in the lineage will be tested by a
756 # subset, any dests further back in the lineage will be tested by a
757 # different iteration over subset. Likewise, if the src was already
757 # different iteration over subset. Likewise, if the src was already
758 # selected, the current lineage can be selected without going back
758 # selected, the current lineage can be selected without going back
759 # further.
759 # further.
760 if src in sources or src in dests:
760 if src in sources or src in dests:
761 dests.update(lineage)
761 dests.update(lineage)
762 break
762 break
763
763
764 r = src
764 r = src
765 src = _getrevsource(repo, r)
765 src = _getrevsource(repo, r)
766
766
767 return subset.filter(dests.__contains__,
767 return subset.filter(dests.__contains__,
768 condrepr=lambda: '<destination %r>' % sorted(dests))
768 condrepr=lambda: '<destination %r>' % sorted(dests))
769
769
770 @predicate('divergent()', safe=True)
770 @predicate('divergent()', safe=True)
771 def divergent(repo, subset, x):
771 def divergent(repo, subset, x):
772 msg = ("'divergent()' is deprecated, "
772 msg = ("'divergent()' is deprecated, "
773 "use 'contentdivergent()'")
773 "use 'contentdivergent()'")
774 repo.ui.deprecwarn(msg, '4.4')
774 repo.ui.deprecwarn(msg, '4.4')
775
775
776 return contentdivergent(repo, subset, x)
776 return contentdivergent(repo, subset, x)
777
777
778 @predicate('contentdivergent()', safe=True)
778 @predicate('contentdivergent()', safe=True)
779 def contentdivergent(repo, subset, x):
779 def contentdivergent(repo, subset, x):
780 """
780 """
781 Final successors of changesets with an alternative set of final
781 Final successors of changesets with an alternative set of final
782 successors. (EXPERIMENTAL)
782 successors. (EXPERIMENTAL)
783 """
783 """
784 # i18n: "contentdivergent" is a keyword
784 # i18n: "contentdivergent" is a keyword
785 getargs(x, 0, 0, _("contentdivergent takes no arguments"))
785 getargs(x, 0, 0, _("contentdivergent takes no arguments"))
786 contentdivergent = obsmod.getrevs(repo, 'contentdivergent')
786 contentdivergent = obsmod.getrevs(repo, 'contentdivergent')
787 return subset & contentdivergent
787 return subset & contentdivergent
788
788
789 @predicate('extdata(source)', safe=False, weight=100)
789 @predicate('extdata(source)', safe=False, weight=100)
790 def extdata(repo, subset, x):
790 def extdata(repo, subset, x):
791 """Changesets in the specified extdata source. (EXPERIMENTAL)"""
791 """Changesets in the specified extdata source. (EXPERIMENTAL)"""
792 # i18n: "extdata" is a keyword
792 # i18n: "extdata" is a keyword
793 args = getargsdict(x, 'extdata', 'source')
793 args = getargsdict(x, 'extdata', 'source')
794 source = getstring(args.get('source'),
794 source = getstring(args.get('source'),
795 # i18n: "extdata" is a keyword
795 # i18n: "extdata" is a keyword
796 _('extdata takes at least 1 string argument'))
796 _('extdata takes at least 1 string argument'))
797 data = scmutil.extdatasource(repo, source)
797 data = scmutil.extdatasource(repo, source)
798 return subset & baseset(data)
798 return subset & baseset(data)
799
799
800 @predicate('extinct()', safe=True)
800 @predicate('extinct()', safe=True)
801 def extinct(repo, subset, x):
801 def extinct(repo, subset, x):
802 """Obsolete changesets with obsolete descendants only.
802 """Obsolete changesets with obsolete descendants only.
803 """
803 """
804 # i18n: "extinct" is a keyword
804 # i18n: "extinct" is a keyword
805 getargs(x, 0, 0, _("extinct takes no arguments"))
805 getargs(x, 0, 0, _("extinct takes no arguments"))
806 extincts = obsmod.getrevs(repo, 'extinct')
806 extincts = obsmod.getrevs(repo, 'extinct')
807 return subset & extincts
807 return subset & extincts
808
808
809 @predicate('extra(label, [value])', safe=True)
809 @predicate('extra(label, [value])', safe=True)
810 def extra(repo, subset, x):
810 def extra(repo, subset, x):
811 """Changesets with the given label in the extra metadata, with the given
811 """Changesets with the given label in the extra metadata, with the given
812 optional value.
812 optional value.
813
813
814 Pattern matching is supported for `value`. See
814 Pattern matching is supported for `value`. See
815 :hg:`help revisions.patterns`.
815 :hg:`help revisions.patterns`.
816 """
816 """
817 args = getargsdict(x, 'extra', 'label value')
817 args = getargsdict(x, 'extra', 'label value')
818 if 'label' not in args:
818 if 'label' not in args:
819 # i18n: "extra" is a keyword
819 # i18n: "extra" is a keyword
820 raise error.ParseError(_('extra takes at least 1 argument'))
820 raise error.ParseError(_('extra takes at least 1 argument'))
821 # i18n: "extra" is a keyword
821 # i18n: "extra" is a keyword
822 label = getstring(args['label'], _('first argument to extra must be '
822 label = getstring(args['label'], _('first argument to extra must be '
823 'a string'))
823 'a string'))
824 value = None
824 value = None
825
825
826 if 'value' in args:
826 if 'value' in args:
827 # i18n: "extra" is a keyword
827 # i18n: "extra" is a keyword
828 value = getstring(args['value'], _('second argument to extra must be '
828 value = getstring(args['value'], _('second argument to extra must be '
829 'a string'))
829 'a string'))
830 kind, value, matcher = util.stringmatcher(value)
830 kind, value, matcher = util.stringmatcher(value)
831
831
832 def _matchvalue(r):
832 def _matchvalue(r):
833 extra = repo[r].extra()
833 extra = repo[r].extra()
834 return label in extra and (value is None or matcher(extra[label]))
834 return label in extra and (value is None or matcher(extra[label]))
835
835
836 return subset.filter(lambda r: _matchvalue(r),
836 return subset.filter(lambda r: _matchvalue(r),
837 condrepr=('<extra[%r] %r>', label, value))
837 condrepr=('<extra[%r] %r>', label, value))
838
838
839 @predicate('filelog(pattern)', safe=True)
839 @predicate('filelog(pattern)', safe=True)
840 def filelog(repo, subset, x):
840 def filelog(repo, subset, x):
841 """Changesets connected to the specified filelog.
841 """Changesets connected to the specified filelog.
842
842
843 For performance reasons, visits only revisions mentioned in the file-level
843 For performance reasons, visits only revisions mentioned in the file-level
844 filelog, rather than filtering through all changesets (much faster, but
844 filelog, rather than filtering through all changesets (much faster, but
845 doesn't include deletes or duplicate changes). For a slower, more accurate
845 doesn't include deletes or duplicate changes). For a slower, more accurate
846 result, use ``file()``.
846 result, use ``file()``.
847
847
848 The pattern without explicit kind like ``glob:`` is expected to be
848 The pattern without explicit kind like ``glob:`` is expected to be
849 relative to the current directory and match against a file exactly
849 relative to the current directory and match against a file exactly
850 for efficiency.
850 for efficiency.
851
851
852 If some linkrev points to revisions filtered by the current repoview, we'll
852 If some linkrev points to revisions filtered by the current repoview, we'll
853 work around it to return a non-filtered value.
853 work around it to return a non-filtered value.
854 """
854 """
855
855
856 # i18n: "filelog" is a keyword
856 # i18n: "filelog" is a keyword
857 pat = getstring(x, _("filelog requires a pattern"))
857 pat = getstring(x, _("filelog requires a pattern"))
858 s = set()
858 s = set()
859 cl = repo.changelog
859 cl = repo.changelog
860
860
861 if not matchmod.patkind(pat):
861 if not matchmod.patkind(pat):
862 f = pathutil.canonpath(repo.root, repo.getcwd(), pat)
862 f = pathutil.canonpath(repo.root, repo.getcwd(), pat)
863 files = [f]
863 files = [f]
864 else:
864 else:
865 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[None])
865 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[None])
866 files = (f for f in repo[None] if m(f))
866 files = (f for f in repo[None] if m(f))
867
867
868 for f in files:
868 for f in files:
869 fl = repo.file(f)
869 fl = repo.file(f)
870 known = {}
870 known = {}
871 scanpos = 0
871 scanpos = 0
872 for fr in list(fl):
872 for fr in list(fl):
873 fn = fl.node(fr)
873 fn = fl.node(fr)
874 if fn in known:
874 if fn in known:
875 s.add(known[fn])
875 s.add(known[fn])
876 continue
876 continue
877
877
878 lr = fl.linkrev(fr)
878 lr = fl.linkrev(fr)
879 if lr in cl:
879 if lr in cl:
880 s.add(lr)
880 s.add(lr)
881 elif scanpos is not None:
881 elif scanpos is not None:
882 # lowest matching changeset is filtered, scan further
882 # lowest matching changeset is filtered, scan further
883 # ahead in changelog
883 # ahead in changelog
884 start = max(lr, scanpos) + 1
884 start = max(lr, scanpos) + 1
885 scanpos = None
885 scanpos = None
886 for r in cl.revs(start):
886 for r in cl.revs(start):
887 # minimize parsing of non-matching entries
887 # minimize parsing of non-matching entries
888 if f in cl.revision(r) and f in cl.readfiles(r):
888 if f in cl.revision(r) and f in cl.readfiles(r):
889 try:
889 try:
890 # try to use manifest delta fastpath
890 # try to use manifest delta fastpath
891 n = repo[r].filenode(f)
891 n = repo[r].filenode(f)
892 if n not in known:
892 if n not in known:
893 if n == fn:
893 if n == fn:
894 s.add(r)
894 s.add(r)
895 scanpos = r
895 scanpos = r
896 break
896 break
897 else:
897 else:
898 known[n] = r
898 known[n] = r
899 except error.ManifestLookupError:
899 except error.ManifestLookupError:
900 # deletion in changelog
900 # deletion in changelog
901 continue
901 continue
902
902
903 return subset & s
903 return subset & s
904
904
905 @predicate('first(set, [n])', safe=True, takeorder=True, weight=0)
905 @predicate('first(set, [n])', safe=True, takeorder=True, weight=0)
906 def first(repo, subset, x, order):
906 def first(repo, subset, x, order):
907 """An alias for limit().
907 """An alias for limit().
908 """
908 """
909 return limit(repo, subset, x, order)
909 return limit(repo, subset, x, order)
910
910
911 def _follow(repo, subset, x, name, followfirst=False):
911 def _follow(repo, subset, x, name, followfirst=False):
912 l = getargs(x, 0, 2, _("%s takes no arguments or a pattern "
912 l = getargs(x, 0, 2, _("%s takes no arguments or a pattern "
913 "and an optional revset") % name)
913 "and an optional revset") % name)
914 c = repo['.']
914 c = repo['.']
915 if l:
915 if l:
916 x = getstring(l[0], _("%s expected a pattern") % name)
916 x = getstring(l[0], _("%s expected a pattern") % name)
917 rev = None
917 revs = [None]
918 if len(l) >= 2:
918 if len(l) >= 2:
919 revs = getset(repo, fullreposet(repo), l[1])
919 revs = getset(repo, fullreposet(repo), l[1])
920 if len(revs) != 1:
920 if not revs:
921 raise error.RepoLookupError(
921 raise error.RepoLookupError(
922 _("%s expected one starting revision") % name)
922 _("%s expected at least one starting revision") % name)
923 rev = revs.last()
923 fctxs = []
924 c = repo[rev]
924 for r in revs:
925 matcher = matchmod.match(repo.root, repo.getcwd(), [x],
925 ctx = mctx = repo[r]
926 ctx=repo[rev], default='path')
926 if r is None:
927
927 ctx = repo['.']
928 files = c.manifest().walk(matcher)
928 m = matchmod.match(repo.root, repo.getcwd(), [x],
929
929 ctx=mctx, default='path')
930 fctxs = [c[f].introfilectx() for f in files]
930 fctxs.extend(ctx[f].introfilectx() for f in ctx.manifest().walk(m))
931 s = dagop.filerevancestors(fctxs, followfirst)
931 s = dagop.filerevancestors(fctxs, followfirst)
932 else:
932 else:
933 s = dagop.revancestors(repo, baseset([c.rev()]), followfirst)
933 s = dagop.revancestors(repo, baseset([c.rev()]), followfirst)
934
934
935 return subset & s
935 return subset & s
936
936
937 @predicate('follow([pattern[, startrev]])', safe=True)
937 @predicate('follow([pattern[, startrev]])', safe=True)
938 def follow(repo, subset, x):
938 def follow(repo, subset, x):
939 """
939 """
940 An alias for ``::.`` (ancestors of the working directory's first parent).
940 An alias for ``::.`` (ancestors of the working directory's first parent).
941 If pattern is specified, the histories of files matching given
941 If pattern is specified, the histories of files matching given
942 pattern in the revision given by startrev are followed, including copies.
942 pattern in the revision given by startrev are followed, including copies.
943 """
943 """
944 return _follow(repo, subset, x, 'follow')
944 return _follow(repo, subset, x, 'follow')
945
945
946 @predicate('_followfirst', safe=True)
946 @predicate('_followfirst', safe=True)
947 def _followfirst(repo, subset, x):
947 def _followfirst(repo, subset, x):
948 # ``followfirst([pattern[, startrev]])``
948 # ``followfirst([pattern[, startrev]])``
949 # Like ``follow([pattern[, startrev]])`` but follows only the first parent
949 # Like ``follow([pattern[, startrev]])`` but follows only the first parent
950 # of every revisions or files revisions.
950 # of every revisions or files revisions.
951 return _follow(repo, subset, x, '_followfirst', followfirst=True)
951 return _follow(repo, subset, x, '_followfirst', followfirst=True)
952
952
953 @predicate('followlines(file, fromline:toline[, startrev=., descend=False])',
953 @predicate('followlines(file, fromline:toline[, startrev=., descend=False])',
954 safe=True)
954 safe=True)
955 def followlines(repo, subset, x):
955 def followlines(repo, subset, x):
956 """Changesets modifying `file` in line range ('fromline', 'toline').
956 """Changesets modifying `file` in line range ('fromline', 'toline').
957
957
958 Line range corresponds to 'file' content at 'startrev' and should hence be
958 Line range corresponds to 'file' content at 'startrev' and should hence be
959 consistent with file size. If startrev is not specified, working directory's
959 consistent with file size. If startrev is not specified, working directory's
960 parent is used.
960 parent is used.
961
961
962 By default, ancestors of 'startrev' are returned. If 'descend' is True,
962 By default, ancestors of 'startrev' are returned. If 'descend' is True,
963 descendants of 'startrev' are returned though renames are (currently) not
963 descendants of 'startrev' are returned though renames are (currently) not
964 followed in this direction.
964 followed in this direction.
965 """
965 """
966 args = getargsdict(x, 'followlines', 'file *lines startrev descend')
966 args = getargsdict(x, 'followlines', 'file *lines startrev descend')
967 if len(args['lines']) != 1:
967 if len(args['lines']) != 1:
968 raise error.ParseError(_("followlines requires a line range"))
968 raise error.ParseError(_("followlines requires a line range"))
969
969
970 rev = '.'
970 rev = '.'
971 if 'startrev' in args:
971 if 'startrev' in args:
972 revs = getset(repo, fullreposet(repo), args['startrev'])
972 revs = getset(repo, fullreposet(repo), args['startrev'])
973 if len(revs) != 1:
973 if len(revs) != 1:
974 raise error.ParseError(
974 raise error.ParseError(
975 # i18n: "followlines" is a keyword
975 # i18n: "followlines" is a keyword
976 _("followlines expects exactly one revision"))
976 _("followlines expects exactly one revision"))
977 rev = revs.last()
977 rev = revs.last()
978
978
979 pat = getstring(args['file'], _("followlines requires a pattern"))
979 pat = getstring(args['file'], _("followlines requires a pattern"))
980 # i18n: "followlines" is a keyword
980 # i18n: "followlines" is a keyword
981 msg = _("followlines expects exactly one file")
981 msg = _("followlines expects exactly one file")
982 fname = scmutil.parsefollowlinespattern(repo, rev, pat, msg)
982 fname = scmutil.parsefollowlinespattern(repo, rev, pat, msg)
983 # i18n: "followlines" is a keyword
983 # i18n: "followlines" is a keyword
984 lr = getrange(args['lines'][0], _("followlines expects a line range"))
984 lr = getrange(args['lines'][0], _("followlines expects a line range"))
985 fromline, toline = [getinteger(a, _("line range bounds must be integers"))
985 fromline, toline = [getinteger(a, _("line range bounds must be integers"))
986 for a in lr]
986 for a in lr]
987 fromline, toline = util.processlinerange(fromline, toline)
987 fromline, toline = util.processlinerange(fromline, toline)
988
988
989 fctx = repo[rev].filectx(fname)
989 fctx = repo[rev].filectx(fname)
990 descend = False
990 descend = False
991 if 'descend' in args:
991 if 'descend' in args:
992 descend = getboolean(args['descend'],
992 descend = getboolean(args['descend'],
993 # i18n: "descend" is a keyword
993 # i18n: "descend" is a keyword
994 _("descend argument must be a boolean"))
994 _("descend argument must be a boolean"))
995 if descend:
995 if descend:
996 rs = generatorset(
996 rs = generatorset(
997 (c.rev() for c, _linerange
997 (c.rev() for c, _linerange
998 in dagop.blockdescendants(fctx, fromline, toline)),
998 in dagop.blockdescendants(fctx, fromline, toline)),
999 iterasc=True)
999 iterasc=True)
1000 else:
1000 else:
1001 rs = generatorset(
1001 rs = generatorset(
1002 (c.rev() for c, _linerange
1002 (c.rev() for c, _linerange
1003 in dagop.blockancestors(fctx, fromline, toline)),
1003 in dagop.blockancestors(fctx, fromline, toline)),
1004 iterasc=False)
1004 iterasc=False)
1005 return subset & rs
1005 return subset & rs
1006
1006
1007 @predicate('all()', safe=True)
1007 @predicate('all()', safe=True)
1008 def getall(repo, subset, x):
1008 def getall(repo, subset, x):
1009 """All changesets, the same as ``0:tip``.
1009 """All changesets, the same as ``0:tip``.
1010 """
1010 """
1011 # i18n: "all" is a keyword
1011 # i18n: "all" is a keyword
1012 getargs(x, 0, 0, _("all takes no arguments"))
1012 getargs(x, 0, 0, _("all takes no arguments"))
1013 return subset & spanset(repo) # drop "null" if any
1013 return subset & spanset(repo) # drop "null" if any
1014
1014
1015 @predicate('grep(regex)', weight=10)
1015 @predicate('grep(regex)', weight=10)
1016 def grep(repo, subset, x):
1016 def grep(repo, subset, x):
1017 """Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
1017 """Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
1018 to ensure special escape characters are handled correctly. Unlike
1018 to ensure special escape characters are handled correctly. Unlike
1019 ``keyword(string)``, the match is case-sensitive.
1019 ``keyword(string)``, the match is case-sensitive.
1020 """
1020 """
1021 try:
1021 try:
1022 # i18n: "grep" is a keyword
1022 # i18n: "grep" is a keyword
1023 gr = re.compile(getstring(x, _("grep requires a string")))
1023 gr = re.compile(getstring(x, _("grep requires a string")))
1024 except re.error as e:
1024 except re.error as e:
1025 raise error.ParseError(_('invalid match pattern: %s') % e)
1025 raise error.ParseError(_('invalid match pattern: %s') % e)
1026
1026
1027 def matches(x):
1027 def matches(x):
1028 c = repo[x]
1028 c = repo[x]
1029 for e in c.files() + [c.user(), c.description()]:
1029 for e in c.files() + [c.user(), c.description()]:
1030 if gr.search(e):
1030 if gr.search(e):
1031 return True
1031 return True
1032 return False
1032 return False
1033
1033
1034 return subset.filter(matches, condrepr=('<grep %r>', gr.pattern))
1034 return subset.filter(matches, condrepr=('<grep %r>', gr.pattern))
1035
1035
1036 @predicate('_matchfiles', safe=True)
1036 @predicate('_matchfiles', safe=True)
1037 def _matchfiles(repo, subset, x):
1037 def _matchfiles(repo, subset, x):
1038 # _matchfiles takes a revset list of prefixed arguments:
1038 # _matchfiles takes a revset list of prefixed arguments:
1039 #
1039 #
1040 # [p:foo, i:bar, x:baz]
1040 # [p:foo, i:bar, x:baz]
1041 #
1041 #
1042 # builds a match object from them and filters subset. Allowed
1042 # builds a match object from them and filters subset. Allowed
1043 # prefixes are 'p:' for regular patterns, 'i:' for include
1043 # prefixes are 'p:' for regular patterns, 'i:' for include
1044 # patterns and 'x:' for exclude patterns. Use 'r:' prefix to pass
1044 # patterns and 'x:' for exclude patterns. Use 'r:' prefix to pass
1045 # a revision identifier, or the empty string to reference the
1045 # a revision identifier, or the empty string to reference the
1046 # working directory, from which the match object is
1046 # working directory, from which the match object is
1047 # initialized. Use 'd:' to set the default matching mode, default
1047 # initialized. Use 'd:' to set the default matching mode, default
1048 # to 'glob'. At most one 'r:' and 'd:' argument can be passed.
1048 # to 'glob'. At most one 'r:' and 'd:' argument can be passed.
1049
1049
1050 l = getargs(x, 1, -1, "_matchfiles requires at least one argument")
1050 l = getargs(x, 1, -1, "_matchfiles requires at least one argument")
1051 pats, inc, exc = [], [], []
1051 pats, inc, exc = [], [], []
1052 rev, default = None, None
1052 rev, default = None, None
1053 for arg in l:
1053 for arg in l:
1054 s = getstring(arg, "_matchfiles requires string arguments")
1054 s = getstring(arg, "_matchfiles requires string arguments")
1055 prefix, value = s[:2], s[2:]
1055 prefix, value = s[:2], s[2:]
1056 if prefix == 'p:':
1056 if prefix == 'p:':
1057 pats.append(value)
1057 pats.append(value)
1058 elif prefix == 'i:':
1058 elif prefix == 'i:':
1059 inc.append(value)
1059 inc.append(value)
1060 elif prefix == 'x:':
1060 elif prefix == 'x:':
1061 exc.append(value)
1061 exc.append(value)
1062 elif prefix == 'r:':
1062 elif prefix == 'r:':
1063 if rev is not None:
1063 if rev is not None:
1064 raise error.ParseError('_matchfiles expected at most one '
1064 raise error.ParseError('_matchfiles expected at most one '
1065 'revision')
1065 'revision')
1066 if value != '': # empty means working directory; leave rev as None
1066 if value != '': # empty means working directory; leave rev as None
1067 rev = value
1067 rev = value
1068 elif prefix == 'd:':
1068 elif prefix == 'd:':
1069 if default is not None:
1069 if default is not None:
1070 raise error.ParseError('_matchfiles expected at most one '
1070 raise error.ParseError('_matchfiles expected at most one '
1071 'default mode')
1071 'default mode')
1072 default = value
1072 default = value
1073 else:
1073 else:
1074 raise error.ParseError('invalid _matchfiles prefix: %s' % prefix)
1074 raise error.ParseError('invalid _matchfiles prefix: %s' % prefix)
1075 if not default:
1075 if not default:
1076 default = 'glob'
1076 default = 'glob'
1077
1077
1078 m = matchmod.match(repo.root, repo.getcwd(), pats, include=inc,
1078 m = matchmod.match(repo.root, repo.getcwd(), pats, include=inc,
1079 exclude=exc, ctx=repo[rev], default=default)
1079 exclude=exc, ctx=repo[rev], default=default)
1080
1080
1081 # This directly read the changelog data as creating changectx for all
1081 # This directly read the changelog data as creating changectx for all
1082 # revisions is quite expensive.
1082 # revisions is quite expensive.
1083 getfiles = repo.changelog.readfiles
1083 getfiles = repo.changelog.readfiles
1084 wdirrev = node.wdirrev
1084 wdirrev = node.wdirrev
1085 def matches(x):
1085 def matches(x):
1086 if x == wdirrev:
1086 if x == wdirrev:
1087 files = repo[x].files()
1087 files = repo[x].files()
1088 else:
1088 else:
1089 files = getfiles(x)
1089 files = getfiles(x)
1090 for f in files:
1090 for f in files:
1091 if m(f):
1091 if m(f):
1092 return True
1092 return True
1093 return False
1093 return False
1094
1094
1095 return subset.filter(matches,
1095 return subset.filter(matches,
1096 condrepr=('<matchfiles patterns=%r, include=%r '
1096 condrepr=('<matchfiles patterns=%r, include=%r '
1097 'exclude=%r, default=%r, rev=%r>',
1097 'exclude=%r, default=%r, rev=%r>',
1098 pats, inc, exc, default, rev))
1098 pats, inc, exc, default, rev))
1099
1099
1100 @predicate('file(pattern)', safe=True, weight=10)
1100 @predicate('file(pattern)', safe=True, weight=10)
1101 def hasfile(repo, subset, x):
1101 def hasfile(repo, subset, x):
1102 """Changesets affecting files matched by pattern.
1102 """Changesets affecting files matched by pattern.
1103
1103
1104 For a faster but less accurate result, consider using ``filelog()``
1104 For a faster but less accurate result, consider using ``filelog()``
1105 instead.
1105 instead.
1106
1106
1107 This predicate uses ``glob:`` as the default kind of pattern.
1107 This predicate uses ``glob:`` as the default kind of pattern.
1108 """
1108 """
1109 # i18n: "file" is a keyword
1109 # i18n: "file" is a keyword
1110 pat = getstring(x, _("file requires a pattern"))
1110 pat = getstring(x, _("file requires a pattern"))
1111 return _matchfiles(repo, subset, ('string', 'p:' + pat))
1111 return _matchfiles(repo, subset, ('string', 'p:' + pat))
1112
1112
1113 @predicate('head()', safe=True)
1113 @predicate('head()', safe=True)
1114 def head(repo, subset, x):
1114 def head(repo, subset, x):
1115 """Changeset is a named branch head.
1115 """Changeset is a named branch head.
1116 """
1116 """
1117 # i18n: "head" is a keyword
1117 # i18n: "head" is a keyword
1118 getargs(x, 0, 0, _("head takes no arguments"))
1118 getargs(x, 0, 0, _("head takes no arguments"))
1119 hs = set()
1119 hs = set()
1120 cl = repo.changelog
1120 cl = repo.changelog
1121 for ls in repo.branchmap().itervalues():
1121 for ls in repo.branchmap().itervalues():
1122 hs.update(cl.rev(h) for h in ls)
1122 hs.update(cl.rev(h) for h in ls)
1123 return subset & baseset(hs)
1123 return subset & baseset(hs)
1124
1124
1125 @predicate('heads(set)', safe=True)
1125 @predicate('heads(set)', safe=True)
1126 def heads(repo, subset, x):
1126 def heads(repo, subset, x):
1127 """Members of set with no children in set.
1127 """Members of set with no children in set.
1128 """
1128 """
1129 s = getset(repo, subset, x)
1129 s = getset(repo, subset, x)
1130 ps = parents(repo, subset, x)
1130 ps = parents(repo, subset, x)
1131 return s - ps
1131 return s - ps
1132
1132
1133 @predicate('hidden()', safe=True)
1133 @predicate('hidden()', safe=True)
1134 def hidden(repo, subset, x):
1134 def hidden(repo, subset, x):
1135 """Hidden changesets.
1135 """Hidden changesets.
1136 """
1136 """
1137 # i18n: "hidden" is a keyword
1137 # i18n: "hidden" is a keyword
1138 getargs(x, 0, 0, _("hidden takes no arguments"))
1138 getargs(x, 0, 0, _("hidden takes no arguments"))
1139 hiddenrevs = repoview.filterrevs(repo, 'visible')
1139 hiddenrevs = repoview.filterrevs(repo, 'visible')
1140 return subset & hiddenrevs
1140 return subset & hiddenrevs
1141
1141
1142 @predicate('keyword(string)', safe=True, weight=10)
1142 @predicate('keyword(string)', safe=True, weight=10)
1143 def keyword(repo, subset, x):
1143 def keyword(repo, subset, x):
1144 """Search commit message, user name, and names of changed files for
1144 """Search commit message, user name, and names of changed files for
1145 string. The match is case-insensitive.
1145 string. The match is case-insensitive.
1146
1146
1147 For a regular expression or case sensitive search of these fields, use
1147 For a regular expression or case sensitive search of these fields, use
1148 ``grep(regex)``.
1148 ``grep(regex)``.
1149 """
1149 """
1150 # i18n: "keyword" is a keyword
1150 # i18n: "keyword" is a keyword
1151 kw = encoding.lower(getstring(x, _("keyword requires a string")))
1151 kw = encoding.lower(getstring(x, _("keyword requires a string")))
1152
1152
1153 def matches(r):
1153 def matches(r):
1154 c = repo[r]
1154 c = repo[r]
1155 return any(kw in encoding.lower(t)
1155 return any(kw in encoding.lower(t)
1156 for t in c.files() + [c.user(), c.description()])
1156 for t in c.files() + [c.user(), c.description()])
1157
1157
1158 return subset.filter(matches, condrepr=('<keyword %r>', kw))
1158 return subset.filter(matches, condrepr=('<keyword %r>', kw))
1159
1159
1160 @predicate('limit(set[, n[, offset]])', safe=True, takeorder=True, weight=0)
1160 @predicate('limit(set[, n[, offset]])', safe=True, takeorder=True, weight=0)
1161 def limit(repo, subset, x, order):
1161 def limit(repo, subset, x, order):
1162 """First n members of set, defaulting to 1, starting from offset.
1162 """First n members of set, defaulting to 1, starting from offset.
1163 """
1163 """
1164 args = getargsdict(x, 'limit', 'set n offset')
1164 args = getargsdict(x, 'limit', 'set n offset')
1165 if 'set' not in args:
1165 if 'set' not in args:
1166 # i18n: "limit" is a keyword
1166 # i18n: "limit" is a keyword
1167 raise error.ParseError(_("limit requires one to three arguments"))
1167 raise error.ParseError(_("limit requires one to three arguments"))
1168 # i18n: "limit" is a keyword
1168 # i18n: "limit" is a keyword
1169 lim = getinteger(args.get('n'), _("limit expects a number"), default=1)
1169 lim = getinteger(args.get('n'), _("limit expects a number"), default=1)
1170 if lim < 0:
1170 if lim < 0:
1171 raise error.ParseError(_("negative number to select"))
1171 raise error.ParseError(_("negative number to select"))
1172 # i18n: "limit" is a keyword
1172 # i18n: "limit" is a keyword
1173 ofs = getinteger(args.get('offset'), _("limit expects a number"), default=0)
1173 ofs = getinteger(args.get('offset'), _("limit expects a number"), default=0)
1174 if ofs < 0:
1174 if ofs < 0:
1175 raise error.ParseError(_("negative offset"))
1175 raise error.ParseError(_("negative offset"))
1176 os = getset(repo, fullreposet(repo), args['set'])
1176 os = getset(repo, fullreposet(repo), args['set'])
1177 ls = os.slice(ofs, ofs + lim)
1177 ls = os.slice(ofs, ofs + lim)
1178 if order == followorder and lim > 1:
1178 if order == followorder and lim > 1:
1179 return subset & ls
1179 return subset & ls
1180 return ls & subset
1180 return ls & subset
1181
1181
1182 @predicate('last(set, [n])', safe=True, takeorder=True)
1182 @predicate('last(set, [n])', safe=True, takeorder=True)
1183 def last(repo, subset, x, order):
1183 def last(repo, subset, x, order):
1184 """Last n members of set, defaulting to 1.
1184 """Last n members of set, defaulting to 1.
1185 """
1185 """
1186 # i18n: "last" is a keyword
1186 # i18n: "last" is a keyword
1187 l = getargs(x, 1, 2, _("last requires one or two arguments"))
1187 l = getargs(x, 1, 2, _("last requires one or two arguments"))
1188 lim = 1
1188 lim = 1
1189 if len(l) == 2:
1189 if len(l) == 2:
1190 # i18n: "last" is a keyword
1190 # i18n: "last" is a keyword
1191 lim = getinteger(l[1], _("last expects a number"))
1191 lim = getinteger(l[1], _("last expects a number"))
1192 if lim < 0:
1192 if lim < 0:
1193 raise error.ParseError(_("negative number to select"))
1193 raise error.ParseError(_("negative number to select"))
1194 os = getset(repo, fullreposet(repo), l[0])
1194 os = getset(repo, fullreposet(repo), l[0])
1195 os.reverse()
1195 os.reverse()
1196 ls = os.slice(0, lim)
1196 ls = os.slice(0, lim)
1197 if order == followorder and lim > 1:
1197 if order == followorder and lim > 1:
1198 return subset & ls
1198 return subset & ls
1199 ls.reverse()
1199 ls.reverse()
1200 return ls & subset
1200 return ls & subset
1201
1201
1202 @predicate('max(set)', safe=True)
1202 @predicate('max(set)', safe=True)
1203 def maxrev(repo, subset, x):
1203 def maxrev(repo, subset, x):
1204 """Changeset with highest revision number in set.
1204 """Changeset with highest revision number in set.
1205 """
1205 """
1206 os = getset(repo, fullreposet(repo), x)
1206 os = getset(repo, fullreposet(repo), x)
1207 try:
1207 try:
1208 m = os.max()
1208 m = os.max()
1209 if m in subset:
1209 if m in subset:
1210 return baseset([m], datarepr=('<max %r, %r>', subset, os))
1210 return baseset([m], datarepr=('<max %r, %r>', subset, os))
1211 except ValueError:
1211 except ValueError:
1212 # os.max() throws a ValueError when the collection is empty.
1212 # os.max() throws a ValueError when the collection is empty.
1213 # Same as python's max().
1213 # Same as python's max().
1214 pass
1214 pass
1215 return baseset(datarepr=('<max %r, %r>', subset, os))
1215 return baseset(datarepr=('<max %r, %r>', subset, os))
1216
1216
1217 @predicate('merge()', safe=True)
1217 @predicate('merge()', safe=True)
1218 def merge(repo, subset, x):
1218 def merge(repo, subset, x):
1219 """Changeset is a merge changeset.
1219 """Changeset is a merge changeset.
1220 """
1220 """
1221 # i18n: "merge" is a keyword
1221 # i18n: "merge" is a keyword
1222 getargs(x, 0, 0, _("merge takes no arguments"))
1222 getargs(x, 0, 0, _("merge takes no arguments"))
1223 cl = repo.changelog
1223 cl = repo.changelog
1224 return subset.filter(lambda r: cl.parentrevs(r)[1] != -1,
1224 return subset.filter(lambda r: cl.parentrevs(r)[1] != -1,
1225 condrepr='<merge>')
1225 condrepr='<merge>')
1226
1226
1227 @predicate('branchpoint()', safe=True)
1227 @predicate('branchpoint()', safe=True)
1228 def branchpoint(repo, subset, x):
1228 def branchpoint(repo, subset, x):
1229 """Changesets with more than one child.
1229 """Changesets with more than one child.
1230 """
1230 """
1231 # i18n: "branchpoint" is a keyword
1231 # i18n: "branchpoint" is a keyword
1232 getargs(x, 0, 0, _("branchpoint takes no arguments"))
1232 getargs(x, 0, 0, _("branchpoint takes no arguments"))
1233 cl = repo.changelog
1233 cl = repo.changelog
1234 if not subset:
1234 if not subset:
1235 return baseset()
1235 return baseset()
1236 # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
1236 # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
1237 # (and if it is not, it should.)
1237 # (and if it is not, it should.)
1238 baserev = min(subset)
1238 baserev = min(subset)
1239 parentscount = [0]*(len(repo) - baserev)
1239 parentscount = [0]*(len(repo) - baserev)
1240 for r in cl.revs(start=baserev + 1):
1240 for r in cl.revs(start=baserev + 1):
1241 for p in cl.parentrevs(r):
1241 for p in cl.parentrevs(r):
1242 if p >= baserev:
1242 if p >= baserev:
1243 parentscount[p - baserev] += 1
1243 parentscount[p - baserev] += 1
1244 return subset.filter(lambda r: parentscount[r - baserev] > 1,
1244 return subset.filter(lambda r: parentscount[r - baserev] > 1,
1245 condrepr='<branchpoint>')
1245 condrepr='<branchpoint>')
1246
1246
1247 @predicate('min(set)', safe=True)
1247 @predicate('min(set)', safe=True)
1248 def minrev(repo, subset, x):
1248 def minrev(repo, subset, x):
1249 """Changeset with lowest revision number in set.
1249 """Changeset with lowest revision number in set.
1250 """
1250 """
1251 os = getset(repo, fullreposet(repo), x)
1251 os = getset(repo, fullreposet(repo), x)
1252 try:
1252 try:
1253 m = os.min()
1253 m = os.min()
1254 if m in subset:
1254 if m in subset:
1255 return baseset([m], datarepr=('<min %r, %r>', subset, os))
1255 return baseset([m], datarepr=('<min %r, %r>', subset, os))
1256 except ValueError:
1256 except ValueError:
1257 # os.min() throws a ValueError when the collection is empty.
1257 # os.min() throws a ValueError when the collection is empty.
1258 # Same as python's min().
1258 # Same as python's min().
1259 pass
1259 pass
1260 return baseset(datarepr=('<min %r, %r>', subset, os))
1260 return baseset(datarepr=('<min %r, %r>', subset, os))
1261
1261
1262 @predicate('modifies(pattern)', safe=True, weight=30)
1262 @predicate('modifies(pattern)', safe=True, weight=30)
1263 def modifies(repo, subset, x):
1263 def modifies(repo, subset, x):
1264 """Changesets modifying files matched by pattern.
1264 """Changesets modifying files matched by pattern.
1265
1265
1266 The pattern without explicit kind like ``glob:`` is expected to be
1266 The pattern without explicit kind like ``glob:`` is expected to be
1267 relative to the current directory and match against a file or a
1267 relative to the current directory and match against a file or a
1268 directory.
1268 directory.
1269 """
1269 """
1270 # i18n: "modifies" is a keyword
1270 # i18n: "modifies" is a keyword
1271 pat = getstring(x, _("modifies requires a pattern"))
1271 pat = getstring(x, _("modifies requires a pattern"))
1272 return checkstatus(repo, subset, pat, 0)
1272 return checkstatus(repo, subset, pat, 0)
1273
1273
1274 @predicate('named(namespace)')
1274 @predicate('named(namespace)')
1275 def named(repo, subset, x):
1275 def named(repo, subset, x):
1276 """The changesets in a given namespace.
1276 """The changesets in a given namespace.
1277
1277
1278 Pattern matching is supported for `namespace`. See
1278 Pattern matching is supported for `namespace`. See
1279 :hg:`help revisions.patterns`.
1279 :hg:`help revisions.patterns`.
1280 """
1280 """
1281 # i18n: "named" is a keyword
1281 # i18n: "named" is a keyword
1282 args = getargs(x, 1, 1, _('named requires a namespace argument'))
1282 args = getargs(x, 1, 1, _('named requires a namespace argument'))
1283
1283
1284 ns = getstring(args[0],
1284 ns = getstring(args[0],
1285 # i18n: "named" is a keyword
1285 # i18n: "named" is a keyword
1286 _('the argument to named must be a string'))
1286 _('the argument to named must be a string'))
1287 kind, pattern, matcher = util.stringmatcher(ns)
1287 kind, pattern, matcher = util.stringmatcher(ns)
1288 namespaces = set()
1288 namespaces = set()
1289 if kind == 'literal':
1289 if kind == 'literal':
1290 if pattern not in repo.names:
1290 if pattern not in repo.names:
1291 raise error.RepoLookupError(_("namespace '%s' does not exist")
1291 raise error.RepoLookupError(_("namespace '%s' does not exist")
1292 % ns)
1292 % ns)
1293 namespaces.add(repo.names[pattern])
1293 namespaces.add(repo.names[pattern])
1294 else:
1294 else:
1295 for name, ns in repo.names.iteritems():
1295 for name, ns in repo.names.iteritems():
1296 if matcher(name):
1296 if matcher(name):
1297 namespaces.add(ns)
1297 namespaces.add(ns)
1298 if not namespaces:
1298 if not namespaces:
1299 raise error.RepoLookupError(_("no namespace exists"
1299 raise error.RepoLookupError(_("no namespace exists"
1300 " that match '%s'") % pattern)
1300 " that match '%s'") % pattern)
1301
1301
1302 names = set()
1302 names = set()
1303 for ns in namespaces:
1303 for ns in namespaces:
1304 for name in ns.listnames(repo):
1304 for name in ns.listnames(repo):
1305 if name not in ns.deprecated:
1305 if name not in ns.deprecated:
1306 names.update(repo[n].rev() for n in ns.nodes(repo, name))
1306 names.update(repo[n].rev() for n in ns.nodes(repo, name))
1307
1307
1308 names -= {node.nullrev}
1308 names -= {node.nullrev}
1309 return subset & names
1309 return subset & names
1310
1310
1311 @predicate('id(string)', safe=True)
1311 @predicate('id(string)', safe=True)
1312 def node_(repo, subset, x):
1312 def node_(repo, subset, x):
1313 """Revision non-ambiguously specified by the given hex string prefix.
1313 """Revision non-ambiguously specified by the given hex string prefix.
1314 """
1314 """
1315 # i18n: "id" is a keyword
1315 # i18n: "id" is a keyword
1316 l = getargs(x, 1, 1, _("id requires one argument"))
1316 l = getargs(x, 1, 1, _("id requires one argument"))
1317 # i18n: "id" is a keyword
1317 # i18n: "id" is a keyword
1318 n = getstring(l[0], _("id requires a string"))
1318 n = getstring(l[0], _("id requires a string"))
1319 if len(n) == 40:
1319 if len(n) == 40:
1320 try:
1320 try:
1321 rn = repo.changelog.rev(node.bin(n))
1321 rn = repo.changelog.rev(node.bin(n))
1322 except error.WdirUnsupported:
1322 except error.WdirUnsupported:
1323 rn = node.wdirrev
1323 rn = node.wdirrev
1324 except (LookupError, TypeError):
1324 except (LookupError, TypeError):
1325 rn = None
1325 rn = None
1326 else:
1326 else:
1327 rn = None
1327 rn = None
1328 try:
1328 try:
1329 pm = repo.changelog._partialmatch(n)
1329 pm = repo.changelog._partialmatch(n)
1330 if pm is not None:
1330 if pm is not None:
1331 rn = repo.changelog.rev(pm)
1331 rn = repo.changelog.rev(pm)
1332 except error.WdirUnsupported:
1332 except error.WdirUnsupported:
1333 rn = node.wdirrev
1333 rn = node.wdirrev
1334
1334
1335 if rn is None:
1335 if rn is None:
1336 return baseset()
1336 return baseset()
1337 result = baseset([rn])
1337 result = baseset([rn])
1338 return result & subset
1338 return result & subset
1339
1339
1340 @predicate('obsolete()', safe=True)
1340 @predicate('obsolete()', safe=True)
1341 def obsolete(repo, subset, x):
1341 def obsolete(repo, subset, x):
1342 """Mutable changeset with a newer version."""
1342 """Mutable changeset with a newer version."""
1343 # i18n: "obsolete" is a keyword
1343 # i18n: "obsolete" is a keyword
1344 getargs(x, 0, 0, _("obsolete takes no arguments"))
1344 getargs(x, 0, 0, _("obsolete takes no arguments"))
1345 obsoletes = obsmod.getrevs(repo, 'obsolete')
1345 obsoletes = obsmod.getrevs(repo, 'obsolete')
1346 return subset & obsoletes
1346 return subset & obsoletes
1347
1347
1348 @predicate('only(set, [set])', safe=True)
1348 @predicate('only(set, [set])', safe=True)
1349 def only(repo, subset, x):
1349 def only(repo, subset, x):
1350 """Changesets that are ancestors of the first set that are not ancestors
1350 """Changesets that are ancestors of the first set that are not ancestors
1351 of any other head in the repo. If a second set is specified, the result
1351 of any other head in the repo. If a second set is specified, the result
1352 is ancestors of the first set that are not ancestors of the second set
1352 is ancestors of the first set that are not ancestors of the second set
1353 (i.e. ::<set1> - ::<set2>).
1353 (i.e. ::<set1> - ::<set2>).
1354 """
1354 """
1355 cl = repo.changelog
1355 cl = repo.changelog
1356 # i18n: "only" is a keyword
1356 # i18n: "only" is a keyword
1357 args = getargs(x, 1, 2, _('only takes one or two arguments'))
1357 args = getargs(x, 1, 2, _('only takes one or two arguments'))
1358 include = getset(repo, fullreposet(repo), args[0])
1358 include = getset(repo, fullreposet(repo), args[0])
1359 if len(args) == 1:
1359 if len(args) == 1:
1360 if not include:
1360 if not include:
1361 return baseset()
1361 return baseset()
1362
1362
1363 descendants = set(dagop.revdescendants(repo, include, False))
1363 descendants = set(dagop.revdescendants(repo, include, False))
1364 exclude = [rev for rev in cl.headrevs()
1364 exclude = [rev for rev in cl.headrevs()
1365 if not rev in descendants and not rev in include]
1365 if not rev in descendants and not rev in include]
1366 else:
1366 else:
1367 exclude = getset(repo, fullreposet(repo), args[1])
1367 exclude = getset(repo, fullreposet(repo), args[1])
1368
1368
1369 results = set(cl.findmissingrevs(common=exclude, heads=include))
1369 results = set(cl.findmissingrevs(common=exclude, heads=include))
1370 # XXX we should turn this into a baseset instead of a set, smartset may do
1370 # XXX we should turn this into a baseset instead of a set, smartset may do
1371 # some optimizations from the fact this is a baseset.
1371 # some optimizations from the fact this is a baseset.
1372 return subset & results
1372 return subset & results
1373
1373
1374 @predicate('origin([set])', safe=True)
1374 @predicate('origin([set])', safe=True)
1375 def origin(repo, subset, x):
1375 def origin(repo, subset, x):
1376 """
1376 """
1377 Changesets that were specified as a source for the grafts, transplants or
1377 Changesets that were specified as a source for the grafts, transplants or
1378 rebases that created the given revisions. Omitting the optional set is the
1378 rebases that created the given revisions. Omitting the optional set is the
1379 same as passing all(). If a changeset created by these operations is itself
1379 same as passing all(). If a changeset created by these operations is itself
1380 specified as a source for one of these operations, only the source changeset
1380 specified as a source for one of these operations, only the source changeset
1381 for the first operation is selected.
1381 for the first operation is selected.
1382 """
1382 """
1383 if x is not None:
1383 if x is not None:
1384 dests = getset(repo, fullreposet(repo), x)
1384 dests = getset(repo, fullreposet(repo), x)
1385 else:
1385 else:
1386 dests = fullreposet(repo)
1386 dests = fullreposet(repo)
1387
1387
1388 def _firstsrc(rev):
1388 def _firstsrc(rev):
1389 src = _getrevsource(repo, rev)
1389 src = _getrevsource(repo, rev)
1390 if src is None:
1390 if src is None:
1391 return None
1391 return None
1392
1392
1393 while True:
1393 while True:
1394 prev = _getrevsource(repo, src)
1394 prev = _getrevsource(repo, src)
1395
1395
1396 if prev is None:
1396 if prev is None:
1397 return src
1397 return src
1398 src = prev
1398 src = prev
1399
1399
1400 o = {_firstsrc(r) for r in dests}
1400 o = {_firstsrc(r) for r in dests}
1401 o -= {None}
1401 o -= {None}
1402 # XXX we should turn this into a baseset instead of a set, smartset may do
1402 # XXX we should turn this into a baseset instead of a set, smartset may do
1403 # some optimizations from the fact this is a baseset.
1403 # some optimizations from the fact this is a baseset.
1404 return subset & o
1404 return subset & o
1405
1405
1406 @predicate('outgoing([path])', safe=False, weight=10)
1406 @predicate('outgoing([path])', safe=False, weight=10)
1407 def outgoing(repo, subset, x):
1407 def outgoing(repo, subset, x):
1408 """Changesets not found in the specified destination repository, or the
1408 """Changesets not found in the specified destination repository, or the
1409 default push location.
1409 default push location.
1410 """
1410 """
1411 # Avoid cycles.
1411 # Avoid cycles.
1412 from . import (
1412 from . import (
1413 discovery,
1413 discovery,
1414 hg,
1414 hg,
1415 )
1415 )
1416 # i18n: "outgoing" is a keyword
1416 # i18n: "outgoing" is a keyword
1417 l = getargs(x, 0, 1, _("outgoing takes one or no arguments"))
1417 l = getargs(x, 0, 1, _("outgoing takes one or no arguments"))
1418 # i18n: "outgoing" is a keyword
1418 # i18n: "outgoing" is a keyword
1419 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
1419 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
1420 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
1420 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
1421 dest, branches = hg.parseurl(dest)
1421 dest, branches = hg.parseurl(dest)
1422 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1422 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1423 if revs:
1423 if revs:
1424 revs = [repo.lookup(rev) for rev in revs]
1424 revs = [repo.lookup(rev) for rev in revs]
1425 other = hg.peer(repo, {}, dest)
1425 other = hg.peer(repo, {}, dest)
1426 repo.ui.pushbuffer()
1426 repo.ui.pushbuffer()
1427 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
1427 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
1428 repo.ui.popbuffer()
1428 repo.ui.popbuffer()
1429 cl = repo.changelog
1429 cl = repo.changelog
1430 o = {cl.rev(r) for r in outgoing.missing}
1430 o = {cl.rev(r) for r in outgoing.missing}
1431 return subset & o
1431 return subset & o
1432
1432
1433 @predicate('p1([set])', safe=True)
1433 @predicate('p1([set])', safe=True)
1434 def p1(repo, subset, x):
1434 def p1(repo, subset, x):
1435 """First parent of changesets in set, or the working directory.
1435 """First parent of changesets in set, or the working directory.
1436 """
1436 """
1437 if x is None:
1437 if x is None:
1438 p = repo[x].p1().rev()
1438 p = repo[x].p1().rev()
1439 if p >= 0:
1439 if p >= 0:
1440 return subset & baseset([p])
1440 return subset & baseset([p])
1441 return baseset()
1441 return baseset()
1442
1442
1443 ps = set()
1443 ps = set()
1444 cl = repo.changelog
1444 cl = repo.changelog
1445 for r in getset(repo, fullreposet(repo), x):
1445 for r in getset(repo, fullreposet(repo), x):
1446 try:
1446 try:
1447 ps.add(cl.parentrevs(r)[0])
1447 ps.add(cl.parentrevs(r)[0])
1448 except error.WdirUnsupported:
1448 except error.WdirUnsupported:
1449 ps.add(repo[r].parents()[0].rev())
1449 ps.add(repo[r].parents()[0].rev())
1450 ps -= {node.nullrev}
1450 ps -= {node.nullrev}
1451 # XXX we should turn this into a baseset instead of a set, smartset may do
1451 # XXX we should turn this into a baseset instead of a set, smartset may do
1452 # some optimizations from the fact this is a baseset.
1452 # some optimizations from the fact this is a baseset.
1453 return subset & ps
1453 return subset & ps
1454
1454
1455 @predicate('p2([set])', safe=True)
1455 @predicate('p2([set])', safe=True)
1456 def p2(repo, subset, x):
1456 def p2(repo, subset, x):
1457 """Second parent of changesets in set, or the working directory.
1457 """Second parent of changesets in set, or the working directory.
1458 """
1458 """
1459 if x is None:
1459 if x is None:
1460 ps = repo[x].parents()
1460 ps = repo[x].parents()
1461 try:
1461 try:
1462 p = ps[1].rev()
1462 p = ps[1].rev()
1463 if p >= 0:
1463 if p >= 0:
1464 return subset & baseset([p])
1464 return subset & baseset([p])
1465 return baseset()
1465 return baseset()
1466 except IndexError:
1466 except IndexError:
1467 return baseset()
1467 return baseset()
1468
1468
1469 ps = set()
1469 ps = set()
1470 cl = repo.changelog
1470 cl = repo.changelog
1471 for r in getset(repo, fullreposet(repo), x):
1471 for r in getset(repo, fullreposet(repo), x):
1472 try:
1472 try:
1473 ps.add(cl.parentrevs(r)[1])
1473 ps.add(cl.parentrevs(r)[1])
1474 except error.WdirUnsupported:
1474 except error.WdirUnsupported:
1475 parents = repo[r].parents()
1475 parents = repo[r].parents()
1476 if len(parents) == 2:
1476 if len(parents) == 2:
1477 ps.add(parents[1])
1477 ps.add(parents[1])
1478 ps -= {node.nullrev}
1478 ps -= {node.nullrev}
1479 # XXX we should turn this into a baseset instead of a set, smartset may do
1479 # XXX we should turn this into a baseset instead of a set, smartset may do
1480 # some optimizations from the fact this is a baseset.
1480 # some optimizations from the fact this is a baseset.
1481 return subset & ps
1481 return subset & ps
1482
1482
1483 def parentpost(repo, subset, x, order):
1483 def parentpost(repo, subset, x, order):
1484 return p1(repo, subset, x)
1484 return p1(repo, subset, x)
1485
1485
1486 @predicate('parents([set])', safe=True)
1486 @predicate('parents([set])', safe=True)
1487 def parents(repo, subset, x):
1487 def parents(repo, subset, x):
1488 """
1488 """
1489 The set of all parents for all changesets in set, or the working directory.
1489 The set of all parents for all changesets in set, or the working directory.
1490 """
1490 """
1491 if x is None:
1491 if x is None:
1492 ps = set(p.rev() for p in repo[x].parents())
1492 ps = set(p.rev() for p in repo[x].parents())
1493 else:
1493 else:
1494 ps = set()
1494 ps = set()
1495 cl = repo.changelog
1495 cl = repo.changelog
1496 up = ps.update
1496 up = ps.update
1497 parentrevs = cl.parentrevs
1497 parentrevs = cl.parentrevs
1498 for r in getset(repo, fullreposet(repo), x):
1498 for r in getset(repo, fullreposet(repo), x):
1499 try:
1499 try:
1500 up(parentrevs(r))
1500 up(parentrevs(r))
1501 except error.WdirUnsupported:
1501 except error.WdirUnsupported:
1502 up(p.rev() for p in repo[r].parents())
1502 up(p.rev() for p in repo[r].parents())
1503 ps -= {node.nullrev}
1503 ps -= {node.nullrev}
1504 return subset & ps
1504 return subset & ps
1505
1505
1506 def _phase(repo, subset, *targets):
1506 def _phase(repo, subset, *targets):
1507 """helper to select all rev in <targets> phases"""
1507 """helper to select all rev in <targets> phases"""
1508 s = repo._phasecache.getrevset(repo, targets)
1508 s = repo._phasecache.getrevset(repo, targets)
1509 return subset & s
1509 return subset & s
1510
1510
1511 @predicate('draft()', safe=True)
1511 @predicate('draft()', safe=True)
1512 def draft(repo, subset, x):
1512 def draft(repo, subset, x):
1513 """Changeset in draft phase."""
1513 """Changeset in draft phase."""
1514 # i18n: "draft" is a keyword
1514 # i18n: "draft" is a keyword
1515 getargs(x, 0, 0, _("draft takes no arguments"))
1515 getargs(x, 0, 0, _("draft takes no arguments"))
1516 target = phases.draft
1516 target = phases.draft
1517 return _phase(repo, subset, target)
1517 return _phase(repo, subset, target)
1518
1518
1519 @predicate('secret()', safe=True)
1519 @predicate('secret()', safe=True)
1520 def secret(repo, subset, x):
1520 def secret(repo, subset, x):
1521 """Changeset in secret phase."""
1521 """Changeset in secret phase."""
1522 # i18n: "secret" is a keyword
1522 # i18n: "secret" is a keyword
1523 getargs(x, 0, 0, _("secret takes no arguments"))
1523 getargs(x, 0, 0, _("secret takes no arguments"))
1524 target = phases.secret
1524 target = phases.secret
1525 return _phase(repo, subset, target)
1525 return _phase(repo, subset, target)
1526
1526
1527 def parentspec(repo, subset, x, n, order):
1527 def parentspec(repo, subset, x, n, order):
1528 """``set^0``
1528 """``set^0``
1529 The set.
1529 The set.
1530 ``set^1`` (or ``set^``), ``set^2``
1530 ``set^1`` (or ``set^``), ``set^2``
1531 First or second parent, respectively, of all changesets in set.
1531 First or second parent, respectively, of all changesets in set.
1532 """
1532 """
1533 try:
1533 try:
1534 n = int(n[1])
1534 n = int(n[1])
1535 if n not in (0, 1, 2):
1535 if n not in (0, 1, 2):
1536 raise ValueError
1536 raise ValueError
1537 except (TypeError, ValueError):
1537 except (TypeError, ValueError):
1538 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
1538 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
1539 ps = set()
1539 ps = set()
1540 cl = repo.changelog
1540 cl = repo.changelog
1541 for r in getset(repo, fullreposet(repo), x):
1541 for r in getset(repo, fullreposet(repo), x):
1542 if n == 0:
1542 if n == 0:
1543 ps.add(r)
1543 ps.add(r)
1544 elif n == 1:
1544 elif n == 1:
1545 try:
1545 try:
1546 ps.add(cl.parentrevs(r)[0])
1546 ps.add(cl.parentrevs(r)[0])
1547 except error.WdirUnsupported:
1547 except error.WdirUnsupported:
1548 ps.add(repo[r].parents()[0].rev())
1548 ps.add(repo[r].parents()[0].rev())
1549 else:
1549 else:
1550 try:
1550 try:
1551 parents = cl.parentrevs(r)
1551 parents = cl.parentrevs(r)
1552 if parents[1] != node.nullrev:
1552 if parents[1] != node.nullrev:
1553 ps.add(parents[1])
1553 ps.add(parents[1])
1554 except error.WdirUnsupported:
1554 except error.WdirUnsupported:
1555 parents = repo[r].parents()
1555 parents = repo[r].parents()
1556 if len(parents) == 2:
1556 if len(parents) == 2:
1557 ps.add(parents[1].rev())
1557 ps.add(parents[1].rev())
1558 return subset & ps
1558 return subset & ps
1559
1559
1560 @predicate('present(set)', safe=True, takeorder=True)
1560 @predicate('present(set)', safe=True, takeorder=True)
1561 def present(repo, subset, x, order):
1561 def present(repo, subset, x, order):
1562 """An empty set, if any revision in set isn't found; otherwise,
1562 """An empty set, if any revision in set isn't found; otherwise,
1563 all revisions in set.
1563 all revisions in set.
1564
1564
1565 If any of specified revisions is not present in the local repository,
1565 If any of specified revisions is not present in the local repository,
1566 the query is normally aborted. But this predicate allows the query
1566 the query is normally aborted. But this predicate allows the query
1567 to continue even in such cases.
1567 to continue even in such cases.
1568 """
1568 """
1569 try:
1569 try:
1570 return getset(repo, subset, x, order)
1570 return getset(repo, subset, x, order)
1571 except error.RepoLookupError:
1571 except error.RepoLookupError:
1572 return baseset()
1572 return baseset()
1573
1573
1574 # for internal use
1574 # for internal use
1575 @predicate('_notpublic', safe=True)
1575 @predicate('_notpublic', safe=True)
1576 def _notpublic(repo, subset, x):
1576 def _notpublic(repo, subset, x):
1577 getargs(x, 0, 0, "_notpublic takes no arguments")
1577 getargs(x, 0, 0, "_notpublic takes no arguments")
1578 return _phase(repo, subset, phases.draft, phases.secret)
1578 return _phase(repo, subset, phases.draft, phases.secret)
1579
1579
1580 # for internal use
1580 # for internal use
1581 @predicate('_phaseandancestors(phasename, set)', safe=True)
1581 @predicate('_phaseandancestors(phasename, set)', safe=True)
1582 def _phaseandancestors(repo, subset, x):
1582 def _phaseandancestors(repo, subset, x):
1583 # equivalent to (phasename() & ancestors(set)) but more efficient
1583 # equivalent to (phasename() & ancestors(set)) but more efficient
1584 # phasename could be one of 'draft', 'secret', or '_notpublic'
1584 # phasename could be one of 'draft', 'secret', or '_notpublic'
1585 args = getargs(x, 2, 2, "_phaseandancestors requires two arguments")
1585 args = getargs(x, 2, 2, "_phaseandancestors requires two arguments")
1586 phasename = getsymbol(args[0])
1586 phasename = getsymbol(args[0])
1587 s = getset(repo, fullreposet(repo), args[1])
1587 s = getset(repo, fullreposet(repo), args[1])
1588
1588
1589 draft = phases.draft
1589 draft = phases.draft
1590 secret = phases.secret
1590 secret = phases.secret
1591 phasenamemap = {
1591 phasenamemap = {
1592 '_notpublic': draft,
1592 '_notpublic': draft,
1593 'draft': draft, # follow secret's ancestors
1593 'draft': draft, # follow secret's ancestors
1594 'secret': secret,
1594 'secret': secret,
1595 }
1595 }
1596 if phasename not in phasenamemap:
1596 if phasename not in phasenamemap:
1597 raise error.ParseError('%r is not a valid phasename' % phasename)
1597 raise error.ParseError('%r is not a valid phasename' % phasename)
1598
1598
1599 minimalphase = phasenamemap[phasename]
1599 minimalphase = phasenamemap[phasename]
1600 getphase = repo._phasecache.phase
1600 getphase = repo._phasecache.phase
1601
1601
1602 def cutfunc(rev):
1602 def cutfunc(rev):
1603 return getphase(repo, rev) < minimalphase
1603 return getphase(repo, rev) < minimalphase
1604
1604
1605 revs = dagop.revancestors(repo, s, cutfunc=cutfunc)
1605 revs = dagop.revancestors(repo, s, cutfunc=cutfunc)
1606
1606
1607 if phasename == 'draft': # need to remove secret changesets
1607 if phasename == 'draft': # need to remove secret changesets
1608 revs = revs.filter(lambda r: getphase(repo, r) == draft)
1608 revs = revs.filter(lambda r: getphase(repo, r) == draft)
1609 return subset & revs
1609 return subset & revs
1610
1610
1611 @predicate('public()', safe=True)
1611 @predicate('public()', safe=True)
1612 def public(repo, subset, x):
1612 def public(repo, subset, x):
1613 """Changeset in public phase."""
1613 """Changeset in public phase."""
1614 # i18n: "public" is a keyword
1614 # i18n: "public" is a keyword
1615 getargs(x, 0, 0, _("public takes no arguments"))
1615 getargs(x, 0, 0, _("public takes no arguments"))
1616 phase = repo._phasecache.phase
1616 phase = repo._phasecache.phase
1617 target = phases.public
1617 target = phases.public
1618 condition = lambda r: phase(repo, r) == target
1618 condition = lambda r: phase(repo, r) == target
1619 return subset.filter(condition, condrepr=('<phase %r>', target),
1619 return subset.filter(condition, condrepr=('<phase %r>', target),
1620 cache=False)
1620 cache=False)
1621
1621
1622 @predicate('remote([id [,path]])', safe=False)
1622 @predicate('remote([id [,path]])', safe=False)
1623 def remote(repo, subset, x):
1623 def remote(repo, subset, x):
1624 """Local revision that corresponds to the given identifier in a
1624 """Local revision that corresponds to the given identifier in a
1625 remote repository, if present. Here, the '.' identifier is a
1625 remote repository, if present. Here, the '.' identifier is a
1626 synonym for the current local branch.
1626 synonym for the current local branch.
1627 """
1627 """
1628
1628
1629 from . import hg # avoid start-up nasties
1629 from . import hg # avoid start-up nasties
1630 # i18n: "remote" is a keyword
1630 # i18n: "remote" is a keyword
1631 l = getargs(x, 0, 2, _("remote takes zero, one, or two arguments"))
1631 l = getargs(x, 0, 2, _("remote takes zero, one, or two arguments"))
1632
1632
1633 q = '.'
1633 q = '.'
1634 if len(l) > 0:
1634 if len(l) > 0:
1635 # i18n: "remote" is a keyword
1635 # i18n: "remote" is a keyword
1636 q = getstring(l[0], _("remote requires a string id"))
1636 q = getstring(l[0], _("remote requires a string id"))
1637 if q == '.':
1637 if q == '.':
1638 q = repo['.'].branch()
1638 q = repo['.'].branch()
1639
1639
1640 dest = ''
1640 dest = ''
1641 if len(l) > 1:
1641 if len(l) > 1:
1642 # i18n: "remote" is a keyword
1642 # i18n: "remote" is a keyword
1643 dest = getstring(l[1], _("remote requires a repository path"))
1643 dest = getstring(l[1], _("remote requires a repository path"))
1644 dest = repo.ui.expandpath(dest or 'default')
1644 dest = repo.ui.expandpath(dest or 'default')
1645 dest, branches = hg.parseurl(dest)
1645 dest, branches = hg.parseurl(dest)
1646 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1646 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1647 if revs:
1647 if revs:
1648 revs = [repo.lookup(rev) for rev in revs]
1648 revs = [repo.lookup(rev) for rev in revs]
1649 other = hg.peer(repo, {}, dest)
1649 other = hg.peer(repo, {}, dest)
1650 n = other.lookup(q)
1650 n = other.lookup(q)
1651 if n in repo:
1651 if n in repo:
1652 r = repo[n].rev()
1652 r = repo[n].rev()
1653 if r in subset:
1653 if r in subset:
1654 return baseset([r])
1654 return baseset([r])
1655 return baseset()
1655 return baseset()
1656
1656
1657 @predicate('removes(pattern)', safe=True, weight=30)
1657 @predicate('removes(pattern)', safe=True, weight=30)
1658 def removes(repo, subset, x):
1658 def removes(repo, subset, x):
1659 """Changesets which remove files matching pattern.
1659 """Changesets which remove files matching pattern.
1660
1660
1661 The pattern without explicit kind like ``glob:`` is expected to be
1661 The pattern without explicit kind like ``glob:`` is expected to be
1662 relative to the current directory and match against a file or a
1662 relative to the current directory and match against a file or a
1663 directory.
1663 directory.
1664 """
1664 """
1665 # i18n: "removes" is a keyword
1665 # i18n: "removes" is a keyword
1666 pat = getstring(x, _("removes requires a pattern"))
1666 pat = getstring(x, _("removes requires a pattern"))
1667 return checkstatus(repo, subset, pat, 2)
1667 return checkstatus(repo, subset, pat, 2)
1668
1668
1669 @predicate('rev(number)', safe=True)
1669 @predicate('rev(number)', safe=True)
1670 def rev(repo, subset, x):
1670 def rev(repo, subset, x):
1671 """Revision with the given numeric identifier.
1671 """Revision with the given numeric identifier.
1672 """
1672 """
1673 # i18n: "rev" is a keyword
1673 # i18n: "rev" is a keyword
1674 l = getargs(x, 1, 1, _("rev requires one argument"))
1674 l = getargs(x, 1, 1, _("rev requires one argument"))
1675 try:
1675 try:
1676 # i18n: "rev" is a keyword
1676 # i18n: "rev" is a keyword
1677 l = int(getstring(l[0], _("rev requires a number")))
1677 l = int(getstring(l[0], _("rev requires a number")))
1678 except (TypeError, ValueError):
1678 except (TypeError, ValueError):
1679 # i18n: "rev" is a keyword
1679 # i18n: "rev" is a keyword
1680 raise error.ParseError(_("rev expects a number"))
1680 raise error.ParseError(_("rev expects a number"))
1681 if l not in repo.changelog and l not in (node.nullrev, node.wdirrev):
1681 if l not in repo.changelog and l not in (node.nullrev, node.wdirrev):
1682 return baseset()
1682 return baseset()
1683 return subset & baseset([l])
1683 return subset & baseset([l])
1684
1684
1685 @predicate('matching(revision [, field])', safe=True)
1685 @predicate('matching(revision [, field])', safe=True)
1686 def matching(repo, subset, x):
1686 def matching(repo, subset, x):
1687 """Changesets in which a given set of fields match the set of fields in the
1687 """Changesets in which a given set of fields match the set of fields in the
1688 selected revision or set.
1688 selected revision or set.
1689
1689
1690 To match more than one field pass the list of fields to match separated
1690 To match more than one field pass the list of fields to match separated
1691 by spaces (e.g. ``author description``).
1691 by spaces (e.g. ``author description``).
1692
1692
1693 Valid fields are most regular revision fields and some special fields.
1693 Valid fields are most regular revision fields and some special fields.
1694
1694
1695 Regular revision fields are ``description``, ``author``, ``branch``,
1695 Regular revision fields are ``description``, ``author``, ``branch``,
1696 ``date``, ``files``, ``phase``, ``parents``, ``substate``, ``user``
1696 ``date``, ``files``, ``phase``, ``parents``, ``substate``, ``user``
1697 and ``diff``.
1697 and ``diff``.
1698 Note that ``author`` and ``user`` are synonyms. ``diff`` refers to the
1698 Note that ``author`` and ``user`` are synonyms. ``diff`` refers to the
1699 contents of the revision. Two revisions matching their ``diff`` will
1699 contents of the revision. Two revisions matching their ``diff`` will
1700 also match their ``files``.
1700 also match their ``files``.
1701
1701
1702 Special fields are ``summary`` and ``metadata``:
1702 Special fields are ``summary`` and ``metadata``:
1703 ``summary`` matches the first line of the description.
1703 ``summary`` matches the first line of the description.
1704 ``metadata`` is equivalent to matching ``description user date``
1704 ``metadata`` is equivalent to matching ``description user date``
1705 (i.e. it matches the main metadata fields).
1705 (i.e. it matches the main metadata fields).
1706
1706
1707 ``metadata`` is the default field which is used when no fields are
1707 ``metadata`` is the default field which is used when no fields are
1708 specified. You can match more than one field at a time.
1708 specified. You can match more than one field at a time.
1709 """
1709 """
1710 # i18n: "matching" is a keyword
1710 # i18n: "matching" is a keyword
1711 l = getargs(x, 1, 2, _("matching takes 1 or 2 arguments"))
1711 l = getargs(x, 1, 2, _("matching takes 1 or 2 arguments"))
1712
1712
1713 revs = getset(repo, fullreposet(repo), l[0])
1713 revs = getset(repo, fullreposet(repo), l[0])
1714
1714
1715 fieldlist = ['metadata']
1715 fieldlist = ['metadata']
1716 if len(l) > 1:
1716 if len(l) > 1:
1717 fieldlist = getstring(l[1],
1717 fieldlist = getstring(l[1],
1718 # i18n: "matching" is a keyword
1718 # i18n: "matching" is a keyword
1719 _("matching requires a string "
1719 _("matching requires a string "
1720 "as its second argument")).split()
1720 "as its second argument")).split()
1721
1721
1722 # Make sure that there are no repeated fields,
1722 # Make sure that there are no repeated fields,
1723 # expand the 'special' 'metadata' field type
1723 # expand the 'special' 'metadata' field type
1724 # and check the 'files' whenever we check the 'diff'
1724 # and check the 'files' whenever we check the 'diff'
1725 fields = []
1725 fields = []
1726 for field in fieldlist:
1726 for field in fieldlist:
1727 if field == 'metadata':
1727 if field == 'metadata':
1728 fields += ['user', 'description', 'date']
1728 fields += ['user', 'description', 'date']
1729 elif field == 'diff':
1729 elif field == 'diff':
1730 # a revision matching the diff must also match the files
1730 # a revision matching the diff must also match the files
1731 # since matching the diff is very costly, make sure to
1731 # since matching the diff is very costly, make sure to
1732 # also match the files first
1732 # also match the files first
1733 fields += ['files', 'diff']
1733 fields += ['files', 'diff']
1734 else:
1734 else:
1735 if field == 'author':
1735 if field == 'author':
1736 field = 'user'
1736 field = 'user'
1737 fields.append(field)
1737 fields.append(field)
1738 fields = set(fields)
1738 fields = set(fields)
1739 if 'summary' in fields and 'description' in fields:
1739 if 'summary' in fields and 'description' in fields:
1740 # If a revision matches its description it also matches its summary
1740 # If a revision matches its description it also matches its summary
1741 fields.discard('summary')
1741 fields.discard('summary')
1742
1742
1743 # We may want to match more than one field
1743 # We may want to match more than one field
1744 # Not all fields take the same amount of time to be matched
1744 # Not all fields take the same amount of time to be matched
1745 # Sort the selected fields in order of increasing matching cost
1745 # Sort the selected fields in order of increasing matching cost
1746 fieldorder = ['phase', 'parents', 'user', 'date', 'branch', 'summary',
1746 fieldorder = ['phase', 'parents', 'user', 'date', 'branch', 'summary',
1747 'files', 'description', 'substate', 'diff']
1747 'files', 'description', 'substate', 'diff']
1748 def fieldkeyfunc(f):
1748 def fieldkeyfunc(f):
1749 try:
1749 try:
1750 return fieldorder.index(f)
1750 return fieldorder.index(f)
1751 except ValueError:
1751 except ValueError:
1752 # assume an unknown field is very costly
1752 # assume an unknown field is very costly
1753 return len(fieldorder)
1753 return len(fieldorder)
1754 fields = list(fields)
1754 fields = list(fields)
1755 fields.sort(key=fieldkeyfunc)
1755 fields.sort(key=fieldkeyfunc)
1756
1756
1757 # Each field will be matched with its own "getfield" function
1757 # Each field will be matched with its own "getfield" function
1758 # which will be added to the getfieldfuncs array of functions
1758 # which will be added to the getfieldfuncs array of functions
1759 getfieldfuncs = []
1759 getfieldfuncs = []
1760 _funcs = {
1760 _funcs = {
1761 'user': lambda r: repo[r].user(),
1761 'user': lambda r: repo[r].user(),
1762 'branch': lambda r: repo[r].branch(),
1762 'branch': lambda r: repo[r].branch(),
1763 'date': lambda r: repo[r].date(),
1763 'date': lambda r: repo[r].date(),
1764 'description': lambda r: repo[r].description(),
1764 'description': lambda r: repo[r].description(),
1765 'files': lambda r: repo[r].files(),
1765 'files': lambda r: repo[r].files(),
1766 'parents': lambda r: repo[r].parents(),
1766 'parents': lambda r: repo[r].parents(),
1767 'phase': lambda r: repo[r].phase(),
1767 'phase': lambda r: repo[r].phase(),
1768 'substate': lambda r: repo[r].substate,
1768 'substate': lambda r: repo[r].substate,
1769 'summary': lambda r: repo[r].description().splitlines()[0],
1769 'summary': lambda r: repo[r].description().splitlines()[0],
1770 'diff': lambda r: list(repo[r].diff(git=True),)
1770 'diff': lambda r: list(repo[r].diff(git=True),)
1771 }
1771 }
1772 for info in fields:
1772 for info in fields:
1773 getfield = _funcs.get(info, None)
1773 getfield = _funcs.get(info, None)
1774 if getfield is None:
1774 if getfield is None:
1775 raise error.ParseError(
1775 raise error.ParseError(
1776 # i18n: "matching" is a keyword
1776 # i18n: "matching" is a keyword
1777 _("unexpected field name passed to matching: %s") % info)
1777 _("unexpected field name passed to matching: %s") % info)
1778 getfieldfuncs.append(getfield)
1778 getfieldfuncs.append(getfield)
1779 # convert the getfield array of functions into a "getinfo" function
1779 # convert the getfield array of functions into a "getinfo" function
1780 # which returns an array of field values (or a single value if there
1780 # which returns an array of field values (or a single value if there
1781 # is only one field to match)
1781 # is only one field to match)
1782 getinfo = lambda r: [f(r) for f in getfieldfuncs]
1782 getinfo = lambda r: [f(r) for f in getfieldfuncs]
1783
1783
1784 def matches(x):
1784 def matches(x):
1785 for rev in revs:
1785 for rev in revs:
1786 target = getinfo(rev)
1786 target = getinfo(rev)
1787 match = True
1787 match = True
1788 for n, f in enumerate(getfieldfuncs):
1788 for n, f in enumerate(getfieldfuncs):
1789 if target[n] != f(x):
1789 if target[n] != f(x):
1790 match = False
1790 match = False
1791 if match:
1791 if match:
1792 return True
1792 return True
1793 return False
1793 return False
1794
1794
1795 return subset.filter(matches, condrepr=('<matching%r %r>', fields, revs))
1795 return subset.filter(matches, condrepr=('<matching%r %r>', fields, revs))
1796
1796
1797 @predicate('reverse(set)', safe=True, takeorder=True, weight=0)
1797 @predicate('reverse(set)', safe=True, takeorder=True, weight=0)
1798 def reverse(repo, subset, x, order):
1798 def reverse(repo, subset, x, order):
1799 """Reverse order of set.
1799 """Reverse order of set.
1800 """
1800 """
1801 l = getset(repo, subset, x, order)
1801 l = getset(repo, subset, x, order)
1802 if order == defineorder:
1802 if order == defineorder:
1803 l.reverse()
1803 l.reverse()
1804 return l
1804 return l
1805
1805
1806 @predicate('roots(set)', safe=True)
1806 @predicate('roots(set)', safe=True)
1807 def roots(repo, subset, x):
1807 def roots(repo, subset, x):
1808 """Changesets in set with no parent changeset in set.
1808 """Changesets in set with no parent changeset in set.
1809 """
1809 """
1810 s = getset(repo, fullreposet(repo), x)
1810 s = getset(repo, fullreposet(repo), x)
1811 parents = repo.changelog.parentrevs
1811 parents = repo.changelog.parentrevs
1812 def filter(r):
1812 def filter(r):
1813 for p in parents(r):
1813 for p in parents(r):
1814 if 0 <= p and p in s:
1814 if 0 <= p and p in s:
1815 return False
1815 return False
1816 return True
1816 return True
1817 return subset & s.filter(filter, condrepr='<roots>')
1817 return subset & s.filter(filter, condrepr='<roots>')
1818
1818
1819 _sortkeyfuncs = {
1819 _sortkeyfuncs = {
1820 'rev': lambda c: c.rev(),
1820 'rev': lambda c: c.rev(),
1821 'branch': lambda c: c.branch(),
1821 'branch': lambda c: c.branch(),
1822 'desc': lambda c: c.description(),
1822 'desc': lambda c: c.description(),
1823 'user': lambda c: c.user(),
1823 'user': lambda c: c.user(),
1824 'author': lambda c: c.user(),
1824 'author': lambda c: c.user(),
1825 'date': lambda c: c.date()[0],
1825 'date': lambda c: c.date()[0],
1826 }
1826 }
1827
1827
1828 def _getsortargs(x):
1828 def _getsortargs(x):
1829 """Parse sort options into (set, [(key, reverse)], opts)"""
1829 """Parse sort options into (set, [(key, reverse)], opts)"""
1830 args = getargsdict(x, 'sort', 'set keys topo.firstbranch')
1830 args = getargsdict(x, 'sort', 'set keys topo.firstbranch')
1831 if 'set' not in args:
1831 if 'set' not in args:
1832 # i18n: "sort" is a keyword
1832 # i18n: "sort" is a keyword
1833 raise error.ParseError(_('sort requires one or two arguments'))
1833 raise error.ParseError(_('sort requires one or two arguments'))
1834 keys = "rev"
1834 keys = "rev"
1835 if 'keys' in args:
1835 if 'keys' in args:
1836 # i18n: "sort" is a keyword
1836 # i18n: "sort" is a keyword
1837 keys = getstring(args['keys'], _("sort spec must be a string"))
1837 keys = getstring(args['keys'], _("sort spec must be a string"))
1838
1838
1839 keyflags = []
1839 keyflags = []
1840 for k in keys.split():
1840 for k in keys.split():
1841 fk = k
1841 fk = k
1842 reverse = (k[0] == '-')
1842 reverse = (k[0] == '-')
1843 if reverse:
1843 if reverse:
1844 k = k[1:]
1844 k = k[1:]
1845 if k not in _sortkeyfuncs and k != 'topo':
1845 if k not in _sortkeyfuncs and k != 'topo':
1846 raise error.ParseError(_("unknown sort key %r") % fk)
1846 raise error.ParseError(_("unknown sort key %r") % fk)
1847 keyflags.append((k, reverse))
1847 keyflags.append((k, reverse))
1848
1848
1849 if len(keyflags) > 1 and any(k == 'topo' for k, reverse in keyflags):
1849 if len(keyflags) > 1 and any(k == 'topo' for k, reverse in keyflags):
1850 # i18n: "topo" is a keyword
1850 # i18n: "topo" is a keyword
1851 raise error.ParseError(_('topo sort order cannot be combined '
1851 raise error.ParseError(_('topo sort order cannot be combined '
1852 'with other sort keys'))
1852 'with other sort keys'))
1853
1853
1854 opts = {}
1854 opts = {}
1855 if 'topo.firstbranch' in args:
1855 if 'topo.firstbranch' in args:
1856 if any(k == 'topo' for k, reverse in keyflags):
1856 if any(k == 'topo' for k, reverse in keyflags):
1857 opts['topo.firstbranch'] = args['topo.firstbranch']
1857 opts['topo.firstbranch'] = args['topo.firstbranch']
1858 else:
1858 else:
1859 # i18n: "topo" and "topo.firstbranch" are keywords
1859 # i18n: "topo" and "topo.firstbranch" are keywords
1860 raise error.ParseError(_('topo.firstbranch can only be used '
1860 raise error.ParseError(_('topo.firstbranch can only be used '
1861 'when using the topo sort key'))
1861 'when using the topo sort key'))
1862
1862
1863 return args['set'], keyflags, opts
1863 return args['set'], keyflags, opts
1864
1864
1865 @predicate('sort(set[, [-]key... [, ...]])', safe=True, takeorder=True,
1865 @predicate('sort(set[, [-]key... [, ...]])', safe=True, takeorder=True,
1866 weight=10)
1866 weight=10)
1867 def sort(repo, subset, x, order):
1867 def sort(repo, subset, x, order):
1868 """Sort set by keys. The default sort order is ascending, specify a key
1868 """Sort set by keys. The default sort order is ascending, specify a key
1869 as ``-key`` to sort in descending order.
1869 as ``-key`` to sort in descending order.
1870
1870
1871 The keys can be:
1871 The keys can be:
1872
1872
1873 - ``rev`` for the revision number,
1873 - ``rev`` for the revision number,
1874 - ``branch`` for the branch name,
1874 - ``branch`` for the branch name,
1875 - ``desc`` for the commit message (description),
1875 - ``desc`` for the commit message (description),
1876 - ``user`` for user name (``author`` can be used as an alias),
1876 - ``user`` for user name (``author`` can be used as an alias),
1877 - ``date`` for the commit date
1877 - ``date`` for the commit date
1878 - ``topo`` for a reverse topographical sort
1878 - ``topo`` for a reverse topographical sort
1879
1879
1880 The ``topo`` sort order cannot be combined with other sort keys. This sort
1880 The ``topo`` sort order cannot be combined with other sort keys. This sort
1881 takes one optional argument, ``topo.firstbranch``, which takes a revset that
1881 takes one optional argument, ``topo.firstbranch``, which takes a revset that
1882 specifies what topographical branches to prioritize in the sort.
1882 specifies what topographical branches to prioritize in the sort.
1883
1883
1884 """
1884 """
1885 s, keyflags, opts = _getsortargs(x)
1885 s, keyflags, opts = _getsortargs(x)
1886 revs = getset(repo, subset, s, order)
1886 revs = getset(repo, subset, s, order)
1887
1887
1888 if not keyflags or order != defineorder:
1888 if not keyflags or order != defineorder:
1889 return revs
1889 return revs
1890 if len(keyflags) == 1 and keyflags[0][0] == "rev":
1890 if len(keyflags) == 1 and keyflags[0][0] == "rev":
1891 revs.sort(reverse=keyflags[0][1])
1891 revs.sort(reverse=keyflags[0][1])
1892 return revs
1892 return revs
1893 elif keyflags[0][0] == "topo":
1893 elif keyflags[0][0] == "topo":
1894 firstbranch = ()
1894 firstbranch = ()
1895 if 'topo.firstbranch' in opts:
1895 if 'topo.firstbranch' in opts:
1896 firstbranch = getset(repo, subset, opts['topo.firstbranch'])
1896 firstbranch = getset(repo, subset, opts['topo.firstbranch'])
1897 revs = baseset(dagop.toposort(revs, repo.changelog.parentrevs,
1897 revs = baseset(dagop.toposort(revs, repo.changelog.parentrevs,
1898 firstbranch),
1898 firstbranch),
1899 istopo=True)
1899 istopo=True)
1900 if keyflags[0][1]:
1900 if keyflags[0][1]:
1901 revs.reverse()
1901 revs.reverse()
1902 return revs
1902 return revs
1903
1903
1904 # sort() is guaranteed to be stable
1904 # sort() is guaranteed to be stable
1905 ctxs = [repo[r] for r in revs]
1905 ctxs = [repo[r] for r in revs]
1906 for k, reverse in reversed(keyflags):
1906 for k, reverse in reversed(keyflags):
1907 ctxs.sort(key=_sortkeyfuncs[k], reverse=reverse)
1907 ctxs.sort(key=_sortkeyfuncs[k], reverse=reverse)
1908 return baseset([c.rev() for c in ctxs])
1908 return baseset([c.rev() for c in ctxs])
1909
1909
1910 @predicate('subrepo([pattern])')
1910 @predicate('subrepo([pattern])')
1911 def subrepo(repo, subset, x):
1911 def subrepo(repo, subset, x):
1912 """Changesets that add, modify or remove the given subrepo. If no subrepo
1912 """Changesets that add, modify or remove the given subrepo. If no subrepo
1913 pattern is named, any subrepo changes are returned.
1913 pattern is named, any subrepo changes are returned.
1914 """
1914 """
1915 # i18n: "subrepo" is a keyword
1915 # i18n: "subrepo" is a keyword
1916 args = getargs(x, 0, 1, _('subrepo takes at most one argument'))
1916 args = getargs(x, 0, 1, _('subrepo takes at most one argument'))
1917 pat = None
1917 pat = None
1918 if len(args) != 0:
1918 if len(args) != 0:
1919 pat = getstring(args[0], _("subrepo requires a pattern"))
1919 pat = getstring(args[0], _("subrepo requires a pattern"))
1920
1920
1921 m = matchmod.exact(repo.root, repo.root, ['.hgsubstate'])
1921 m = matchmod.exact(repo.root, repo.root, ['.hgsubstate'])
1922
1922
1923 def submatches(names):
1923 def submatches(names):
1924 k, p, m = util.stringmatcher(pat)
1924 k, p, m = util.stringmatcher(pat)
1925 for name in names:
1925 for name in names:
1926 if m(name):
1926 if m(name):
1927 yield name
1927 yield name
1928
1928
1929 def matches(x):
1929 def matches(x):
1930 c = repo[x]
1930 c = repo[x]
1931 s = repo.status(c.p1().node(), c.node(), match=m)
1931 s = repo.status(c.p1().node(), c.node(), match=m)
1932
1932
1933 if pat is None:
1933 if pat is None:
1934 return s.added or s.modified or s.removed
1934 return s.added or s.modified or s.removed
1935
1935
1936 if s.added:
1936 if s.added:
1937 return any(submatches(c.substate.keys()))
1937 return any(submatches(c.substate.keys()))
1938
1938
1939 if s.modified:
1939 if s.modified:
1940 subs = set(c.p1().substate.keys())
1940 subs = set(c.p1().substate.keys())
1941 subs.update(c.substate.keys())
1941 subs.update(c.substate.keys())
1942
1942
1943 for path in submatches(subs):
1943 for path in submatches(subs):
1944 if c.p1().substate.get(path) != c.substate.get(path):
1944 if c.p1().substate.get(path) != c.substate.get(path):
1945 return True
1945 return True
1946
1946
1947 if s.removed:
1947 if s.removed:
1948 return any(submatches(c.p1().substate.keys()))
1948 return any(submatches(c.p1().substate.keys()))
1949
1949
1950 return False
1950 return False
1951
1951
1952 return subset.filter(matches, condrepr=('<subrepo %r>', pat))
1952 return subset.filter(matches, condrepr=('<subrepo %r>', pat))
1953
1953
1954 def _mapbynodefunc(repo, s, f):
1954 def _mapbynodefunc(repo, s, f):
1955 """(repo, smartset, [node] -> [node]) -> smartset
1955 """(repo, smartset, [node] -> [node]) -> smartset
1956
1956
1957 Helper method to map a smartset to another smartset given a function only
1957 Helper method to map a smartset to another smartset given a function only
1958 talking about nodes. Handles converting between rev numbers and nodes, and
1958 talking about nodes. Handles converting between rev numbers and nodes, and
1959 filtering.
1959 filtering.
1960 """
1960 """
1961 cl = repo.unfiltered().changelog
1961 cl = repo.unfiltered().changelog
1962 torev = cl.rev
1962 torev = cl.rev
1963 tonode = cl.node
1963 tonode = cl.node
1964 nodemap = cl.nodemap
1964 nodemap = cl.nodemap
1965 result = set(torev(n) for n in f(tonode(r) for r in s) if n in nodemap)
1965 result = set(torev(n) for n in f(tonode(r) for r in s) if n in nodemap)
1966 return smartset.baseset(result - repo.changelog.filteredrevs)
1966 return smartset.baseset(result - repo.changelog.filteredrevs)
1967
1967
1968 @predicate('successors(set)', safe=True)
1968 @predicate('successors(set)', safe=True)
1969 def successors(repo, subset, x):
1969 def successors(repo, subset, x):
1970 """All successors for set, including the given set themselves"""
1970 """All successors for set, including the given set themselves"""
1971 s = getset(repo, fullreposet(repo), x)
1971 s = getset(repo, fullreposet(repo), x)
1972 f = lambda nodes: obsutil.allsuccessors(repo.obsstore, nodes)
1972 f = lambda nodes: obsutil.allsuccessors(repo.obsstore, nodes)
1973 d = _mapbynodefunc(repo, s, f)
1973 d = _mapbynodefunc(repo, s, f)
1974 return subset & d
1974 return subset & d
1975
1975
1976 def _substringmatcher(pattern, casesensitive=True):
1976 def _substringmatcher(pattern, casesensitive=True):
1977 kind, pattern, matcher = util.stringmatcher(pattern,
1977 kind, pattern, matcher = util.stringmatcher(pattern,
1978 casesensitive=casesensitive)
1978 casesensitive=casesensitive)
1979 if kind == 'literal':
1979 if kind == 'literal':
1980 if not casesensitive:
1980 if not casesensitive:
1981 pattern = encoding.lower(pattern)
1981 pattern = encoding.lower(pattern)
1982 matcher = lambda s: pattern in encoding.lower(s)
1982 matcher = lambda s: pattern in encoding.lower(s)
1983 else:
1983 else:
1984 matcher = lambda s: pattern in s
1984 matcher = lambda s: pattern in s
1985 return kind, pattern, matcher
1985 return kind, pattern, matcher
1986
1986
1987 @predicate('tag([name])', safe=True)
1987 @predicate('tag([name])', safe=True)
1988 def tag(repo, subset, x):
1988 def tag(repo, subset, x):
1989 """The specified tag by name, or all tagged revisions if no name is given.
1989 """The specified tag by name, or all tagged revisions if no name is given.
1990
1990
1991 Pattern matching is supported for `name`. See
1991 Pattern matching is supported for `name`. See
1992 :hg:`help revisions.patterns`.
1992 :hg:`help revisions.patterns`.
1993 """
1993 """
1994 # i18n: "tag" is a keyword
1994 # i18n: "tag" is a keyword
1995 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
1995 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
1996 cl = repo.changelog
1996 cl = repo.changelog
1997 if args:
1997 if args:
1998 pattern = getstring(args[0],
1998 pattern = getstring(args[0],
1999 # i18n: "tag" is a keyword
1999 # i18n: "tag" is a keyword
2000 _('the argument to tag must be a string'))
2000 _('the argument to tag must be a string'))
2001 kind, pattern, matcher = util.stringmatcher(pattern)
2001 kind, pattern, matcher = util.stringmatcher(pattern)
2002 if kind == 'literal':
2002 if kind == 'literal':
2003 # avoid resolving all tags
2003 # avoid resolving all tags
2004 tn = repo._tagscache.tags.get(pattern, None)
2004 tn = repo._tagscache.tags.get(pattern, None)
2005 if tn is None:
2005 if tn is None:
2006 raise error.RepoLookupError(_("tag '%s' does not exist")
2006 raise error.RepoLookupError(_("tag '%s' does not exist")
2007 % pattern)
2007 % pattern)
2008 s = {repo[tn].rev()}
2008 s = {repo[tn].rev()}
2009 else:
2009 else:
2010 s = {cl.rev(n) for t, n in repo.tagslist() if matcher(t)}
2010 s = {cl.rev(n) for t, n in repo.tagslist() if matcher(t)}
2011 else:
2011 else:
2012 s = {cl.rev(n) for t, n in repo.tagslist() if t != 'tip'}
2012 s = {cl.rev(n) for t, n in repo.tagslist() if t != 'tip'}
2013 return subset & s
2013 return subset & s
2014
2014
2015 @predicate('tagged', safe=True)
2015 @predicate('tagged', safe=True)
2016 def tagged(repo, subset, x):
2016 def tagged(repo, subset, x):
2017 return tag(repo, subset, x)
2017 return tag(repo, subset, x)
2018
2018
2019 @predicate('unstable()', safe=True)
2019 @predicate('unstable()', safe=True)
2020 def unstable(repo, subset, x):
2020 def unstable(repo, subset, x):
2021 msg = ("'unstable()' is deprecated, "
2021 msg = ("'unstable()' is deprecated, "
2022 "use 'orphan()'")
2022 "use 'orphan()'")
2023 repo.ui.deprecwarn(msg, '4.4')
2023 repo.ui.deprecwarn(msg, '4.4')
2024
2024
2025 return orphan(repo, subset, x)
2025 return orphan(repo, subset, x)
2026
2026
2027 @predicate('orphan()', safe=True)
2027 @predicate('orphan()', safe=True)
2028 def orphan(repo, subset, x):
2028 def orphan(repo, subset, x):
2029 """Non-obsolete changesets with obsolete ancestors. (EXPERIMENTAL)
2029 """Non-obsolete changesets with obsolete ancestors. (EXPERIMENTAL)
2030 """
2030 """
2031 # i18n: "orphan" is a keyword
2031 # i18n: "orphan" is a keyword
2032 getargs(x, 0, 0, _("orphan takes no arguments"))
2032 getargs(x, 0, 0, _("orphan takes no arguments"))
2033 orphan = obsmod.getrevs(repo, 'orphan')
2033 orphan = obsmod.getrevs(repo, 'orphan')
2034 return subset & orphan
2034 return subset & orphan
2035
2035
2036
2036
2037 @predicate('user(string)', safe=True, weight=10)
2037 @predicate('user(string)', safe=True, weight=10)
2038 def user(repo, subset, x):
2038 def user(repo, subset, x):
2039 """User name contains string. The match is case-insensitive.
2039 """User name contains string. The match is case-insensitive.
2040
2040
2041 Pattern matching is supported for `string`. See
2041 Pattern matching is supported for `string`. See
2042 :hg:`help revisions.patterns`.
2042 :hg:`help revisions.patterns`.
2043 """
2043 """
2044 return author(repo, subset, x)
2044 return author(repo, subset, x)
2045
2045
2046 @predicate('wdir()', safe=True, weight=0)
2046 @predicate('wdir()', safe=True, weight=0)
2047 def wdir(repo, subset, x):
2047 def wdir(repo, subset, x):
2048 """Working directory. (EXPERIMENTAL)"""
2048 """Working directory. (EXPERIMENTAL)"""
2049 # i18n: "wdir" is a keyword
2049 # i18n: "wdir" is a keyword
2050 getargs(x, 0, 0, _("wdir takes no arguments"))
2050 getargs(x, 0, 0, _("wdir takes no arguments"))
2051 if node.wdirrev in subset or isinstance(subset, fullreposet):
2051 if node.wdirrev in subset or isinstance(subset, fullreposet):
2052 return baseset([node.wdirrev])
2052 return baseset([node.wdirrev])
2053 return baseset()
2053 return baseset()
2054
2054
2055 def _orderedlist(repo, subset, x):
2055 def _orderedlist(repo, subset, x):
2056 s = getstring(x, "internal error")
2056 s = getstring(x, "internal error")
2057 if not s:
2057 if not s:
2058 return baseset()
2058 return baseset()
2059 # remove duplicates here. it's difficult for caller to deduplicate sets
2059 # remove duplicates here. it's difficult for caller to deduplicate sets
2060 # because different symbols can point to the same rev.
2060 # because different symbols can point to the same rev.
2061 cl = repo.changelog
2061 cl = repo.changelog
2062 ls = []
2062 ls = []
2063 seen = set()
2063 seen = set()
2064 for t in s.split('\0'):
2064 for t in s.split('\0'):
2065 try:
2065 try:
2066 # fast path for integer revision
2066 # fast path for integer revision
2067 r = int(t)
2067 r = int(t)
2068 if str(r) != t or r not in cl:
2068 if str(r) != t or r not in cl:
2069 raise ValueError
2069 raise ValueError
2070 revs = [r]
2070 revs = [r]
2071 except ValueError:
2071 except ValueError:
2072 revs = stringset(repo, subset, t, defineorder)
2072 revs = stringset(repo, subset, t, defineorder)
2073
2073
2074 for r in revs:
2074 for r in revs:
2075 if r in seen:
2075 if r in seen:
2076 continue
2076 continue
2077 if (r in subset
2077 if (r in subset
2078 or r == node.nullrev and isinstance(subset, fullreposet)):
2078 or r == node.nullrev and isinstance(subset, fullreposet)):
2079 ls.append(r)
2079 ls.append(r)
2080 seen.add(r)
2080 seen.add(r)
2081 return baseset(ls)
2081 return baseset(ls)
2082
2082
2083 # for internal use
2083 # for internal use
2084 @predicate('_list', safe=True, takeorder=True)
2084 @predicate('_list', safe=True, takeorder=True)
2085 def _list(repo, subset, x, order):
2085 def _list(repo, subset, x, order):
2086 if order == followorder:
2086 if order == followorder:
2087 # slow path to take the subset order
2087 # slow path to take the subset order
2088 return subset & _orderedlist(repo, fullreposet(repo), x)
2088 return subset & _orderedlist(repo, fullreposet(repo), x)
2089 else:
2089 else:
2090 return _orderedlist(repo, subset, x)
2090 return _orderedlist(repo, subset, x)
2091
2091
2092 def _orderedintlist(repo, subset, x):
2092 def _orderedintlist(repo, subset, x):
2093 s = getstring(x, "internal error")
2093 s = getstring(x, "internal error")
2094 if not s:
2094 if not s:
2095 return baseset()
2095 return baseset()
2096 ls = [int(r) for r in s.split('\0')]
2096 ls = [int(r) for r in s.split('\0')]
2097 s = subset
2097 s = subset
2098 return baseset([r for r in ls if r in s])
2098 return baseset([r for r in ls if r in s])
2099
2099
2100 # for internal use
2100 # for internal use
2101 @predicate('_intlist', safe=True, takeorder=True, weight=0)
2101 @predicate('_intlist', safe=True, takeorder=True, weight=0)
2102 def _intlist(repo, subset, x, order):
2102 def _intlist(repo, subset, x, order):
2103 if order == followorder:
2103 if order == followorder:
2104 # slow path to take the subset order
2104 # slow path to take the subset order
2105 return subset & _orderedintlist(repo, fullreposet(repo), x)
2105 return subset & _orderedintlist(repo, fullreposet(repo), x)
2106 else:
2106 else:
2107 return _orderedintlist(repo, subset, x)
2107 return _orderedintlist(repo, subset, x)
2108
2108
2109 def _orderedhexlist(repo, subset, x):
2109 def _orderedhexlist(repo, subset, x):
2110 s = getstring(x, "internal error")
2110 s = getstring(x, "internal error")
2111 if not s:
2111 if not s:
2112 return baseset()
2112 return baseset()
2113 cl = repo.changelog
2113 cl = repo.changelog
2114 ls = [cl.rev(node.bin(r)) for r in s.split('\0')]
2114 ls = [cl.rev(node.bin(r)) for r in s.split('\0')]
2115 s = subset
2115 s = subset
2116 return baseset([r for r in ls if r in s])
2116 return baseset([r for r in ls if r in s])
2117
2117
2118 # for internal use
2118 # for internal use
2119 @predicate('_hexlist', safe=True, takeorder=True)
2119 @predicate('_hexlist', safe=True, takeorder=True)
2120 def _hexlist(repo, subset, x, order):
2120 def _hexlist(repo, subset, x, order):
2121 if order == followorder:
2121 if order == followorder:
2122 # slow path to take the subset order
2122 # slow path to take the subset order
2123 return subset & _orderedhexlist(repo, fullreposet(repo), x)
2123 return subset & _orderedhexlist(repo, fullreposet(repo), x)
2124 else:
2124 else:
2125 return _orderedhexlist(repo, subset, x)
2125 return _orderedhexlist(repo, subset, x)
2126
2126
2127 methods = {
2127 methods = {
2128 "range": rangeset,
2128 "range": rangeset,
2129 "rangeall": rangeall,
2129 "rangeall": rangeall,
2130 "rangepre": rangepre,
2130 "rangepre": rangepre,
2131 "rangepost": rangepost,
2131 "rangepost": rangepost,
2132 "dagrange": dagrange,
2132 "dagrange": dagrange,
2133 "string": stringset,
2133 "string": stringset,
2134 "symbol": stringset,
2134 "symbol": stringset,
2135 "and": andset,
2135 "and": andset,
2136 "andsmally": andsmallyset,
2136 "andsmally": andsmallyset,
2137 "or": orset,
2137 "or": orset,
2138 "not": notset,
2138 "not": notset,
2139 "difference": differenceset,
2139 "difference": differenceset,
2140 "relation": relationset,
2140 "relation": relationset,
2141 "relsubscript": relsubscriptset,
2141 "relsubscript": relsubscriptset,
2142 "subscript": subscriptset,
2142 "subscript": subscriptset,
2143 "list": listset,
2143 "list": listset,
2144 "keyvalue": keyvaluepair,
2144 "keyvalue": keyvaluepair,
2145 "func": func,
2145 "func": func,
2146 "ancestor": ancestorspec,
2146 "ancestor": ancestorspec,
2147 "parent": parentspec,
2147 "parent": parentspec,
2148 "parentpost": parentpost,
2148 "parentpost": parentpost,
2149 }
2149 }
2150
2150
2151 def posttreebuilthook(tree, repo):
2151 def posttreebuilthook(tree, repo):
2152 # hook for extensions to execute code on the optimized tree
2152 # hook for extensions to execute code on the optimized tree
2153 pass
2153 pass
2154
2154
2155 def match(ui, spec, repo=None):
2155 def match(ui, spec, repo=None):
2156 """Create a matcher for a single revision spec"""
2156 """Create a matcher for a single revision spec"""
2157 return matchany(ui, [spec], repo=repo)
2157 return matchany(ui, [spec], repo=repo)
2158
2158
2159 def matchany(ui, specs, repo=None, localalias=None):
2159 def matchany(ui, specs, repo=None, localalias=None):
2160 """Create a matcher that will include any revisions matching one of the
2160 """Create a matcher that will include any revisions matching one of the
2161 given specs
2161 given specs
2162
2162
2163 If localalias is not None, it is a dict {name: definitionstring}. It takes
2163 If localalias is not None, it is a dict {name: definitionstring}. It takes
2164 precedence over [revsetalias] config section.
2164 precedence over [revsetalias] config section.
2165 """
2165 """
2166 if not specs:
2166 if not specs:
2167 def mfunc(repo, subset=None):
2167 def mfunc(repo, subset=None):
2168 return baseset()
2168 return baseset()
2169 return mfunc
2169 return mfunc
2170 if not all(specs):
2170 if not all(specs):
2171 raise error.ParseError(_("empty query"))
2171 raise error.ParseError(_("empty query"))
2172 lookup = None
2172 lookup = None
2173 if repo:
2173 if repo:
2174 lookup = repo.__contains__
2174 lookup = repo.__contains__
2175 if len(specs) == 1:
2175 if len(specs) == 1:
2176 tree = revsetlang.parse(specs[0], lookup)
2176 tree = revsetlang.parse(specs[0], lookup)
2177 else:
2177 else:
2178 tree = ('or',
2178 tree = ('or',
2179 ('list',) + tuple(revsetlang.parse(s, lookup) for s in specs))
2179 ('list',) + tuple(revsetlang.parse(s, lookup) for s in specs))
2180
2180
2181 aliases = []
2181 aliases = []
2182 warn = None
2182 warn = None
2183 if ui:
2183 if ui:
2184 aliases.extend(ui.configitems('revsetalias'))
2184 aliases.extend(ui.configitems('revsetalias'))
2185 warn = ui.warn
2185 warn = ui.warn
2186 if localalias:
2186 if localalias:
2187 aliases.extend(localalias.items())
2187 aliases.extend(localalias.items())
2188 if aliases:
2188 if aliases:
2189 tree = revsetlang.expandaliases(tree, aliases, warn=warn)
2189 tree = revsetlang.expandaliases(tree, aliases, warn=warn)
2190 tree = revsetlang.foldconcat(tree)
2190 tree = revsetlang.foldconcat(tree)
2191 tree = revsetlang.analyze(tree)
2191 tree = revsetlang.analyze(tree)
2192 tree = revsetlang.optimize(tree)
2192 tree = revsetlang.optimize(tree)
2193 posttreebuilthook(tree, repo)
2193 posttreebuilthook(tree, repo)
2194 return makematcher(tree)
2194 return makematcher(tree)
2195
2195
2196 def makematcher(tree):
2196 def makematcher(tree):
2197 """Create a matcher from an evaluatable tree"""
2197 """Create a matcher from an evaluatable tree"""
2198 def mfunc(repo, subset=None, order=None):
2198 def mfunc(repo, subset=None, order=None):
2199 if order is None:
2199 if order is None:
2200 if subset is None:
2200 if subset is None:
2201 order = defineorder # 'x'
2201 order = defineorder # 'x'
2202 else:
2202 else:
2203 order = followorder # 'subset & x'
2203 order = followorder # 'subset & x'
2204 if subset is None:
2204 if subset is None:
2205 subset = fullreposet(repo)
2205 subset = fullreposet(repo)
2206 return getset(repo, subset, tree, order)
2206 return getset(repo, subset, tree, order)
2207 return mfunc
2207 return mfunc
2208
2208
2209 def loadpredicate(ui, extname, registrarobj):
2209 def loadpredicate(ui, extname, registrarobj):
2210 """Load revset predicates from specified registrarobj
2210 """Load revset predicates from specified registrarobj
2211 """
2211 """
2212 for name, func in registrarobj._table.iteritems():
2212 for name, func in registrarobj._table.iteritems():
2213 symbols[name] = func
2213 symbols[name] = func
2214 if func._safe:
2214 if func._safe:
2215 safesymbols.add(name)
2215 safesymbols.add(name)
2216
2216
2217 # load built-in predicates explicitly to setup safesymbols
2217 # load built-in predicates explicitly to setup safesymbols
2218 loadpredicate(None, None, predicate)
2218 loadpredicate(None, None, predicate)
2219
2219
2220 # tell hggettext to extract docstrings from these functions:
2220 # tell hggettext to extract docstrings from these functions:
2221 i18nfunctions = symbols.values()
2221 i18nfunctions = symbols.values()
@@ -1,2466 +1,2479
1 Log on empty repository: checking consistency
1 Log on empty repository: checking consistency
2
2
3 $ hg init empty
3 $ hg init empty
4 $ cd empty
4 $ cd empty
5 $ hg log
5 $ hg log
6 $ hg log -r 1
6 $ hg log -r 1
7 abort: unknown revision '1'!
7 abort: unknown revision '1'!
8 [255]
8 [255]
9 $ hg log -r -1:0
9 $ hg log -r -1:0
10 abort: unknown revision '-1'!
10 abort: unknown revision '-1'!
11 [255]
11 [255]
12 $ hg log -r 'branch(name)'
12 $ hg log -r 'branch(name)'
13 abort: unknown revision 'name'!
13 abort: unknown revision 'name'!
14 [255]
14 [255]
15 $ hg log -r null -q
15 $ hg log -r null -q
16 -1:000000000000
16 -1:000000000000
17
17
18 $ cd ..
18 $ cd ..
19
19
20 The g is crafted to have 2 filelog topological heads in a linear
20 The g is crafted to have 2 filelog topological heads in a linear
21 changeset graph
21 changeset graph
22
22
23 $ hg init a
23 $ hg init a
24 $ cd a
24 $ cd a
25 $ echo a > a
25 $ echo a > a
26 $ echo f > f
26 $ echo f > f
27 $ hg ci -Ama -d '1 0'
27 $ hg ci -Ama -d '1 0'
28 adding a
28 adding a
29 adding f
29 adding f
30
30
31 $ hg cp a b
31 $ hg cp a b
32 $ hg cp f g
32 $ hg cp f g
33 $ hg ci -mb -d '2 0'
33 $ hg ci -mb -d '2 0'
34
34
35 $ mkdir dir
35 $ mkdir dir
36 $ hg mv b dir
36 $ hg mv b dir
37 $ echo g >> g
37 $ echo g >> g
38 $ echo f >> f
38 $ echo f >> f
39 $ hg ci -mc -d '3 0'
39 $ hg ci -mc -d '3 0'
40
40
41 $ hg mv a b
41 $ hg mv a b
42 $ hg cp -f f g
42 $ hg cp -f f g
43 $ echo a > d
43 $ echo a > d
44 $ hg add d
44 $ hg add d
45 $ hg ci -md -d '4 0'
45 $ hg ci -md -d '4 0'
46
46
47 $ hg mv dir/b e
47 $ hg mv dir/b e
48 $ hg ci -me -d '5 0'
48 $ hg ci -me -d '5 0'
49
49
50 Make sure largefiles doesn't interfere with logging a regular file
50 Make sure largefiles doesn't interfere with logging a regular file
51 $ hg --debug log a -T '{rev}: {desc}\n' --config extensions.largefiles=
51 $ hg --debug log a -T '{rev}: {desc}\n' --config extensions.largefiles=
52 The fsmonitor extension is incompatible with the largefiles extension and has been disabled. (fsmonitor !)
52 The fsmonitor extension is incompatible with the largefiles extension and has been disabled. (fsmonitor !)
53 updated patterns: .hglf/a, a
53 updated patterns: .hglf/a, a
54 0: a
54 0: a
55 $ hg log a
55 $ hg log a
56 changeset: 0:9161b9aeaf16
56 changeset: 0:9161b9aeaf16
57 user: test
57 user: test
58 date: Thu Jan 01 00:00:01 1970 +0000
58 date: Thu Jan 01 00:00:01 1970 +0000
59 summary: a
59 summary: a
60
60
61 $ hg log glob:a*
61 $ hg log glob:a*
62 changeset: 3:2ca5ba701980
62 changeset: 3:2ca5ba701980
63 user: test
63 user: test
64 date: Thu Jan 01 00:00:04 1970 +0000
64 date: Thu Jan 01 00:00:04 1970 +0000
65 summary: d
65 summary: d
66
66
67 changeset: 0:9161b9aeaf16
67 changeset: 0:9161b9aeaf16
68 user: test
68 user: test
69 date: Thu Jan 01 00:00:01 1970 +0000
69 date: Thu Jan 01 00:00:01 1970 +0000
70 summary: a
70 summary: a
71
71
72 $ hg --debug log glob:a* -T '{rev}: {desc}\n' --config extensions.largefiles=
72 $ hg --debug log glob:a* -T '{rev}: {desc}\n' --config extensions.largefiles=
73 The fsmonitor extension is incompatible with the largefiles extension and has been disabled. (fsmonitor !)
73 The fsmonitor extension is incompatible with the largefiles extension and has been disabled. (fsmonitor !)
74 updated patterns: glob:.hglf/a*, glob:a*
74 updated patterns: glob:.hglf/a*, glob:a*
75 3: d
75 3: d
76 0: a
76 0: a
77
77
78 log on directory
78 log on directory
79
79
80 $ hg log dir
80 $ hg log dir
81 changeset: 4:7e4639b4691b
81 changeset: 4:7e4639b4691b
82 tag: tip
82 tag: tip
83 user: test
83 user: test
84 date: Thu Jan 01 00:00:05 1970 +0000
84 date: Thu Jan 01 00:00:05 1970 +0000
85 summary: e
85 summary: e
86
86
87 changeset: 2:f8954cd4dc1f
87 changeset: 2:f8954cd4dc1f
88 user: test
88 user: test
89 date: Thu Jan 01 00:00:03 1970 +0000
89 date: Thu Jan 01 00:00:03 1970 +0000
90 summary: c
90 summary: c
91
91
92 $ hg log somethingthatdoesntexist dir
92 $ hg log somethingthatdoesntexist dir
93 changeset: 4:7e4639b4691b
93 changeset: 4:7e4639b4691b
94 tag: tip
94 tag: tip
95 user: test
95 user: test
96 date: Thu Jan 01 00:00:05 1970 +0000
96 date: Thu Jan 01 00:00:05 1970 +0000
97 summary: e
97 summary: e
98
98
99 changeset: 2:f8954cd4dc1f
99 changeset: 2:f8954cd4dc1f
100 user: test
100 user: test
101 date: Thu Jan 01 00:00:03 1970 +0000
101 date: Thu Jan 01 00:00:03 1970 +0000
102 summary: c
102 summary: c
103
103
104
104
105 -f, non-existent directory
105 -f, non-existent directory
106
106
107 $ hg log -f dir
107 $ hg log -f dir
108 abort: cannot follow file not in parent revision: "dir"
108 abort: cannot follow file not in parent revision: "dir"
109 [255]
109 [255]
110
110
111 -f, directory
111 -f, directory
112
112
113 $ hg up -q 3
113 $ hg up -q 3
114 $ hg log -f dir
114 $ hg log -f dir
115 changeset: 2:f8954cd4dc1f
115 changeset: 2:f8954cd4dc1f
116 user: test
116 user: test
117 date: Thu Jan 01 00:00:03 1970 +0000
117 date: Thu Jan 01 00:00:03 1970 +0000
118 summary: c
118 summary: c
119
119
120 -f, directory with --patch
120 -f, directory with --patch
121
121
122 $ hg log -f dir -p
122 $ hg log -f dir -p
123 changeset: 2:f8954cd4dc1f
123 changeset: 2:f8954cd4dc1f
124 user: test
124 user: test
125 date: Thu Jan 01 00:00:03 1970 +0000
125 date: Thu Jan 01 00:00:03 1970 +0000
126 summary: c
126 summary: c
127
127
128 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
128 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
129 --- /dev/null* (glob)
129 --- /dev/null* (glob)
130 +++ b/dir/b* (glob)
130 +++ b/dir/b* (glob)
131 @@ -0,0 +1,1 @@
131 @@ -0,0 +1,1 @@
132 +a
132 +a
133
133
134
134
135 -f, pattern
135 -f, pattern
136
136
137 $ hg log -f -I 'dir**' -p
137 $ hg log -f -I 'dir**' -p
138 changeset: 2:f8954cd4dc1f
138 changeset: 2:f8954cd4dc1f
139 user: test
139 user: test
140 date: Thu Jan 01 00:00:03 1970 +0000
140 date: Thu Jan 01 00:00:03 1970 +0000
141 summary: c
141 summary: c
142
142
143 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
143 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
144 --- /dev/null* (glob)
144 --- /dev/null* (glob)
145 +++ b/dir/b* (glob)
145 +++ b/dir/b* (glob)
146 @@ -0,0 +1,1 @@
146 @@ -0,0 +1,1 @@
147 +a
147 +a
148
148
149 $ hg up -q 4
149 $ hg up -q 4
150
150
151 -f, a wrong style
151 -f, a wrong style
152
152
153 $ hg log -f -l1 --style something
153 $ hg log -f -l1 --style something
154 abort: style 'something' not found
154 abort: style 'something' not found
155 (available styles: bisect, changelog, compact, default, phases, show, status, xml)
155 (available styles: bisect, changelog, compact, default, phases, show, status, xml)
156 [255]
156 [255]
157
157
158 -f, phases style
158 -f, phases style
159
159
160
160
161 $ hg log -f -l1 --style phases
161 $ hg log -f -l1 --style phases
162 changeset: 4:7e4639b4691b
162 changeset: 4:7e4639b4691b
163 tag: tip
163 tag: tip
164 phase: draft
164 phase: draft
165 user: test
165 user: test
166 date: Thu Jan 01 00:00:05 1970 +0000
166 date: Thu Jan 01 00:00:05 1970 +0000
167 summary: e
167 summary: e
168
168
169
169
170 $ hg log -f -l1 --style phases -q
170 $ hg log -f -l1 --style phases -q
171 4:7e4639b4691b
171 4:7e4639b4691b
172
172
173 -f, but no args
173 -f, but no args
174
174
175 $ hg log -f
175 $ hg log -f
176 changeset: 4:7e4639b4691b
176 changeset: 4:7e4639b4691b
177 tag: tip
177 tag: tip
178 user: test
178 user: test
179 date: Thu Jan 01 00:00:05 1970 +0000
179 date: Thu Jan 01 00:00:05 1970 +0000
180 summary: e
180 summary: e
181
181
182 changeset: 3:2ca5ba701980
182 changeset: 3:2ca5ba701980
183 user: test
183 user: test
184 date: Thu Jan 01 00:00:04 1970 +0000
184 date: Thu Jan 01 00:00:04 1970 +0000
185 summary: d
185 summary: d
186
186
187 changeset: 2:f8954cd4dc1f
187 changeset: 2:f8954cd4dc1f
188 user: test
188 user: test
189 date: Thu Jan 01 00:00:03 1970 +0000
189 date: Thu Jan 01 00:00:03 1970 +0000
190 summary: c
190 summary: c
191
191
192 changeset: 1:d89b0a12d229
192 changeset: 1:d89b0a12d229
193 user: test
193 user: test
194 date: Thu Jan 01 00:00:02 1970 +0000
194 date: Thu Jan 01 00:00:02 1970 +0000
195 summary: b
195 summary: b
196
196
197 changeset: 0:9161b9aeaf16
197 changeset: 0:9161b9aeaf16
198 user: test
198 user: test
199 date: Thu Jan 01 00:00:01 1970 +0000
199 date: Thu Jan 01 00:00:01 1970 +0000
200 summary: a
200 summary: a
201
201
202
202
203 one rename
203 one rename
204
204
205 $ hg up -q 2
205 $ hg up -q 2
206 $ hg log -vf a
206 $ hg log -vf a
207 changeset: 0:9161b9aeaf16
207 changeset: 0:9161b9aeaf16
208 user: test
208 user: test
209 date: Thu Jan 01 00:00:01 1970 +0000
209 date: Thu Jan 01 00:00:01 1970 +0000
210 files: a f
210 files: a f
211 description:
211 description:
212 a
212 a
213
213
214
214
215
215
216 many renames
216 many renames
217
217
218 $ hg up -q tip
218 $ hg up -q tip
219 $ hg log -vf e
219 $ hg log -vf e
220 changeset: 4:7e4639b4691b
220 changeset: 4:7e4639b4691b
221 tag: tip
221 tag: tip
222 user: test
222 user: test
223 date: Thu Jan 01 00:00:05 1970 +0000
223 date: Thu Jan 01 00:00:05 1970 +0000
224 files: dir/b e
224 files: dir/b e
225 description:
225 description:
226 e
226 e
227
227
228
228
229 changeset: 2:f8954cd4dc1f
229 changeset: 2:f8954cd4dc1f
230 user: test
230 user: test
231 date: Thu Jan 01 00:00:03 1970 +0000
231 date: Thu Jan 01 00:00:03 1970 +0000
232 files: b dir/b f g
232 files: b dir/b f g
233 description:
233 description:
234 c
234 c
235
235
236
236
237 changeset: 1:d89b0a12d229
237 changeset: 1:d89b0a12d229
238 user: test
238 user: test
239 date: Thu Jan 01 00:00:02 1970 +0000
239 date: Thu Jan 01 00:00:02 1970 +0000
240 files: b g
240 files: b g
241 description:
241 description:
242 b
242 b
243
243
244
244
245 changeset: 0:9161b9aeaf16
245 changeset: 0:9161b9aeaf16
246 user: test
246 user: test
247 date: Thu Jan 01 00:00:01 1970 +0000
247 date: Thu Jan 01 00:00:01 1970 +0000
248 files: a f
248 files: a f
249 description:
249 description:
250 a
250 a
251
251
252
252
253
253
254
254
255 log -pf dir/b
255 log -pf dir/b
256
256
257 $ hg up -q 3
257 $ hg up -q 3
258 $ hg log -pf dir/b
258 $ hg log -pf dir/b
259 changeset: 2:f8954cd4dc1f
259 changeset: 2:f8954cd4dc1f
260 user: test
260 user: test
261 date: Thu Jan 01 00:00:03 1970 +0000
261 date: Thu Jan 01 00:00:03 1970 +0000
262 summary: c
262 summary: c
263
263
264 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
264 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
265 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
265 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
266 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
266 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
267 @@ -0,0 +1,1 @@
267 @@ -0,0 +1,1 @@
268 +a
268 +a
269
269
270 changeset: 1:d89b0a12d229
270 changeset: 1:d89b0a12d229
271 user: test
271 user: test
272 date: Thu Jan 01 00:00:02 1970 +0000
272 date: Thu Jan 01 00:00:02 1970 +0000
273 summary: b
273 summary: b
274
274
275 diff -r 9161b9aeaf16 -r d89b0a12d229 b
275 diff -r 9161b9aeaf16 -r d89b0a12d229 b
276 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
276 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
277 +++ b/b Thu Jan 01 00:00:02 1970 +0000
277 +++ b/b Thu Jan 01 00:00:02 1970 +0000
278 @@ -0,0 +1,1 @@
278 @@ -0,0 +1,1 @@
279 +a
279 +a
280
280
281 changeset: 0:9161b9aeaf16
281 changeset: 0:9161b9aeaf16
282 user: test
282 user: test
283 date: Thu Jan 01 00:00:01 1970 +0000
283 date: Thu Jan 01 00:00:01 1970 +0000
284 summary: a
284 summary: a
285
285
286 diff -r 000000000000 -r 9161b9aeaf16 a
286 diff -r 000000000000 -r 9161b9aeaf16 a
287 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
287 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
288 +++ b/a Thu Jan 01 00:00:01 1970 +0000
288 +++ b/a Thu Jan 01 00:00:01 1970 +0000
289 @@ -0,0 +1,1 @@
289 @@ -0,0 +1,1 @@
290 +a
290 +a
291
291
292
292
293 log -pf b inside dir
293 log -pf b inside dir
294
294
295 $ hg --cwd=dir log -pf b
295 $ hg --cwd=dir log -pf b
296 changeset: 2:f8954cd4dc1f
296 changeset: 2:f8954cd4dc1f
297 user: test
297 user: test
298 date: Thu Jan 01 00:00:03 1970 +0000
298 date: Thu Jan 01 00:00:03 1970 +0000
299 summary: c
299 summary: c
300
300
301 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
301 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
302 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
302 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
303 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
303 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
304 @@ -0,0 +1,1 @@
304 @@ -0,0 +1,1 @@
305 +a
305 +a
306
306
307 changeset: 1:d89b0a12d229
307 changeset: 1:d89b0a12d229
308 user: test
308 user: test
309 date: Thu Jan 01 00:00:02 1970 +0000
309 date: Thu Jan 01 00:00:02 1970 +0000
310 summary: b
310 summary: b
311
311
312 diff -r 9161b9aeaf16 -r d89b0a12d229 b
312 diff -r 9161b9aeaf16 -r d89b0a12d229 b
313 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
313 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
314 +++ b/b Thu Jan 01 00:00:02 1970 +0000
314 +++ b/b Thu Jan 01 00:00:02 1970 +0000
315 @@ -0,0 +1,1 @@
315 @@ -0,0 +1,1 @@
316 +a
316 +a
317
317
318 changeset: 0:9161b9aeaf16
318 changeset: 0:9161b9aeaf16
319 user: test
319 user: test
320 date: Thu Jan 01 00:00:01 1970 +0000
320 date: Thu Jan 01 00:00:01 1970 +0000
321 summary: a
321 summary: a
322
322
323 diff -r 000000000000 -r 9161b9aeaf16 a
323 diff -r 000000000000 -r 9161b9aeaf16 a
324 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
324 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
325 +++ b/a Thu Jan 01 00:00:01 1970 +0000
325 +++ b/a Thu Jan 01 00:00:01 1970 +0000
326 @@ -0,0 +1,1 @@
326 @@ -0,0 +1,1 @@
327 +a
327 +a
328
328
329
329
330 log -pf, but no args
330 log -pf, but no args
331
331
332 $ hg log -pf
332 $ hg log -pf
333 changeset: 3:2ca5ba701980
333 changeset: 3:2ca5ba701980
334 user: test
334 user: test
335 date: Thu Jan 01 00:00:04 1970 +0000
335 date: Thu Jan 01 00:00:04 1970 +0000
336 summary: d
336 summary: d
337
337
338 diff -r f8954cd4dc1f -r 2ca5ba701980 a
338 diff -r f8954cd4dc1f -r 2ca5ba701980 a
339 --- a/a Thu Jan 01 00:00:03 1970 +0000
339 --- a/a Thu Jan 01 00:00:03 1970 +0000
340 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
340 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
341 @@ -1,1 +0,0 @@
341 @@ -1,1 +0,0 @@
342 -a
342 -a
343 diff -r f8954cd4dc1f -r 2ca5ba701980 b
343 diff -r f8954cd4dc1f -r 2ca5ba701980 b
344 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
344 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
345 +++ b/b Thu Jan 01 00:00:04 1970 +0000
345 +++ b/b Thu Jan 01 00:00:04 1970 +0000
346 @@ -0,0 +1,1 @@
346 @@ -0,0 +1,1 @@
347 +a
347 +a
348 diff -r f8954cd4dc1f -r 2ca5ba701980 d
348 diff -r f8954cd4dc1f -r 2ca5ba701980 d
349 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
349 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
350 +++ b/d Thu Jan 01 00:00:04 1970 +0000
350 +++ b/d Thu Jan 01 00:00:04 1970 +0000
351 @@ -0,0 +1,1 @@
351 @@ -0,0 +1,1 @@
352 +a
352 +a
353 diff -r f8954cd4dc1f -r 2ca5ba701980 g
353 diff -r f8954cd4dc1f -r 2ca5ba701980 g
354 --- a/g Thu Jan 01 00:00:03 1970 +0000
354 --- a/g Thu Jan 01 00:00:03 1970 +0000
355 +++ b/g Thu Jan 01 00:00:04 1970 +0000
355 +++ b/g Thu Jan 01 00:00:04 1970 +0000
356 @@ -1,2 +1,2 @@
356 @@ -1,2 +1,2 @@
357 f
357 f
358 -g
358 -g
359 +f
359 +f
360
360
361 changeset: 2:f8954cd4dc1f
361 changeset: 2:f8954cd4dc1f
362 user: test
362 user: test
363 date: Thu Jan 01 00:00:03 1970 +0000
363 date: Thu Jan 01 00:00:03 1970 +0000
364 summary: c
364 summary: c
365
365
366 diff -r d89b0a12d229 -r f8954cd4dc1f b
366 diff -r d89b0a12d229 -r f8954cd4dc1f b
367 --- a/b Thu Jan 01 00:00:02 1970 +0000
367 --- a/b Thu Jan 01 00:00:02 1970 +0000
368 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
368 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
369 @@ -1,1 +0,0 @@
369 @@ -1,1 +0,0 @@
370 -a
370 -a
371 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
371 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
372 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
372 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
373 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
373 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
374 @@ -0,0 +1,1 @@
374 @@ -0,0 +1,1 @@
375 +a
375 +a
376 diff -r d89b0a12d229 -r f8954cd4dc1f f
376 diff -r d89b0a12d229 -r f8954cd4dc1f f
377 --- a/f Thu Jan 01 00:00:02 1970 +0000
377 --- a/f Thu Jan 01 00:00:02 1970 +0000
378 +++ b/f Thu Jan 01 00:00:03 1970 +0000
378 +++ b/f Thu Jan 01 00:00:03 1970 +0000
379 @@ -1,1 +1,2 @@
379 @@ -1,1 +1,2 @@
380 f
380 f
381 +f
381 +f
382 diff -r d89b0a12d229 -r f8954cd4dc1f g
382 diff -r d89b0a12d229 -r f8954cd4dc1f g
383 --- a/g Thu Jan 01 00:00:02 1970 +0000
383 --- a/g Thu Jan 01 00:00:02 1970 +0000
384 +++ b/g Thu Jan 01 00:00:03 1970 +0000
384 +++ b/g Thu Jan 01 00:00:03 1970 +0000
385 @@ -1,1 +1,2 @@
385 @@ -1,1 +1,2 @@
386 f
386 f
387 +g
387 +g
388
388
389 changeset: 1:d89b0a12d229
389 changeset: 1:d89b0a12d229
390 user: test
390 user: test
391 date: Thu Jan 01 00:00:02 1970 +0000
391 date: Thu Jan 01 00:00:02 1970 +0000
392 summary: b
392 summary: b
393
393
394 diff -r 9161b9aeaf16 -r d89b0a12d229 b
394 diff -r 9161b9aeaf16 -r d89b0a12d229 b
395 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
395 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
396 +++ b/b Thu Jan 01 00:00:02 1970 +0000
396 +++ b/b Thu Jan 01 00:00:02 1970 +0000
397 @@ -0,0 +1,1 @@
397 @@ -0,0 +1,1 @@
398 +a
398 +a
399 diff -r 9161b9aeaf16 -r d89b0a12d229 g
399 diff -r 9161b9aeaf16 -r d89b0a12d229 g
400 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
400 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
401 +++ b/g Thu Jan 01 00:00:02 1970 +0000
401 +++ b/g Thu Jan 01 00:00:02 1970 +0000
402 @@ -0,0 +1,1 @@
402 @@ -0,0 +1,1 @@
403 +f
403 +f
404
404
405 changeset: 0:9161b9aeaf16
405 changeset: 0:9161b9aeaf16
406 user: test
406 user: test
407 date: Thu Jan 01 00:00:01 1970 +0000
407 date: Thu Jan 01 00:00:01 1970 +0000
408 summary: a
408 summary: a
409
409
410 diff -r 000000000000 -r 9161b9aeaf16 a
410 diff -r 000000000000 -r 9161b9aeaf16 a
411 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
411 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
412 +++ b/a Thu Jan 01 00:00:01 1970 +0000
412 +++ b/a Thu Jan 01 00:00:01 1970 +0000
413 @@ -0,0 +1,1 @@
413 @@ -0,0 +1,1 @@
414 +a
414 +a
415 diff -r 000000000000 -r 9161b9aeaf16 f
415 diff -r 000000000000 -r 9161b9aeaf16 f
416 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
416 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
417 +++ b/f Thu Jan 01 00:00:01 1970 +0000
417 +++ b/f Thu Jan 01 00:00:01 1970 +0000
418 @@ -0,0 +1,1 @@
418 @@ -0,0 +1,1 @@
419 +f
419 +f
420
420
421
421
422 log -vf dir/b
422 log -vf dir/b
423
423
424 $ hg log -vf dir/b
424 $ hg log -vf dir/b
425 changeset: 2:f8954cd4dc1f
425 changeset: 2:f8954cd4dc1f
426 user: test
426 user: test
427 date: Thu Jan 01 00:00:03 1970 +0000
427 date: Thu Jan 01 00:00:03 1970 +0000
428 files: b dir/b f g
428 files: b dir/b f g
429 description:
429 description:
430 c
430 c
431
431
432
432
433 changeset: 1:d89b0a12d229
433 changeset: 1:d89b0a12d229
434 user: test
434 user: test
435 date: Thu Jan 01 00:00:02 1970 +0000
435 date: Thu Jan 01 00:00:02 1970 +0000
436 files: b g
436 files: b g
437 description:
437 description:
438 b
438 b
439
439
440
440
441 changeset: 0:9161b9aeaf16
441 changeset: 0:9161b9aeaf16
442 user: test
442 user: test
443 date: Thu Jan 01 00:00:01 1970 +0000
443 date: Thu Jan 01 00:00:01 1970 +0000
444 files: a f
444 files: a f
445 description:
445 description:
446 a
446 a
447
447
448
448
449
449
450
450
451 -f and multiple filelog heads
451 -f and multiple filelog heads
452
452
453 $ hg up -q 2
453 $ hg up -q 2
454 $ hg log -f g --template '{rev}\n'
454 $ hg log -f g --template '{rev}\n'
455 2
455 2
456 1
456 1
457 0
457 0
458 $ hg up -q tip
458 $ hg up -q tip
459 $ hg log -f g --template '{rev}\n'
459 $ hg log -f g --template '{rev}\n'
460 3
460 3
461 2
461 2
462 0
462 0
463
463
464
464
465 log copies with --copies
465 log copies with --copies
466
466
467 $ hg log -vC --template '{rev} {file_copies}\n'
467 $ hg log -vC --template '{rev} {file_copies}\n'
468 4 e (dir/b)
468 4 e (dir/b)
469 3 b (a)g (f)
469 3 b (a)g (f)
470 2 dir/b (b)
470 2 dir/b (b)
471 1 b (a)g (f)
471 1 b (a)g (f)
472 0
472 0
473
473
474 log copies switch without --copies, with old filecopy template
474 log copies switch without --copies, with old filecopy template
475
475
476 $ hg log -v --template '{rev} {file_copies_switch%filecopy}\n'
476 $ hg log -v --template '{rev} {file_copies_switch%filecopy}\n'
477 4
477 4
478 3
478 3
479 2
479 2
480 1
480 1
481 0
481 0
482
482
483 log copies switch with --copies
483 log copies switch with --copies
484
484
485 $ hg log -vC --template '{rev} {file_copies_switch}\n'
485 $ hg log -vC --template '{rev} {file_copies_switch}\n'
486 4 e (dir/b)
486 4 e (dir/b)
487 3 b (a)g (f)
487 3 b (a)g (f)
488 2 dir/b (b)
488 2 dir/b (b)
489 1 b (a)g (f)
489 1 b (a)g (f)
490 0
490 0
491
491
492
492
493 log copies with hardcoded style and with --style=default
493 log copies with hardcoded style and with --style=default
494
494
495 $ hg log -vC -r4
495 $ hg log -vC -r4
496 changeset: 4:7e4639b4691b
496 changeset: 4:7e4639b4691b
497 tag: tip
497 tag: tip
498 user: test
498 user: test
499 date: Thu Jan 01 00:00:05 1970 +0000
499 date: Thu Jan 01 00:00:05 1970 +0000
500 files: dir/b e
500 files: dir/b e
501 copies: e (dir/b)
501 copies: e (dir/b)
502 description:
502 description:
503 e
503 e
504
504
505
505
506 $ hg log -vC -r4 --style=default
506 $ hg log -vC -r4 --style=default
507 changeset: 4:7e4639b4691b
507 changeset: 4:7e4639b4691b
508 tag: tip
508 tag: tip
509 user: test
509 user: test
510 date: Thu Jan 01 00:00:05 1970 +0000
510 date: Thu Jan 01 00:00:05 1970 +0000
511 files: dir/b e
511 files: dir/b e
512 copies: e (dir/b)
512 copies: e (dir/b)
513 description:
513 description:
514 e
514 e
515
515
516
516
517 $ hg log -vC -r4 -Tjson
517 $ hg log -vC -r4 -Tjson
518 [
518 [
519 {
519 {
520 "rev": 4,
520 "rev": 4,
521 "node": "7e4639b4691b9f84b81036a8d4fb218ce3c5e3a3",
521 "node": "7e4639b4691b9f84b81036a8d4fb218ce3c5e3a3",
522 "branch": "default",
522 "branch": "default",
523 "phase": "draft",
523 "phase": "draft",
524 "user": "test",
524 "user": "test",
525 "date": [5, 0],
525 "date": [5, 0],
526 "desc": "e",
526 "desc": "e",
527 "bookmarks": [],
527 "bookmarks": [],
528 "tags": ["tip"],
528 "tags": ["tip"],
529 "parents": ["2ca5ba7019804f1f597249caddf22a64d34df0ba"],
529 "parents": ["2ca5ba7019804f1f597249caddf22a64d34df0ba"],
530 "files": ["dir/b", "e"],
530 "files": ["dir/b", "e"],
531 "copies": {"e": "dir/b"}
531 "copies": {"e": "dir/b"}
532 }
532 }
533 ]
533 ]
534
534
535 log copies, non-linear manifest
535 log copies, non-linear manifest
536
536
537 $ hg up -C 3
537 $ hg up -C 3
538 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
538 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
539 $ hg mv dir/b e
539 $ hg mv dir/b e
540 $ echo foo > foo
540 $ echo foo > foo
541 $ hg ci -Ame2 -d '6 0'
541 $ hg ci -Ame2 -d '6 0'
542 adding foo
542 adding foo
543 created new head
543 created new head
544 $ hg log -v --template '{rev} {file_copies}\n' -r 5
544 $ hg log -v --template '{rev} {file_copies}\n' -r 5
545 5 e (dir/b)
545 5 e (dir/b)
546
546
547
547
548 log copies, execute bit set
548 log copies, execute bit set
549
549
550 #if execbit
550 #if execbit
551 $ chmod +x e
551 $ chmod +x e
552 $ hg ci -me3 -d '7 0'
552 $ hg ci -me3 -d '7 0'
553 $ hg log -v --template '{rev} {file_copies}\n' -r 6
553 $ hg log -v --template '{rev} {file_copies}\n' -r 6
554 6
554 6
555 #endif
555 #endif
556
556
557
557
558 log -p d
558 log -p d
559
559
560 $ hg log -pv d
560 $ hg log -pv d
561 changeset: 3:2ca5ba701980
561 changeset: 3:2ca5ba701980
562 user: test
562 user: test
563 date: Thu Jan 01 00:00:04 1970 +0000
563 date: Thu Jan 01 00:00:04 1970 +0000
564 files: a b d g
564 files: a b d g
565 description:
565 description:
566 d
566 d
567
567
568
568
569 diff -r f8954cd4dc1f -r 2ca5ba701980 d
569 diff -r f8954cd4dc1f -r 2ca5ba701980 d
570 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
570 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
571 +++ b/d Thu Jan 01 00:00:04 1970 +0000
571 +++ b/d Thu Jan 01 00:00:04 1970 +0000
572 @@ -0,0 +1,1 @@
572 @@ -0,0 +1,1 @@
573 +a
573 +a
574
574
575
575
576
576
577 log --removed file
577 log --removed file
578
578
579 $ hg log --removed -v a
579 $ hg log --removed -v a
580 changeset: 3:2ca5ba701980
580 changeset: 3:2ca5ba701980
581 user: test
581 user: test
582 date: Thu Jan 01 00:00:04 1970 +0000
582 date: Thu Jan 01 00:00:04 1970 +0000
583 files: a b d g
583 files: a b d g
584 description:
584 description:
585 d
585 d
586
586
587
587
588 changeset: 0:9161b9aeaf16
588 changeset: 0:9161b9aeaf16
589 user: test
589 user: test
590 date: Thu Jan 01 00:00:01 1970 +0000
590 date: Thu Jan 01 00:00:01 1970 +0000
591 files: a f
591 files: a f
592 description:
592 description:
593 a
593 a
594
594
595
595
596
596
597 log --removed revrange file
597 log --removed revrange file
598
598
599 $ hg log --removed -v -r0:2 a
599 $ hg log --removed -v -r0:2 a
600 changeset: 0:9161b9aeaf16
600 changeset: 0:9161b9aeaf16
601 user: test
601 user: test
602 date: Thu Jan 01 00:00:01 1970 +0000
602 date: Thu Jan 01 00:00:01 1970 +0000
603 files: a f
603 files: a f
604 description:
604 description:
605 a
605 a
606
606
607
607
608 $ cd ..
608 $ cd ..
609
609
610 log --follow tests
610 log --follow tests
611
611
612 $ hg init follow
612 $ hg init follow
613 $ cd follow
613 $ cd follow
614
614
615 $ echo base > base
615 $ echo base > base
616 $ hg ci -Ambase -d '1 0'
616 $ hg ci -Ambase -d '1 0'
617 adding base
617 adding base
618
618
619 $ echo r1 >> base
619 $ echo r1 >> base
620 $ hg ci -Amr1 -d '1 0'
620 $ hg ci -Amr1 -d '1 0'
621 $ echo r2 >> base
621 $ echo r2 >> base
622 $ hg ci -Amr2 -d '1 0'
622 $ hg ci -Amr2 -d '1 0'
623
623
624 $ hg up -C 1
624 $ hg up -C 1
625 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
625 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
626 $ echo b1 > b1
626 $ echo b1 > b1
627
627
628 log -r "follow('set:clean()')"
628 log -r "follow('set:clean()')"
629
629
630 $ hg log -r "follow('set:clean()')"
630 $ hg log -r "follow('set:clean()')"
631 changeset: 0:67e992f2c4f3
631 changeset: 0:67e992f2c4f3
632 user: test
632 user: test
633 date: Thu Jan 01 00:00:01 1970 +0000
633 date: Thu Jan 01 00:00:01 1970 +0000
634 summary: base
634 summary: base
635
635
636 changeset: 1:3d5bf5654eda
636 changeset: 1:3d5bf5654eda
637 user: test
637 user: test
638 date: Thu Jan 01 00:00:01 1970 +0000
638 date: Thu Jan 01 00:00:01 1970 +0000
639 summary: r1
639 summary: r1
640
640
641
641
642 $ hg ci -Amb1 -d '1 0'
642 $ hg ci -Amb1 -d '1 0'
643 adding b1
643 adding b1
644 created new head
644 created new head
645
645
646
646
647 log -f
647 log -f
648
648
649 $ hg log -f
649 $ hg log -f
650 changeset: 3:e62f78d544b4
650 changeset: 3:e62f78d544b4
651 tag: tip
651 tag: tip
652 parent: 1:3d5bf5654eda
652 parent: 1:3d5bf5654eda
653 user: test
653 user: test
654 date: Thu Jan 01 00:00:01 1970 +0000
654 date: Thu Jan 01 00:00:01 1970 +0000
655 summary: b1
655 summary: b1
656
656
657 changeset: 1:3d5bf5654eda
657 changeset: 1:3d5bf5654eda
658 user: test
658 user: test
659 date: Thu Jan 01 00:00:01 1970 +0000
659 date: Thu Jan 01 00:00:01 1970 +0000
660 summary: r1
660 summary: r1
661
661
662 changeset: 0:67e992f2c4f3
662 changeset: 0:67e992f2c4f3
663 user: test
663 user: test
664 date: Thu Jan 01 00:00:01 1970 +0000
664 date: Thu Jan 01 00:00:01 1970 +0000
665 summary: base
665 summary: base
666
666
667
667
668 log -r follow('glob:b*')
668 log -r follow('glob:b*')
669
669
670 $ hg log -r "follow('glob:b*')"
670 $ hg log -r "follow('glob:b*')"
671 changeset: 0:67e992f2c4f3
671 changeset: 0:67e992f2c4f3
672 user: test
672 user: test
673 date: Thu Jan 01 00:00:01 1970 +0000
673 date: Thu Jan 01 00:00:01 1970 +0000
674 summary: base
674 summary: base
675
675
676 changeset: 1:3d5bf5654eda
676 changeset: 1:3d5bf5654eda
677 user: test
677 user: test
678 date: Thu Jan 01 00:00:01 1970 +0000
678 date: Thu Jan 01 00:00:01 1970 +0000
679 summary: r1
679 summary: r1
680
680
681 changeset: 3:e62f78d544b4
681 changeset: 3:e62f78d544b4
682 tag: tip
682 tag: tip
683 parent: 1:3d5bf5654eda
683 parent: 1:3d5bf5654eda
684 user: test
684 user: test
685 date: Thu Jan 01 00:00:01 1970 +0000
685 date: Thu Jan 01 00:00:01 1970 +0000
686 summary: b1
686 summary: b1
687
687
688 log -f -r '1 + 4'
688 log -f -r '1 + 4'
689
689
690 $ hg up -C 0
690 $ hg up -C 0
691 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
691 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
692 $ echo b2 > b2
692 $ echo b2 > b2
693 $ hg ci -Amb2 -d '1 0'
693 $ hg ci -Amb2 -d '1 0'
694 adding b2
694 adding b2
695 created new head
695 created new head
696 $ hg log -f -r '1 + 4'
696 $ hg log -f -r '1 + 4'
697 changeset: 4:ddb82e70d1a1
697 changeset: 4:ddb82e70d1a1
698 tag: tip
698 tag: tip
699 parent: 0:67e992f2c4f3
699 parent: 0:67e992f2c4f3
700 user: test
700 user: test
701 date: Thu Jan 01 00:00:01 1970 +0000
701 date: Thu Jan 01 00:00:01 1970 +0000
702 summary: b2
702 summary: b2
703
703
704 changeset: 1:3d5bf5654eda
704 changeset: 1:3d5bf5654eda
705 user: test
705 user: test
706 date: Thu Jan 01 00:00:01 1970 +0000
706 date: Thu Jan 01 00:00:01 1970 +0000
707 summary: r1
707 summary: r1
708
708
709 changeset: 0:67e992f2c4f3
709 changeset: 0:67e992f2c4f3
710 user: test
710 user: test
711 date: Thu Jan 01 00:00:01 1970 +0000
711 date: Thu Jan 01 00:00:01 1970 +0000
712 summary: base
712 summary: base
713
713
714 log -r "follow('set:grep(b2)')"
714 log -r "follow('set:grep(b2)')"
715
715
716 $ hg log -r "follow('set:grep(b2)')"
716 $ hg log -r "follow('set:grep(b2)')"
717 changeset: 4:ddb82e70d1a1
717 changeset: 4:ddb82e70d1a1
718 tag: tip
718 tag: tip
719 parent: 0:67e992f2c4f3
719 parent: 0:67e992f2c4f3
720 user: test
720 user: test
721 date: Thu Jan 01 00:00:01 1970 +0000
721 date: Thu Jan 01 00:00:01 1970 +0000
722 summary: b2
722 summary: b2
723
723
724 log -r "follow('set:grep(b2)', 4)"
724 log -r "follow('set:grep(b2)', 4)"
725
725
726 $ hg up -qC 0
726 $ hg up -qC 0
727 $ hg log -r "follow('set:grep(b2)', 4)"
727 $ hg log -r "follow('set:grep(b2)', 4)"
728 changeset: 4:ddb82e70d1a1
728 changeset: 4:ddb82e70d1a1
729 tag: tip
729 tag: tip
730 parent: 0:67e992f2c4f3
730 parent: 0:67e992f2c4f3
731 user: test
731 user: test
732 date: Thu Jan 01 00:00:01 1970 +0000
732 date: Thu Jan 01 00:00:01 1970 +0000
733 summary: b2
733 summary: b2
734
734
735
736 follow files starting from multiple revisions:
737
738 $ hg log -T '{rev}: {files}\n' -r "follow('glob:b?', 2+3+4)"
739 3: b1
740 4: b2
741
742 follow files starting from empty revision:
743
744 $ hg log -T '{rev}: {files}\n' -r "follow('glob:*', .-.)"
745 abort: follow expected at least one starting revision!
746 [255]
747
735 $ hg up -qC 4
748 $ hg up -qC 4
736
749
737 log -f -r null
750 log -f -r null
738
751
739 $ hg log -f -r null
752 $ hg log -f -r null
740 changeset: -1:000000000000
753 changeset: -1:000000000000
741 user:
754 user:
742 date: Thu Jan 01 00:00:00 1970 +0000
755 date: Thu Jan 01 00:00:00 1970 +0000
743
756
744 $ hg log -f -r null -G
757 $ hg log -f -r null -G
745 o changeset: -1:000000000000
758 o changeset: -1:000000000000
746 user:
759 user:
747 date: Thu Jan 01 00:00:00 1970 +0000
760 date: Thu Jan 01 00:00:00 1970 +0000
748
761
749
762
750
763
751 log -f with null parent
764 log -f with null parent
752
765
753 $ hg up -C null
766 $ hg up -C null
754 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
767 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
755 $ hg log -f
768 $ hg log -f
756
769
757
770
758 log -r . with two parents
771 log -r . with two parents
759
772
760 $ hg up -C 3
773 $ hg up -C 3
761 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
774 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
762 $ hg merge tip
775 $ hg merge tip
763 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
776 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
764 (branch merge, don't forget to commit)
777 (branch merge, don't forget to commit)
765 $ hg log -r .
778 $ hg log -r .
766 changeset: 3:e62f78d544b4
779 changeset: 3:e62f78d544b4
767 parent: 1:3d5bf5654eda
780 parent: 1:3d5bf5654eda
768 user: test
781 user: test
769 date: Thu Jan 01 00:00:01 1970 +0000
782 date: Thu Jan 01 00:00:01 1970 +0000
770 summary: b1
783 summary: b1
771
784
772
785
773
786
774 log -r . with one parent
787 log -r . with one parent
775
788
776 $ hg ci -mm12 -d '1 0'
789 $ hg ci -mm12 -d '1 0'
777 $ hg log -r .
790 $ hg log -r .
778 changeset: 5:302e9dd6890d
791 changeset: 5:302e9dd6890d
779 tag: tip
792 tag: tip
780 parent: 3:e62f78d544b4
793 parent: 3:e62f78d544b4
781 parent: 4:ddb82e70d1a1
794 parent: 4:ddb82e70d1a1
782 user: test
795 user: test
783 date: Thu Jan 01 00:00:01 1970 +0000
796 date: Thu Jan 01 00:00:01 1970 +0000
784 summary: m12
797 summary: m12
785
798
786
799
787 $ echo postm >> b1
800 $ echo postm >> b1
788 $ hg ci -Amb1.1 -d'1 0'
801 $ hg ci -Amb1.1 -d'1 0'
789
802
790
803
791 log --follow-first
804 log --follow-first
792
805
793 $ hg log --follow-first
806 $ hg log --follow-first
794 changeset: 6:2404bbcab562
807 changeset: 6:2404bbcab562
795 tag: tip
808 tag: tip
796 user: test
809 user: test
797 date: Thu Jan 01 00:00:01 1970 +0000
810 date: Thu Jan 01 00:00:01 1970 +0000
798 summary: b1.1
811 summary: b1.1
799
812
800 changeset: 5:302e9dd6890d
813 changeset: 5:302e9dd6890d
801 parent: 3:e62f78d544b4
814 parent: 3:e62f78d544b4
802 parent: 4:ddb82e70d1a1
815 parent: 4:ddb82e70d1a1
803 user: test
816 user: test
804 date: Thu Jan 01 00:00:01 1970 +0000
817 date: Thu Jan 01 00:00:01 1970 +0000
805 summary: m12
818 summary: m12
806
819
807 changeset: 3:e62f78d544b4
820 changeset: 3:e62f78d544b4
808 parent: 1:3d5bf5654eda
821 parent: 1:3d5bf5654eda
809 user: test
822 user: test
810 date: Thu Jan 01 00:00:01 1970 +0000
823 date: Thu Jan 01 00:00:01 1970 +0000
811 summary: b1
824 summary: b1
812
825
813 changeset: 1:3d5bf5654eda
826 changeset: 1:3d5bf5654eda
814 user: test
827 user: test
815 date: Thu Jan 01 00:00:01 1970 +0000
828 date: Thu Jan 01 00:00:01 1970 +0000
816 summary: r1
829 summary: r1
817
830
818 changeset: 0:67e992f2c4f3
831 changeset: 0:67e992f2c4f3
819 user: test
832 user: test
820 date: Thu Jan 01 00:00:01 1970 +0000
833 date: Thu Jan 01 00:00:01 1970 +0000
821 summary: base
834 summary: base
822
835
823
836
824
837
825 log -P 2
838 log -P 2
826
839
827 $ hg log -P 2
840 $ hg log -P 2
828 changeset: 6:2404bbcab562
841 changeset: 6:2404bbcab562
829 tag: tip
842 tag: tip
830 user: test
843 user: test
831 date: Thu Jan 01 00:00:01 1970 +0000
844 date: Thu Jan 01 00:00:01 1970 +0000
832 summary: b1.1
845 summary: b1.1
833
846
834 changeset: 5:302e9dd6890d
847 changeset: 5:302e9dd6890d
835 parent: 3:e62f78d544b4
848 parent: 3:e62f78d544b4
836 parent: 4:ddb82e70d1a1
849 parent: 4:ddb82e70d1a1
837 user: test
850 user: test
838 date: Thu Jan 01 00:00:01 1970 +0000
851 date: Thu Jan 01 00:00:01 1970 +0000
839 summary: m12
852 summary: m12
840
853
841 changeset: 4:ddb82e70d1a1
854 changeset: 4:ddb82e70d1a1
842 parent: 0:67e992f2c4f3
855 parent: 0:67e992f2c4f3
843 user: test
856 user: test
844 date: Thu Jan 01 00:00:01 1970 +0000
857 date: Thu Jan 01 00:00:01 1970 +0000
845 summary: b2
858 summary: b2
846
859
847 changeset: 3:e62f78d544b4
860 changeset: 3:e62f78d544b4
848 parent: 1:3d5bf5654eda
861 parent: 1:3d5bf5654eda
849 user: test
862 user: test
850 date: Thu Jan 01 00:00:01 1970 +0000
863 date: Thu Jan 01 00:00:01 1970 +0000
851 summary: b1
864 summary: b1
852
865
853
866
854
867
855 log -r tip -p --git
868 log -r tip -p --git
856
869
857 $ hg log -r tip -p --git
870 $ hg log -r tip -p --git
858 changeset: 6:2404bbcab562
871 changeset: 6:2404bbcab562
859 tag: tip
872 tag: tip
860 user: test
873 user: test
861 date: Thu Jan 01 00:00:01 1970 +0000
874 date: Thu Jan 01 00:00:01 1970 +0000
862 summary: b1.1
875 summary: b1.1
863
876
864 diff --git a/b1 b/b1
877 diff --git a/b1 b/b1
865 --- a/b1
878 --- a/b1
866 +++ b/b1
879 +++ b/b1
867 @@ -1,1 +1,2 @@
880 @@ -1,1 +1,2 @@
868 b1
881 b1
869 +postm
882 +postm
870
883
871
884
872
885
873 log -r ""
886 log -r ""
874
887
875 $ hg log -r ''
888 $ hg log -r ''
876 hg: parse error: empty query
889 hg: parse error: empty query
877 [255]
890 [255]
878
891
879 log -r <some unknown node id>
892 log -r <some unknown node id>
880
893
881 $ hg log -r 1000000000000000000000000000000000000000
894 $ hg log -r 1000000000000000000000000000000000000000
882 abort: unknown revision '1000000000000000000000000000000000000000'!
895 abort: unknown revision '1000000000000000000000000000000000000000'!
883 [255]
896 [255]
884
897
885 log -k r1
898 log -k r1
886
899
887 $ hg log -k r1
900 $ hg log -k r1
888 changeset: 1:3d5bf5654eda
901 changeset: 1:3d5bf5654eda
889 user: test
902 user: test
890 date: Thu Jan 01 00:00:01 1970 +0000
903 date: Thu Jan 01 00:00:01 1970 +0000
891 summary: r1
904 summary: r1
892
905
893 log -p -l2 --color=always
906 log -p -l2 --color=always
894
907
895 $ hg --config extensions.color= --config color.mode=ansi \
908 $ hg --config extensions.color= --config color.mode=ansi \
896 > log -p -l2 --color=always
909 > log -p -l2 --color=always
897 \x1b[0;33mchangeset: 6:2404bbcab562\x1b[0m (esc)
910 \x1b[0;33mchangeset: 6:2404bbcab562\x1b[0m (esc)
898 tag: tip
911 tag: tip
899 user: test
912 user: test
900 date: Thu Jan 01 00:00:01 1970 +0000
913 date: Thu Jan 01 00:00:01 1970 +0000
901 summary: b1.1
914 summary: b1.1
902
915
903 \x1b[0;1mdiff -r 302e9dd6890d -r 2404bbcab562 b1\x1b[0m (esc)
916 \x1b[0;1mdiff -r 302e9dd6890d -r 2404bbcab562 b1\x1b[0m (esc)
904 \x1b[0;31;1m--- a/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
917 \x1b[0;31;1m--- a/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
905 \x1b[0;32;1m+++ b/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
918 \x1b[0;32;1m+++ b/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
906 \x1b[0;35m@@ -1,1 +1,2 @@\x1b[0m (esc)
919 \x1b[0;35m@@ -1,1 +1,2 @@\x1b[0m (esc)
907 b1
920 b1
908 \x1b[0;32m+postm\x1b[0m (esc)
921 \x1b[0;32m+postm\x1b[0m (esc)
909
922
910 \x1b[0;33mchangeset: 5:302e9dd6890d\x1b[0m (esc)
923 \x1b[0;33mchangeset: 5:302e9dd6890d\x1b[0m (esc)
911 parent: 3:e62f78d544b4
924 parent: 3:e62f78d544b4
912 parent: 4:ddb82e70d1a1
925 parent: 4:ddb82e70d1a1
913 user: test
926 user: test
914 date: Thu Jan 01 00:00:01 1970 +0000
927 date: Thu Jan 01 00:00:01 1970 +0000
915 summary: m12
928 summary: m12
916
929
917 \x1b[0;1mdiff -r e62f78d544b4 -r 302e9dd6890d b2\x1b[0m (esc)
930 \x1b[0;1mdiff -r e62f78d544b4 -r 302e9dd6890d b2\x1b[0m (esc)
918 \x1b[0;31;1m--- /dev/null Thu Jan 01 00:00:00 1970 +0000\x1b[0m (esc)
931 \x1b[0;31;1m--- /dev/null Thu Jan 01 00:00:00 1970 +0000\x1b[0m (esc)
919 \x1b[0;32;1m+++ b/b2 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
932 \x1b[0;32;1m+++ b/b2 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
920 \x1b[0;35m@@ -0,0 +1,1 @@\x1b[0m (esc)
933 \x1b[0;35m@@ -0,0 +1,1 @@\x1b[0m (esc)
921 \x1b[0;32m+b2\x1b[0m (esc)
934 \x1b[0;32m+b2\x1b[0m (esc)
922
935
923
936
924
937
925 log -r tip --stat
938 log -r tip --stat
926
939
927 $ hg log -r tip --stat
940 $ hg log -r tip --stat
928 changeset: 6:2404bbcab562
941 changeset: 6:2404bbcab562
929 tag: tip
942 tag: tip
930 user: test
943 user: test
931 date: Thu Jan 01 00:00:01 1970 +0000
944 date: Thu Jan 01 00:00:01 1970 +0000
932 summary: b1.1
945 summary: b1.1
933
946
934 b1 | 1 +
947 b1 | 1 +
935 1 files changed, 1 insertions(+), 0 deletions(-)
948 1 files changed, 1 insertions(+), 0 deletions(-)
936
949
937
950
938 $ cd ..
951 $ cd ..
939
952
940 log --follow --patch FILE in repository where linkrev isn't trustworthy
953 log --follow --patch FILE in repository where linkrev isn't trustworthy
941 (issue5376)
954 (issue5376)
942
955
943 $ hg init follow-dup
956 $ hg init follow-dup
944 $ cd follow-dup
957 $ cd follow-dup
945 $ cat <<EOF >> .hg/hgrc
958 $ cat <<EOF >> .hg/hgrc
946 > [ui]
959 > [ui]
947 > logtemplate = '=== {rev}: {desc}\n'
960 > logtemplate = '=== {rev}: {desc}\n'
948 > [diff]
961 > [diff]
949 > nodates = True
962 > nodates = True
950 > EOF
963 > EOF
951 $ echo 0 >> a
964 $ echo 0 >> a
952 $ hg ci -qAm 'a0'
965 $ hg ci -qAm 'a0'
953 $ echo 1 >> a
966 $ echo 1 >> a
954 $ hg ci -m 'a1'
967 $ hg ci -m 'a1'
955 $ hg up -q 0
968 $ hg up -q 0
956 $ echo 1 >> a
969 $ echo 1 >> a
957 $ touch b
970 $ touch b
958 $ hg ci -qAm 'a1 with b'
971 $ hg ci -qAm 'a1 with b'
959 $ echo 3 >> a
972 $ echo 3 >> a
960 $ hg ci -m 'a3'
973 $ hg ci -m 'a3'
961
974
962 fctx.rev() == 2, but fctx.linkrev() == 1
975 fctx.rev() == 2, but fctx.linkrev() == 1
963
976
964 $ hg log -pf a
977 $ hg log -pf a
965 === 3: a3
978 === 3: a3
966 diff -r 4ea02ba94d66 -r e7a6331a34f0 a
979 diff -r 4ea02ba94d66 -r e7a6331a34f0 a
967 --- a/a
980 --- a/a
968 +++ b/a
981 +++ b/a
969 @@ -1,2 +1,3 @@
982 @@ -1,2 +1,3 @@
970 0
983 0
971 1
984 1
972 +3
985 +3
973
986
974 === 2: a1 with b
987 === 2: a1 with b
975 diff -r 49b5e81287e2 -r 4ea02ba94d66 a
988 diff -r 49b5e81287e2 -r 4ea02ba94d66 a
976 --- a/a
989 --- a/a
977 +++ b/a
990 +++ b/a
978 @@ -1,1 +1,2 @@
991 @@ -1,1 +1,2 @@
979 0
992 0
980 +1
993 +1
981
994
982 === 0: a0
995 === 0: a0
983 diff -r 000000000000 -r 49b5e81287e2 a
996 diff -r 000000000000 -r 49b5e81287e2 a
984 --- /dev/null
997 --- /dev/null
985 +++ b/a
998 +++ b/a
986 @@ -0,0 +1,1 @@
999 @@ -0,0 +1,1 @@
987 +0
1000 +0
988
1001
989
1002
990 fctx.introrev() == 2, but fctx.linkrev() == 1
1003 fctx.introrev() == 2, but fctx.linkrev() == 1
991
1004
992 $ hg up -q 2
1005 $ hg up -q 2
993 $ hg log -pf a
1006 $ hg log -pf a
994 === 2: a1 with b
1007 === 2: a1 with b
995 diff -r 49b5e81287e2 -r 4ea02ba94d66 a
1008 diff -r 49b5e81287e2 -r 4ea02ba94d66 a
996 --- a/a
1009 --- a/a
997 +++ b/a
1010 +++ b/a
998 @@ -1,1 +1,2 @@
1011 @@ -1,1 +1,2 @@
999 0
1012 0
1000 +1
1013 +1
1001
1014
1002 === 0: a0
1015 === 0: a0
1003 diff -r 000000000000 -r 49b5e81287e2 a
1016 diff -r 000000000000 -r 49b5e81287e2 a
1004 --- /dev/null
1017 --- /dev/null
1005 +++ b/a
1018 +++ b/a
1006 @@ -0,0 +1,1 @@
1019 @@ -0,0 +1,1 @@
1007 +0
1020 +0
1008
1021
1009
1022
1010 $ cd ..
1023 $ cd ..
1011
1024
1012 Multiple copy sources of a file:
1025 Multiple copy sources of a file:
1013
1026
1014 $ hg init follow-multi
1027 $ hg init follow-multi
1015 $ cd follow-multi
1028 $ cd follow-multi
1016 $ echo 0 >> a
1029 $ echo 0 >> a
1017 $ hg ci -qAm 'a'
1030 $ hg ci -qAm 'a'
1018 $ hg cp a b
1031 $ hg cp a b
1019 $ hg ci -m 'a->b'
1032 $ hg ci -m 'a->b'
1020 $ echo 2 >> a
1033 $ echo 2 >> a
1021 $ hg ci -m 'a'
1034 $ hg ci -m 'a'
1022 $ echo 3 >> b
1035 $ echo 3 >> b
1023 $ hg ci -m 'b'
1036 $ hg ci -m 'b'
1024 $ echo 4 >> a
1037 $ echo 4 >> a
1025 $ echo 4 >> b
1038 $ echo 4 >> b
1026 $ hg ci -m 'a,b'
1039 $ hg ci -m 'a,b'
1027 $ echo 5 >> a
1040 $ echo 5 >> a
1028 $ hg ci -m 'a0'
1041 $ hg ci -m 'a0'
1029 $ echo 6 >> b
1042 $ echo 6 >> b
1030 $ hg ci -m 'b0'
1043 $ hg ci -m 'b0'
1031 $ hg up -q 4
1044 $ hg up -q 4
1032 $ echo 7 >> b
1045 $ echo 7 >> b
1033 $ hg ci -m 'b1'
1046 $ hg ci -m 'b1'
1034 created new head
1047 created new head
1035 $ echo 8 >> a
1048 $ echo 8 >> a
1036 $ hg ci -m 'a1'
1049 $ hg ci -m 'a1'
1037 $ hg rm a
1050 $ hg rm a
1038 $ hg mv b a
1051 $ hg mv b a
1039 $ hg ci -m 'b1->a1'
1052 $ hg ci -m 'b1->a1'
1040 $ hg merge -qt :local
1053 $ hg merge -qt :local
1041 $ hg ci -m '(a0,b1->a1)->a'
1054 $ hg ci -m '(a0,b1->a1)->a'
1042
1055
1043 $ hg log -GT '{rev}: {desc}\n'
1056 $ hg log -GT '{rev}: {desc}\n'
1044 @ 10: (a0,b1->a1)->a
1057 @ 10: (a0,b1->a1)->a
1045 |\
1058 |\
1046 | o 9: b1->a1
1059 | o 9: b1->a1
1047 | |
1060 | |
1048 | o 8: a1
1061 | o 8: a1
1049 | |
1062 | |
1050 | o 7: b1
1063 | o 7: b1
1051 | |
1064 | |
1052 o | 6: b0
1065 o | 6: b0
1053 | |
1066 | |
1054 o | 5: a0
1067 o | 5: a0
1055 |/
1068 |/
1056 o 4: a,b
1069 o 4: a,b
1057 |
1070 |
1058 o 3: b
1071 o 3: b
1059 |
1072 |
1060 o 2: a
1073 o 2: a
1061 |
1074 |
1062 o 1: a->b
1075 o 1: a->b
1063 |
1076 |
1064 o 0: a
1077 o 0: a
1065
1078
1066
1079
1067 since file 'a' has multiple copy sources at the revision 4, ancestors can't
1080 since file 'a' has multiple copy sources at the revision 4, ancestors can't
1068 be indexed solely by fctx.linkrev().
1081 be indexed solely by fctx.linkrev().
1069
1082
1070 $ hg log -T '{rev}: {desc}\n' -f a
1083 $ hg log -T '{rev}: {desc}\n' -f a
1071 10: (a0,b1->a1)->a
1084 10: (a0,b1->a1)->a
1072 9: b1->a1
1085 9: b1->a1
1073 7: b1
1086 7: b1
1074 5: a0
1087 5: a0
1075 4: a,b
1088 4: a,b
1076 3: b
1089 3: b
1077 2: a
1090 2: a
1078 1: a->b
1091 1: a->b
1079 0: a
1092 0: a
1080
1093
1081 $ cd ..
1094 $ cd ..
1082
1095
1083 Test that log should respect the order of -rREV even if multiple OR conditions
1096 Test that log should respect the order of -rREV even if multiple OR conditions
1084 are specified (issue5100):
1097 are specified (issue5100):
1085
1098
1086 $ hg init revorder
1099 $ hg init revorder
1087 $ cd revorder
1100 $ cd revorder
1088
1101
1089 $ hg branch -q b0
1102 $ hg branch -q b0
1090 $ echo 0 >> f0
1103 $ echo 0 >> f0
1091 $ hg ci -qAm k0 -u u0
1104 $ hg ci -qAm k0 -u u0
1092 $ hg branch -q b1
1105 $ hg branch -q b1
1093 $ echo 1 >> f1
1106 $ echo 1 >> f1
1094 $ hg ci -qAm k1 -u u1
1107 $ hg ci -qAm k1 -u u1
1095 $ hg branch -q b2
1108 $ hg branch -q b2
1096 $ echo 2 >> f2
1109 $ echo 2 >> f2
1097 $ hg ci -qAm k2 -u u2
1110 $ hg ci -qAm k2 -u u2
1098
1111
1099 $ hg update -q b2
1112 $ hg update -q b2
1100 $ echo 3 >> f2
1113 $ echo 3 >> f2
1101 $ hg ci -qAm k2 -u u2
1114 $ hg ci -qAm k2 -u u2
1102 $ hg update -q b1
1115 $ hg update -q b1
1103 $ echo 4 >> f1
1116 $ echo 4 >> f1
1104 $ hg ci -qAm k1 -u u1
1117 $ hg ci -qAm k1 -u u1
1105 $ hg update -q b0
1118 $ hg update -q b0
1106 $ echo 5 >> f0
1119 $ echo 5 >> f0
1107 $ hg ci -qAm k0 -u u0
1120 $ hg ci -qAm k0 -u u0
1108
1121
1109 summary of revisions:
1122 summary of revisions:
1110
1123
1111 $ hg log -G -T '{rev} {branch} {author} {desc} {files}\n'
1124 $ hg log -G -T '{rev} {branch} {author} {desc} {files}\n'
1112 @ 5 b0 u0 k0 f0
1125 @ 5 b0 u0 k0 f0
1113 |
1126 |
1114 | o 4 b1 u1 k1 f1
1127 | o 4 b1 u1 k1 f1
1115 | |
1128 | |
1116 | | o 3 b2 u2 k2 f2
1129 | | o 3 b2 u2 k2 f2
1117 | | |
1130 | | |
1118 | | o 2 b2 u2 k2 f2
1131 | | o 2 b2 u2 k2 f2
1119 | |/
1132 | |/
1120 | o 1 b1 u1 k1 f1
1133 | o 1 b1 u1 k1 f1
1121 |/
1134 |/
1122 o 0 b0 u0 k0 f0
1135 o 0 b0 u0 k0 f0
1123
1136
1124
1137
1125 log -b BRANCH in ascending order:
1138 log -b BRANCH in ascending order:
1126
1139
1127 $ hg log -r0:tip -T '{rev} {branch}\n' -b b0 -b b1
1140 $ hg log -r0:tip -T '{rev} {branch}\n' -b b0 -b b1
1128 0 b0
1141 0 b0
1129 1 b1
1142 1 b1
1130 4 b1
1143 4 b1
1131 5 b0
1144 5 b0
1132 $ hg log -r0:tip -T '{rev} {branch}\n' -b b1 -b b0
1145 $ hg log -r0:tip -T '{rev} {branch}\n' -b b1 -b b0
1133 0 b0
1146 0 b0
1134 1 b1
1147 1 b1
1135 4 b1
1148 4 b1
1136 5 b0
1149 5 b0
1137
1150
1138 log --only-branch BRANCH in descending order:
1151 log --only-branch BRANCH in descending order:
1139
1152
1140 $ hg log -rtip:0 -T '{rev} {branch}\n' --only-branch b1 --only-branch b2
1153 $ hg log -rtip:0 -T '{rev} {branch}\n' --only-branch b1 --only-branch b2
1141 4 b1
1154 4 b1
1142 3 b2
1155 3 b2
1143 2 b2
1156 2 b2
1144 1 b1
1157 1 b1
1145 $ hg log -rtip:0 -T '{rev} {branch}\n' --only-branch b2 --only-branch b1
1158 $ hg log -rtip:0 -T '{rev} {branch}\n' --only-branch b2 --only-branch b1
1146 4 b1
1159 4 b1
1147 3 b2
1160 3 b2
1148 2 b2
1161 2 b2
1149 1 b1
1162 1 b1
1150
1163
1151 log -u USER in ascending order, against compound set:
1164 log -u USER in ascending order, against compound set:
1152
1165
1153 $ hg log -r'::head()' -T '{rev} {author}\n' -u u0 -u u2
1166 $ hg log -r'::head()' -T '{rev} {author}\n' -u u0 -u u2
1154 0 u0
1167 0 u0
1155 2 u2
1168 2 u2
1156 3 u2
1169 3 u2
1157 5 u0
1170 5 u0
1158 $ hg log -r'::head()' -T '{rev} {author}\n' -u u2 -u u0
1171 $ hg log -r'::head()' -T '{rev} {author}\n' -u u2 -u u0
1159 0 u0
1172 0 u0
1160 2 u2
1173 2 u2
1161 3 u2
1174 3 u2
1162 5 u0
1175 5 u0
1163
1176
1164 log -k TEXT in descending order, against compound set:
1177 log -k TEXT in descending order, against compound set:
1165
1178
1166 $ hg log -r'5 + reverse(::3)' -T '{rev} {desc}\n' -k k0 -k k1 -k k2
1179 $ hg log -r'5 + reverse(::3)' -T '{rev} {desc}\n' -k k0 -k k1 -k k2
1167 5 k0
1180 5 k0
1168 3 k2
1181 3 k2
1169 2 k2
1182 2 k2
1170 1 k1
1183 1 k1
1171 0 k0
1184 0 k0
1172 $ hg log -r'5 + reverse(::3)' -T '{rev} {desc}\n' -k k2 -k k1 -k k0
1185 $ hg log -r'5 + reverse(::3)' -T '{rev} {desc}\n' -k k2 -k k1 -k k0
1173 5 k0
1186 5 k0
1174 3 k2
1187 3 k2
1175 2 k2
1188 2 k2
1176 1 k1
1189 1 k1
1177 0 k0
1190 0 k0
1178
1191
1179 log FILE in ascending order, against dagrange:
1192 log FILE in ascending order, against dagrange:
1180
1193
1181 $ hg log -r1:: -T '{rev} {files}\n' f1 f2
1194 $ hg log -r1:: -T '{rev} {files}\n' f1 f2
1182 1 f1
1195 1 f1
1183 2 f2
1196 2 f2
1184 3 f2
1197 3 f2
1185 4 f1
1198 4 f1
1186 $ hg log -r1:: -T '{rev} {files}\n' f2 f1
1199 $ hg log -r1:: -T '{rev} {files}\n' f2 f1
1187 1 f1
1200 1 f1
1188 2 f2
1201 2 f2
1189 3 f2
1202 3 f2
1190 4 f1
1203 4 f1
1191
1204
1192 $ cd ..
1205 $ cd ..
1193
1206
1194 User
1207 User
1195
1208
1196 $ hg init usertest
1209 $ hg init usertest
1197 $ cd usertest
1210 $ cd usertest
1198
1211
1199 $ echo a > a
1212 $ echo a > a
1200 $ hg ci -A -m "a" -u "User One <user1@example.org>"
1213 $ hg ci -A -m "a" -u "User One <user1@example.org>"
1201 adding a
1214 adding a
1202 $ echo b > b
1215 $ echo b > b
1203 $ hg ci -A -m "b" -u "User Two <user2@example.org>"
1216 $ hg ci -A -m "b" -u "User Two <user2@example.org>"
1204 adding b
1217 adding b
1205
1218
1206 $ hg log -u "User One <user1@example.org>"
1219 $ hg log -u "User One <user1@example.org>"
1207 changeset: 0:29a4c94f1924
1220 changeset: 0:29a4c94f1924
1208 user: User One <user1@example.org>
1221 user: User One <user1@example.org>
1209 date: Thu Jan 01 00:00:00 1970 +0000
1222 date: Thu Jan 01 00:00:00 1970 +0000
1210 summary: a
1223 summary: a
1211
1224
1212 $ hg log -u "user1" -u "user2"
1225 $ hg log -u "user1" -u "user2"
1213 changeset: 1:e834b5e69c0e
1226 changeset: 1:e834b5e69c0e
1214 tag: tip
1227 tag: tip
1215 user: User Two <user2@example.org>
1228 user: User Two <user2@example.org>
1216 date: Thu Jan 01 00:00:00 1970 +0000
1229 date: Thu Jan 01 00:00:00 1970 +0000
1217 summary: b
1230 summary: b
1218
1231
1219 changeset: 0:29a4c94f1924
1232 changeset: 0:29a4c94f1924
1220 user: User One <user1@example.org>
1233 user: User One <user1@example.org>
1221 date: Thu Jan 01 00:00:00 1970 +0000
1234 date: Thu Jan 01 00:00:00 1970 +0000
1222 summary: a
1235 summary: a
1223
1236
1224 $ hg log -u "user3"
1237 $ hg log -u "user3"
1225
1238
1226 $ cd ..
1239 $ cd ..
1227
1240
1228 $ hg init branches
1241 $ hg init branches
1229 $ cd branches
1242 $ cd branches
1230
1243
1231 $ echo a > a
1244 $ echo a > a
1232 $ hg ci -A -m "commit on default"
1245 $ hg ci -A -m "commit on default"
1233 adding a
1246 adding a
1234 $ hg branch test
1247 $ hg branch test
1235 marked working directory as branch test
1248 marked working directory as branch test
1236 (branches are permanent and global, did you want a bookmark?)
1249 (branches are permanent and global, did you want a bookmark?)
1237 $ echo b > b
1250 $ echo b > b
1238 $ hg ci -A -m "commit on test"
1251 $ hg ci -A -m "commit on test"
1239 adding b
1252 adding b
1240
1253
1241 $ hg up default
1254 $ hg up default
1242 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1255 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1243 $ echo c > c
1256 $ echo c > c
1244 $ hg ci -A -m "commit on default"
1257 $ hg ci -A -m "commit on default"
1245 adding c
1258 adding c
1246 $ hg up test
1259 $ hg up test
1247 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1260 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1248 $ echo c > c
1261 $ echo c > c
1249 $ hg ci -A -m "commit on test"
1262 $ hg ci -A -m "commit on test"
1250 adding c
1263 adding c
1251
1264
1252
1265
1253 log -b default
1266 log -b default
1254
1267
1255 $ hg log -b default
1268 $ hg log -b default
1256 changeset: 2:c3a4f03cc9a7
1269 changeset: 2:c3a4f03cc9a7
1257 parent: 0:24427303d56f
1270 parent: 0:24427303d56f
1258 user: test
1271 user: test
1259 date: Thu Jan 01 00:00:00 1970 +0000
1272 date: Thu Jan 01 00:00:00 1970 +0000
1260 summary: commit on default
1273 summary: commit on default
1261
1274
1262 changeset: 0:24427303d56f
1275 changeset: 0:24427303d56f
1263 user: test
1276 user: test
1264 date: Thu Jan 01 00:00:00 1970 +0000
1277 date: Thu Jan 01 00:00:00 1970 +0000
1265 summary: commit on default
1278 summary: commit on default
1266
1279
1267
1280
1268
1281
1269 log -b test
1282 log -b test
1270
1283
1271 $ hg log -b test
1284 $ hg log -b test
1272 changeset: 3:f5d8de11c2e2
1285 changeset: 3:f5d8de11c2e2
1273 branch: test
1286 branch: test
1274 tag: tip
1287 tag: tip
1275 parent: 1:d32277701ccb
1288 parent: 1:d32277701ccb
1276 user: test
1289 user: test
1277 date: Thu Jan 01 00:00:00 1970 +0000
1290 date: Thu Jan 01 00:00:00 1970 +0000
1278 summary: commit on test
1291 summary: commit on test
1279
1292
1280 changeset: 1:d32277701ccb
1293 changeset: 1:d32277701ccb
1281 branch: test
1294 branch: test
1282 user: test
1295 user: test
1283 date: Thu Jan 01 00:00:00 1970 +0000
1296 date: Thu Jan 01 00:00:00 1970 +0000
1284 summary: commit on test
1297 summary: commit on test
1285
1298
1286
1299
1287
1300
1288 log -b dummy
1301 log -b dummy
1289
1302
1290 $ hg log -b dummy
1303 $ hg log -b dummy
1291 abort: unknown revision 'dummy'!
1304 abort: unknown revision 'dummy'!
1292 [255]
1305 [255]
1293
1306
1294
1307
1295 log -b .
1308 log -b .
1296
1309
1297 $ hg log -b .
1310 $ hg log -b .
1298 changeset: 3:f5d8de11c2e2
1311 changeset: 3:f5d8de11c2e2
1299 branch: test
1312 branch: test
1300 tag: tip
1313 tag: tip
1301 parent: 1:d32277701ccb
1314 parent: 1:d32277701ccb
1302 user: test
1315 user: test
1303 date: Thu Jan 01 00:00:00 1970 +0000
1316 date: Thu Jan 01 00:00:00 1970 +0000
1304 summary: commit on test
1317 summary: commit on test
1305
1318
1306 changeset: 1:d32277701ccb
1319 changeset: 1:d32277701ccb
1307 branch: test
1320 branch: test
1308 user: test
1321 user: test
1309 date: Thu Jan 01 00:00:00 1970 +0000
1322 date: Thu Jan 01 00:00:00 1970 +0000
1310 summary: commit on test
1323 summary: commit on test
1311
1324
1312
1325
1313
1326
1314 log -b default -b test
1327 log -b default -b test
1315
1328
1316 $ hg log -b default -b test
1329 $ hg log -b default -b test
1317 changeset: 3:f5d8de11c2e2
1330 changeset: 3:f5d8de11c2e2
1318 branch: test
1331 branch: test
1319 tag: tip
1332 tag: tip
1320 parent: 1:d32277701ccb
1333 parent: 1:d32277701ccb
1321 user: test
1334 user: test
1322 date: Thu Jan 01 00:00:00 1970 +0000
1335 date: Thu Jan 01 00:00:00 1970 +0000
1323 summary: commit on test
1336 summary: commit on test
1324
1337
1325 changeset: 2:c3a4f03cc9a7
1338 changeset: 2:c3a4f03cc9a7
1326 parent: 0:24427303d56f
1339 parent: 0:24427303d56f
1327 user: test
1340 user: test
1328 date: Thu Jan 01 00:00:00 1970 +0000
1341 date: Thu Jan 01 00:00:00 1970 +0000
1329 summary: commit on default
1342 summary: commit on default
1330
1343
1331 changeset: 1:d32277701ccb
1344 changeset: 1:d32277701ccb
1332 branch: test
1345 branch: test
1333 user: test
1346 user: test
1334 date: Thu Jan 01 00:00:00 1970 +0000
1347 date: Thu Jan 01 00:00:00 1970 +0000
1335 summary: commit on test
1348 summary: commit on test
1336
1349
1337 changeset: 0:24427303d56f
1350 changeset: 0:24427303d56f
1338 user: test
1351 user: test
1339 date: Thu Jan 01 00:00:00 1970 +0000
1352 date: Thu Jan 01 00:00:00 1970 +0000
1340 summary: commit on default
1353 summary: commit on default
1341
1354
1342
1355
1343
1356
1344 log -b default -b .
1357 log -b default -b .
1345
1358
1346 $ hg log -b default -b .
1359 $ hg log -b default -b .
1347 changeset: 3:f5d8de11c2e2
1360 changeset: 3:f5d8de11c2e2
1348 branch: test
1361 branch: test
1349 tag: tip
1362 tag: tip
1350 parent: 1:d32277701ccb
1363 parent: 1:d32277701ccb
1351 user: test
1364 user: test
1352 date: Thu Jan 01 00:00:00 1970 +0000
1365 date: Thu Jan 01 00:00:00 1970 +0000
1353 summary: commit on test
1366 summary: commit on test
1354
1367
1355 changeset: 2:c3a4f03cc9a7
1368 changeset: 2:c3a4f03cc9a7
1356 parent: 0:24427303d56f
1369 parent: 0:24427303d56f
1357 user: test
1370 user: test
1358 date: Thu Jan 01 00:00:00 1970 +0000
1371 date: Thu Jan 01 00:00:00 1970 +0000
1359 summary: commit on default
1372 summary: commit on default
1360
1373
1361 changeset: 1:d32277701ccb
1374 changeset: 1:d32277701ccb
1362 branch: test
1375 branch: test
1363 user: test
1376 user: test
1364 date: Thu Jan 01 00:00:00 1970 +0000
1377 date: Thu Jan 01 00:00:00 1970 +0000
1365 summary: commit on test
1378 summary: commit on test
1366
1379
1367 changeset: 0:24427303d56f
1380 changeset: 0:24427303d56f
1368 user: test
1381 user: test
1369 date: Thu Jan 01 00:00:00 1970 +0000
1382 date: Thu Jan 01 00:00:00 1970 +0000
1370 summary: commit on default
1383 summary: commit on default
1371
1384
1372
1385
1373
1386
1374 log -b . -b test
1387 log -b . -b test
1375
1388
1376 $ hg log -b . -b test
1389 $ hg log -b . -b test
1377 changeset: 3:f5d8de11c2e2
1390 changeset: 3:f5d8de11c2e2
1378 branch: test
1391 branch: test
1379 tag: tip
1392 tag: tip
1380 parent: 1:d32277701ccb
1393 parent: 1:d32277701ccb
1381 user: test
1394 user: test
1382 date: Thu Jan 01 00:00:00 1970 +0000
1395 date: Thu Jan 01 00:00:00 1970 +0000
1383 summary: commit on test
1396 summary: commit on test
1384
1397
1385 changeset: 1:d32277701ccb
1398 changeset: 1:d32277701ccb
1386 branch: test
1399 branch: test
1387 user: test
1400 user: test
1388 date: Thu Jan 01 00:00:00 1970 +0000
1401 date: Thu Jan 01 00:00:00 1970 +0000
1389 summary: commit on test
1402 summary: commit on test
1390
1403
1391
1404
1392
1405
1393 log -b 2
1406 log -b 2
1394
1407
1395 $ hg log -b 2
1408 $ hg log -b 2
1396 changeset: 2:c3a4f03cc9a7
1409 changeset: 2:c3a4f03cc9a7
1397 parent: 0:24427303d56f
1410 parent: 0:24427303d56f
1398 user: test
1411 user: test
1399 date: Thu Jan 01 00:00:00 1970 +0000
1412 date: Thu Jan 01 00:00:00 1970 +0000
1400 summary: commit on default
1413 summary: commit on default
1401
1414
1402 changeset: 0:24427303d56f
1415 changeset: 0:24427303d56f
1403 user: test
1416 user: test
1404 date: Thu Jan 01 00:00:00 1970 +0000
1417 date: Thu Jan 01 00:00:00 1970 +0000
1405 summary: commit on default
1418 summary: commit on default
1406
1419
1407 #if gettext
1420 #if gettext
1408
1421
1409 Test that all log names are translated (e.g. branches, bookmarks, tags):
1422 Test that all log names are translated (e.g. branches, bookmarks, tags):
1410
1423
1411 $ hg bookmark babar -r tip
1424 $ hg bookmark babar -r tip
1412
1425
1413 $ HGENCODING=UTF-8 LANGUAGE=de hg log -r tip
1426 $ HGENCODING=UTF-8 LANGUAGE=de hg log -r tip
1414 \xc3\x84nderung: 3:f5d8de11c2e2 (esc)
1427 \xc3\x84nderung: 3:f5d8de11c2e2 (esc)
1415 Zweig: test
1428 Zweig: test
1416 Lesezeichen: babar
1429 Lesezeichen: babar
1417 Marke: tip
1430 Marke: tip
1418 Vorg\xc3\xa4nger: 1:d32277701ccb (esc)
1431 Vorg\xc3\xa4nger: 1:d32277701ccb (esc)
1419 Nutzer: test
1432 Nutzer: test
1420 Datum: Thu Jan 01 00:00:00 1970 +0000
1433 Datum: Thu Jan 01 00:00:00 1970 +0000
1421 Zusammenfassung: commit on test
1434 Zusammenfassung: commit on test
1422
1435
1423 $ hg bookmark -d babar
1436 $ hg bookmark -d babar
1424
1437
1425 #endif
1438 #endif
1426
1439
1427 log -p --cwd dir (in subdir)
1440 log -p --cwd dir (in subdir)
1428
1441
1429 $ mkdir dir
1442 $ mkdir dir
1430 $ hg log -p --cwd dir
1443 $ hg log -p --cwd dir
1431 changeset: 3:f5d8de11c2e2
1444 changeset: 3:f5d8de11c2e2
1432 branch: test
1445 branch: test
1433 tag: tip
1446 tag: tip
1434 parent: 1:d32277701ccb
1447 parent: 1:d32277701ccb
1435 user: test
1448 user: test
1436 date: Thu Jan 01 00:00:00 1970 +0000
1449 date: Thu Jan 01 00:00:00 1970 +0000
1437 summary: commit on test
1450 summary: commit on test
1438
1451
1439 diff -r d32277701ccb -r f5d8de11c2e2 c
1452 diff -r d32277701ccb -r f5d8de11c2e2 c
1440 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1453 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1441 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1454 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1442 @@ -0,0 +1,1 @@
1455 @@ -0,0 +1,1 @@
1443 +c
1456 +c
1444
1457
1445 changeset: 2:c3a4f03cc9a7
1458 changeset: 2:c3a4f03cc9a7
1446 parent: 0:24427303d56f
1459 parent: 0:24427303d56f
1447 user: test
1460 user: test
1448 date: Thu Jan 01 00:00:00 1970 +0000
1461 date: Thu Jan 01 00:00:00 1970 +0000
1449 summary: commit on default
1462 summary: commit on default
1450
1463
1451 diff -r 24427303d56f -r c3a4f03cc9a7 c
1464 diff -r 24427303d56f -r c3a4f03cc9a7 c
1452 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1465 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1453 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1466 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1454 @@ -0,0 +1,1 @@
1467 @@ -0,0 +1,1 @@
1455 +c
1468 +c
1456
1469
1457 changeset: 1:d32277701ccb
1470 changeset: 1:d32277701ccb
1458 branch: test
1471 branch: test
1459 user: test
1472 user: test
1460 date: Thu Jan 01 00:00:00 1970 +0000
1473 date: Thu Jan 01 00:00:00 1970 +0000
1461 summary: commit on test
1474 summary: commit on test
1462
1475
1463 diff -r 24427303d56f -r d32277701ccb b
1476 diff -r 24427303d56f -r d32277701ccb b
1464 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1477 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1465 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1478 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1466 @@ -0,0 +1,1 @@
1479 @@ -0,0 +1,1 @@
1467 +b
1480 +b
1468
1481
1469 changeset: 0:24427303d56f
1482 changeset: 0:24427303d56f
1470 user: test
1483 user: test
1471 date: Thu Jan 01 00:00:00 1970 +0000
1484 date: Thu Jan 01 00:00:00 1970 +0000
1472 summary: commit on default
1485 summary: commit on default
1473
1486
1474 diff -r 000000000000 -r 24427303d56f a
1487 diff -r 000000000000 -r 24427303d56f a
1475 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1488 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1476 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1489 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1477 @@ -0,0 +1,1 @@
1490 @@ -0,0 +1,1 @@
1478 +a
1491 +a
1479
1492
1480
1493
1481
1494
1482 log -p -R repo
1495 log -p -R repo
1483
1496
1484 $ cd dir
1497 $ cd dir
1485 $ hg log -p -R .. ../a
1498 $ hg log -p -R .. ../a
1486 changeset: 0:24427303d56f
1499 changeset: 0:24427303d56f
1487 user: test
1500 user: test
1488 date: Thu Jan 01 00:00:00 1970 +0000
1501 date: Thu Jan 01 00:00:00 1970 +0000
1489 summary: commit on default
1502 summary: commit on default
1490
1503
1491 diff -r 000000000000 -r 24427303d56f a
1504 diff -r 000000000000 -r 24427303d56f a
1492 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1505 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1493 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1506 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1494 @@ -0,0 +1,1 @@
1507 @@ -0,0 +1,1 @@
1495 +a
1508 +a
1496
1509
1497
1510
1498 $ cd ../..
1511 $ cd ../..
1499
1512
1500 $ hg init follow2
1513 $ hg init follow2
1501 $ cd follow2
1514 $ cd follow2
1502
1515
1503 # Build the following history:
1516 # Build the following history:
1504 # tip - o - x - o - x - x
1517 # tip - o - x - o - x - x
1505 # \ /
1518 # \ /
1506 # o - o - o - x
1519 # o - o - o - x
1507 # \ /
1520 # \ /
1508 # o
1521 # o
1509 #
1522 #
1510 # Where "o" is a revision containing "foo" and
1523 # Where "o" is a revision containing "foo" and
1511 # "x" is a revision without "foo"
1524 # "x" is a revision without "foo"
1512
1525
1513 $ touch init
1526 $ touch init
1514 $ hg ci -A -m "init, unrelated"
1527 $ hg ci -A -m "init, unrelated"
1515 adding init
1528 adding init
1516 $ echo 'foo' > init
1529 $ echo 'foo' > init
1517 $ hg ci -m "change, unrelated"
1530 $ hg ci -m "change, unrelated"
1518 $ echo 'foo' > foo
1531 $ echo 'foo' > foo
1519 $ hg ci -A -m "add unrelated old foo"
1532 $ hg ci -A -m "add unrelated old foo"
1520 adding foo
1533 adding foo
1521 $ hg rm foo
1534 $ hg rm foo
1522 $ hg ci -m "delete foo, unrelated"
1535 $ hg ci -m "delete foo, unrelated"
1523 $ echo 'related' > foo
1536 $ echo 'related' > foo
1524 $ hg ci -A -m "add foo, related"
1537 $ hg ci -A -m "add foo, related"
1525 adding foo
1538 adding foo
1526
1539
1527 $ hg up 0
1540 $ hg up 0
1528 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1541 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1529 $ touch branch
1542 $ touch branch
1530 $ hg ci -A -m "first branch, unrelated"
1543 $ hg ci -A -m "first branch, unrelated"
1531 adding branch
1544 adding branch
1532 created new head
1545 created new head
1533 $ touch foo
1546 $ touch foo
1534 $ hg ci -A -m "create foo, related"
1547 $ hg ci -A -m "create foo, related"
1535 adding foo
1548 adding foo
1536 $ echo 'change' > foo
1549 $ echo 'change' > foo
1537 $ hg ci -m "change foo, related"
1550 $ hg ci -m "change foo, related"
1538
1551
1539 $ hg up 6
1552 $ hg up 6
1540 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1553 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1541 $ echo 'change foo in branch' > foo
1554 $ echo 'change foo in branch' > foo
1542 $ hg ci -m "change foo in branch, related"
1555 $ hg ci -m "change foo in branch, related"
1543 created new head
1556 created new head
1544 $ hg merge 7
1557 $ hg merge 7
1545 merging foo
1558 merging foo
1546 warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
1559 warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
1547 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
1560 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
1548 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1561 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1549 [1]
1562 [1]
1550 $ echo 'merge 1' > foo
1563 $ echo 'merge 1' > foo
1551 $ hg resolve -m foo
1564 $ hg resolve -m foo
1552 (no more unresolved files)
1565 (no more unresolved files)
1553 $ hg ci -m "First merge, related"
1566 $ hg ci -m "First merge, related"
1554
1567
1555 $ hg merge 4
1568 $ hg merge 4
1556 merging foo
1569 merging foo
1557 warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
1570 warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
1558 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
1571 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
1559 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1572 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1560 [1]
1573 [1]
1561 $ echo 'merge 2' > foo
1574 $ echo 'merge 2' > foo
1562 $ hg resolve -m foo
1575 $ hg resolve -m foo
1563 (no more unresolved files)
1576 (no more unresolved files)
1564 $ hg ci -m "Last merge, related"
1577 $ hg ci -m "Last merge, related"
1565
1578
1566 $ hg log --graph
1579 $ hg log --graph
1567 @ changeset: 10:4dae8563d2c5
1580 @ changeset: 10:4dae8563d2c5
1568 |\ tag: tip
1581 |\ tag: tip
1569 | | parent: 9:7b35701b003e
1582 | | parent: 9:7b35701b003e
1570 | | parent: 4:88176d361b69
1583 | | parent: 4:88176d361b69
1571 | | user: test
1584 | | user: test
1572 | | date: Thu Jan 01 00:00:00 1970 +0000
1585 | | date: Thu Jan 01 00:00:00 1970 +0000
1573 | | summary: Last merge, related
1586 | | summary: Last merge, related
1574 | |
1587 | |
1575 | o changeset: 9:7b35701b003e
1588 | o changeset: 9:7b35701b003e
1576 | |\ parent: 8:e5416ad8a855
1589 | |\ parent: 8:e5416ad8a855
1577 | | | parent: 7:87fe3144dcfa
1590 | | | parent: 7:87fe3144dcfa
1578 | | | user: test
1591 | | | user: test
1579 | | | date: Thu Jan 01 00:00:00 1970 +0000
1592 | | | date: Thu Jan 01 00:00:00 1970 +0000
1580 | | | summary: First merge, related
1593 | | | summary: First merge, related
1581 | | |
1594 | | |
1582 | | o changeset: 8:e5416ad8a855
1595 | | o changeset: 8:e5416ad8a855
1583 | | | parent: 6:dc6c325fe5ee
1596 | | | parent: 6:dc6c325fe5ee
1584 | | | user: test
1597 | | | user: test
1585 | | | date: Thu Jan 01 00:00:00 1970 +0000
1598 | | | date: Thu Jan 01 00:00:00 1970 +0000
1586 | | | summary: change foo in branch, related
1599 | | | summary: change foo in branch, related
1587 | | |
1600 | | |
1588 | o | changeset: 7:87fe3144dcfa
1601 | o | changeset: 7:87fe3144dcfa
1589 | |/ user: test
1602 | |/ user: test
1590 | | date: Thu Jan 01 00:00:00 1970 +0000
1603 | | date: Thu Jan 01 00:00:00 1970 +0000
1591 | | summary: change foo, related
1604 | | summary: change foo, related
1592 | |
1605 | |
1593 | o changeset: 6:dc6c325fe5ee
1606 | o changeset: 6:dc6c325fe5ee
1594 | | user: test
1607 | | user: test
1595 | | date: Thu Jan 01 00:00:00 1970 +0000
1608 | | date: Thu Jan 01 00:00:00 1970 +0000
1596 | | summary: create foo, related
1609 | | summary: create foo, related
1597 | |
1610 | |
1598 | o changeset: 5:73db34516eb9
1611 | o changeset: 5:73db34516eb9
1599 | | parent: 0:e87515fd044a
1612 | | parent: 0:e87515fd044a
1600 | | user: test
1613 | | user: test
1601 | | date: Thu Jan 01 00:00:00 1970 +0000
1614 | | date: Thu Jan 01 00:00:00 1970 +0000
1602 | | summary: first branch, unrelated
1615 | | summary: first branch, unrelated
1603 | |
1616 | |
1604 o | changeset: 4:88176d361b69
1617 o | changeset: 4:88176d361b69
1605 | | user: test
1618 | | user: test
1606 | | date: Thu Jan 01 00:00:00 1970 +0000
1619 | | date: Thu Jan 01 00:00:00 1970 +0000
1607 | | summary: add foo, related
1620 | | summary: add foo, related
1608 | |
1621 | |
1609 o | changeset: 3:dd78ae4afb56
1622 o | changeset: 3:dd78ae4afb56
1610 | | user: test
1623 | | user: test
1611 | | date: Thu Jan 01 00:00:00 1970 +0000
1624 | | date: Thu Jan 01 00:00:00 1970 +0000
1612 | | summary: delete foo, unrelated
1625 | | summary: delete foo, unrelated
1613 | |
1626 | |
1614 o | changeset: 2:c4c64aedf0f7
1627 o | changeset: 2:c4c64aedf0f7
1615 | | user: test
1628 | | user: test
1616 | | date: Thu Jan 01 00:00:00 1970 +0000
1629 | | date: Thu Jan 01 00:00:00 1970 +0000
1617 | | summary: add unrelated old foo
1630 | | summary: add unrelated old foo
1618 | |
1631 | |
1619 o | changeset: 1:e5faa7440653
1632 o | changeset: 1:e5faa7440653
1620 |/ user: test
1633 |/ user: test
1621 | date: Thu Jan 01 00:00:00 1970 +0000
1634 | date: Thu Jan 01 00:00:00 1970 +0000
1622 | summary: change, unrelated
1635 | summary: change, unrelated
1623 |
1636 |
1624 o changeset: 0:e87515fd044a
1637 o changeset: 0:e87515fd044a
1625 user: test
1638 user: test
1626 date: Thu Jan 01 00:00:00 1970 +0000
1639 date: Thu Jan 01 00:00:00 1970 +0000
1627 summary: init, unrelated
1640 summary: init, unrelated
1628
1641
1629
1642
1630 $ hg --traceback log -f foo
1643 $ hg --traceback log -f foo
1631 changeset: 10:4dae8563d2c5
1644 changeset: 10:4dae8563d2c5
1632 tag: tip
1645 tag: tip
1633 parent: 9:7b35701b003e
1646 parent: 9:7b35701b003e
1634 parent: 4:88176d361b69
1647 parent: 4:88176d361b69
1635 user: test
1648 user: test
1636 date: Thu Jan 01 00:00:00 1970 +0000
1649 date: Thu Jan 01 00:00:00 1970 +0000
1637 summary: Last merge, related
1650 summary: Last merge, related
1638
1651
1639 changeset: 9:7b35701b003e
1652 changeset: 9:7b35701b003e
1640 parent: 8:e5416ad8a855
1653 parent: 8:e5416ad8a855
1641 parent: 7:87fe3144dcfa
1654 parent: 7:87fe3144dcfa
1642 user: test
1655 user: test
1643 date: Thu Jan 01 00:00:00 1970 +0000
1656 date: Thu Jan 01 00:00:00 1970 +0000
1644 summary: First merge, related
1657 summary: First merge, related
1645
1658
1646 changeset: 8:e5416ad8a855
1659 changeset: 8:e5416ad8a855
1647 parent: 6:dc6c325fe5ee
1660 parent: 6:dc6c325fe5ee
1648 user: test
1661 user: test
1649 date: Thu Jan 01 00:00:00 1970 +0000
1662 date: Thu Jan 01 00:00:00 1970 +0000
1650 summary: change foo in branch, related
1663 summary: change foo in branch, related
1651
1664
1652 changeset: 7:87fe3144dcfa
1665 changeset: 7:87fe3144dcfa
1653 user: test
1666 user: test
1654 date: Thu Jan 01 00:00:00 1970 +0000
1667 date: Thu Jan 01 00:00:00 1970 +0000
1655 summary: change foo, related
1668 summary: change foo, related
1656
1669
1657 changeset: 6:dc6c325fe5ee
1670 changeset: 6:dc6c325fe5ee
1658 user: test
1671 user: test
1659 date: Thu Jan 01 00:00:00 1970 +0000
1672 date: Thu Jan 01 00:00:00 1970 +0000
1660 summary: create foo, related
1673 summary: create foo, related
1661
1674
1662 changeset: 4:88176d361b69
1675 changeset: 4:88176d361b69
1663 user: test
1676 user: test
1664 date: Thu Jan 01 00:00:00 1970 +0000
1677 date: Thu Jan 01 00:00:00 1970 +0000
1665 summary: add foo, related
1678 summary: add foo, related
1666
1679
1667
1680
1668 Also check when maxrev < lastrevfilelog
1681 Also check when maxrev < lastrevfilelog
1669
1682
1670 $ hg --traceback log -f -r4 foo
1683 $ hg --traceback log -f -r4 foo
1671 changeset: 4:88176d361b69
1684 changeset: 4:88176d361b69
1672 user: test
1685 user: test
1673 date: Thu Jan 01 00:00:00 1970 +0000
1686 date: Thu Jan 01 00:00:00 1970 +0000
1674 summary: add foo, related
1687 summary: add foo, related
1675
1688
1676 changeset: 2:c4c64aedf0f7
1689 changeset: 2:c4c64aedf0f7
1677 user: test
1690 user: test
1678 date: Thu Jan 01 00:00:00 1970 +0000
1691 date: Thu Jan 01 00:00:00 1970 +0000
1679 summary: add unrelated old foo
1692 summary: add unrelated old foo
1680
1693
1681 $ cd ..
1694 $ cd ..
1682
1695
1683 Issue2383: hg log showing _less_ differences than hg diff
1696 Issue2383: hg log showing _less_ differences than hg diff
1684
1697
1685 $ hg init issue2383
1698 $ hg init issue2383
1686 $ cd issue2383
1699 $ cd issue2383
1687
1700
1688 Create a test repo:
1701 Create a test repo:
1689
1702
1690 $ echo a > a
1703 $ echo a > a
1691 $ hg ci -Am0
1704 $ hg ci -Am0
1692 adding a
1705 adding a
1693 $ echo b > b
1706 $ echo b > b
1694 $ hg ci -Am1
1707 $ hg ci -Am1
1695 adding b
1708 adding b
1696 $ hg co 0
1709 $ hg co 0
1697 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1710 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1698 $ echo b > a
1711 $ echo b > a
1699 $ hg ci -m2
1712 $ hg ci -m2
1700 created new head
1713 created new head
1701
1714
1702 Merge:
1715 Merge:
1703
1716
1704 $ hg merge
1717 $ hg merge
1705 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1718 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1706 (branch merge, don't forget to commit)
1719 (branch merge, don't forget to commit)
1707
1720
1708 Make sure there's a file listed in the merge to trigger the bug:
1721 Make sure there's a file listed in the merge to trigger the bug:
1709
1722
1710 $ echo c > a
1723 $ echo c > a
1711 $ hg ci -m3
1724 $ hg ci -m3
1712
1725
1713 Two files shown here in diff:
1726 Two files shown here in diff:
1714
1727
1715 $ hg diff --rev 2:3
1728 $ hg diff --rev 2:3
1716 diff -r b09be438c43a -r 8e07aafe1edc a
1729 diff -r b09be438c43a -r 8e07aafe1edc a
1717 --- a/a Thu Jan 01 00:00:00 1970 +0000
1730 --- a/a Thu Jan 01 00:00:00 1970 +0000
1718 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1731 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1719 @@ -1,1 +1,1 @@
1732 @@ -1,1 +1,1 @@
1720 -b
1733 -b
1721 +c
1734 +c
1722 diff -r b09be438c43a -r 8e07aafe1edc b
1735 diff -r b09be438c43a -r 8e07aafe1edc b
1723 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1736 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1724 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1737 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1725 @@ -0,0 +1,1 @@
1738 @@ -0,0 +1,1 @@
1726 +b
1739 +b
1727
1740
1728 Diff here should be the same:
1741 Diff here should be the same:
1729
1742
1730 $ hg log -vpr 3
1743 $ hg log -vpr 3
1731 changeset: 3:8e07aafe1edc
1744 changeset: 3:8e07aafe1edc
1732 tag: tip
1745 tag: tip
1733 parent: 2:b09be438c43a
1746 parent: 2:b09be438c43a
1734 parent: 1:925d80f479bb
1747 parent: 1:925d80f479bb
1735 user: test
1748 user: test
1736 date: Thu Jan 01 00:00:00 1970 +0000
1749 date: Thu Jan 01 00:00:00 1970 +0000
1737 files: a
1750 files: a
1738 description:
1751 description:
1739 3
1752 3
1740
1753
1741
1754
1742 diff -r b09be438c43a -r 8e07aafe1edc a
1755 diff -r b09be438c43a -r 8e07aafe1edc a
1743 --- a/a Thu Jan 01 00:00:00 1970 +0000
1756 --- a/a Thu Jan 01 00:00:00 1970 +0000
1744 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1757 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1745 @@ -1,1 +1,1 @@
1758 @@ -1,1 +1,1 @@
1746 -b
1759 -b
1747 +c
1760 +c
1748 diff -r b09be438c43a -r 8e07aafe1edc b
1761 diff -r b09be438c43a -r 8e07aafe1edc b
1749 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1762 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1750 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1763 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1751 @@ -0,0 +1,1 @@
1764 @@ -0,0 +1,1 @@
1752 +b
1765 +b
1753
1766
1754 $ cd ..
1767 $ cd ..
1755
1768
1756 'hg log -r rev fn' when last(filelog(fn)) != rev
1769 'hg log -r rev fn' when last(filelog(fn)) != rev
1757
1770
1758 $ hg init simplelog
1771 $ hg init simplelog
1759 $ cd simplelog
1772 $ cd simplelog
1760 $ echo f > a
1773 $ echo f > a
1761 $ hg ci -Am'a' -d '0 0'
1774 $ hg ci -Am'a' -d '0 0'
1762 adding a
1775 adding a
1763 $ echo f >> a
1776 $ echo f >> a
1764 $ hg ci -Am'a bis' -d '1 0'
1777 $ hg ci -Am'a bis' -d '1 0'
1765
1778
1766 $ hg log -r0 a
1779 $ hg log -r0 a
1767 changeset: 0:9f758d63dcde
1780 changeset: 0:9f758d63dcde
1768 user: test
1781 user: test
1769 date: Thu Jan 01 00:00:00 1970 +0000
1782 date: Thu Jan 01 00:00:00 1970 +0000
1770 summary: a
1783 summary: a
1771
1784
1772 enable obsolete to test hidden feature
1785 enable obsolete to test hidden feature
1773
1786
1774 $ cat >> $HGRCPATH << EOF
1787 $ cat >> $HGRCPATH << EOF
1775 > [experimental]
1788 > [experimental]
1776 > evolution.createmarkers=True
1789 > evolution.createmarkers=True
1777 > EOF
1790 > EOF
1778
1791
1779 $ hg log --template='{rev}:{node}\n'
1792 $ hg log --template='{rev}:{node}\n'
1780 1:a765632148dc55d38c35c4f247c618701886cb2f
1793 1:a765632148dc55d38c35c4f247c618701886cb2f
1781 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1794 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1782 $ hg debugobsolete a765632148dc55d38c35c4f247c618701886cb2f
1795 $ hg debugobsolete a765632148dc55d38c35c4f247c618701886cb2f
1783 obsoleted 1 changesets
1796 obsoleted 1 changesets
1784 $ hg up null -q
1797 $ hg up null -q
1785 $ hg log --template='{rev}:{node}\n'
1798 $ hg log --template='{rev}:{node}\n'
1786 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1799 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1787 $ hg log --template='{rev}:{node}\n' --hidden
1800 $ hg log --template='{rev}:{node}\n' --hidden
1788 1:a765632148dc55d38c35c4f247c618701886cb2f
1801 1:a765632148dc55d38c35c4f247c618701886cb2f
1789 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1802 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1790 $ hg log -r a
1803 $ hg log -r a
1791 abort: hidden revision 'a'!
1804 abort: hidden revision 'a'!
1792 (use --hidden to access hidden revisions)
1805 (use --hidden to access hidden revisions)
1793 [255]
1806 [255]
1794
1807
1795 test that parent prevent a changeset to be hidden
1808 test that parent prevent a changeset to be hidden
1796
1809
1797 $ hg up 1 -q --hidden
1810 $ hg up 1 -q --hidden
1798 $ hg log --template='{rev}:{node}\n'
1811 $ hg log --template='{rev}:{node}\n'
1799 1:a765632148dc55d38c35c4f247c618701886cb2f
1812 1:a765632148dc55d38c35c4f247c618701886cb2f
1800 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1813 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1801
1814
1802 test that second parent prevent a changeset to be hidden too
1815 test that second parent prevent a changeset to be hidden too
1803
1816
1804 $ hg debugsetparents 0 1 # nothing suitable to merge here
1817 $ hg debugsetparents 0 1 # nothing suitable to merge here
1805 $ hg log --template='{rev}:{node}\n'
1818 $ hg log --template='{rev}:{node}\n'
1806 1:a765632148dc55d38c35c4f247c618701886cb2f
1819 1:a765632148dc55d38c35c4f247c618701886cb2f
1807 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1820 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1808 $ hg debugsetparents 1
1821 $ hg debugsetparents 1
1809 $ hg up -q null
1822 $ hg up -q null
1810
1823
1811 bookmarks prevent a changeset being hidden
1824 bookmarks prevent a changeset being hidden
1812
1825
1813 $ hg bookmark --hidden -r 1 X
1826 $ hg bookmark --hidden -r 1 X
1814 $ hg log --template '{rev}:{node}\n'
1827 $ hg log --template '{rev}:{node}\n'
1815 1:a765632148dc55d38c35c4f247c618701886cb2f
1828 1:a765632148dc55d38c35c4f247c618701886cb2f
1816 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1829 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1817 $ hg bookmark -d X
1830 $ hg bookmark -d X
1818
1831
1819 divergent bookmarks are not hidden
1832 divergent bookmarks are not hidden
1820
1833
1821 $ hg bookmark --hidden -r 1 X@foo
1834 $ hg bookmark --hidden -r 1 X@foo
1822 $ hg log --template '{rev}:{node}\n'
1835 $ hg log --template '{rev}:{node}\n'
1823 1:a765632148dc55d38c35c4f247c618701886cb2f
1836 1:a765632148dc55d38c35c4f247c618701886cb2f
1824 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1837 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1825
1838
1826 test hidden revision 0 (issue5385)
1839 test hidden revision 0 (issue5385)
1827
1840
1828 $ hg bookmark -d X@foo
1841 $ hg bookmark -d X@foo
1829 $ hg up null -q
1842 $ hg up null -q
1830 $ hg debugobsolete 9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1843 $ hg debugobsolete 9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1831 obsoleted 1 changesets
1844 obsoleted 1 changesets
1832 $ echo f > b
1845 $ echo f > b
1833 $ hg ci -Am'b' -d '2 0'
1846 $ hg ci -Am'b' -d '2 0'
1834 adding b
1847 adding b
1835 $ echo f >> b
1848 $ echo f >> b
1836 $ hg ci -m'b bis' -d '3 0'
1849 $ hg ci -m'b bis' -d '3 0'
1837 $ hg log -T'{rev}:{node}\n'
1850 $ hg log -T'{rev}:{node}\n'
1838 3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e
1851 3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e
1839 2:94375ec45bddd2a824535fc04855bd058c926ec0
1852 2:94375ec45bddd2a824535fc04855bd058c926ec0
1840
1853
1841 $ hg log -T'{rev}:{node}\n' -r:
1854 $ hg log -T'{rev}:{node}\n' -r:
1842 2:94375ec45bddd2a824535fc04855bd058c926ec0
1855 2:94375ec45bddd2a824535fc04855bd058c926ec0
1843 3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e
1856 3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e
1844 $ hg log -T'{rev}:{node}\n' -r:tip
1857 $ hg log -T'{rev}:{node}\n' -r:tip
1845 2:94375ec45bddd2a824535fc04855bd058c926ec0
1858 2:94375ec45bddd2a824535fc04855bd058c926ec0
1846 3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e
1859 3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e
1847 $ hg log -T'{rev}:{node}\n' -r:0
1860 $ hg log -T'{rev}:{node}\n' -r:0
1848 abort: hidden revision '0'!
1861 abort: hidden revision '0'!
1849 (use --hidden to access hidden revisions)
1862 (use --hidden to access hidden revisions)
1850 [255]
1863 [255]
1851 $ hg log -T'{rev}:{node}\n' -f
1864 $ hg log -T'{rev}:{node}\n' -f
1852 3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e
1865 3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e
1853 2:94375ec45bddd2a824535fc04855bd058c926ec0
1866 2:94375ec45bddd2a824535fc04855bd058c926ec0
1854
1867
1855 clear extensions configuration
1868 clear extensions configuration
1856 $ echo '[extensions]' >> $HGRCPATH
1869 $ echo '[extensions]' >> $HGRCPATH
1857 $ echo "obs=!" >> $HGRCPATH
1870 $ echo "obs=!" >> $HGRCPATH
1858 $ cd ..
1871 $ cd ..
1859
1872
1860 test -u/-k for problematic encoding
1873 test -u/-k for problematic encoding
1861 # unicode: cp932:
1874 # unicode: cp932:
1862 # u30A2 0x83 0x41(= 'A')
1875 # u30A2 0x83 0x41(= 'A')
1863 # u30C2 0x83 0x61(= 'a')
1876 # u30C2 0x83 0x61(= 'a')
1864
1877
1865 $ hg init problematicencoding
1878 $ hg init problematicencoding
1866 $ cd problematicencoding
1879 $ cd problematicencoding
1867
1880
1868 $ $PYTHON > setup.sh <<EOF
1881 $ $PYTHON > setup.sh <<EOF
1869 > print(u'''
1882 > print(u'''
1870 > echo a > text
1883 > echo a > text
1871 > hg add text
1884 > hg add text
1872 > hg --encoding utf-8 commit -u '\u30A2' -m none
1885 > hg --encoding utf-8 commit -u '\u30A2' -m none
1873 > echo b > text
1886 > echo b > text
1874 > hg --encoding utf-8 commit -u '\u30C2' -m none
1887 > hg --encoding utf-8 commit -u '\u30C2' -m none
1875 > echo c > text
1888 > echo c > text
1876 > hg --encoding utf-8 commit -u none -m '\u30A2'
1889 > hg --encoding utf-8 commit -u none -m '\u30A2'
1877 > echo d > text
1890 > echo d > text
1878 > hg --encoding utf-8 commit -u none -m '\u30C2'
1891 > hg --encoding utf-8 commit -u none -m '\u30C2'
1879 > '''.encode('utf-8'))
1892 > '''.encode('utf-8'))
1880 > EOF
1893 > EOF
1881 $ sh < setup.sh
1894 $ sh < setup.sh
1882
1895
1883 test in problematic encoding
1896 test in problematic encoding
1884 $ $PYTHON > test.sh <<EOF
1897 $ $PYTHON > test.sh <<EOF
1885 > print(u'''
1898 > print(u'''
1886 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30A2'
1899 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30A2'
1887 > echo ====
1900 > echo ====
1888 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30C2'
1901 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30C2'
1889 > echo ====
1902 > echo ====
1890 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30A2'
1903 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30A2'
1891 > echo ====
1904 > echo ====
1892 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30C2'
1905 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30C2'
1893 > '''.encode('cp932'))
1906 > '''.encode('cp932'))
1894 > EOF
1907 > EOF
1895 $ sh < test.sh
1908 $ sh < test.sh
1896 0
1909 0
1897 ====
1910 ====
1898 1
1911 1
1899 ====
1912 ====
1900 2
1913 2
1901 0
1914 0
1902 ====
1915 ====
1903 3
1916 3
1904 1
1917 1
1905
1918
1906 $ cd ..
1919 $ cd ..
1907
1920
1908 test hg log on non-existent files and on directories
1921 test hg log on non-existent files and on directories
1909 $ hg init issue1340
1922 $ hg init issue1340
1910 $ cd issue1340
1923 $ cd issue1340
1911 $ mkdir d1; mkdir D2; mkdir D3.i; mkdir d4.hg; mkdir d5.d; mkdir .d6
1924 $ mkdir d1; mkdir D2; mkdir D3.i; mkdir d4.hg; mkdir d5.d; mkdir .d6
1912 $ echo 1 > d1/f1
1925 $ echo 1 > d1/f1
1913 $ echo 1 > D2/f1
1926 $ echo 1 > D2/f1
1914 $ echo 1 > D3.i/f1
1927 $ echo 1 > D3.i/f1
1915 $ echo 1 > d4.hg/f1
1928 $ echo 1 > d4.hg/f1
1916 $ echo 1 > d5.d/f1
1929 $ echo 1 > d5.d/f1
1917 $ echo 1 > .d6/f1
1930 $ echo 1 > .d6/f1
1918 $ hg -q add .
1931 $ hg -q add .
1919 $ hg commit -m "a bunch of weird directories"
1932 $ hg commit -m "a bunch of weird directories"
1920 $ hg log -l1 d1/f1 | grep changeset
1933 $ hg log -l1 d1/f1 | grep changeset
1921 changeset: 0:65624cd9070a
1934 changeset: 0:65624cd9070a
1922 $ hg log -l1 f1
1935 $ hg log -l1 f1
1923 $ hg log -l1 . | grep changeset
1936 $ hg log -l1 . | grep changeset
1924 changeset: 0:65624cd9070a
1937 changeset: 0:65624cd9070a
1925 $ hg log -l1 ./ | grep changeset
1938 $ hg log -l1 ./ | grep changeset
1926 changeset: 0:65624cd9070a
1939 changeset: 0:65624cd9070a
1927 $ hg log -l1 d1 | grep changeset
1940 $ hg log -l1 d1 | grep changeset
1928 changeset: 0:65624cd9070a
1941 changeset: 0:65624cd9070a
1929 $ hg log -l1 D2 | grep changeset
1942 $ hg log -l1 D2 | grep changeset
1930 changeset: 0:65624cd9070a
1943 changeset: 0:65624cd9070a
1931 $ hg log -l1 D2/f1 | grep changeset
1944 $ hg log -l1 D2/f1 | grep changeset
1932 changeset: 0:65624cd9070a
1945 changeset: 0:65624cd9070a
1933 $ hg log -l1 D3.i | grep changeset
1946 $ hg log -l1 D3.i | grep changeset
1934 changeset: 0:65624cd9070a
1947 changeset: 0:65624cd9070a
1935 $ hg log -l1 D3.i/f1 | grep changeset
1948 $ hg log -l1 D3.i/f1 | grep changeset
1936 changeset: 0:65624cd9070a
1949 changeset: 0:65624cd9070a
1937 $ hg log -l1 d4.hg | grep changeset
1950 $ hg log -l1 d4.hg | grep changeset
1938 changeset: 0:65624cd9070a
1951 changeset: 0:65624cd9070a
1939 $ hg log -l1 d4.hg/f1 | grep changeset
1952 $ hg log -l1 d4.hg/f1 | grep changeset
1940 changeset: 0:65624cd9070a
1953 changeset: 0:65624cd9070a
1941 $ hg log -l1 d5.d | grep changeset
1954 $ hg log -l1 d5.d | grep changeset
1942 changeset: 0:65624cd9070a
1955 changeset: 0:65624cd9070a
1943 $ hg log -l1 d5.d/f1 | grep changeset
1956 $ hg log -l1 d5.d/f1 | grep changeset
1944 changeset: 0:65624cd9070a
1957 changeset: 0:65624cd9070a
1945 $ hg log -l1 .d6 | grep changeset
1958 $ hg log -l1 .d6 | grep changeset
1946 changeset: 0:65624cd9070a
1959 changeset: 0:65624cd9070a
1947 $ hg log -l1 .d6/f1 | grep changeset
1960 $ hg log -l1 .d6/f1 | grep changeset
1948 changeset: 0:65624cd9070a
1961 changeset: 0:65624cd9070a
1949
1962
1950 issue3772: hg log -r :null showing revision 0 as well
1963 issue3772: hg log -r :null showing revision 0 as well
1951
1964
1952 $ hg log -r :null
1965 $ hg log -r :null
1953 changeset: 0:65624cd9070a
1966 changeset: 0:65624cd9070a
1954 tag: tip
1967 tag: tip
1955 user: test
1968 user: test
1956 date: Thu Jan 01 00:00:00 1970 +0000
1969 date: Thu Jan 01 00:00:00 1970 +0000
1957 summary: a bunch of weird directories
1970 summary: a bunch of weird directories
1958
1971
1959 changeset: -1:000000000000
1972 changeset: -1:000000000000
1960 user:
1973 user:
1961 date: Thu Jan 01 00:00:00 1970 +0000
1974 date: Thu Jan 01 00:00:00 1970 +0000
1962
1975
1963 $ hg log -r null:null
1976 $ hg log -r null:null
1964 changeset: -1:000000000000
1977 changeset: -1:000000000000
1965 user:
1978 user:
1966 date: Thu Jan 01 00:00:00 1970 +0000
1979 date: Thu Jan 01 00:00:00 1970 +0000
1967
1980
1968 working-directory revision requires special treatment
1981 working-directory revision requires special treatment
1969
1982
1970 clean:
1983 clean:
1971
1984
1972 $ hg log -r 'wdir()' --debug
1985 $ hg log -r 'wdir()' --debug
1973 changeset: 2147483647:ffffffffffffffffffffffffffffffffffffffff
1986 changeset: 2147483647:ffffffffffffffffffffffffffffffffffffffff
1974 phase: draft
1987 phase: draft
1975 parent: 0:65624cd9070a035fa7191a54f2b8af39f16b0c08
1988 parent: 0:65624cd9070a035fa7191a54f2b8af39f16b0c08
1976 parent: -1:0000000000000000000000000000000000000000
1989 parent: -1:0000000000000000000000000000000000000000
1977 user: test
1990 user: test
1978 date: [A-Za-z0-9:+ ]+ (re)
1991 date: [A-Za-z0-9:+ ]+ (re)
1979 extra: branch=default
1992 extra: branch=default
1980
1993
1981 $ hg log -r 'wdir()' -p --stat
1994 $ hg log -r 'wdir()' -p --stat
1982 changeset: 2147483647:ffffffffffff
1995 changeset: 2147483647:ffffffffffff
1983 parent: 0:65624cd9070a
1996 parent: 0:65624cd9070a
1984 user: test
1997 user: test
1985 date: [A-Za-z0-9:+ ]+ (re)
1998 date: [A-Za-z0-9:+ ]+ (re)
1986
1999
1987
2000
1988
2001
1989
2002
1990 dirty:
2003 dirty:
1991
2004
1992 $ echo 2 >> d1/f1
2005 $ echo 2 >> d1/f1
1993 $ echo 2 > d1/f2
2006 $ echo 2 > d1/f2
1994 $ hg add d1/f2
2007 $ hg add d1/f2
1995 $ hg remove .d6/f1
2008 $ hg remove .d6/f1
1996 $ hg status
2009 $ hg status
1997 M d1/f1
2010 M d1/f1
1998 A d1/f2
2011 A d1/f2
1999 R .d6/f1
2012 R .d6/f1
2000
2013
2001 $ hg log -r 'wdir()'
2014 $ hg log -r 'wdir()'
2002 changeset: 2147483647:ffffffffffff
2015 changeset: 2147483647:ffffffffffff
2003 parent: 0:65624cd9070a
2016 parent: 0:65624cd9070a
2004 user: test
2017 user: test
2005 date: [A-Za-z0-9:+ ]+ (re)
2018 date: [A-Za-z0-9:+ ]+ (re)
2006
2019
2007 $ hg log -r 'wdir()' -q
2020 $ hg log -r 'wdir()' -q
2008 2147483647:ffffffffffff
2021 2147483647:ffffffffffff
2009
2022
2010 $ hg log -r 'wdir()' --debug
2023 $ hg log -r 'wdir()' --debug
2011 changeset: 2147483647:ffffffffffffffffffffffffffffffffffffffff
2024 changeset: 2147483647:ffffffffffffffffffffffffffffffffffffffff
2012 phase: draft
2025 phase: draft
2013 parent: 0:65624cd9070a035fa7191a54f2b8af39f16b0c08
2026 parent: 0:65624cd9070a035fa7191a54f2b8af39f16b0c08
2014 parent: -1:0000000000000000000000000000000000000000
2027 parent: -1:0000000000000000000000000000000000000000
2015 user: test
2028 user: test
2016 date: [A-Za-z0-9:+ ]+ (re)
2029 date: [A-Za-z0-9:+ ]+ (re)
2017 files: d1/f1
2030 files: d1/f1
2018 files+: d1/f2
2031 files+: d1/f2
2019 files-: .d6/f1
2032 files-: .d6/f1
2020 extra: branch=default
2033 extra: branch=default
2021
2034
2022 $ hg log -r 'wdir()' -p --stat --git
2035 $ hg log -r 'wdir()' -p --stat --git
2023 changeset: 2147483647:ffffffffffff
2036 changeset: 2147483647:ffffffffffff
2024 parent: 0:65624cd9070a
2037 parent: 0:65624cd9070a
2025 user: test
2038 user: test
2026 date: [A-Za-z0-9:+ ]+ (re)
2039 date: [A-Za-z0-9:+ ]+ (re)
2027
2040
2028 .d6/f1 | 1 -
2041 .d6/f1 | 1 -
2029 d1/f1 | 1 +
2042 d1/f1 | 1 +
2030 d1/f2 | 1 +
2043 d1/f2 | 1 +
2031 3 files changed, 2 insertions(+), 1 deletions(-)
2044 3 files changed, 2 insertions(+), 1 deletions(-)
2032
2045
2033 diff --git a/.d6/f1 b/.d6/f1
2046 diff --git a/.d6/f1 b/.d6/f1
2034 deleted file mode 100644
2047 deleted file mode 100644
2035 --- a/.d6/f1
2048 --- a/.d6/f1
2036 +++ /dev/null
2049 +++ /dev/null
2037 @@ -1,1 +0,0 @@
2050 @@ -1,1 +0,0 @@
2038 -1
2051 -1
2039 diff --git a/d1/f1 b/d1/f1
2052 diff --git a/d1/f1 b/d1/f1
2040 --- a/d1/f1
2053 --- a/d1/f1
2041 +++ b/d1/f1
2054 +++ b/d1/f1
2042 @@ -1,1 +1,2 @@
2055 @@ -1,1 +1,2 @@
2043 1
2056 1
2044 +2
2057 +2
2045 diff --git a/d1/f2 b/d1/f2
2058 diff --git a/d1/f2 b/d1/f2
2046 new file mode 100644
2059 new file mode 100644
2047 --- /dev/null
2060 --- /dev/null
2048 +++ b/d1/f2
2061 +++ b/d1/f2
2049 @@ -0,0 +1,1 @@
2062 @@ -0,0 +1,1 @@
2050 +2
2063 +2
2051
2064
2052 $ hg log -r 'wdir()' -Tjson
2065 $ hg log -r 'wdir()' -Tjson
2053 [
2066 [
2054 {
2067 {
2055 "rev": null,
2068 "rev": null,
2056 "node": null,
2069 "node": null,
2057 "branch": "default",
2070 "branch": "default",
2058 "phase": "draft",
2071 "phase": "draft",
2059 "user": "test",
2072 "user": "test",
2060 "date": [*, 0], (glob)
2073 "date": [*, 0], (glob)
2061 "desc": "",
2074 "desc": "",
2062 "bookmarks": [],
2075 "bookmarks": [],
2063 "tags": [],
2076 "tags": [],
2064 "parents": ["65624cd9070a035fa7191a54f2b8af39f16b0c08"]
2077 "parents": ["65624cd9070a035fa7191a54f2b8af39f16b0c08"]
2065 }
2078 }
2066 ]
2079 ]
2067
2080
2068 $ hg log -r 'wdir()' -Tjson -q
2081 $ hg log -r 'wdir()' -Tjson -q
2069 [
2082 [
2070 {
2083 {
2071 "rev": null,
2084 "rev": null,
2072 "node": null
2085 "node": null
2073 }
2086 }
2074 ]
2087 ]
2075
2088
2076 $ hg log -r 'wdir()' -Tjson --debug
2089 $ hg log -r 'wdir()' -Tjson --debug
2077 [
2090 [
2078 {
2091 {
2079 "rev": null,
2092 "rev": null,
2080 "node": null,
2093 "node": null,
2081 "branch": "default",
2094 "branch": "default",
2082 "phase": "draft",
2095 "phase": "draft",
2083 "user": "test",
2096 "user": "test",
2084 "date": [*, 0], (glob)
2097 "date": [*, 0], (glob)
2085 "desc": "",
2098 "desc": "",
2086 "bookmarks": [],
2099 "bookmarks": [],
2087 "tags": [],
2100 "tags": [],
2088 "parents": ["65624cd9070a035fa7191a54f2b8af39f16b0c08"],
2101 "parents": ["65624cd9070a035fa7191a54f2b8af39f16b0c08"],
2089 "manifest": null,
2102 "manifest": null,
2090 "extra": {"branch": "default"},
2103 "extra": {"branch": "default"},
2091 "modified": ["d1/f1"],
2104 "modified": ["d1/f1"],
2092 "added": ["d1/f2"],
2105 "added": ["d1/f2"],
2093 "removed": [".d6/f1"]
2106 "removed": [".d6/f1"]
2094 }
2107 }
2095 ]
2108 ]
2096
2109
2097 $ hg revert -aqC
2110 $ hg revert -aqC
2098
2111
2099 Check that adding an arbitrary name shows up in log automatically
2112 Check that adding an arbitrary name shows up in log automatically
2100
2113
2101 $ cat > ../names.py <<EOF
2114 $ cat > ../names.py <<EOF
2102 > """A small extension to test adding arbitrary names to a repo"""
2115 > """A small extension to test adding arbitrary names to a repo"""
2103 > from __future__ import absolute_import
2116 > from __future__ import absolute_import
2104 > from mercurial import namespaces
2117 > from mercurial import namespaces
2105 >
2118 >
2106 > def reposetup(ui, repo):
2119 > def reposetup(ui, repo):
2107 > foo = {'foo': repo[0].node()}
2120 > foo = {'foo': repo[0].node()}
2108 > names = lambda r: foo.keys()
2121 > names = lambda r: foo.keys()
2109 > namemap = lambda r, name: foo.get(name)
2122 > namemap = lambda r, name: foo.get(name)
2110 > nodemap = lambda r, node: [name for name, n in foo.iteritems()
2123 > nodemap = lambda r, node: [name for name, n in foo.iteritems()
2111 > if n == node]
2124 > if n == node]
2112 > ns = namespaces.namespace(
2125 > ns = namespaces.namespace(
2113 > "bars", templatename="bar", logname="barlog",
2126 > "bars", templatename="bar", logname="barlog",
2114 > colorname="barcolor", listnames=names, namemap=namemap,
2127 > colorname="barcolor", listnames=names, namemap=namemap,
2115 > nodemap=nodemap)
2128 > nodemap=nodemap)
2116 >
2129 >
2117 > repo.names.addnamespace(ns)
2130 > repo.names.addnamespace(ns)
2118 > EOF
2131 > EOF
2119
2132
2120 $ hg --config extensions.names=../names.py log -r 0
2133 $ hg --config extensions.names=../names.py log -r 0
2121 changeset: 0:65624cd9070a
2134 changeset: 0:65624cd9070a
2122 tag: tip
2135 tag: tip
2123 barlog: foo
2136 barlog: foo
2124 user: test
2137 user: test
2125 date: Thu Jan 01 00:00:00 1970 +0000
2138 date: Thu Jan 01 00:00:00 1970 +0000
2126 summary: a bunch of weird directories
2139 summary: a bunch of weird directories
2127
2140
2128 $ hg --config extensions.names=../names.py \
2141 $ hg --config extensions.names=../names.py \
2129 > --config extensions.color= --config color.log.barcolor=red \
2142 > --config extensions.color= --config color.log.barcolor=red \
2130 > --color=always log -r 0
2143 > --color=always log -r 0
2131 \x1b[0;33mchangeset: 0:65624cd9070a\x1b[0m (esc)
2144 \x1b[0;33mchangeset: 0:65624cd9070a\x1b[0m (esc)
2132 tag: tip
2145 tag: tip
2133 \x1b[0;31mbarlog: foo\x1b[0m (esc)
2146 \x1b[0;31mbarlog: foo\x1b[0m (esc)
2134 user: test
2147 user: test
2135 date: Thu Jan 01 00:00:00 1970 +0000
2148 date: Thu Jan 01 00:00:00 1970 +0000
2136 summary: a bunch of weird directories
2149 summary: a bunch of weird directories
2137
2150
2138 $ hg --config extensions.names=../names.py log -r 0 --template '{bars}\n'
2151 $ hg --config extensions.names=../names.py log -r 0 --template '{bars}\n'
2139 foo
2152 foo
2140
2153
2141 $ cd ..
2154 $ cd ..
2142
2155
2143 hg log -f dir across branches
2156 hg log -f dir across branches
2144
2157
2145 $ hg init acrossbranches
2158 $ hg init acrossbranches
2146 $ cd acrossbranches
2159 $ cd acrossbranches
2147 $ mkdir d
2160 $ mkdir d
2148 $ echo a > d/a && hg ci -Aqm a
2161 $ echo a > d/a && hg ci -Aqm a
2149 $ echo b > d/a && hg ci -Aqm b
2162 $ echo b > d/a && hg ci -Aqm b
2150 $ hg up -q 0
2163 $ hg up -q 0
2151 $ echo b > d/a && hg ci -Aqm c
2164 $ echo b > d/a && hg ci -Aqm c
2152 $ hg log -f d -T '{desc}' -G
2165 $ hg log -f d -T '{desc}' -G
2153 @ c
2166 @ c
2154 |
2167 |
2155 o a
2168 o a
2156
2169
2157 Ensure that largefiles doesn't interfere with following a normal file
2170 Ensure that largefiles doesn't interfere with following a normal file
2158 $ hg --config extensions.largefiles= log -f d -T '{desc}' -G
2171 $ hg --config extensions.largefiles= log -f d -T '{desc}' -G
2159 The fsmonitor extension is incompatible with the largefiles extension and has been disabled. (fsmonitor !)
2172 The fsmonitor extension is incompatible with the largefiles extension and has been disabled. (fsmonitor !)
2160 @ c
2173 @ c
2161 |
2174 |
2162 o a
2175 o a
2163
2176
2164 $ hg log -f d/a -T '{desc}' -G
2177 $ hg log -f d/a -T '{desc}' -G
2165 @ c
2178 @ c
2166 |
2179 |
2167 o a
2180 o a
2168
2181
2169 $ cd ..
2182 $ cd ..
2170
2183
2171 hg log -f with linkrev pointing to another branch
2184 hg log -f with linkrev pointing to another branch
2172 -------------------------------------------------
2185 -------------------------------------------------
2173
2186
2174 create history with a filerev whose linkrev points to another branch
2187 create history with a filerev whose linkrev points to another branch
2175
2188
2176 $ hg init branchedlinkrev
2189 $ hg init branchedlinkrev
2177 $ cd branchedlinkrev
2190 $ cd branchedlinkrev
2178 $ echo 1 > a
2191 $ echo 1 > a
2179 $ hg commit -Am 'content1'
2192 $ hg commit -Am 'content1'
2180 adding a
2193 adding a
2181 $ echo 2 > a
2194 $ echo 2 > a
2182 $ hg commit -m 'content2'
2195 $ hg commit -m 'content2'
2183 $ hg up --rev 'desc(content1)'
2196 $ hg up --rev 'desc(content1)'
2184 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
2197 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
2185 $ echo unrelated > unrelated
2198 $ echo unrelated > unrelated
2186 $ hg commit -Am 'unrelated'
2199 $ hg commit -Am 'unrelated'
2187 adding unrelated
2200 adding unrelated
2188 created new head
2201 created new head
2189 $ hg graft -r 'desc(content2)'
2202 $ hg graft -r 'desc(content2)'
2190 grafting 1:2294ae80ad84 "content2"
2203 grafting 1:2294ae80ad84 "content2"
2191 $ echo 3 > a
2204 $ echo 3 > a
2192 $ hg commit -m 'content3'
2205 $ hg commit -m 'content3'
2193 $ hg log -G
2206 $ hg log -G
2194 @ changeset: 4:50b9b36e9c5d
2207 @ changeset: 4:50b9b36e9c5d
2195 | tag: tip
2208 | tag: tip
2196 | user: test
2209 | user: test
2197 | date: Thu Jan 01 00:00:00 1970 +0000
2210 | date: Thu Jan 01 00:00:00 1970 +0000
2198 | summary: content3
2211 | summary: content3
2199 |
2212 |
2200 o changeset: 3:15b2327059e5
2213 o changeset: 3:15b2327059e5
2201 | user: test
2214 | user: test
2202 | date: Thu Jan 01 00:00:00 1970 +0000
2215 | date: Thu Jan 01 00:00:00 1970 +0000
2203 | summary: content2
2216 | summary: content2
2204 |
2217 |
2205 o changeset: 2:2029acd1168c
2218 o changeset: 2:2029acd1168c
2206 | parent: 0:ae0a3c9f9e95
2219 | parent: 0:ae0a3c9f9e95
2207 | user: test
2220 | user: test
2208 | date: Thu Jan 01 00:00:00 1970 +0000
2221 | date: Thu Jan 01 00:00:00 1970 +0000
2209 | summary: unrelated
2222 | summary: unrelated
2210 |
2223 |
2211 | o changeset: 1:2294ae80ad84
2224 | o changeset: 1:2294ae80ad84
2212 |/ user: test
2225 |/ user: test
2213 | date: Thu Jan 01 00:00:00 1970 +0000
2226 | date: Thu Jan 01 00:00:00 1970 +0000
2214 | summary: content2
2227 | summary: content2
2215 |
2228 |
2216 o changeset: 0:ae0a3c9f9e95
2229 o changeset: 0:ae0a3c9f9e95
2217 user: test
2230 user: test
2218 date: Thu Jan 01 00:00:00 1970 +0000
2231 date: Thu Jan 01 00:00:00 1970 +0000
2219 summary: content1
2232 summary: content1
2220
2233
2221
2234
2222 log -f on the file should list the graft result.
2235 log -f on the file should list the graft result.
2223
2236
2224 $ hg log -Gf a
2237 $ hg log -Gf a
2225 @ changeset: 4:50b9b36e9c5d
2238 @ changeset: 4:50b9b36e9c5d
2226 | tag: tip
2239 | tag: tip
2227 | user: test
2240 | user: test
2228 | date: Thu Jan 01 00:00:00 1970 +0000
2241 | date: Thu Jan 01 00:00:00 1970 +0000
2229 | summary: content3
2242 | summary: content3
2230 |
2243 |
2231 o changeset: 3:15b2327059e5
2244 o changeset: 3:15b2327059e5
2232 : user: test
2245 : user: test
2233 : date: Thu Jan 01 00:00:00 1970 +0000
2246 : date: Thu Jan 01 00:00:00 1970 +0000
2234 : summary: content2
2247 : summary: content2
2235 :
2248 :
2236 o changeset: 0:ae0a3c9f9e95
2249 o changeset: 0:ae0a3c9f9e95
2237 user: test
2250 user: test
2238 date: Thu Jan 01 00:00:00 1970 +0000
2251 date: Thu Jan 01 00:00:00 1970 +0000
2239 summary: content1
2252 summary: content1
2240
2253
2241
2254
2242 plain log lists the original version
2255 plain log lists the original version
2243 (XXX we should probably list both)
2256 (XXX we should probably list both)
2244
2257
2245 $ hg log -G a
2258 $ hg log -G a
2246 @ changeset: 4:50b9b36e9c5d
2259 @ changeset: 4:50b9b36e9c5d
2247 : tag: tip
2260 : tag: tip
2248 : user: test
2261 : user: test
2249 : date: Thu Jan 01 00:00:00 1970 +0000
2262 : date: Thu Jan 01 00:00:00 1970 +0000
2250 : summary: content3
2263 : summary: content3
2251 :
2264 :
2252 : o changeset: 1:2294ae80ad84
2265 : o changeset: 1:2294ae80ad84
2253 :/ user: test
2266 :/ user: test
2254 : date: Thu Jan 01 00:00:00 1970 +0000
2267 : date: Thu Jan 01 00:00:00 1970 +0000
2255 : summary: content2
2268 : summary: content2
2256 :
2269 :
2257 o changeset: 0:ae0a3c9f9e95
2270 o changeset: 0:ae0a3c9f9e95
2258 user: test
2271 user: test
2259 date: Thu Jan 01 00:00:00 1970 +0000
2272 date: Thu Jan 01 00:00:00 1970 +0000
2260 summary: content1
2273 summary: content1
2261
2274
2262
2275
2263 hg log -f from the grafted changeset
2276 hg log -f from the grafted changeset
2264 (The bootstrap should properly take the topology in account)
2277 (The bootstrap should properly take the topology in account)
2265
2278
2266 $ hg up 'desc(content3)^'
2279 $ hg up 'desc(content3)^'
2267 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
2280 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
2268 $ hg log -Gf a
2281 $ hg log -Gf a
2269 @ changeset: 3:15b2327059e5
2282 @ changeset: 3:15b2327059e5
2270 : user: test
2283 : user: test
2271 : date: Thu Jan 01 00:00:00 1970 +0000
2284 : date: Thu Jan 01 00:00:00 1970 +0000
2272 : summary: content2
2285 : summary: content2
2273 :
2286 :
2274 o changeset: 0:ae0a3c9f9e95
2287 o changeset: 0:ae0a3c9f9e95
2275 user: test
2288 user: test
2276 date: Thu Jan 01 00:00:00 1970 +0000
2289 date: Thu Jan 01 00:00:00 1970 +0000
2277 summary: content1
2290 summary: content1
2278
2291
2279
2292
2280 Test that we use the first non-hidden changeset in that case.
2293 Test that we use the first non-hidden changeset in that case.
2281
2294
2282 (hide the changeset)
2295 (hide the changeset)
2283
2296
2284 $ hg log -T '{node}\n' -r 1
2297 $ hg log -T '{node}\n' -r 1
2285 2294ae80ad8447bc78383182eeac50cb049df623
2298 2294ae80ad8447bc78383182eeac50cb049df623
2286 $ hg debugobsolete 2294ae80ad8447bc78383182eeac50cb049df623
2299 $ hg debugobsolete 2294ae80ad8447bc78383182eeac50cb049df623
2287 obsoleted 1 changesets
2300 obsoleted 1 changesets
2288 $ hg log -G
2301 $ hg log -G
2289 o changeset: 4:50b9b36e9c5d
2302 o changeset: 4:50b9b36e9c5d
2290 | tag: tip
2303 | tag: tip
2291 | user: test
2304 | user: test
2292 | date: Thu Jan 01 00:00:00 1970 +0000
2305 | date: Thu Jan 01 00:00:00 1970 +0000
2293 | summary: content3
2306 | summary: content3
2294 |
2307 |
2295 @ changeset: 3:15b2327059e5
2308 @ changeset: 3:15b2327059e5
2296 | user: test
2309 | user: test
2297 | date: Thu Jan 01 00:00:00 1970 +0000
2310 | date: Thu Jan 01 00:00:00 1970 +0000
2298 | summary: content2
2311 | summary: content2
2299 |
2312 |
2300 o changeset: 2:2029acd1168c
2313 o changeset: 2:2029acd1168c
2301 | parent: 0:ae0a3c9f9e95
2314 | parent: 0:ae0a3c9f9e95
2302 | user: test
2315 | user: test
2303 | date: Thu Jan 01 00:00:00 1970 +0000
2316 | date: Thu Jan 01 00:00:00 1970 +0000
2304 | summary: unrelated
2317 | summary: unrelated
2305 |
2318 |
2306 o changeset: 0:ae0a3c9f9e95
2319 o changeset: 0:ae0a3c9f9e95
2307 user: test
2320 user: test
2308 date: Thu Jan 01 00:00:00 1970 +0000
2321 date: Thu Jan 01 00:00:00 1970 +0000
2309 summary: content1
2322 summary: content1
2310
2323
2311
2324
2312 Check that log on the file does not drop the file revision.
2325 Check that log on the file does not drop the file revision.
2313
2326
2314 $ hg log -G a
2327 $ hg log -G a
2315 o changeset: 4:50b9b36e9c5d
2328 o changeset: 4:50b9b36e9c5d
2316 | tag: tip
2329 | tag: tip
2317 | user: test
2330 | user: test
2318 | date: Thu Jan 01 00:00:00 1970 +0000
2331 | date: Thu Jan 01 00:00:00 1970 +0000
2319 | summary: content3
2332 | summary: content3
2320 |
2333 |
2321 @ changeset: 3:15b2327059e5
2334 @ changeset: 3:15b2327059e5
2322 : user: test
2335 : user: test
2323 : date: Thu Jan 01 00:00:00 1970 +0000
2336 : date: Thu Jan 01 00:00:00 1970 +0000
2324 : summary: content2
2337 : summary: content2
2325 :
2338 :
2326 o changeset: 0:ae0a3c9f9e95
2339 o changeset: 0:ae0a3c9f9e95
2327 user: test
2340 user: test
2328 date: Thu Jan 01 00:00:00 1970 +0000
2341 date: Thu Jan 01 00:00:00 1970 +0000
2329 summary: content1
2342 summary: content1
2330
2343
2331
2344
2332 Even when a head revision is linkrev-shadowed.
2345 Even when a head revision is linkrev-shadowed.
2333
2346
2334 $ hg log -T '{node}\n' -r 4
2347 $ hg log -T '{node}\n' -r 4
2335 50b9b36e9c5df2c6fc6dcefa8ad0da929e84aed2
2348 50b9b36e9c5df2c6fc6dcefa8ad0da929e84aed2
2336 $ hg debugobsolete 50b9b36e9c5df2c6fc6dcefa8ad0da929e84aed2
2349 $ hg debugobsolete 50b9b36e9c5df2c6fc6dcefa8ad0da929e84aed2
2337 obsoleted 1 changesets
2350 obsoleted 1 changesets
2338 $ hg log -G a
2351 $ hg log -G a
2339 @ changeset: 3:15b2327059e5
2352 @ changeset: 3:15b2327059e5
2340 : tag: tip
2353 : tag: tip
2341 : user: test
2354 : user: test
2342 : date: Thu Jan 01 00:00:00 1970 +0000
2355 : date: Thu Jan 01 00:00:00 1970 +0000
2343 : summary: content2
2356 : summary: content2
2344 :
2357 :
2345 o changeset: 0:ae0a3c9f9e95
2358 o changeset: 0:ae0a3c9f9e95
2346 user: test
2359 user: test
2347 date: Thu Jan 01 00:00:00 1970 +0000
2360 date: Thu Jan 01 00:00:00 1970 +0000
2348 summary: content1
2361 summary: content1
2349
2362
2350
2363
2351 $ cd ..
2364 $ cd ..
2352
2365
2353 Even when the file revision is missing from some head:
2366 Even when the file revision is missing from some head:
2354
2367
2355 $ hg init issue4490
2368 $ hg init issue4490
2356 $ cd issue4490
2369 $ cd issue4490
2357 $ echo '[experimental]' >> .hg/hgrc
2370 $ echo '[experimental]' >> .hg/hgrc
2358 $ echo 'evolution.createmarkers=True' >> .hg/hgrc
2371 $ echo 'evolution.createmarkers=True' >> .hg/hgrc
2359 $ echo a > a
2372 $ echo a > a
2360 $ hg ci -Am0
2373 $ hg ci -Am0
2361 adding a
2374 adding a
2362 $ echo b > b
2375 $ echo b > b
2363 $ hg ci -Am1
2376 $ hg ci -Am1
2364 adding b
2377 adding b
2365 $ echo B > b
2378 $ echo B > b
2366 $ hg ci --amend -m 1
2379 $ hg ci --amend -m 1
2367 $ hg up 0
2380 $ hg up 0
2368 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
2381 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
2369 $ echo c > c
2382 $ echo c > c
2370 $ hg ci -Am2
2383 $ hg ci -Am2
2371 adding c
2384 adding c
2372 created new head
2385 created new head
2373 $ hg up 'head() and not .'
2386 $ hg up 'head() and not .'
2374 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
2387 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
2375 $ hg log -G
2388 $ hg log -G
2376 o changeset: 3:db815d6d32e6
2389 o changeset: 3:db815d6d32e6
2377 | tag: tip
2390 | tag: tip
2378 | parent: 0:f7b1eb17ad24
2391 | parent: 0:f7b1eb17ad24
2379 | user: test
2392 | user: test
2380 | date: Thu Jan 01 00:00:00 1970 +0000
2393 | date: Thu Jan 01 00:00:00 1970 +0000
2381 | summary: 2
2394 | summary: 2
2382 |
2395 |
2383 | @ changeset: 2:9bc8ce7f9356
2396 | @ changeset: 2:9bc8ce7f9356
2384 |/ parent: 0:f7b1eb17ad24
2397 |/ parent: 0:f7b1eb17ad24
2385 | user: test
2398 | user: test
2386 | date: Thu Jan 01 00:00:00 1970 +0000
2399 | date: Thu Jan 01 00:00:00 1970 +0000
2387 | summary: 1
2400 | summary: 1
2388 |
2401 |
2389 o changeset: 0:f7b1eb17ad24
2402 o changeset: 0:f7b1eb17ad24
2390 user: test
2403 user: test
2391 date: Thu Jan 01 00:00:00 1970 +0000
2404 date: Thu Jan 01 00:00:00 1970 +0000
2392 summary: 0
2405 summary: 0
2393
2406
2394 $ hg log -f -G b
2407 $ hg log -f -G b
2395 @ changeset: 2:9bc8ce7f9356
2408 @ changeset: 2:9bc8ce7f9356
2396 | parent: 0:f7b1eb17ad24
2409 | parent: 0:f7b1eb17ad24
2397 ~ user: test
2410 ~ user: test
2398 date: Thu Jan 01 00:00:00 1970 +0000
2411 date: Thu Jan 01 00:00:00 1970 +0000
2399 summary: 1
2412 summary: 1
2400
2413
2401 $ hg log -G b
2414 $ hg log -G b
2402 @ changeset: 2:9bc8ce7f9356
2415 @ changeset: 2:9bc8ce7f9356
2403 | parent: 0:f7b1eb17ad24
2416 | parent: 0:f7b1eb17ad24
2404 ~ user: test
2417 ~ user: test
2405 date: Thu Jan 01 00:00:00 1970 +0000
2418 date: Thu Jan 01 00:00:00 1970 +0000
2406 summary: 1
2419 summary: 1
2407
2420
2408 $ cd ..
2421 $ cd ..
2409
2422
2410 Check proper report when the manifest changes but not the file issue4499
2423 Check proper report when the manifest changes but not the file issue4499
2411 ------------------------------------------------------------------------
2424 ------------------------------------------------------------------------
2412
2425
2413 $ hg init issue4499
2426 $ hg init issue4499
2414 $ cd issue4499
2427 $ cd issue4499
2415 $ for f in A B C D F E G H I J K L M N O P Q R S T U; do
2428 $ for f in A B C D F E G H I J K L M N O P Q R S T U; do
2416 > echo 1 > $f;
2429 > echo 1 > $f;
2417 > hg add $f;
2430 > hg add $f;
2418 > done
2431 > done
2419 $ hg commit -m 'A1B1C1'
2432 $ hg commit -m 'A1B1C1'
2420 $ echo 2 > A
2433 $ echo 2 > A
2421 $ echo 2 > B
2434 $ echo 2 > B
2422 $ echo 2 > C
2435 $ echo 2 > C
2423 $ hg commit -m 'A2B2C2'
2436 $ hg commit -m 'A2B2C2'
2424 $ hg up 0
2437 $ hg up 0
2425 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
2438 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
2426 $ echo 3 > A
2439 $ echo 3 > A
2427 $ echo 2 > B
2440 $ echo 2 > B
2428 $ echo 2 > C
2441 $ echo 2 > C
2429 $ hg commit -m 'A3B2C2'
2442 $ hg commit -m 'A3B2C2'
2430 created new head
2443 created new head
2431
2444
2432 $ hg log -G
2445 $ hg log -G
2433 @ changeset: 2:fe5fc3d0eb17
2446 @ changeset: 2:fe5fc3d0eb17
2434 | tag: tip
2447 | tag: tip
2435 | parent: 0:abf4f0e38563
2448 | parent: 0:abf4f0e38563
2436 | user: test
2449 | user: test
2437 | date: Thu Jan 01 00:00:00 1970 +0000
2450 | date: Thu Jan 01 00:00:00 1970 +0000
2438 | summary: A3B2C2
2451 | summary: A3B2C2
2439 |
2452 |
2440 | o changeset: 1:07dcc6b312c0
2453 | o changeset: 1:07dcc6b312c0
2441 |/ user: test
2454 |/ user: test
2442 | date: Thu Jan 01 00:00:00 1970 +0000
2455 | date: Thu Jan 01 00:00:00 1970 +0000
2443 | summary: A2B2C2
2456 | summary: A2B2C2
2444 |
2457 |
2445 o changeset: 0:abf4f0e38563
2458 o changeset: 0:abf4f0e38563
2446 user: test
2459 user: test
2447 date: Thu Jan 01 00:00:00 1970 +0000
2460 date: Thu Jan 01 00:00:00 1970 +0000
2448 summary: A1B1C1
2461 summary: A1B1C1
2449
2462
2450
2463
2451 Log -f on B should reports current changesets
2464 Log -f on B should reports current changesets
2452
2465
2453 $ hg log -fG B
2466 $ hg log -fG B
2454 @ changeset: 2:fe5fc3d0eb17
2467 @ changeset: 2:fe5fc3d0eb17
2455 | tag: tip
2468 | tag: tip
2456 | parent: 0:abf4f0e38563
2469 | parent: 0:abf4f0e38563
2457 | user: test
2470 | user: test
2458 | date: Thu Jan 01 00:00:00 1970 +0000
2471 | date: Thu Jan 01 00:00:00 1970 +0000
2459 | summary: A3B2C2
2472 | summary: A3B2C2
2460 |
2473 |
2461 o changeset: 0:abf4f0e38563
2474 o changeset: 0:abf4f0e38563
2462 user: test
2475 user: test
2463 date: Thu Jan 01 00:00:00 1970 +0000
2476 date: Thu Jan 01 00:00:00 1970 +0000
2464 summary: A1B1C1
2477 summary: A1B1C1
2465
2478
2466 $ cd ..
2479 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now