##// END OF EJS Templates
revset: use integer representation of wdir() in revset...
Yuya Nishihara -
r25765:5e1b0739 default
parent child Browse files
Show More
@@ -1,3652 +1,3652 b''
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 import re
8 import re
9 import parser, util, error, hbisect, phases
9 import parser, util, error, hbisect, phases
10 import node
10 import node
11 import heapq
11 import heapq
12 import match as matchmod
12 import match as matchmod
13 from i18n import _
13 from i18n import _
14 import encoding
14 import encoding
15 import obsolete as obsmod
15 import obsolete as obsmod
16 import pathutil
16 import pathutil
17 import repoview
17 import repoview
18
18
19 def _revancestors(repo, revs, followfirst):
19 def _revancestors(repo, revs, followfirst):
20 """Like revlog.ancestors(), but supports followfirst."""
20 """Like revlog.ancestors(), but supports followfirst."""
21 if followfirst:
21 if followfirst:
22 cut = 1
22 cut = 1
23 else:
23 else:
24 cut = None
24 cut = None
25 cl = repo.changelog
25 cl = repo.changelog
26
26
27 def iterate():
27 def iterate():
28 revs.sort(reverse=True)
28 revs.sort(reverse=True)
29 irevs = iter(revs)
29 irevs = iter(revs)
30 h = []
30 h = []
31
31
32 inputrev = next(irevs, None)
32 inputrev = next(irevs, None)
33 if inputrev is not None:
33 if inputrev is not None:
34 heapq.heappush(h, -inputrev)
34 heapq.heappush(h, -inputrev)
35
35
36 seen = set()
36 seen = set()
37 while h:
37 while h:
38 current = -heapq.heappop(h)
38 current = -heapq.heappop(h)
39 if current == inputrev:
39 if current == inputrev:
40 inputrev = next(irevs, None)
40 inputrev = next(irevs, None)
41 if inputrev is not None:
41 if inputrev is not None:
42 heapq.heappush(h, -inputrev)
42 heapq.heappush(h, -inputrev)
43 if current not in seen:
43 if current not in seen:
44 seen.add(current)
44 seen.add(current)
45 yield current
45 yield current
46 for parent in cl.parentrevs(current)[:cut]:
46 for parent in cl.parentrevs(current)[:cut]:
47 if parent != node.nullrev:
47 if parent != node.nullrev:
48 heapq.heappush(h, -parent)
48 heapq.heappush(h, -parent)
49
49
50 return generatorset(iterate(), iterasc=False)
50 return generatorset(iterate(), iterasc=False)
51
51
52 def _revdescendants(repo, revs, followfirst):
52 def _revdescendants(repo, revs, followfirst):
53 """Like revlog.descendants() but supports followfirst."""
53 """Like revlog.descendants() but supports followfirst."""
54 if followfirst:
54 if followfirst:
55 cut = 1
55 cut = 1
56 else:
56 else:
57 cut = None
57 cut = None
58
58
59 def iterate():
59 def iterate():
60 cl = repo.changelog
60 cl = repo.changelog
61 # XXX this should be 'parentset.min()' assuming 'parentset' is a
61 # XXX this should be 'parentset.min()' assuming 'parentset' is a
62 # smartset (and if it is not, it should.)
62 # smartset (and if it is not, it should.)
63 first = min(revs)
63 first = min(revs)
64 nullrev = node.nullrev
64 nullrev = node.nullrev
65 if first == nullrev:
65 if first == nullrev:
66 # Are there nodes with a null first parent and a non-null
66 # Are there nodes with a null first parent and a non-null
67 # second one? Maybe. Do we care? Probably not.
67 # second one? Maybe. Do we care? Probably not.
68 for i in cl:
68 for i in cl:
69 yield i
69 yield i
70 else:
70 else:
71 seen = set(revs)
71 seen = set(revs)
72 for i in cl.revs(first + 1):
72 for i in cl.revs(first + 1):
73 for x in cl.parentrevs(i)[:cut]:
73 for x in cl.parentrevs(i)[:cut]:
74 if x != nullrev and x in seen:
74 if x != nullrev and x in seen:
75 seen.add(i)
75 seen.add(i)
76 yield i
76 yield i
77 break
77 break
78
78
79 return generatorset(iterate(), iterasc=True)
79 return generatorset(iterate(), iterasc=True)
80
80
81 def _revsbetween(repo, roots, heads):
81 def _revsbetween(repo, roots, heads):
82 """Return all paths between roots and heads, inclusive of both endpoint
82 """Return all paths between roots and heads, inclusive of both endpoint
83 sets."""
83 sets."""
84 if not roots:
84 if not roots:
85 return baseset()
85 return baseset()
86 parentrevs = repo.changelog.parentrevs
86 parentrevs = repo.changelog.parentrevs
87 visit = list(heads)
87 visit = list(heads)
88 reachable = set()
88 reachable = set()
89 seen = {}
89 seen = {}
90 # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
90 # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
91 # (and if it is not, it should.)
91 # (and if it is not, it should.)
92 minroot = min(roots)
92 minroot = min(roots)
93 roots = set(roots)
93 roots = set(roots)
94 # prefetch all the things! (because python is slow)
94 # prefetch all the things! (because python is slow)
95 reached = reachable.add
95 reached = reachable.add
96 dovisit = visit.append
96 dovisit = visit.append
97 nextvisit = visit.pop
97 nextvisit = visit.pop
98 # open-code the post-order traversal due to the tiny size of
98 # open-code the post-order traversal due to the tiny size of
99 # sys.getrecursionlimit()
99 # sys.getrecursionlimit()
100 while visit:
100 while visit:
101 rev = nextvisit()
101 rev = nextvisit()
102 if rev in roots:
102 if rev in roots:
103 reached(rev)
103 reached(rev)
104 parents = parentrevs(rev)
104 parents = parentrevs(rev)
105 seen[rev] = parents
105 seen[rev] = parents
106 for parent in parents:
106 for parent in parents:
107 if parent >= minroot and parent not in seen:
107 if parent >= minroot and parent not in seen:
108 dovisit(parent)
108 dovisit(parent)
109 if not reachable:
109 if not reachable:
110 return baseset()
110 return baseset()
111 for rev in sorted(seen):
111 for rev in sorted(seen):
112 for parent in seen[rev]:
112 for parent in seen[rev]:
113 if parent in reachable:
113 if parent in reachable:
114 reached(rev)
114 reached(rev)
115 return baseset(sorted(reachable))
115 return baseset(sorted(reachable))
116
116
117 elements = {
117 elements = {
118 "(": (21, ("group", 1, ")"), ("func", 1, ")")),
118 "(": (21, ("group", 1, ")"), ("func", 1, ")")),
119 "##": (20, None, ("_concat", 20)),
119 "##": (20, None, ("_concat", 20)),
120 "~": (18, None, ("ancestor", 18)),
120 "~": (18, None, ("ancestor", 18)),
121 "^": (18, None, ("parent", 18), ("parentpost", 18)),
121 "^": (18, None, ("parent", 18), ("parentpost", 18)),
122 "-": (5, ("negate", 19), ("minus", 5)),
122 "-": (5, ("negate", 19), ("minus", 5)),
123 "::": (17, ("dagrangepre", 17), ("dagrange", 17),
123 "::": (17, ("dagrangepre", 17), ("dagrange", 17),
124 ("dagrangepost", 17)),
124 ("dagrangepost", 17)),
125 "..": (17, ("dagrangepre", 17), ("dagrange", 17),
125 "..": (17, ("dagrangepre", 17), ("dagrange", 17),
126 ("dagrangepost", 17)),
126 ("dagrangepost", 17)),
127 ":": (15, ("rangepre", 15), ("range", 15), ("rangepost", 15)),
127 ":": (15, ("rangepre", 15), ("range", 15), ("rangepost", 15)),
128 "not": (10, ("not", 10)),
128 "not": (10, ("not", 10)),
129 "!": (10, ("not", 10)),
129 "!": (10, ("not", 10)),
130 "and": (5, None, ("and", 5)),
130 "and": (5, None, ("and", 5)),
131 "&": (5, None, ("and", 5)),
131 "&": (5, None, ("and", 5)),
132 "%": (5, None, ("only", 5), ("onlypost", 5)),
132 "%": (5, None, ("only", 5), ("onlypost", 5)),
133 "or": (4, None, ("or", 4)),
133 "or": (4, None, ("or", 4)),
134 "|": (4, None, ("or", 4)),
134 "|": (4, None, ("or", 4)),
135 "+": (4, None, ("or", 4)),
135 "+": (4, None, ("or", 4)),
136 "=": (3, None, ("keyvalue", 3)),
136 "=": (3, None, ("keyvalue", 3)),
137 ",": (2, None, ("list", 2)),
137 ",": (2, None, ("list", 2)),
138 ")": (0, None, None),
138 ")": (0, None, None),
139 "symbol": (0, ("symbol",), None),
139 "symbol": (0, ("symbol",), None),
140 "string": (0, ("string",), None),
140 "string": (0, ("string",), None),
141 "end": (0, None, None),
141 "end": (0, None, None),
142 }
142 }
143
143
144 keywords = set(['and', 'or', 'not'])
144 keywords = set(['and', 'or', 'not'])
145
145
146 # default set of valid characters for the initial letter of symbols
146 # default set of valid characters for the initial letter of symbols
147 _syminitletters = set(c for c in [chr(i) for i in xrange(256)]
147 _syminitletters = set(c for c in [chr(i) for i in xrange(256)]
148 if c.isalnum() or c in '._@' or ord(c) > 127)
148 if c.isalnum() or c in '._@' or ord(c) > 127)
149
149
150 # default set of valid characters for non-initial letters of symbols
150 # default set of valid characters for non-initial letters of symbols
151 _symletters = set(c for c in [chr(i) for i in xrange(256)]
151 _symletters = set(c for c in [chr(i) for i in xrange(256)]
152 if c.isalnum() or c in '-._/@' or ord(c) > 127)
152 if c.isalnum() or c in '-._/@' or ord(c) > 127)
153
153
154 def tokenize(program, lookup=None, syminitletters=None, symletters=None):
154 def tokenize(program, lookup=None, syminitletters=None, symletters=None):
155 '''
155 '''
156 Parse a revset statement into a stream of tokens
156 Parse a revset statement into a stream of tokens
157
157
158 ``syminitletters`` is the set of valid characters for the initial
158 ``syminitletters`` is the set of valid characters for the initial
159 letter of symbols.
159 letter of symbols.
160
160
161 By default, character ``c`` is recognized as valid for initial
161 By default, character ``c`` is recognized as valid for initial
162 letter of symbols, if ``c.isalnum() or c in '._@' or ord(c) > 127``.
162 letter of symbols, if ``c.isalnum() or c in '._@' or ord(c) > 127``.
163
163
164 ``symletters`` is the set of valid characters for non-initial
164 ``symletters`` is the set of valid characters for non-initial
165 letters of symbols.
165 letters of symbols.
166
166
167 By default, character ``c`` is recognized as valid for non-initial
167 By default, character ``c`` is recognized as valid for non-initial
168 letters of symbols, if ``c.isalnum() or c in '-._/@' or ord(c) > 127``.
168 letters of symbols, if ``c.isalnum() or c in '-._/@' or ord(c) > 127``.
169
169
170 Check that @ is a valid unquoted token character (issue3686):
170 Check that @ is a valid unquoted token character (issue3686):
171 >>> list(tokenize("@::"))
171 >>> list(tokenize("@::"))
172 [('symbol', '@', 0), ('::', None, 1), ('end', None, 3)]
172 [('symbol', '@', 0), ('::', None, 1), ('end', None, 3)]
173
173
174 '''
174 '''
175 if syminitletters is None:
175 if syminitletters is None:
176 syminitletters = _syminitletters
176 syminitletters = _syminitletters
177 if symletters is None:
177 if symletters is None:
178 symletters = _symletters
178 symletters = _symletters
179
179
180 pos, l = 0, len(program)
180 pos, l = 0, len(program)
181 while pos < l:
181 while pos < l:
182 c = program[pos]
182 c = program[pos]
183 if c.isspace(): # skip inter-token whitespace
183 if c.isspace(): # skip inter-token whitespace
184 pass
184 pass
185 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
185 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
186 yield ('::', None, pos)
186 yield ('::', None, pos)
187 pos += 1 # skip ahead
187 pos += 1 # skip ahead
188 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
188 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
189 yield ('..', None, pos)
189 yield ('..', None, pos)
190 pos += 1 # skip ahead
190 pos += 1 # skip ahead
191 elif c == '#' and program[pos:pos + 2] == '##': # look ahead carefully
191 elif c == '#' and program[pos:pos + 2] == '##': # look ahead carefully
192 yield ('##', None, pos)
192 yield ('##', None, pos)
193 pos += 1 # skip ahead
193 pos += 1 # skip ahead
194 elif c in "():=,-|&+!~^%": # handle simple operators
194 elif c in "():=,-|&+!~^%": # handle simple operators
195 yield (c, None, pos)
195 yield (c, None, pos)
196 elif (c in '"\'' or c == 'r' and
196 elif (c in '"\'' or c == 'r' and
197 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
197 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
198 if c == 'r':
198 if c == 'r':
199 pos += 1
199 pos += 1
200 c = program[pos]
200 c = program[pos]
201 decode = lambda x: x
201 decode = lambda x: x
202 else:
202 else:
203 decode = lambda x: x.decode('string-escape')
203 decode = lambda x: x.decode('string-escape')
204 pos += 1
204 pos += 1
205 s = pos
205 s = pos
206 while pos < l: # find closing quote
206 while pos < l: # find closing quote
207 d = program[pos]
207 d = program[pos]
208 if d == '\\': # skip over escaped characters
208 if d == '\\': # skip over escaped characters
209 pos += 2
209 pos += 2
210 continue
210 continue
211 if d == c:
211 if d == c:
212 yield ('string', decode(program[s:pos]), s)
212 yield ('string', decode(program[s:pos]), s)
213 break
213 break
214 pos += 1
214 pos += 1
215 else:
215 else:
216 raise error.ParseError(_("unterminated string"), s)
216 raise error.ParseError(_("unterminated string"), s)
217 # gather up a symbol/keyword
217 # gather up a symbol/keyword
218 elif c in syminitletters:
218 elif c in syminitletters:
219 s = pos
219 s = pos
220 pos += 1
220 pos += 1
221 while pos < l: # find end of symbol
221 while pos < l: # find end of symbol
222 d = program[pos]
222 d = program[pos]
223 if d not in symletters:
223 if d not in symletters:
224 break
224 break
225 if d == '.' and program[pos - 1] == '.': # special case for ..
225 if d == '.' and program[pos - 1] == '.': # special case for ..
226 pos -= 1
226 pos -= 1
227 break
227 break
228 pos += 1
228 pos += 1
229 sym = program[s:pos]
229 sym = program[s:pos]
230 if sym in keywords: # operator keywords
230 if sym in keywords: # operator keywords
231 yield (sym, None, s)
231 yield (sym, None, s)
232 elif '-' in sym:
232 elif '-' in sym:
233 # some jerk gave us foo-bar-baz, try to check if it's a symbol
233 # some jerk gave us foo-bar-baz, try to check if it's a symbol
234 if lookup and lookup(sym):
234 if lookup and lookup(sym):
235 # looks like a real symbol
235 # looks like a real symbol
236 yield ('symbol', sym, s)
236 yield ('symbol', sym, s)
237 else:
237 else:
238 # looks like an expression
238 # looks like an expression
239 parts = sym.split('-')
239 parts = sym.split('-')
240 for p in parts[:-1]:
240 for p in parts[:-1]:
241 if p: # possible consecutive -
241 if p: # possible consecutive -
242 yield ('symbol', p, s)
242 yield ('symbol', p, s)
243 s += len(p)
243 s += len(p)
244 yield ('-', None, pos)
244 yield ('-', None, pos)
245 s += 1
245 s += 1
246 if parts[-1]: # possible trailing -
246 if parts[-1]: # possible trailing -
247 yield ('symbol', parts[-1], s)
247 yield ('symbol', parts[-1], s)
248 else:
248 else:
249 yield ('symbol', sym, s)
249 yield ('symbol', sym, s)
250 pos -= 1
250 pos -= 1
251 else:
251 else:
252 raise error.ParseError(_("syntax error in revset '%s'") %
252 raise error.ParseError(_("syntax error in revset '%s'") %
253 program, pos)
253 program, pos)
254 pos += 1
254 pos += 1
255 yield ('end', None, pos)
255 yield ('end', None, pos)
256
256
257 def parseerrordetail(inst):
257 def parseerrordetail(inst):
258 """Compose error message from specified ParseError object
258 """Compose error message from specified ParseError object
259 """
259 """
260 if len(inst.args) > 1:
260 if len(inst.args) > 1:
261 return _('at %s: %s') % (inst.args[1], inst.args[0])
261 return _('at %s: %s') % (inst.args[1], inst.args[0])
262 else:
262 else:
263 return inst.args[0]
263 return inst.args[0]
264
264
265 # helpers
265 # helpers
266
266
267 def getstring(x, err):
267 def getstring(x, err):
268 if x and (x[0] == 'string' or x[0] == 'symbol'):
268 if x and (x[0] == 'string' or x[0] == 'symbol'):
269 return x[1]
269 return x[1]
270 raise error.ParseError(err)
270 raise error.ParseError(err)
271
271
272 def getlist(x):
272 def getlist(x):
273 if not x:
273 if not x:
274 return []
274 return []
275 if x[0] == 'list':
275 if x[0] == 'list':
276 return getlist(x[1]) + [x[2]]
276 return getlist(x[1]) + [x[2]]
277 return [x]
277 return [x]
278
278
279 def getargs(x, min, max, err):
279 def getargs(x, min, max, err):
280 l = getlist(x)
280 l = getlist(x)
281 if len(l) < min or (max >= 0 and len(l) > max):
281 if len(l) < min or (max >= 0 and len(l) > max):
282 raise error.ParseError(err)
282 raise error.ParseError(err)
283 return l
283 return l
284
284
285 def getkwargs(x, funcname, keys):
285 def getkwargs(x, funcname, keys):
286 return parser.buildargsdict(getlist(x), funcname, keys.split(),
286 return parser.buildargsdict(getlist(x), funcname, keys.split(),
287 keyvaluenode='keyvalue', keynode='symbol')
287 keyvaluenode='keyvalue', keynode='symbol')
288
288
289 def isvalidsymbol(tree):
289 def isvalidsymbol(tree):
290 """Examine whether specified ``tree`` is valid ``symbol`` or not
290 """Examine whether specified ``tree`` is valid ``symbol`` or not
291 """
291 """
292 return tree[0] == 'symbol' and len(tree) > 1
292 return tree[0] == 'symbol' and len(tree) > 1
293
293
294 def getsymbol(tree):
294 def getsymbol(tree):
295 """Get symbol name from valid ``symbol`` in ``tree``
295 """Get symbol name from valid ``symbol`` in ``tree``
296
296
297 This assumes that ``tree`` is already examined by ``isvalidsymbol``.
297 This assumes that ``tree`` is already examined by ``isvalidsymbol``.
298 """
298 """
299 return tree[1]
299 return tree[1]
300
300
301 def isvalidfunc(tree):
301 def isvalidfunc(tree):
302 """Examine whether specified ``tree`` is valid ``func`` or not
302 """Examine whether specified ``tree`` is valid ``func`` or not
303 """
303 """
304 return tree[0] == 'func' and len(tree) > 1 and isvalidsymbol(tree[1])
304 return tree[0] == 'func' and len(tree) > 1 and isvalidsymbol(tree[1])
305
305
306 def getfuncname(tree):
306 def getfuncname(tree):
307 """Get function name from valid ``func`` in ``tree``
307 """Get function name from valid ``func`` in ``tree``
308
308
309 This assumes that ``tree`` is already examined by ``isvalidfunc``.
309 This assumes that ``tree`` is already examined by ``isvalidfunc``.
310 """
310 """
311 return getsymbol(tree[1])
311 return getsymbol(tree[1])
312
312
313 def getfuncargs(tree):
313 def getfuncargs(tree):
314 """Get list of function arguments from valid ``func`` in ``tree``
314 """Get list of function arguments from valid ``func`` in ``tree``
315
315
316 This assumes that ``tree`` is already examined by ``isvalidfunc``.
316 This assumes that ``tree`` is already examined by ``isvalidfunc``.
317 """
317 """
318 if len(tree) > 2:
318 if len(tree) > 2:
319 return getlist(tree[2])
319 return getlist(tree[2])
320 else:
320 else:
321 return []
321 return []
322
322
323 def getset(repo, subset, x):
323 def getset(repo, subset, x):
324 if not x:
324 if not x:
325 raise error.ParseError(_("missing argument"))
325 raise error.ParseError(_("missing argument"))
326 s = methods[x[0]](repo, subset, *x[1:])
326 s = methods[x[0]](repo, subset, *x[1:])
327 if util.safehasattr(s, 'isascending'):
327 if util.safehasattr(s, 'isascending'):
328 return s
328 return s
329 if (repo.ui.configbool('devel', 'all-warnings')
329 if (repo.ui.configbool('devel', 'all-warnings')
330 or repo.ui.configbool('devel', 'old-revset')):
330 or repo.ui.configbool('devel', 'old-revset')):
331 # else case should not happen, because all non-func are internal,
331 # else case should not happen, because all non-func are internal,
332 # ignoring for now.
332 # ignoring for now.
333 if x[0] == 'func' and x[1][0] == 'symbol' and x[1][1] in symbols:
333 if x[0] == 'func' and x[1][0] == 'symbol' and x[1][1] in symbols:
334 repo.ui.develwarn('revset "%s" use list instead of smartset, '
334 repo.ui.develwarn('revset "%s" use list instead of smartset, '
335 '(upgrade your code)' % x[1][1])
335 '(upgrade your code)' % x[1][1])
336 return baseset(s)
336 return baseset(s)
337
337
338 def _getrevsource(repo, r):
338 def _getrevsource(repo, r):
339 extra = repo[r].extra()
339 extra = repo[r].extra()
340 for label in ('source', 'transplant_source', 'rebase_source'):
340 for label in ('source', 'transplant_source', 'rebase_source'):
341 if label in extra:
341 if label in extra:
342 try:
342 try:
343 return repo[extra[label]].rev()
343 return repo[extra[label]].rev()
344 except error.RepoLookupError:
344 except error.RepoLookupError:
345 pass
345 pass
346 return None
346 return None
347
347
348 # operator methods
348 # operator methods
349
349
350 def stringset(repo, subset, x):
350 def stringset(repo, subset, x):
351 x = repo[x].rev()
351 x = repo[x].rev()
352 if (x in subset
352 if (x in subset
353 or x == node.nullrev and isinstance(subset, fullreposet)):
353 or x == node.nullrev and isinstance(subset, fullreposet)):
354 return baseset([x])
354 return baseset([x])
355 return baseset()
355 return baseset()
356
356
357 def rangeset(repo, subset, x, y):
357 def rangeset(repo, subset, x, y):
358 m = getset(repo, fullreposet(repo), x)
358 m = getset(repo, fullreposet(repo), x)
359 n = getset(repo, fullreposet(repo), y)
359 n = getset(repo, fullreposet(repo), y)
360
360
361 if not m or not n:
361 if not m or not n:
362 return baseset()
362 return baseset()
363 m, n = m.first(), n.last()
363 m, n = m.first(), n.last()
364
364
365 if m < n:
365 if m < n:
366 r = spanset(repo, m, n + 1)
366 r = spanset(repo, m, n + 1)
367 else:
367 else:
368 r = spanset(repo, m, n - 1)
368 r = spanset(repo, m, n - 1)
369 # XXX We should combine with subset first: 'subset & baseset(...)'. This is
369 # XXX We should combine with subset first: 'subset & baseset(...)'. This is
370 # necessary to ensure we preserve the order in subset.
370 # necessary to ensure we preserve the order in subset.
371 #
371 #
372 # This has performance implication, carrying the sorting over when possible
372 # This has performance implication, carrying the sorting over when possible
373 # would be more efficient.
373 # would be more efficient.
374 return r & subset
374 return r & subset
375
375
376 def dagrange(repo, subset, x, y):
376 def dagrange(repo, subset, x, y):
377 r = fullreposet(repo)
377 r = fullreposet(repo)
378 xs = _revsbetween(repo, getset(repo, r, x), getset(repo, r, y))
378 xs = _revsbetween(repo, getset(repo, r, x), getset(repo, r, y))
379 # XXX We should combine with subset first: 'subset & baseset(...)'. This is
379 # XXX We should combine with subset first: 'subset & baseset(...)'. This is
380 # necessary to ensure we preserve the order in subset.
380 # necessary to ensure we preserve the order in subset.
381 return xs & subset
381 return xs & subset
382
382
383 def andset(repo, subset, x, y):
383 def andset(repo, subset, x, y):
384 return getset(repo, getset(repo, subset, x), y)
384 return getset(repo, getset(repo, subset, x), y)
385
385
386 def orset(repo, subset, *xs):
386 def orset(repo, subset, *xs):
387 rs = [getset(repo, subset, x) for x in xs]
387 rs = [getset(repo, subset, x) for x in xs]
388 return _combinesets(rs)
388 return _combinesets(rs)
389
389
390 def notset(repo, subset, x):
390 def notset(repo, subset, x):
391 return subset - getset(repo, subset, x)
391 return subset - getset(repo, subset, x)
392
392
393 def listset(repo, subset, a, b):
393 def listset(repo, subset, a, b):
394 raise error.ParseError(_("can't use a list in this context"))
394 raise error.ParseError(_("can't use a list in this context"))
395
395
396 def keyvaluepair(repo, subset, k, v):
396 def keyvaluepair(repo, subset, k, v):
397 raise error.ParseError(_("can't use a key-value pair in this context"))
397 raise error.ParseError(_("can't use a key-value pair in this context"))
398
398
399 def func(repo, subset, a, b):
399 def func(repo, subset, a, b):
400 if a[0] == 'symbol' and a[1] in symbols:
400 if a[0] == 'symbol' and a[1] in symbols:
401 return symbols[a[1]](repo, subset, b)
401 return symbols[a[1]](repo, subset, b)
402
402
403 keep = lambda fn: getattr(fn, '__doc__', None) is not None
403 keep = lambda fn: getattr(fn, '__doc__', None) is not None
404
404
405 syms = [s for (s, fn) in symbols.items() if keep(fn)]
405 syms = [s for (s, fn) in symbols.items() if keep(fn)]
406 raise error.UnknownIdentifier(a[1], syms)
406 raise error.UnknownIdentifier(a[1], syms)
407
407
408 # functions
408 # functions
409
409
410 def adds(repo, subset, x):
410 def adds(repo, subset, x):
411 """``adds(pattern)``
411 """``adds(pattern)``
412 Changesets that add a file matching pattern.
412 Changesets that add a file matching pattern.
413
413
414 The pattern without explicit kind like ``glob:`` is expected to be
414 The pattern without explicit kind like ``glob:`` is expected to be
415 relative to the current directory and match against a file or a
415 relative to the current directory and match against a file or a
416 directory.
416 directory.
417 """
417 """
418 # i18n: "adds" is a keyword
418 # i18n: "adds" is a keyword
419 pat = getstring(x, _("adds requires a pattern"))
419 pat = getstring(x, _("adds requires a pattern"))
420 return checkstatus(repo, subset, pat, 1)
420 return checkstatus(repo, subset, pat, 1)
421
421
422 def ancestor(repo, subset, x):
422 def ancestor(repo, subset, x):
423 """``ancestor(*changeset)``
423 """``ancestor(*changeset)``
424 A greatest common ancestor of the changesets.
424 A greatest common ancestor of the changesets.
425
425
426 Accepts 0 or more changesets.
426 Accepts 0 or more changesets.
427 Will return empty list when passed no args.
427 Will return empty list when passed no args.
428 Greatest common ancestor of a single changeset is that changeset.
428 Greatest common ancestor of a single changeset is that changeset.
429 """
429 """
430 # i18n: "ancestor" is a keyword
430 # i18n: "ancestor" is a keyword
431 l = getlist(x)
431 l = getlist(x)
432 rl = fullreposet(repo)
432 rl = fullreposet(repo)
433 anc = None
433 anc = None
434
434
435 # (getset(repo, rl, i) for i in l) generates a list of lists
435 # (getset(repo, rl, i) for i in l) generates a list of lists
436 for revs in (getset(repo, rl, i) for i in l):
436 for revs in (getset(repo, rl, i) for i in l):
437 for r in revs:
437 for r in revs:
438 if anc is None:
438 if anc is None:
439 anc = repo[r]
439 anc = repo[r]
440 else:
440 else:
441 anc = anc.ancestor(repo[r])
441 anc = anc.ancestor(repo[r])
442
442
443 if anc is not None and anc.rev() in subset:
443 if anc is not None and anc.rev() in subset:
444 return baseset([anc.rev()])
444 return baseset([anc.rev()])
445 return baseset()
445 return baseset()
446
446
447 def _ancestors(repo, subset, x, followfirst=False):
447 def _ancestors(repo, subset, x, followfirst=False):
448 heads = getset(repo, fullreposet(repo), x)
448 heads = getset(repo, fullreposet(repo), x)
449 if not heads:
449 if not heads:
450 return baseset()
450 return baseset()
451 s = _revancestors(repo, heads, followfirst)
451 s = _revancestors(repo, heads, followfirst)
452 return subset & s
452 return subset & s
453
453
454 def ancestors(repo, subset, x):
454 def ancestors(repo, subset, x):
455 """``ancestors(set)``
455 """``ancestors(set)``
456 Changesets that are ancestors of a changeset in set.
456 Changesets that are ancestors of a changeset in set.
457 """
457 """
458 return _ancestors(repo, subset, x)
458 return _ancestors(repo, subset, x)
459
459
460 def _firstancestors(repo, subset, x):
460 def _firstancestors(repo, subset, x):
461 # ``_firstancestors(set)``
461 # ``_firstancestors(set)``
462 # Like ``ancestors(set)`` but follows only the first parents.
462 # Like ``ancestors(set)`` but follows only the first parents.
463 return _ancestors(repo, subset, x, followfirst=True)
463 return _ancestors(repo, subset, x, followfirst=True)
464
464
465 def ancestorspec(repo, subset, x, n):
465 def ancestorspec(repo, subset, x, n):
466 """``set~n``
466 """``set~n``
467 Changesets that are the Nth ancestor (first parents only) of a changeset
467 Changesets that are the Nth ancestor (first parents only) of a changeset
468 in set.
468 in set.
469 """
469 """
470 try:
470 try:
471 n = int(n[1])
471 n = int(n[1])
472 except (TypeError, ValueError):
472 except (TypeError, ValueError):
473 raise error.ParseError(_("~ expects a number"))
473 raise error.ParseError(_("~ expects a number"))
474 ps = set()
474 ps = set()
475 cl = repo.changelog
475 cl = repo.changelog
476 for r in getset(repo, fullreposet(repo), x):
476 for r in getset(repo, fullreposet(repo), x):
477 for i in range(n):
477 for i in range(n):
478 r = cl.parentrevs(r)[0]
478 r = cl.parentrevs(r)[0]
479 ps.add(r)
479 ps.add(r)
480 return subset & ps
480 return subset & ps
481
481
482 def author(repo, subset, x):
482 def author(repo, subset, x):
483 """``author(string)``
483 """``author(string)``
484 Alias for ``user(string)``.
484 Alias for ``user(string)``.
485 """
485 """
486 # i18n: "author" is a keyword
486 # i18n: "author" is a keyword
487 n = encoding.lower(getstring(x, _("author requires a string")))
487 n = encoding.lower(getstring(x, _("author requires a string")))
488 kind, pattern, matcher = _substringmatcher(n)
488 kind, pattern, matcher = _substringmatcher(n)
489 return subset.filter(lambda x: matcher(encoding.lower(repo[x].user())))
489 return subset.filter(lambda x: matcher(encoding.lower(repo[x].user())))
490
490
491 def bisect(repo, subset, x):
491 def bisect(repo, subset, x):
492 """``bisect(string)``
492 """``bisect(string)``
493 Changesets marked in the specified bisect status:
493 Changesets marked in the specified bisect status:
494
494
495 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
495 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
496 - ``goods``, ``bads`` : csets topologically good/bad
496 - ``goods``, ``bads`` : csets topologically good/bad
497 - ``range`` : csets taking part in the bisection
497 - ``range`` : csets taking part in the bisection
498 - ``pruned`` : csets that are goods, bads or skipped
498 - ``pruned`` : csets that are goods, bads or skipped
499 - ``untested`` : csets whose fate is yet unknown
499 - ``untested`` : csets whose fate is yet unknown
500 - ``ignored`` : csets ignored due to DAG topology
500 - ``ignored`` : csets ignored due to DAG topology
501 - ``current`` : the cset currently being bisected
501 - ``current`` : the cset currently being bisected
502 """
502 """
503 # i18n: "bisect" is a keyword
503 # i18n: "bisect" is a keyword
504 status = getstring(x, _("bisect requires a string")).lower()
504 status = getstring(x, _("bisect requires a string")).lower()
505 state = set(hbisect.get(repo, status))
505 state = set(hbisect.get(repo, status))
506 return subset & state
506 return subset & state
507
507
508 # Backward-compatibility
508 # Backward-compatibility
509 # - no help entry so that we do not advertise it any more
509 # - no help entry so that we do not advertise it any more
510 def bisected(repo, subset, x):
510 def bisected(repo, subset, x):
511 return bisect(repo, subset, x)
511 return bisect(repo, subset, x)
512
512
513 def bookmark(repo, subset, x):
513 def bookmark(repo, subset, x):
514 """``bookmark([name])``
514 """``bookmark([name])``
515 The named bookmark or all bookmarks.
515 The named bookmark or all bookmarks.
516
516
517 If `name` starts with `re:`, the remainder of the name is treated as
517 If `name` starts with `re:`, the remainder of the name is treated as
518 a regular expression. To match a bookmark that actually starts with `re:`,
518 a regular expression. To match a bookmark that actually starts with `re:`,
519 use the prefix `literal:`.
519 use the prefix `literal:`.
520 """
520 """
521 # i18n: "bookmark" is a keyword
521 # i18n: "bookmark" is a keyword
522 args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
522 args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
523 if args:
523 if args:
524 bm = getstring(args[0],
524 bm = getstring(args[0],
525 # i18n: "bookmark" is a keyword
525 # i18n: "bookmark" is a keyword
526 _('the argument to bookmark must be a string'))
526 _('the argument to bookmark must be a string'))
527 kind, pattern, matcher = _stringmatcher(bm)
527 kind, pattern, matcher = _stringmatcher(bm)
528 bms = set()
528 bms = set()
529 if kind == 'literal':
529 if kind == 'literal':
530 bmrev = repo._bookmarks.get(pattern, None)
530 bmrev = repo._bookmarks.get(pattern, None)
531 if not bmrev:
531 if not bmrev:
532 raise error.RepoLookupError(_("bookmark '%s' does not exist")
532 raise error.RepoLookupError(_("bookmark '%s' does not exist")
533 % bm)
533 % bm)
534 bms.add(repo[bmrev].rev())
534 bms.add(repo[bmrev].rev())
535 else:
535 else:
536 matchrevs = set()
536 matchrevs = set()
537 for name, bmrev in repo._bookmarks.iteritems():
537 for name, bmrev in repo._bookmarks.iteritems():
538 if matcher(name):
538 if matcher(name):
539 matchrevs.add(bmrev)
539 matchrevs.add(bmrev)
540 if not matchrevs:
540 if not matchrevs:
541 raise error.RepoLookupError(_("no bookmarks exist"
541 raise error.RepoLookupError(_("no bookmarks exist"
542 " that match '%s'") % pattern)
542 " that match '%s'") % pattern)
543 for bmrev in matchrevs:
543 for bmrev in matchrevs:
544 bms.add(repo[bmrev].rev())
544 bms.add(repo[bmrev].rev())
545 else:
545 else:
546 bms = set([repo[r].rev()
546 bms = set([repo[r].rev()
547 for r in repo._bookmarks.values()])
547 for r in repo._bookmarks.values()])
548 bms -= set([node.nullrev])
548 bms -= set([node.nullrev])
549 return subset & bms
549 return subset & bms
550
550
551 def branch(repo, subset, x):
551 def branch(repo, subset, x):
552 """``branch(string or set)``
552 """``branch(string or set)``
553 All changesets belonging to the given branch or the branches of the given
553 All changesets belonging to the given branch or the branches of the given
554 changesets.
554 changesets.
555
555
556 If `string` starts with `re:`, the remainder of the name is treated as
556 If `string` starts with `re:`, the remainder of the name is treated as
557 a regular expression. To match a branch that actually starts with `re:`,
557 a regular expression. To match a branch that actually starts with `re:`,
558 use the prefix `literal:`.
558 use the prefix `literal:`.
559 """
559 """
560 getbi = repo.revbranchcache().branchinfo
560 getbi = repo.revbranchcache().branchinfo
561
561
562 try:
562 try:
563 b = getstring(x, '')
563 b = getstring(x, '')
564 except error.ParseError:
564 except error.ParseError:
565 # not a string, but another revspec, e.g. tip()
565 # not a string, but another revspec, e.g. tip()
566 pass
566 pass
567 else:
567 else:
568 kind, pattern, matcher = _stringmatcher(b)
568 kind, pattern, matcher = _stringmatcher(b)
569 if kind == 'literal':
569 if kind == 'literal':
570 # note: falls through to the revspec case if no branch with
570 # note: falls through to the revspec case if no branch with
571 # this name exists
571 # this name exists
572 if pattern in repo.branchmap():
572 if pattern in repo.branchmap():
573 return subset.filter(lambda r: matcher(getbi(r)[0]))
573 return subset.filter(lambda r: matcher(getbi(r)[0]))
574 else:
574 else:
575 return subset.filter(lambda r: matcher(getbi(r)[0]))
575 return subset.filter(lambda r: matcher(getbi(r)[0]))
576
576
577 s = getset(repo, fullreposet(repo), x)
577 s = getset(repo, fullreposet(repo), x)
578 b = set()
578 b = set()
579 for r in s:
579 for r in s:
580 b.add(getbi(r)[0])
580 b.add(getbi(r)[0])
581 c = s.__contains__
581 c = s.__contains__
582 return subset.filter(lambda r: c(r) or getbi(r)[0] in b)
582 return subset.filter(lambda r: c(r) or getbi(r)[0] in b)
583
583
584 def bumped(repo, subset, x):
584 def bumped(repo, subset, x):
585 """``bumped()``
585 """``bumped()``
586 Mutable changesets marked as successors of public changesets.
586 Mutable changesets marked as successors of public changesets.
587
587
588 Only non-public and non-obsolete changesets can be `bumped`.
588 Only non-public and non-obsolete changesets can be `bumped`.
589 """
589 """
590 # i18n: "bumped" is a keyword
590 # i18n: "bumped" is a keyword
591 getargs(x, 0, 0, _("bumped takes no arguments"))
591 getargs(x, 0, 0, _("bumped takes no arguments"))
592 bumped = obsmod.getrevs(repo, 'bumped')
592 bumped = obsmod.getrevs(repo, 'bumped')
593 return subset & bumped
593 return subset & bumped
594
594
595 def bundle(repo, subset, x):
595 def bundle(repo, subset, x):
596 """``bundle()``
596 """``bundle()``
597 Changesets in the bundle.
597 Changesets in the bundle.
598
598
599 Bundle must be specified by the -R option."""
599 Bundle must be specified by the -R option."""
600
600
601 try:
601 try:
602 bundlerevs = repo.changelog.bundlerevs
602 bundlerevs = repo.changelog.bundlerevs
603 except AttributeError:
603 except AttributeError:
604 raise util.Abort(_("no bundle provided - specify with -R"))
604 raise util.Abort(_("no bundle provided - specify with -R"))
605 return subset & bundlerevs
605 return subset & bundlerevs
606
606
607 def checkstatus(repo, subset, pat, field):
607 def checkstatus(repo, subset, pat, field):
608 hasset = matchmod.patkind(pat) == 'set'
608 hasset = matchmod.patkind(pat) == 'set'
609
609
610 mcache = [None]
610 mcache = [None]
611 def matches(x):
611 def matches(x):
612 c = repo[x]
612 c = repo[x]
613 if not mcache[0] or hasset:
613 if not mcache[0] or hasset:
614 mcache[0] = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
614 mcache[0] = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
615 m = mcache[0]
615 m = mcache[0]
616 fname = None
616 fname = None
617 if not m.anypats() and len(m.files()) == 1:
617 if not m.anypats() and len(m.files()) == 1:
618 fname = m.files()[0]
618 fname = m.files()[0]
619 if fname is not None:
619 if fname is not None:
620 if fname not in c.files():
620 if fname not in c.files():
621 return False
621 return False
622 else:
622 else:
623 for f in c.files():
623 for f in c.files():
624 if m(f):
624 if m(f):
625 break
625 break
626 else:
626 else:
627 return False
627 return False
628 files = repo.status(c.p1().node(), c.node())[field]
628 files = repo.status(c.p1().node(), c.node())[field]
629 if fname is not None:
629 if fname is not None:
630 if fname in files:
630 if fname in files:
631 return True
631 return True
632 else:
632 else:
633 for f in files:
633 for f in files:
634 if m(f):
634 if m(f):
635 return True
635 return True
636
636
637 return subset.filter(matches)
637 return subset.filter(matches)
638
638
639 def _children(repo, narrow, parentset):
639 def _children(repo, narrow, parentset):
640 if not parentset:
640 if not parentset:
641 return baseset()
641 return baseset()
642 cs = set()
642 cs = set()
643 pr = repo.changelog.parentrevs
643 pr = repo.changelog.parentrevs
644 minrev = parentset.min()
644 minrev = parentset.min()
645 for r in narrow:
645 for r in narrow:
646 if r <= minrev:
646 if r <= minrev:
647 continue
647 continue
648 for p in pr(r):
648 for p in pr(r):
649 if p in parentset:
649 if p in parentset:
650 cs.add(r)
650 cs.add(r)
651 # XXX using a set to feed the baseset is wrong. Sets are not ordered.
651 # XXX using a set to feed the baseset is wrong. Sets are not ordered.
652 # This does not break because of other fullreposet misbehavior.
652 # This does not break because of other fullreposet misbehavior.
653 return baseset(cs)
653 return baseset(cs)
654
654
655 def children(repo, subset, x):
655 def children(repo, subset, x):
656 """``children(set)``
656 """``children(set)``
657 Child changesets of changesets in set.
657 Child changesets of changesets in set.
658 """
658 """
659 s = getset(repo, fullreposet(repo), x)
659 s = getset(repo, fullreposet(repo), x)
660 cs = _children(repo, subset, s)
660 cs = _children(repo, subset, s)
661 return subset & cs
661 return subset & cs
662
662
663 def closed(repo, subset, x):
663 def closed(repo, subset, x):
664 """``closed()``
664 """``closed()``
665 Changeset is closed.
665 Changeset is closed.
666 """
666 """
667 # i18n: "closed" is a keyword
667 # i18n: "closed" is a keyword
668 getargs(x, 0, 0, _("closed takes no arguments"))
668 getargs(x, 0, 0, _("closed takes no arguments"))
669 return subset.filter(lambda r: repo[r].closesbranch())
669 return subset.filter(lambda r: repo[r].closesbranch())
670
670
671 def contains(repo, subset, x):
671 def contains(repo, subset, x):
672 """``contains(pattern)``
672 """``contains(pattern)``
673 The revision's manifest contains a file matching pattern (but might not
673 The revision's manifest contains a file matching pattern (but might not
674 modify it). See :hg:`help patterns` for information about file patterns.
674 modify it). See :hg:`help patterns` for information about file patterns.
675
675
676 The pattern without explicit kind like ``glob:`` is expected to be
676 The pattern without explicit kind like ``glob:`` is expected to be
677 relative to the current directory and match against a file exactly
677 relative to the current directory and match against a file exactly
678 for efficiency.
678 for efficiency.
679 """
679 """
680 # i18n: "contains" is a keyword
680 # i18n: "contains" is a keyword
681 pat = getstring(x, _("contains requires a pattern"))
681 pat = getstring(x, _("contains requires a pattern"))
682
682
683 def matches(x):
683 def matches(x):
684 if not matchmod.patkind(pat):
684 if not matchmod.patkind(pat):
685 pats = pathutil.canonpath(repo.root, repo.getcwd(), pat)
685 pats = pathutil.canonpath(repo.root, repo.getcwd(), pat)
686 if pats in repo[x]:
686 if pats in repo[x]:
687 return True
687 return True
688 else:
688 else:
689 c = repo[x]
689 c = repo[x]
690 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
690 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
691 for f in c.manifest():
691 for f in c.manifest():
692 if m(f):
692 if m(f):
693 return True
693 return True
694 return False
694 return False
695
695
696 return subset.filter(matches)
696 return subset.filter(matches)
697
697
698 def converted(repo, subset, x):
698 def converted(repo, subset, x):
699 """``converted([id])``
699 """``converted([id])``
700 Changesets converted from the given identifier in the old repository if
700 Changesets converted from the given identifier in the old repository if
701 present, or all converted changesets if no identifier is specified.
701 present, or all converted changesets if no identifier is specified.
702 """
702 """
703
703
704 # There is exactly no chance of resolving the revision, so do a simple
704 # There is exactly no chance of resolving the revision, so do a simple
705 # string compare and hope for the best
705 # string compare and hope for the best
706
706
707 rev = None
707 rev = None
708 # i18n: "converted" is a keyword
708 # i18n: "converted" is a keyword
709 l = getargs(x, 0, 1, _('converted takes one or no arguments'))
709 l = getargs(x, 0, 1, _('converted takes one or no arguments'))
710 if l:
710 if l:
711 # i18n: "converted" is a keyword
711 # i18n: "converted" is a keyword
712 rev = getstring(l[0], _('converted requires a revision'))
712 rev = getstring(l[0], _('converted requires a revision'))
713
713
714 def _matchvalue(r):
714 def _matchvalue(r):
715 source = repo[r].extra().get('convert_revision', None)
715 source = repo[r].extra().get('convert_revision', None)
716 return source is not None and (rev is None or source.startswith(rev))
716 return source is not None and (rev is None or source.startswith(rev))
717
717
718 return subset.filter(lambda r: _matchvalue(r))
718 return subset.filter(lambda r: _matchvalue(r))
719
719
720 def date(repo, subset, x):
720 def date(repo, subset, x):
721 """``date(interval)``
721 """``date(interval)``
722 Changesets within the interval, see :hg:`help dates`.
722 Changesets within the interval, see :hg:`help dates`.
723 """
723 """
724 # i18n: "date" is a keyword
724 # i18n: "date" is a keyword
725 ds = getstring(x, _("date requires a string"))
725 ds = getstring(x, _("date requires a string"))
726 dm = util.matchdate(ds)
726 dm = util.matchdate(ds)
727 return subset.filter(lambda x: dm(repo[x].date()[0]))
727 return subset.filter(lambda x: dm(repo[x].date()[0]))
728
728
729 def desc(repo, subset, x):
729 def desc(repo, subset, x):
730 """``desc(string)``
730 """``desc(string)``
731 Search commit message for string. The match is case-insensitive.
731 Search commit message for string. The match is case-insensitive.
732 """
732 """
733 # i18n: "desc" is a keyword
733 # i18n: "desc" is a keyword
734 ds = encoding.lower(getstring(x, _("desc requires a string")))
734 ds = encoding.lower(getstring(x, _("desc requires a string")))
735
735
736 def matches(x):
736 def matches(x):
737 c = repo[x]
737 c = repo[x]
738 return ds in encoding.lower(c.description())
738 return ds in encoding.lower(c.description())
739
739
740 return subset.filter(matches)
740 return subset.filter(matches)
741
741
742 def _descendants(repo, subset, x, followfirst=False):
742 def _descendants(repo, subset, x, followfirst=False):
743 roots = getset(repo, fullreposet(repo), x)
743 roots = getset(repo, fullreposet(repo), x)
744 if not roots:
744 if not roots:
745 return baseset()
745 return baseset()
746 s = _revdescendants(repo, roots, followfirst)
746 s = _revdescendants(repo, roots, followfirst)
747
747
748 # Both sets need to be ascending in order to lazily return the union
748 # Both sets need to be ascending in order to lazily return the union
749 # in the correct order.
749 # in the correct order.
750 base = subset & roots
750 base = subset & roots
751 desc = subset & s
751 desc = subset & s
752 result = base + desc
752 result = base + desc
753 if subset.isascending():
753 if subset.isascending():
754 result.sort()
754 result.sort()
755 elif subset.isdescending():
755 elif subset.isdescending():
756 result.sort(reverse=True)
756 result.sort(reverse=True)
757 else:
757 else:
758 result = subset & result
758 result = subset & result
759 return result
759 return result
760
760
761 def descendants(repo, subset, x):
761 def descendants(repo, subset, x):
762 """``descendants(set)``
762 """``descendants(set)``
763 Changesets which are descendants of changesets in set.
763 Changesets which are descendants of changesets in set.
764 """
764 """
765 return _descendants(repo, subset, x)
765 return _descendants(repo, subset, x)
766
766
767 def _firstdescendants(repo, subset, x):
767 def _firstdescendants(repo, subset, x):
768 # ``_firstdescendants(set)``
768 # ``_firstdescendants(set)``
769 # Like ``descendants(set)`` but follows only the first parents.
769 # Like ``descendants(set)`` but follows only the first parents.
770 return _descendants(repo, subset, x, followfirst=True)
770 return _descendants(repo, subset, x, followfirst=True)
771
771
772 def destination(repo, subset, x):
772 def destination(repo, subset, x):
773 """``destination([set])``
773 """``destination([set])``
774 Changesets that were created by a graft, transplant or rebase operation,
774 Changesets that were created by a graft, transplant or rebase operation,
775 with the given revisions specified as the source. Omitting the optional set
775 with the given revisions specified as the source. Omitting the optional set
776 is the same as passing all().
776 is the same as passing all().
777 """
777 """
778 if x is not None:
778 if x is not None:
779 sources = getset(repo, fullreposet(repo), x)
779 sources = getset(repo, fullreposet(repo), x)
780 else:
780 else:
781 sources = fullreposet(repo)
781 sources = fullreposet(repo)
782
782
783 dests = set()
783 dests = set()
784
784
785 # subset contains all of the possible destinations that can be returned, so
785 # subset contains all of the possible destinations that can be returned, so
786 # iterate over them and see if their source(s) were provided in the arg set.
786 # iterate over them and see if their source(s) were provided in the arg set.
787 # Even if the immediate src of r is not in the arg set, src's source (or
787 # Even if the immediate src of r is not in the arg set, src's source (or
788 # further back) may be. Scanning back further than the immediate src allows
788 # further back) may be. Scanning back further than the immediate src allows
789 # transitive transplants and rebases to yield the same results as transitive
789 # transitive transplants and rebases to yield the same results as transitive
790 # grafts.
790 # grafts.
791 for r in subset:
791 for r in subset:
792 src = _getrevsource(repo, r)
792 src = _getrevsource(repo, r)
793 lineage = None
793 lineage = None
794
794
795 while src is not None:
795 while src is not None:
796 if lineage is None:
796 if lineage is None:
797 lineage = list()
797 lineage = list()
798
798
799 lineage.append(r)
799 lineage.append(r)
800
800
801 # The visited lineage is a match if the current source is in the arg
801 # The visited lineage is a match if the current source is in the arg
802 # set. Since every candidate dest is visited by way of iterating
802 # set. Since every candidate dest is visited by way of iterating
803 # subset, any dests further back in the lineage will be tested by a
803 # subset, any dests further back in the lineage will be tested by a
804 # different iteration over subset. Likewise, if the src was already
804 # different iteration over subset. Likewise, if the src was already
805 # selected, the current lineage can be selected without going back
805 # selected, the current lineage can be selected without going back
806 # further.
806 # further.
807 if src in sources or src in dests:
807 if src in sources or src in dests:
808 dests.update(lineage)
808 dests.update(lineage)
809 break
809 break
810
810
811 r = src
811 r = src
812 src = _getrevsource(repo, r)
812 src = _getrevsource(repo, r)
813
813
814 return subset.filter(dests.__contains__)
814 return subset.filter(dests.__contains__)
815
815
816 def divergent(repo, subset, x):
816 def divergent(repo, subset, x):
817 """``divergent()``
817 """``divergent()``
818 Final successors of changesets with an alternative set of final successors.
818 Final successors of changesets with an alternative set of final successors.
819 """
819 """
820 # i18n: "divergent" is a keyword
820 # i18n: "divergent" is a keyword
821 getargs(x, 0, 0, _("divergent takes no arguments"))
821 getargs(x, 0, 0, _("divergent takes no arguments"))
822 divergent = obsmod.getrevs(repo, 'divergent')
822 divergent = obsmod.getrevs(repo, 'divergent')
823 return subset & divergent
823 return subset & divergent
824
824
825 def extinct(repo, subset, x):
825 def extinct(repo, subset, x):
826 """``extinct()``
826 """``extinct()``
827 Obsolete changesets with obsolete descendants only.
827 Obsolete changesets with obsolete descendants only.
828 """
828 """
829 # i18n: "extinct" is a keyword
829 # i18n: "extinct" is a keyword
830 getargs(x, 0, 0, _("extinct takes no arguments"))
830 getargs(x, 0, 0, _("extinct takes no arguments"))
831 extincts = obsmod.getrevs(repo, 'extinct')
831 extincts = obsmod.getrevs(repo, 'extinct')
832 return subset & extincts
832 return subset & extincts
833
833
834 def extra(repo, subset, x):
834 def extra(repo, subset, x):
835 """``extra(label, [value])``
835 """``extra(label, [value])``
836 Changesets with the given label in the extra metadata, with the given
836 Changesets with the given label in the extra metadata, with the given
837 optional value.
837 optional value.
838
838
839 If `value` starts with `re:`, the remainder of the value is treated as
839 If `value` starts with `re:`, the remainder of the value is treated as
840 a regular expression. To match a value that actually starts with `re:`,
840 a regular expression. To match a value that actually starts with `re:`,
841 use the prefix `literal:`.
841 use the prefix `literal:`.
842 """
842 """
843 args = getkwargs(x, 'extra', 'label value')
843 args = getkwargs(x, 'extra', 'label value')
844 if 'label' not in args:
844 if 'label' not in args:
845 # i18n: "extra" is a keyword
845 # i18n: "extra" is a keyword
846 raise error.ParseError(_('extra takes at least 1 argument'))
846 raise error.ParseError(_('extra takes at least 1 argument'))
847 # i18n: "extra" is a keyword
847 # i18n: "extra" is a keyword
848 label = getstring(args['label'], _('first argument to extra must be '
848 label = getstring(args['label'], _('first argument to extra must be '
849 'a string'))
849 'a string'))
850 value = None
850 value = None
851
851
852 if 'value' in args:
852 if 'value' in args:
853 # i18n: "extra" is a keyword
853 # i18n: "extra" is a keyword
854 value = getstring(args['value'], _('second argument to extra must be '
854 value = getstring(args['value'], _('second argument to extra must be '
855 'a string'))
855 'a string'))
856 kind, value, matcher = _stringmatcher(value)
856 kind, value, matcher = _stringmatcher(value)
857
857
858 def _matchvalue(r):
858 def _matchvalue(r):
859 extra = repo[r].extra()
859 extra = repo[r].extra()
860 return label in extra and (value is None or matcher(extra[label]))
860 return label in extra and (value is None or matcher(extra[label]))
861
861
862 return subset.filter(lambda r: _matchvalue(r))
862 return subset.filter(lambda r: _matchvalue(r))
863
863
864 def filelog(repo, subset, x):
864 def filelog(repo, subset, x):
865 """``filelog(pattern)``
865 """``filelog(pattern)``
866 Changesets connected to the specified filelog.
866 Changesets connected to the specified filelog.
867
867
868 For performance reasons, visits only revisions mentioned in the file-level
868 For performance reasons, visits only revisions mentioned in the file-level
869 filelog, rather than filtering through all changesets (much faster, but
869 filelog, rather than filtering through all changesets (much faster, but
870 doesn't include deletes or duplicate changes). For a slower, more accurate
870 doesn't include deletes or duplicate changes). For a slower, more accurate
871 result, use ``file()``.
871 result, use ``file()``.
872
872
873 The pattern without explicit kind like ``glob:`` is expected to be
873 The pattern without explicit kind like ``glob:`` is expected to be
874 relative to the current directory and match against a file exactly
874 relative to the current directory and match against a file exactly
875 for efficiency.
875 for efficiency.
876
876
877 If some linkrev points to revisions filtered by the current repoview, we'll
877 If some linkrev points to revisions filtered by the current repoview, we'll
878 work around it to return a non-filtered value.
878 work around it to return a non-filtered value.
879 """
879 """
880
880
881 # i18n: "filelog" is a keyword
881 # i18n: "filelog" is a keyword
882 pat = getstring(x, _("filelog requires a pattern"))
882 pat = getstring(x, _("filelog requires a pattern"))
883 s = set()
883 s = set()
884 cl = repo.changelog
884 cl = repo.changelog
885
885
886 if not matchmod.patkind(pat):
886 if not matchmod.patkind(pat):
887 f = pathutil.canonpath(repo.root, repo.getcwd(), pat)
887 f = pathutil.canonpath(repo.root, repo.getcwd(), pat)
888 files = [f]
888 files = [f]
889 else:
889 else:
890 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[None])
890 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[None])
891 files = (f for f in repo[None] if m(f))
891 files = (f for f in repo[None] if m(f))
892
892
893 for f in files:
893 for f in files:
894 backrevref = {} # final value for: filerev -> changerev
894 backrevref = {} # final value for: filerev -> changerev
895 lowestchild = {} # lowest known filerev child of a filerev
895 lowestchild = {} # lowest known filerev child of a filerev
896 delayed = [] # filerev with filtered linkrev, for post-processing
896 delayed = [] # filerev with filtered linkrev, for post-processing
897 lowesthead = None # cache for manifest content of all head revisions
897 lowesthead = None # cache for manifest content of all head revisions
898 fl = repo.file(f)
898 fl = repo.file(f)
899 for fr in list(fl):
899 for fr in list(fl):
900 rev = fl.linkrev(fr)
900 rev = fl.linkrev(fr)
901 if rev not in cl:
901 if rev not in cl:
902 # changerev pointed in linkrev is filtered
902 # changerev pointed in linkrev is filtered
903 # record it for post processing.
903 # record it for post processing.
904 delayed.append((fr, rev))
904 delayed.append((fr, rev))
905 continue
905 continue
906 for p in fl.parentrevs(fr):
906 for p in fl.parentrevs(fr):
907 if 0 <= p and p not in lowestchild:
907 if 0 <= p and p not in lowestchild:
908 lowestchild[p] = fr
908 lowestchild[p] = fr
909 backrevref[fr] = rev
909 backrevref[fr] = rev
910 s.add(rev)
910 s.add(rev)
911
911
912 # Post-processing of all filerevs we skipped because they were
912 # Post-processing of all filerevs we skipped because they were
913 # filtered. If such filerevs have known and unfiltered children, this
913 # filtered. If such filerevs have known and unfiltered children, this
914 # means they have an unfiltered appearance out there. We'll use linkrev
914 # means they have an unfiltered appearance out there. We'll use linkrev
915 # adjustment to find one of these appearances. The lowest known child
915 # adjustment to find one of these appearances. The lowest known child
916 # will be used as a starting point because it is the best upper-bound we
916 # will be used as a starting point because it is the best upper-bound we
917 # have.
917 # have.
918 #
918 #
919 # This approach will fail when an unfiltered but linkrev-shadowed
919 # This approach will fail when an unfiltered but linkrev-shadowed
920 # appearance exists in a head changeset without unfiltered filerev
920 # appearance exists in a head changeset without unfiltered filerev
921 # children anywhere.
921 # children anywhere.
922 while delayed:
922 while delayed:
923 # must be a descending iteration. To slowly fill lowest child
923 # must be a descending iteration. To slowly fill lowest child
924 # information that is of potential use by the next item.
924 # information that is of potential use by the next item.
925 fr, rev = delayed.pop()
925 fr, rev = delayed.pop()
926 lkr = rev
926 lkr = rev
927
927
928 child = lowestchild.get(fr)
928 child = lowestchild.get(fr)
929
929
930 if child is None:
930 if child is None:
931 # search for existence of this file revision in a head revision.
931 # search for existence of this file revision in a head revision.
932 # There are three possibilities:
932 # There are three possibilities:
933 # - the revision exists in a head and we can find an
933 # - the revision exists in a head and we can find an
934 # introduction from there,
934 # introduction from there,
935 # - the revision does not exist in a head because it has been
935 # - the revision does not exist in a head because it has been
936 # changed since its introduction: we would have found a child
936 # changed since its introduction: we would have found a child
937 # and be in the other 'else' clause,
937 # and be in the other 'else' clause,
938 # - all versions of the revision are hidden.
938 # - all versions of the revision are hidden.
939 if lowesthead is None:
939 if lowesthead is None:
940 lowesthead = {}
940 lowesthead = {}
941 for h in repo.heads():
941 for h in repo.heads():
942 fnode = repo[h].manifest().get(f)
942 fnode = repo[h].manifest().get(f)
943 if fnode is not None:
943 if fnode is not None:
944 lowesthead[fl.rev(fnode)] = h
944 lowesthead[fl.rev(fnode)] = h
945 headrev = lowesthead.get(fr)
945 headrev = lowesthead.get(fr)
946 if headrev is None:
946 if headrev is None:
947 # content is nowhere unfiltered
947 # content is nowhere unfiltered
948 continue
948 continue
949 rev = repo[headrev][f].introrev()
949 rev = repo[headrev][f].introrev()
950 else:
950 else:
951 # the lowest known child is a good upper bound
951 # the lowest known child is a good upper bound
952 childcrev = backrevref[child]
952 childcrev = backrevref[child]
953 # XXX this does not guarantee returning the lowest
953 # XXX this does not guarantee returning the lowest
954 # introduction of this revision, but this gives a
954 # introduction of this revision, but this gives a
955 # result which is a good start and will fit in most
955 # result which is a good start and will fit in most
956 # cases. We probably need to fix the multiple
956 # cases. We probably need to fix the multiple
957 # introductions case properly (report each
957 # introductions case properly (report each
958 # introduction, even for identical file revisions)
958 # introduction, even for identical file revisions)
959 # once and for all at some point anyway.
959 # once and for all at some point anyway.
960 for p in repo[childcrev][f].parents():
960 for p in repo[childcrev][f].parents():
961 if p.filerev() == fr:
961 if p.filerev() == fr:
962 rev = p.rev()
962 rev = p.rev()
963 break
963 break
964 if rev == lkr: # no shadowed entry found
964 if rev == lkr: # no shadowed entry found
965 # XXX This should never happen unless some manifest points
965 # XXX This should never happen unless some manifest points
966 # to biggish file revisions (like a revision that uses a
966 # to biggish file revisions (like a revision that uses a
967 # parent that never appears in the manifest ancestors)
967 # parent that never appears in the manifest ancestors)
968 continue
968 continue
969
969
970 # Fill the data for the next iteration.
970 # Fill the data for the next iteration.
971 for p in fl.parentrevs(fr):
971 for p in fl.parentrevs(fr):
972 if 0 <= p and p not in lowestchild:
972 if 0 <= p and p not in lowestchild:
973 lowestchild[p] = fr
973 lowestchild[p] = fr
974 backrevref[fr] = rev
974 backrevref[fr] = rev
975 s.add(rev)
975 s.add(rev)
976
976
977 return subset & s
977 return subset & s
978
978
979 def first(repo, subset, x):
979 def first(repo, subset, x):
980 """``first(set, [n])``
980 """``first(set, [n])``
981 An alias for limit().
981 An alias for limit().
982 """
982 """
983 return limit(repo, subset, x)
983 return limit(repo, subset, x)
984
984
985 def _follow(repo, subset, x, name, followfirst=False):
985 def _follow(repo, subset, x, name, followfirst=False):
986 l = getargs(x, 0, 1, _("%s takes no arguments or a filename") % name)
986 l = getargs(x, 0, 1, _("%s takes no arguments or a filename") % name)
987 c = repo['.']
987 c = repo['.']
988 if l:
988 if l:
989 x = getstring(l[0], _("%s expected a filename") % name)
989 x = getstring(l[0], _("%s expected a filename") % name)
990 if x in c:
990 if x in c:
991 cx = c[x]
991 cx = c[x]
992 s = set(ctx.rev() for ctx in cx.ancestors(followfirst=followfirst))
992 s = set(ctx.rev() for ctx in cx.ancestors(followfirst=followfirst))
993 # include the revision responsible for the most recent version
993 # include the revision responsible for the most recent version
994 s.add(cx.introrev())
994 s.add(cx.introrev())
995 else:
995 else:
996 return baseset()
996 return baseset()
997 else:
997 else:
998 s = _revancestors(repo, baseset([c.rev()]), followfirst)
998 s = _revancestors(repo, baseset([c.rev()]), followfirst)
999
999
1000 return subset & s
1000 return subset & s
1001
1001
1002 def follow(repo, subset, x):
1002 def follow(repo, subset, x):
1003 """``follow([file])``
1003 """``follow([file])``
1004 An alias for ``::.`` (ancestors of the working directory's first parent).
1004 An alias for ``::.`` (ancestors of the working directory's first parent).
1005 If a filename is specified, the history of the given file is followed,
1005 If a filename is specified, the history of the given file is followed,
1006 including copies.
1006 including copies.
1007 """
1007 """
1008 return _follow(repo, subset, x, 'follow')
1008 return _follow(repo, subset, x, 'follow')
1009
1009
1010 def _followfirst(repo, subset, x):
1010 def _followfirst(repo, subset, x):
1011 # ``followfirst([file])``
1011 # ``followfirst([file])``
1012 # Like ``follow([file])`` but follows only the first parent of
1012 # Like ``follow([file])`` but follows only the first parent of
1013 # every revision or file revision.
1013 # every revision or file revision.
1014 return _follow(repo, subset, x, '_followfirst', followfirst=True)
1014 return _follow(repo, subset, x, '_followfirst', followfirst=True)
1015
1015
1016 def getall(repo, subset, x):
1016 def getall(repo, subset, x):
1017 """``all()``
1017 """``all()``
1018 All changesets, the same as ``0:tip``.
1018 All changesets, the same as ``0:tip``.
1019 """
1019 """
1020 # i18n: "all" is a keyword
1020 # i18n: "all" is a keyword
1021 getargs(x, 0, 0, _("all takes no arguments"))
1021 getargs(x, 0, 0, _("all takes no arguments"))
1022 return subset & spanset(repo) # drop "null" if any
1022 return subset & spanset(repo) # drop "null" if any
1023
1023
1024 def grep(repo, subset, x):
1024 def grep(repo, subset, x):
1025 """``grep(regex)``
1025 """``grep(regex)``
1026 Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
1026 Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
1027 to ensure special escape characters are handled correctly. Unlike
1027 to ensure special escape characters are handled correctly. Unlike
1028 ``keyword(string)``, the match is case-sensitive.
1028 ``keyword(string)``, the match is case-sensitive.
1029 """
1029 """
1030 try:
1030 try:
1031 # i18n: "grep" is a keyword
1031 # i18n: "grep" is a keyword
1032 gr = re.compile(getstring(x, _("grep requires a string")))
1032 gr = re.compile(getstring(x, _("grep requires a string")))
1033 except re.error as e:
1033 except re.error as e:
1034 raise error.ParseError(_('invalid match pattern: %s') % e)
1034 raise error.ParseError(_('invalid match pattern: %s') % e)
1035
1035
1036 def matches(x):
1036 def matches(x):
1037 c = repo[x]
1037 c = repo[x]
1038 for e in c.files() + [c.user(), c.description()]:
1038 for e in c.files() + [c.user(), c.description()]:
1039 if gr.search(e):
1039 if gr.search(e):
1040 return True
1040 return True
1041 return False
1041 return False
1042
1042
1043 return subset.filter(matches)
1043 return subset.filter(matches)
1044
1044
1045 def _matchfiles(repo, subset, x):
1045 def _matchfiles(repo, subset, x):
1046 # _matchfiles takes a revset list of prefixed arguments:
1046 # _matchfiles takes a revset list of prefixed arguments:
1047 #
1047 #
1048 # [p:foo, i:bar, x:baz]
1048 # [p:foo, i:bar, x:baz]
1049 #
1049 #
1050 # builds a match object from them and filters subset. Allowed
1050 # builds a match object from them and filters subset. Allowed
1051 # prefixes are 'p:' for regular patterns, 'i:' for include
1051 # prefixes are 'p:' for regular patterns, 'i:' for include
1052 # patterns and 'x:' for exclude patterns. Use 'r:' prefix to pass
1052 # patterns and 'x:' for exclude patterns. Use 'r:' prefix to pass
1053 # a revision identifier, or the empty string to reference the
1053 # a revision identifier, or the empty string to reference the
1054 # working directory, from which the match object is
1054 # working directory, from which the match object is
1055 # initialized. Use 'd:' to set the default matching mode, default
1055 # initialized. Use 'd:' to set the default matching mode, default
1056 # to 'glob'. At most one 'r:' and 'd:' argument can be passed.
1056 # to 'glob'. At most one 'r:' and 'd:' argument can be passed.
1057
1057
1058 # i18n: "_matchfiles" is a keyword
1058 # i18n: "_matchfiles" is a keyword
1059 l = getargs(x, 1, -1, _("_matchfiles requires at least one argument"))
1059 l = getargs(x, 1, -1, _("_matchfiles requires at least one argument"))
1060 pats, inc, exc = [], [], []
1060 pats, inc, exc = [], [], []
1061 rev, default = None, None
1061 rev, default = None, None
1062 for arg in l:
1062 for arg in l:
1063 # i18n: "_matchfiles" is a keyword
1063 # i18n: "_matchfiles" is a keyword
1064 s = getstring(arg, _("_matchfiles requires string arguments"))
1064 s = getstring(arg, _("_matchfiles requires string arguments"))
1065 prefix, value = s[:2], s[2:]
1065 prefix, value = s[:2], s[2:]
1066 if prefix == 'p:':
1066 if prefix == 'p:':
1067 pats.append(value)
1067 pats.append(value)
1068 elif prefix == 'i:':
1068 elif prefix == 'i:':
1069 inc.append(value)
1069 inc.append(value)
1070 elif prefix == 'x:':
1070 elif prefix == 'x:':
1071 exc.append(value)
1071 exc.append(value)
1072 elif prefix == 'r:':
1072 elif prefix == 'r:':
1073 if rev is not None:
1073 if rev is not None:
1074 # i18n: "_matchfiles" is a keyword
1074 # i18n: "_matchfiles" is a keyword
1075 raise error.ParseError(_('_matchfiles expected at most one '
1075 raise error.ParseError(_('_matchfiles expected at most one '
1076 'revision'))
1076 'revision'))
1077 if value != '': # empty means working directory; leave rev as None
1077 if value != '': # empty means working directory; leave rev as None
1078 rev = value
1078 rev = value
1079 elif prefix == 'd:':
1079 elif prefix == 'd:':
1080 if default is not None:
1080 if default is not None:
1081 # i18n: "_matchfiles" is a keyword
1081 # i18n: "_matchfiles" is a keyword
1082 raise error.ParseError(_('_matchfiles expected at most one '
1082 raise error.ParseError(_('_matchfiles expected at most one '
1083 'default mode'))
1083 'default mode'))
1084 default = value
1084 default = value
1085 else:
1085 else:
1086 # i18n: "_matchfiles" is a keyword
1086 # i18n: "_matchfiles" is a keyword
1087 raise error.ParseError(_('invalid _matchfiles prefix: %s') % prefix)
1087 raise error.ParseError(_('invalid _matchfiles prefix: %s') % prefix)
1088 if not default:
1088 if not default:
1089 default = 'glob'
1089 default = 'glob'
1090
1090
1091 m = matchmod.match(repo.root, repo.getcwd(), pats, include=inc,
1091 m = matchmod.match(repo.root, repo.getcwd(), pats, include=inc,
1092 exclude=exc, ctx=repo[rev], default=default)
1092 exclude=exc, ctx=repo[rev], default=default)
1093
1093
1094 def matches(x):
1094 def matches(x):
1095 for f in repo[x].files():
1095 for f in repo[x].files():
1096 if m(f):
1096 if m(f):
1097 return True
1097 return True
1098 return False
1098 return False
1099
1099
1100 return subset.filter(matches)
1100 return subset.filter(matches)
1101
1101
1102 def hasfile(repo, subset, x):
1102 def hasfile(repo, subset, x):
1103 """``file(pattern)``
1103 """``file(pattern)``
1104 Changesets affecting files matched by pattern.
1104 Changesets affecting files matched by pattern.
1105
1105
1106 For a faster but less accurate result, consider using ``filelog()``
1106 For a faster but less accurate result, consider using ``filelog()``
1107 instead.
1107 instead.
1108
1108
1109 This predicate uses ``glob:`` as the default kind of pattern.
1109 This predicate uses ``glob:`` as the default kind of pattern.
1110 """
1110 """
1111 # i18n: "file" is a keyword
1111 # i18n: "file" is a keyword
1112 pat = getstring(x, _("file requires a pattern"))
1112 pat = getstring(x, _("file requires a pattern"))
1113 return _matchfiles(repo, subset, ('string', 'p:' + pat))
1113 return _matchfiles(repo, subset, ('string', 'p:' + pat))
1114
1114
1115 def head(repo, subset, x):
1115 def head(repo, subset, x):
1116 """``head()``
1116 """``head()``
1117 Changeset is a named branch head.
1117 Changeset is a named branch head.
1118 """
1118 """
1119 # i18n: "head" is a keyword
1119 # i18n: "head" is a keyword
1120 getargs(x, 0, 0, _("head takes no arguments"))
1120 getargs(x, 0, 0, _("head takes no arguments"))
1121 hs = set()
1121 hs = set()
1122 cl = repo.changelog
1122 cl = repo.changelog
1123 for b, ls in repo.branchmap().iteritems():
1123 for b, ls in repo.branchmap().iteritems():
1124 hs.update(cl.rev(h) for h in ls)
1124 hs.update(cl.rev(h) for h in ls)
1125 # XXX using a set to feed the baseset is wrong. Sets are not ordered.
1125 # XXX using a set to feed the baseset is wrong. Sets are not ordered.
1126 # This does not break because of other fullreposet misbehavior.
1126 # This does not break because of other fullreposet misbehavior.
1127 # XXX We should combine with subset first: 'subset & baseset(...)'. This is
1127 # XXX We should combine with subset first: 'subset & baseset(...)'. This is
1128 # necessary to ensure we preserve the order in subset.
1128 # necessary to ensure we preserve the order in subset.
1129 return baseset(hs) & subset
1129 return baseset(hs) & subset
1130
1130
1131 def heads(repo, subset, x):
1131 def heads(repo, subset, x):
1132 """``heads(set)``
1132 """``heads(set)``
1133 Members of set with no children in set.
1133 Members of set with no children in set.
1134 """
1134 """
1135 s = getset(repo, subset, x)
1135 s = getset(repo, subset, x)
1136 ps = parents(repo, subset, x)
1136 ps = parents(repo, subset, x)
1137 return s - ps
1137 return s - ps
1138
1138
1139 def hidden(repo, subset, x):
1139 def hidden(repo, subset, x):
1140 """``hidden()``
1140 """``hidden()``
1141 Hidden changesets.
1141 Hidden changesets.
1142 """
1142 """
1143 # i18n: "hidden" is a keyword
1143 # i18n: "hidden" is a keyword
1144 getargs(x, 0, 0, _("hidden takes no arguments"))
1144 getargs(x, 0, 0, _("hidden takes no arguments"))
1145 hiddenrevs = repoview.filterrevs(repo, 'visible')
1145 hiddenrevs = repoview.filterrevs(repo, 'visible')
1146 return subset & hiddenrevs
1146 return subset & hiddenrevs
1147
1147
1148 def keyword(repo, subset, x):
1148 def keyword(repo, subset, x):
1149 """``keyword(string)``
1149 """``keyword(string)``
1150 Search commit message, user name, and names of changed files for
1150 Search commit message, user name, and names of changed files for
1151 string. The match is case-insensitive.
1151 string. The match is case-insensitive.
1152 """
1152 """
1153 # i18n: "keyword" is a keyword
1153 # i18n: "keyword" is a keyword
1154 kw = encoding.lower(getstring(x, _("keyword requires a string")))
1154 kw = encoding.lower(getstring(x, _("keyword requires a string")))
1155
1155
1156 def matches(r):
1156 def matches(r):
1157 c = repo[r]
1157 c = repo[r]
1158 return any(kw in encoding.lower(t)
1158 return any(kw in encoding.lower(t)
1159 for t in c.files() + [c.user(), c.description()])
1159 for t in c.files() + [c.user(), c.description()])
1160
1160
1161 return subset.filter(matches)
1161 return subset.filter(matches)
1162
1162
1163 def limit(repo, subset, x):
1163 def limit(repo, subset, x):
1164 """``limit(set, [n])``
1164 """``limit(set, [n])``
1165 First n members of set, defaulting to 1.
1165 First n members of set, defaulting to 1.
1166 """
1166 """
1167 # i18n: "limit" is a keyword
1167 # i18n: "limit" is a keyword
1168 l = getargs(x, 1, 2, _("limit requires one or two arguments"))
1168 l = getargs(x, 1, 2, _("limit requires one or two arguments"))
1169 try:
1169 try:
1170 lim = 1
1170 lim = 1
1171 if len(l) == 2:
1171 if len(l) == 2:
1172 # i18n: "limit" is a keyword
1172 # i18n: "limit" is a keyword
1173 lim = int(getstring(l[1], _("limit requires a number")))
1173 lim = int(getstring(l[1], _("limit requires a number")))
1174 except (TypeError, ValueError):
1174 except (TypeError, ValueError):
1175 # i18n: "limit" is a keyword
1175 # i18n: "limit" is a keyword
1176 raise error.ParseError(_("limit expects a number"))
1176 raise error.ParseError(_("limit expects a number"))
1177 ss = subset
1177 ss = subset
1178 os = getset(repo, fullreposet(repo), l[0])
1178 os = getset(repo, fullreposet(repo), l[0])
1179 result = []
1179 result = []
1180 it = iter(os)
1180 it = iter(os)
1181 for x in xrange(lim):
1181 for x in xrange(lim):
1182 y = next(it, None)
1182 y = next(it, None)
1183 if y is None:
1183 if y is None:
1184 break
1184 break
1185 elif y in ss:
1185 elif y in ss:
1186 result.append(y)
1186 result.append(y)
1187 return baseset(result)
1187 return baseset(result)
1188
1188
1189 def last(repo, subset, x):
1189 def last(repo, subset, x):
1190 """``last(set, [n])``
1190 """``last(set, [n])``
1191 Last n members of set, defaulting to 1.
1191 Last n members of set, defaulting to 1.
1192 """
1192 """
1193 # i18n: "last" is a keyword
1193 # i18n: "last" is a keyword
1194 l = getargs(x, 1, 2, _("last requires one or two arguments"))
1194 l = getargs(x, 1, 2, _("last requires one or two arguments"))
1195 try:
1195 try:
1196 lim = 1
1196 lim = 1
1197 if len(l) == 2:
1197 if len(l) == 2:
1198 # i18n: "last" is a keyword
1198 # i18n: "last" is a keyword
1199 lim = int(getstring(l[1], _("last requires a number")))
1199 lim = int(getstring(l[1], _("last requires a number")))
1200 except (TypeError, ValueError):
1200 except (TypeError, ValueError):
1201 # i18n: "last" is a keyword
1201 # i18n: "last" is a keyword
1202 raise error.ParseError(_("last expects a number"))
1202 raise error.ParseError(_("last expects a number"))
1203 ss = subset
1203 ss = subset
1204 os = getset(repo, fullreposet(repo), l[0])
1204 os = getset(repo, fullreposet(repo), l[0])
1205 os.reverse()
1205 os.reverse()
1206 result = []
1206 result = []
1207 it = iter(os)
1207 it = iter(os)
1208 for x in xrange(lim):
1208 for x in xrange(lim):
1209 y = next(it, None)
1209 y = next(it, None)
1210 if y is None:
1210 if y is None:
1211 break
1211 break
1212 elif y in ss:
1212 elif y in ss:
1213 result.append(y)
1213 result.append(y)
1214 return baseset(result)
1214 return baseset(result)
1215
1215
1216 def maxrev(repo, subset, x):
1216 def maxrev(repo, subset, x):
1217 """``max(set)``
1217 """``max(set)``
1218 Changeset with highest revision number in set.
1218 Changeset with highest revision number in set.
1219 """
1219 """
1220 os = getset(repo, fullreposet(repo), x)
1220 os = getset(repo, fullreposet(repo), x)
1221 if os:
1221 if os:
1222 m = os.max()
1222 m = os.max()
1223 if m in subset:
1223 if m in subset:
1224 return baseset([m])
1224 return baseset([m])
1225 return baseset()
1225 return baseset()
1226
1226
1227 def merge(repo, subset, x):
1227 def merge(repo, subset, x):
1228 """``merge()``
1228 """``merge()``
1229 Changeset is a merge changeset.
1229 Changeset is a merge changeset.
1230 """
1230 """
1231 # i18n: "merge" is a keyword
1231 # i18n: "merge" is a keyword
1232 getargs(x, 0, 0, _("merge takes no arguments"))
1232 getargs(x, 0, 0, _("merge takes no arguments"))
1233 cl = repo.changelog
1233 cl = repo.changelog
1234 return subset.filter(lambda r: cl.parentrevs(r)[1] != -1)
1234 return subset.filter(lambda r: cl.parentrevs(r)[1] != -1)
1235
1235
1236 def branchpoint(repo, subset, x):
1236 def branchpoint(repo, subset, x):
1237 """``branchpoint()``
1237 """``branchpoint()``
1238 Changesets with more than one child.
1238 Changesets with more than one child.
1239 """
1239 """
1240 # i18n: "branchpoint" is a keyword
1240 # i18n: "branchpoint" is a keyword
1241 getargs(x, 0, 0, _("branchpoint takes no arguments"))
1241 getargs(x, 0, 0, _("branchpoint takes no arguments"))
1242 cl = repo.changelog
1242 cl = repo.changelog
1243 if not subset:
1243 if not subset:
1244 return baseset()
1244 return baseset()
1245 # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
1245 # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
1246 # (and if it is not, it should.)
1246 # (and if it is not, it should.)
1247 baserev = min(subset)
1247 baserev = min(subset)
1248 parentscount = [0]*(len(repo) - baserev)
1248 parentscount = [0]*(len(repo) - baserev)
1249 for r in cl.revs(start=baserev + 1):
1249 for r in cl.revs(start=baserev + 1):
1250 for p in cl.parentrevs(r):
1250 for p in cl.parentrevs(r):
1251 if p >= baserev:
1251 if p >= baserev:
1252 parentscount[p - baserev] += 1
1252 parentscount[p - baserev] += 1
1253 return subset.filter(lambda r: parentscount[r - baserev] > 1)
1253 return subset.filter(lambda r: parentscount[r - baserev] > 1)
1254
1254
1255 def minrev(repo, subset, x):
1255 def minrev(repo, subset, x):
1256 """``min(set)``
1256 """``min(set)``
1257 Changeset with lowest revision number in set.
1257 Changeset with lowest revision number in set.
1258 """
1258 """
1259 os = getset(repo, fullreposet(repo), x)
1259 os = getset(repo, fullreposet(repo), x)
1260 if os:
1260 if os:
1261 m = os.min()
1261 m = os.min()
1262 if m in subset:
1262 if m in subset:
1263 return baseset([m])
1263 return baseset([m])
1264 return baseset()
1264 return baseset()
1265
1265
1266 def modifies(repo, subset, x):
1266 def modifies(repo, subset, x):
1267 """``modifies(pattern)``
1267 """``modifies(pattern)``
1268 Changesets modifying files matched by pattern.
1268 Changesets modifying files matched by pattern.
1269
1269
1270 The pattern without explicit kind like ``glob:`` is expected to be
1270 The pattern without explicit kind like ``glob:`` is expected to be
1271 relative to the current directory and match against a file or a
1271 relative to the current directory and match against a file or a
1272 directory.
1272 directory.
1273 """
1273 """
1274 # i18n: "modifies" is a keyword
1274 # i18n: "modifies" is a keyword
1275 pat = getstring(x, _("modifies requires a pattern"))
1275 pat = getstring(x, _("modifies requires a pattern"))
1276 return checkstatus(repo, subset, pat, 0)
1276 return checkstatus(repo, subset, pat, 0)
1277
1277
1278 def named(repo, subset, x):
1278 def named(repo, subset, x):
1279 """``named(namespace)``
1279 """``named(namespace)``
1280 The changesets in a given namespace.
1280 The changesets in a given namespace.
1281
1281
1282 If `namespace` starts with `re:`, the remainder of the string is treated as
1282 If `namespace` starts with `re:`, the remainder of the string is treated as
1283 a regular expression. To match a namespace that actually starts with `re:`,
1283 a regular expression. To match a namespace that actually starts with `re:`,
1284 use the prefix `literal:`.
1284 use the prefix `literal:`.
1285 """
1285 """
1286 # i18n: "named" is a keyword
1286 # i18n: "named" is a keyword
1287 args = getargs(x, 1, 1, _('named requires a namespace argument'))
1287 args = getargs(x, 1, 1, _('named requires a namespace argument'))
1288
1288
1289 ns = getstring(args[0],
1289 ns = getstring(args[0],
1290 # i18n: "named" is a keyword
1290 # i18n: "named" is a keyword
1291 _('the argument to named must be a string'))
1291 _('the argument to named must be a string'))
1292 kind, pattern, matcher = _stringmatcher(ns)
1292 kind, pattern, matcher = _stringmatcher(ns)
1293 namespaces = set()
1293 namespaces = set()
1294 if kind == 'literal':
1294 if kind == 'literal':
1295 if pattern not in repo.names:
1295 if pattern not in repo.names:
1296 raise error.RepoLookupError(_("namespace '%s' does not exist")
1296 raise error.RepoLookupError(_("namespace '%s' does not exist")
1297 % ns)
1297 % ns)
1298 namespaces.add(repo.names[pattern])
1298 namespaces.add(repo.names[pattern])
1299 else:
1299 else:
1300 for name, ns in repo.names.iteritems():
1300 for name, ns in repo.names.iteritems():
1301 if matcher(name):
1301 if matcher(name):
1302 namespaces.add(ns)
1302 namespaces.add(ns)
1303 if not namespaces:
1303 if not namespaces:
1304 raise error.RepoLookupError(_("no namespace exists"
1304 raise error.RepoLookupError(_("no namespace exists"
1305 " that match '%s'") % pattern)
1305 " that match '%s'") % pattern)
1306
1306
1307 names = set()
1307 names = set()
1308 for ns in namespaces:
1308 for ns in namespaces:
1309 for name in ns.listnames(repo):
1309 for name in ns.listnames(repo):
1310 if name not in ns.deprecated:
1310 if name not in ns.deprecated:
1311 names.update(repo[n].rev() for n in ns.nodes(repo, name))
1311 names.update(repo[n].rev() for n in ns.nodes(repo, name))
1312
1312
1313 names -= set([node.nullrev])
1313 names -= set([node.nullrev])
1314 return subset & names
1314 return subset & names
1315
1315
1316 def node_(repo, subset, x):
1316 def node_(repo, subset, x):
1317 """``id(string)``
1317 """``id(string)``
1318 Revision non-ambiguously specified by the given hex string prefix.
1318 Revision non-ambiguously specified by the given hex string prefix.
1319 """
1319 """
1320 # i18n: "id" is a keyword
1320 # i18n: "id" is a keyword
1321 l = getargs(x, 1, 1, _("id requires one argument"))
1321 l = getargs(x, 1, 1, _("id requires one argument"))
1322 # i18n: "id" is a keyword
1322 # i18n: "id" is a keyword
1323 n = getstring(l[0], _("id requires a string"))
1323 n = getstring(l[0], _("id requires a string"))
1324 if len(n) == 40:
1324 if len(n) == 40:
1325 try:
1325 try:
1326 rn = repo.changelog.rev(node.bin(n))
1326 rn = repo.changelog.rev(node.bin(n))
1327 except (LookupError, TypeError):
1327 except (LookupError, TypeError):
1328 rn = None
1328 rn = None
1329 else:
1329 else:
1330 rn = None
1330 rn = None
1331 pm = repo.changelog._partialmatch(n)
1331 pm = repo.changelog._partialmatch(n)
1332 if pm is not None:
1332 if pm is not None:
1333 rn = repo.changelog.rev(pm)
1333 rn = repo.changelog.rev(pm)
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 def obsolete(repo, subset, x):
1340 def obsolete(repo, subset, x):
1341 """``obsolete()``
1341 """``obsolete()``
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 def only(repo, subset, x):
1348 def only(repo, subset, x):
1349 """``only(set, [set])``
1349 """``only(set, [set])``
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(_revdescendants(repo, include, False))
1363 descendants = set(_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 optimisations from the fact this is a baseset.
1371 # some optimisations from the fact this is a baseset.
1372 return subset & results
1372 return subset & results
1373
1373
1374 def origin(repo, subset, x):
1374 def origin(repo, subset, x):
1375 """``origin([set])``
1375 """``origin([set])``
1376 Changesets that were specified as a source for the grafts, transplants or
1376 Changesets that were specified as a source for the grafts, transplants or
1377 rebases that created the given revisions. Omitting the optional set is the
1377 rebases that created the given revisions. Omitting the optional set is the
1378 same as passing all(). If a changeset created by these operations is itself
1378 same as passing all(). If a changeset created by these operations is itself
1379 specified as a source for one of these operations, only the source changeset
1379 specified as a source for one of these operations, only the source changeset
1380 for the first operation is selected.
1380 for the first operation is selected.
1381 """
1381 """
1382 if x is not None:
1382 if x is not None:
1383 dests = getset(repo, fullreposet(repo), x)
1383 dests = getset(repo, fullreposet(repo), x)
1384 else:
1384 else:
1385 dests = fullreposet(repo)
1385 dests = fullreposet(repo)
1386
1386
1387 def _firstsrc(rev):
1387 def _firstsrc(rev):
1388 src = _getrevsource(repo, rev)
1388 src = _getrevsource(repo, rev)
1389 if src is None:
1389 if src is None:
1390 return None
1390 return None
1391
1391
1392 while True:
1392 while True:
1393 prev = _getrevsource(repo, src)
1393 prev = _getrevsource(repo, src)
1394
1394
1395 if prev is None:
1395 if prev is None:
1396 return src
1396 return src
1397 src = prev
1397 src = prev
1398
1398
1399 o = set([_firstsrc(r) for r in dests])
1399 o = set([_firstsrc(r) for r in dests])
1400 o -= set([None])
1400 o -= set([None])
1401 # XXX we should turn this into a baseset instead of a set, smartset may do
1401 # XXX we should turn this into a baseset instead of a set, smartset may do
1402 # some optimisations from the fact this is a baseset.
1402 # some optimisations from the fact this is a baseset.
1403 return subset & o
1403 return subset & o
1404
1404
1405 def outgoing(repo, subset, x):
1405 def outgoing(repo, subset, x):
1406 """``outgoing([path])``
1406 """``outgoing([path])``
1407 Changesets not found in the specified destination repository, or the
1407 Changesets not found in the specified destination repository, or the
1408 default push location.
1408 default push location.
1409 """
1409 """
1410 # Avoid cycles.
1410 # Avoid cycles.
1411 import discovery
1411 import discovery
1412 import hg
1412 import hg
1413 # i18n: "outgoing" is a keyword
1413 # i18n: "outgoing" is a keyword
1414 l = getargs(x, 0, 1, _("outgoing takes one or no arguments"))
1414 l = getargs(x, 0, 1, _("outgoing takes one or no arguments"))
1415 # i18n: "outgoing" is a keyword
1415 # i18n: "outgoing" is a keyword
1416 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
1416 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
1417 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
1417 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
1418 dest, branches = hg.parseurl(dest)
1418 dest, branches = hg.parseurl(dest)
1419 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1419 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1420 if revs:
1420 if revs:
1421 revs = [repo.lookup(rev) for rev in revs]
1421 revs = [repo.lookup(rev) for rev in revs]
1422 other = hg.peer(repo, {}, dest)
1422 other = hg.peer(repo, {}, dest)
1423 repo.ui.pushbuffer()
1423 repo.ui.pushbuffer()
1424 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
1424 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
1425 repo.ui.popbuffer()
1425 repo.ui.popbuffer()
1426 cl = repo.changelog
1426 cl = repo.changelog
1427 o = set([cl.rev(r) for r in outgoing.missing])
1427 o = set([cl.rev(r) for r in outgoing.missing])
1428 return subset & o
1428 return subset & o
1429
1429
1430 def p1(repo, subset, x):
1430 def p1(repo, subset, x):
1431 """``p1([set])``
1431 """``p1([set])``
1432 First parent of changesets in set, or the working directory.
1432 First parent of changesets in set, or the working directory.
1433 """
1433 """
1434 if x is None:
1434 if x is None:
1435 p = repo[x].p1().rev()
1435 p = repo[x].p1().rev()
1436 if p >= 0:
1436 if p >= 0:
1437 return subset & baseset([p])
1437 return subset & baseset([p])
1438 return baseset()
1438 return baseset()
1439
1439
1440 ps = set()
1440 ps = set()
1441 cl = repo.changelog
1441 cl = repo.changelog
1442 for r in getset(repo, fullreposet(repo), x):
1442 for r in getset(repo, fullreposet(repo), x):
1443 ps.add(cl.parentrevs(r)[0])
1443 ps.add(cl.parentrevs(r)[0])
1444 ps -= set([node.nullrev])
1444 ps -= set([node.nullrev])
1445 # XXX we should turn this into a baseset instead of a set, smartset may do
1445 # XXX we should turn this into a baseset instead of a set, smartset may do
1446 # some optimisations from the fact this is a baseset.
1446 # some optimisations from the fact this is a baseset.
1447 return subset & ps
1447 return subset & ps
1448
1448
1449 def p2(repo, subset, x):
1449 def p2(repo, subset, x):
1450 """``p2([set])``
1450 """``p2([set])``
1451 Second parent of changesets in set, or the working directory.
1451 Second parent of changesets in set, or the working directory.
1452 """
1452 """
1453 if x is None:
1453 if x is None:
1454 ps = repo[x].parents()
1454 ps = repo[x].parents()
1455 try:
1455 try:
1456 p = ps[1].rev()
1456 p = ps[1].rev()
1457 if p >= 0:
1457 if p >= 0:
1458 return subset & baseset([p])
1458 return subset & baseset([p])
1459 return baseset()
1459 return baseset()
1460 except IndexError:
1460 except IndexError:
1461 return baseset()
1461 return baseset()
1462
1462
1463 ps = set()
1463 ps = set()
1464 cl = repo.changelog
1464 cl = repo.changelog
1465 for r in getset(repo, fullreposet(repo), x):
1465 for r in getset(repo, fullreposet(repo), x):
1466 ps.add(cl.parentrevs(r)[1])
1466 ps.add(cl.parentrevs(r)[1])
1467 ps -= set([node.nullrev])
1467 ps -= set([node.nullrev])
1468 # XXX we should turn this into a baseset instead of a set, smartset may do
1468 # XXX we should turn this into a baseset instead of a set, smartset may do
1469 # some optimisations from the fact this is a baseset.
1469 # some optimisations from the fact this is a baseset.
1470 return subset & ps
1470 return subset & ps
1471
1471
1472 def parents(repo, subset, x):
1472 def parents(repo, subset, x):
1473 """``parents([set])``
1473 """``parents([set])``
1474 The set of all parents for all changesets in set, or the working directory.
1474 The set of all parents for all changesets in set, or the working directory.
1475 """
1475 """
1476 if x is None:
1476 if x is None:
1477 ps = set(p.rev() for p in repo[x].parents())
1477 ps = set(p.rev() for p in repo[x].parents())
1478 else:
1478 else:
1479 ps = set()
1479 ps = set()
1480 cl = repo.changelog
1480 cl = repo.changelog
1481 up = ps.update
1481 up = ps.update
1482 parentrevs = cl.parentrevs
1482 parentrevs = cl.parentrevs
1483 for r in getset(repo, fullreposet(repo), x):
1483 for r in getset(repo, fullreposet(repo), x):
1484 if r is None:
1484 if r == node.wdirrev:
1485 up(p.rev() for p in repo[r].parents())
1485 up(p.rev() for p in repo[r].parents())
1486 else:
1486 else:
1487 up(parentrevs(r))
1487 up(parentrevs(r))
1488 ps -= set([node.nullrev])
1488 ps -= set([node.nullrev])
1489 return subset & ps
1489 return subset & ps
1490
1490
1491 def _phase(repo, subset, target):
1491 def _phase(repo, subset, target):
1492 """helper to select all rev in phase <target>"""
1492 """helper to select all rev in phase <target>"""
1493 repo._phasecache.loadphaserevs(repo) # ensure phase's sets are loaded
1493 repo._phasecache.loadphaserevs(repo) # ensure phase's sets are loaded
1494 if repo._phasecache._phasesets:
1494 if repo._phasecache._phasesets:
1495 s = repo._phasecache._phasesets[target] - repo.changelog.filteredrevs
1495 s = repo._phasecache._phasesets[target] - repo.changelog.filteredrevs
1496 s = baseset(s)
1496 s = baseset(s)
1497 s.sort() # set are non ordered, so we enforce ascending
1497 s.sort() # set are non ordered, so we enforce ascending
1498 return subset & s
1498 return subset & s
1499 else:
1499 else:
1500 phase = repo._phasecache.phase
1500 phase = repo._phasecache.phase
1501 condition = lambda r: phase(repo, r) == target
1501 condition = lambda r: phase(repo, r) == target
1502 return subset.filter(condition, cache=False)
1502 return subset.filter(condition, cache=False)
1503
1503
1504 def draft(repo, subset, x):
1504 def draft(repo, subset, x):
1505 """``draft()``
1505 """``draft()``
1506 Changeset in draft phase."""
1506 Changeset in draft phase."""
1507 # i18n: "draft" is a keyword
1507 # i18n: "draft" is a keyword
1508 getargs(x, 0, 0, _("draft takes no arguments"))
1508 getargs(x, 0, 0, _("draft takes no arguments"))
1509 target = phases.draft
1509 target = phases.draft
1510 return _phase(repo, subset, target)
1510 return _phase(repo, subset, target)
1511
1511
1512 def secret(repo, subset, x):
1512 def secret(repo, subset, x):
1513 """``secret()``
1513 """``secret()``
1514 Changeset in secret phase."""
1514 Changeset in secret phase."""
1515 # i18n: "secret" is a keyword
1515 # i18n: "secret" is a keyword
1516 getargs(x, 0, 0, _("secret takes no arguments"))
1516 getargs(x, 0, 0, _("secret takes no arguments"))
1517 target = phases.secret
1517 target = phases.secret
1518 return _phase(repo, subset, target)
1518 return _phase(repo, subset, target)
1519
1519
1520 def parentspec(repo, subset, x, n):
1520 def parentspec(repo, subset, x, n):
1521 """``set^0``
1521 """``set^0``
1522 The set.
1522 The set.
1523 ``set^1`` (or ``set^``), ``set^2``
1523 ``set^1`` (or ``set^``), ``set^2``
1524 First or second parent, respectively, of all changesets in set.
1524 First or second parent, respectively, of all changesets in set.
1525 """
1525 """
1526 try:
1526 try:
1527 n = int(n[1])
1527 n = int(n[1])
1528 if n not in (0, 1, 2):
1528 if n not in (0, 1, 2):
1529 raise ValueError
1529 raise ValueError
1530 except (TypeError, ValueError):
1530 except (TypeError, ValueError):
1531 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
1531 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
1532 ps = set()
1532 ps = set()
1533 cl = repo.changelog
1533 cl = repo.changelog
1534 for r in getset(repo, fullreposet(repo), x):
1534 for r in getset(repo, fullreposet(repo), x):
1535 if n == 0:
1535 if n == 0:
1536 ps.add(r)
1536 ps.add(r)
1537 elif n == 1:
1537 elif n == 1:
1538 ps.add(cl.parentrevs(r)[0])
1538 ps.add(cl.parentrevs(r)[0])
1539 elif n == 2:
1539 elif n == 2:
1540 parents = cl.parentrevs(r)
1540 parents = cl.parentrevs(r)
1541 if len(parents) > 1:
1541 if len(parents) > 1:
1542 ps.add(parents[1])
1542 ps.add(parents[1])
1543 return subset & ps
1543 return subset & ps
1544
1544
1545 def present(repo, subset, x):
1545 def present(repo, subset, x):
1546 """``present(set)``
1546 """``present(set)``
1547 An empty set, if any revision in set isn't found; otherwise,
1547 An empty set, if any revision in set isn't found; otherwise,
1548 all revisions in set.
1548 all revisions in set.
1549
1549
1550 If any of specified revisions is not present in the local repository,
1550 If any of specified revisions is not present in the local repository,
1551 the query is normally aborted. But this predicate allows the query
1551 the query is normally aborted. But this predicate allows the query
1552 to continue even in such cases.
1552 to continue even in such cases.
1553 """
1553 """
1554 try:
1554 try:
1555 return getset(repo, subset, x)
1555 return getset(repo, subset, x)
1556 except error.RepoLookupError:
1556 except error.RepoLookupError:
1557 return baseset()
1557 return baseset()
1558
1558
1559 # for internal use
1559 # for internal use
1560 def _notpublic(repo, subset, x):
1560 def _notpublic(repo, subset, x):
1561 getargs(x, 0, 0, "_notpublic takes no arguments")
1561 getargs(x, 0, 0, "_notpublic takes no arguments")
1562 repo._phasecache.loadphaserevs(repo) # ensure phase's sets are loaded
1562 repo._phasecache.loadphaserevs(repo) # ensure phase's sets are loaded
1563 if repo._phasecache._phasesets:
1563 if repo._phasecache._phasesets:
1564 s = set()
1564 s = set()
1565 for u in repo._phasecache._phasesets[1:]:
1565 for u in repo._phasecache._phasesets[1:]:
1566 s.update(u)
1566 s.update(u)
1567 s = baseset(s - repo.changelog.filteredrevs)
1567 s = baseset(s - repo.changelog.filteredrevs)
1568 s.sort()
1568 s.sort()
1569 return subset & s
1569 return subset & s
1570 else:
1570 else:
1571 phase = repo._phasecache.phase
1571 phase = repo._phasecache.phase
1572 target = phases.public
1572 target = phases.public
1573 condition = lambda r: phase(repo, r) != target
1573 condition = lambda r: phase(repo, r) != target
1574 return subset.filter(condition, cache=False)
1574 return subset.filter(condition, cache=False)
1575
1575
1576 def public(repo, subset, x):
1576 def public(repo, subset, x):
1577 """``public()``
1577 """``public()``
1578 Changeset in public phase."""
1578 Changeset in public phase."""
1579 # i18n: "public" is a keyword
1579 # i18n: "public" is a keyword
1580 getargs(x, 0, 0, _("public takes no arguments"))
1580 getargs(x, 0, 0, _("public takes no arguments"))
1581 phase = repo._phasecache.phase
1581 phase = repo._phasecache.phase
1582 target = phases.public
1582 target = phases.public
1583 condition = lambda r: phase(repo, r) == target
1583 condition = lambda r: phase(repo, r) == target
1584 return subset.filter(condition, cache=False)
1584 return subset.filter(condition, cache=False)
1585
1585
1586 def remote(repo, subset, x):
1586 def remote(repo, subset, x):
1587 """``remote([id [,path]])``
1587 """``remote([id [,path]])``
1588 Local revision that corresponds to the given identifier in a
1588 Local revision that corresponds to the given identifier in a
1589 remote repository, if present. Here, the '.' identifier is a
1589 remote repository, if present. Here, the '.' identifier is a
1590 synonym for the current local branch.
1590 synonym for the current local branch.
1591 """
1591 """
1592
1592
1593 import hg # avoid start-up nasties
1593 import hg # avoid start-up nasties
1594 # i18n: "remote" is a keyword
1594 # i18n: "remote" is a keyword
1595 l = getargs(x, 0, 2, _("remote takes one, two or no arguments"))
1595 l = getargs(x, 0, 2, _("remote takes one, two or no arguments"))
1596
1596
1597 q = '.'
1597 q = '.'
1598 if len(l) > 0:
1598 if len(l) > 0:
1599 # i18n: "remote" is a keyword
1599 # i18n: "remote" is a keyword
1600 q = getstring(l[0], _("remote requires a string id"))
1600 q = getstring(l[0], _("remote requires a string id"))
1601 if q == '.':
1601 if q == '.':
1602 q = repo['.'].branch()
1602 q = repo['.'].branch()
1603
1603
1604 dest = ''
1604 dest = ''
1605 if len(l) > 1:
1605 if len(l) > 1:
1606 # i18n: "remote" is a keyword
1606 # i18n: "remote" is a keyword
1607 dest = getstring(l[1], _("remote requires a repository path"))
1607 dest = getstring(l[1], _("remote requires a repository path"))
1608 dest = repo.ui.expandpath(dest or 'default')
1608 dest = repo.ui.expandpath(dest or 'default')
1609 dest, branches = hg.parseurl(dest)
1609 dest, branches = hg.parseurl(dest)
1610 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1610 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1611 if revs:
1611 if revs:
1612 revs = [repo.lookup(rev) for rev in revs]
1612 revs = [repo.lookup(rev) for rev in revs]
1613 other = hg.peer(repo, {}, dest)
1613 other = hg.peer(repo, {}, dest)
1614 n = other.lookup(q)
1614 n = other.lookup(q)
1615 if n in repo:
1615 if n in repo:
1616 r = repo[n].rev()
1616 r = repo[n].rev()
1617 if r in subset:
1617 if r in subset:
1618 return baseset([r])
1618 return baseset([r])
1619 return baseset()
1619 return baseset()
1620
1620
1621 def removes(repo, subset, x):
1621 def removes(repo, subset, x):
1622 """``removes(pattern)``
1622 """``removes(pattern)``
1623 Changesets which remove files matching pattern.
1623 Changesets which remove files matching pattern.
1624
1624
1625 The pattern without explicit kind like ``glob:`` is expected to be
1625 The pattern without explicit kind like ``glob:`` is expected to be
1626 relative to the current directory and match against a file or a
1626 relative to the current directory and match against a file or a
1627 directory.
1627 directory.
1628 """
1628 """
1629 # i18n: "removes" is a keyword
1629 # i18n: "removes" is a keyword
1630 pat = getstring(x, _("removes requires a pattern"))
1630 pat = getstring(x, _("removes requires a pattern"))
1631 return checkstatus(repo, subset, pat, 2)
1631 return checkstatus(repo, subset, pat, 2)
1632
1632
1633 def rev(repo, subset, x):
1633 def rev(repo, subset, x):
1634 """``rev(number)``
1634 """``rev(number)``
1635 Revision with the given numeric identifier.
1635 Revision with the given numeric identifier.
1636 """
1636 """
1637 # i18n: "rev" is a keyword
1637 # i18n: "rev" is a keyword
1638 l = getargs(x, 1, 1, _("rev requires one argument"))
1638 l = getargs(x, 1, 1, _("rev requires one argument"))
1639 try:
1639 try:
1640 # i18n: "rev" is a keyword
1640 # i18n: "rev" is a keyword
1641 l = int(getstring(l[0], _("rev requires a number")))
1641 l = int(getstring(l[0], _("rev requires a number")))
1642 except (TypeError, ValueError):
1642 except (TypeError, ValueError):
1643 # i18n: "rev" is a keyword
1643 # i18n: "rev" is a keyword
1644 raise error.ParseError(_("rev expects a number"))
1644 raise error.ParseError(_("rev expects a number"))
1645 if l not in repo.changelog and l != node.nullrev:
1645 if l not in repo.changelog and l != node.nullrev:
1646 return baseset()
1646 return baseset()
1647 return subset & baseset([l])
1647 return subset & baseset([l])
1648
1648
1649 def matching(repo, subset, x):
1649 def matching(repo, subset, x):
1650 """``matching(revision [, field])``
1650 """``matching(revision [, field])``
1651 Changesets in which a given set of fields match the set of fields in the
1651 Changesets in which a given set of fields match the set of fields in the
1652 selected revision or set.
1652 selected revision or set.
1653
1653
1654 To match more than one field pass the list of fields to match separated
1654 To match more than one field pass the list of fields to match separated
1655 by spaces (e.g. ``author description``).
1655 by spaces (e.g. ``author description``).
1656
1656
1657 Valid fields are most regular revision fields and some special fields.
1657 Valid fields are most regular revision fields and some special fields.
1658
1658
1659 Regular revision fields are ``description``, ``author``, ``branch``,
1659 Regular revision fields are ``description``, ``author``, ``branch``,
1660 ``date``, ``files``, ``phase``, ``parents``, ``substate``, ``user``
1660 ``date``, ``files``, ``phase``, ``parents``, ``substate``, ``user``
1661 and ``diff``.
1661 and ``diff``.
1662 Note that ``author`` and ``user`` are synonyms. ``diff`` refers to the
1662 Note that ``author`` and ``user`` are synonyms. ``diff`` refers to the
1663 contents of the revision. Two revisions matching their ``diff`` will
1663 contents of the revision. Two revisions matching their ``diff`` will
1664 also match their ``files``.
1664 also match their ``files``.
1665
1665
1666 Special fields are ``summary`` and ``metadata``:
1666 Special fields are ``summary`` and ``metadata``:
1667 ``summary`` matches the first line of the description.
1667 ``summary`` matches the first line of the description.
1668 ``metadata`` is equivalent to matching ``description user date``
1668 ``metadata`` is equivalent to matching ``description user date``
1669 (i.e. it matches the main metadata fields).
1669 (i.e. it matches the main metadata fields).
1670
1670
1671 ``metadata`` is the default field which is used when no fields are
1671 ``metadata`` is the default field which is used when no fields are
1672 specified. You can match more than one field at a time.
1672 specified. You can match more than one field at a time.
1673 """
1673 """
1674 # i18n: "matching" is a keyword
1674 # i18n: "matching" is a keyword
1675 l = getargs(x, 1, 2, _("matching takes 1 or 2 arguments"))
1675 l = getargs(x, 1, 2, _("matching takes 1 or 2 arguments"))
1676
1676
1677 revs = getset(repo, fullreposet(repo), l[0])
1677 revs = getset(repo, fullreposet(repo), l[0])
1678
1678
1679 fieldlist = ['metadata']
1679 fieldlist = ['metadata']
1680 if len(l) > 1:
1680 if len(l) > 1:
1681 fieldlist = getstring(l[1],
1681 fieldlist = getstring(l[1],
1682 # i18n: "matching" is a keyword
1682 # i18n: "matching" is a keyword
1683 _("matching requires a string "
1683 _("matching requires a string "
1684 "as its second argument")).split()
1684 "as its second argument")).split()
1685
1685
1686 # Make sure that there are no repeated fields,
1686 # Make sure that there are no repeated fields,
1687 # expand the 'special' 'metadata' field type
1687 # expand the 'special' 'metadata' field type
1688 # and check the 'files' whenever we check the 'diff'
1688 # and check the 'files' whenever we check the 'diff'
1689 fields = []
1689 fields = []
1690 for field in fieldlist:
1690 for field in fieldlist:
1691 if field == 'metadata':
1691 if field == 'metadata':
1692 fields += ['user', 'description', 'date']
1692 fields += ['user', 'description', 'date']
1693 elif field == 'diff':
1693 elif field == 'diff':
1694 # a revision matching the diff must also match the files
1694 # a revision matching the diff must also match the files
1695 # since matching the diff is very costly, make sure to
1695 # since matching the diff is very costly, make sure to
1696 # also match the files first
1696 # also match the files first
1697 fields += ['files', 'diff']
1697 fields += ['files', 'diff']
1698 else:
1698 else:
1699 if field == 'author':
1699 if field == 'author':
1700 field = 'user'
1700 field = 'user'
1701 fields.append(field)
1701 fields.append(field)
1702 fields = set(fields)
1702 fields = set(fields)
1703 if 'summary' in fields and 'description' in fields:
1703 if 'summary' in fields and 'description' in fields:
1704 # If a revision matches its description it also matches its summary
1704 # If a revision matches its description it also matches its summary
1705 fields.discard('summary')
1705 fields.discard('summary')
1706
1706
1707 # We may want to match more than one field
1707 # We may want to match more than one field
1708 # Not all fields take the same amount of time to be matched
1708 # Not all fields take the same amount of time to be matched
1709 # Sort the selected fields in order of increasing matching cost
1709 # Sort the selected fields in order of increasing matching cost
1710 fieldorder = ['phase', 'parents', 'user', 'date', 'branch', 'summary',
1710 fieldorder = ['phase', 'parents', 'user', 'date', 'branch', 'summary',
1711 'files', 'description', 'substate', 'diff']
1711 'files', 'description', 'substate', 'diff']
1712 def fieldkeyfunc(f):
1712 def fieldkeyfunc(f):
1713 try:
1713 try:
1714 return fieldorder.index(f)
1714 return fieldorder.index(f)
1715 except ValueError:
1715 except ValueError:
1716 # assume an unknown field is very costly
1716 # assume an unknown field is very costly
1717 return len(fieldorder)
1717 return len(fieldorder)
1718 fields = list(fields)
1718 fields = list(fields)
1719 fields.sort(key=fieldkeyfunc)
1719 fields.sort(key=fieldkeyfunc)
1720
1720
1721 # Each field will be matched with its own "getfield" function
1721 # Each field will be matched with its own "getfield" function
1722 # which will be added to the getfieldfuncs array of functions
1722 # which will be added to the getfieldfuncs array of functions
1723 getfieldfuncs = []
1723 getfieldfuncs = []
1724 _funcs = {
1724 _funcs = {
1725 'user': lambda r: repo[r].user(),
1725 'user': lambda r: repo[r].user(),
1726 'branch': lambda r: repo[r].branch(),
1726 'branch': lambda r: repo[r].branch(),
1727 'date': lambda r: repo[r].date(),
1727 'date': lambda r: repo[r].date(),
1728 'description': lambda r: repo[r].description(),
1728 'description': lambda r: repo[r].description(),
1729 'files': lambda r: repo[r].files(),
1729 'files': lambda r: repo[r].files(),
1730 'parents': lambda r: repo[r].parents(),
1730 'parents': lambda r: repo[r].parents(),
1731 'phase': lambda r: repo[r].phase(),
1731 'phase': lambda r: repo[r].phase(),
1732 'substate': lambda r: repo[r].substate,
1732 'substate': lambda r: repo[r].substate,
1733 'summary': lambda r: repo[r].description().splitlines()[0],
1733 'summary': lambda r: repo[r].description().splitlines()[0],
1734 'diff': lambda r: list(repo[r].diff(git=True),)
1734 'diff': lambda r: list(repo[r].diff(git=True),)
1735 }
1735 }
1736 for info in fields:
1736 for info in fields:
1737 getfield = _funcs.get(info, None)
1737 getfield = _funcs.get(info, None)
1738 if getfield is None:
1738 if getfield is None:
1739 raise error.ParseError(
1739 raise error.ParseError(
1740 # i18n: "matching" is a keyword
1740 # i18n: "matching" is a keyword
1741 _("unexpected field name passed to matching: %s") % info)
1741 _("unexpected field name passed to matching: %s") % info)
1742 getfieldfuncs.append(getfield)
1742 getfieldfuncs.append(getfield)
1743 # convert the getfield array of functions into a "getinfo" function
1743 # convert the getfield array of functions into a "getinfo" function
1744 # which returns an array of field values (or a single value if there
1744 # which returns an array of field values (or a single value if there
1745 # is only one field to match)
1745 # is only one field to match)
1746 getinfo = lambda r: [f(r) for f in getfieldfuncs]
1746 getinfo = lambda r: [f(r) for f in getfieldfuncs]
1747
1747
1748 def matches(x):
1748 def matches(x):
1749 for rev in revs:
1749 for rev in revs:
1750 target = getinfo(rev)
1750 target = getinfo(rev)
1751 match = True
1751 match = True
1752 for n, f in enumerate(getfieldfuncs):
1752 for n, f in enumerate(getfieldfuncs):
1753 if target[n] != f(x):
1753 if target[n] != f(x):
1754 match = False
1754 match = False
1755 if match:
1755 if match:
1756 return True
1756 return True
1757 return False
1757 return False
1758
1758
1759 return subset.filter(matches)
1759 return subset.filter(matches)
1760
1760
1761 def reverse(repo, subset, x):
1761 def reverse(repo, subset, x):
1762 """``reverse(set)``
1762 """``reverse(set)``
1763 Reverse order of set.
1763 Reverse order of set.
1764 """
1764 """
1765 l = getset(repo, subset, x)
1765 l = getset(repo, subset, x)
1766 l.reverse()
1766 l.reverse()
1767 return l
1767 return l
1768
1768
1769 def roots(repo, subset, x):
1769 def roots(repo, subset, x):
1770 """``roots(set)``
1770 """``roots(set)``
1771 Changesets in set with no parent changeset in set.
1771 Changesets in set with no parent changeset in set.
1772 """
1772 """
1773 s = getset(repo, fullreposet(repo), x)
1773 s = getset(repo, fullreposet(repo), x)
1774 parents = repo.changelog.parentrevs
1774 parents = repo.changelog.parentrevs
1775 def filter(r):
1775 def filter(r):
1776 for p in parents(r):
1776 for p in parents(r):
1777 if 0 <= p and p in s:
1777 if 0 <= p and p in s:
1778 return False
1778 return False
1779 return True
1779 return True
1780 return subset & s.filter(filter)
1780 return subset & s.filter(filter)
1781
1781
1782 def sort(repo, subset, x):
1782 def sort(repo, subset, x):
1783 """``sort(set[, [-]key...])``
1783 """``sort(set[, [-]key...])``
1784 Sort set by keys. The default sort order is ascending, specify a key
1784 Sort set by keys. The default sort order is ascending, specify a key
1785 as ``-key`` to sort in descending order.
1785 as ``-key`` to sort in descending order.
1786
1786
1787 The keys can be:
1787 The keys can be:
1788
1788
1789 - ``rev`` for the revision number,
1789 - ``rev`` for the revision number,
1790 - ``branch`` for the branch name,
1790 - ``branch`` for the branch name,
1791 - ``desc`` for the commit message (description),
1791 - ``desc`` for the commit message (description),
1792 - ``user`` for user name (``author`` can be used as an alias),
1792 - ``user`` for user name (``author`` can be used as an alias),
1793 - ``date`` for the commit date
1793 - ``date`` for the commit date
1794 """
1794 """
1795 # i18n: "sort" is a keyword
1795 # i18n: "sort" is a keyword
1796 l = getargs(x, 1, 2, _("sort requires one or two arguments"))
1796 l = getargs(x, 1, 2, _("sort requires one or two arguments"))
1797 keys = "rev"
1797 keys = "rev"
1798 if len(l) == 2:
1798 if len(l) == 2:
1799 # i18n: "sort" is a keyword
1799 # i18n: "sort" is a keyword
1800 keys = getstring(l[1], _("sort spec must be a string"))
1800 keys = getstring(l[1], _("sort spec must be a string"))
1801
1801
1802 s = l[0]
1802 s = l[0]
1803 keys = keys.split()
1803 keys = keys.split()
1804 l = []
1804 l = []
1805 def invert(s):
1805 def invert(s):
1806 return "".join(chr(255 - ord(c)) for c in s)
1806 return "".join(chr(255 - ord(c)) for c in s)
1807 revs = getset(repo, subset, s)
1807 revs = getset(repo, subset, s)
1808 if keys == ["rev"]:
1808 if keys == ["rev"]:
1809 revs.sort()
1809 revs.sort()
1810 return revs
1810 return revs
1811 elif keys == ["-rev"]:
1811 elif keys == ["-rev"]:
1812 revs.sort(reverse=True)
1812 revs.sort(reverse=True)
1813 return revs
1813 return revs
1814 for r in revs:
1814 for r in revs:
1815 c = repo[r]
1815 c = repo[r]
1816 e = []
1816 e = []
1817 for k in keys:
1817 for k in keys:
1818 if k == 'rev':
1818 if k == 'rev':
1819 e.append(r)
1819 e.append(r)
1820 elif k == '-rev':
1820 elif k == '-rev':
1821 e.append(-r)
1821 e.append(-r)
1822 elif k == 'branch':
1822 elif k == 'branch':
1823 e.append(c.branch())
1823 e.append(c.branch())
1824 elif k == '-branch':
1824 elif k == '-branch':
1825 e.append(invert(c.branch()))
1825 e.append(invert(c.branch()))
1826 elif k == 'desc':
1826 elif k == 'desc':
1827 e.append(c.description())
1827 e.append(c.description())
1828 elif k == '-desc':
1828 elif k == '-desc':
1829 e.append(invert(c.description()))
1829 e.append(invert(c.description()))
1830 elif k in 'user author':
1830 elif k in 'user author':
1831 e.append(c.user())
1831 e.append(c.user())
1832 elif k in '-user -author':
1832 elif k in '-user -author':
1833 e.append(invert(c.user()))
1833 e.append(invert(c.user()))
1834 elif k == 'date':
1834 elif k == 'date':
1835 e.append(c.date()[0])
1835 e.append(c.date()[0])
1836 elif k == '-date':
1836 elif k == '-date':
1837 e.append(-c.date()[0])
1837 e.append(-c.date()[0])
1838 else:
1838 else:
1839 raise error.ParseError(_("unknown sort key %r") % k)
1839 raise error.ParseError(_("unknown sort key %r") % k)
1840 e.append(r)
1840 e.append(r)
1841 l.append(e)
1841 l.append(e)
1842 l.sort()
1842 l.sort()
1843 return baseset([e[-1] for e in l])
1843 return baseset([e[-1] for e in l])
1844
1844
1845 def subrepo(repo, subset, x):
1845 def subrepo(repo, subset, x):
1846 """``subrepo([pattern])``
1846 """``subrepo([pattern])``
1847 Changesets that add, modify or remove the given subrepo. If no subrepo
1847 Changesets that add, modify or remove the given subrepo. If no subrepo
1848 pattern is named, any subrepo changes are returned.
1848 pattern is named, any subrepo changes are returned.
1849 """
1849 """
1850 # i18n: "subrepo" is a keyword
1850 # i18n: "subrepo" is a keyword
1851 args = getargs(x, 0, 1, _('subrepo takes at most one argument'))
1851 args = getargs(x, 0, 1, _('subrepo takes at most one argument'))
1852 if len(args) != 0:
1852 if len(args) != 0:
1853 pat = getstring(args[0], _("subrepo requires a pattern"))
1853 pat = getstring(args[0], _("subrepo requires a pattern"))
1854
1854
1855 m = matchmod.exact(repo.root, repo.root, ['.hgsubstate'])
1855 m = matchmod.exact(repo.root, repo.root, ['.hgsubstate'])
1856
1856
1857 def submatches(names):
1857 def submatches(names):
1858 k, p, m = _stringmatcher(pat)
1858 k, p, m = _stringmatcher(pat)
1859 for name in names:
1859 for name in names:
1860 if m(name):
1860 if m(name):
1861 yield name
1861 yield name
1862
1862
1863 def matches(x):
1863 def matches(x):
1864 c = repo[x]
1864 c = repo[x]
1865 s = repo.status(c.p1().node(), c.node(), match=m)
1865 s = repo.status(c.p1().node(), c.node(), match=m)
1866
1866
1867 if len(args) == 0:
1867 if len(args) == 0:
1868 return s.added or s.modified or s.removed
1868 return s.added or s.modified or s.removed
1869
1869
1870 if s.added:
1870 if s.added:
1871 return any(submatches(c.substate.keys()))
1871 return any(submatches(c.substate.keys()))
1872
1872
1873 if s.modified:
1873 if s.modified:
1874 subs = set(c.p1().substate.keys())
1874 subs = set(c.p1().substate.keys())
1875 subs.update(c.substate.keys())
1875 subs.update(c.substate.keys())
1876
1876
1877 for path in submatches(subs):
1877 for path in submatches(subs):
1878 if c.p1().substate.get(path) != c.substate.get(path):
1878 if c.p1().substate.get(path) != c.substate.get(path):
1879 return True
1879 return True
1880
1880
1881 if s.removed:
1881 if s.removed:
1882 return any(submatches(c.p1().substate.keys()))
1882 return any(submatches(c.p1().substate.keys()))
1883
1883
1884 return False
1884 return False
1885
1885
1886 return subset.filter(matches)
1886 return subset.filter(matches)
1887
1887
1888 def _stringmatcher(pattern):
1888 def _stringmatcher(pattern):
1889 """
1889 """
1890 accepts a string, possibly starting with 're:' or 'literal:' prefix.
1890 accepts a string, possibly starting with 're:' or 'literal:' prefix.
1891 returns the matcher name, pattern, and matcher function.
1891 returns the matcher name, pattern, and matcher function.
1892 missing or unknown prefixes are treated as literal matches.
1892 missing or unknown prefixes are treated as literal matches.
1893
1893
1894 helper for tests:
1894 helper for tests:
1895 >>> def test(pattern, *tests):
1895 >>> def test(pattern, *tests):
1896 ... kind, pattern, matcher = _stringmatcher(pattern)
1896 ... kind, pattern, matcher = _stringmatcher(pattern)
1897 ... return (kind, pattern, [bool(matcher(t)) for t in tests])
1897 ... return (kind, pattern, [bool(matcher(t)) for t in tests])
1898
1898
1899 exact matching (no prefix):
1899 exact matching (no prefix):
1900 >>> test('abcdefg', 'abc', 'def', 'abcdefg')
1900 >>> test('abcdefg', 'abc', 'def', 'abcdefg')
1901 ('literal', 'abcdefg', [False, False, True])
1901 ('literal', 'abcdefg', [False, False, True])
1902
1902
1903 regex matching ('re:' prefix)
1903 regex matching ('re:' prefix)
1904 >>> test('re:a.+b', 'nomatch', 'fooadef', 'fooadefbar')
1904 >>> test('re:a.+b', 'nomatch', 'fooadef', 'fooadefbar')
1905 ('re', 'a.+b', [False, False, True])
1905 ('re', 'a.+b', [False, False, True])
1906
1906
1907 force exact matches ('literal:' prefix)
1907 force exact matches ('literal:' prefix)
1908 >>> test('literal:re:foobar', 'foobar', 're:foobar')
1908 >>> test('literal:re:foobar', 'foobar', 're:foobar')
1909 ('literal', 're:foobar', [False, True])
1909 ('literal', 're:foobar', [False, True])
1910
1910
1911 unknown prefixes are ignored and treated as literals
1911 unknown prefixes are ignored and treated as literals
1912 >>> test('foo:bar', 'foo', 'bar', 'foo:bar')
1912 >>> test('foo:bar', 'foo', 'bar', 'foo:bar')
1913 ('literal', 'foo:bar', [False, False, True])
1913 ('literal', 'foo:bar', [False, False, True])
1914 """
1914 """
1915 if pattern.startswith('re:'):
1915 if pattern.startswith('re:'):
1916 pattern = pattern[3:]
1916 pattern = pattern[3:]
1917 try:
1917 try:
1918 regex = re.compile(pattern)
1918 regex = re.compile(pattern)
1919 except re.error as e:
1919 except re.error as e:
1920 raise error.ParseError(_('invalid regular expression: %s')
1920 raise error.ParseError(_('invalid regular expression: %s')
1921 % e)
1921 % e)
1922 return 're', pattern, regex.search
1922 return 're', pattern, regex.search
1923 elif pattern.startswith('literal:'):
1923 elif pattern.startswith('literal:'):
1924 pattern = pattern[8:]
1924 pattern = pattern[8:]
1925 return 'literal', pattern, pattern.__eq__
1925 return 'literal', pattern, pattern.__eq__
1926
1926
1927 def _substringmatcher(pattern):
1927 def _substringmatcher(pattern):
1928 kind, pattern, matcher = _stringmatcher(pattern)
1928 kind, pattern, matcher = _stringmatcher(pattern)
1929 if kind == 'literal':
1929 if kind == 'literal':
1930 matcher = lambda s: pattern in s
1930 matcher = lambda s: pattern in s
1931 return kind, pattern, matcher
1931 return kind, pattern, matcher
1932
1932
1933 def tag(repo, subset, x):
1933 def tag(repo, subset, x):
1934 """``tag([name])``
1934 """``tag([name])``
1935 The specified tag by name, or all tagged revisions if no name is given.
1935 The specified tag by name, or all tagged revisions if no name is given.
1936
1936
1937 If `name` starts with `re:`, the remainder of the name is treated as
1937 If `name` starts with `re:`, the remainder of the name is treated as
1938 a regular expression. To match a tag that actually starts with `re:`,
1938 a regular expression. To match a tag that actually starts with `re:`,
1939 use the prefix `literal:`.
1939 use the prefix `literal:`.
1940 """
1940 """
1941 # i18n: "tag" is a keyword
1941 # i18n: "tag" is a keyword
1942 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
1942 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
1943 cl = repo.changelog
1943 cl = repo.changelog
1944 if args:
1944 if args:
1945 pattern = getstring(args[0],
1945 pattern = getstring(args[0],
1946 # i18n: "tag" is a keyword
1946 # i18n: "tag" is a keyword
1947 _('the argument to tag must be a string'))
1947 _('the argument to tag must be a string'))
1948 kind, pattern, matcher = _stringmatcher(pattern)
1948 kind, pattern, matcher = _stringmatcher(pattern)
1949 if kind == 'literal':
1949 if kind == 'literal':
1950 # avoid resolving all tags
1950 # avoid resolving all tags
1951 tn = repo._tagscache.tags.get(pattern, None)
1951 tn = repo._tagscache.tags.get(pattern, None)
1952 if tn is None:
1952 if tn is None:
1953 raise error.RepoLookupError(_("tag '%s' does not exist")
1953 raise error.RepoLookupError(_("tag '%s' does not exist")
1954 % pattern)
1954 % pattern)
1955 s = set([repo[tn].rev()])
1955 s = set([repo[tn].rev()])
1956 else:
1956 else:
1957 s = set([cl.rev(n) for t, n in repo.tagslist() if matcher(t)])
1957 s = set([cl.rev(n) for t, n in repo.tagslist() if matcher(t)])
1958 else:
1958 else:
1959 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
1959 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
1960 return subset & s
1960 return subset & s
1961
1961
1962 def tagged(repo, subset, x):
1962 def tagged(repo, subset, x):
1963 return tag(repo, subset, x)
1963 return tag(repo, subset, x)
1964
1964
1965 def unstable(repo, subset, x):
1965 def unstable(repo, subset, x):
1966 """``unstable()``
1966 """``unstable()``
1967 Non-obsolete changesets with obsolete ancestors.
1967 Non-obsolete changesets with obsolete ancestors.
1968 """
1968 """
1969 # i18n: "unstable" is a keyword
1969 # i18n: "unstable" is a keyword
1970 getargs(x, 0, 0, _("unstable takes no arguments"))
1970 getargs(x, 0, 0, _("unstable takes no arguments"))
1971 unstables = obsmod.getrevs(repo, 'unstable')
1971 unstables = obsmod.getrevs(repo, 'unstable')
1972 return subset & unstables
1972 return subset & unstables
1973
1973
1974
1974
1975 def user(repo, subset, x):
1975 def user(repo, subset, x):
1976 """``user(string)``
1976 """``user(string)``
1977 User name contains string. The match is case-insensitive.
1977 User name contains string. The match is case-insensitive.
1978
1978
1979 If `string` starts with `re:`, the remainder of the string is treated as
1979 If `string` starts with `re:`, the remainder of the string is treated as
1980 a regular expression. To match a user that actually contains `re:`, use
1980 a regular expression. To match a user that actually contains `re:`, use
1981 the prefix `literal:`.
1981 the prefix `literal:`.
1982 """
1982 """
1983 return author(repo, subset, x)
1983 return author(repo, subset, x)
1984
1984
1985 # experimental
1985 # experimental
1986 def wdir(repo, subset, x):
1986 def wdir(repo, subset, x):
1987 # i18n: "wdir" is a keyword
1987 # i18n: "wdir" is a keyword
1988 getargs(x, 0, 0, _("wdir takes no arguments"))
1988 getargs(x, 0, 0, _("wdir takes no arguments"))
1989 if None in subset or isinstance(subset, fullreposet):
1989 if node.wdirrev in subset or isinstance(subset, fullreposet):
1990 return baseset([None])
1990 return baseset([node.wdirrev])
1991 return baseset()
1991 return baseset()
1992
1992
1993 # for internal use
1993 # for internal use
1994 def _list(repo, subset, x):
1994 def _list(repo, subset, x):
1995 s = getstring(x, "internal error")
1995 s = getstring(x, "internal error")
1996 if not s:
1996 if not s:
1997 return baseset()
1997 return baseset()
1998 # remove duplicates here. it's difficult for caller to deduplicate sets
1998 # remove duplicates here. it's difficult for caller to deduplicate sets
1999 # because different symbols can point to the same rev.
1999 # because different symbols can point to the same rev.
2000 cl = repo.changelog
2000 cl = repo.changelog
2001 ls = []
2001 ls = []
2002 seen = set()
2002 seen = set()
2003 for t in s.split('\0'):
2003 for t in s.split('\0'):
2004 try:
2004 try:
2005 # fast path for integer revision
2005 # fast path for integer revision
2006 r = int(t)
2006 r = int(t)
2007 if str(r) != t or r not in cl:
2007 if str(r) != t or r not in cl:
2008 raise ValueError
2008 raise ValueError
2009 except ValueError:
2009 except ValueError:
2010 r = repo[t].rev()
2010 r = repo[t].rev()
2011 if r in seen:
2011 if r in seen:
2012 continue
2012 continue
2013 if (r in subset
2013 if (r in subset
2014 or r == node.nullrev and isinstance(subset, fullreposet)):
2014 or r == node.nullrev and isinstance(subset, fullreposet)):
2015 ls.append(r)
2015 ls.append(r)
2016 seen.add(r)
2016 seen.add(r)
2017 return baseset(ls)
2017 return baseset(ls)
2018
2018
2019 # for internal use
2019 # for internal use
2020 def _intlist(repo, subset, x):
2020 def _intlist(repo, subset, x):
2021 s = getstring(x, "internal error")
2021 s = getstring(x, "internal error")
2022 if not s:
2022 if not s:
2023 return baseset()
2023 return baseset()
2024 ls = [int(r) for r in s.split('\0')]
2024 ls = [int(r) for r in s.split('\0')]
2025 s = subset
2025 s = subset
2026 return baseset([r for r in ls if r in s])
2026 return baseset([r for r in ls if r in s])
2027
2027
2028 # for internal use
2028 # for internal use
2029 def _hexlist(repo, subset, x):
2029 def _hexlist(repo, subset, x):
2030 s = getstring(x, "internal error")
2030 s = getstring(x, "internal error")
2031 if not s:
2031 if not s:
2032 return baseset()
2032 return baseset()
2033 cl = repo.changelog
2033 cl = repo.changelog
2034 ls = [cl.rev(node.bin(r)) for r in s.split('\0')]
2034 ls = [cl.rev(node.bin(r)) for r in s.split('\0')]
2035 s = subset
2035 s = subset
2036 return baseset([r for r in ls if r in s])
2036 return baseset([r for r in ls if r in s])
2037
2037
2038 symbols = {
2038 symbols = {
2039 "adds": adds,
2039 "adds": adds,
2040 "all": getall,
2040 "all": getall,
2041 "ancestor": ancestor,
2041 "ancestor": ancestor,
2042 "ancestors": ancestors,
2042 "ancestors": ancestors,
2043 "_firstancestors": _firstancestors,
2043 "_firstancestors": _firstancestors,
2044 "author": author,
2044 "author": author,
2045 "bisect": bisect,
2045 "bisect": bisect,
2046 "bisected": bisected,
2046 "bisected": bisected,
2047 "bookmark": bookmark,
2047 "bookmark": bookmark,
2048 "branch": branch,
2048 "branch": branch,
2049 "branchpoint": branchpoint,
2049 "branchpoint": branchpoint,
2050 "bumped": bumped,
2050 "bumped": bumped,
2051 "bundle": bundle,
2051 "bundle": bundle,
2052 "children": children,
2052 "children": children,
2053 "closed": closed,
2053 "closed": closed,
2054 "contains": contains,
2054 "contains": contains,
2055 "converted": converted,
2055 "converted": converted,
2056 "date": date,
2056 "date": date,
2057 "desc": desc,
2057 "desc": desc,
2058 "descendants": descendants,
2058 "descendants": descendants,
2059 "_firstdescendants": _firstdescendants,
2059 "_firstdescendants": _firstdescendants,
2060 "destination": destination,
2060 "destination": destination,
2061 "divergent": divergent,
2061 "divergent": divergent,
2062 "draft": draft,
2062 "draft": draft,
2063 "extinct": extinct,
2063 "extinct": extinct,
2064 "extra": extra,
2064 "extra": extra,
2065 "file": hasfile,
2065 "file": hasfile,
2066 "filelog": filelog,
2066 "filelog": filelog,
2067 "first": first,
2067 "first": first,
2068 "follow": follow,
2068 "follow": follow,
2069 "_followfirst": _followfirst,
2069 "_followfirst": _followfirst,
2070 "grep": grep,
2070 "grep": grep,
2071 "head": head,
2071 "head": head,
2072 "heads": heads,
2072 "heads": heads,
2073 "hidden": hidden,
2073 "hidden": hidden,
2074 "id": node_,
2074 "id": node_,
2075 "keyword": keyword,
2075 "keyword": keyword,
2076 "last": last,
2076 "last": last,
2077 "limit": limit,
2077 "limit": limit,
2078 "_matchfiles": _matchfiles,
2078 "_matchfiles": _matchfiles,
2079 "max": maxrev,
2079 "max": maxrev,
2080 "merge": merge,
2080 "merge": merge,
2081 "min": minrev,
2081 "min": minrev,
2082 "modifies": modifies,
2082 "modifies": modifies,
2083 "named": named,
2083 "named": named,
2084 "obsolete": obsolete,
2084 "obsolete": obsolete,
2085 "only": only,
2085 "only": only,
2086 "origin": origin,
2086 "origin": origin,
2087 "outgoing": outgoing,
2087 "outgoing": outgoing,
2088 "p1": p1,
2088 "p1": p1,
2089 "p2": p2,
2089 "p2": p2,
2090 "parents": parents,
2090 "parents": parents,
2091 "present": present,
2091 "present": present,
2092 "public": public,
2092 "public": public,
2093 "_notpublic": _notpublic,
2093 "_notpublic": _notpublic,
2094 "remote": remote,
2094 "remote": remote,
2095 "removes": removes,
2095 "removes": removes,
2096 "rev": rev,
2096 "rev": rev,
2097 "reverse": reverse,
2097 "reverse": reverse,
2098 "roots": roots,
2098 "roots": roots,
2099 "sort": sort,
2099 "sort": sort,
2100 "secret": secret,
2100 "secret": secret,
2101 "subrepo": subrepo,
2101 "subrepo": subrepo,
2102 "matching": matching,
2102 "matching": matching,
2103 "tag": tag,
2103 "tag": tag,
2104 "tagged": tagged,
2104 "tagged": tagged,
2105 "user": user,
2105 "user": user,
2106 "unstable": unstable,
2106 "unstable": unstable,
2107 "wdir": wdir,
2107 "wdir": wdir,
2108 "_list": _list,
2108 "_list": _list,
2109 "_intlist": _intlist,
2109 "_intlist": _intlist,
2110 "_hexlist": _hexlist,
2110 "_hexlist": _hexlist,
2111 }
2111 }
2112
2112
2113 # symbols which can't be used for a DoS attack for any given input
2113 # symbols which can't be used for a DoS attack for any given input
2114 # (e.g. those which accept regexes as plain strings shouldn't be included)
2114 # (e.g. those which accept regexes as plain strings shouldn't be included)
2115 # functions that just return a lot of changesets (like all) don't count here
2115 # functions that just return a lot of changesets (like all) don't count here
2116 safesymbols = set([
2116 safesymbols = set([
2117 "adds",
2117 "adds",
2118 "all",
2118 "all",
2119 "ancestor",
2119 "ancestor",
2120 "ancestors",
2120 "ancestors",
2121 "_firstancestors",
2121 "_firstancestors",
2122 "author",
2122 "author",
2123 "bisect",
2123 "bisect",
2124 "bisected",
2124 "bisected",
2125 "bookmark",
2125 "bookmark",
2126 "branch",
2126 "branch",
2127 "branchpoint",
2127 "branchpoint",
2128 "bumped",
2128 "bumped",
2129 "bundle",
2129 "bundle",
2130 "children",
2130 "children",
2131 "closed",
2131 "closed",
2132 "converted",
2132 "converted",
2133 "date",
2133 "date",
2134 "desc",
2134 "desc",
2135 "descendants",
2135 "descendants",
2136 "_firstdescendants",
2136 "_firstdescendants",
2137 "destination",
2137 "destination",
2138 "divergent",
2138 "divergent",
2139 "draft",
2139 "draft",
2140 "extinct",
2140 "extinct",
2141 "extra",
2141 "extra",
2142 "file",
2142 "file",
2143 "filelog",
2143 "filelog",
2144 "first",
2144 "first",
2145 "follow",
2145 "follow",
2146 "_followfirst",
2146 "_followfirst",
2147 "head",
2147 "head",
2148 "heads",
2148 "heads",
2149 "hidden",
2149 "hidden",
2150 "id",
2150 "id",
2151 "keyword",
2151 "keyword",
2152 "last",
2152 "last",
2153 "limit",
2153 "limit",
2154 "_matchfiles",
2154 "_matchfiles",
2155 "max",
2155 "max",
2156 "merge",
2156 "merge",
2157 "min",
2157 "min",
2158 "modifies",
2158 "modifies",
2159 "obsolete",
2159 "obsolete",
2160 "only",
2160 "only",
2161 "origin",
2161 "origin",
2162 "outgoing",
2162 "outgoing",
2163 "p1",
2163 "p1",
2164 "p2",
2164 "p2",
2165 "parents",
2165 "parents",
2166 "present",
2166 "present",
2167 "public",
2167 "public",
2168 "_notpublic",
2168 "_notpublic",
2169 "remote",
2169 "remote",
2170 "removes",
2170 "removes",
2171 "rev",
2171 "rev",
2172 "reverse",
2172 "reverse",
2173 "roots",
2173 "roots",
2174 "sort",
2174 "sort",
2175 "secret",
2175 "secret",
2176 "matching",
2176 "matching",
2177 "tag",
2177 "tag",
2178 "tagged",
2178 "tagged",
2179 "user",
2179 "user",
2180 "unstable",
2180 "unstable",
2181 "wdir",
2181 "wdir",
2182 "_list",
2182 "_list",
2183 "_intlist",
2183 "_intlist",
2184 "_hexlist",
2184 "_hexlist",
2185 ])
2185 ])
2186
2186
2187 methods = {
2187 methods = {
2188 "range": rangeset,
2188 "range": rangeset,
2189 "dagrange": dagrange,
2189 "dagrange": dagrange,
2190 "string": stringset,
2190 "string": stringset,
2191 "symbol": stringset,
2191 "symbol": stringset,
2192 "and": andset,
2192 "and": andset,
2193 "or": orset,
2193 "or": orset,
2194 "not": notset,
2194 "not": notset,
2195 "list": listset,
2195 "list": listset,
2196 "keyvalue": keyvaluepair,
2196 "keyvalue": keyvaluepair,
2197 "func": func,
2197 "func": func,
2198 "ancestor": ancestorspec,
2198 "ancestor": ancestorspec,
2199 "parent": parentspec,
2199 "parent": parentspec,
2200 "parentpost": p1,
2200 "parentpost": p1,
2201 }
2201 }
2202
2202
2203 def optimize(x, small):
2203 def optimize(x, small):
2204 if x is None:
2204 if x is None:
2205 return 0, x
2205 return 0, x
2206
2206
2207 smallbonus = 1
2207 smallbonus = 1
2208 if small:
2208 if small:
2209 smallbonus = .5
2209 smallbonus = .5
2210
2210
2211 op = x[0]
2211 op = x[0]
2212 if op == 'minus':
2212 if op == 'minus':
2213 return optimize(('and', x[1], ('not', x[2])), small)
2213 return optimize(('and', x[1], ('not', x[2])), small)
2214 elif op == 'only':
2214 elif op == 'only':
2215 return optimize(('func', ('symbol', 'only'),
2215 return optimize(('func', ('symbol', 'only'),
2216 ('list', x[1], x[2])), small)
2216 ('list', x[1], x[2])), small)
2217 elif op == 'onlypost':
2217 elif op == 'onlypost':
2218 return optimize(('func', ('symbol', 'only'), x[1]), small)
2218 return optimize(('func', ('symbol', 'only'), x[1]), small)
2219 elif op == 'dagrangepre':
2219 elif op == 'dagrangepre':
2220 return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
2220 return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
2221 elif op == 'dagrangepost':
2221 elif op == 'dagrangepost':
2222 return optimize(('func', ('symbol', 'descendants'), x[1]), small)
2222 return optimize(('func', ('symbol', 'descendants'), x[1]), small)
2223 elif op == 'rangepre':
2223 elif op == 'rangepre':
2224 return optimize(('range', ('string', '0'), x[1]), small)
2224 return optimize(('range', ('string', '0'), x[1]), small)
2225 elif op == 'rangepost':
2225 elif op == 'rangepost':
2226 return optimize(('range', x[1], ('string', 'tip')), small)
2226 return optimize(('range', x[1], ('string', 'tip')), small)
2227 elif op == 'negate':
2227 elif op == 'negate':
2228 return optimize(('string',
2228 return optimize(('string',
2229 '-' + getstring(x[1], _("can't negate that"))), small)
2229 '-' + getstring(x[1], _("can't negate that"))), small)
2230 elif op in 'string symbol negate':
2230 elif op in 'string symbol negate':
2231 return smallbonus, x # single revisions are small
2231 return smallbonus, x # single revisions are small
2232 elif op == 'and':
2232 elif op == 'and':
2233 wa, ta = optimize(x[1], True)
2233 wa, ta = optimize(x[1], True)
2234 wb, tb = optimize(x[2], True)
2234 wb, tb = optimize(x[2], True)
2235
2235
2236 # (::x and not ::y)/(not ::y and ::x) have a fast path
2236 # (::x and not ::y)/(not ::y and ::x) have a fast path
2237 def isonly(revs, bases):
2237 def isonly(revs, bases):
2238 return (
2238 return (
2239 revs[0] == 'func'
2239 revs[0] == 'func'
2240 and getstring(revs[1], _('not a symbol')) == 'ancestors'
2240 and getstring(revs[1], _('not a symbol')) == 'ancestors'
2241 and bases[0] == 'not'
2241 and bases[0] == 'not'
2242 and bases[1][0] == 'func'
2242 and bases[1][0] == 'func'
2243 and getstring(bases[1][1], _('not a symbol')) == 'ancestors')
2243 and getstring(bases[1][1], _('not a symbol')) == 'ancestors')
2244
2244
2245 w = min(wa, wb)
2245 w = min(wa, wb)
2246 if isonly(ta, tb):
2246 if isonly(ta, tb):
2247 return w, ('func', ('symbol', 'only'), ('list', ta[2], tb[1][2]))
2247 return w, ('func', ('symbol', 'only'), ('list', ta[2], tb[1][2]))
2248 if isonly(tb, ta):
2248 if isonly(tb, ta):
2249 return w, ('func', ('symbol', 'only'), ('list', tb[2], ta[1][2]))
2249 return w, ('func', ('symbol', 'only'), ('list', tb[2], ta[1][2]))
2250
2250
2251 if wa > wb:
2251 if wa > wb:
2252 return w, (op, tb, ta)
2252 return w, (op, tb, ta)
2253 return w, (op, ta, tb)
2253 return w, (op, ta, tb)
2254 elif op == 'or':
2254 elif op == 'or':
2255 # fast path for machine-generated expression, that is likely to have
2255 # fast path for machine-generated expression, that is likely to have
2256 # lots of trivial revisions: 'a + b + c()' to '_list(a b) + c()'
2256 # lots of trivial revisions: 'a + b + c()' to '_list(a b) + c()'
2257 ws, ts, ss = [], [], []
2257 ws, ts, ss = [], [], []
2258 def flushss():
2258 def flushss():
2259 if not ss:
2259 if not ss:
2260 return
2260 return
2261 if len(ss) == 1:
2261 if len(ss) == 1:
2262 w, t = ss[0]
2262 w, t = ss[0]
2263 else:
2263 else:
2264 s = '\0'.join(t[1] for w, t in ss)
2264 s = '\0'.join(t[1] for w, t in ss)
2265 y = ('func', ('symbol', '_list'), ('string', s))
2265 y = ('func', ('symbol', '_list'), ('string', s))
2266 w, t = optimize(y, False)
2266 w, t = optimize(y, False)
2267 ws.append(w)
2267 ws.append(w)
2268 ts.append(t)
2268 ts.append(t)
2269 del ss[:]
2269 del ss[:]
2270 for y in x[1:]:
2270 for y in x[1:]:
2271 w, t = optimize(y, False)
2271 w, t = optimize(y, False)
2272 if t[0] == 'string' or t[0] == 'symbol':
2272 if t[0] == 'string' or t[0] == 'symbol':
2273 ss.append((w, t))
2273 ss.append((w, t))
2274 continue
2274 continue
2275 flushss()
2275 flushss()
2276 ws.append(w)
2276 ws.append(w)
2277 ts.append(t)
2277 ts.append(t)
2278 flushss()
2278 flushss()
2279 if len(ts) == 1:
2279 if len(ts) == 1:
2280 return ws[0], ts[0] # 'or' operation is fully optimized out
2280 return ws[0], ts[0] # 'or' operation is fully optimized out
2281 # we can't reorder trees by weight because it would change the order.
2281 # we can't reorder trees by weight because it would change the order.
2282 # ("sort(a + b)" == "sort(b + a)", but "a + b" != "b + a")
2282 # ("sort(a + b)" == "sort(b + a)", but "a + b" != "b + a")
2283 # ts = tuple(t for w, t in sorted(zip(ws, ts), key=lambda wt: wt[0]))
2283 # ts = tuple(t for w, t in sorted(zip(ws, ts), key=lambda wt: wt[0]))
2284 return max(ws), (op,) + tuple(ts)
2284 return max(ws), (op,) + tuple(ts)
2285 elif op == 'not':
2285 elif op == 'not':
2286 # Optimize not public() to _notpublic() because we have a fast version
2286 # Optimize not public() to _notpublic() because we have a fast version
2287 if x[1] == ('func', ('symbol', 'public'), None):
2287 if x[1] == ('func', ('symbol', 'public'), None):
2288 newsym = ('func', ('symbol', '_notpublic'), None)
2288 newsym = ('func', ('symbol', '_notpublic'), None)
2289 o = optimize(newsym, not small)
2289 o = optimize(newsym, not small)
2290 return o[0], o[1]
2290 return o[0], o[1]
2291 else:
2291 else:
2292 o = optimize(x[1], not small)
2292 o = optimize(x[1], not small)
2293 return o[0], (op, o[1])
2293 return o[0], (op, o[1])
2294 elif op == 'parentpost':
2294 elif op == 'parentpost':
2295 o = optimize(x[1], small)
2295 o = optimize(x[1], small)
2296 return o[0], (op, o[1])
2296 return o[0], (op, o[1])
2297 elif op == 'group':
2297 elif op == 'group':
2298 return optimize(x[1], small)
2298 return optimize(x[1], small)
2299 elif op in 'dagrange range list parent ancestorspec':
2299 elif op in 'dagrange range list parent ancestorspec':
2300 if op == 'parent':
2300 if op == 'parent':
2301 # x^:y means (x^) : y, not x ^ (:y)
2301 # x^:y means (x^) : y, not x ^ (:y)
2302 post = ('parentpost', x[1])
2302 post = ('parentpost', x[1])
2303 if x[2][0] == 'dagrangepre':
2303 if x[2][0] == 'dagrangepre':
2304 return optimize(('dagrange', post, x[2][1]), small)
2304 return optimize(('dagrange', post, x[2][1]), small)
2305 elif x[2][0] == 'rangepre':
2305 elif x[2][0] == 'rangepre':
2306 return optimize(('range', post, x[2][1]), small)
2306 return optimize(('range', post, x[2][1]), small)
2307
2307
2308 wa, ta = optimize(x[1], small)
2308 wa, ta = optimize(x[1], small)
2309 wb, tb = optimize(x[2], small)
2309 wb, tb = optimize(x[2], small)
2310 return wa + wb, (op, ta, tb)
2310 return wa + wb, (op, ta, tb)
2311 elif op == 'func':
2311 elif op == 'func':
2312 f = getstring(x[1], _("not a symbol"))
2312 f = getstring(x[1], _("not a symbol"))
2313 wa, ta = optimize(x[2], small)
2313 wa, ta = optimize(x[2], small)
2314 if f in ("author branch closed date desc file grep keyword "
2314 if f in ("author branch closed date desc file grep keyword "
2315 "outgoing user"):
2315 "outgoing user"):
2316 w = 10 # slow
2316 w = 10 # slow
2317 elif f in "modifies adds removes":
2317 elif f in "modifies adds removes":
2318 w = 30 # slower
2318 w = 30 # slower
2319 elif f == "contains":
2319 elif f == "contains":
2320 w = 100 # very slow
2320 w = 100 # very slow
2321 elif f == "ancestor":
2321 elif f == "ancestor":
2322 w = 1 * smallbonus
2322 w = 1 * smallbonus
2323 elif f in "reverse limit first _intlist":
2323 elif f in "reverse limit first _intlist":
2324 w = 0
2324 w = 0
2325 elif f in "sort":
2325 elif f in "sort":
2326 w = 10 # assume most sorts look at changelog
2326 w = 10 # assume most sorts look at changelog
2327 else:
2327 else:
2328 w = 1
2328 w = 1
2329 return w + wa, (op, x[1], ta)
2329 return w + wa, (op, x[1], ta)
2330 return 1, x
2330 return 1, x
2331
2331
2332 _aliasarg = ('func', ('symbol', '_aliasarg'))
2332 _aliasarg = ('func', ('symbol', '_aliasarg'))
2333 def _getaliasarg(tree):
2333 def _getaliasarg(tree):
2334 """If tree matches ('func', ('symbol', '_aliasarg'), ('string', X))
2334 """If tree matches ('func', ('symbol', '_aliasarg'), ('string', X))
2335 return X, None otherwise.
2335 return X, None otherwise.
2336 """
2336 """
2337 if (len(tree) == 3 and tree[:2] == _aliasarg
2337 if (len(tree) == 3 and tree[:2] == _aliasarg
2338 and tree[2][0] == 'string'):
2338 and tree[2][0] == 'string'):
2339 return tree[2][1]
2339 return tree[2][1]
2340 return None
2340 return None
2341
2341
2342 def _checkaliasarg(tree, known=None):
2342 def _checkaliasarg(tree, known=None):
2343 """Check tree contains no _aliasarg construct or only ones which
2343 """Check tree contains no _aliasarg construct or only ones which
2344 value is in known. Used to avoid alias placeholders injection.
2344 value is in known. Used to avoid alias placeholders injection.
2345 """
2345 """
2346 if isinstance(tree, tuple):
2346 if isinstance(tree, tuple):
2347 arg = _getaliasarg(tree)
2347 arg = _getaliasarg(tree)
2348 if arg is not None and (not known or arg not in known):
2348 if arg is not None and (not known or arg not in known):
2349 raise error.UnknownIdentifier('_aliasarg', [])
2349 raise error.UnknownIdentifier('_aliasarg', [])
2350 for t in tree:
2350 for t in tree:
2351 _checkaliasarg(t, known)
2351 _checkaliasarg(t, known)
2352
2352
2353 # the set of valid characters for the initial letter of symbols in
2353 # the set of valid characters for the initial letter of symbols in
2354 # alias declarations and definitions
2354 # alias declarations and definitions
2355 _aliassyminitletters = set(c for c in [chr(i) for i in xrange(256)]
2355 _aliassyminitletters = set(c for c in [chr(i) for i in xrange(256)]
2356 if c.isalnum() or c in '._@$' or ord(c) > 127)
2356 if c.isalnum() or c in '._@$' or ord(c) > 127)
2357
2357
2358 def _tokenizealias(program, lookup=None):
2358 def _tokenizealias(program, lookup=None):
2359 """Parse alias declaration/definition into a stream of tokens
2359 """Parse alias declaration/definition into a stream of tokens
2360
2360
2361 This allows symbol names to use also ``$`` as an initial letter
2361 This allows symbol names to use also ``$`` as an initial letter
2362 (for backward compatibility), and callers of this function should
2362 (for backward compatibility), and callers of this function should
2363 examine whether ``$`` is used also for unexpected symbols or not.
2363 examine whether ``$`` is used also for unexpected symbols or not.
2364 """
2364 """
2365 return tokenize(program, lookup=lookup,
2365 return tokenize(program, lookup=lookup,
2366 syminitletters=_aliassyminitletters)
2366 syminitletters=_aliassyminitletters)
2367
2367
2368 def _parsealiasdecl(decl):
2368 def _parsealiasdecl(decl):
2369 """Parse alias declaration ``decl``
2369 """Parse alias declaration ``decl``
2370
2370
2371 This returns ``(name, tree, args, errorstr)`` tuple:
2371 This returns ``(name, tree, args, errorstr)`` tuple:
2372
2372
2373 - ``name``: of declared alias (may be ``decl`` itself at error)
2373 - ``name``: of declared alias (may be ``decl`` itself at error)
2374 - ``tree``: parse result (or ``None`` at error)
2374 - ``tree``: parse result (or ``None`` at error)
2375 - ``args``: list of alias argument names (or None for symbol declaration)
2375 - ``args``: list of alias argument names (or None for symbol declaration)
2376 - ``errorstr``: detail about detected error (or None)
2376 - ``errorstr``: detail about detected error (or None)
2377
2377
2378 >>> _parsealiasdecl('foo')
2378 >>> _parsealiasdecl('foo')
2379 ('foo', ('symbol', 'foo'), None, None)
2379 ('foo', ('symbol', 'foo'), None, None)
2380 >>> _parsealiasdecl('$foo')
2380 >>> _parsealiasdecl('$foo')
2381 ('$foo', None, None, "'$' not for alias arguments")
2381 ('$foo', None, None, "'$' not for alias arguments")
2382 >>> _parsealiasdecl('foo::bar')
2382 >>> _parsealiasdecl('foo::bar')
2383 ('foo::bar', None, None, 'invalid format')
2383 ('foo::bar', None, None, 'invalid format')
2384 >>> _parsealiasdecl('foo bar')
2384 >>> _parsealiasdecl('foo bar')
2385 ('foo bar', None, None, 'at 4: invalid token')
2385 ('foo bar', None, None, 'at 4: invalid token')
2386 >>> _parsealiasdecl('foo()')
2386 >>> _parsealiasdecl('foo()')
2387 ('foo', ('func', ('symbol', 'foo')), [], None)
2387 ('foo', ('func', ('symbol', 'foo')), [], None)
2388 >>> _parsealiasdecl('$foo()')
2388 >>> _parsealiasdecl('$foo()')
2389 ('$foo()', None, None, "'$' not for alias arguments")
2389 ('$foo()', None, None, "'$' not for alias arguments")
2390 >>> _parsealiasdecl('foo($1, $2)')
2390 >>> _parsealiasdecl('foo($1, $2)')
2391 ('foo', ('func', ('symbol', 'foo')), ['$1', '$2'], None)
2391 ('foo', ('func', ('symbol', 'foo')), ['$1', '$2'], None)
2392 >>> _parsealiasdecl('foo(bar_bar, baz.baz)')
2392 >>> _parsealiasdecl('foo(bar_bar, baz.baz)')
2393 ('foo', ('func', ('symbol', 'foo')), ['bar_bar', 'baz.baz'], None)
2393 ('foo', ('func', ('symbol', 'foo')), ['bar_bar', 'baz.baz'], None)
2394 >>> _parsealiasdecl('foo($1, $2, nested($1, $2))')
2394 >>> _parsealiasdecl('foo($1, $2, nested($1, $2))')
2395 ('foo($1, $2, nested($1, $2))', None, None, 'invalid argument list')
2395 ('foo($1, $2, nested($1, $2))', None, None, 'invalid argument list')
2396 >>> _parsealiasdecl('foo(bar($1, $2))')
2396 >>> _parsealiasdecl('foo(bar($1, $2))')
2397 ('foo(bar($1, $2))', None, None, 'invalid argument list')
2397 ('foo(bar($1, $2))', None, None, 'invalid argument list')
2398 >>> _parsealiasdecl('foo("string")')
2398 >>> _parsealiasdecl('foo("string")')
2399 ('foo("string")', None, None, 'invalid argument list')
2399 ('foo("string")', None, None, 'invalid argument list')
2400 >>> _parsealiasdecl('foo($1, $2')
2400 >>> _parsealiasdecl('foo($1, $2')
2401 ('foo($1, $2', None, None, 'at 10: unexpected token: end')
2401 ('foo($1, $2', None, None, 'at 10: unexpected token: end')
2402 >>> _parsealiasdecl('foo("string')
2402 >>> _parsealiasdecl('foo("string')
2403 ('foo("string', None, None, 'at 5: unterminated string')
2403 ('foo("string', None, None, 'at 5: unterminated string')
2404 >>> _parsealiasdecl('foo($1, $2, $1)')
2404 >>> _parsealiasdecl('foo($1, $2, $1)')
2405 ('foo', None, None, 'argument names collide with each other')
2405 ('foo', None, None, 'argument names collide with each other')
2406 """
2406 """
2407 p = parser.parser(elements)
2407 p = parser.parser(elements)
2408 try:
2408 try:
2409 tree, pos = p.parse(_tokenizealias(decl))
2409 tree, pos = p.parse(_tokenizealias(decl))
2410 if (pos != len(decl)):
2410 if (pos != len(decl)):
2411 raise error.ParseError(_('invalid token'), pos)
2411 raise error.ParseError(_('invalid token'), pos)
2412
2412
2413 if isvalidsymbol(tree):
2413 if isvalidsymbol(tree):
2414 # "name = ...." style
2414 # "name = ...." style
2415 name = getsymbol(tree)
2415 name = getsymbol(tree)
2416 if name.startswith('$'):
2416 if name.startswith('$'):
2417 return (decl, None, None, _("'$' not for alias arguments"))
2417 return (decl, None, None, _("'$' not for alias arguments"))
2418 return (name, ('symbol', name), None, None)
2418 return (name, ('symbol', name), None, None)
2419
2419
2420 if isvalidfunc(tree):
2420 if isvalidfunc(tree):
2421 # "name(arg, ....) = ...." style
2421 # "name(arg, ....) = ...." style
2422 name = getfuncname(tree)
2422 name = getfuncname(tree)
2423 if name.startswith('$'):
2423 if name.startswith('$'):
2424 return (decl, None, None, _("'$' not for alias arguments"))
2424 return (decl, None, None, _("'$' not for alias arguments"))
2425 args = []
2425 args = []
2426 for arg in getfuncargs(tree):
2426 for arg in getfuncargs(tree):
2427 if not isvalidsymbol(arg):
2427 if not isvalidsymbol(arg):
2428 return (decl, None, None, _("invalid argument list"))
2428 return (decl, None, None, _("invalid argument list"))
2429 args.append(getsymbol(arg))
2429 args.append(getsymbol(arg))
2430 if len(args) != len(set(args)):
2430 if len(args) != len(set(args)):
2431 return (name, None, None,
2431 return (name, None, None,
2432 _("argument names collide with each other"))
2432 _("argument names collide with each other"))
2433 return (name, ('func', ('symbol', name)), args, None)
2433 return (name, ('func', ('symbol', name)), args, None)
2434
2434
2435 return (decl, None, None, _("invalid format"))
2435 return (decl, None, None, _("invalid format"))
2436 except error.ParseError as inst:
2436 except error.ParseError as inst:
2437 return (decl, None, None, parseerrordetail(inst))
2437 return (decl, None, None, parseerrordetail(inst))
2438
2438
2439 def _parsealiasdefn(defn, args):
2439 def _parsealiasdefn(defn, args):
2440 """Parse alias definition ``defn``
2440 """Parse alias definition ``defn``
2441
2441
2442 This function also replaces alias argument references in the
2442 This function also replaces alias argument references in the
2443 specified definition by ``_aliasarg(ARGNAME)``.
2443 specified definition by ``_aliasarg(ARGNAME)``.
2444
2444
2445 ``args`` is a list of alias argument names, or None if the alias
2445 ``args`` is a list of alias argument names, or None if the alias
2446 is declared as a symbol.
2446 is declared as a symbol.
2447
2447
2448 This returns "tree" as parsing result.
2448 This returns "tree" as parsing result.
2449
2449
2450 >>> args = ['$1', '$2', 'foo']
2450 >>> args = ['$1', '$2', 'foo']
2451 >>> print prettyformat(_parsealiasdefn('$1 or foo', args))
2451 >>> print prettyformat(_parsealiasdefn('$1 or foo', args))
2452 (or
2452 (or
2453 (func
2453 (func
2454 ('symbol', '_aliasarg')
2454 ('symbol', '_aliasarg')
2455 ('string', '$1'))
2455 ('string', '$1'))
2456 (func
2456 (func
2457 ('symbol', '_aliasarg')
2457 ('symbol', '_aliasarg')
2458 ('string', 'foo')))
2458 ('string', 'foo')))
2459 >>> try:
2459 >>> try:
2460 ... _parsealiasdefn('$1 or $bar', args)
2460 ... _parsealiasdefn('$1 or $bar', args)
2461 ... except error.ParseError, inst:
2461 ... except error.ParseError, inst:
2462 ... print parseerrordetail(inst)
2462 ... print parseerrordetail(inst)
2463 at 6: '$' not for alias arguments
2463 at 6: '$' not for alias arguments
2464 >>> args = ['$1', '$10', 'foo']
2464 >>> args = ['$1', '$10', 'foo']
2465 >>> print prettyformat(_parsealiasdefn('$10 or foobar', args))
2465 >>> print prettyformat(_parsealiasdefn('$10 or foobar', args))
2466 (or
2466 (or
2467 (func
2467 (func
2468 ('symbol', '_aliasarg')
2468 ('symbol', '_aliasarg')
2469 ('string', '$10'))
2469 ('string', '$10'))
2470 ('symbol', 'foobar'))
2470 ('symbol', 'foobar'))
2471 >>> print prettyformat(_parsealiasdefn('"$1" or "foo"', args))
2471 >>> print prettyformat(_parsealiasdefn('"$1" or "foo"', args))
2472 (or
2472 (or
2473 ('string', '$1')
2473 ('string', '$1')
2474 ('string', 'foo'))
2474 ('string', 'foo'))
2475 """
2475 """
2476 def tokenizedefn(program, lookup=None):
2476 def tokenizedefn(program, lookup=None):
2477 if args:
2477 if args:
2478 argset = set(args)
2478 argset = set(args)
2479 else:
2479 else:
2480 argset = set()
2480 argset = set()
2481
2481
2482 for t, value, pos in _tokenizealias(program, lookup=lookup):
2482 for t, value, pos in _tokenizealias(program, lookup=lookup):
2483 if t == 'symbol':
2483 if t == 'symbol':
2484 if value in argset:
2484 if value in argset:
2485 # emulate tokenization of "_aliasarg('ARGNAME')":
2485 # emulate tokenization of "_aliasarg('ARGNAME')":
2486 # "_aliasarg()" is an unknown symbol only used separate
2486 # "_aliasarg()" is an unknown symbol only used separate
2487 # alias argument placeholders from regular strings.
2487 # alias argument placeholders from regular strings.
2488 yield ('symbol', '_aliasarg', pos)
2488 yield ('symbol', '_aliasarg', pos)
2489 yield ('(', None, pos)
2489 yield ('(', None, pos)
2490 yield ('string', value, pos)
2490 yield ('string', value, pos)
2491 yield (')', None, pos)
2491 yield (')', None, pos)
2492 continue
2492 continue
2493 elif value.startswith('$'):
2493 elif value.startswith('$'):
2494 raise error.ParseError(_("'$' not for alias arguments"),
2494 raise error.ParseError(_("'$' not for alias arguments"),
2495 pos)
2495 pos)
2496 yield (t, value, pos)
2496 yield (t, value, pos)
2497
2497
2498 p = parser.parser(elements)
2498 p = parser.parser(elements)
2499 tree, pos = p.parse(tokenizedefn(defn))
2499 tree, pos = p.parse(tokenizedefn(defn))
2500 if pos != len(defn):
2500 if pos != len(defn):
2501 raise error.ParseError(_('invalid token'), pos)
2501 raise error.ParseError(_('invalid token'), pos)
2502 return parser.simplifyinfixops(tree, ('or',))
2502 return parser.simplifyinfixops(tree, ('or',))
2503
2503
2504 class revsetalias(object):
2504 class revsetalias(object):
2505 # whether own `error` information is already shown or not.
2505 # whether own `error` information is already shown or not.
2506 # this avoids showing same warning multiple times at each `findaliases`.
2506 # this avoids showing same warning multiple times at each `findaliases`.
2507 warned = False
2507 warned = False
2508
2508
2509 def __init__(self, name, value):
2509 def __init__(self, name, value):
2510 '''Aliases like:
2510 '''Aliases like:
2511
2511
2512 h = heads(default)
2512 h = heads(default)
2513 b($1) = ancestors($1) - ancestors(default)
2513 b($1) = ancestors($1) - ancestors(default)
2514 '''
2514 '''
2515 self.name, self.tree, self.args, self.error = _parsealiasdecl(name)
2515 self.name, self.tree, self.args, self.error = _parsealiasdecl(name)
2516 if self.error:
2516 if self.error:
2517 self.error = _('failed to parse the declaration of revset alias'
2517 self.error = _('failed to parse the declaration of revset alias'
2518 ' "%s": %s') % (self.name, self.error)
2518 ' "%s": %s') % (self.name, self.error)
2519 return
2519 return
2520
2520
2521 try:
2521 try:
2522 self.replacement = _parsealiasdefn(value, self.args)
2522 self.replacement = _parsealiasdefn(value, self.args)
2523 # Check for placeholder injection
2523 # Check for placeholder injection
2524 _checkaliasarg(self.replacement, self.args)
2524 _checkaliasarg(self.replacement, self.args)
2525 except error.ParseError as inst:
2525 except error.ParseError as inst:
2526 self.error = _('failed to parse the definition of revset alias'
2526 self.error = _('failed to parse the definition of revset alias'
2527 ' "%s": %s') % (self.name, parseerrordetail(inst))
2527 ' "%s": %s') % (self.name, parseerrordetail(inst))
2528
2528
2529 def _getalias(aliases, tree):
2529 def _getalias(aliases, tree):
2530 """If tree looks like an unexpanded alias, return it. Return None
2530 """If tree looks like an unexpanded alias, return it. Return None
2531 otherwise.
2531 otherwise.
2532 """
2532 """
2533 if isinstance(tree, tuple) and tree:
2533 if isinstance(tree, tuple) and tree:
2534 if tree[0] == 'symbol' and len(tree) == 2:
2534 if tree[0] == 'symbol' and len(tree) == 2:
2535 name = tree[1]
2535 name = tree[1]
2536 alias = aliases.get(name)
2536 alias = aliases.get(name)
2537 if alias and alias.args is None and alias.tree == tree:
2537 if alias and alias.args is None and alias.tree == tree:
2538 return alias
2538 return alias
2539 if tree[0] == 'func' and len(tree) > 1:
2539 if tree[0] == 'func' and len(tree) > 1:
2540 if tree[1][0] == 'symbol' and len(tree[1]) == 2:
2540 if tree[1][0] == 'symbol' and len(tree[1]) == 2:
2541 name = tree[1][1]
2541 name = tree[1][1]
2542 alias = aliases.get(name)
2542 alias = aliases.get(name)
2543 if alias and alias.args is not None and alias.tree == tree[:2]:
2543 if alias and alias.args is not None and alias.tree == tree[:2]:
2544 return alias
2544 return alias
2545 return None
2545 return None
2546
2546
2547 def _expandargs(tree, args):
2547 def _expandargs(tree, args):
2548 """Replace _aliasarg instances with the substitution value of the
2548 """Replace _aliasarg instances with the substitution value of the
2549 same name in args, recursively.
2549 same name in args, recursively.
2550 """
2550 """
2551 if not tree or not isinstance(tree, tuple):
2551 if not tree or not isinstance(tree, tuple):
2552 return tree
2552 return tree
2553 arg = _getaliasarg(tree)
2553 arg = _getaliasarg(tree)
2554 if arg is not None:
2554 if arg is not None:
2555 return args[arg]
2555 return args[arg]
2556 return tuple(_expandargs(t, args) for t in tree)
2556 return tuple(_expandargs(t, args) for t in tree)
2557
2557
2558 def _expandaliases(aliases, tree, expanding, cache):
2558 def _expandaliases(aliases, tree, expanding, cache):
2559 """Expand aliases in tree, recursively.
2559 """Expand aliases in tree, recursively.
2560
2560
2561 'aliases' is a dictionary mapping user defined aliases to
2561 'aliases' is a dictionary mapping user defined aliases to
2562 revsetalias objects.
2562 revsetalias objects.
2563 """
2563 """
2564 if not isinstance(tree, tuple):
2564 if not isinstance(tree, tuple):
2565 # Do not expand raw strings
2565 # Do not expand raw strings
2566 return tree
2566 return tree
2567 alias = _getalias(aliases, tree)
2567 alias = _getalias(aliases, tree)
2568 if alias is not None:
2568 if alias is not None:
2569 if alias.error:
2569 if alias.error:
2570 raise util.Abort(alias.error)
2570 raise util.Abort(alias.error)
2571 if alias in expanding:
2571 if alias in expanding:
2572 raise error.ParseError(_('infinite expansion of revset alias "%s" '
2572 raise error.ParseError(_('infinite expansion of revset alias "%s" '
2573 'detected') % alias.name)
2573 'detected') % alias.name)
2574 expanding.append(alias)
2574 expanding.append(alias)
2575 if alias.name not in cache:
2575 if alias.name not in cache:
2576 cache[alias.name] = _expandaliases(aliases, alias.replacement,
2576 cache[alias.name] = _expandaliases(aliases, alias.replacement,
2577 expanding, cache)
2577 expanding, cache)
2578 result = cache[alias.name]
2578 result = cache[alias.name]
2579 expanding.pop()
2579 expanding.pop()
2580 if alias.args is not None:
2580 if alias.args is not None:
2581 l = getlist(tree[2])
2581 l = getlist(tree[2])
2582 if len(l) != len(alias.args):
2582 if len(l) != len(alias.args):
2583 raise error.ParseError(
2583 raise error.ParseError(
2584 _('invalid number of arguments: %s') % len(l))
2584 _('invalid number of arguments: %s') % len(l))
2585 l = [_expandaliases(aliases, a, [], cache) for a in l]
2585 l = [_expandaliases(aliases, a, [], cache) for a in l]
2586 result = _expandargs(result, dict(zip(alias.args, l)))
2586 result = _expandargs(result, dict(zip(alias.args, l)))
2587 else:
2587 else:
2588 result = tuple(_expandaliases(aliases, t, expanding, cache)
2588 result = tuple(_expandaliases(aliases, t, expanding, cache)
2589 for t in tree)
2589 for t in tree)
2590 return result
2590 return result
2591
2591
2592 def findaliases(ui, tree, showwarning=None):
2592 def findaliases(ui, tree, showwarning=None):
2593 _checkaliasarg(tree)
2593 _checkaliasarg(tree)
2594 aliases = {}
2594 aliases = {}
2595 for k, v in ui.configitems('revsetalias'):
2595 for k, v in ui.configitems('revsetalias'):
2596 alias = revsetalias(k, v)
2596 alias = revsetalias(k, v)
2597 aliases[alias.name] = alias
2597 aliases[alias.name] = alias
2598 tree = _expandaliases(aliases, tree, [], {})
2598 tree = _expandaliases(aliases, tree, [], {})
2599 if showwarning:
2599 if showwarning:
2600 # warn about problematic (but not referred) aliases
2600 # warn about problematic (but not referred) aliases
2601 for name, alias in sorted(aliases.iteritems()):
2601 for name, alias in sorted(aliases.iteritems()):
2602 if alias.error and not alias.warned:
2602 if alias.error and not alias.warned:
2603 showwarning(_('warning: %s\n') % (alias.error))
2603 showwarning(_('warning: %s\n') % (alias.error))
2604 alias.warned = True
2604 alias.warned = True
2605 return tree
2605 return tree
2606
2606
2607 def foldconcat(tree):
2607 def foldconcat(tree):
2608 """Fold elements to be concatenated by `##`
2608 """Fold elements to be concatenated by `##`
2609 """
2609 """
2610 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
2610 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
2611 return tree
2611 return tree
2612 if tree[0] == '_concat':
2612 if tree[0] == '_concat':
2613 pending = [tree]
2613 pending = [tree]
2614 l = []
2614 l = []
2615 while pending:
2615 while pending:
2616 e = pending.pop()
2616 e = pending.pop()
2617 if e[0] == '_concat':
2617 if e[0] == '_concat':
2618 pending.extend(reversed(e[1:]))
2618 pending.extend(reversed(e[1:]))
2619 elif e[0] in ('string', 'symbol'):
2619 elif e[0] in ('string', 'symbol'):
2620 l.append(e[1])
2620 l.append(e[1])
2621 else:
2621 else:
2622 msg = _("\"##\" can't concatenate \"%s\" element") % (e[0])
2622 msg = _("\"##\" can't concatenate \"%s\" element") % (e[0])
2623 raise error.ParseError(msg)
2623 raise error.ParseError(msg)
2624 return ('string', ''.join(l))
2624 return ('string', ''.join(l))
2625 else:
2625 else:
2626 return tuple(foldconcat(t) for t in tree)
2626 return tuple(foldconcat(t) for t in tree)
2627
2627
2628 def parse(spec, lookup=None):
2628 def parse(spec, lookup=None):
2629 p = parser.parser(elements)
2629 p = parser.parser(elements)
2630 tree, pos = p.parse(tokenize(spec, lookup=lookup))
2630 tree, pos = p.parse(tokenize(spec, lookup=lookup))
2631 if pos != len(spec):
2631 if pos != len(spec):
2632 raise error.ParseError(_("invalid token"), pos)
2632 raise error.ParseError(_("invalid token"), pos)
2633 return parser.simplifyinfixops(tree, ('or',))
2633 return parser.simplifyinfixops(tree, ('or',))
2634
2634
2635 def posttreebuilthook(tree, repo):
2635 def posttreebuilthook(tree, repo):
2636 # hook for extensions to execute code on the optimized tree
2636 # hook for extensions to execute code on the optimized tree
2637 pass
2637 pass
2638
2638
2639 def match(ui, spec, repo=None):
2639 def match(ui, spec, repo=None):
2640 if not spec:
2640 if not spec:
2641 raise error.ParseError(_("empty query"))
2641 raise error.ParseError(_("empty query"))
2642 lookup = None
2642 lookup = None
2643 if repo:
2643 if repo:
2644 lookup = repo.__contains__
2644 lookup = repo.__contains__
2645 tree = parse(spec, lookup)
2645 tree = parse(spec, lookup)
2646 if ui:
2646 if ui:
2647 tree = findaliases(ui, tree, showwarning=ui.warn)
2647 tree = findaliases(ui, tree, showwarning=ui.warn)
2648 tree = foldconcat(tree)
2648 tree = foldconcat(tree)
2649 weight, tree = optimize(tree, True)
2649 weight, tree = optimize(tree, True)
2650 posttreebuilthook(tree, repo)
2650 posttreebuilthook(tree, repo)
2651 def mfunc(repo, subset=None):
2651 def mfunc(repo, subset=None):
2652 if subset is None:
2652 if subset is None:
2653 subset = fullreposet(repo)
2653 subset = fullreposet(repo)
2654 if util.safehasattr(subset, 'isascending'):
2654 if util.safehasattr(subset, 'isascending'):
2655 result = getset(repo, subset, tree)
2655 result = getset(repo, subset, tree)
2656 else:
2656 else:
2657 result = getset(repo, baseset(subset), tree)
2657 result = getset(repo, baseset(subset), tree)
2658 return result
2658 return result
2659 return mfunc
2659 return mfunc
2660
2660
2661 def formatspec(expr, *args):
2661 def formatspec(expr, *args):
2662 '''
2662 '''
2663 This is a convenience function for using revsets internally, and
2663 This is a convenience function for using revsets internally, and
2664 escapes arguments appropriately. Aliases are intentionally ignored
2664 escapes arguments appropriately. Aliases are intentionally ignored
2665 so that intended expression behavior isn't accidentally subverted.
2665 so that intended expression behavior isn't accidentally subverted.
2666
2666
2667 Supported arguments:
2667 Supported arguments:
2668
2668
2669 %r = revset expression, parenthesized
2669 %r = revset expression, parenthesized
2670 %d = int(arg), no quoting
2670 %d = int(arg), no quoting
2671 %s = string(arg), escaped and single-quoted
2671 %s = string(arg), escaped and single-quoted
2672 %b = arg.branch(), escaped and single-quoted
2672 %b = arg.branch(), escaped and single-quoted
2673 %n = hex(arg), single-quoted
2673 %n = hex(arg), single-quoted
2674 %% = a literal '%'
2674 %% = a literal '%'
2675
2675
2676 Prefixing the type with 'l' specifies a parenthesized list of that type.
2676 Prefixing the type with 'l' specifies a parenthesized list of that type.
2677
2677
2678 >>> formatspec('%r:: and %lr', '10 or 11', ("this()", "that()"))
2678 >>> formatspec('%r:: and %lr', '10 or 11', ("this()", "that()"))
2679 '(10 or 11):: and ((this()) or (that()))'
2679 '(10 or 11):: and ((this()) or (that()))'
2680 >>> formatspec('%d:: and not %d::', 10, 20)
2680 >>> formatspec('%d:: and not %d::', 10, 20)
2681 '10:: and not 20::'
2681 '10:: and not 20::'
2682 >>> formatspec('%ld or %ld', [], [1])
2682 >>> formatspec('%ld or %ld', [], [1])
2683 "_list('') or 1"
2683 "_list('') or 1"
2684 >>> formatspec('keyword(%s)', 'foo\\xe9')
2684 >>> formatspec('keyword(%s)', 'foo\\xe9')
2685 "keyword('foo\\\\xe9')"
2685 "keyword('foo\\\\xe9')"
2686 >>> b = lambda: 'default'
2686 >>> b = lambda: 'default'
2687 >>> b.branch = b
2687 >>> b.branch = b
2688 >>> formatspec('branch(%b)', b)
2688 >>> formatspec('branch(%b)', b)
2689 "branch('default')"
2689 "branch('default')"
2690 >>> formatspec('root(%ls)', ['a', 'b', 'c', 'd'])
2690 >>> formatspec('root(%ls)', ['a', 'b', 'c', 'd'])
2691 "root(_list('a\\x00b\\x00c\\x00d'))"
2691 "root(_list('a\\x00b\\x00c\\x00d'))"
2692 '''
2692 '''
2693
2693
2694 def quote(s):
2694 def quote(s):
2695 return repr(str(s))
2695 return repr(str(s))
2696
2696
2697 def argtype(c, arg):
2697 def argtype(c, arg):
2698 if c == 'd':
2698 if c == 'd':
2699 return str(int(arg))
2699 return str(int(arg))
2700 elif c == 's':
2700 elif c == 's':
2701 return quote(arg)
2701 return quote(arg)
2702 elif c == 'r':
2702 elif c == 'r':
2703 parse(arg) # make sure syntax errors are confined
2703 parse(arg) # make sure syntax errors are confined
2704 return '(%s)' % arg
2704 return '(%s)' % arg
2705 elif c == 'n':
2705 elif c == 'n':
2706 return quote(node.hex(arg))
2706 return quote(node.hex(arg))
2707 elif c == 'b':
2707 elif c == 'b':
2708 return quote(arg.branch())
2708 return quote(arg.branch())
2709
2709
2710 def listexp(s, t):
2710 def listexp(s, t):
2711 l = len(s)
2711 l = len(s)
2712 if l == 0:
2712 if l == 0:
2713 return "_list('')"
2713 return "_list('')"
2714 elif l == 1:
2714 elif l == 1:
2715 return argtype(t, s[0])
2715 return argtype(t, s[0])
2716 elif t == 'd':
2716 elif t == 'd':
2717 return "_intlist('%s')" % "\0".join(str(int(a)) for a in s)
2717 return "_intlist('%s')" % "\0".join(str(int(a)) for a in s)
2718 elif t == 's':
2718 elif t == 's':
2719 return "_list('%s')" % "\0".join(s)
2719 return "_list('%s')" % "\0".join(s)
2720 elif t == 'n':
2720 elif t == 'n':
2721 return "_hexlist('%s')" % "\0".join(node.hex(a) for a in s)
2721 return "_hexlist('%s')" % "\0".join(node.hex(a) for a in s)
2722 elif t == 'b':
2722 elif t == 'b':
2723 return "_list('%s')" % "\0".join(a.branch() for a in s)
2723 return "_list('%s')" % "\0".join(a.branch() for a in s)
2724
2724
2725 m = l // 2
2725 m = l // 2
2726 return '(%s or %s)' % (listexp(s[:m], t), listexp(s[m:], t))
2726 return '(%s or %s)' % (listexp(s[:m], t), listexp(s[m:], t))
2727
2727
2728 ret = ''
2728 ret = ''
2729 pos = 0
2729 pos = 0
2730 arg = 0
2730 arg = 0
2731 while pos < len(expr):
2731 while pos < len(expr):
2732 c = expr[pos]
2732 c = expr[pos]
2733 if c == '%':
2733 if c == '%':
2734 pos += 1
2734 pos += 1
2735 d = expr[pos]
2735 d = expr[pos]
2736 if d == '%':
2736 if d == '%':
2737 ret += d
2737 ret += d
2738 elif d in 'dsnbr':
2738 elif d in 'dsnbr':
2739 ret += argtype(d, args[arg])
2739 ret += argtype(d, args[arg])
2740 arg += 1
2740 arg += 1
2741 elif d == 'l':
2741 elif d == 'l':
2742 # a list of some type
2742 # a list of some type
2743 pos += 1
2743 pos += 1
2744 d = expr[pos]
2744 d = expr[pos]
2745 ret += listexp(list(args[arg]), d)
2745 ret += listexp(list(args[arg]), d)
2746 arg += 1
2746 arg += 1
2747 else:
2747 else:
2748 raise util.Abort('unexpected revspec format character %s' % d)
2748 raise util.Abort('unexpected revspec format character %s' % d)
2749 else:
2749 else:
2750 ret += c
2750 ret += c
2751 pos += 1
2751 pos += 1
2752
2752
2753 return ret
2753 return ret
2754
2754
2755 def prettyformat(tree):
2755 def prettyformat(tree):
2756 return parser.prettyformat(tree, ('string', 'symbol'))
2756 return parser.prettyformat(tree, ('string', 'symbol'))
2757
2757
2758 def depth(tree):
2758 def depth(tree):
2759 if isinstance(tree, tuple):
2759 if isinstance(tree, tuple):
2760 return max(map(depth, tree)) + 1
2760 return max(map(depth, tree)) + 1
2761 else:
2761 else:
2762 return 0
2762 return 0
2763
2763
2764 def funcsused(tree):
2764 def funcsused(tree):
2765 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
2765 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
2766 return set()
2766 return set()
2767 else:
2767 else:
2768 funcs = set()
2768 funcs = set()
2769 for s in tree[1:]:
2769 for s in tree[1:]:
2770 funcs |= funcsused(s)
2770 funcs |= funcsused(s)
2771 if tree[0] == 'func':
2771 if tree[0] == 'func':
2772 funcs.add(tree[1][1])
2772 funcs.add(tree[1][1])
2773 return funcs
2773 return funcs
2774
2774
2775 class abstractsmartset(object):
2775 class abstractsmartset(object):
2776
2776
2777 def __nonzero__(self):
2777 def __nonzero__(self):
2778 """True if the smartset is not empty"""
2778 """True if the smartset is not empty"""
2779 raise NotImplementedError()
2779 raise NotImplementedError()
2780
2780
2781 def __contains__(self, rev):
2781 def __contains__(self, rev):
2782 """provide fast membership testing"""
2782 """provide fast membership testing"""
2783 raise NotImplementedError()
2783 raise NotImplementedError()
2784
2784
2785 def __iter__(self):
2785 def __iter__(self):
2786 """iterate the set in the order it is supposed to be iterated"""
2786 """iterate the set in the order it is supposed to be iterated"""
2787 raise NotImplementedError()
2787 raise NotImplementedError()
2788
2788
2789 # Attributes containing a function to perform a fast iteration in a given
2789 # Attributes containing a function to perform a fast iteration in a given
2790 # direction. A smartset can have none, one, or both defined.
2790 # direction. A smartset can have none, one, or both defined.
2791 #
2791 #
2792 # Default value is None instead of a function returning None to avoid
2792 # Default value is None instead of a function returning None to avoid
2793 # initializing an iterator just for testing if a fast method exists.
2793 # initializing an iterator just for testing if a fast method exists.
2794 fastasc = None
2794 fastasc = None
2795 fastdesc = None
2795 fastdesc = None
2796
2796
2797 def isascending(self):
2797 def isascending(self):
2798 """True if the set will iterate in ascending order"""
2798 """True if the set will iterate in ascending order"""
2799 raise NotImplementedError()
2799 raise NotImplementedError()
2800
2800
2801 def isdescending(self):
2801 def isdescending(self):
2802 """True if the set will iterate in descending order"""
2802 """True if the set will iterate in descending order"""
2803 raise NotImplementedError()
2803 raise NotImplementedError()
2804
2804
2805 def min(self):
2805 def min(self):
2806 """return the minimum element in the set"""
2806 """return the minimum element in the set"""
2807 if self.fastasc is not None:
2807 if self.fastasc is not None:
2808 for r in self.fastasc():
2808 for r in self.fastasc():
2809 return r
2809 return r
2810 raise ValueError('arg is an empty sequence')
2810 raise ValueError('arg is an empty sequence')
2811 return min(self)
2811 return min(self)
2812
2812
2813 def max(self):
2813 def max(self):
2814 """return the maximum element in the set"""
2814 """return the maximum element in the set"""
2815 if self.fastdesc is not None:
2815 if self.fastdesc is not None:
2816 for r in self.fastdesc():
2816 for r in self.fastdesc():
2817 return r
2817 return r
2818 raise ValueError('arg is an empty sequence')
2818 raise ValueError('arg is an empty sequence')
2819 return max(self)
2819 return max(self)
2820
2820
2821 def first(self):
2821 def first(self):
2822 """return the first element in the set (user iteration perspective)
2822 """return the first element in the set (user iteration perspective)
2823
2823
2824 Return None if the set is empty"""
2824 Return None if the set is empty"""
2825 raise NotImplementedError()
2825 raise NotImplementedError()
2826
2826
2827 def last(self):
2827 def last(self):
2828 """return the last element in the set (user iteration perspective)
2828 """return the last element in the set (user iteration perspective)
2829
2829
2830 Return None if the set is empty"""
2830 Return None if the set is empty"""
2831 raise NotImplementedError()
2831 raise NotImplementedError()
2832
2832
2833 def __len__(self):
2833 def __len__(self):
2834 """return the length of the smartsets
2834 """return the length of the smartsets
2835
2835
2836 This can be expensive on smartset that could be lazy otherwise."""
2836 This can be expensive on smartset that could be lazy otherwise."""
2837 raise NotImplementedError()
2837 raise NotImplementedError()
2838
2838
2839 def reverse(self):
2839 def reverse(self):
2840 """reverse the expected iteration order"""
2840 """reverse the expected iteration order"""
2841 raise NotImplementedError()
2841 raise NotImplementedError()
2842
2842
2843 def sort(self, reverse=True):
2843 def sort(self, reverse=True):
2844 """get the set to iterate in an ascending or descending order"""
2844 """get the set to iterate in an ascending or descending order"""
2845 raise NotImplementedError()
2845 raise NotImplementedError()
2846
2846
2847 def __and__(self, other):
2847 def __and__(self, other):
2848 """Returns a new object with the intersection of the two collections.
2848 """Returns a new object with the intersection of the two collections.
2849
2849
2850 This is part of the mandatory API for smartset."""
2850 This is part of the mandatory API for smartset."""
2851 if isinstance(other, fullreposet):
2851 if isinstance(other, fullreposet):
2852 return self
2852 return self
2853 return self.filter(other.__contains__, cache=False)
2853 return self.filter(other.__contains__, cache=False)
2854
2854
2855 def __add__(self, other):
2855 def __add__(self, other):
2856 """Returns a new object with the union of the two collections.
2856 """Returns a new object with the union of the two collections.
2857
2857
2858 This is part of the mandatory API for smartset."""
2858 This is part of the mandatory API for smartset."""
2859 return addset(self, other)
2859 return addset(self, other)
2860
2860
2861 def __sub__(self, other):
2861 def __sub__(self, other):
2862 """Returns a new object with the substraction of the two collections.
2862 """Returns a new object with the substraction of the two collections.
2863
2863
2864 This is part of the mandatory API for smartset."""
2864 This is part of the mandatory API for smartset."""
2865 c = other.__contains__
2865 c = other.__contains__
2866 return self.filter(lambda r: not c(r), cache=False)
2866 return self.filter(lambda r: not c(r), cache=False)
2867
2867
2868 def filter(self, condition, cache=True):
2868 def filter(self, condition, cache=True):
2869 """Returns this smartset filtered by condition as a new smartset.
2869 """Returns this smartset filtered by condition as a new smartset.
2870
2870
2871 `condition` is a callable which takes a revision number and returns a
2871 `condition` is a callable which takes a revision number and returns a
2872 boolean.
2872 boolean.
2873
2873
2874 This is part of the mandatory API for smartset."""
2874 This is part of the mandatory API for smartset."""
2875 # builtin cannot be cached. but do not needs to
2875 # builtin cannot be cached. but do not needs to
2876 if cache and util.safehasattr(condition, 'func_code'):
2876 if cache and util.safehasattr(condition, 'func_code'):
2877 condition = util.cachefunc(condition)
2877 condition = util.cachefunc(condition)
2878 return filteredset(self, condition)
2878 return filteredset(self, condition)
2879
2879
2880 class baseset(abstractsmartset):
2880 class baseset(abstractsmartset):
2881 """Basic data structure that represents a revset and contains the basic
2881 """Basic data structure that represents a revset and contains the basic
2882 operation that it should be able to perform.
2882 operation that it should be able to perform.
2883
2883
2884 Every method in this class should be implemented by any smartset class.
2884 Every method in this class should be implemented by any smartset class.
2885 """
2885 """
2886 def __init__(self, data=()):
2886 def __init__(self, data=()):
2887 if not isinstance(data, list):
2887 if not isinstance(data, list):
2888 data = list(data)
2888 data = list(data)
2889 self._list = data
2889 self._list = data
2890 self._ascending = None
2890 self._ascending = None
2891
2891
2892 @util.propertycache
2892 @util.propertycache
2893 def _set(self):
2893 def _set(self):
2894 return set(self._list)
2894 return set(self._list)
2895
2895
2896 @util.propertycache
2896 @util.propertycache
2897 def _asclist(self):
2897 def _asclist(self):
2898 asclist = self._list[:]
2898 asclist = self._list[:]
2899 asclist.sort()
2899 asclist.sort()
2900 return asclist
2900 return asclist
2901
2901
2902 def __iter__(self):
2902 def __iter__(self):
2903 if self._ascending is None:
2903 if self._ascending is None:
2904 return iter(self._list)
2904 return iter(self._list)
2905 elif self._ascending:
2905 elif self._ascending:
2906 return iter(self._asclist)
2906 return iter(self._asclist)
2907 else:
2907 else:
2908 return reversed(self._asclist)
2908 return reversed(self._asclist)
2909
2909
2910 def fastasc(self):
2910 def fastasc(self):
2911 return iter(self._asclist)
2911 return iter(self._asclist)
2912
2912
2913 def fastdesc(self):
2913 def fastdesc(self):
2914 return reversed(self._asclist)
2914 return reversed(self._asclist)
2915
2915
2916 @util.propertycache
2916 @util.propertycache
2917 def __contains__(self):
2917 def __contains__(self):
2918 return self._set.__contains__
2918 return self._set.__contains__
2919
2919
2920 def __nonzero__(self):
2920 def __nonzero__(self):
2921 return bool(self._list)
2921 return bool(self._list)
2922
2922
2923 def sort(self, reverse=False):
2923 def sort(self, reverse=False):
2924 self._ascending = not bool(reverse)
2924 self._ascending = not bool(reverse)
2925
2925
2926 def reverse(self):
2926 def reverse(self):
2927 if self._ascending is None:
2927 if self._ascending is None:
2928 self._list.reverse()
2928 self._list.reverse()
2929 else:
2929 else:
2930 self._ascending = not self._ascending
2930 self._ascending = not self._ascending
2931
2931
2932 def __len__(self):
2932 def __len__(self):
2933 return len(self._list)
2933 return len(self._list)
2934
2934
2935 def isascending(self):
2935 def isascending(self):
2936 """Returns True if the collection is ascending order, False if not.
2936 """Returns True if the collection is ascending order, False if not.
2937
2937
2938 This is part of the mandatory API for smartset."""
2938 This is part of the mandatory API for smartset."""
2939 if len(self) <= 1:
2939 if len(self) <= 1:
2940 return True
2940 return True
2941 return self._ascending is not None and self._ascending
2941 return self._ascending is not None and self._ascending
2942
2942
2943 def isdescending(self):
2943 def isdescending(self):
2944 """Returns True if the collection is descending order, False if not.
2944 """Returns True if the collection is descending order, False if not.
2945
2945
2946 This is part of the mandatory API for smartset."""
2946 This is part of the mandatory API for smartset."""
2947 if len(self) <= 1:
2947 if len(self) <= 1:
2948 return True
2948 return True
2949 return self._ascending is not None and not self._ascending
2949 return self._ascending is not None and not self._ascending
2950
2950
2951 def first(self):
2951 def first(self):
2952 if self:
2952 if self:
2953 if self._ascending is None:
2953 if self._ascending is None:
2954 return self._list[0]
2954 return self._list[0]
2955 elif self._ascending:
2955 elif self._ascending:
2956 return self._asclist[0]
2956 return self._asclist[0]
2957 else:
2957 else:
2958 return self._asclist[-1]
2958 return self._asclist[-1]
2959 return None
2959 return None
2960
2960
2961 def last(self):
2961 def last(self):
2962 if self:
2962 if self:
2963 if self._ascending is None:
2963 if self._ascending is None:
2964 return self._list[-1]
2964 return self._list[-1]
2965 elif self._ascending:
2965 elif self._ascending:
2966 return self._asclist[-1]
2966 return self._asclist[-1]
2967 else:
2967 else:
2968 return self._asclist[0]
2968 return self._asclist[0]
2969 return None
2969 return None
2970
2970
2971 def __repr__(self):
2971 def __repr__(self):
2972 d = {None: '', False: '-', True: '+'}[self._ascending]
2972 d = {None: '', False: '-', True: '+'}[self._ascending]
2973 return '<%s%s %r>' % (type(self).__name__, d, self._list)
2973 return '<%s%s %r>' % (type(self).__name__, d, self._list)
2974
2974
2975 class filteredset(abstractsmartset):
2975 class filteredset(abstractsmartset):
2976 """Duck type for baseset class which iterates lazily over the revisions in
2976 """Duck type for baseset class which iterates lazily over the revisions in
2977 the subset and contains a function which tests for membership in the
2977 the subset and contains a function which tests for membership in the
2978 revset
2978 revset
2979 """
2979 """
2980 def __init__(self, subset, condition=lambda x: True):
2980 def __init__(self, subset, condition=lambda x: True):
2981 """
2981 """
2982 condition: a function that decide whether a revision in the subset
2982 condition: a function that decide whether a revision in the subset
2983 belongs to the revset or not.
2983 belongs to the revset or not.
2984 """
2984 """
2985 self._subset = subset
2985 self._subset = subset
2986 self._condition = condition
2986 self._condition = condition
2987 self._cache = {}
2987 self._cache = {}
2988
2988
2989 def __contains__(self, x):
2989 def __contains__(self, x):
2990 c = self._cache
2990 c = self._cache
2991 if x not in c:
2991 if x not in c:
2992 v = c[x] = x in self._subset and self._condition(x)
2992 v = c[x] = x in self._subset and self._condition(x)
2993 return v
2993 return v
2994 return c[x]
2994 return c[x]
2995
2995
2996 def __iter__(self):
2996 def __iter__(self):
2997 return self._iterfilter(self._subset)
2997 return self._iterfilter(self._subset)
2998
2998
2999 def _iterfilter(self, it):
2999 def _iterfilter(self, it):
3000 cond = self._condition
3000 cond = self._condition
3001 for x in it:
3001 for x in it:
3002 if cond(x):
3002 if cond(x):
3003 yield x
3003 yield x
3004
3004
3005 @property
3005 @property
3006 def fastasc(self):
3006 def fastasc(self):
3007 it = self._subset.fastasc
3007 it = self._subset.fastasc
3008 if it is None:
3008 if it is None:
3009 return None
3009 return None
3010 return lambda: self._iterfilter(it())
3010 return lambda: self._iterfilter(it())
3011
3011
3012 @property
3012 @property
3013 def fastdesc(self):
3013 def fastdesc(self):
3014 it = self._subset.fastdesc
3014 it = self._subset.fastdesc
3015 if it is None:
3015 if it is None:
3016 return None
3016 return None
3017 return lambda: self._iterfilter(it())
3017 return lambda: self._iterfilter(it())
3018
3018
3019 def __nonzero__(self):
3019 def __nonzero__(self):
3020 for r in self:
3020 for r in self:
3021 return True
3021 return True
3022 return False
3022 return False
3023
3023
3024 def __len__(self):
3024 def __len__(self):
3025 # Basic implementation to be changed in future patches.
3025 # Basic implementation to be changed in future patches.
3026 l = baseset([r for r in self])
3026 l = baseset([r for r in self])
3027 return len(l)
3027 return len(l)
3028
3028
3029 def sort(self, reverse=False):
3029 def sort(self, reverse=False):
3030 self._subset.sort(reverse=reverse)
3030 self._subset.sort(reverse=reverse)
3031
3031
3032 def reverse(self):
3032 def reverse(self):
3033 self._subset.reverse()
3033 self._subset.reverse()
3034
3034
3035 def isascending(self):
3035 def isascending(self):
3036 return self._subset.isascending()
3036 return self._subset.isascending()
3037
3037
3038 def isdescending(self):
3038 def isdescending(self):
3039 return self._subset.isdescending()
3039 return self._subset.isdescending()
3040
3040
3041 def first(self):
3041 def first(self):
3042 for x in self:
3042 for x in self:
3043 return x
3043 return x
3044 return None
3044 return None
3045
3045
3046 def last(self):
3046 def last(self):
3047 it = None
3047 it = None
3048 if self.isascending():
3048 if self.isascending():
3049 it = self.fastdesc
3049 it = self.fastdesc
3050 elif self.isdescending():
3050 elif self.isdescending():
3051 it = self.fastasc
3051 it = self.fastasc
3052 if it is not None:
3052 if it is not None:
3053 for x in it():
3053 for x in it():
3054 return x
3054 return x
3055 return None #empty case
3055 return None #empty case
3056 else:
3056 else:
3057 x = None
3057 x = None
3058 for x in self:
3058 for x in self:
3059 pass
3059 pass
3060 return x
3060 return x
3061
3061
3062 def __repr__(self):
3062 def __repr__(self):
3063 return '<%s %r>' % (type(self).__name__, self._subset)
3063 return '<%s %r>' % (type(self).__name__, self._subset)
3064
3064
3065 # this function will be removed, or merged to addset or orset, when
3065 # this function will be removed, or merged to addset or orset, when
3066 # - scmutil.revrange() can be rewritten to not combine calculated smartsets
3066 # - scmutil.revrange() can be rewritten to not combine calculated smartsets
3067 # - or addset can handle more than two sets without balanced tree
3067 # - or addset can handle more than two sets without balanced tree
3068 def _combinesets(subsets):
3068 def _combinesets(subsets):
3069 """Create balanced tree of addsets representing union of given sets"""
3069 """Create balanced tree of addsets representing union of given sets"""
3070 if not subsets:
3070 if not subsets:
3071 return baseset()
3071 return baseset()
3072 if len(subsets) == 1:
3072 if len(subsets) == 1:
3073 return subsets[0]
3073 return subsets[0]
3074 p = len(subsets) // 2
3074 p = len(subsets) // 2
3075 xs = _combinesets(subsets[:p])
3075 xs = _combinesets(subsets[:p])
3076 ys = _combinesets(subsets[p:])
3076 ys = _combinesets(subsets[p:])
3077 return addset(xs, ys)
3077 return addset(xs, ys)
3078
3078
3079 def _iterordered(ascending, iter1, iter2):
3079 def _iterordered(ascending, iter1, iter2):
3080 """produce an ordered iteration from two iterators with the same order
3080 """produce an ordered iteration from two iterators with the same order
3081
3081
3082 The ascending is used to indicated the iteration direction.
3082 The ascending is used to indicated the iteration direction.
3083 """
3083 """
3084 choice = max
3084 choice = max
3085 if ascending:
3085 if ascending:
3086 choice = min
3086 choice = min
3087
3087
3088 val1 = None
3088 val1 = None
3089 val2 = None
3089 val2 = None
3090 try:
3090 try:
3091 # Consume both iterators in an ordered way until one is empty
3091 # Consume both iterators in an ordered way until one is empty
3092 while True:
3092 while True:
3093 if val1 is None:
3093 if val1 is None:
3094 val1 = iter1.next()
3094 val1 = iter1.next()
3095 if val2 is None:
3095 if val2 is None:
3096 val2 = iter2.next()
3096 val2 = iter2.next()
3097 next = choice(val1, val2)
3097 next = choice(val1, val2)
3098 yield next
3098 yield next
3099 if val1 == next:
3099 if val1 == next:
3100 val1 = None
3100 val1 = None
3101 if val2 == next:
3101 if val2 == next:
3102 val2 = None
3102 val2 = None
3103 except StopIteration:
3103 except StopIteration:
3104 # Flush any remaining values and consume the other one
3104 # Flush any remaining values and consume the other one
3105 it = iter2
3105 it = iter2
3106 if val1 is not None:
3106 if val1 is not None:
3107 yield val1
3107 yield val1
3108 it = iter1
3108 it = iter1
3109 elif val2 is not None:
3109 elif val2 is not None:
3110 # might have been equality and both are empty
3110 # might have been equality and both are empty
3111 yield val2
3111 yield val2
3112 for val in it:
3112 for val in it:
3113 yield val
3113 yield val
3114
3114
3115 class addset(abstractsmartset):
3115 class addset(abstractsmartset):
3116 """Represent the addition of two sets
3116 """Represent the addition of two sets
3117
3117
3118 Wrapper structure for lazily adding two structures without losing much
3118 Wrapper structure for lazily adding two structures without losing much
3119 performance on the __contains__ method
3119 performance on the __contains__ method
3120
3120
3121 If the ascending attribute is set, that means the two structures are
3121 If the ascending attribute is set, that means the two structures are
3122 ordered in either an ascending or descending way. Therefore, we can add
3122 ordered in either an ascending or descending way. Therefore, we can add
3123 them maintaining the order by iterating over both at the same time
3123 them maintaining the order by iterating over both at the same time
3124
3124
3125 >>> xs = baseset([0, 3, 2])
3125 >>> xs = baseset([0, 3, 2])
3126 >>> ys = baseset([5, 2, 4])
3126 >>> ys = baseset([5, 2, 4])
3127
3127
3128 >>> rs = addset(xs, ys)
3128 >>> rs = addset(xs, ys)
3129 >>> bool(rs), 0 in rs, 1 in rs, 5 in rs, rs.first(), rs.last()
3129 >>> bool(rs), 0 in rs, 1 in rs, 5 in rs, rs.first(), rs.last()
3130 (True, True, False, True, 0, 4)
3130 (True, True, False, True, 0, 4)
3131 >>> rs = addset(xs, baseset([]))
3131 >>> rs = addset(xs, baseset([]))
3132 >>> bool(rs), 0 in rs, 1 in rs, rs.first(), rs.last()
3132 >>> bool(rs), 0 in rs, 1 in rs, rs.first(), rs.last()
3133 (True, True, False, 0, 2)
3133 (True, True, False, 0, 2)
3134 >>> rs = addset(baseset([]), baseset([]))
3134 >>> rs = addset(baseset([]), baseset([]))
3135 >>> bool(rs), 0 in rs, rs.first(), rs.last()
3135 >>> bool(rs), 0 in rs, rs.first(), rs.last()
3136 (False, False, None, None)
3136 (False, False, None, None)
3137
3137
3138 iterate unsorted:
3138 iterate unsorted:
3139 >>> rs = addset(xs, ys)
3139 >>> rs = addset(xs, ys)
3140 >>> [x for x in rs] # without _genlist
3140 >>> [x for x in rs] # without _genlist
3141 [0, 3, 2, 5, 4]
3141 [0, 3, 2, 5, 4]
3142 >>> assert not rs._genlist
3142 >>> assert not rs._genlist
3143 >>> len(rs)
3143 >>> len(rs)
3144 5
3144 5
3145 >>> [x for x in rs] # with _genlist
3145 >>> [x for x in rs] # with _genlist
3146 [0, 3, 2, 5, 4]
3146 [0, 3, 2, 5, 4]
3147 >>> assert rs._genlist
3147 >>> assert rs._genlist
3148
3148
3149 iterate ascending:
3149 iterate ascending:
3150 >>> rs = addset(xs, ys, ascending=True)
3150 >>> rs = addset(xs, ys, ascending=True)
3151 >>> [x for x in rs], [x for x in rs.fastasc()] # without _asclist
3151 >>> [x for x in rs], [x for x in rs.fastasc()] # without _asclist
3152 ([0, 2, 3, 4, 5], [0, 2, 3, 4, 5])
3152 ([0, 2, 3, 4, 5], [0, 2, 3, 4, 5])
3153 >>> assert not rs._asclist
3153 >>> assert not rs._asclist
3154 >>> len(rs)
3154 >>> len(rs)
3155 5
3155 5
3156 >>> [x for x in rs], [x for x in rs.fastasc()]
3156 >>> [x for x in rs], [x for x in rs.fastasc()]
3157 ([0, 2, 3, 4, 5], [0, 2, 3, 4, 5])
3157 ([0, 2, 3, 4, 5], [0, 2, 3, 4, 5])
3158 >>> assert rs._asclist
3158 >>> assert rs._asclist
3159
3159
3160 iterate descending:
3160 iterate descending:
3161 >>> rs = addset(xs, ys, ascending=False)
3161 >>> rs = addset(xs, ys, ascending=False)
3162 >>> [x for x in rs], [x for x in rs.fastdesc()] # without _asclist
3162 >>> [x for x in rs], [x for x in rs.fastdesc()] # without _asclist
3163 ([5, 4, 3, 2, 0], [5, 4, 3, 2, 0])
3163 ([5, 4, 3, 2, 0], [5, 4, 3, 2, 0])
3164 >>> assert not rs._asclist
3164 >>> assert not rs._asclist
3165 >>> len(rs)
3165 >>> len(rs)
3166 5
3166 5
3167 >>> [x for x in rs], [x for x in rs.fastdesc()]
3167 >>> [x for x in rs], [x for x in rs.fastdesc()]
3168 ([5, 4, 3, 2, 0], [5, 4, 3, 2, 0])
3168 ([5, 4, 3, 2, 0], [5, 4, 3, 2, 0])
3169 >>> assert rs._asclist
3169 >>> assert rs._asclist
3170
3170
3171 iterate ascending without fastasc:
3171 iterate ascending without fastasc:
3172 >>> rs = addset(xs, generatorset(ys), ascending=True)
3172 >>> rs = addset(xs, generatorset(ys), ascending=True)
3173 >>> assert rs.fastasc is None
3173 >>> assert rs.fastasc is None
3174 >>> [x for x in rs]
3174 >>> [x for x in rs]
3175 [0, 2, 3, 4, 5]
3175 [0, 2, 3, 4, 5]
3176
3176
3177 iterate descending without fastdesc:
3177 iterate descending without fastdesc:
3178 >>> rs = addset(generatorset(xs), ys, ascending=False)
3178 >>> rs = addset(generatorset(xs), ys, ascending=False)
3179 >>> assert rs.fastdesc is None
3179 >>> assert rs.fastdesc is None
3180 >>> [x for x in rs]
3180 >>> [x for x in rs]
3181 [5, 4, 3, 2, 0]
3181 [5, 4, 3, 2, 0]
3182 """
3182 """
3183 def __init__(self, revs1, revs2, ascending=None):
3183 def __init__(self, revs1, revs2, ascending=None):
3184 self._r1 = revs1
3184 self._r1 = revs1
3185 self._r2 = revs2
3185 self._r2 = revs2
3186 self._iter = None
3186 self._iter = None
3187 self._ascending = ascending
3187 self._ascending = ascending
3188 self._genlist = None
3188 self._genlist = None
3189 self._asclist = None
3189 self._asclist = None
3190
3190
3191 def __len__(self):
3191 def __len__(self):
3192 return len(self._list)
3192 return len(self._list)
3193
3193
3194 def __nonzero__(self):
3194 def __nonzero__(self):
3195 return bool(self._r1) or bool(self._r2)
3195 return bool(self._r1) or bool(self._r2)
3196
3196
3197 @util.propertycache
3197 @util.propertycache
3198 def _list(self):
3198 def _list(self):
3199 if not self._genlist:
3199 if not self._genlist:
3200 self._genlist = baseset(iter(self))
3200 self._genlist = baseset(iter(self))
3201 return self._genlist
3201 return self._genlist
3202
3202
3203 def __iter__(self):
3203 def __iter__(self):
3204 """Iterate over both collections without repeating elements
3204 """Iterate over both collections without repeating elements
3205
3205
3206 If the ascending attribute is not set, iterate over the first one and
3206 If the ascending attribute is not set, iterate over the first one and
3207 then over the second one checking for membership on the first one so we
3207 then over the second one checking for membership on the first one so we
3208 dont yield any duplicates.
3208 dont yield any duplicates.
3209
3209
3210 If the ascending attribute is set, iterate over both collections at the
3210 If the ascending attribute is set, iterate over both collections at the
3211 same time, yielding only one value at a time in the given order.
3211 same time, yielding only one value at a time in the given order.
3212 """
3212 """
3213 if self._ascending is None:
3213 if self._ascending is None:
3214 if self._genlist:
3214 if self._genlist:
3215 return iter(self._genlist)
3215 return iter(self._genlist)
3216 def arbitraryordergen():
3216 def arbitraryordergen():
3217 for r in self._r1:
3217 for r in self._r1:
3218 yield r
3218 yield r
3219 inr1 = self._r1.__contains__
3219 inr1 = self._r1.__contains__
3220 for r in self._r2:
3220 for r in self._r2:
3221 if not inr1(r):
3221 if not inr1(r):
3222 yield r
3222 yield r
3223 return arbitraryordergen()
3223 return arbitraryordergen()
3224 # try to use our own fast iterator if it exists
3224 # try to use our own fast iterator if it exists
3225 self._trysetasclist()
3225 self._trysetasclist()
3226 if self._ascending:
3226 if self._ascending:
3227 attr = 'fastasc'
3227 attr = 'fastasc'
3228 else:
3228 else:
3229 attr = 'fastdesc'
3229 attr = 'fastdesc'
3230 it = getattr(self, attr)
3230 it = getattr(self, attr)
3231 if it is not None:
3231 if it is not None:
3232 return it()
3232 return it()
3233 # maybe half of the component supports fast
3233 # maybe half of the component supports fast
3234 # get iterator for _r1
3234 # get iterator for _r1
3235 iter1 = getattr(self._r1, attr)
3235 iter1 = getattr(self._r1, attr)
3236 if iter1 is None:
3236 if iter1 is None:
3237 # let's avoid side effect (not sure it matters)
3237 # let's avoid side effect (not sure it matters)
3238 iter1 = iter(sorted(self._r1, reverse=not self._ascending))
3238 iter1 = iter(sorted(self._r1, reverse=not self._ascending))
3239 else:
3239 else:
3240 iter1 = iter1()
3240 iter1 = iter1()
3241 # get iterator for _r2
3241 # get iterator for _r2
3242 iter2 = getattr(self._r2, attr)
3242 iter2 = getattr(self._r2, attr)
3243 if iter2 is None:
3243 if iter2 is None:
3244 # let's avoid side effect (not sure it matters)
3244 # let's avoid side effect (not sure it matters)
3245 iter2 = iter(sorted(self._r2, reverse=not self._ascending))
3245 iter2 = iter(sorted(self._r2, reverse=not self._ascending))
3246 else:
3246 else:
3247 iter2 = iter2()
3247 iter2 = iter2()
3248 return _iterordered(self._ascending, iter1, iter2)
3248 return _iterordered(self._ascending, iter1, iter2)
3249
3249
3250 def _trysetasclist(self):
3250 def _trysetasclist(self):
3251 """populate the _asclist attribute if possible and necessary"""
3251 """populate the _asclist attribute if possible and necessary"""
3252 if self._genlist is not None and self._asclist is None:
3252 if self._genlist is not None and self._asclist is None:
3253 self._asclist = sorted(self._genlist)
3253 self._asclist = sorted(self._genlist)
3254
3254
3255 @property
3255 @property
3256 def fastasc(self):
3256 def fastasc(self):
3257 self._trysetasclist()
3257 self._trysetasclist()
3258 if self._asclist is not None:
3258 if self._asclist is not None:
3259 return self._asclist.__iter__
3259 return self._asclist.__iter__
3260 iter1 = self._r1.fastasc
3260 iter1 = self._r1.fastasc
3261 iter2 = self._r2.fastasc
3261 iter2 = self._r2.fastasc
3262 if None in (iter1, iter2):
3262 if None in (iter1, iter2):
3263 return None
3263 return None
3264 return lambda: _iterordered(True, iter1(), iter2())
3264 return lambda: _iterordered(True, iter1(), iter2())
3265
3265
3266 @property
3266 @property
3267 def fastdesc(self):
3267 def fastdesc(self):
3268 self._trysetasclist()
3268 self._trysetasclist()
3269 if self._asclist is not None:
3269 if self._asclist is not None:
3270 return self._asclist.__reversed__
3270 return self._asclist.__reversed__
3271 iter1 = self._r1.fastdesc
3271 iter1 = self._r1.fastdesc
3272 iter2 = self._r2.fastdesc
3272 iter2 = self._r2.fastdesc
3273 if None in (iter1, iter2):
3273 if None in (iter1, iter2):
3274 return None
3274 return None
3275 return lambda: _iterordered(False, iter1(), iter2())
3275 return lambda: _iterordered(False, iter1(), iter2())
3276
3276
3277 def __contains__(self, x):
3277 def __contains__(self, x):
3278 return x in self._r1 or x in self._r2
3278 return x in self._r1 or x in self._r2
3279
3279
3280 def sort(self, reverse=False):
3280 def sort(self, reverse=False):
3281 """Sort the added set
3281 """Sort the added set
3282
3282
3283 For this we use the cached list with all the generated values and if we
3283 For this we use the cached list with all the generated values and if we
3284 know they are ascending or descending we can sort them in a smart way.
3284 know they are ascending or descending we can sort them in a smart way.
3285 """
3285 """
3286 self._ascending = not reverse
3286 self._ascending = not reverse
3287
3287
3288 def isascending(self):
3288 def isascending(self):
3289 return self._ascending is not None and self._ascending
3289 return self._ascending is not None and self._ascending
3290
3290
3291 def isdescending(self):
3291 def isdescending(self):
3292 return self._ascending is not None and not self._ascending
3292 return self._ascending is not None and not self._ascending
3293
3293
3294 def reverse(self):
3294 def reverse(self):
3295 if self._ascending is None:
3295 if self._ascending is None:
3296 self._list.reverse()
3296 self._list.reverse()
3297 else:
3297 else:
3298 self._ascending = not self._ascending
3298 self._ascending = not self._ascending
3299
3299
3300 def first(self):
3300 def first(self):
3301 for x in self:
3301 for x in self:
3302 return x
3302 return x
3303 return None
3303 return None
3304
3304
3305 def last(self):
3305 def last(self):
3306 self.reverse()
3306 self.reverse()
3307 val = self.first()
3307 val = self.first()
3308 self.reverse()
3308 self.reverse()
3309 return val
3309 return val
3310
3310
3311 def __repr__(self):
3311 def __repr__(self):
3312 d = {None: '', False: '-', True: '+'}[self._ascending]
3312 d = {None: '', False: '-', True: '+'}[self._ascending]
3313 return '<%s%s %r, %r>' % (type(self).__name__, d, self._r1, self._r2)
3313 return '<%s%s %r, %r>' % (type(self).__name__, d, self._r1, self._r2)
3314
3314
3315 class generatorset(abstractsmartset):
3315 class generatorset(abstractsmartset):
3316 """Wrap a generator for lazy iteration
3316 """Wrap a generator for lazy iteration
3317
3317
3318 Wrapper structure for generators that provides lazy membership and can
3318 Wrapper structure for generators that provides lazy membership and can
3319 be iterated more than once.
3319 be iterated more than once.
3320 When asked for membership it generates values until either it finds the
3320 When asked for membership it generates values until either it finds the
3321 requested one or has gone through all the elements in the generator
3321 requested one or has gone through all the elements in the generator
3322 """
3322 """
3323 def __init__(self, gen, iterasc=None):
3323 def __init__(self, gen, iterasc=None):
3324 """
3324 """
3325 gen: a generator producing the values for the generatorset.
3325 gen: a generator producing the values for the generatorset.
3326 """
3326 """
3327 self._gen = gen
3327 self._gen = gen
3328 self._asclist = None
3328 self._asclist = None
3329 self._cache = {}
3329 self._cache = {}
3330 self._genlist = []
3330 self._genlist = []
3331 self._finished = False
3331 self._finished = False
3332 self._ascending = True
3332 self._ascending = True
3333 if iterasc is not None:
3333 if iterasc is not None:
3334 if iterasc:
3334 if iterasc:
3335 self.fastasc = self._iterator
3335 self.fastasc = self._iterator
3336 self.__contains__ = self._asccontains
3336 self.__contains__ = self._asccontains
3337 else:
3337 else:
3338 self.fastdesc = self._iterator
3338 self.fastdesc = self._iterator
3339 self.__contains__ = self._desccontains
3339 self.__contains__ = self._desccontains
3340
3340
3341 def __nonzero__(self):
3341 def __nonzero__(self):
3342 # Do not use 'for r in self' because it will enforce the iteration
3342 # Do not use 'for r in self' because it will enforce the iteration
3343 # order (default ascending), possibly unrolling a whole descending
3343 # order (default ascending), possibly unrolling a whole descending
3344 # iterator.
3344 # iterator.
3345 if self._genlist:
3345 if self._genlist:
3346 return True
3346 return True
3347 for r in self._consumegen():
3347 for r in self._consumegen():
3348 return True
3348 return True
3349 return False
3349 return False
3350
3350
3351 def __contains__(self, x):
3351 def __contains__(self, x):
3352 if x in self._cache:
3352 if x in self._cache:
3353 return self._cache[x]
3353 return self._cache[x]
3354
3354
3355 # Use new values only, as existing values would be cached.
3355 # Use new values only, as existing values would be cached.
3356 for l in self._consumegen():
3356 for l in self._consumegen():
3357 if l == x:
3357 if l == x:
3358 return True
3358 return True
3359
3359
3360 self._cache[x] = False
3360 self._cache[x] = False
3361 return False
3361 return False
3362
3362
3363 def _asccontains(self, x):
3363 def _asccontains(self, x):
3364 """version of contains optimised for ascending generator"""
3364 """version of contains optimised for ascending generator"""
3365 if x in self._cache:
3365 if x in self._cache:
3366 return self._cache[x]
3366 return self._cache[x]
3367
3367
3368 # Use new values only, as existing values would be cached.
3368 # Use new values only, as existing values would be cached.
3369 for l in self._consumegen():
3369 for l in self._consumegen():
3370 if l == x:
3370 if l == x:
3371 return True
3371 return True
3372 if l > x:
3372 if l > x:
3373 break
3373 break
3374
3374
3375 self._cache[x] = False
3375 self._cache[x] = False
3376 return False
3376 return False
3377
3377
3378 def _desccontains(self, x):
3378 def _desccontains(self, x):
3379 """version of contains optimised for descending generator"""
3379 """version of contains optimised for descending generator"""
3380 if x in self._cache:
3380 if x in self._cache:
3381 return self._cache[x]
3381 return self._cache[x]
3382
3382
3383 # Use new values only, as existing values would be cached.
3383 # Use new values only, as existing values would be cached.
3384 for l in self._consumegen():
3384 for l in self._consumegen():
3385 if l == x:
3385 if l == x:
3386 return True
3386 return True
3387 if l < x:
3387 if l < x:
3388 break
3388 break
3389
3389
3390 self._cache[x] = False
3390 self._cache[x] = False
3391 return False
3391 return False
3392
3392
3393 def __iter__(self):
3393 def __iter__(self):
3394 if self._ascending:
3394 if self._ascending:
3395 it = self.fastasc
3395 it = self.fastasc
3396 else:
3396 else:
3397 it = self.fastdesc
3397 it = self.fastdesc
3398 if it is not None:
3398 if it is not None:
3399 return it()
3399 return it()
3400 # we need to consume the iterator
3400 # we need to consume the iterator
3401 for x in self._consumegen():
3401 for x in self._consumegen():
3402 pass
3402 pass
3403 # recall the same code
3403 # recall the same code
3404 return iter(self)
3404 return iter(self)
3405
3405
3406 def _iterator(self):
3406 def _iterator(self):
3407 if self._finished:
3407 if self._finished:
3408 return iter(self._genlist)
3408 return iter(self._genlist)
3409
3409
3410 # We have to use this complex iteration strategy to allow multiple
3410 # We have to use this complex iteration strategy to allow multiple
3411 # iterations at the same time. We need to be able to catch revision
3411 # iterations at the same time. We need to be able to catch revision
3412 # removed from _consumegen and added to genlist in another instance.
3412 # removed from _consumegen and added to genlist in another instance.
3413 #
3413 #
3414 # Getting rid of it would provide an about 15% speed up on this
3414 # Getting rid of it would provide an about 15% speed up on this
3415 # iteration.
3415 # iteration.
3416 genlist = self._genlist
3416 genlist = self._genlist
3417 nextrev = self._consumegen().next
3417 nextrev = self._consumegen().next
3418 _len = len # cache global lookup
3418 _len = len # cache global lookup
3419 def gen():
3419 def gen():
3420 i = 0
3420 i = 0
3421 while True:
3421 while True:
3422 if i < _len(genlist):
3422 if i < _len(genlist):
3423 yield genlist[i]
3423 yield genlist[i]
3424 else:
3424 else:
3425 yield nextrev()
3425 yield nextrev()
3426 i += 1
3426 i += 1
3427 return gen()
3427 return gen()
3428
3428
3429 def _consumegen(self):
3429 def _consumegen(self):
3430 cache = self._cache
3430 cache = self._cache
3431 genlist = self._genlist.append
3431 genlist = self._genlist.append
3432 for item in self._gen:
3432 for item in self._gen:
3433 cache[item] = True
3433 cache[item] = True
3434 genlist(item)
3434 genlist(item)
3435 yield item
3435 yield item
3436 if not self._finished:
3436 if not self._finished:
3437 self._finished = True
3437 self._finished = True
3438 asc = self._genlist[:]
3438 asc = self._genlist[:]
3439 asc.sort()
3439 asc.sort()
3440 self._asclist = asc
3440 self._asclist = asc
3441 self.fastasc = asc.__iter__
3441 self.fastasc = asc.__iter__
3442 self.fastdesc = asc.__reversed__
3442 self.fastdesc = asc.__reversed__
3443
3443
3444 def __len__(self):
3444 def __len__(self):
3445 for x in self._consumegen():
3445 for x in self._consumegen():
3446 pass
3446 pass
3447 return len(self._genlist)
3447 return len(self._genlist)
3448
3448
3449 def sort(self, reverse=False):
3449 def sort(self, reverse=False):
3450 self._ascending = not reverse
3450 self._ascending = not reverse
3451
3451
3452 def reverse(self):
3452 def reverse(self):
3453 self._ascending = not self._ascending
3453 self._ascending = not self._ascending
3454
3454
3455 def isascending(self):
3455 def isascending(self):
3456 return self._ascending
3456 return self._ascending
3457
3457
3458 def isdescending(self):
3458 def isdescending(self):
3459 return not self._ascending
3459 return not self._ascending
3460
3460
3461 def first(self):
3461 def first(self):
3462 if self._ascending:
3462 if self._ascending:
3463 it = self.fastasc
3463 it = self.fastasc
3464 else:
3464 else:
3465 it = self.fastdesc
3465 it = self.fastdesc
3466 if it is None:
3466 if it is None:
3467 # we need to consume all and try again
3467 # we need to consume all and try again
3468 for x in self._consumegen():
3468 for x in self._consumegen():
3469 pass
3469 pass
3470 return self.first()
3470 return self.first()
3471 return next(it(), None)
3471 return next(it(), None)
3472
3472
3473 def last(self):
3473 def last(self):
3474 if self._ascending:
3474 if self._ascending:
3475 it = self.fastdesc
3475 it = self.fastdesc
3476 else:
3476 else:
3477 it = self.fastasc
3477 it = self.fastasc
3478 if it is None:
3478 if it is None:
3479 # we need to consume all and try again
3479 # we need to consume all and try again
3480 for x in self._consumegen():
3480 for x in self._consumegen():
3481 pass
3481 pass
3482 return self.first()
3482 return self.first()
3483 return next(it(), None)
3483 return next(it(), None)
3484
3484
3485 def __repr__(self):
3485 def __repr__(self):
3486 d = {False: '-', True: '+'}[self._ascending]
3486 d = {False: '-', True: '+'}[self._ascending]
3487 return '<%s%s>' % (type(self).__name__, d)
3487 return '<%s%s>' % (type(self).__name__, d)
3488
3488
3489 class spanset(abstractsmartset):
3489 class spanset(abstractsmartset):
3490 """Duck type for baseset class which represents a range of revisions and
3490 """Duck type for baseset class which represents a range of revisions and
3491 can work lazily and without having all the range in memory
3491 can work lazily and without having all the range in memory
3492
3492
3493 Note that spanset(x, y) behave almost like xrange(x, y) except for two
3493 Note that spanset(x, y) behave almost like xrange(x, y) except for two
3494 notable points:
3494 notable points:
3495 - when x < y it will be automatically descending,
3495 - when x < y it will be automatically descending,
3496 - revision filtered with this repoview will be skipped.
3496 - revision filtered with this repoview will be skipped.
3497
3497
3498 """
3498 """
3499 def __init__(self, repo, start=0, end=None):
3499 def __init__(self, repo, start=0, end=None):
3500 """
3500 """
3501 start: first revision included the set
3501 start: first revision included the set
3502 (default to 0)
3502 (default to 0)
3503 end: first revision excluded (last+1)
3503 end: first revision excluded (last+1)
3504 (default to len(repo)
3504 (default to len(repo)
3505
3505
3506 Spanset will be descending if `end` < `start`.
3506 Spanset will be descending if `end` < `start`.
3507 """
3507 """
3508 if end is None:
3508 if end is None:
3509 end = len(repo)
3509 end = len(repo)
3510 self._ascending = start <= end
3510 self._ascending = start <= end
3511 if not self._ascending:
3511 if not self._ascending:
3512 start, end = end + 1, start +1
3512 start, end = end + 1, start +1
3513 self._start = start
3513 self._start = start
3514 self._end = end
3514 self._end = end
3515 self._hiddenrevs = repo.changelog.filteredrevs
3515 self._hiddenrevs = repo.changelog.filteredrevs
3516
3516
3517 def sort(self, reverse=False):
3517 def sort(self, reverse=False):
3518 self._ascending = not reverse
3518 self._ascending = not reverse
3519
3519
3520 def reverse(self):
3520 def reverse(self):
3521 self._ascending = not self._ascending
3521 self._ascending = not self._ascending
3522
3522
3523 def _iterfilter(self, iterrange):
3523 def _iterfilter(self, iterrange):
3524 s = self._hiddenrevs
3524 s = self._hiddenrevs
3525 for r in iterrange:
3525 for r in iterrange:
3526 if r not in s:
3526 if r not in s:
3527 yield r
3527 yield r
3528
3528
3529 def __iter__(self):
3529 def __iter__(self):
3530 if self._ascending:
3530 if self._ascending:
3531 return self.fastasc()
3531 return self.fastasc()
3532 else:
3532 else:
3533 return self.fastdesc()
3533 return self.fastdesc()
3534
3534
3535 def fastasc(self):
3535 def fastasc(self):
3536 iterrange = xrange(self._start, self._end)
3536 iterrange = xrange(self._start, self._end)
3537 if self._hiddenrevs:
3537 if self._hiddenrevs:
3538 return self._iterfilter(iterrange)
3538 return self._iterfilter(iterrange)
3539 return iter(iterrange)
3539 return iter(iterrange)
3540
3540
3541 def fastdesc(self):
3541 def fastdesc(self):
3542 iterrange = xrange(self._end - 1, self._start - 1, -1)
3542 iterrange = xrange(self._end - 1, self._start - 1, -1)
3543 if self._hiddenrevs:
3543 if self._hiddenrevs:
3544 return self._iterfilter(iterrange)
3544 return self._iterfilter(iterrange)
3545 return iter(iterrange)
3545 return iter(iterrange)
3546
3546
3547 def __contains__(self, rev):
3547 def __contains__(self, rev):
3548 hidden = self._hiddenrevs
3548 hidden = self._hiddenrevs
3549 return ((self._start <= rev < self._end)
3549 return ((self._start <= rev < self._end)
3550 and not (hidden and rev in hidden))
3550 and not (hidden and rev in hidden))
3551
3551
3552 def __nonzero__(self):
3552 def __nonzero__(self):
3553 for r in self:
3553 for r in self:
3554 return True
3554 return True
3555 return False
3555 return False
3556
3556
3557 def __len__(self):
3557 def __len__(self):
3558 if not self._hiddenrevs:
3558 if not self._hiddenrevs:
3559 return abs(self._end - self._start)
3559 return abs(self._end - self._start)
3560 else:
3560 else:
3561 count = 0
3561 count = 0
3562 start = self._start
3562 start = self._start
3563 end = self._end
3563 end = self._end
3564 for rev in self._hiddenrevs:
3564 for rev in self._hiddenrevs:
3565 if (end < rev <= start) or (start <= rev < end):
3565 if (end < rev <= start) or (start <= rev < end):
3566 count += 1
3566 count += 1
3567 return abs(self._end - self._start) - count
3567 return abs(self._end - self._start) - count
3568
3568
3569 def isascending(self):
3569 def isascending(self):
3570 return self._ascending
3570 return self._ascending
3571
3571
3572 def isdescending(self):
3572 def isdescending(self):
3573 return not self._ascending
3573 return not self._ascending
3574
3574
3575 def first(self):
3575 def first(self):
3576 if self._ascending:
3576 if self._ascending:
3577 it = self.fastasc
3577 it = self.fastasc
3578 else:
3578 else:
3579 it = self.fastdesc
3579 it = self.fastdesc
3580 for x in it():
3580 for x in it():
3581 return x
3581 return x
3582 return None
3582 return None
3583
3583
3584 def last(self):
3584 def last(self):
3585 if self._ascending:
3585 if self._ascending:
3586 it = self.fastdesc
3586 it = self.fastdesc
3587 else:
3587 else:
3588 it = self.fastasc
3588 it = self.fastasc
3589 for x in it():
3589 for x in it():
3590 return x
3590 return x
3591 return None
3591 return None
3592
3592
3593 def __repr__(self):
3593 def __repr__(self):
3594 d = {False: '-', True: '+'}[self._ascending]
3594 d = {False: '-', True: '+'}[self._ascending]
3595 return '<%s%s %d:%d>' % (type(self).__name__, d,
3595 return '<%s%s %d:%d>' % (type(self).__name__, d,
3596 self._start, self._end - 1)
3596 self._start, self._end - 1)
3597
3597
3598 class fullreposet(spanset):
3598 class fullreposet(spanset):
3599 """a set containing all revisions in the repo
3599 """a set containing all revisions in the repo
3600
3600
3601 This class exists to host special optimization and magic to handle virtual
3601 This class exists to host special optimization and magic to handle virtual
3602 revisions such as "null".
3602 revisions such as "null".
3603 """
3603 """
3604
3604
3605 def __init__(self, repo):
3605 def __init__(self, repo):
3606 super(fullreposet, self).__init__(repo)
3606 super(fullreposet, self).__init__(repo)
3607
3607
3608 def __and__(self, other):
3608 def __and__(self, other):
3609 """As self contains the whole repo, all of the other set should also be
3609 """As self contains the whole repo, all of the other set should also be
3610 in self. Therefore `self & other = other`.
3610 in self. Therefore `self & other = other`.
3611
3611
3612 This boldly assumes the other contains valid revs only.
3612 This boldly assumes the other contains valid revs only.
3613 """
3613 """
3614 # other not a smartset, make is so
3614 # other not a smartset, make is so
3615 if not util.safehasattr(other, 'isascending'):
3615 if not util.safehasattr(other, 'isascending'):
3616 # filter out hidden revision
3616 # filter out hidden revision
3617 # (this boldly assumes all smartset are pure)
3617 # (this boldly assumes all smartset are pure)
3618 #
3618 #
3619 # `other` was used with "&", let's assume this is a set like
3619 # `other` was used with "&", let's assume this is a set like
3620 # object.
3620 # object.
3621 other = baseset(other - self._hiddenrevs)
3621 other = baseset(other - self._hiddenrevs)
3622
3622
3623 # XXX As fullreposet is also used as bootstrap, this is wrong.
3623 # XXX As fullreposet is also used as bootstrap, this is wrong.
3624 #
3624 #
3625 # With a giveme312() revset returning [3,1,2], this makes
3625 # With a giveme312() revset returning [3,1,2], this makes
3626 # 'hg log -r "giveme312()"' -> 1, 2, 3 (wrong)
3626 # 'hg log -r "giveme312()"' -> 1, 2, 3 (wrong)
3627 # We cannot just drop it because other usage still need to sort it:
3627 # We cannot just drop it because other usage still need to sort it:
3628 # 'hg log -r "all() and giveme312()"' -> 1, 2, 3 (right)
3628 # 'hg log -r "all() and giveme312()"' -> 1, 2, 3 (right)
3629 #
3629 #
3630 # There is also some faulty revset implementations that rely on it
3630 # There is also some faulty revset implementations that rely on it
3631 # (eg: children as of its state in e8075329c5fb)
3631 # (eg: children as of its state in e8075329c5fb)
3632 #
3632 #
3633 # When we fix the two points above we can move this into the if clause
3633 # When we fix the two points above we can move this into the if clause
3634 other.sort(reverse=self.isdescending())
3634 other.sort(reverse=self.isdescending())
3635 return other
3635 return other
3636
3636
3637 def prettyformatset(revs):
3637 def prettyformatset(revs):
3638 lines = []
3638 lines = []
3639 rs = repr(revs)
3639 rs = repr(revs)
3640 p = 0
3640 p = 0
3641 while p < len(rs):
3641 while p < len(rs):
3642 q = rs.find('<', p + 1)
3642 q = rs.find('<', p + 1)
3643 if q < 0:
3643 if q < 0:
3644 q = len(rs)
3644 q = len(rs)
3645 l = rs.count('<', 0, p) - rs.count('>', 0, p)
3645 l = rs.count('<', 0, p) - rs.count('>', 0, p)
3646 assert l >= 0
3646 assert l >= 0
3647 lines.append((l, rs[p:q].rstrip()))
3647 lines.append((l, rs[p:q].rstrip()))
3648 p = q
3648 p = q
3649 return '\n'.join(' ' * l + s for l, s in lines)
3649 return '\n'.join(' ' * l + s for l, s in lines)
3650
3650
3651 # tell hggettext to extract docstrings from these functions:
3651 # tell hggettext to extract docstrings from these functions:
3652 i18nfunctions = symbols.values()
3652 i18nfunctions = symbols.values()
@@ -1,2395 +1,2403 b''
1 @ (34) head
1 @ (34) head
2 |
2 |
3 | o (33) head
3 | o (33) head
4 | |
4 | |
5 o | (32) expand
5 o | (32) expand
6 |\ \
6 |\ \
7 | o \ (31) expand
7 | o \ (31) expand
8 | |\ \
8 | |\ \
9 | | o \ (30) expand
9 | | o \ (30) expand
10 | | |\ \
10 | | |\ \
11 | | | o | (29) regular commit
11 | | | o | (29) regular commit
12 | | | | |
12 | | | | |
13 | | o | | (28) merge zero known
13 | | o | | (28) merge zero known
14 | | |\ \ \
14 | | |\ \ \
15 o | | | | | (27) collapse
15 o | | | | | (27) collapse
16 |/ / / / /
16 |/ / / / /
17 | | o---+ (26) merge one known; far right
17 | | o---+ (26) merge one known; far right
18 | | | | |
18 | | | | |
19 +---o | | (25) merge one known; far left
19 +---o | | (25) merge one known; far left
20 | | | | |
20 | | | | |
21 | | o | | (24) merge one known; immediate right
21 | | o | | (24) merge one known; immediate right
22 | | |\| |
22 | | |\| |
23 | | o | | (23) merge one known; immediate left
23 | | o | | (23) merge one known; immediate left
24 | |/| | |
24 | |/| | |
25 +---o---+ (22) merge two known; one far left, one far right
25 +---o---+ (22) merge two known; one far left, one far right
26 | | / /
26 | | / /
27 o | | | (21) expand
27 o | | | (21) expand
28 |\ \ \ \
28 |\ \ \ \
29 | o---+-+ (20) merge two known; two far right
29 | o---+-+ (20) merge two known; two far right
30 | / / /
30 | / / /
31 o | | | (19) expand
31 o | | | (19) expand
32 |\ \ \ \
32 |\ \ \ \
33 +---+---o (18) merge two known; two far left
33 +---+---o (18) merge two known; two far left
34 | | | |
34 | | | |
35 | o | | (17) expand
35 | o | | (17) expand
36 | |\ \ \
36 | |\ \ \
37 | | o---+ (16) merge two known; one immediate right, one near right
37 | | o---+ (16) merge two known; one immediate right, one near right
38 | | |/ /
38 | | |/ /
39 o | | | (15) expand
39 o | | | (15) expand
40 |\ \ \ \
40 |\ \ \ \
41 | o-----+ (14) merge two known; one immediate right, one far right
41 | o-----+ (14) merge two known; one immediate right, one far right
42 | |/ / /
42 | |/ / /
43 o | | | (13) expand
43 o | | | (13) expand
44 |\ \ \ \
44 |\ \ \ \
45 +---o | | (12) merge two known; one immediate right, one far left
45 +---o | | (12) merge two known; one immediate right, one far left
46 | | |/ /
46 | | |/ /
47 | o | | (11) expand
47 | o | | (11) expand
48 | |\ \ \
48 | |\ \ \
49 | | o---+ (10) merge two known; one immediate left, one near right
49 | | o---+ (10) merge two known; one immediate left, one near right
50 | |/ / /
50 | |/ / /
51 o | | | (9) expand
51 o | | | (9) expand
52 |\ \ \ \
52 |\ \ \ \
53 | o-----+ (8) merge two known; one immediate left, one far right
53 | o-----+ (8) merge two known; one immediate left, one far right
54 |/ / / /
54 |/ / / /
55 o | | | (7) expand
55 o | | | (7) expand
56 |\ \ \ \
56 |\ \ \ \
57 +---o | | (6) merge two known; one immediate left, one far left
57 +---o | | (6) merge two known; one immediate left, one far left
58 | |/ / /
58 | |/ / /
59 | o | | (5) expand
59 | o | | (5) expand
60 | |\ \ \
60 | |\ \ \
61 | | o | | (4) merge two known; one immediate left, one immediate right
61 | | o | | (4) merge two known; one immediate left, one immediate right
62 | |/|/ /
62 | |/|/ /
63 | o / / (3) collapse
63 | o / / (3) collapse
64 |/ / /
64 |/ / /
65 o / / (2) collapse
65 o / / (2) collapse
66 |/ /
66 |/ /
67 o / (1) collapse
67 o / (1) collapse
68 |/
68 |/
69 o (0) root
69 o (0) root
70
70
71
71
72 $ commit()
72 $ commit()
73 > {
73 > {
74 > rev=$1
74 > rev=$1
75 > msg=$2
75 > msg=$2
76 > shift 2
76 > shift 2
77 > if [ "$#" -gt 0 ]; then
77 > if [ "$#" -gt 0 ]; then
78 > hg debugsetparents "$@"
78 > hg debugsetparents "$@"
79 > fi
79 > fi
80 > echo $rev > a
80 > echo $rev > a
81 > hg commit -Aqd "$rev 0" -m "($rev) $msg"
81 > hg commit -Aqd "$rev 0" -m "($rev) $msg"
82 > }
82 > }
83
83
84 $ cat > printrevset.py <<EOF
84 $ cat > printrevset.py <<EOF
85 > from mercurial import extensions, revset, commands, cmdutil
85 > from mercurial import extensions, revset, commands, cmdutil
86 >
86 >
87 > def uisetup(ui):
87 > def uisetup(ui):
88 > def printrevset(orig, ui, repo, *pats, **opts):
88 > def printrevset(orig, ui, repo, *pats, **opts):
89 > if opts.get('print_revset'):
89 > if opts.get('print_revset'):
90 > expr = cmdutil.getgraphlogrevs(repo, pats, opts)[1]
90 > expr = cmdutil.getgraphlogrevs(repo, pats, opts)[1]
91 > if expr:
91 > if expr:
92 > tree = revset.parse(expr)
92 > tree = revset.parse(expr)
93 > else:
93 > else:
94 > tree = []
94 > tree = []
95 > ui.write('%r\n' % (opts.get('rev', []),))
95 > ui.write('%r\n' % (opts.get('rev', []),))
96 > ui.write(revset.prettyformat(tree) + '\n')
96 > ui.write(revset.prettyformat(tree) + '\n')
97 > return 0
97 > return 0
98 > return orig(ui, repo, *pats, **opts)
98 > return orig(ui, repo, *pats, **opts)
99 > entry = extensions.wrapcommand(commands.table, 'log', printrevset)
99 > entry = extensions.wrapcommand(commands.table, 'log', printrevset)
100 > entry[1].append(('', 'print-revset', False,
100 > entry[1].append(('', 'print-revset', False,
101 > 'print generated revset and exit (DEPRECATED)'))
101 > 'print generated revset and exit (DEPRECATED)'))
102 > EOF
102 > EOF
103
103
104 $ echo "[extensions]" >> $HGRCPATH
104 $ echo "[extensions]" >> $HGRCPATH
105 $ echo "printrevset=`pwd`/printrevset.py" >> $HGRCPATH
105 $ echo "printrevset=`pwd`/printrevset.py" >> $HGRCPATH
106
106
107 $ hg init repo
107 $ hg init repo
108 $ cd repo
108 $ cd repo
109
109
110 Empty repo:
110 Empty repo:
111
111
112 $ hg log -G
112 $ hg log -G
113
113
114
114
115 Building DAG:
115 Building DAG:
116
116
117 $ commit 0 "root"
117 $ commit 0 "root"
118 $ commit 1 "collapse" 0
118 $ commit 1 "collapse" 0
119 $ commit 2 "collapse" 1
119 $ commit 2 "collapse" 1
120 $ commit 3 "collapse" 2
120 $ commit 3 "collapse" 2
121 $ commit 4 "merge two known; one immediate left, one immediate right" 1 3
121 $ commit 4 "merge two known; one immediate left, one immediate right" 1 3
122 $ commit 5 "expand" 3 4
122 $ commit 5 "expand" 3 4
123 $ commit 6 "merge two known; one immediate left, one far left" 2 5
123 $ commit 6 "merge two known; one immediate left, one far left" 2 5
124 $ commit 7 "expand" 2 5
124 $ commit 7 "expand" 2 5
125 $ commit 8 "merge two known; one immediate left, one far right" 0 7
125 $ commit 8 "merge two known; one immediate left, one far right" 0 7
126 $ commit 9 "expand" 7 8
126 $ commit 9 "expand" 7 8
127 $ commit 10 "merge two known; one immediate left, one near right" 0 6
127 $ commit 10 "merge two known; one immediate left, one near right" 0 6
128 $ commit 11 "expand" 6 10
128 $ commit 11 "expand" 6 10
129 $ commit 12 "merge two known; one immediate right, one far left" 1 9
129 $ commit 12 "merge two known; one immediate right, one far left" 1 9
130 $ commit 13 "expand" 9 11
130 $ commit 13 "expand" 9 11
131 $ commit 14 "merge two known; one immediate right, one far right" 0 12
131 $ commit 14 "merge two known; one immediate right, one far right" 0 12
132 $ commit 15 "expand" 13 14
132 $ commit 15 "expand" 13 14
133 $ commit 16 "merge two known; one immediate right, one near right" 0 1
133 $ commit 16 "merge two known; one immediate right, one near right" 0 1
134 $ commit 17 "expand" 12 16
134 $ commit 17 "expand" 12 16
135 $ commit 18 "merge two known; two far left" 1 15
135 $ commit 18 "merge two known; two far left" 1 15
136 $ commit 19 "expand" 15 17
136 $ commit 19 "expand" 15 17
137 $ commit 20 "merge two known; two far right" 0 18
137 $ commit 20 "merge two known; two far right" 0 18
138 $ commit 21 "expand" 19 20
138 $ commit 21 "expand" 19 20
139 $ commit 22 "merge two known; one far left, one far right" 18 21
139 $ commit 22 "merge two known; one far left, one far right" 18 21
140 $ commit 23 "merge one known; immediate left" 1 22
140 $ commit 23 "merge one known; immediate left" 1 22
141 $ commit 24 "merge one known; immediate right" 0 23
141 $ commit 24 "merge one known; immediate right" 0 23
142 $ commit 25 "merge one known; far left" 21 24
142 $ commit 25 "merge one known; far left" 21 24
143 $ commit 26 "merge one known; far right" 18 25
143 $ commit 26 "merge one known; far right" 18 25
144 $ commit 27 "collapse" 21
144 $ commit 27 "collapse" 21
145 $ commit 28 "merge zero known" 1 26
145 $ commit 28 "merge zero known" 1 26
146 $ commit 29 "regular commit" 0
146 $ commit 29 "regular commit" 0
147 $ commit 30 "expand" 28 29
147 $ commit 30 "expand" 28 29
148 $ commit 31 "expand" 21 30
148 $ commit 31 "expand" 21 30
149 $ commit 32 "expand" 27 31
149 $ commit 32 "expand" 27 31
150 $ commit 33 "head" 18
150 $ commit 33 "head" 18
151 $ commit 34 "head" 32
151 $ commit 34 "head" 32
152
152
153
153
154 $ hg log -G -q
154 $ hg log -G -q
155 @ 34:fea3ac5810e0
155 @ 34:fea3ac5810e0
156 |
156 |
157 | o 33:68608f5145f9
157 | o 33:68608f5145f9
158 | |
158 | |
159 o | 32:d06dffa21a31
159 o | 32:d06dffa21a31
160 |\ \
160 |\ \
161 | o \ 31:621d83e11f67
161 | o \ 31:621d83e11f67
162 | |\ \
162 | |\ \
163 | | o \ 30:6e11cd4b648f
163 | | o \ 30:6e11cd4b648f
164 | | |\ \
164 | | |\ \
165 | | | o | 29:cd9bb2be7593
165 | | | o | 29:cd9bb2be7593
166 | | | | |
166 | | | | |
167 | | o | | 28:44ecd0b9ae99
167 | | o | | 28:44ecd0b9ae99
168 | | |\ \ \
168 | | |\ \ \
169 o | | | | | 27:886ed638191b
169 o | | | | | 27:886ed638191b
170 |/ / / / /
170 |/ / / / /
171 | | o---+ 26:7f25b6c2f0b9
171 | | o---+ 26:7f25b6c2f0b9
172 | | | | |
172 | | | | |
173 +---o | | 25:91da8ed57247
173 +---o | | 25:91da8ed57247
174 | | | | |
174 | | | | |
175 | | o | | 24:a9c19a3d96b7
175 | | o | | 24:a9c19a3d96b7
176 | | |\| |
176 | | |\| |
177 | | o | | 23:a01cddf0766d
177 | | o | | 23:a01cddf0766d
178 | |/| | |
178 | |/| | |
179 +---o---+ 22:e0d9cccacb5d
179 +---o---+ 22:e0d9cccacb5d
180 | | / /
180 | | / /
181 o | | | 21:d42a756af44d
181 o | | | 21:d42a756af44d
182 |\ \ \ \
182 |\ \ \ \
183 | o---+-+ 20:d30ed6450e32
183 | o---+-+ 20:d30ed6450e32
184 | / / /
184 | / / /
185 o | | | 19:31ddc2c1573b
185 o | | | 19:31ddc2c1573b
186 |\ \ \ \
186 |\ \ \ \
187 +---+---o 18:1aa84d96232a
187 +---+---o 18:1aa84d96232a
188 | | | |
188 | | | |
189 | o | | 17:44765d7c06e0
189 | o | | 17:44765d7c06e0
190 | |\ \ \
190 | |\ \ \
191 | | o---+ 16:3677d192927d
191 | | o---+ 16:3677d192927d
192 | | |/ /
192 | | |/ /
193 o | | | 15:1dda3f72782d
193 o | | | 15:1dda3f72782d
194 |\ \ \ \
194 |\ \ \ \
195 | o-----+ 14:8eac370358ef
195 | o-----+ 14:8eac370358ef
196 | |/ / /
196 | |/ / /
197 o | | | 13:22d8966a97e3
197 o | | | 13:22d8966a97e3
198 |\ \ \ \
198 |\ \ \ \
199 +---o | | 12:86b91144a6e9
199 +---o | | 12:86b91144a6e9
200 | | |/ /
200 | | |/ /
201 | o | | 11:832d76e6bdf2
201 | o | | 11:832d76e6bdf2
202 | |\ \ \
202 | |\ \ \
203 | | o---+ 10:74c64d036d72
203 | | o---+ 10:74c64d036d72
204 | |/ / /
204 | |/ / /
205 o | | | 9:7010c0af0a35
205 o | | | 9:7010c0af0a35
206 |\ \ \ \
206 |\ \ \ \
207 | o-----+ 8:7a0b11f71937
207 | o-----+ 8:7a0b11f71937
208 |/ / / /
208 |/ / / /
209 o | | | 7:b632bb1b1224
209 o | | | 7:b632bb1b1224
210 |\ \ \ \
210 |\ \ \ \
211 +---o | | 6:b105a072e251
211 +---o | | 6:b105a072e251
212 | |/ / /
212 | |/ / /
213 | o | | 5:4409d547b708
213 | o | | 5:4409d547b708
214 | |\ \ \
214 | |\ \ \
215 | | o | | 4:26a8bac39d9f
215 | | o | | 4:26a8bac39d9f
216 | |/|/ /
216 | |/|/ /
217 | o / / 3:27eef8ed80b4
217 | o / / 3:27eef8ed80b4
218 |/ / /
218 |/ / /
219 o / / 2:3d9a33b8d1e1
219 o / / 2:3d9a33b8d1e1
220 |/ /
220 |/ /
221 o / 1:6db2ef61d156
221 o / 1:6db2ef61d156
222 |/
222 |/
223 o 0:e6eb3150255d
223 o 0:e6eb3150255d
224
224
225
225
226 $ hg log -G
226 $ hg log -G
227 @ changeset: 34:fea3ac5810e0
227 @ changeset: 34:fea3ac5810e0
228 | tag: tip
228 | tag: tip
229 | parent: 32:d06dffa21a31
229 | parent: 32:d06dffa21a31
230 | user: test
230 | user: test
231 | date: Thu Jan 01 00:00:34 1970 +0000
231 | date: Thu Jan 01 00:00:34 1970 +0000
232 | summary: (34) head
232 | summary: (34) head
233 |
233 |
234 | o changeset: 33:68608f5145f9
234 | o changeset: 33:68608f5145f9
235 | | parent: 18:1aa84d96232a
235 | | parent: 18:1aa84d96232a
236 | | user: test
236 | | user: test
237 | | date: Thu Jan 01 00:00:33 1970 +0000
237 | | date: Thu Jan 01 00:00:33 1970 +0000
238 | | summary: (33) head
238 | | summary: (33) head
239 | |
239 | |
240 o | changeset: 32:d06dffa21a31
240 o | changeset: 32:d06dffa21a31
241 |\ \ parent: 27:886ed638191b
241 |\ \ parent: 27:886ed638191b
242 | | | parent: 31:621d83e11f67
242 | | | parent: 31:621d83e11f67
243 | | | user: test
243 | | | user: test
244 | | | date: Thu Jan 01 00:00:32 1970 +0000
244 | | | date: Thu Jan 01 00:00:32 1970 +0000
245 | | | summary: (32) expand
245 | | | summary: (32) expand
246 | | |
246 | | |
247 | o | changeset: 31:621d83e11f67
247 | o | changeset: 31:621d83e11f67
248 | |\ \ parent: 21:d42a756af44d
248 | |\ \ parent: 21:d42a756af44d
249 | | | | parent: 30:6e11cd4b648f
249 | | | | parent: 30:6e11cd4b648f
250 | | | | user: test
250 | | | | user: test
251 | | | | date: Thu Jan 01 00:00:31 1970 +0000
251 | | | | date: Thu Jan 01 00:00:31 1970 +0000
252 | | | | summary: (31) expand
252 | | | | summary: (31) expand
253 | | | |
253 | | | |
254 | | o | changeset: 30:6e11cd4b648f
254 | | o | changeset: 30:6e11cd4b648f
255 | | |\ \ parent: 28:44ecd0b9ae99
255 | | |\ \ parent: 28:44ecd0b9ae99
256 | | | | | parent: 29:cd9bb2be7593
256 | | | | | parent: 29:cd9bb2be7593
257 | | | | | user: test
257 | | | | | user: test
258 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
258 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
259 | | | | | summary: (30) expand
259 | | | | | summary: (30) expand
260 | | | | |
260 | | | | |
261 | | | o | changeset: 29:cd9bb2be7593
261 | | | o | changeset: 29:cd9bb2be7593
262 | | | | | parent: 0:e6eb3150255d
262 | | | | | parent: 0:e6eb3150255d
263 | | | | | user: test
263 | | | | | user: test
264 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
264 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
265 | | | | | summary: (29) regular commit
265 | | | | | summary: (29) regular commit
266 | | | | |
266 | | | | |
267 | | o | | changeset: 28:44ecd0b9ae99
267 | | o | | changeset: 28:44ecd0b9ae99
268 | | |\ \ \ parent: 1:6db2ef61d156
268 | | |\ \ \ parent: 1:6db2ef61d156
269 | | | | | | parent: 26:7f25b6c2f0b9
269 | | | | | | parent: 26:7f25b6c2f0b9
270 | | | | | | user: test
270 | | | | | | user: test
271 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
271 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
272 | | | | | | summary: (28) merge zero known
272 | | | | | | summary: (28) merge zero known
273 | | | | | |
273 | | | | | |
274 o | | | | | changeset: 27:886ed638191b
274 o | | | | | changeset: 27:886ed638191b
275 |/ / / / / parent: 21:d42a756af44d
275 |/ / / / / parent: 21:d42a756af44d
276 | | | | | user: test
276 | | | | | user: test
277 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
277 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
278 | | | | | summary: (27) collapse
278 | | | | | summary: (27) collapse
279 | | | | |
279 | | | | |
280 | | o---+ changeset: 26:7f25b6c2f0b9
280 | | o---+ changeset: 26:7f25b6c2f0b9
281 | | | | | parent: 18:1aa84d96232a
281 | | | | | parent: 18:1aa84d96232a
282 | | | | | parent: 25:91da8ed57247
282 | | | | | parent: 25:91da8ed57247
283 | | | | | user: test
283 | | | | | user: test
284 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
284 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
285 | | | | | summary: (26) merge one known; far right
285 | | | | | summary: (26) merge one known; far right
286 | | | | |
286 | | | | |
287 +---o | | changeset: 25:91da8ed57247
287 +---o | | changeset: 25:91da8ed57247
288 | | | | | parent: 21:d42a756af44d
288 | | | | | parent: 21:d42a756af44d
289 | | | | | parent: 24:a9c19a3d96b7
289 | | | | | parent: 24:a9c19a3d96b7
290 | | | | | user: test
290 | | | | | user: test
291 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
291 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
292 | | | | | summary: (25) merge one known; far left
292 | | | | | summary: (25) merge one known; far left
293 | | | | |
293 | | | | |
294 | | o | | changeset: 24:a9c19a3d96b7
294 | | o | | changeset: 24:a9c19a3d96b7
295 | | |\| | parent: 0:e6eb3150255d
295 | | |\| | parent: 0:e6eb3150255d
296 | | | | | parent: 23:a01cddf0766d
296 | | | | | parent: 23:a01cddf0766d
297 | | | | | user: test
297 | | | | | user: test
298 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
298 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
299 | | | | | summary: (24) merge one known; immediate right
299 | | | | | summary: (24) merge one known; immediate right
300 | | | | |
300 | | | | |
301 | | o | | changeset: 23:a01cddf0766d
301 | | o | | changeset: 23:a01cddf0766d
302 | |/| | | parent: 1:6db2ef61d156
302 | |/| | | parent: 1:6db2ef61d156
303 | | | | | parent: 22:e0d9cccacb5d
303 | | | | | parent: 22:e0d9cccacb5d
304 | | | | | user: test
304 | | | | | user: test
305 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
305 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
306 | | | | | summary: (23) merge one known; immediate left
306 | | | | | summary: (23) merge one known; immediate left
307 | | | | |
307 | | | | |
308 +---o---+ changeset: 22:e0d9cccacb5d
308 +---o---+ changeset: 22:e0d9cccacb5d
309 | | | | parent: 18:1aa84d96232a
309 | | | | parent: 18:1aa84d96232a
310 | | / / parent: 21:d42a756af44d
310 | | / / parent: 21:d42a756af44d
311 | | | | user: test
311 | | | | user: test
312 | | | | date: Thu Jan 01 00:00:22 1970 +0000
312 | | | | date: Thu Jan 01 00:00:22 1970 +0000
313 | | | | summary: (22) merge two known; one far left, one far right
313 | | | | summary: (22) merge two known; one far left, one far right
314 | | | |
314 | | | |
315 o | | | changeset: 21:d42a756af44d
315 o | | | changeset: 21:d42a756af44d
316 |\ \ \ \ parent: 19:31ddc2c1573b
316 |\ \ \ \ parent: 19:31ddc2c1573b
317 | | | | | parent: 20:d30ed6450e32
317 | | | | | parent: 20:d30ed6450e32
318 | | | | | user: test
318 | | | | | user: test
319 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
319 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
320 | | | | | summary: (21) expand
320 | | | | | summary: (21) expand
321 | | | | |
321 | | | | |
322 | o---+-+ changeset: 20:d30ed6450e32
322 | o---+-+ changeset: 20:d30ed6450e32
323 | | | | parent: 0:e6eb3150255d
323 | | | | parent: 0:e6eb3150255d
324 | / / / parent: 18:1aa84d96232a
324 | / / / parent: 18:1aa84d96232a
325 | | | | user: test
325 | | | | user: test
326 | | | | date: Thu Jan 01 00:00:20 1970 +0000
326 | | | | date: Thu Jan 01 00:00:20 1970 +0000
327 | | | | summary: (20) merge two known; two far right
327 | | | | summary: (20) merge two known; two far right
328 | | | |
328 | | | |
329 o | | | changeset: 19:31ddc2c1573b
329 o | | | changeset: 19:31ddc2c1573b
330 |\ \ \ \ parent: 15:1dda3f72782d
330 |\ \ \ \ parent: 15:1dda3f72782d
331 | | | | | parent: 17:44765d7c06e0
331 | | | | | parent: 17:44765d7c06e0
332 | | | | | user: test
332 | | | | | user: test
333 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
333 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
334 | | | | | summary: (19) expand
334 | | | | | summary: (19) expand
335 | | | | |
335 | | | | |
336 +---+---o changeset: 18:1aa84d96232a
336 +---+---o changeset: 18:1aa84d96232a
337 | | | | parent: 1:6db2ef61d156
337 | | | | parent: 1:6db2ef61d156
338 | | | | parent: 15:1dda3f72782d
338 | | | | parent: 15:1dda3f72782d
339 | | | | user: test
339 | | | | user: test
340 | | | | date: Thu Jan 01 00:00:18 1970 +0000
340 | | | | date: Thu Jan 01 00:00:18 1970 +0000
341 | | | | summary: (18) merge two known; two far left
341 | | | | summary: (18) merge two known; two far left
342 | | | |
342 | | | |
343 | o | | changeset: 17:44765d7c06e0
343 | o | | changeset: 17:44765d7c06e0
344 | |\ \ \ parent: 12:86b91144a6e9
344 | |\ \ \ parent: 12:86b91144a6e9
345 | | | | | parent: 16:3677d192927d
345 | | | | | parent: 16:3677d192927d
346 | | | | | user: test
346 | | | | | user: test
347 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
347 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
348 | | | | | summary: (17) expand
348 | | | | | summary: (17) expand
349 | | | | |
349 | | | | |
350 | | o---+ changeset: 16:3677d192927d
350 | | o---+ changeset: 16:3677d192927d
351 | | | | | parent: 0:e6eb3150255d
351 | | | | | parent: 0:e6eb3150255d
352 | | |/ / parent: 1:6db2ef61d156
352 | | |/ / parent: 1:6db2ef61d156
353 | | | | user: test
353 | | | | user: test
354 | | | | date: Thu Jan 01 00:00:16 1970 +0000
354 | | | | date: Thu Jan 01 00:00:16 1970 +0000
355 | | | | summary: (16) merge two known; one immediate right, one near right
355 | | | | summary: (16) merge two known; one immediate right, one near right
356 | | | |
356 | | | |
357 o | | | changeset: 15:1dda3f72782d
357 o | | | changeset: 15:1dda3f72782d
358 |\ \ \ \ parent: 13:22d8966a97e3
358 |\ \ \ \ parent: 13:22d8966a97e3
359 | | | | | parent: 14:8eac370358ef
359 | | | | | parent: 14:8eac370358ef
360 | | | | | user: test
360 | | | | | user: test
361 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
361 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
362 | | | | | summary: (15) expand
362 | | | | | summary: (15) expand
363 | | | | |
363 | | | | |
364 | o-----+ changeset: 14:8eac370358ef
364 | o-----+ changeset: 14:8eac370358ef
365 | | | | | parent: 0:e6eb3150255d
365 | | | | | parent: 0:e6eb3150255d
366 | |/ / / parent: 12:86b91144a6e9
366 | |/ / / parent: 12:86b91144a6e9
367 | | | | user: test
367 | | | | user: test
368 | | | | date: Thu Jan 01 00:00:14 1970 +0000
368 | | | | date: Thu Jan 01 00:00:14 1970 +0000
369 | | | | summary: (14) merge two known; one immediate right, one far right
369 | | | | summary: (14) merge two known; one immediate right, one far right
370 | | | |
370 | | | |
371 o | | | changeset: 13:22d8966a97e3
371 o | | | changeset: 13:22d8966a97e3
372 |\ \ \ \ parent: 9:7010c0af0a35
372 |\ \ \ \ parent: 9:7010c0af0a35
373 | | | | | parent: 11:832d76e6bdf2
373 | | | | | parent: 11:832d76e6bdf2
374 | | | | | user: test
374 | | | | | user: test
375 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
375 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
376 | | | | | summary: (13) expand
376 | | | | | summary: (13) expand
377 | | | | |
377 | | | | |
378 +---o | | changeset: 12:86b91144a6e9
378 +---o | | changeset: 12:86b91144a6e9
379 | | |/ / parent: 1:6db2ef61d156
379 | | |/ / parent: 1:6db2ef61d156
380 | | | | parent: 9:7010c0af0a35
380 | | | | parent: 9:7010c0af0a35
381 | | | | user: test
381 | | | | user: test
382 | | | | date: Thu Jan 01 00:00:12 1970 +0000
382 | | | | date: Thu Jan 01 00:00:12 1970 +0000
383 | | | | summary: (12) merge two known; one immediate right, one far left
383 | | | | summary: (12) merge two known; one immediate right, one far left
384 | | | |
384 | | | |
385 | o | | changeset: 11:832d76e6bdf2
385 | o | | changeset: 11:832d76e6bdf2
386 | |\ \ \ parent: 6:b105a072e251
386 | |\ \ \ parent: 6:b105a072e251
387 | | | | | parent: 10:74c64d036d72
387 | | | | | parent: 10:74c64d036d72
388 | | | | | user: test
388 | | | | | user: test
389 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
389 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
390 | | | | | summary: (11) expand
390 | | | | | summary: (11) expand
391 | | | | |
391 | | | | |
392 | | o---+ changeset: 10:74c64d036d72
392 | | o---+ changeset: 10:74c64d036d72
393 | | | | | parent: 0:e6eb3150255d
393 | | | | | parent: 0:e6eb3150255d
394 | |/ / / parent: 6:b105a072e251
394 | |/ / / parent: 6:b105a072e251
395 | | | | user: test
395 | | | | user: test
396 | | | | date: Thu Jan 01 00:00:10 1970 +0000
396 | | | | date: Thu Jan 01 00:00:10 1970 +0000
397 | | | | summary: (10) merge two known; one immediate left, one near right
397 | | | | summary: (10) merge two known; one immediate left, one near right
398 | | | |
398 | | | |
399 o | | | changeset: 9:7010c0af0a35
399 o | | | changeset: 9:7010c0af0a35
400 |\ \ \ \ parent: 7:b632bb1b1224
400 |\ \ \ \ parent: 7:b632bb1b1224
401 | | | | | parent: 8:7a0b11f71937
401 | | | | | parent: 8:7a0b11f71937
402 | | | | | user: test
402 | | | | | user: test
403 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
403 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
404 | | | | | summary: (9) expand
404 | | | | | summary: (9) expand
405 | | | | |
405 | | | | |
406 | o-----+ changeset: 8:7a0b11f71937
406 | o-----+ changeset: 8:7a0b11f71937
407 | | | | | parent: 0:e6eb3150255d
407 | | | | | parent: 0:e6eb3150255d
408 |/ / / / parent: 7:b632bb1b1224
408 |/ / / / parent: 7:b632bb1b1224
409 | | | | user: test
409 | | | | user: test
410 | | | | date: Thu Jan 01 00:00:08 1970 +0000
410 | | | | date: Thu Jan 01 00:00:08 1970 +0000
411 | | | | summary: (8) merge two known; one immediate left, one far right
411 | | | | summary: (8) merge two known; one immediate left, one far right
412 | | | |
412 | | | |
413 o | | | changeset: 7:b632bb1b1224
413 o | | | changeset: 7:b632bb1b1224
414 |\ \ \ \ parent: 2:3d9a33b8d1e1
414 |\ \ \ \ parent: 2:3d9a33b8d1e1
415 | | | | | parent: 5:4409d547b708
415 | | | | | parent: 5:4409d547b708
416 | | | | | user: test
416 | | | | | user: test
417 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
417 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
418 | | | | | summary: (7) expand
418 | | | | | summary: (7) expand
419 | | | | |
419 | | | | |
420 +---o | | changeset: 6:b105a072e251
420 +---o | | changeset: 6:b105a072e251
421 | |/ / / parent: 2:3d9a33b8d1e1
421 | |/ / / parent: 2:3d9a33b8d1e1
422 | | | | parent: 5:4409d547b708
422 | | | | parent: 5:4409d547b708
423 | | | | user: test
423 | | | | user: test
424 | | | | date: Thu Jan 01 00:00:06 1970 +0000
424 | | | | date: Thu Jan 01 00:00:06 1970 +0000
425 | | | | summary: (6) merge two known; one immediate left, one far left
425 | | | | summary: (6) merge two known; one immediate left, one far left
426 | | | |
426 | | | |
427 | o | | changeset: 5:4409d547b708
427 | o | | changeset: 5:4409d547b708
428 | |\ \ \ parent: 3:27eef8ed80b4
428 | |\ \ \ parent: 3:27eef8ed80b4
429 | | | | | parent: 4:26a8bac39d9f
429 | | | | | parent: 4:26a8bac39d9f
430 | | | | | user: test
430 | | | | | user: test
431 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
431 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
432 | | | | | summary: (5) expand
432 | | | | | summary: (5) expand
433 | | | | |
433 | | | | |
434 | | o | | changeset: 4:26a8bac39d9f
434 | | o | | changeset: 4:26a8bac39d9f
435 | |/|/ / parent: 1:6db2ef61d156
435 | |/|/ / parent: 1:6db2ef61d156
436 | | | | parent: 3:27eef8ed80b4
436 | | | | parent: 3:27eef8ed80b4
437 | | | | user: test
437 | | | | user: test
438 | | | | date: Thu Jan 01 00:00:04 1970 +0000
438 | | | | date: Thu Jan 01 00:00:04 1970 +0000
439 | | | | summary: (4) merge two known; one immediate left, one immediate right
439 | | | | summary: (4) merge two known; one immediate left, one immediate right
440 | | | |
440 | | | |
441 | o | | changeset: 3:27eef8ed80b4
441 | o | | changeset: 3:27eef8ed80b4
442 |/ / / user: test
442 |/ / / user: test
443 | | | date: Thu Jan 01 00:00:03 1970 +0000
443 | | | date: Thu Jan 01 00:00:03 1970 +0000
444 | | | summary: (3) collapse
444 | | | summary: (3) collapse
445 | | |
445 | | |
446 o | | changeset: 2:3d9a33b8d1e1
446 o | | changeset: 2:3d9a33b8d1e1
447 |/ / user: test
447 |/ / user: test
448 | | date: Thu Jan 01 00:00:02 1970 +0000
448 | | date: Thu Jan 01 00:00:02 1970 +0000
449 | | summary: (2) collapse
449 | | summary: (2) collapse
450 | |
450 | |
451 o | changeset: 1:6db2ef61d156
451 o | changeset: 1:6db2ef61d156
452 |/ user: test
452 |/ user: test
453 | date: Thu Jan 01 00:00:01 1970 +0000
453 | date: Thu Jan 01 00:00:01 1970 +0000
454 | summary: (1) collapse
454 | summary: (1) collapse
455 |
455 |
456 o changeset: 0:e6eb3150255d
456 o changeset: 0:e6eb3150255d
457 user: test
457 user: test
458 date: Thu Jan 01 00:00:00 1970 +0000
458 date: Thu Jan 01 00:00:00 1970 +0000
459 summary: (0) root
459 summary: (0) root
460
460
461
461
462 File glog:
462 File glog:
463 $ hg log -G a
463 $ hg log -G a
464 @ changeset: 34:fea3ac5810e0
464 @ changeset: 34:fea3ac5810e0
465 | tag: tip
465 | tag: tip
466 | parent: 32:d06dffa21a31
466 | parent: 32:d06dffa21a31
467 | user: test
467 | user: test
468 | date: Thu Jan 01 00:00:34 1970 +0000
468 | date: Thu Jan 01 00:00:34 1970 +0000
469 | summary: (34) head
469 | summary: (34) head
470 |
470 |
471 | o changeset: 33:68608f5145f9
471 | o changeset: 33:68608f5145f9
472 | | parent: 18:1aa84d96232a
472 | | parent: 18:1aa84d96232a
473 | | user: test
473 | | user: test
474 | | date: Thu Jan 01 00:00:33 1970 +0000
474 | | date: Thu Jan 01 00:00:33 1970 +0000
475 | | summary: (33) head
475 | | summary: (33) head
476 | |
476 | |
477 o | changeset: 32:d06dffa21a31
477 o | changeset: 32:d06dffa21a31
478 |\ \ parent: 27:886ed638191b
478 |\ \ parent: 27:886ed638191b
479 | | | parent: 31:621d83e11f67
479 | | | parent: 31:621d83e11f67
480 | | | user: test
480 | | | user: test
481 | | | date: Thu Jan 01 00:00:32 1970 +0000
481 | | | date: Thu Jan 01 00:00:32 1970 +0000
482 | | | summary: (32) expand
482 | | | summary: (32) expand
483 | | |
483 | | |
484 | o | changeset: 31:621d83e11f67
484 | o | changeset: 31:621d83e11f67
485 | |\ \ parent: 21:d42a756af44d
485 | |\ \ parent: 21:d42a756af44d
486 | | | | parent: 30:6e11cd4b648f
486 | | | | parent: 30:6e11cd4b648f
487 | | | | user: test
487 | | | | user: test
488 | | | | date: Thu Jan 01 00:00:31 1970 +0000
488 | | | | date: Thu Jan 01 00:00:31 1970 +0000
489 | | | | summary: (31) expand
489 | | | | summary: (31) expand
490 | | | |
490 | | | |
491 | | o | changeset: 30:6e11cd4b648f
491 | | o | changeset: 30:6e11cd4b648f
492 | | |\ \ parent: 28:44ecd0b9ae99
492 | | |\ \ parent: 28:44ecd0b9ae99
493 | | | | | parent: 29:cd9bb2be7593
493 | | | | | parent: 29:cd9bb2be7593
494 | | | | | user: test
494 | | | | | user: test
495 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
495 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
496 | | | | | summary: (30) expand
496 | | | | | summary: (30) expand
497 | | | | |
497 | | | | |
498 | | | o | changeset: 29:cd9bb2be7593
498 | | | o | changeset: 29:cd9bb2be7593
499 | | | | | parent: 0:e6eb3150255d
499 | | | | | parent: 0:e6eb3150255d
500 | | | | | user: test
500 | | | | | user: test
501 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
501 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
502 | | | | | summary: (29) regular commit
502 | | | | | summary: (29) regular commit
503 | | | | |
503 | | | | |
504 | | o | | changeset: 28:44ecd0b9ae99
504 | | o | | changeset: 28:44ecd0b9ae99
505 | | |\ \ \ parent: 1:6db2ef61d156
505 | | |\ \ \ parent: 1:6db2ef61d156
506 | | | | | | parent: 26:7f25b6c2f0b9
506 | | | | | | parent: 26:7f25b6c2f0b9
507 | | | | | | user: test
507 | | | | | | user: test
508 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
508 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
509 | | | | | | summary: (28) merge zero known
509 | | | | | | summary: (28) merge zero known
510 | | | | | |
510 | | | | | |
511 o | | | | | changeset: 27:886ed638191b
511 o | | | | | changeset: 27:886ed638191b
512 |/ / / / / parent: 21:d42a756af44d
512 |/ / / / / parent: 21:d42a756af44d
513 | | | | | user: test
513 | | | | | user: test
514 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
514 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
515 | | | | | summary: (27) collapse
515 | | | | | summary: (27) collapse
516 | | | | |
516 | | | | |
517 | | o---+ changeset: 26:7f25b6c2f0b9
517 | | o---+ changeset: 26:7f25b6c2f0b9
518 | | | | | parent: 18:1aa84d96232a
518 | | | | | parent: 18:1aa84d96232a
519 | | | | | parent: 25:91da8ed57247
519 | | | | | parent: 25:91da8ed57247
520 | | | | | user: test
520 | | | | | user: test
521 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
521 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
522 | | | | | summary: (26) merge one known; far right
522 | | | | | summary: (26) merge one known; far right
523 | | | | |
523 | | | | |
524 +---o | | changeset: 25:91da8ed57247
524 +---o | | changeset: 25:91da8ed57247
525 | | | | | parent: 21:d42a756af44d
525 | | | | | parent: 21:d42a756af44d
526 | | | | | parent: 24:a9c19a3d96b7
526 | | | | | parent: 24:a9c19a3d96b7
527 | | | | | user: test
527 | | | | | user: test
528 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
528 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
529 | | | | | summary: (25) merge one known; far left
529 | | | | | summary: (25) merge one known; far left
530 | | | | |
530 | | | | |
531 | | o | | changeset: 24:a9c19a3d96b7
531 | | o | | changeset: 24:a9c19a3d96b7
532 | | |\| | parent: 0:e6eb3150255d
532 | | |\| | parent: 0:e6eb3150255d
533 | | | | | parent: 23:a01cddf0766d
533 | | | | | parent: 23:a01cddf0766d
534 | | | | | user: test
534 | | | | | user: test
535 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
535 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
536 | | | | | summary: (24) merge one known; immediate right
536 | | | | | summary: (24) merge one known; immediate right
537 | | | | |
537 | | | | |
538 | | o | | changeset: 23:a01cddf0766d
538 | | o | | changeset: 23:a01cddf0766d
539 | |/| | | parent: 1:6db2ef61d156
539 | |/| | | parent: 1:6db2ef61d156
540 | | | | | parent: 22:e0d9cccacb5d
540 | | | | | parent: 22:e0d9cccacb5d
541 | | | | | user: test
541 | | | | | user: test
542 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
542 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
543 | | | | | summary: (23) merge one known; immediate left
543 | | | | | summary: (23) merge one known; immediate left
544 | | | | |
544 | | | | |
545 +---o---+ changeset: 22:e0d9cccacb5d
545 +---o---+ changeset: 22:e0d9cccacb5d
546 | | | | parent: 18:1aa84d96232a
546 | | | | parent: 18:1aa84d96232a
547 | | / / parent: 21:d42a756af44d
547 | | / / parent: 21:d42a756af44d
548 | | | | user: test
548 | | | | user: test
549 | | | | date: Thu Jan 01 00:00:22 1970 +0000
549 | | | | date: Thu Jan 01 00:00:22 1970 +0000
550 | | | | summary: (22) merge two known; one far left, one far right
550 | | | | summary: (22) merge two known; one far left, one far right
551 | | | |
551 | | | |
552 o | | | changeset: 21:d42a756af44d
552 o | | | changeset: 21:d42a756af44d
553 |\ \ \ \ parent: 19:31ddc2c1573b
553 |\ \ \ \ parent: 19:31ddc2c1573b
554 | | | | | parent: 20:d30ed6450e32
554 | | | | | parent: 20:d30ed6450e32
555 | | | | | user: test
555 | | | | | user: test
556 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
556 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
557 | | | | | summary: (21) expand
557 | | | | | summary: (21) expand
558 | | | | |
558 | | | | |
559 | o---+-+ changeset: 20:d30ed6450e32
559 | o---+-+ changeset: 20:d30ed6450e32
560 | | | | parent: 0:e6eb3150255d
560 | | | | parent: 0:e6eb3150255d
561 | / / / parent: 18:1aa84d96232a
561 | / / / parent: 18:1aa84d96232a
562 | | | | user: test
562 | | | | user: test
563 | | | | date: Thu Jan 01 00:00:20 1970 +0000
563 | | | | date: Thu Jan 01 00:00:20 1970 +0000
564 | | | | summary: (20) merge two known; two far right
564 | | | | summary: (20) merge two known; two far right
565 | | | |
565 | | | |
566 o | | | changeset: 19:31ddc2c1573b
566 o | | | changeset: 19:31ddc2c1573b
567 |\ \ \ \ parent: 15:1dda3f72782d
567 |\ \ \ \ parent: 15:1dda3f72782d
568 | | | | | parent: 17:44765d7c06e0
568 | | | | | parent: 17:44765d7c06e0
569 | | | | | user: test
569 | | | | | user: test
570 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
570 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
571 | | | | | summary: (19) expand
571 | | | | | summary: (19) expand
572 | | | | |
572 | | | | |
573 +---+---o changeset: 18:1aa84d96232a
573 +---+---o changeset: 18:1aa84d96232a
574 | | | | parent: 1:6db2ef61d156
574 | | | | parent: 1:6db2ef61d156
575 | | | | parent: 15:1dda3f72782d
575 | | | | parent: 15:1dda3f72782d
576 | | | | user: test
576 | | | | user: test
577 | | | | date: Thu Jan 01 00:00:18 1970 +0000
577 | | | | date: Thu Jan 01 00:00:18 1970 +0000
578 | | | | summary: (18) merge two known; two far left
578 | | | | summary: (18) merge two known; two far left
579 | | | |
579 | | | |
580 | o | | changeset: 17:44765d7c06e0
580 | o | | changeset: 17:44765d7c06e0
581 | |\ \ \ parent: 12:86b91144a6e9
581 | |\ \ \ parent: 12:86b91144a6e9
582 | | | | | parent: 16:3677d192927d
582 | | | | | parent: 16:3677d192927d
583 | | | | | user: test
583 | | | | | user: test
584 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
584 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
585 | | | | | summary: (17) expand
585 | | | | | summary: (17) expand
586 | | | | |
586 | | | | |
587 | | o---+ changeset: 16:3677d192927d
587 | | o---+ changeset: 16:3677d192927d
588 | | | | | parent: 0:e6eb3150255d
588 | | | | | parent: 0:e6eb3150255d
589 | | |/ / parent: 1:6db2ef61d156
589 | | |/ / parent: 1:6db2ef61d156
590 | | | | user: test
590 | | | | user: test
591 | | | | date: Thu Jan 01 00:00:16 1970 +0000
591 | | | | date: Thu Jan 01 00:00:16 1970 +0000
592 | | | | summary: (16) merge two known; one immediate right, one near right
592 | | | | summary: (16) merge two known; one immediate right, one near right
593 | | | |
593 | | | |
594 o | | | changeset: 15:1dda3f72782d
594 o | | | changeset: 15:1dda3f72782d
595 |\ \ \ \ parent: 13:22d8966a97e3
595 |\ \ \ \ parent: 13:22d8966a97e3
596 | | | | | parent: 14:8eac370358ef
596 | | | | | parent: 14:8eac370358ef
597 | | | | | user: test
597 | | | | | user: test
598 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
598 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
599 | | | | | summary: (15) expand
599 | | | | | summary: (15) expand
600 | | | | |
600 | | | | |
601 | o-----+ changeset: 14:8eac370358ef
601 | o-----+ changeset: 14:8eac370358ef
602 | | | | | parent: 0:e6eb3150255d
602 | | | | | parent: 0:e6eb3150255d
603 | |/ / / parent: 12:86b91144a6e9
603 | |/ / / parent: 12:86b91144a6e9
604 | | | | user: test
604 | | | | user: test
605 | | | | date: Thu Jan 01 00:00:14 1970 +0000
605 | | | | date: Thu Jan 01 00:00:14 1970 +0000
606 | | | | summary: (14) merge two known; one immediate right, one far right
606 | | | | summary: (14) merge two known; one immediate right, one far right
607 | | | |
607 | | | |
608 o | | | changeset: 13:22d8966a97e3
608 o | | | changeset: 13:22d8966a97e3
609 |\ \ \ \ parent: 9:7010c0af0a35
609 |\ \ \ \ parent: 9:7010c0af0a35
610 | | | | | parent: 11:832d76e6bdf2
610 | | | | | parent: 11:832d76e6bdf2
611 | | | | | user: test
611 | | | | | user: test
612 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
612 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
613 | | | | | summary: (13) expand
613 | | | | | summary: (13) expand
614 | | | | |
614 | | | | |
615 +---o | | changeset: 12:86b91144a6e9
615 +---o | | changeset: 12:86b91144a6e9
616 | | |/ / parent: 1:6db2ef61d156
616 | | |/ / parent: 1:6db2ef61d156
617 | | | | parent: 9:7010c0af0a35
617 | | | | parent: 9:7010c0af0a35
618 | | | | user: test
618 | | | | user: test
619 | | | | date: Thu Jan 01 00:00:12 1970 +0000
619 | | | | date: Thu Jan 01 00:00:12 1970 +0000
620 | | | | summary: (12) merge two known; one immediate right, one far left
620 | | | | summary: (12) merge two known; one immediate right, one far left
621 | | | |
621 | | | |
622 | o | | changeset: 11:832d76e6bdf2
622 | o | | changeset: 11:832d76e6bdf2
623 | |\ \ \ parent: 6:b105a072e251
623 | |\ \ \ parent: 6:b105a072e251
624 | | | | | parent: 10:74c64d036d72
624 | | | | | parent: 10:74c64d036d72
625 | | | | | user: test
625 | | | | | user: test
626 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
626 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
627 | | | | | summary: (11) expand
627 | | | | | summary: (11) expand
628 | | | | |
628 | | | | |
629 | | o---+ changeset: 10:74c64d036d72
629 | | o---+ changeset: 10:74c64d036d72
630 | | | | | parent: 0:e6eb3150255d
630 | | | | | parent: 0:e6eb3150255d
631 | |/ / / parent: 6:b105a072e251
631 | |/ / / parent: 6:b105a072e251
632 | | | | user: test
632 | | | | user: test
633 | | | | date: Thu Jan 01 00:00:10 1970 +0000
633 | | | | date: Thu Jan 01 00:00:10 1970 +0000
634 | | | | summary: (10) merge two known; one immediate left, one near right
634 | | | | summary: (10) merge two known; one immediate left, one near right
635 | | | |
635 | | | |
636 o | | | changeset: 9:7010c0af0a35
636 o | | | changeset: 9:7010c0af0a35
637 |\ \ \ \ parent: 7:b632bb1b1224
637 |\ \ \ \ parent: 7:b632bb1b1224
638 | | | | | parent: 8:7a0b11f71937
638 | | | | | parent: 8:7a0b11f71937
639 | | | | | user: test
639 | | | | | user: test
640 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
640 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
641 | | | | | summary: (9) expand
641 | | | | | summary: (9) expand
642 | | | | |
642 | | | | |
643 | o-----+ changeset: 8:7a0b11f71937
643 | o-----+ changeset: 8:7a0b11f71937
644 | | | | | parent: 0:e6eb3150255d
644 | | | | | parent: 0:e6eb3150255d
645 |/ / / / parent: 7:b632bb1b1224
645 |/ / / / parent: 7:b632bb1b1224
646 | | | | user: test
646 | | | | user: test
647 | | | | date: Thu Jan 01 00:00:08 1970 +0000
647 | | | | date: Thu Jan 01 00:00:08 1970 +0000
648 | | | | summary: (8) merge two known; one immediate left, one far right
648 | | | | summary: (8) merge two known; one immediate left, one far right
649 | | | |
649 | | | |
650 o | | | changeset: 7:b632bb1b1224
650 o | | | changeset: 7:b632bb1b1224
651 |\ \ \ \ parent: 2:3d9a33b8d1e1
651 |\ \ \ \ parent: 2:3d9a33b8d1e1
652 | | | | | parent: 5:4409d547b708
652 | | | | | parent: 5:4409d547b708
653 | | | | | user: test
653 | | | | | user: test
654 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
654 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
655 | | | | | summary: (7) expand
655 | | | | | summary: (7) expand
656 | | | | |
656 | | | | |
657 +---o | | changeset: 6:b105a072e251
657 +---o | | changeset: 6:b105a072e251
658 | |/ / / parent: 2:3d9a33b8d1e1
658 | |/ / / parent: 2:3d9a33b8d1e1
659 | | | | parent: 5:4409d547b708
659 | | | | parent: 5:4409d547b708
660 | | | | user: test
660 | | | | user: test
661 | | | | date: Thu Jan 01 00:00:06 1970 +0000
661 | | | | date: Thu Jan 01 00:00:06 1970 +0000
662 | | | | summary: (6) merge two known; one immediate left, one far left
662 | | | | summary: (6) merge two known; one immediate left, one far left
663 | | | |
663 | | | |
664 | o | | changeset: 5:4409d547b708
664 | o | | changeset: 5:4409d547b708
665 | |\ \ \ parent: 3:27eef8ed80b4
665 | |\ \ \ parent: 3:27eef8ed80b4
666 | | | | | parent: 4:26a8bac39d9f
666 | | | | | parent: 4:26a8bac39d9f
667 | | | | | user: test
667 | | | | | user: test
668 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
668 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
669 | | | | | summary: (5) expand
669 | | | | | summary: (5) expand
670 | | | | |
670 | | | | |
671 | | o | | changeset: 4:26a8bac39d9f
671 | | o | | changeset: 4:26a8bac39d9f
672 | |/|/ / parent: 1:6db2ef61d156
672 | |/|/ / parent: 1:6db2ef61d156
673 | | | | parent: 3:27eef8ed80b4
673 | | | | parent: 3:27eef8ed80b4
674 | | | | user: test
674 | | | | user: test
675 | | | | date: Thu Jan 01 00:00:04 1970 +0000
675 | | | | date: Thu Jan 01 00:00:04 1970 +0000
676 | | | | summary: (4) merge two known; one immediate left, one immediate right
676 | | | | summary: (4) merge two known; one immediate left, one immediate right
677 | | | |
677 | | | |
678 | o | | changeset: 3:27eef8ed80b4
678 | o | | changeset: 3:27eef8ed80b4
679 |/ / / user: test
679 |/ / / user: test
680 | | | date: Thu Jan 01 00:00:03 1970 +0000
680 | | | date: Thu Jan 01 00:00:03 1970 +0000
681 | | | summary: (3) collapse
681 | | | summary: (3) collapse
682 | | |
682 | | |
683 o | | changeset: 2:3d9a33b8d1e1
683 o | | changeset: 2:3d9a33b8d1e1
684 |/ / user: test
684 |/ / user: test
685 | | date: Thu Jan 01 00:00:02 1970 +0000
685 | | date: Thu Jan 01 00:00:02 1970 +0000
686 | | summary: (2) collapse
686 | | summary: (2) collapse
687 | |
687 | |
688 o | changeset: 1:6db2ef61d156
688 o | changeset: 1:6db2ef61d156
689 |/ user: test
689 |/ user: test
690 | date: Thu Jan 01 00:00:01 1970 +0000
690 | date: Thu Jan 01 00:00:01 1970 +0000
691 | summary: (1) collapse
691 | summary: (1) collapse
692 |
692 |
693 o changeset: 0:e6eb3150255d
693 o changeset: 0:e6eb3150255d
694 user: test
694 user: test
695 date: Thu Jan 01 00:00:00 1970 +0000
695 date: Thu Jan 01 00:00:00 1970 +0000
696 summary: (0) root
696 summary: (0) root
697
697
698
698
699 File glog per revset:
699 File glog per revset:
700
700
701 $ hg log -G -r 'file("a")'
701 $ hg log -G -r 'file("a")'
702 @ changeset: 34:fea3ac5810e0
702 @ changeset: 34:fea3ac5810e0
703 | tag: tip
703 | tag: tip
704 | parent: 32:d06dffa21a31
704 | parent: 32:d06dffa21a31
705 | user: test
705 | user: test
706 | date: Thu Jan 01 00:00:34 1970 +0000
706 | date: Thu Jan 01 00:00:34 1970 +0000
707 | summary: (34) head
707 | summary: (34) head
708 |
708 |
709 | o changeset: 33:68608f5145f9
709 | o changeset: 33:68608f5145f9
710 | | parent: 18:1aa84d96232a
710 | | parent: 18:1aa84d96232a
711 | | user: test
711 | | user: test
712 | | date: Thu Jan 01 00:00:33 1970 +0000
712 | | date: Thu Jan 01 00:00:33 1970 +0000
713 | | summary: (33) head
713 | | summary: (33) head
714 | |
714 | |
715 o | changeset: 32:d06dffa21a31
715 o | changeset: 32:d06dffa21a31
716 |\ \ parent: 27:886ed638191b
716 |\ \ parent: 27:886ed638191b
717 | | | parent: 31:621d83e11f67
717 | | | parent: 31:621d83e11f67
718 | | | user: test
718 | | | user: test
719 | | | date: Thu Jan 01 00:00:32 1970 +0000
719 | | | date: Thu Jan 01 00:00:32 1970 +0000
720 | | | summary: (32) expand
720 | | | summary: (32) expand
721 | | |
721 | | |
722 | o | changeset: 31:621d83e11f67
722 | o | changeset: 31:621d83e11f67
723 | |\ \ parent: 21:d42a756af44d
723 | |\ \ parent: 21:d42a756af44d
724 | | | | parent: 30:6e11cd4b648f
724 | | | | parent: 30:6e11cd4b648f
725 | | | | user: test
725 | | | | user: test
726 | | | | date: Thu Jan 01 00:00:31 1970 +0000
726 | | | | date: Thu Jan 01 00:00:31 1970 +0000
727 | | | | summary: (31) expand
727 | | | | summary: (31) expand
728 | | | |
728 | | | |
729 | | o | changeset: 30:6e11cd4b648f
729 | | o | changeset: 30:6e11cd4b648f
730 | | |\ \ parent: 28:44ecd0b9ae99
730 | | |\ \ parent: 28:44ecd0b9ae99
731 | | | | | parent: 29:cd9bb2be7593
731 | | | | | parent: 29:cd9bb2be7593
732 | | | | | user: test
732 | | | | | user: test
733 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
733 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
734 | | | | | summary: (30) expand
734 | | | | | summary: (30) expand
735 | | | | |
735 | | | | |
736 | | | o | changeset: 29:cd9bb2be7593
736 | | | o | changeset: 29:cd9bb2be7593
737 | | | | | parent: 0:e6eb3150255d
737 | | | | | parent: 0:e6eb3150255d
738 | | | | | user: test
738 | | | | | user: test
739 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
739 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
740 | | | | | summary: (29) regular commit
740 | | | | | summary: (29) regular commit
741 | | | | |
741 | | | | |
742 | | o | | changeset: 28:44ecd0b9ae99
742 | | o | | changeset: 28:44ecd0b9ae99
743 | | |\ \ \ parent: 1:6db2ef61d156
743 | | |\ \ \ parent: 1:6db2ef61d156
744 | | | | | | parent: 26:7f25b6c2f0b9
744 | | | | | | parent: 26:7f25b6c2f0b9
745 | | | | | | user: test
745 | | | | | | user: test
746 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
746 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
747 | | | | | | summary: (28) merge zero known
747 | | | | | | summary: (28) merge zero known
748 | | | | | |
748 | | | | | |
749 o | | | | | changeset: 27:886ed638191b
749 o | | | | | changeset: 27:886ed638191b
750 |/ / / / / parent: 21:d42a756af44d
750 |/ / / / / parent: 21:d42a756af44d
751 | | | | | user: test
751 | | | | | user: test
752 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
752 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
753 | | | | | summary: (27) collapse
753 | | | | | summary: (27) collapse
754 | | | | |
754 | | | | |
755 | | o---+ changeset: 26:7f25b6c2f0b9
755 | | o---+ changeset: 26:7f25b6c2f0b9
756 | | | | | parent: 18:1aa84d96232a
756 | | | | | parent: 18:1aa84d96232a
757 | | | | | parent: 25:91da8ed57247
757 | | | | | parent: 25:91da8ed57247
758 | | | | | user: test
758 | | | | | user: test
759 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
759 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
760 | | | | | summary: (26) merge one known; far right
760 | | | | | summary: (26) merge one known; far right
761 | | | | |
761 | | | | |
762 +---o | | changeset: 25:91da8ed57247
762 +---o | | changeset: 25:91da8ed57247
763 | | | | | parent: 21:d42a756af44d
763 | | | | | parent: 21:d42a756af44d
764 | | | | | parent: 24:a9c19a3d96b7
764 | | | | | parent: 24:a9c19a3d96b7
765 | | | | | user: test
765 | | | | | user: test
766 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
766 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
767 | | | | | summary: (25) merge one known; far left
767 | | | | | summary: (25) merge one known; far left
768 | | | | |
768 | | | | |
769 | | o | | changeset: 24:a9c19a3d96b7
769 | | o | | changeset: 24:a9c19a3d96b7
770 | | |\| | parent: 0:e6eb3150255d
770 | | |\| | parent: 0:e6eb3150255d
771 | | | | | parent: 23:a01cddf0766d
771 | | | | | parent: 23:a01cddf0766d
772 | | | | | user: test
772 | | | | | user: test
773 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
773 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
774 | | | | | summary: (24) merge one known; immediate right
774 | | | | | summary: (24) merge one known; immediate right
775 | | | | |
775 | | | | |
776 | | o | | changeset: 23:a01cddf0766d
776 | | o | | changeset: 23:a01cddf0766d
777 | |/| | | parent: 1:6db2ef61d156
777 | |/| | | parent: 1:6db2ef61d156
778 | | | | | parent: 22:e0d9cccacb5d
778 | | | | | parent: 22:e0d9cccacb5d
779 | | | | | user: test
779 | | | | | user: test
780 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
780 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
781 | | | | | summary: (23) merge one known; immediate left
781 | | | | | summary: (23) merge one known; immediate left
782 | | | | |
782 | | | | |
783 +---o---+ changeset: 22:e0d9cccacb5d
783 +---o---+ changeset: 22:e0d9cccacb5d
784 | | | | parent: 18:1aa84d96232a
784 | | | | parent: 18:1aa84d96232a
785 | | / / parent: 21:d42a756af44d
785 | | / / parent: 21:d42a756af44d
786 | | | | user: test
786 | | | | user: test
787 | | | | date: Thu Jan 01 00:00:22 1970 +0000
787 | | | | date: Thu Jan 01 00:00:22 1970 +0000
788 | | | | summary: (22) merge two known; one far left, one far right
788 | | | | summary: (22) merge two known; one far left, one far right
789 | | | |
789 | | | |
790 o | | | changeset: 21:d42a756af44d
790 o | | | changeset: 21:d42a756af44d
791 |\ \ \ \ parent: 19:31ddc2c1573b
791 |\ \ \ \ parent: 19:31ddc2c1573b
792 | | | | | parent: 20:d30ed6450e32
792 | | | | | parent: 20:d30ed6450e32
793 | | | | | user: test
793 | | | | | user: test
794 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
794 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
795 | | | | | summary: (21) expand
795 | | | | | summary: (21) expand
796 | | | | |
796 | | | | |
797 | o---+-+ changeset: 20:d30ed6450e32
797 | o---+-+ changeset: 20:d30ed6450e32
798 | | | | parent: 0:e6eb3150255d
798 | | | | parent: 0:e6eb3150255d
799 | / / / parent: 18:1aa84d96232a
799 | / / / parent: 18:1aa84d96232a
800 | | | | user: test
800 | | | | user: test
801 | | | | date: Thu Jan 01 00:00:20 1970 +0000
801 | | | | date: Thu Jan 01 00:00:20 1970 +0000
802 | | | | summary: (20) merge two known; two far right
802 | | | | summary: (20) merge two known; two far right
803 | | | |
803 | | | |
804 o | | | changeset: 19:31ddc2c1573b
804 o | | | changeset: 19:31ddc2c1573b
805 |\ \ \ \ parent: 15:1dda3f72782d
805 |\ \ \ \ parent: 15:1dda3f72782d
806 | | | | | parent: 17:44765d7c06e0
806 | | | | | parent: 17:44765d7c06e0
807 | | | | | user: test
807 | | | | | user: test
808 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
808 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
809 | | | | | summary: (19) expand
809 | | | | | summary: (19) expand
810 | | | | |
810 | | | | |
811 +---+---o changeset: 18:1aa84d96232a
811 +---+---o changeset: 18:1aa84d96232a
812 | | | | parent: 1:6db2ef61d156
812 | | | | parent: 1:6db2ef61d156
813 | | | | parent: 15:1dda3f72782d
813 | | | | parent: 15:1dda3f72782d
814 | | | | user: test
814 | | | | user: test
815 | | | | date: Thu Jan 01 00:00:18 1970 +0000
815 | | | | date: Thu Jan 01 00:00:18 1970 +0000
816 | | | | summary: (18) merge two known; two far left
816 | | | | summary: (18) merge two known; two far left
817 | | | |
817 | | | |
818 | o | | changeset: 17:44765d7c06e0
818 | o | | changeset: 17:44765d7c06e0
819 | |\ \ \ parent: 12:86b91144a6e9
819 | |\ \ \ parent: 12:86b91144a6e9
820 | | | | | parent: 16:3677d192927d
820 | | | | | parent: 16:3677d192927d
821 | | | | | user: test
821 | | | | | user: test
822 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
822 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
823 | | | | | summary: (17) expand
823 | | | | | summary: (17) expand
824 | | | | |
824 | | | | |
825 | | o---+ changeset: 16:3677d192927d
825 | | o---+ changeset: 16:3677d192927d
826 | | | | | parent: 0:e6eb3150255d
826 | | | | | parent: 0:e6eb3150255d
827 | | |/ / parent: 1:6db2ef61d156
827 | | |/ / parent: 1:6db2ef61d156
828 | | | | user: test
828 | | | | user: test
829 | | | | date: Thu Jan 01 00:00:16 1970 +0000
829 | | | | date: Thu Jan 01 00:00:16 1970 +0000
830 | | | | summary: (16) merge two known; one immediate right, one near right
830 | | | | summary: (16) merge two known; one immediate right, one near right
831 | | | |
831 | | | |
832 o | | | changeset: 15:1dda3f72782d
832 o | | | changeset: 15:1dda3f72782d
833 |\ \ \ \ parent: 13:22d8966a97e3
833 |\ \ \ \ parent: 13:22d8966a97e3
834 | | | | | parent: 14:8eac370358ef
834 | | | | | parent: 14:8eac370358ef
835 | | | | | user: test
835 | | | | | user: test
836 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
836 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
837 | | | | | summary: (15) expand
837 | | | | | summary: (15) expand
838 | | | | |
838 | | | | |
839 | o-----+ changeset: 14:8eac370358ef
839 | o-----+ changeset: 14:8eac370358ef
840 | | | | | parent: 0:e6eb3150255d
840 | | | | | parent: 0:e6eb3150255d
841 | |/ / / parent: 12:86b91144a6e9
841 | |/ / / parent: 12:86b91144a6e9
842 | | | | user: test
842 | | | | user: test
843 | | | | date: Thu Jan 01 00:00:14 1970 +0000
843 | | | | date: Thu Jan 01 00:00:14 1970 +0000
844 | | | | summary: (14) merge two known; one immediate right, one far right
844 | | | | summary: (14) merge two known; one immediate right, one far right
845 | | | |
845 | | | |
846 o | | | changeset: 13:22d8966a97e3
846 o | | | changeset: 13:22d8966a97e3
847 |\ \ \ \ parent: 9:7010c0af0a35
847 |\ \ \ \ parent: 9:7010c0af0a35
848 | | | | | parent: 11:832d76e6bdf2
848 | | | | | parent: 11:832d76e6bdf2
849 | | | | | user: test
849 | | | | | user: test
850 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
850 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
851 | | | | | summary: (13) expand
851 | | | | | summary: (13) expand
852 | | | | |
852 | | | | |
853 +---o | | changeset: 12:86b91144a6e9
853 +---o | | changeset: 12:86b91144a6e9
854 | | |/ / parent: 1:6db2ef61d156
854 | | |/ / parent: 1:6db2ef61d156
855 | | | | parent: 9:7010c0af0a35
855 | | | | parent: 9:7010c0af0a35
856 | | | | user: test
856 | | | | user: test
857 | | | | date: Thu Jan 01 00:00:12 1970 +0000
857 | | | | date: Thu Jan 01 00:00:12 1970 +0000
858 | | | | summary: (12) merge two known; one immediate right, one far left
858 | | | | summary: (12) merge two known; one immediate right, one far left
859 | | | |
859 | | | |
860 | o | | changeset: 11:832d76e6bdf2
860 | o | | changeset: 11:832d76e6bdf2
861 | |\ \ \ parent: 6:b105a072e251
861 | |\ \ \ parent: 6:b105a072e251
862 | | | | | parent: 10:74c64d036d72
862 | | | | | parent: 10:74c64d036d72
863 | | | | | user: test
863 | | | | | user: test
864 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
864 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
865 | | | | | summary: (11) expand
865 | | | | | summary: (11) expand
866 | | | | |
866 | | | | |
867 | | o---+ changeset: 10:74c64d036d72
867 | | o---+ changeset: 10:74c64d036d72
868 | | | | | parent: 0:e6eb3150255d
868 | | | | | parent: 0:e6eb3150255d
869 | |/ / / parent: 6:b105a072e251
869 | |/ / / parent: 6:b105a072e251
870 | | | | user: test
870 | | | | user: test
871 | | | | date: Thu Jan 01 00:00:10 1970 +0000
871 | | | | date: Thu Jan 01 00:00:10 1970 +0000
872 | | | | summary: (10) merge two known; one immediate left, one near right
872 | | | | summary: (10) merge two known; one immediate left, one near right
873 | | | |
873 | | | |
874 o | | | changeset: 9:7010c0af0a35
874 o | | | changeset: 9:7010c0af0a35
875 |\ \ \ \ parent: 7:b632bb1b1224
875 |\ \ \ \ parent: 7:b632bb1b1224
876 | | | | | parent: 8:7a0b11f71937
876 | | | | | parent: 8:7a0b11f71937
877 | | | | | user: test
877 | | | | | user: test
878 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
878 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
879 | | | | | summary: (9) expand
879 | | | | | summary: (9) expand
880 | | | | |
880 | | | | |
881 | o-----+ changeset: 8:7a0b11f71937
881 | o-----+ changeset: 8:7a0b11f71937
882 | | | | | parent: 0:e6eb3150255d
882 | | | | | parent: 0:e6eb3150255d
883 |/ / / / parent: 7:b632bb1b1224
883 |/ / / / parent: 7:b632bb1b1224
884 | | | | user: test
884 | | | | user: test
885 | | | | date: Thu Jan 01 00:00:08 1970 +0000
885 | | | | date: Thu Jan 01 00:00:08 1970 +0000
886 | | | | summary: (8) merge two known; one immediate left, one far right
886 | | | | summary: (8) merge two known; one immediate left, one far right
887 | | | |
887 | | | |
888 o | | | changeset: 7:b632bb1b1224
888 o | | | changeset: 7:b632bb1b1224
889 |\ \ \ \ parent: 2:3d9a33b8d1e1
889 |\ \ \ \ parent: 2:3d9a33b8d1e1
890 | | | | | parent: 5:4409d547b708
890 | | | | | parent: 5:4409d547b708
891 | | | | | user: test
891 | | | | | user: test
892 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
892 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
893 | | | | | summary: (7) expand
893 | | | | | summary: (7) expand
894 | | | | |
894 | | | | |
895 +---o | | changeset: 6:b105a072e251
895 +---o | | changeset: 6:b105a072e251
896 | |/ / / parent: 2:3d9a33b8d1e1
896 | |/ / / parent: 2:3d9a33b8d1e1
897 | | | | parent: 5:4409d547b708
897 | | | | parent: 5:4409d547b708
898 | | | | user: test
898 | | | | user: test
899 | | | | date: Thu Jan 01 00:00:06 1970 +0000
899 | | | | date: Thu Jan 01 00:00:06 1970 +0000
900 | | | | summary: (6) merge two known; one immediate left, one far left
900 | | | | summary: (6) merge two known; one immediate left, one far left
901 | | | |
901 | | | |
902 | o | | changeset: 5:4409d547b708
902 | o | | changeset: 5:4409d547b708
903 | |\ \ \ parent: 3:27eef8ed80b4
903 | |\ \ \ parent: 3:27eef8ed80b4
904 | | | | | parent: 4:26a8bac39d9f
904 | | | | | parent: 4:26a8bac39d9f
905 | | | | | user: test
905 | | | | | user: test
906 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
906 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
907 | | | | | summary: (5) expand
907 | | | | | summary: (5) expand
908 | | | | |
908 | | | | |
909 | | o | | changeset: 4:26a8bac39d9f
909 | | o | | changeset: 4:26a8bac39d9f
910 | |/|/ / parent: 1:6db2ef61d156
910 | |/|/ / parent: 1:6db2ef61d156
911 | | | | parent: 3:27eef8ed80b4
911 | | | | parent: 3:27eef8ed80b4
912 | | | | user: test
912 | | | | user: test
913 | | | | date: Thu Jan 01 00:00:04 1970 +0000
913 | | | | date: Thu Jan 01 00:00:04 1970 +0000
914 | | | | summary: (4) merge two known; one immediate left, one immediate right
914 | | | | summary: (4) merge two known; one immediate left, one immediate right
915 | | | |
915 | | | |
916 | o | | changeset: 3:27eef8ed80b4
916 | o | | changeset: 3:27eef8ed80b4
917 |/ / / user: test
917 |/ / / user: test
918 | | | date: Thu Jan 01 00:00:03 1970 +0000
918 | | | date: Thu Jan 01 00:00:03 1970 +0000
919 | | | summary: (3) collapse
919 | | | summary: (3) collapse
920 | | |
920 | | |
921 o | | changeset: 2:3d9a33b8d1e1
921 o | | changeset: 2:3d9a33b8d1e1
922 |/ / user: test
922 |/ / user: test
923 | | date: Thu Jan 01 00:00:02 1970 +0000
923 | | date: Thu Jan 01 00:00:02 1970 +0000
924 | | summary: (2) collapse
924 | | summary: (2) collapse
925 | |
925 | |
926 o | changeset: 1:6db2ef61d156
926 o | changeset: 1:6db2ef61d156
927 |/ user: test
927 |/ user: test
928 | date: Thu Jan 01 00:00:01 1970 +0000
928 | date: Thu Jan 01 00:00:01 1970 +0000
929 | summary: (1) collapse
929 | summary: (1) collapse
930 |
930 |
931 o changeset: 0:e6eb3150255d
931 o changeset: 0:e6eb3150255d
932 user: test
932 user: test
933 date: Thu Jan 01 00:00:00 1970 +0000
933 date: Thu Jan 01 00:00:00 1970 +0000
934 summary: (0) root
934 summary: (0) root
935
935
936
936
937
937
938 File glog per revset (only merges):
938 File glog per revset (only merges):
939
939
940 $ hg log -G -r 'file("a")' -m
940 $ hg log -G -r 'file("a")' -m
941 o changeset: 32:d06dffa21a31
941 o changeset: 32:d06dffa21a31
942 |\ parent: 27:886ed638191b
942 |\ parent: 27:886ed638191b
943 | | parent: 31:621d83e11f67
943 | | parent: 31:621d83e11f67
944 | | user: test
944 | | user: test
945 | | date: Thu Jan 01 00:00:32 1970 +0000
945 | | date: Thu Jan 01 00:00:32 1970 +0000
946 | | summary: (32) expand
946 | | summary: (32) expand
947 | |
947 | |
948 o | changeset: 31:621d83e11f67
948 o | changeset: 31:621d83e11f67
949 |\| parent: 21:d42a756af44d
949 |\| parent: 21:d42a756af44d
950 | | parent: 30:6e11cd4b648f
950 | | parent: 30:6e11cd4b648f
951 | | user: test
951 | | user: test
952 | | date: Thu Jan 01 00:00:31 1970 +0000
952 | | date: Thu Jan 01 00:00:31 1970 +0000
953 | | summary: (31) expand
953 | | summary: (31) expand
954 | |
954 | |
955 o | changeset: 30:6e11cd4b648f
955 o | changeset: 30:6e11cd4b648f
956 |\ \ parent: 28:44ecd0b9ae99
956 |\ \ parent: 28:44ecd0b9ae99
957 | | | parent: 29:cd9bb2be7593
957 | | | parent: 29:cd9bb2be7593
958 | | | user: test
958 | | | user: test
959 | | | date: Thu Jan 01 00:00:30 1970 +0000
959 | | | date: Thu Jan 01 00:00:30 1970 +0000
960 | | | summary: (30) expand
960 | | | summary: (30) expand
961 | | |
961 | | |
962 o | | changeset: 28:44ecd0b9ae99
962 o | | changeset: 28:44ecd0b9ae99
963 |\ \ \ parent: 1:6db2ef61d156
963 |\ \ \ parent: 1:6db2ef61d156
964 | | | | parent: 26:7f25b6c2f0b9
964 | | | | parent: 26:7f25b6c2f0b9
965 | | | | user: test
965 | | | | user: test
966 | | | | date: Thu Jan 01 00:00:28 1970 +0000
966 | | | | date: Thu Jan 01 00:00:28 1970 +0000
967 | | | | summary: (28) merge zero known
967 | | | | summary: (28) merge zero known
968 | | | |
968 | | | |
969 o | | | changeset: 26:7f25b6c2f0b9
969 o | | | changeset: 26:7f25b6c2f0b9
970 |\ \ \ \ parent: 18:1aa84d96232a
970 |\ \ \ \ parent: 18:1aa84d96232a
971 | | | | | parent: 25:91da8ed57247
971 | | | | | parent: 25:91da8ed57247
972 | | | | | user: test
972 | | | | | user: test
973 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
973 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
974 | | | | | summary: (26) merge one known; far right
974 | | | | | summary: (26) merge one known; far right
975 | | | | |
975 | | | | |
976 | o-----+ changeset: 25:91da8ed57247
976 | o-----+ changeset: 25:91da8ed57247
977 | | | | | parent: 21:d42a756af44d
977 | | | | | parent: 21:d42a756af44d
978 | | | | | parent: 24:a9c19a3d96b7
978 | | | | | parent: 24:a9c19a3d96b7
979 | | | | | user: test
979 | | | | | user: test
980 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
980 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
981 | | | | | summary: (25) merge one known; far left
981 | | | | | summary: (25) merge one known; far left
982 | | | | |
982 | | | | |
983 | o | | | changeset: 24:a9c19a3d96b7
983 | o | | | changeset: 24:a9c19a3d96b7
984 | |\ \ \ \ parent: 0:e6eb3150255d
984 | |\ \ \ \ parent: 0:e6eb3150255d
985 | | | | | | parent: 23:a01cddf0766d
985 | | | | | | parent: 23:a01cddf0766d
986 | | | | | | user: test
986 | | | | | | user: test
987 | | | | | | date: Thu Jan 01 00:00:24 1970 +0000
987 | | | | | | date: Thu Jan 01 00:00:24 1970 +0000
988 | | | | | | summary: (24) merge one known; immediate right
988 | | | | | | summary: (24) merge one known; immediate right
989 | | | | | |
989 | | | | | |
990 | o---+ | | changeset: 23:a01cddf0766d
990 | o---+ | | changeset: 23:a01cddf0766d
991 | | | | | | parent: 1:6db2ef61d156
991 | | | | | | parent: 1:6db2ef61d156
992 | | | | | | parent: 22:e0d9cccacb5d
992 | | | | | | parent: 22:e0d9cccacb5d
993 | | | | | | user: test
993 | | | | | | user: test
994 | | | | | | date: Thu Jan 01 00:00:23 1970 +0000
994 | | | | | | date: Thu Jan 01 00:00:23 1970 +0000
995 | | | | | | summary: (23) merge one known; immediate left
995 | | | | | | summary: (23) merge one known; immediate left
996 | | | | | |
996 | | | | | |
997 | o-------+ changeset: 22:e0d9cccacb5d
997 | o-------+ changeset: 22:e0d9cccacb5d
998 | | | | | | parent: 18:1aa84d96232a
998 | | | | | | parent: 18:1aa84d96232a
999 |/ / / / / parent: 21:d42a756af44d
999 |/ / / / / parent: 21:d42a756af44d
1000 | | | | | user: test
1000 | | | | | user: test
1001 | | | | | date: Thu Jan 01 00:00:22 1970 +0000
1001 | | | | | date: Thu Jan 01 00:00:22 1970 +0000
1002 | | | | | summary: (22) merge two known; one far left, one far right
1002 | | | | | summary: (22) merge two known; one far left, one far right
1003 | | | | |
1003 | | | | |
1004 | | | | o changeset: 21:d42a756af44d
1004 | | | | o changeset: 21:d42a756af44d
1005 | | | | |\ parent: 19:31ddc2c1573b
1005 | | | | |\ parent: 19:31ddc2c1573b
1006 | | | | | | parent: 20:d30ed6450e32
1006 | | | | | | parent: 20:d30ed6450e32
1007 | | | | | | user: test
1007 | | | | | | user: test
1008 | | | | | | date: Thu Jan 01 00:00:21 1970 +0000
1008 | | | | | | date: Thu Jan 01 00:00:21 1970 +0000
1009 | | | | | | summary: (21) expand
1009 | | | | | | summary: (21) expand
1010 | | | | | |
1010 | | | | | |
1011 +-+-------o changeset: 20:d30ed6450e32
1011 +-+-------o changeset: 20:d30ed6450e32
1012 | | | | | parent: 0:e6eb3150255d
1012 | | | | | parent: 0:e6eb3150255d
1013 | | | | | parent: 18:1aa84d96232a
1013 | | | | | parent: 18:1aa84d96232a
1014 | | | | | user: test
1014 | | | | | user: test
1015 | | | | | date: Thu Jan 01 00:00:20 1970 +0000
1015 | | | | | date: Thu Jan 01 00:00:20 1970 +0000
1016 | | | | | summary: (20) merge two known; two far right
1016 | | | | | summary: (20) merge two known; two far right
1017 | | | | |
1017 | | | | |
1018 | | | | o changeset: 19:31ddc2c1573b
1018 | | | | o changeset: 19:31ddc2c1573b
1019 | | | | |\ parent: 15:1dda3f72782d
1019 | | | | |\ parent: 15:1dda3f72782d
1020 | | | | | | parent: 17:44765d7c06e0
1020 | | | | | | parent: 17:44765d7c06e0
1021 | | | | | | user: test
1021 | | | | | | user: test
1022 | | | | | | date: Thu Jan 01 00:00:19 1970 +0000
1022 | | | | | | date: Thu Jan 01 00:00:19 1970 +0000
1023 | | | | | | summary: (19) expand
1023 | | | | | | summary: (19) expand
1024 | | | | | |
1024 | | | | | |
1025 o---+---+ | changeset: 18:1aa84d96232a
1025 o---+---+ | changeset: 18:1aa84d96232a
1026 | | | | | parent: 1:6db2ef61d156
1026 | | | | | parent: 1:6db2ef61d156
1027 / / / / / parent: 15:1dda3f72782d
1027 / / / / / parent: 15:1dda3f72782d
1028 | | | | | user: test
1028 | | | | | user: test
1029 | | | | | date: Thu Jan 01 00:00:18 1970 +0000
1029 | | | | | date: Thu Jan 01 00:00:18 1970 +0000
1030 | | | | | summary: (18) merge two known; two far left
1030 | | | | | summary: (18) merge two known; two far left
1031 | | | | |
1031 | | | | |
1032 | | | | o changeset: 17:44765d7c06e0
1032 | | | | o changeset: 17:44765d7c06e0
1033 | | | | |\ parent: 12:86b91144a6e9
1033 | | | | |\ parent: 12:86b91144a6e9
1034 | | | | | | parent: 16:3677d192927d
1034 | | | | | | parent: 16:3677d192927d
1035 | | | | | | user: test
1035 | | | | | | user: test
1036 | | | | | | date: Thu Jan 01 00:00:17 1970 +0000
1036 | | | | | | date: Thu Jan 01 00:00:17 1970 +0000
1037 | | | | | | summary: (17) expand
1037 | | | | | | summary: (17) expand
1038 | | | | | |
1038 | | | | | |
1039 +-+-------o changeset: 16:3677d192927d
1039 +-+-------o changeset: 16:3677d192927d
1040 | | | | | parent: 0:e6eb3150255d
1040 | | | | | parent: 0:e6eb3150255d
1041 | | | | | parent: 1:6db2ef61d156
1041 | | | | | parent: 1:6db2ef61d156
1042 | | | | | user: test
1042 | | | | | user: test
1043 | | | | | date: Thu Jan 01 00:00:16 1970 +0000
1043 | | | | | date: Thu Jan 01 00:00:16 1970 +0000
1044 | | | | | summary: (16) merge two known; one immediate right, one near right
1044 | | | | | summary: (16) merge two known; one immediate right, one near right
1045 | | | | |
1045 | | | | |
1046 | | | o | changeset: 15:1dda3f72782d
1046 | | | o | changeset: 15:1dda3f72782d
1047 | | | |\ \ parent: 13:22d8966a97e3
1047 | | | |\ \ parent: 13:22d8966a97e3
1048 | | | | | | parent: 14:8eac370358ef
1048 | | | | | | parent: 14:8eac370358ef
1049 | | | | | | user: test
1049 | | | | | | user: test
1050 | | | | | | date: Thu Jan 01 00:00:15 1970 +0000
1050 | | | | | | date: Thu Jan 01 00:00:15 1970 +0000
1051 | | | | | | summary: (15) expand
1051 | | | | | | summary: (15) expand
1052 | | | | | |
1052 | | | | | |
1053 +-------o | changeset: 14:8eac370358ef
1053 +-------o | changeset: 14:8eac370358ef
1054 | | | | |/ parent: 0:e6eb3150255d
1054 | | | | |/ parent: 0:e6eb3150255d
1055 | | | | | parent: 12:86b91144a6e9
1055 | | | | | parent: 12:86b91144a6e9
1056 | | | | | user: test
1056 | | | | | user: test
1057 | | | | | date: Thu Jan 01 00:00:14 1970 +0000
1057 | | | | | date: Thu Jan 01 00:00:14 1970 +0000
1058 | | | | | summary: (14) merge two known; one immediate right, one far right
1058 | | | | | summary: (14) merge two known; one immediate right, one far right
1059 | | | | |
1059 | | | | |
1060 | | | o | changeset: 13:22d8966a97e3
1060 | | | o | changeset: 13:22d8966a97e3
1061 | | | |\ \ parent: 9:7010c0af0a35
1061 | | | |\ \ parent: 9:7010c0af0a35
1062 | | | | | | parent: 11:832d76e6bdf2
1062 | | | | | | parent: 11:832d76e6bdf2
1063 | | | | | | user: test
1063 | | | | | | user: test
1064 | | | | | | date: Thu Jan 01 00:00:13 1970 +0000
1064 | | | | | | date: Thu Jan 01 00:00:13 1970 +0000
1065 | | | | | | summary: (13) expand
1065 | | | | | | summary: (13) expand
1066 | | | | | |
1066 | | | | | |
1067 | +---+---o changeset: 12:86b91144a6e9
1067 | +---+---o changeset: 12:86b91144a6e9
1068 | | | | | parent: 1:6db2ef61d156
1068 | | | | | parent: 1:6db2ef61d156
1069 | | | | | parent: 9:7010c0af0a35
1069 | | | | | parent: 9:7010c0af0a35
1070 | | | | | user: test
1070 | | | | | user: test
1071 | | | | | date: Thu Jan 01 00:00:12 1970 +0000
1071 | | | | | date: Thu Jan 01 00:00:12 1970 +0000
1072 | | | | | summary: (12) merge two known; one immediate right, one far left
1072 | | | | | summary: (12) merge two known; one immediate right, one far left
1073 | | | | |
1073 | | | | |
1074 | | | | o changeset: 11:832d76e6bdf2
1074 | | | | o changeset: 11:832d76e6bdf2
1075 | | | | |\ parent: 6:b105a072e251
1075 | | | | |\ parent: 6:b105a072e251
1076 | | | | | | parent: 10:74c64d036d72
1076 | | | | | | parent: 10:74c64d036d72
1077 | | | | | | user: test
1077 | | | | | | user: test
1078 | | | | | | date: Thu Jan 01 00:00:11 1970 +0000
1078 | | | | | | date: Thu Jan 01 00:00:11 1970 +0000
1079 | | | | | | summary: (11) expand
1079 | | | | | | summary: (11) expand
1080 | | | | | |
1080 | | | | | |
1081 +---------o changeset: 10:74c64d036d72
1081 +---------o changeset: 10:74c64d036d72
1082 | | | | |/ parent: 0:e6eb3150255d
1082 | | | | |/ parent: 0:e6eb3150255d
1083 | | | | | parent: 6:b105a072e251
1083 | | | | | parent: 6:b105a072e251
1084 | | | | | user: test
1084 | | | | | user: test
1085 | | | | | date: Thu Jan 01 00:00:10 1970 +0000
1085 | | | | | date: Thu Jan 01 00:00:10 1970 +0000
1086 | | | | | summary: (10) merge two known; one immediate left, one near right
1086 | | | | | summary: (10) merge two known; one immediate left, one near right
1087 | | | | |
1087 | | | | |
1088 | | | o | changeset: 9:7010c0af0a35
1088 | | | o | changeset: 9:7010c0af0a35
1089 | | | |\ \ parent: 7:b632bb1b1224
1089 | | | |\ \ parent: 7:b632bb1b1224
1090 | | | | | | parent: 8:7a0b11f71937
1090 | | | | | | parent: 8:7a0b11f71937
1091 | | | | | | user: test
1091 | | | | | | user: test
1092 | | | | | | date: Thu Jan 01 00:00:09 1970 +0000
1092 | | | | | | date: Thu Jan 01 00:00:09 1970 +0000
1093 | | | | | | summary: (9) expand
1093 | | | | | | summary: (9) expand
1094 | | | | | |
1094 | | | | | |
1095 +-------o | changeset: 8:7a0b11f71937
1095 +-------o | changeset: 8:7a0b11f71937
1096 | | | |/ / parent: 0:e6eb3150255d
1096 | | | |/ / parent: 0:e6eb3150255d
1097 | | | | | parent: 7:b632bb1b1224
1097 | | | | | parent: 7:b632bb1b1224
1098 | | | | | user: test
1098 | | | | | user: test
1099 | | | | | date: Thu Jan 01 00:00:08 1970 +0000
1099 | | | | | date: Thu Jan 01 00:00:08 1970 +0000
1100 | | | | | summary: (8) merge two known; one immediate left, one far right
1100 | | | | | summary: (8) merge two known; one immediate left, one far right
1101 | | | | |
1101 | | | | |
1102 | | | o | changeset: 7:b632bb1b1224
1102 | | | o | changeset: 7:b632bb1b1224
1103 | | | |\ \ parent: 2:3d9a33b8d1e1
1103 | | | |\ \ parent: 2:3d9a33b8d1e1
1104 | | | | | | parent: 5:4409d547b708
1104 | | | | | | parent: 5:4409d547b708
1105 | | | | | | user: test
1105 | | | | | | user: test
1106 | | | | | | date: Thu Jan 01 00:00:07 1970 +0000
1106 | | | | | | date: Thu Jan 01 00:00:07 1970 +0000
1107 | | | | | | summary: (7) expand
1107 | | | | | | summary: (7) expand
1108 | | | | | |
1108 | | | | | |
1109 | | | +---o changeset: 6:b105a072e251
1109 | | | +---o changeset: 6:b105a072e251
1110 | | | | |/ parent: 2:3d9a33b8d1e1
1110 | | | | |/ parent: 2:3d9a33b8d1e1
1111 | | | | | parent: 5:4409d547b708
1111 | | | | | parent: 5:4409d547b708
1112 | | | | | user: test
1112 | | | | | user: test
1113 | | | | | date: Thu Jan 01 00:00:06 1970 +0000
1113 | | | | | date: Thu Jan 01 00:00:06 1970 +0000
1114 | | | | | summary: (6) merge two known; one immediate left, one far left
1114 | | | | | summary: (6) merge two known; one immediate left, one far left
1115 | | | | |
1115 | | | | |
1116 | | | o | changeset: 5:4409d547b708
1116 | | | o | changeset: 5:4409d547b708
1117 | | | |\ \ parent: 3:27eef8ed80b4
1117 | | | |\ \ parent: 3:27eef8ed80b4
1118 | | | | | | parent: 4:26a8bac39d9f
1118 | | | | | | parent: 4:26a8bac39d9f
1119 | | | | | | user: test
1119 | | | | | | user: test
1120 | | | | | | date: Thu Jan 01 00:00:05 1970 +0000
1120 | | | | | | date: Thu Jan 01 00:00:05 1970 +0000
1121 | | | | | | summary: (5) expand
1121 | | | | | | summary: (5) expand
1122 | | | | | |
1122 | | | | | |
1123 | +---o | | changeset: 4:26a8bac39d9f
1123 | +---o | | changeset: 4:26a8bac39d9f
1124 | | | |/ / parent: 1:6db2ef61d156
1124 | | | |/ / parent: 1:6db2ef61d156
1125 | | | | | parent: 3:27eef8ed80b4
1125 | | | | | parent: 3:27eef8ed80b4
1126 | | | | | user: test
1126 | | | | | user: test
1127 | | | | | date: Thu Jan 01 00:00:04 1970 +0000
1127 | | | | | date: Thu Jan 01 00:00:04 1970 +0000
1128 | | | | | summary: (4) merge two known; one immediate left, one immediate right
1128 | | | | | summary: (4) merge two known; one immediate left, one immediate right
1129 | | | | |
1129 | | | | |
1130
1130
1131
1131
1132 Empty revision range - display nothing:
1132 Empty revision range - display nothing:
1133 $ hg log -G -r 1..0
1133 $ hg log -G -r 1..0
1134
1134
1135 $ cd ..
1135 $ cd ..
1136
1136
1137 #if no-outer-repo
1137 #if no-outer-repo
1138
1138
1139 From outer space:
1139 From outer space:
1140 $ hg log -G -l1 repo
1140 $ hg log -G -l1 repo
1141 @ changeset: 34:fea3ac5810e0
1141 @ changeset: 34:fea3ac5810e0
1142 | tag: tip
1142 | tag: tip
1143 | parent: 32:d06dffa21a31
1143 | parent: 32:d06dffa21a31
1144 | user: test
1144 | user: test
1145 | date: Thu Jan 01 00:00:34 1970 +0000
1145 | date: Thu Jan 01 00:00:34 1970 +0000
1146 | summary: (34) head
1146 | summary: (34) head
1147 |
1147 |
1148 $ hg log -G -l1 repo/a
1148 $ hg log -G -l1 repo/a
1149 @ changeset: 34:fea3ac5810e0
1149 @ changeset: 34:fea3ac5810e0
1150 | tag: tip
1150 | tag: tip
1151 | parent: 32:d06dffa21a31
1151 | parent: 32:d06dffa21a31
1152 | user: test
1152 | user: test
1153 | date: Thu Jan 01 00:00:34 1970 +0000
1153 | date: Thu Jan 01 00:00:34 1970 +0000
1154 | summary: (34) head
1154 | summary: (34) head
1155 |
1155 |
1156 $ hg log -G -l1 repo/missing
1156 $ hg log -G -l1 repo/missing
1157
1157
1158 #endif
1158 #endif
1159
1159
1160 File log with revs != cset revs:
1160 File log with revs != cset revs:
1161 $ hg init flog
1161 $ hg init flog
1162 $ cd flog
1162 $ cd flog
1163 $ echo one >one
1163 $ echo one >one
1164 $ hg add one
1164 $ hg add one
1165 $ hg commit -mone
1165 $ hg commit -mone
1166 $ echo two >two
1166 $ echo two >two
1167 $ hg add two
1167 $ hg add two
1168 $ hg commit -mtwo
1168 $ hg commit -mtwo
1169 $ echo more >two
1169 $ echo more >two
1170 $ hg commit -mmore
1170 $ hg commit -mmore
1171 $ hg log -G two
1171 $ hg log -G two
1172 @ changeset: 2:12c28321755b
1172 @ changeset: 2:12c28321755b
1173 | tag: tip
1173 | tag: tip
1174 | user: test
1174 | user: test
1175 | date: Thu Jan 01 00:00:00 1970 +0000
1175 | date: Thu Jan 01 00:00:00 1970 +0000
1176 | summary: more
1176 | summary: more
1177 |
1177 |
1178 o changeset: 1:5ac72c0599bf
1178 o changeset: 1:5ac72c0599bf
1179 | user: test
1179 | user: test
1180 | date: Thu Jan 01 00:00:00 1970 +0000
1180 | date: Thu Jan 01 00:00:00 1970 +0000
1181 | summary: two
1181 | summary: two
1182 |
1182 |
1183
1183
1184 Issue1896: File log with explicit style
1184 Issue1896: File log with explicit style
1185 $ hg log -G --style=default one
1185 $ hg log -G --style=default one
1186 o changeset: 0:3d578b4a1f53
1186 o changeset: 0:3d578b4a1f53
1187 user: test
1187 user: test
1188 date: Thu Jan 01 00:00:00 1970 +0000
1188 date: Thu Jan 01 00:00:00 1970 +0000
1189 summary: one
1189 summary: one
1190
1190
1191 Issue2395: glog --style header and footer
1191 Issue2395: glog --style header and footer
1192 $ hg log -G --style=xml one
1192 $ hg log -G --style=xml one
1193 <?xml version="1.0"?>
1193 <?xml version="1.0"?>
1194 <log>
1194 <log>
1195 o <logentry revision="0" node="3d578b4a1f537d5fcf7301bfa9c0b97adfaa6fb1">
1195 o <logentry revision="0" node="3d578b4a1f537d5fcf7301bfa9c0b97adfaa6fb1">
1196 <author email="test">test</author>
1196 <author email="test">test</author>
1197 <date>1970-01-01T00:00:00+00:00</date>
1197 <date>1970-01-01T00:00:00+00:00</date>
1198 <msg xml:space="preserve">one</msg>
1198 <msg xml:space="preserve">one</msg>
1199 </logentry>
1199 </logentry>
1200 </log>
1200 </log>
1201
1201
1202 $ cd ..
1202 $ cd ..
1203
1203
1204 Incoming and outgoing:
1204 Incoming and outgoing:
1205
1205
1206 $ hg clone -U -r31 repo repo2
1206 $ hg clone -U -r31 repo repo2
1207 adding changesets
1207 adding changesets
1208 adding manifests
1208 adding manifests
1209 adding file changes
1209 adding file changes
1210 added 31 changesets with 31 changes to 1 files
1210 added 31 changesets with 31 changes to 1 files
1211 $ cd repo2
1211 $ cd repo2
1212
1212
1213 $ hg incoming --graph ../repo
1213 $ hg incoming --graph ../repo
1214 comparing with ../repo
1214 comparing with ../repo
1215 searching for changes
1215 searching for changes
1216 o changeset: 34:fea3ac5810e0
1216 o changeset: 34:fea3ac5810e0
1217 | tag: tip
1217 | tag: tip
1218 | parent: 32:d06dffa21a31
1218 | parent: 32:d06dffa21a31
1219 | user: test
1219 | user: test
1220 | date: Thu Jan 01 00:00:34 1970 +0000
1220 | date: Thu Jan 01 00:00:34 1970 +0000
1221 | summary: (34) head
1221 | summary: (34) head
1222 |
1222 |
1223 | o changeset: 33:68608f5145f9
1223 | o changeset: 33:68608f5145f9
1224 | parent: 18:1aa84d96232a
1224 | parent: 18:1aa84d96232a
1225 | user: test
1225 | user: test
1226 | date: Thu Jan 01 00:00:33 1970 +0000
1226 | date: Thu Jan 01 00:00:33 1970 +0000
1227 | summary: (33) head
1227 | summary: (33) head
1228 |
1228 |
1229 o changeset: 32:d06dffa21a31
1229 o changeset: 32:d06dffa21a31
1230 | parent: 27:886ed638191b
1230 | parent: 27:886ed638191b
1231 | parent: 31:621d83e11f67
1231 | parent: 31:621d83e11f67
1232 | user: test
1232 | user: test
1233 | date: Thu Jan 01 00:00:32 1970 +0000
1233 | date: Thu Jan 01 00:00:32 1970 +0000
1234 | summary: (32) expand
1234 | summary: (32) expand
1235 |
1235 |
1236 o changeset: 27:886ed638191b
1236 o changeset: 27:886ed638191b
1237 parent: 21:d42a756af44d
1237 parent: 21:d42a756af44d
1238 user: test
1238 user: test
1239 date: Thu Jan 01 00:00:27 1970 +0000
1239 date: Thu Jan 01 00:00:27 1970 +0000
1240 summary: (27) collapse
1240 summary: (27) collapse
1241
1241
1242 $ cd ..
1242 $ cd ..
1243
1243
1244 $ hg -R repo outgoing --graph repo2
1244 $ hg -R repo outgoing --graph repo2
1245 comparing with repo2
1245 comparing with repo2
1246 searching for changes
1246 searching for changes
1247 @ changeset: 34:fea3ac5810e0
1247 @ changeset: 34:fea3ac5810e0
1248 | tag: tip
1248 | tag: tip
1249 | parent: 32:d06dffa21a31
1249 | parent: 32:d06dffa21a31
1250 | user: test
1250 | user: test
1251 | date: Thu Jan 01 00:00:34 1970 +0000
1251 | date: Thu Jan 01 00:00:34 1970 +0000
1252 | summary: (34) head
1252 | summary: (34) head
1253 |
1253 |
1254 | o changeset: 33:68608f5145f9
1254 | o changeset: 33:68608f5145f9
1255 | parent: 18:1aa84d96232a
1255 | parent: 18:1aa84d96232a
1256 | user: test
1256 | user: test
1257 | date: Thu Jan 01 00:00:33 1970 +0000
1257 | date: Thu Jan 01 00:00:33 1970 +0000
1258 | summary: (33) head
1258 | summary: (33) head
1259 |
1259 |
1260 o changeset: 32:d06dffa21a31
1260 o changeset: 32:d06dffa21a31
1261 | parent: 27:886ed638191b
1261 | parent: 27:886ed638191b
1262 | parent: 31:621d83e11f67
1262 | parent: 31:621d83e11f67
1263 | user: test
1263 | user: test
1264 | date: Thu Jan 01 00:00:32 1970 +0000
1264 | date: Thu Jan 01 00:00:32 1970 +0000
1265 | summary: (32) expand
1265 | summary: (32) expand
1266 |
1266 |
1267 o changeset: 27:886ed638191b
1267 o changeset: 27:886ed638191b
1268 parent: 21:d42a756af44d
1268 parent: 21:d42a756af44d
1269 user: test
1269 user: test
1270 date: Thu Jan 01 00:00:27 1970 +0000
1270 date: Thu Jan 01 00:00:27 1970 +0000
1271 summary: (27) collapse
1271 summary: (27) collapse
1272
1272
1273
1273
1274 File + limit with revs != cset revs:
1274 File + limit with revs != cset revs:
1275 $ cd repo
1275 $ cd repo
1276 $ touch b
1276 $ touch b
1277 $ hg ci -Aqm0
1277 $ hg ci -Aqm0
1278 $ hg log -G -l2 a
1278 $ hg log -G -l2 a
1279 o changeset: 34:fea3ac5810e0
1279 o changeset: 34:fea3ac5810e0
1280 | parent: 32:d06dffa21a31
1280 | parent: 32:d06dffa21a31
1281 | user: test
1281 | user: test
1282 | date: Thu Jan 01 00:00:34 1970 +0000
1282 | date: Thu Jan 01 00:00:34 1970 +0000
1283 | summary: (34) head
1283 | summary: (34) head
1284 |
1284 |
1285 | o changeset: 33:68608f5145f9
1285 | o changeset: 33:68608f5145f9
1286 | | parent: 18:1aa84d96232a
1286 | | parent: 18:1aa84d96232a
1287 | | user: test
1287 | | user: test
1288 | | date: Thu Jan 01 00:00:33 1970 +0000
1288 | | date: Thu Jan 01 00:00:33 1970 +0000
1289 | | summary: (33) head
1289 | | summary: (33) head
1290 | |
1290 | |
1291
1291
1292 File + limit + -ra:b, (b - a) < limit:
1292 File + limit + -ra:b, (b - a) < limit:
1293 $ hg log -G -l3000 -r32:tip a
1293 $ hg log -G -l3000 -r32:tip a
1294 o changeset: 34:fea3ac5810e0
1294 o changeset: 34:fea3ac5810e0
1295 | parent: 32:d06dffa21a31
1295 | parent: 32:d06dffa21a31
1296 | user: test
1296 | user: test
1297 | date: Thu Jan 01 00:00:34 1970 +0000
1297 | date: Thu Jan 01 00:00:34 1970 +0000
1298 | summary: (34) head
1298 | summary: (34) head
1299 |
1299 |
1300 | o changeset: 33:68608f5145f9
1300 | o changeset: 33:68608f5145f9
1301 | | parent: 18:1aa84d96232a
1301 | | parent: 18:1aa84d96232a
1302 | | user: test
1302 | | user: test
1303 | | date: Thu Jan 01 00:00:33 1970 +0000
1303 | | date: Thu Jan 01 00:00:33 1970 +0000
1304 | | summary: (33) head
1304 | | summary: (33) head
1305 | |
1305 | |
1306 o | changeset: 32:d06dffa21a31
1306 o | changeset: 32:d06dffa21a31
1307 |\ \ parent: 27:886ed638191b
1307 |\ \ parent: 27:886ed638191b
1308 | | | parent: 31:621d83e11f67
1308 | | | parent: 31:621d83e11f67
1309 | | | user: test
1309 | | | user: test
1310 | | | date: Thu Jan 01 00:00:32 1970 +0000
1310 | | | date: Thu Jan 01 00:00:32 1970 +0000
1311 | | | summary: (32) expand
1311 | | | summary: (32) expand
1312 | | |
1312 | | |
1313
1313
1314 Point out a common and an uncommon unshown parent
1314 Point out a common and an uncommon unshown parent
1315
1315
1316 $ hg log -G -r 'rev(8) or rev(9)'
1316 $ hg log -G -r 'rev(8) or rev(9)'
1317 o changeset: 9:7010c0af0a35
1317 o changeset: 9:7010c0af0a35
1318 |\ parent: 7:b632bb1b1224
1318 |\ parent: 7:b632bb1b1224
1319 | | parent: 8:7a0b11f71937
1319 | | parent: 8:7a0b11f71937
1320 | | user: test
1320 | | user: test
1321 | | date: Thu Jan 01 00:00:09 1970 +0000
1321 | | date: Thu Jan 01 00:00:09 1970 +0000
1322 | | summary: (9) expand
1322 | | summary: (9) expand
1323 | |
1323 | |
1324 o | changeset: 8:7a0b11f71937
1324 o | changeset: 8:7a0b11f71937
1325 |\| parent: 0:e6eb3150255d
1325 |\| parent: 0:e6eb3150255d
1326 | | parent: 7:b632bb1b1224
1326 | | parent: 7:b632bb1b1224
1327 | | user: test
1327 | | user: test
1328 | | date: Thu Jan 01 00:00:08 1970 +0000
1328 | | date: Thu Jan 01 00:00:08 1970 +0000
1329 | | summary: (8) merge two known; one immediate left, one far right
1329 | | summary: (8) merge two known; one immediate left, one far right
1330 | |
1330 | |
1331
1331
1332 File + limit + -ra:b, b < tip:
1332 File + limit + -ra:b, b < tip:
1333
1333
1334 $ hg log -G -l1 -r32:34 a
1334 $ hg log -G -l1 -r32:34 a
1335 o changeset: 34:fea3ac5810e0
1335 o changeset: 34:fea3ac5810e0
1336 | parent: 32:d06dffa21a31
1336 | parent: 32:d06dffa21a31
1337 | user: test
1337 | user: test
1338 | date: Thu Jan 01 00:00:34 1970 +0000
1338 | date: Thu Jan 01 00:00:34 1970 +0000
1339 | summary: (34) head
1339 | summary: (34) head
1340 |
1340 |
1341
1341
1342 file(File) + limit + -ra:b, b < tip:
1342 file(File) + limit + -ra:b, b < tip:
1343
1343
1344 $ hg log -G -l1 -r32:34 -r 'file("a")'
1344 $ hg log -G -l1 -r32:34 -r 'file("a")'
1345 o changeset: 34:fea3ac5810e0
1345 o changeset: 34:fea3ac5810e0
1346 | parent: 32:d06dffa21a31
1346 | parent: 32:d06dffa21a31
1347 | user: test
1347 | user: test
1348 | date: Thu Jan 01 00:00:34 1970 +0000
1348 | date: Thu Jan 01 00:00:34 1970 +0000
1349 | summary: (34) head
1349 | summary: (34) head
1350 |
1350 |
1351
1351
1352 limit(file(File) and a::b), b < tip:
1352 limit(file(File) and a::b), b < tip:
1353
1353
1354 $ hg log -G -r 'limit(file("a") and 32::34, 1)'
1354 $ hg log -G -r 'limit(file("a") and 32::34, 1)'
1355 o changeset: 32:d06dffa21a31
1355 o changeset: 32:d06dffa21a31
1356 |\ parent: 27:886ed638191b
1356 |\ parent: 27:886ed638191b
1357 | | parent: 31:621d83e11f67
1357 | | parent: 31:621d83e11f67
1358 | | user: test
1358 | | user: test
1359 | | date: Thu Jan 01 00:00:32 1970 +0000
1359 | | date: Thu Jan 01 00:00:32 1970 +0000
1360 | | summary: (32) expand
1360 | | summary: (32) expand
1361 | |
1361 | |
1362
1362
1363 File + limit + -ra:b, b < tip:
1363 File + limit + -ra:b, b < tip:
1364
1364
1365 $ hg log -G -r 'limit(file("a") and 34::32, 1)'
1365 $ hg log -G -r 'limit(file("a") and 34::32, 1)'
1366
1366
1367 File + limit + -ra:b, b < tip, (b - a) < limit:
1367 File + limit + -ra:b, b < tip, (b - a) < limit:
1368
1368
1369 $ hg log -G -l10 -r33:34 a
1369 $ hg log -G -l10 -r33:34 a
1370 o changeset: 34:fea3ac5810e0
1370 o changeset: 34:fea3ac5810e0
1371 | parent: 32:d06dffa21a31
1371 | parent: 32:d06dffa21a31
1372 | user: test
1372 | user: test
1373 | date: Thu Jan 01 00:00:34 1970 +0000
1373 | date: Thu Jan 01 00:00:34 1970 +0000
1374 | summary: (34) head
1374 | summary: (34) head
1375 |
1375 |
1376 | o changeset: 33:68608f5145f9
1376 | o changeset: 33:68608f5145f9
1377 | | parent: 18:1aa84d96232a
1377 | | parent: 18:1aa84d96232a
1378 | | user: test
1378 | | user: test
1379 | | date: Thu Jan 01 00:00:33 1970 +0000
1379 | | date: Thu Jan 01 00:00:33 1970 +0000
1380 | | summary: (33) head
1380 | | summary: (33) head
1381 | |
1381 | |
1382
1382
1383 Do not crash or produce strange graphs if history is buggy
1383 Do not crash or produce strange graphs if history is buggy
1384
1384
1385 $ hg branch branch
1385 $ hg branch branch
1386 marked working directory as branch branch
1386 marked working directory as branch branch
1387 (branches are permanent and global, did you want a bookmark?)
1387 (branches are permanent and global, did you want a bookmark?)
1388 $ commit 36 "buggy merge: identical parents" 35 35
1388 $ commit 36 "buggy merge: identical parents" 35 35
1389 $ hg log -G -l5
1389 $ hg log -G -l5
1390 @ changeset: 36:08a19a744424
1390 @ changeset: 36:08a19a744424
1391 | branch: branch
1391 | branch: branch
1392 | tag: tip
1392 | tag: tip
1393 | parent: 35:9159c3644c5e
1393 | parent: 35:9159c3644c5e
1394 | parent: 35:9159c3644c5e
1394 | parent: 35:9159c3644c5e
1395 | user: test
1395 | user: test
1396 | date: Thu Jan 01 00:00:36 1970 +0000
1396 | date: Thu Jan 01 00:00:36 1970 +0000
1397 | summary: (36) buggy merge: identical parents
1397 | summary: (36) buggy merge: identical parents
1398 |
1398 |
1399 o changeset: 35:9159c3644c5e
1399 o changeset: 35:9159c3644c5e
1400 | user: test
1400 | user: test
1401 | date: Thu Jan 01 00:00:00 1970 +0000
1401 | date: Thu Jan 01 00:00:00 1970 +0000
1402 | summary: 0
1402 | summary: 0
1403 |
1403 |
1404 o changeset: 34:fea3ac5810e0
1404 o changeset: 34:fea3ac5810e0
1405 | parent: 32:d06dffa21a31
1405 | parent: 32:d06dffa21a31
1406 | user: test
1406 | user: test
1407 | date: Thu Jan 01 00:00:34 1970 +0000
1407 | date: Thu Jan 01 00:00:34 1970 +0000
1408 | summary: (34) head
1408 | summary: (34) head
1409 |
1409 |
1410 | o changeset: 33:68608f5145f9
1410 | o changeset: 33:68608f5145f9
1411 | | parent: 18:1aa84d96232a
1411 | | parent: 18:1aa84d96232a
1412 | | user: test
1412 | | user: test
1413 | | date: Thu Jan 01 00:00:33 1970 +0000
1413 | | date: Thu Jan 01 00:00:33 1970 +0000
1414 | | summary: (33) head
1414 | | summary: (33) head
1415 | |
1415 | |
1416 o | changeset: 32:d06dffa21a31
1416 o | changeset: 32:d06dffa21a31
1417 |\ \ parent: 27:886ed638191b
1417 |\ \ parent: 27:886ed638191b
1418 | | | parent: 31:621d83e11f67
1418 | | | parent: 31:621d83e11f67
1419 | | | user: test
1419 | | | user: test
1420 | | | date: Thu Jan 01 00:00:32 1970 +0000
1420 | | | date: Thu Jan 01 00:00:32 1970 +0000
1421 | | | summary: (32) expand
1421 | | | summary: (32) expand
1422 | | |
1422 | | |
1423
1423
1424 Test log -G options
1424 Test log -G options
1425
1425
1426 $ testlog() {
1426 $ testlog() {
1427 > hg log -G --print-revset "$@"
1427 > hg log -G --print-revset "$@"
1428 > hg log --template 'nodetag {rev}\n' "$@" | grep nodetag \
1428 > hg log --template 'nodetag {rev}\n' "$@" | grep nodetag \
1429 > | sed 's/.*nodetag/nodetag/' > log.nodes
1429 > | sed 's/.*nodetag/nodetag/' > log.nodes
1430 > hg log -G --template 'nodetag {rev}\n' "$@" | grep nodetag \
1430 > hg log -G --template 'nodetag {rev}\n' "$@" | grep nodetag \
1431 > | sed 's/.*nodetag/nodetag/' > glog.nodes
1431 > | sed 's/.*nodetag/nodetag/' > glog.nodes
1432 > diff -u log.nodes glog.nodes | grep '^[-+@ ]' || :
1432 > diff -u log.nodes glog.nodes | grep '^[-+@ ]' || :
1433 > }
1433 > }
1434
1434
1435 glog always reorders nodes which explains the difference with log
1435 glog always reorders nodes which explains the difference with log
1436
1436
1437 $ testlog -r 27 -r 25 -r 21 -r 34 -r 32 -r 31
1437 $ testlog -r 27 -r 25 -r 21 -r 34 -r 32 -r 31
1438 ['27', '25', '21', '34', '32', '31']
1438 ['27', '25', '21', '34', '32', '31']
1439 []
1439 []
1440 --- log.nodes * (glob)
1440 --- log.nodes * (glob)
1441 +++ glog.nodes * (glob)
1441 +++ glog.nodes * (glob)
1442 @@ -1,6 +1,6 @@
1442 @@ -1,6 +1,6 @@
1443 -nodetag 27
1443 -nodetag 27
1444 -nodetag 25
1444 -nodetag 25
1445 -nodetag 21
1445 -nodetag 21
1446 nodetag 34
1446 nodetag 34
1447 nodetag 32
1447 nodetag 32
1448 nodetag 31
1448 nodetag 31
1449 +nodetag 27
1449 +nodetag 27
1450 +nodetag 25
1450 +nodetag 25
1451 +nodetag 21
1451 +nodetag 21
1452 $ testlog -u test -u not-a-user
1452 $ testlog -u test -u not-a-user
1453 []
1453 []
1454 (group
1454 (group
1455 (group
1455 (group
1456 (or
1456 (or
1457 (func
1457 (func
1458 ('symbol', 'user')
1458 ('symbol', 'user')
1459 ('string', 'test'))
1459 ('string', 'test'))
1460 (func
1460 (func
1461 ('symbol', 'user')
1461 ('symbol', 'user')
1462 ('string', 'not-a-user')))))
1462 ('string', 'not-a-user')))))
1463 $ testlog -b not-a-branch
1463 $ testlog -b not-a-branch
1464 abort: unknown revision 'not-a-branch'!
1464 abort: unknown revision 'not-a-branch'!
1465 abort: unknown revision 'not-a-branch'!
1465 abort: unknown revision 'not-a-branch'!
1466 abort: unknown revision 'not-a-branch'!
1466 abort: unknown revision 'not-a-branch'!
1467 $ testlog -b 35 -b 36 --only-branch branch
1467 $ testlog -b 35 -b 36 --only-branch branch
1468 []
1468 []
1469 (group
1469 (group
1470 (group
1470 (group
1471 (or
1471 (or
1472 (func
1472 (func
1473 ('symbol', 'branch')
1473 ('symbol', 'branch')
1474 ('string', 'default'))
1474 ('string', 'default'))
1475 (func
1475 (func
1476 ('symbol', 'branch')
1476 ('symbol', 'branch')
1477 ('string', 'branch'))
1477 ('string', 'branch'))
1478 (func
1478 (func
1479 ('symbol', 'branch')
1479 ('symbol', 'branch')
1480 ('string', 'branch')))))
1480 ('string', 'branch')))))
1481 $ testlog -k expand -k merge
1481 $ testlog -k expand -k merge
1482 []
1482 []
1483 (group
1483 (group
1484 (group
1484 (group
1485 (or
1485 (or
1486 (func
1486 (func
1487 ('symbol', 'keyword')
1487 ('symbol', 'keyword')
1488 ('string', 'expand'))
1488 ('string', 'expand'))
1489 (func
1489 (func
1490 ('symbol', 'keyword')
1490 ('symbol', 'keyword')
1491 ('string', 'merge')))))
1491 ('string', 'merge')))))
1492 $ testlog --only-merges
1492 $ testlog --only-merges
1493 []
1493 []
1494 (group
1494 (group
1495 (func
1495 (func
1496 ('symbol', 'merge')
1496 ('symbol', 'merge')
1497 None))
1497 None))
1498 $ testlog --no-merges
1498 $ testlog --no-merges
1499 []
1499 []
1500 (group
1500 (group
1501 (not
1501 (not
1502 (func
1502 (func
1503 ('symbol', 'merge')
1503 ('symbol', 'merge')
1504 None)))
1504 None)))
1505 $ testlog --date '2 0 to 4 0'
1505 $ testlog --date '2 0 to 4 0'
1506 []
1506 []
1507 (group
1507 (group
1508 (func
1508 (func
1509 ('symbol', 'date')
1509 ('symbol', 'date')
1510 ('string', '2 0 to 4 0')))
1510 ('string', '2 0 to 4 0')))
1511 $ hg log -G -d 'brace ) in a date'
1511 $ hg log -G -d 'brace ) in a date'
1512 abort: invalid date: 'brace ) in a date'
1512 abort: invalid date: 'brace ) in a date'
1513 [255]
1513 [255]
1514 $ testlog --prune 31 --prune 32
1514 $ testlog --prune 31 --prune 32
1515 []
1515 []
1516 (group
1516 (group
1517 (group
1517 (group
1518 (and
1518 (and
1519 (not
1519 (not
1520 (group
1520 (group
1521 (or
1521 (or
1522 ('string', '31')
1522 ('string', '31')
1523 (func
1523 (func
1524 ('symbol', 'ancestors')
1524 ('symbol', 'ancestors')
1525 ('string', '31')))))
1525 ('string', '31')))))
1526 (not
1526 (not
1527 (group
1527 (group
1528 (or
1528 (or
1529 ('string', '32')
1529 ('string', '32')
1530 (func
1530 (func
1531 ('symbol', 'ancestors')
1531 ('symbol', 'ancestors')
1532 ('string', '32'))))))))
1532 ('string', '32'))))))))
1533
1533
1534 Dedicated repo for --follow and paths filtering. The g is crafted to
1534 Dedicated repo for --follow and paths filtering. The g is crafted to
1535 have 2 filelog topological heads in a linear changeset graph.
1535 have 2 filelog topological heads in a linear changeset graph.
1536
1536
1537 $ cd ..
1537 $ cd ..
1538 $ hg init follow
1538 $ hg init follow
1539 $ cd follow
1539 $ cd follow
1540 $ testlog --follow
1540 $ testlog --follow
1541 []
1541 []
1542 []
1542 []
1543 $ testlog -rnull
1543 $ testlog -rnull
1544 ['null']
1544 ['null']
1545 []
1545 []
1546 $ echo a > a
1546 $ echo a > a
1547 $ echo aa > aa
1547 $ echo aa > aa
1548 $ echo f > f
1548 $ echo f > f
1549 $ hg ci -Am "add a" a aa f
1549 $ hg ci -Am "add a" a aa f
1550 $ hg cp a b
1550 $ hg cp a b
1551 $ hg cp f g
1551 $ hg cp f g
1552 $ hg ci -m "copy a b"
1552 $ hg ci -m "copy a b"
1553 $ mkdir dir
1553 $ mkdir dir
1554 $ hg mv b dir
1554 $ hg mv b dir
1555 $ echo g >> g
1555 $ echo g >> g
1556 $ echo f >> f
1556 $ echo f >> f
1557 $ hg ci -m "mv b dir/b"
1557 $ hg ci -m "mv b dir/b"
1558 $ hg mv a b
1558 $ hg mv a b
1559 $ hg cp -f f g
1559 $ hg cp -f f g
1560 $ echo a > d
1560 $ echo a > d
1561 $ hg add d
1561 $ hg add d
1562 $ hg ci -m "mv a b; add d"
1562 $ hg ci -m "mv a b; add d"
1563 $ hg mv dir/b e
1563 $ hg mv dir/b e
1564 $ hg ci -m "mv dir/b e"
1564 $ hg ci -m "mv dir/b e"
1565 $ hg log -G --template '({rev}) {desc|firstline}\n'
1565 $ hg log -G --template '({rev}) {desc|firstline}\n'
1566 @ (4) mv dir/b e
1566 @ (4) mv dir/b e
1567 |
1567 |
1568 o (3) mv a b; add d
1568 o (3) mv a b; add d
1569 |
1569 |
1570 o (2) mv b dir/b
1570 o (2) mv b dir/b
1571 |
1571 |
1572 o (1) copy a b
1572 o (1) copy a b
1573 |
1573 |
1574 o (0) add a
1574 o (0) add a
1575
1575
1576
1576
1577 $ testlog a
1577 $ testlog a
1578 []
1578 []
1579 (group
1579 (group
1580 (group
1580 (group
1581 (func
1581 (func
1582 ('symbol', 'filelog')
1582 ('symbol', 'filelog')
1583 ('string', 'a'))))
1583 ('string', 'a'))))
1584 $ testlog a b
1584 $ testlog a b
1585 []
1585 []
1586 (group
1586 (group
1587 (group
1587 (group
1588 (or
1588 (or
1589 (func
1589 (func
1590 ('symbol', 'filelog')
1590 ('symbol', 'filelog')
1591 ('string', 'a'))
1591 ('string', 'a'))
1592 (func
1592 (func
1593 ('symbol', 'filelog')
1593 ('symbol', 'filelog')
1594 ('string', 'b')))))
1594 ('string', 'b')))))
1595
1595
1596 Test falling back to slow path for non-existing files
1596 Test falling back to slow path for non-existing files
1597
1597
1598 $ testlog a c
1598 $ testlog a c
1599 []
1599 []
1600 (group
1600 (group
1601 (func
1601 (func
1602 ('symbol', '_matchfiles')
1602 ('symbol', '_matchfiles')
1603 (list
1603 (list
1604 (list
1604 (list
1605 (list
1605 (list
1606 ('string', 'r:')
1606 ('string', 'r:')
1607 ('string', 'd:relpath'))
1607 ('string', 'd:relpath'))
1608 ('string', 'p:a'))
1608 ('string', 'p:a'))
1609 ('string', 'p:c'))))
1609 ('string', 'p:c'))))
1610
1610
1611 Test multiple --include/--exclude/paths
1611 Test multiple --include/--exclude/paths
1612
1612
1613 $ testlog --include a --include e --exclude b --exclude e a e
1613 $ testlog --include a --include e --exclude b --exclude e a e
1614 []
1614 []
1615 (group
1615 (group
1616 (func
1616 (func
1617 ('symbol', '_matchfiles')
1617 ('symbol', '_matchfiles')
1618 (list
1618 (list
1619 (list
1619 (list
1620 (list
1620 (list
1621 (list
1621 (list
1622 (list
1622 (list
1623 (list
1623 (list
1624 (list
1624 (list
1625 ('string', 'r:')
1625 ('string', 'r:')
1626 ('string', 'd:relpath'))
1626 ('string', 'd:relpath'))
1627 ('string', 'p:a'))
1627 ('string', 'p:a'))
1628 ('string', 'p:e'))
1628 ('string', 'p:e'))
1629 ('string', 'i:a'))
1629 ('string', 'i:a'))
1630 ('string', 'i:e'))
1630 ('string', 'i:e'))
1631 ('string', 'x:b'))
1631 ('string', 'x:b'))
1632 ('string', 'x:e'))))
1632 ('string', 'x:e'))))
1633
1633
1634 Test glob expansion of pats
1634 Test glob expansion of pats
1635
1635
1636 $ expandglobs=`$PYTHON -c "import mercurial.util; \
1636 $ expandglobs=`$PYTHON -c "import mercurial.util; \
1637 > print mercurial.util.expandglobs and 'true' or 'false'"`
1637 > print mercurial.util.expandglobs and 'true' or 'false'"`
1638 $ if [ $expandglobs = "true" ]; then
1638 $ if [ $expandglobs = "true" ]; then
1639 > testlog 'a*';
1639 > testlog 'a*';
1640 > else
1640 > else
1641 > testlog a*;
1641 > testlog a*;
1642 > fi;
1642 > fi;
1643 []
1643 []
1644 (group
1644 (group
1645 (group
1645 (group
1646 (func
1646 (func
1647 ('symbol', 'filelog')
1647 ('symbol', 'filelog')
1648 ('string', 'aa'))))
1648 ('string', 'aa'))))
1649
1649
1650 Test --follow on a non-existent directory
1650 Test --follow on a non-existent directory
1651
1651
1652 $ testlog -f dir
1652 $ testlog -f dir
1653 abort: cannot follow file not in parent revision: "dir"
1653 abort: cannot follow file not in parent revision: "dir"
1654 abort: cannot follow file not in parent revision: "dir"
1654 abort: cannot follow file not in parent revision: "dir"
1655 abort: cannot follow file not in parent revision: "dir"
1655 abort: cannot follow file not in parent revision: "dir"
1656
1656
1657 Test --follow on a directory
1657 Test --follow on a directory
1658
1658
1659 $ hg up -q '.^'
1659 $ hg up -q '.^'
1660 $ testlog -f dir
1660 $ testlog -f dir
1661 []
1661 []
1662 (group
1662 (group
1663 (and
1663 (and
1664 (func
1664 (func
1665 ('symbol', 'ancestors')
1665 ('symbol', 'ancestors')
1666 ('symbol', '.'))
1666 ('symbol', '.'))
1667 (func
1667 (func
1668 ('symbol', '_matchfiles')
1668 ('symbol', '_matchfiles')
1669 (list
1669 (list
1670 (list
1670 (list
1671 ('string', 'r:')
1671 ('string', 'r:')
1672 ('string', 'd:relpath'))
1672 ('string', 'd:relpath'))
1673 ('string', 'p:dir')))))
1673 ('string', 'p:dir')))))
1674 $ hg up -q tip
1674 $ hg up -q tip
1675
1675
1676 Test --follow on file not in parent revision
1676 Test --follow on file not in parent revision
1677
1677
1678 $ testlog -f a
1678 $ testlog -f a
1679 abort: cannot follow file not in parent revision: "a"
1679 abort: cannot follow file not in parent revision: "a"
1680 abort: cannot follow file not in parent revision: "a"
1680 abort: cannot follow file not in parent revision: "a"
1681 abort: cannot follow file not in parent revision: "a"
1681 abort: cannot follow file not in parent revision: "a"
1682
1682
1683 Test --follow and patterns
1683 Test --follow and patterns
1684
1684
1685 $ testlog -f 'glob:*'
1685 $ testlog -f 'glob:*'
1686 []
1686 []
1687 (group
1687 (group
1688 (and
1688 (and
1689 (func
1689 (func
1690 ('symbol', 'ancestors')
1690 ('symbol', 'ancestors')
1691 ('symbol', '.'))
1691 ('symbol', '.'))
1692 (func
1692 (func
1693 ('symbol', '_matchfiles')
1693 ('symbol', '_matchfiles')
1694 (list
1694 (list
1695 (list
1695 (list
1696 ('string', 'r:')
1696 ('string', 'r:')
1697 ('string', 'd:relpath'))
1697 ('string', 'd:relpath'))
1698 ('string', 'p:glob:*')))))
1698 ('string', 'p:glob:*')))))
1699
1699
1700 Test --follow on a single rename
1700 Test --follow on a single rename
1701
1701
1702 $ hg up -q 2
1702 $ hg up -q 2
1703 $ testlog -f a
1703 $ testlog -f a
1704 []
1704 []
1705 (group
1705 (group
1706 (group
1706 (group
1707 (func
1707 (func
1708 ('symbol', 'follow')
1708 ('symbol', 'follow')
1709 ('string', 'a'))))
1709 ('string', 'a'))))
1710
1710
1711 Test --follow and multiple renames
1711 Test --follow and multiple renames
1712
1712
1713 $ hg up -q tip
1713 $ hg up -q tip
1714 $ testlog -f e
1714 $ testlog -f e
1715 []
1715 []
1716 (group
1716 (group
1717 (group
1717 (group
1718 (func
1718 (func
1719 ('symbol', 'follow')
1719 ('symbol', 'follow')
1720 ('string', 'e'))))
1720 ('string', 'e'))))
1721
1721
1722 Test --follow and multiple filelog heads
1722 Test --follow and multiple filelog heads
1723
1723
1724 $ hg up -q 2
1724 $ hg up -q 2
1725 $ testlog -f g
1725 $ testlog -f g
1726 []
1726 []
1727 (group
1727 (group
1728 (group
1728 (group
1729 (func
1729 (func
1730 ('symbol', 'follow')
1730 ('symbol', 'follow')
1731 ('string', 'g'))))
1731 ('string', 'g'))))
1732 $ cat log.nodes
1732 $ cat log.nodes
1733 nodetag 2
1733 nodetag 2
1734 nodetag 1
1734 nodetag 1
1735 nodetag 0
1735 nodetag 0
1736 $ hg up -q tip
1736 $ hg up -q tip
1737 $ testlog -f g
1737 $ testlog -f g
1738 []
1738 []
1739 (group
1739 (group
1740 (group
1740 (group
1741 (func
1741 (func
1742 ('symbol', 'follow')
1742 ('symbol', 'follow')
1743 ('string', 'g'))))
1743 ('string', 'g'))))
1744 $ cat log.nodes
1744 $ cat log.nodes
1745 nodetag 3
1745 nodetag 3
1746 nodetag 2
1746 nodetag 2
1747 nodetag 0
1747 nodetag 0
1748
1748
1749 Test --follow and multiple files
1749 Test --follow and multiple files
1750
1750
1751 $ testlog -f g e
1751 $ testlog -f g e
1752 []
1752 []
1753 (group
1753 (group
1754 (group
1754 (group
1755 (or
1755 (or
1756 (func
1756 (func
1757 ('symbol', 'follow')
1757 ('symbol', 'follow')
1758 ('string', 'g'))
1758 ('string', 'g'))
1759 (func
1759 (func
1760 ('symbol', 'follow')
1760 ('symbol', 'follow')
1761 ('string', 'e')))))
1761 ('string', 'e')))))
1762 $ cat log.nodes
1762 $ cat log.nodes
1763 nodetag 4
1763 nodetag 4
1764 nodetag 3
1764 nodetag 3
1765 nodetag 2
1765 nodetag 2
1766 nodetag 1
1766 nodetag 1
1767 nodetag 0
1767 nodetag 0
1768
1768
1769 Test --follow null parent
1769 Test --follow null parent
1770
1770
1771 $ hg up -q null
1771 $ hg up -q null
1772 $ testlog -f
1772 $ testlog -f
1773 []
1773 []
1774 []
1774 []
1775
1775
1776 Test --follow-first
1776 Test --follow-first
1777
1777
1778 $ hg up -q 3
1778 $ hg up -q 3
1779 $ echo ee > e
1779 $ echo ee > e
1780 $ hg ci -Am "add another e" e
1780 $ hg ci -Am "add another e" e
1781 created new head
1781 created new head
1782 $ hg merge --tool internal:other 4
1782 $ hg merge --tool internal:other 4
1783 0 files updated, 1 files merged, 1 files removed, 0 files unresolved
1783 0 files updated, 1 files merged, 1 files removed, 0 files unresolved
1784 (branch merge, don't forget to commit)
1784 (branch merge, don't forget to commit)
1785 $ echo merge > e
1785 $ echo merge > e
1786 $ hg ci -m "merge 5 and 4"
1786 $ hg ci -m "merge 5 and 4"
1787 $ testlog --follow-first
1787 $ testlog --follow-first
1788 []
1788 []
1789 (group
1789 (group
1790 (func
1790 (func
1791 ('symbol', '_firstancestors')
1791 ('symbol', '_firstancestors')
1792 (func
1792 (func
1793 ('symbol', 'rev')
1793 ('symbol', 'rev')
1794 ('symbol', '6'))))
1794 ('symbol', '6'))))
1795
1795
1796 Cannot compare with log --follow-first FILE as it never worked
1796 Cannot compare with log --follow-first FILE as it never worked
1797
1797
1798 $ hg log -G --print-revset --follow-first e
1798 $ hg log -G --print-revset --follow-first e
1799 []
1799 []
1800 (group
1800 (group
1801 (group
1801 (group
1802 (func
1802 (func
1803 ('symbol', '_followfirst')
1803 ('symbol', '_followfirst')
1804 ('string', 'e'))))
1804 ('string', 'e'))))
1805 $ hg log -G --follow-first e --template '{rev} {desc|firstline}\n'
1805 $ hg log -G --follow-first e --template '{rev} {desc|firstline}\n'
1806 @ 6 merge 5 and 4
1806 @ 6 merge 5 and 4
1807 |\
1807 |\
1808 o | 5 add another e
1808 o | 5 add another e
1809 | |
1809 | |
1810
1810
1811 Test --copies
1811 Test --copies
1812
1812
1813 $ hg log -G --copies --template "{rev} {desc|firstline} \
1813 $ hg log -G --copies --template "{rev} {desc|firstline} \
1814 > copies: {file_copies_switch}\n"
1814 > copies: {file_copies_switch}\n"
1815 @ 6 merge 5 and 4 copies:
1815 @ 6 merge 5 and 4 copies:
1816 |\
1816 |\
1817 | o 5 add another e copies:
1817 | o 5 add another e copies:
1818 | |
1818 | |
1819 o | 4 mv dir/b e copies: e (dir/b)
1819 o | 4 mv dir/b e copies: e (dir/b)
1820 |/
1820 |/
1821 o 3 mv a b; add d copies: b (a)g (f)
1821 o 3 mv a b; add d copies: b (a)g (f)
1822 |
1822 |
1823 o 2 mv b dir/b copies: dir/b (b)
1823 o 2 mv b dir/b copies: dir/b (b)
1824 |
1824 |
1825 o 1 copy a b copies: b (a)g (f)
1825 o 1 copy a b copies: b (a)g (f)
1826 |
1826 |
1827 o 0 add a copies:
1827 o 0 add a copies:
1828
1828
1829 Test "set:..." and parent revision
1829 Test "set:..." and parent revision
1830
1830
1831 $ hg up -q 4
1831 $ hg up -q 4
1832 $ testlog "set:copied()"
1832 $ testlog "set:copied()"
1833 []
1833 []
1834 (group
1834 (group
1835 (func
1835 (func
1836 ('symbol', '_matchfiles')
1836 ('symbol', '_matchfiles')
1837 (list
1837 (list
1838 (list
1838 (list
1839 ('string', 'r:')
1839 ('string', 'r:')
1840 ('string', 'd:relpath'))
1840 ('string', 'd:relpath'))
1841 ('string', 'p:set:copied()'))))
1841 ('string', 'p:set:copied()'))))
1842 $ testlog --include "set:copied()"
1842 $ testlog --include "set:copied()"
1843 []
1843 []
1844 (group
1844 (group
1845 (func
1845 (func
1846 ('symbol', '_matchfiles')
1846 ('symbol', '_matchfiles')
1847 (list
1847 (list
1848 (list
1848 (list
1849 ('string', 'r:')
1849 ('string', 'r:')
1850 ('string', 'd:relpath'))
1850 ('string', 'd:relpath'))
1851 ('string', 'i:set:copied()'))))
1851 ('string', 'i:set:copied()'))))
1852 $ testlog -r "sort(file('set:copied()'), -rev)"
1852 $ testlog -r "sort(file('set:copied()'), -rev)"
1853 ["sort(file('set:copied()'), -rev)"]
1853 ["sort(file('set:copied()'), -rev)"]
1854 []
1854 []
1855
1855
1856 Test --removed
1856 Test --removed
1857
1857
1858 $ testlog --removed
1858 $ testlog --removed
1859 []
1859 []
1860 []
1860 []
1861 $ testlog --removed a
1861 $ testlog --removed a
1862 []
1862 []
1863 (group
1863 (group
1864 (func
1864 (func
1865 ('symbol', '_matchfiles')
1865 ('symbol', '_matchfiles')
1866 (list
1866 (list
1867 (list
1867 (list
1868 ('string', 'r:')
1868 ('string', 'r:')
1869 ('string', 'd:relpath'))
1869 ('string', 'd:relpath'))
1870 ('string', 'p:a'))))
1870 ('string', 'p:a'))))
1871 $ testlog --removed --follow a
1871 $ testlog --removed --follow a
1872 []
1872 []
1873 (group
1873 (group
1874 (and
1874 (and
1875 (func
1875 (func
1876 ('symbol', 'ancestors')
1876 ('symbol', 'ancestors')
1877 ('symbol', '.'))
1877 ('symbol', '.'))
1878 (func
1878 (func
1879 ('symbol', '_matchfiles')
1879 ('symbol', '_matchfiles')
1880 (list
1880 (list
1881 (list
1881 (list
1882 ('string', 'r:')
1882 ('string', 'r:')
1883 ('string', 'd:relpath'))
1883 ('string', 'd:relpath'))
1884 ('string', 'p:a')))))
1884 ('string', 'p:a')))))
1885
1885
1886 Test --patch and --stat with --follow and --follow-first
1886 Test --patch and --stat with --follow and --follow-first
1887
1887
1888 $ hg up -q 3
1888 $ hg up -q 3
1889 $ hg log -G --git --patch b
1889 $ hg log -G --git --patch b
1890 o changeset: 1:216d4c92cf98
1890 o changeset: 1:216d4c92cf98
1891 | user: test
1891 | user: test
1892 | date: Thu Jan 01 00:00:00 1970 +0000
1892 | date: Thu Jan 01 00:00:00 1970 +0000
1893 | summary: copy a b
1893 | summary: copy a b
1894 |
1894 |
1895 | diff --git a/a b/b
1895 | diff --git a/a b/b
1896 | copy from a
1896 | copy from a
1897 | copy to b
1897 | copy to b
1898 |
1898 |
1899
1899
1900 $ hg log -G --git --stat b
1900 $ hg log -G --git --stat b
1901 o changeset: 1:216d4c92cf98
1901 o changeset: 1:216d4c92cf98
1902 | user: test
1902 | user: test
1903 | date: Thu Jan 01 00:00:00 1970 +0000
1903 | date: Thu Jan 01 00:00:00 1970 +0000
1904 | summary: copy a b
1904 | summary: copy a b
1905 |
1905 |
1906 | b | 0
1906 | b | 0
1907 | 1 files changed, 0 insertions(+), 0 deletions(-)
1907 | 1 files changed, 0 insertions(+), 0 deletions(-)
1908 |
1908 |
1909
1909
1910 $ hg log -G --git --patch --follow b
1910 $ hg log -G --git --patch --follow b
1911 o changeset: 1:216d4c92cf98
1911 o changeset: 1:216d4c92cf98
1912 | user: test
1912 | user: test
1913 | date: Thu Jan 01 00:00:00 1970 +0000
1913 | date: Thu Jan 01 00:00:00 1970 +0000
1914 | summary: copy a b
1914 | summary: copy a b
1915 |
1915 |
1916 | diff --git a/a b/b
1916 | diff --git a/a b/b
1917 | copy from a
1917 | copy from a
1918 | copy to b
1918 | copy to b
1919 |
1919 |
1920 o changeset: 0:f8035bb17114
1920 o changeset: 0:f8035bb17114
1921 user: test
1921 user: test
1922 date: Thu Jan 01 00:00:00 1970 +0000
1922 date: Thu Jan 01 00:00:00 1970 +0000
1923 summary: add a
1923 summary: add a
1924
1924
1925 diff --git a/a b/a
1925 diff --git a/a b/a
1926 new file mode 100644
1926 new file mode 100644
1927 --- /dev/null
1927 --- /dev/null
1928 +++ b/a
1928 +++ b/a
1929 @@ -0,0 +1,1 @@
1929 @@ -0,0 +1,1 @@
1930 +a
1930 +a
1931
1931
1932
1932
1933 $ hg log -G --git --stat --follow b
1933 $ hg log -G --git --stat --follow b
1934 o changeset: 1:216d4c92cf98
1934 o changeset: 1:216d4c92cf98
1935 | user: test
1935 | user: test
1936 | date: Thu Jan 01 00:00:00 1970 +0000
1936 | date: Thu Jan 01 00:00:00 1970 +0000
1937 | summary: copy a b
1937 | summary: copy a b
1938 |
1938 |
1939 | b | 0
1939 | b | 0
1940 | 1 files changed, 0 insertions(+), 0 deletions(-)
1940 | 1 files changed, 0 insertions(+), 0 deletions(-)
1941 |
1941 |
1942 o changeset: 0:f8035bb17114
1942 o changeset: 0:f8035bb17114
1943 user: test
1943 user: test
1944 date: Thu Jan 01 00:00:00 1970 +0000
1944 date: Thu Jan 01 00:00:00 1970 +0000
1945 summary: add a
1945 summary: add a
1946
1946
1947 a | 1 +
1947 a | 1 +
1948 1 files changed, 1 insertions(+), 0 deletions(-)
1948 1 files changed, 1 insertions(+), 0 deletions(-)
1949
1949
1950
1950
1951 $ hg up -q 6
1951 $ hg up -q 6
1952 $ hg log -G --git --patch --follow-first e
1952 $ hg log -G --git --patch --follow-first e
1953 @ changeset: 6:fc281d8ff18d
1953 @ changeset: 6:fc281d8ff18d
1954 |\ tag: tip
1954 |\ tag: tip
1955 | | parent: 5:99b31f1c2782
1955 | | parent: 5:99b31f1c2782
1956 | | parent: 4:17d952250a9d
1956 | | parent: 4:17d952250a9d
1957 | | user: test
1957 | | user: test
1958 | | date: Thu Jan 01 00:00:00 1970 +0000
1958 | | date: Thu Jan 01 00:00:00 1970 +0000
1959 | | summary: merge 5 and 4
1959 | | summary: merge 5 and 4
1960 | |
1960 | |
1961 | | diff --git a/e b/e
1961 | | diff --git a/e b/e
1962 | | --- a/e
1962 | | --- a/e
1963 | | +++ b/e
1963 | | +++ b/e
1964 | | @@ -1,1 +1,1 @@
1964 | | @@ -1,1 +1,1 @@
1965 | | -ee
1965 | | -ee
1966 | | +merge
1966 | | +merge
1967 | |
1967 | |
1968 o | changeset: 5:99b31f1c2782
1968 o | changeset: 5:99b31f1c2782
1969 | | parent: 3:5918b8d165d1
1969 | | parent: 3:5918b8d165d1
1970 | | user: test
1970 | | user: test
1971 | | date: Thu Jan 01 00:00:00 1970 +0000
1971 | | date: Thu Jan 01 00:00:00 1970 +0000
1972 | | summary: add another e
1972 | | summary: add another e
1973 | |
1973 | |
1974 | | diff --git a/e b/e
1974 | | diff --git a/e b/e
1975 | | new file mode 100644
1975 | | new file mode 100644
1976 | | --- /dev/null
1976 | | --- /dev/null
1977 | | +++ b/e
1977 | | +++ b/e
1978 | | @@ -0,0 +1,1 @@
1978 | | @@ -0,0 +1,1 @@
1979 | | +ee
1979 | | +ee
1980 | |
1980 | |
1981
1981
1982 Test old-style --rev
1982 Test old-style --rev
1983
1983
1984 $ hg tag 'foo-bar'
1984 $ hg tag 'foo-bar'
1985 $ testlog -r 'foo-bar'
1985 $ testlog -r 'foo-bar'
1986 ['foo-bar']
1986 ['foo-bar']
1987 []
1987 []
1988
1988
1989 Test --follow and forward --rev
1989 Test --follow and forward --rev
1990
1990
1991 $ hg up -q 6
1991 $ hg up -q 6
1992 $ echo g > g
1992 $ echo g > g
1993 $ hg ci -Am 'add g' g
1993 $ hg ci -Am 'add g' g
1994 created new head
1994 created new head
1995 $ hg up -q 2
1995 $ hg up -q 2
1996 $ hg log -G --template "{rev} {desc|firstline}\n"
1996 $ hg log -G --template "{rev} {desc|firstline}\n"
1997 o 8 add g
1997 o 8 add g
1998 |
1998 |
1999 | o 7 Added tag foo-bar for changeset fc281d8ff18d
1999 | o 7 Added tag foo-bar for changeset fc281d8ff18d
2000 |/
2000 |/
2001 o 6 merge 5 and 4
2001 o 6 merge 5 and 4
2002 |\
2002 |\
2003 | o 5 add another e
2003 | o 5 add another e
2004 | |
2004 | |
2005 o | 4 mv dir/b e
2005 o | 4 mv dir/b e
2006 |/
2006 |/
2007 o 3 mv a b; add d
2007 o 3 mv a b; add d
2008 |
2008 |
2009 @ 2 mv b dir/b
2009 @ 2 mv b dir/b
2010 |
2010 |
2011 o 1 copy a b
2011 o 1 copy a b
2012 |
2012 |
2013 o 0 add a
2013 o 0 add a
2014
2014
2015 $ hg archive -r 7 archive
2015 $ hg archive -r 7 archive
2016 $ grep changessincelatesttag archive/.hg_archival.txt
2016 $ grep changessincelatesttag archive/.hg_archival.txt
2017 changessincelatesttag: 1
2017 changessincelatesttag: 1
2018 $ rm -r archive
2018 $ rm -r archive
2019
2019
2020 changessincelatesttag with no prior tag
2020 changessincelatesttag with no prior tag
2021 $ hg archive -r 4 archive
2021 $ hg archive -r 4 archive
2022 $ grep changessincelatesttag archive/.hg_archival.txt
2022 $ grep changessincelatesttag archive/.hg_archival.txt
2023 changessincelatesttag: 5
2023 changessincelatesttag: 5
2024
2024
2025 $ hg export 'all()'
2025 $ hg export 'all()'
2026 # HG changeset patch
2026 # HG changeset patch
2027 # User test
2027 # User test
2028 # Date 0 0
2028 # Date 0 0
2029 # Thu Jan 01 00:00:00 1970 +0000
2029 # Thu Jan 01 00:00:00 1970 +0000
2030 # Node ID f8035bb17114da16215af3436ec5222428ace8ee
2030 # Node ID f8035bb17114da16215af3436ec5222428ace8ee
2031 # Parent 0000000000000000000000000000000000000000
2031 # Parent 0000000000000000000000000000000000000000
2032 add a
2032 add a
2033
2033
2034 diff -r 000000000000 -r f8035bb17114 a
2034 diff -r 000000000000 -r f8035bb17114 a
2035 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2035 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2036 +++ b/a Thu Jan 01 00:00:00 1970 +0000
2036 +++ b/a Thu Jan 01 00:00:00 1970 +0000
2037 @@ -0,0 +1,1 @@
2037 @@ -0,0 +1,1 @@
2038 +a
2038 +a
2039 diff -r 000000000000 -r f8035bb17114 aa
2039 diff -r 000000000000 -r f8035bb17114 aa
2040 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2040 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2041 +++ b/aa Thu Jan 01 00:00:00 1970 +0000
2041 +++ b/aa Thu Jan 01 00:00:00 1970 +0000
2042 @@ -0,0 +1,1 @@
2042 @@ -0,0 +1,1 @@
2043 +aa
2043 +aa
2044 diff -r 000000000000 -r f8035bb17114 f
2044 diff -r 000000000000 -r f8035bb17114 f
2045 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2045 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2046 +++ b/f Thu Jan 01 00:00:00 1970 +0000
2046 +++ b/f Thu Jan 01 00:00:00 1970 +0000
2047 @@ -0,0 +1,1 @@
2047 @@ -0,0 +1,1 @@
2048 +f
2048 +f
2049 # HG changeset patch
2049 # HG changeset patch
2050 # User test
2050 # User test
2051 # Date 0 0
2051 # Date 0 0
2052 # Thu Jan 01 00:00:00 1970 +0000
2052 # Thu Jan 01 00:00:00 1970 +0000
2053 # Node ID 216d4c92cf98ff2b4641d508b76b529f3d424c92
2053 # Node ID 216d4c92cf98ff2b4641d508b76b529f3d424c92
2054 # Parent f8035bb17114da16215af3436ec5222428ace8ee
2054 # Parent f8035bb17114da16215af3436ec5222428ace8ee
2055 copy a b
2055 copy a b
2056
2056
2057 diff -r f8035bb17114 -r 216d4c92cf98 b
2057 diff -r f8035bb17114 -r 216d4c92cf98 b
2058 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2058 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2059 +++ b/b Thu Jan 01 00:00:00 1970 +0000
2059 +++ b/b Thu Jan 01 00:00:00 1970 +0000
2060 @@ -0,0 +1,1 @@
2060 @@ -0,0 +1,1 @@
2061 +a
2061 +a
2062 diff -r f8035bb17114 -r 216d4c92cf98 g
2062 diff -r f8035bb17114 -r 216d4c92cf98 g
2063 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2063 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2064 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2064 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2065 @@ -0,0 +1,1 @@
2065 @@ -0,0 +1,1 @@
2066 +f
2066 +f
2067 # HG changeset patch
2067 # HG changeset patch
2068 # User test
2068 # User test
2069 # Date 0 0
2069 # Date 0 0
2070 # Thu Jan 01 00:00:00 1970 +0000
2070 # Thu Jan 01 00:00:00 1970 +0000
2071 # Node ID bb573313a9e8349099b6ea2b2fb1fc7f424446f3
2071 # Node ID bb573313a9e8349099b6ea2b2fb1fc7f424446f3
2072 # Parent 216d4c92cf98ff2b4641d508b76b529f3d424c92
2072 # Parent 216d4c92cf98ff2b4641d508b76b529f3d424c92
2073 mv b dir/b
2073 mv b dir/b
2074
2074
2075 diff -r 216d4c92cf98 -r bb573313a9e8 b
2075 diff -r 216d4c92cf98 -r bb573313a9e8 b
2076 --- a/b Thu Jan 01 00:00:00 1970 +0000
2076 --- a/b Thu Jan 01 00:00:00 1970 +0000
2077 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2077 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2078 @@ -1,1 +0,0 @@
2078 @@ -1,1 +0,0 @@
2079 -a
2079 -a
2080 diff -r 216d4c92cf98 -r bb573313a9e8 dir/b
2080 diff -r 216d4c92cf98 -r bb573313a9e8 dir/b
2081 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2081 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2082 +++ b/dir/b Thu Jan 01 00:00:00 1970 +0000
2082 +++ b/dir/b Thu Jan 01 00:00:00 1970 +0000
2083 @@ -0,0 +1,1 @@
2083 @@ -0,0 +1,1 @@
2084 +a
2084 +a
2085 diff -r 216d4c92cf98 -r bb573313a9e8 f
2085 diff -r 216d4c92cf98 -r bb573313a9e8 f
2086 --- a/f Thu Jan 01 00:00:00 1970 +0000
2086 --- a/f Thu Jan 01 00:00:00 1970 +0000
2087 +++ b/f Thu Jan 01 00:00:00 1970 +0000
2087 +++ b/f Thu Jan 01 00:00:00 1970 +0000
2088 @@ -1,1 +1,2 @@
2088 @@ -1,1 +1,2 @@
2089 f
2089 f
2090 +f
2090 +f
2091 diff -r 216d4c92cf98 -r bb573313a9e8 g
2091 diff -r 216d4c92cf98 -r bb573313a9e8 g
2092 --- a/g Thu Jan 01 00:00:00 1970 +0000
2092 --- a/g Thu Jan 01 00:00:00 1970 +0000
2093 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2093 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2094 @@ -1,1 +1,2 @@
2094 @@ -1,1 +1,2 @@
2095 f
2095 f
2096 +g
2096 +g
2097 # HG changeset patch
2097 # HG changeset patch
2098 # User test
2098 # User test
2099 # Date 0 0
2099 # Date 0 0
2100 # Thu Jan 01 00:00:00 1970 +0000
2100 # Thu Jan 01 00:00:00 1970 +0000
2101 # Node ID 5918b8d165d1364e78a66d02e66caa0133c5d1ed
2101 # Node ID 5918b8d165d1364e78a66d02e66caa0133c5d1ed
2102 # Parent bb573313a9e8349099b6ea2b2fb1fc7f424446f3
2102 # Parent bb573313a9e8349099b6ea2b2fb1fc7f424446f3
2103 mv a b; add d
2103 mv a b; add d
2104
2104
2105 diff -r bb573313a9e8 -r 5918b8d165d1 a
2105 diff -r bb573313a9e8 -r 5918b8d165d1 a
2106 --- a/a Thu Jan 01 00:00:00 1970 +0000
2106 --- a/a Thu Jan 01 00:00:00 1970 +0000
2107 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2107 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2108 @@ -1,1 +0,0 @@
2108 @@ -1,1 +0,0 @@
2109 -a
2109 -a
2110 diff -r bb573313a9e8 -r 5918b8d165d1 b
2110 diff -r bb573313a9e8 -r 5918b8d165d1 b
2111 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2111 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2112 +++ b/b Thu Jan 01 00:00:00 1970 +0000
2112 +++ b/b Thu Jan 01 00:00:00 1970 +0000
2113 @@ -0,0 +1,1 @@
2113 @@ -0,0 +1,1 @@
2114 +a
2114 +a
2115 diff -r bb573313a9e8 -r 5918b8d165d1 d
2115 diff -r bb573313a9e8 -r 5918b8d165d1 d
2116 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2116 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2117 +++ b/d Thu Jan 01 00:00:00 1970 +0000
2117 +++ b/d Thu Jan 01 00:00:00 1970 +0000
2118 @@ -0,0 +1,1 @@
2118 @@ -0,0 +1,1 @@
2119 +a
2119 +a
2120 diff -r bb573313a9e8 -r 5918b8d165d1 g
2120 diff -r bb573313a9e8 -r 5918b8d165d1 g
2121 --- a/g Thu Jan 01 00:00:00 1970 +0000
2121 --- a/g Thu Jan 01 00:00:00 1970 +0000
2122 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2122 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2123 @@ -1,2 +1,2 @@
2123 @@ -1,2 +1,2 @@
2124 f
2124 f
2125 -g
2125 -g
2126 +f
2126 +f
2127 # HG changeset patch
2127 # HG changeset patch
2128 # User test
2128 # User test
2129 # Date 0 0
2129 # Date 0 0
2130 # Thu Jan 01 00:00:00 1970 +0000
2130 # Thu Jan 01 00:00:00 1970 +0000
2131 # Node ID 17d952250a9d03cc3dc77b199ab60e959b9b0260
2131 # Node ID 17d952250a9d03cc3dc77b199ab60e959b9b0260
2132 # Parent 5918b8d165d1364e78a66d02e66caa0133c5d1ed
2132 # Parent 5918b8d165d1364e78a66d02e66caa0133c5d1ed
2133 mv dir/b e
2133 mv dir/b e
2134
2134
2135 diff -r 5918b8d165d1 -r 17d952250a9d dir/b
2135 diff -r 5918b8d165d1 -r 17d952250a9d dir/b
2136 --- a/dir/b Thu Jan 01 00:00:00 1970 +0000
2136 --- a/dir/b Thu Jan 01 00:00:00 1970 +0000
2137 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2137 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2138 @@ -1,1 +0,0 @@
2138 @@ -1,1 +0,0 @@
2139 -a
2139 -a
2140 diff -r 5918b8d165d1 -r 17d952250a9d e
2140 diff -r 5918b8d165d1 -r 17d952250a9d e
2141 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2141 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2142 +++ b/e Thu Jan 01 00:00:00 1970 +0000
2142 +++ b/e Thu Jan 01 00:00:00 1970 +0000
2143 @@ -0,0 +1,1 @@
2143 @@ -0,0 +1,1 @@
2144 +a
2144 +a
2145 # HG changeset patch
2145 # HG changeset patch
2146 # User test
2146 # User test
2147 # Date 0 0
2147 # Date 0 0
2148 # Thu Jan 01 00:00:00 1970 +0000
2148 # Thu Jan 01 00:00:00 1970 +0000
2149 # Node ID 99b31f1c2782e2deb1723cef08930f70fc84b37b
2149 # Node ID 99b31f1c2782e2deb1723cef08930f70fc84b37b
2150 # Parent 5918b8d165d1364e78a66d02e66caa0133c5d1ed
2150 # Parent 5918b8d165d1364e78a66d02e66caa0133c5d1ed
2151 add another e
2151 add another e
2152
2152
2153 diff -r 5918b8d165d1 -r 99b31f1c2782 e
2153 diff -r 5918b8d165d1 -r 99b31f1c2782 e
2154 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2154 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2155 +++ b/e Thu Jan 01 00:00:00 1970 +0000
2155 +++ b/e Thu Jan 01 00:00:00 1970 +0000
2156 @@ -0,0 +1,1 @@
2156 @@ -0,0 +1,1 @@
2157 +ee
2157 +ee
2158 # HG changeset patch
2158 # HG changeset patch
2159 # User test
2159 # User test
2160 # Date 0 0
2160 # Date 0 0
2161 # Thu Jan 01 00:00:00 1970 +0000
2161 # Thu Jan 01 00:00:00 1970 +0000
2162 # Node ID fc281d8ff18d999ad6497b3d27390bcd695dcc73
2162 # Node ID fc281d8ff18d999ad6497b3d27390bcd695dcc73
2163 # Parent 99b31f1c2782e2deb1723cef08930f70fc84b37b
2163 # Parent 99b31f1c2782e2deb1723cef08930f70fc84b37b
2164 # Parent 17d952250a9d03cc3dc77b199ab60e959b9b0260
2164 # Parent 17d952250a9d03cc3dc77b199ab60e959b9b0260
2165 merge 5 and 4
2165 merge 5 and 4
2166
2166
2167 diff -r 99b31f1c2782 -r fc281d8ff18d dir/b
2167 diff -r 99b31f1c2782 -r fc281d8ff18d dir/b
2168 --- a/dir/b Thu Jan 01 00:00:00 1970 +0000
2168 --- a/dir/b Thu Jan 01 00:00:00 1970 +0000
2169 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2169 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2170 @@ -1,1 +0,0 @@
2170 @@ -1,1 +0,0 @@
2171 -a
2171 -a
2172 diff -r 99b31f1c2782 -r fc281d8ff18d e
2172 diff -r 99b31f1c2782 -r fc281d8ff18d e
2173 --- a/e Thu Jan 01 00:00:00 1970 +0000
2173 --- a/e Thu Jan 01 00:00:00 1970 +0000
2174 +++ b/e Thu Jan 01 00:00:00 1970 +0000
2174 +++ b/e Thu Jan 01 00:00:00 1970 +0000
2175 @@ -1,1 +1,1 @@
2175 @@ -1,1 +1,1 @@
2176 -ee
2176 -ee
2177 +merge
2177 +merge
2178 # HG changeset patch
2178 # HG changeset patch
2179 # User test
2179 # User test
2180 # Date 0 0
2180 # Date 0 0
2181 # Thu Jan 01 00:00:00 1970 +0000
2181 # Thu Jan 01 00:00:00 1970 +0000
2182 # Node ID 02dbb8e276b8ab7abfd07cab50c901647e75c2dd
2182 # Node ID 02dbb8e276b8ab7abfd07cab50c901647e75c2dd
2183 # Parent fc281d8ff18d999ad6497b3d27390bcd695dcc73
2183 # Parent fc281d8ff18d999ad6497b3d27390bcd695dcc73
2184 Added tag foo-bar for changeset fc281d8ff18d
2184 Added tag foo-bar for changeset fc281d8ff18d
2185
2185
2186 diff -r fc281d8ff18d -r 02dbb8e276b8 .hgtags
2186 diff -r fc281d8ff18d -r 02dbb8e276b8 .hgtags
2187 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2187 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2188 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
2188 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
2189 @@ -0,0 +1,1 @@
2189 @@ -0,0 +1,1 @@
2190 +fc281d8ff18d999ad6497b3d27390bcd695dcc73 foo-bar
2190 +fc281d8ff18d999ad6497b3d27390bcd695dcc73 foo-bar
2191 # HG changeset patch
2191 # HG changeset patch
2192 # User test
2192 # User test
2193 # Date 0 0
2193 # Date 0 0
2194 # Thu Jan 01 00:00:00 1970 +0000
2194 # Thu Jan 01 00:00:00 1970 +0000
2195 # Node ID 24c2e826ddebf80f9dcd60b856bdb8e6715c5449
2195 # Node ID 24c2e826ddebf80f9dcd60b856bdb8e6715c5449
2196 # Parent fc281d8ff18d999ad6497b3d27390bcd695dcc73
2196 # Parent fc281d8ff18d999ad6497b3d27390bcd695dcc73
2197 add g
2197 add g
2198
2198
2199 diff -r fc281d8ff18d -r 24c2e826ddeb g
2199 diff -r fc281d8ff18d -r 24c2e826ddeb g
2200 --- a/g Thu Jan 01 00:00:00 1970 +0000
2200 --- a/g Thu Jan 01 00:00:00 1970 +0000
2201 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2201 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2202 @@ -1,2 +1,1 @@
2202 @@ -1,2 +1,1 @@
2203 -f
2203 -f
2204 -f
2204 -f
2205 +g
2205 +g
2206 $ testlog --follow -r6 -r8 -r5 -r7 -r4
2206 $ testlog --follow -r6 -r8 -r5 -r7 -r4
2207 ['6', '8', '5', '7', '4']
2207 ['6', '8', '5', '7', '4']
2208 (group
2208 (group
2209 (func
2209 (func
2210 ('symbol', 'descendants')
2210 ('symbol', 'descendants')
2211 (func
2211 (func
2212 ('symbol', 'rev')
2212 ('symbol', 'rev')
2213 ('symbol', '6'))))
2213 ('symbol', '6'))))
2214
2214
2215 Test --follow-first and forward --rev
2215 Test --follow-first and forward --rev
2216
2216
2217 $ testlog --follow-first -r6 -r8 -r5 -r7 -r4
2217 $ testlog --follow-first -r6 -r8 -r5 -r7 -r4
2218 ['6', '8', '5', '7', '4']
2218 ['6', '8', '5', '7', '4']
2219 (group
2219 (group
2220 (func
2220 (func
2221 ('symbol', '_firstdescendants')
2221 ('symbol', '_firstdescendants')
2222 (func
2222 (func
2223 ('symbol', 'rev')
2223 ('symbol', 'rev')
2224 ('symbol', '6'))))
2224 ('symbol', '6'))))
2225 --- log.nodes * (glob)
2225 --- log.nodes * (glob)
2226 +++ glog.nodes * (glob)
2226 +++ glog.nodes * (glob)
2227 @@ -1,3 +1,3 @@
2227 @@ -1,3 +1,3 @@
2228 -nodetag 6
2228 -nodetag 6
2229 nodetag 8
2229 nodetag 8
2230 nodetag 7
2230 nodetag 7
2231 +nodetag 6
2231 +nodetag 6
2232
2232
2233 Test --follow and backward --rev
2233 Test --follow and backward --rev
2234
2234
2235 $ testlog --follow -r6 -r5 -r7 -r8 -r4
2235 $ testlog --follow -r6 -r5 -r7 -r8 -r4
2236 ['6', '5', '7', '8', '4']
2236 ['6', '5', '7', '8', '4']
2237 (group
2237 (group
2238 (func
2238 (func
2239 ('symbol', 'ancestors')
2239 ('symbol', 'ancestors')
2240 (func
2240 (func
2241 ('symbol', 'rev')
2241 ('symbol', 'rev')
2242 ('symbol', '6'))))
2242 ('symbol', '6'))))
2243
2243
2244 Test --follow-first and backward --rev
2244 Test --follow-first and backward --rev
2245
2245
2246 $ testlog --follow-first -r6 -r5 -r7 -r8 -r4
2246 $ testlog --follow-first -r6 -r5 -r7 -r8 -r4
2247 ['6', '5', '7', '8', '4']
2247 ['6', '5', '7', '8', '4']
2248 (group
2248 (group
2249 (func
2249 (func
2250 ('symbol', '_firstancestors')
2250 ('symbol', '_firstancestors')
2251 (func
2251 (func
2252 ('symbol', 'rev')
2252 ('symbol', 'rev')
2253 ('symbol', '6'))))
2253 ('symbol', '6'))))
2254
2254
2255 Test --follow with --rev of graphlog extension
2255 Test --follow with --rev of graphlog extension
2256
2256
2257 $ hg --config extensions.graphlog= glog -qfr1
2257 $ hg --config extensions.graphlog= glog -qfr1
2258 o 1:216d4c92cf98
2258 o 1:216d4c92cf98
2259 |
2259 |
2260 o 0:f8035bb17114
2260 o 0:f8035bb17114
2261
2261
2262
2262
2263 Test subdir
2263 Test subdir
2264
2264
2265 $ hg up -q 3
2265 $ hg up -q 3
2266 $ cd dir
2266 $ cd dir
2267 $ testlog .
2267 $ testlog .
2268 []
2268 []
2269 (group
2269 (group
2270 (func
2270 (func
2271 ('symbol', '_matchfiles')
2271 ('symbol', '_matchfiles')
2272 (list
2272 (list
2273 (list
2273 (list
2274 ('string', 'r:')
2274 ('string', 'r:')
2275 ('string', 'd:relpath'))
2275 ('string', 'd:relpath'))
2276 ('string', 'p:.'))))
2276 ('string', 'p:.'))))
2277 $ testlog ../b
2277 $ testlog ../b
2278 []
2278 []
2279 (group
2279 (group
2280 (group
2280 (group
2281 (func
2281 (func
2282 ('symbol', 'filelog')
2282 ('symbol', 'filelog')
2283 ('string', '../b'))))
2283 ('string', '../b'))))
2284 $ testlog -f ../b
2284 $ testlog -f ../b
2285 []
2285 []
2286 (group
2286 (group
2287 (group
2287 (group
2288 (func
2288 (func
2289 ('symbol', 'follow')
2289 ('symbol', 'follow')
2290 ('string', 'b'))))
2290 ('string', 'b'))))
2291 $ cd ..
2291 $ cd ..
2292
2292
2293 Test --hidden
2293 Test --hidden
2294 (enable obsolete)
2294 (enable obsolete)
2295
2295
2296 $ cat >> $HGRCPATH << EOF
2296 $ cat >> $HGRCPATH << EOF
2297 > [experimental]
2297 > [experimental]
2298 > evolution=createmarkers
2298 > evolution=createmarkers
2299 > EOF
2299 > EOF
2300
2300
2301 $ hg debugobsolete `hg id --debug -i -r 8`
2301 $ hg debugobsolete `hg id --debug -i -r 8`
2302 $ testlog
2302 $ testlog
2303 []
2303 []
2304 []
2304 []
2305 $ testlog --hidden
2305 $ testlog --hidden
2306 []
2306 []
2307 []
2307 []
2308 $ hg log -G --template '{rev} {desc}\n'
2308 $ hg log -G --template '{rev} {desc}\n'
2309 o 7 Added tag foo-bar for changeset fc281d8ff18d
2309 o 7 Added tag foo-bar for changeset fc281d8ff18d
2310 |
2310 |
2311 o 6 merge 5 and 4
2311 o 6 merge 5 and 4
2312 |\
2312 |\
2313 | o 5 add another e
2313 | o 5 add another e
2314 | |
2314 | |
2315 o | 4 mv dir/b e
2315 o | 4 mv dir/b e
2316 |/
2316 |/
2317 @ 3 mv a b; add d
2317 @ 3 mv a b; add d
2318 |
2318 |
2319 o 2 mv b dir/b
2319 o 2 mv b dir/b
2320 |
2320 |
2321 o 1 copy a b
2321 o 1 copy a b
2322 |
2322 |
2323 o 0 add a
2323 o 0 add a
2324
2324
2325
2325
2326 A template without trailing newline should do something sane
2326 A template without trailing newline should do something sane
2327
2327
2328 $ hg log -G -r ::2 --template '{rev} {desc}'
2328 $ hg log -G -r ::2 --template '{rev} {desc}'
2329 o 2 mv b dir/b
2329 o 2 mv b dir/b
2330 |
2330 |
2331 o 1 copy a b
2331 o 1 copy a b
2332 |
2332 |
2333 o 0 add a
2333 o 0 add a
2334
2334
2335
2335
2336 Extra newlines must be preserved
2336 Extra newlines must be preserved
2337
2337
2338 $ hg log -G -r ::2 --template '\n{rev} {desc}\n\n'
2338 $ hg log -G -r ::2 --template '\n{rev} {desc}\n\n'
2339 o
2339 o
2340 | 2 mv b dir/b
2340 | 2 mv b dir/b
2341 |
2341 |
2342 o
2342 o
2343 | 1 copy a b
2343 | 1 copy a b
2344 |
2344 |
2345 o
2345 o
2346 0 add a
2346 0 add a
2347
2347
2348
2348
2349 The almost-empty template should do something sane too ...
2349 The almost-empty template should do something sane too ...
2350
2350
2351 $ hg log -G -r ::2 --template '\n'
2351 $ hg log -G -r ::2 --template '\n'
2352 o
2352 o
2353 |
2353 |
2354 o
2354 o
2355 |
2355 |
2356 o
2356 o
2357
2357
2358
2358
2359 issue3772
2359 issue3772
2360
2360
2361 $ hg log -G -r :null
2361 $ hg log -G -r :null
2362 o changeset: 0:f8035bb17114
2362 o changeset: 0:f8035bb17114
2363 | user: test
2363 | user: test
2364 | date: Thu Jan 01 00:00:00 1970 +0000
2364 | date: Thu Jan 01 00:00:00 1970 +0000
2365 | summary: add a
2365 | summary: add a
2366 |
2366 |
2367 o changeset: -1:000000000000
2367 o changeset: -1:000000000000
2368 user:
2368 user:
2369 date: Thu Jan 01 00:00:00 1970 +0000
2369 date: Thu Jan 01 00:00:00 1970 +0000
2370
2370
2371 $ hg log -G -r null:null
2371 $ hg log -G -r null:null
2372 o changeset: -1:000000000000
2372 o changeset: -1:000000000000
2373 user:
2373 user:
2374 date: Thu Jan 01 00:00:00 1970 +0000
2374 date: Thu Jan 01 00:00:00 1970 +0000
2375
2375
2376
2376
2377 should not draw line down to null due to the magic of fullreposet
2377 should not draw line down to null due to the magic of fullreposet
2378
2378
2379 $ hg log -G -r 'all()' | tail -6
2379 $ hg log -G -r 'all()' | tail -6
2380 |
2380 |
2381 o changeset: 0:f8035bb17114
2381 o changeset: 0:f8035bb17114
2382 user: test
2382 user: test
2383 date: Thu Jan 01 00:00:00 1970 +0000
2383 date: Thu Jan 01 00:00:00 1970 +0000
2384 summary: add a
2384 summary: add a
2385
2385
2386
2386
2387 $ hg log -G -r 'branch(default)' | tail -6
2387 $ hg log -G -r 'branch(default)' | tail -6
2388 |
2388 |
2389 o changeset: 0:f8035bb17114
2389 o changeset: 0:f8035bb17114
2390 user: test
2390 user: test
2391 date: Thu Jan 01 00:00:00 1970 +0000
2391 date: Thu Jan 01 00:00:00 1970 +0000
2392 summary: add a
2392 summary: add a
2393
2393
2394
2394
2395 working-directory revision
2396
2397 $ hg log -G -qr '. + wdir()'
2398 o 2147483647:ffffffffffff
2399 |
2400 @ 3:5918b8d165d1
2401 |
2402
2395 $ cd ..
2403 $ cd ..
@@ -1,2053 +1,2061 b''
1 $ HGENCODING=utf-8
1 $ HGENCODING=utf-8
2 $ export HGENCODING
2 $ export HGENCODING
3 $ cat > testrevset.py << EOF
3 $ cat > testrevset.py << EOF
4 > import mercurial.revset
4 > import mercurial.revset
5 >
5 >
6 > baseset = mercurial.revset.baseset
6 > baseset = mercurial.revset.baseset
7 >
7 >
8 > def r3232(repo, subset, x):
8 > def r3232(repo, subset, x):
9 > """"simple revset that return [3,2,3,2]
9 > """"simple revset that return [3,2,3,2]
10 >
10 >
11 > revisions duplicated on purpose.
11 > revisions duplicated on purpose.
12 > """
12 > """
13 > if 3 not in subset:
13 > if 3 not in subset:
14 > if 2 in subset:
14 > if 2 in subset:
15 > return baseset([2,2])
15 > return baseset([2,2])
16 > return baseset()
16 > return baseset()
17 > return baseset([3,3,2,2])
17 > return baseset([3,3,2,2])
18 >
18 >
19 > mercurial.revset.symbols['r3232'] = r3232
19 > mercurial.revset.symbols['r3232'] = r3232
20 > EOF
20 > EOF
21 $ cat >> $HGRCPATH << EOF
21 $ cat >> $HGRCPATH << EOF
22 > [extensions]
22 > [extensions]
23 > testrevset=$TESTTMP/testrevset.py
23 > testrevset=$TESTTMP/testrevset.py
24 > EOF
24 > EOF
25
25
26 $ try() {
26 $ try() {
27 > hg debugrevspec --debug "$@"
27 > hg debugrevspec --debug "$@"
28 > }
28 > }
29
29
30 $ log() {
30 $ log() {
31 > hg log --template '{rev}\n' -r "$1"
31 > hg log --template '{rev}\n' -r "$1"
32 > }
32 > }
33
33
34 $ hg init repo
34 $ hg init repo
35 $ cd repo
35 $ cd repo
36
36
37 $ echo a > a
37 $ echo a > a
38 $ hg branch a
38 $ hg branch a
39 marked working directory as branch a
39 marked working directory as branch a
40 (branches are permanent and global, did you want a bookmark?)
40 (branches are permanent and global, did you want a bookmark?)
41 $ hg ci -Aqm0
41 $ hg ci -Aqm0
42
42
43 $ echo b > b
43 $ echo b > b
44 $ hg branch b
44 $ hg branch b
45 marked working directory as branch b
45 marked working directory as branch b
46 $ hg ci -Aqm1
46 $ hg ci -Aqm1
47
47
48 $ rm a
48 $ rm a
49 $ hg branch a-b-c-
49 $ hg branch a-b-c-
50 marked working directory as branch a-b-c-
50 marked working directory as branch a-b-c-
51 $ hg ci -Aqm2 -u Bob
51 $ hg ci -Aqm2 -u Bob
52
52
53 $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
53 $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
54 2
54 2
55 $ hg log -r "extra('branch')" --template '{rev}\n'
55 $ hg log -r "extra('branch')" --template '{rev}\n'
56 0
56 0
57 1
57 1
58 2
58 2
59 $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
59 $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
60 0 a
60 0 a
61 2 a-b-c-
61 2 a-b-c-
62
62
63 $ hg co 1
63 $ hg co 1
64 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
64 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
65 $ hg branch +a+b+c+
65 $ hg branch +a+b+c+
66 marked working directory as branch +a+b+c+
66 marked working directory as branch +a+b+c+
67 $ hg ci -Aqm3
67 $ hg ci -Aqm3
68
68
69 $ hg co 2 # interleave
69 $ hg co 2 # interleave
70 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
70 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
71 $ echo bb > b
71 $ echo bb > b
72 $ hg branch -- -a-b-c-
72 $ hg branch -- -a-b-c-
73 marked working directory as branch -a-b-c-
73 marked working directory as branch -a-b-c-
74 $ hg ci -Aqm4 -d "May 12 2005"
74 $ hg ci -Aqm4 -d "May 12 2005"
75
75
76 $ hg co 3
76 $ hg co 3
77 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
77 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
78 $ hg branch !a/b/c/
78 $ hg branch !a/b/c/
79 marked working directory as branch !a/b/c/
79 marked working directory as branch !a/b/c/
80 $ hg ci -Aqm"5 bug"
80 $ hg ci -Aqm"5 bug"
81
81
82 $ hg merge 4
82 $ hg merge 4
83 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
83 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
84 (branch merge, don't forget to commit)
84 (branch merge, don't forget to commit)
85 $ hg branch _a_b_c_
85 $ hg branch _a_b_c_
86 marked working directory as branch _a_b_c_
86 marked working directory as branch _a_b_c_
87 $ hg ci -Aqm"6 issue619"
87 $ hg ci -Aqm"6 issue619"
88
88
89 $ hg branch .a.b.c.
89 $ hg branch .a.b.c.
90 marked working directory as branch .a.b.c.
90 marked working directory as branch .a.b.c.
91 $ hg ci -Aqm7
91 $ hg ci -Aqm7
92
92
93 $ hg branch all
93 $ hg branch all
94 marked working directory as branch all
94 marked working directory as branch all
95
95
96 $ hg co 4
96 $ hg co 4
97 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
97 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
98 $ hg branch Γ©
98 $ hg branch Γ©
99 marked working directory as branch \xc3\xa9 (esc)
99 marked working directory as branch \xc3\xa9 (esc)
100 $ hg ci -Aqm9
100 $ hg ci -Aqm9
101
101
102 $ hg tag -r6 1.0
102 $ hg tag -r6 1.0
103 $ hg bookmark -r6 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
103 $ hg bookmark -r6 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
104
104
105 $ hg clone --quiet -U -r 7 . ../remote1
105 $ hg clone --quiet -U -r 7 . ../remote1
106 $ hg clone --quiet -U -r 8 . ../remote2
106 $ hg clone --quiet -U -r 8 . ../remote2
107 $ echo "[paths]" >> .hg/hgrc
107 $ echo "[paths]" >> .hg/hgrc
108 $ echo "default = ../remote1" >> .hg/hgrc
108 $ echo "default = ../remote1" >> .hg/hgrc
109
109
110 trivial
110 trivial
111
111
112 $ try 0:1
112 $ try 0:1
113 (range
113 (range
114 ('symbol', '0')
114 ('symbol', '0')
115 ('symbol', '1'))
115 ('symbol', '1'))
116 * set:
116 * set:
117 <spanset+ 0:1>
117 <spanset+ 0:1>
118 0
118 0
119 1
119 1
120 $ try 3::6
120 $ try 3::6
121 (dagrange
121 (dagrange
122 ('symbol', '3')
122 ('symbol', '3')
123 ('symbol', '6'))
123 ('symbol', '6'))
124 * set:
124 * set:
125 <baseset [3, 5, 6]>
125 <baseset [3, 5, 6]>
126 3
126 3
127 5
127 5
128 6
128 6
129 $ try '0|1|2'
129 $ try '0|1|2'
130 (or
130 (or
131 ('symbol', '0')
131 ('symbol', '0')
132 ('symbol', '1')
132 ('symbol', '1')
133 ('symbol', '2'))
133 ('symbol', '2'))
134 * set:
134 * set:
135 <baseset [0, 1, 2]>
135 <baseset [0, 1, 2]>
136 0
136 0
137 1
137 1
138 2
138 2
139
139
140 names that should work without quoting
140 names that should work without quoting
141
141
142 $ try a
142 $ try a
143 ('symbol', 'a')
143 ('symbol', 'a')
144 * set:
144 * set:
145 <baseset [0]>
145 <baseset [0]>
146 0
146 0
147 $ try b-a
147 $ try b-a
148 (minus
148 (minus
149 ('symbol', 'b')
149 ('symbol', 'b')
150 ('symbol', 'a'))
150 ('symbol', 'a'))
151 * set:
151 * set:
152 <filteredset
152 <filteredset
153 <baseset [1]>>
153 <baseset [1]>>
154 1
154 1
155 $ try _a_b_c_
155 $ try _a_b_c_
156 ('symbol', '_a_b_c_')
156 ('symbol', '_a_b_c_')
157 * set:
157 * set:
158 <baseset [6]>
158 <baseset [6]>
159 6
159 6
160 $ try _a_b_c_-a
160 $ try _a_b_c_-a
161 (minus
161 (minus
162 ('symbol', '_a_b_c_')
162 ('symbol', '_a_b_c_')
163 ('symbol', 'a'))
163 ('symbol', 'a'))
164 * set:
164 * set:
165 <filteredset
165 <filteredset
166 <baseset [6]>>
166 <baseset [6]>>
167 6
167 6
168 $ try .a.b.c.
168 $ try .a.b.c.
169 ('symbol', '.a.b.c.')
169 ('symbol', '.a.b.c.')
170 * set:
170 * set:
171 <baseset [7]>
171 <baseset [7]>
172 7
172 7
173 $ try .a.b.c.-a
173 $ try .a.b.c.-a
174 (minus
174 (minus
175 ('symbol', '.a.b.c.')
175 ('symbol', '.a.b.c.')
176 ('symbol', 'a'))
176 ('symbol', 'a'))
177 * set:
177 * set:
178 <filteredset
178 <filteredset
179 <baseset [7]>>
179 <baseset [7]>>
180 7
180 7
181 $ try -- '-a-b-c-' # complains
181 $ try -- '-a-b-c-' # complains
182 hg: parse error at 7: not a prefix: end
182 hg: parse error at 7: not a prefix: end
183 [255]
183 [255]
184 $ log -a-b-c- # succeeds with fallback
184 $ log -a-b-c- # succeeds with fallback
185 4
185 4
186
186
187 $ try -- -a-b-c--a # complains
187 $ try -- -a-b-c--a # complains
188 (minus
188 (minus
189 (minus
189 (minus
190 (minus
190 (minus
191 (negate
191 (negate
192 ('symbol', 'a'))
192 ('symbol', 'a'))
193 ('symbol', 'b'))
193 ('symbol', 'b'))
194 ('symbol', 'c'))
194 ('symbol', 'c'))
195 (negate
195 (negate
196 ('symbol', 'a')))
196 ('symbol', 'a')))
197 abort: unknown revision '-a'!
197 abort: unknown revision '-a'!
198 [255]
198 [255]
199 $ try Γ©
199 $ try Γ©
200 ('symbol', '\xc3\xa9')
200 ('symbol', '\xc3\xa9')
201 * set:
201 * set:
202 <baseset [9]>
202 <baseset [9]>
203 9
203 9
204
204
205 no quoting needed
205 no quoting needed
206
206
207 $ log ::a-b-c-
207 $ log ::a-b-c-
208 0
208 0
209 1
209 1
210 2
210 2
211
211
212 quoting needed
212 quoting needed
213
213
214 $ try '"-a-b-c-"-a'
214 $ try '"-a-b-c-"-a'
215 (minus
215 (minus
216 ('string', '-a-b-c-')
216 ('string', '-a-b-c-')
217 ('symbol', 'a'))
217 ('symbol', 'a'))
218 * set:
218 * set:
219 <filteredset
219 <filteredset
220 <baseset [4]>>
220 <baseset [4]>>
221 4
221 4
222
222
223 $ log '1 or 2'
223 $ log '1 or 2'
224 1
224 1
225 2
225 2
226 $ log '1|2'
226 $ log '1|2'
227 1
227 1
228 2
228 2
229 $ log '1 and 2'
229 $ log '1 and 2'
230 $ log '1&2'
230 $ log '1&2'
231 $ try '1&2|3' # precedence - and is higher
231 $ try '1&2|3' # precedence - and is higher
232 (or
232 (or
233 (and
233 (and
234 ('symbol', '1')
234 ('symbol', '1')
235 ('symbol', '2'))
235 ('symbol', '2'))
236 ('symbol', '3'))
236 ('symbol', '3'))
237 * set:
237 * set:
238 <addset
238 <addset
239 <baseset []>,
239 <baseset []>,
240 <baseset [3]>>
240 <baseset [3]>>
241 3
241 3
242 $ try '1|2&3'
242 $ try '1|2&3'
243 (or
243 (or
244 ('symbol', '1')
244 ('symbol', '1')
245 (and
245 (and
246 ('symbol', '2')
246 ('symbol', '2')
247 ('symbol', '3')))
247 ('symbol', '3')))
248 * set:
248 * set:
249 <addset
249 <addset
250 <baseset [1]>,
250 <baseset [1]>,
251 <baseset []>>
251 <baseset []>>
252 1
252 1
253 $ try '1&2&3' # associativity
253 $ try '1&2&3' # associativity
254 (and
254 (and
255 (and
255 (and
256 ('symbol', '1')
256 ('symbol', '1')
257 ('symbol', '2'))
257 ('symbol', '2'))
258 ('symbol', '3'))
258 ('symbol', '3'))
259 * set:
259 * set:
260 <baseset []>
260 <baseset []>
261 $ try '1|(2|3)'
261 $ try '1|(2|3)'
262 (or
262 (or
263 ('symbol', '1')
263 ('symbol', '1')
264 (group
264 (group
265 (or
265 (or
266 ('symbol', '2')
266 ('symbol', '2')
267 ('symbol', '3'))))
267 ('symbol', '3'))))
268 * set:
268 * set:
269 <addset
269 <addset
270 <baseset [1]>,
270 <baseset [1]>,
271 <baseset [2, 3]>>
271 <baseset [2, 3]>>
272 1
272 1
273 2
273 2
274 3
274 3
275 $ log '1.0' # tag
275 $ log '1.0' # tag
276 6
276 6
277 $ log 'a' # branch
277 $ log 'a' # branch
278 0
278 0
279 $ log '2785f51ee'
279 $ log '2785f51ee'
280 0
280 0
281 $ log 'date(2005)'
281 $ log 'date(2005)'
282 4
282 4
283 $ log 'date(this is a test)'
283 $ log 'date(this is a test)'
284 hg: parse error at 10: unexpected token: symbol
284 hg: parse error at 10: unexpected token: symbol
285 [255]
285 [255]
286 $ log 'date()'
286 $ log 'date()'
287 hg: parse error: date requires a string
287 hg: parse error: date requires a string
288 [255]
288 [255]
289 $ log 'date'
289 $ log 'date'
290 abort: unknown revision 'date'!
290 abort: unknown revision 'date'!
291 [255]
291 [255]
292 $ log 'date('
292 $ log 'date('
293 hg: parse error at 5: not a prefix: end
293 hg: parse error at 5: not a prefix: end
294 [255]
294 [255]
295 $ log 'date(tip)'
295 $ log 'date(tip)'
296 abort: invalid date: 'tip'
296 abort: invalid date: 'tip'
297 [255]
297 [255]
298 $ log '0:date'
298 $ log '0:date'
299 abort: unknown revision 'date'!
299 abort: unknown revision 'date'!
300 [255]
300 [255]
301 $ log '::"date"'
301 $ log '::"date"'
302 abort: unknown revision 'date'!
302 abort: unknown revision 'date'!
303 [255]
303 [255]
304 $ hg book date -r 4
304 $ hg book date -r 4
305 $ log '0:date'
305 $ log '0:date'
306 0
306 0
307 1
307 1
308 2
308 2
309 3
309 3
310 4
310 4
311 $ log '::date'
311 $ log '::date'
312 0
312 0
313 1
313 1
314 2
314 2
315 4
315 4
316 $ log '::"date"'
316 $ log '::"date"'
317 0
317 0
318 1
318 1
319 2
319 2
320 4
320 4
321 $ log 'date(2005) and 1::'
321 $ log 'date(2005) and 1::'
322 4
322 4
323 $ hg book -d date
323 $ hg book -d date
324
324
325 keyword arguments
325 keyword arguments
326
326
327 $ log 'extra(branch, value=a)'
327 $ log 'extra(branch, value=a)'
328 0
328 0
329
329
330 $ log 'extra(branch, a, b)'
330 $ log 'extra(branch, a, b)'
331 hg: parse error: extra takes at most 2 arguments
331 hg: parse error: extra takes at most 2 arguments
332 [255]
332 [255]
333 $ log 'extra(a, label=b)'
333 $ log 'extra(a, label=b)'
334 hg: parse error: extra got multiple values for keyword argument 'label'
334 hg: parse error: extra got multiple values for keyword argument 'label'
335 [255]
335 [255]
336 $ log 'extra(label=branch, default)'
336 $ log 'extra(label=branch, default)'
337 hg: parse error: extra got an invalid argument
337 hg: parse error: extra got an invalid argument
338 [255]
338 [255]
339 $ log 'extra(branch, foo+bar=baz)'
339 $ log 'extra(branch, foo+bar=baz)'
340 hg: parse error: extra got an invalid argument
340 hg: parse error: extra got an invalid argument
341 [255]
341 [255]
342 $ log 'extra(unknown=branch)'
342 $ log 'extra(unknown=branch)'
343 hg: parse error: extra got an unexpected keyword argument 'unknown'
343 hg: parse error: extra got an unexpected keyword argument 'unknown'
344 [255]
344 [255]
345
345
346 $ try 'foo=bar|baz'
346 $ try 'foo=bar|baz'
347 (keyvalue
347 (keyvalue
348 ('symbol', 'foo')
348 ('symbol', 'foo')
349 (or
349 (or
350 ('symbol', 'bar')
350 ('symbol', 'bar')
351 ('symbol', 'baz')))
351 ('symbol', 'baz')))
352 hg: parse error: can't use a key-value pair in this context
352 hg: parse error: can't use a key-value pair in this context
353 [255]
353 [255]
354
354
355 Test that symbols only get parsed as functions if there's an opening
355 Test that symbols only get parsed as functions if there's an opening
356 parenthesis.
356 parenthesis.
357
357
358 $ hg book only -r 9
358 $ hg book only -r 9
359 $ log 'only(only)' # Outer "only" is a function, inner "only" is the bookmark
359 $ log 'only(only)' # Outer "only" is a function, inner "only" is the bookmark
360 8
360 8
361 9
361 9
362
362
363 ancestor can accept 0 or more arguments
363 ancestor can accept 0 or more arguments
364
364
365 $ log 'ancestor()'
365 $ log 'ancestor()'
366 $ log 'ancestor(1)'
366 $ log 'ancestor(1)'
367 1
367 1
368 $ log 'ancestor(4,5)'
368 $ log 'ancestor(4,5)'
369 1
369 1
370 $ log 'ancestor(4,5) and 4'
370 $ log 'ancestor(4,5) and 4'
371 $ log 'ancestor(0,0,1,3)'
371 $ log 'ancestor(0,0,1,3)'
372 0
372 0
373 $ log 'ancestor(3,1,5,3,5,1)'
373 $ log 'ancestor(3,1,5,3,5,1)'
374 1
374 1
375 $ log 'ancestor(0,1,3,5)'
375 $ log 'ancestor(0,1,3,5)'
376 0
376 0
377 $ log 'ancestor(1,2,3,4,5)'
377 $ log 'ancestor(1,2,3,4,5)'
378 1
378 1
379
379
380 test ancestors
380 test ancestors
381
381
382 $ log 'ancestors(5)'
382 $ log 'ancestors(5)'
383 0
383 0
384 1
384 1
385 3
385 3
386 5
386 5
387 $ log 'ancestor(ancestors(5))'
387 $ log 'ancestor(ancestors(5))'
388 0
388 0
389 $ log '::r3232()'
389 $ log '::r3232()'
390 0
390 0
391 1
391 1
392 2
392 2
393 3
393 3
394
394
395 $ log 'author(bob)'
395 $ log 'author(bob)'
396 2
396 2
397 $ log 'author("re:bob|test")'
397 $ log 'author("re:bob|test")'
398 0
398 0
399 1
399 1
400 2
400 2
401 3
401 3
402 4
402 4
403 5
403 5
404 6
404 6
405 7
405 7
406 8
406 8
407 9
407 9
408 $ log 'branch(Γ©)'
408 $ log 'branch(Γ©)'
409 8
409 8
410 9
410 9
411 $ log 'branch(a)'
411 $ log 'branch(a)'
412 0
412 0
413 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
413 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
414 0 a
414 0 a
415 2 a-b-c-
415 2 a-b-c-
416 3 +a+b+c+
416 3 +a+b+c+
417 4 -a-b-c-
417 4 -a-b-c-
418 5 !a/b/c/
418 5 !a/b/c/
419 6 _a_b_c_
419 6 _a_b_c_
420 7 .a.b.c.
420 7 .a.b.c.
421 $ log 'children(ancestor(4,5))'
421 $ log 'children(ancestor(4,5))'
422 2
422 2
423 3
423 3
424 $ log 'closed()'
424 $ log 'closed()'
425 $ log 'contains(a)'
425 $ log 'contains(a)'
426 0
426 0
427 1
427 1
428 3
428 3
429 5
429 5
430 $ log 'contains("../repo/a")'
430 $ log 'contains("../repo/a")'
431 0
431 0
432 1
432 1
433 3
433 3
434 5
434 5
435 $ log 'desc(B)'
435 $ log 'desc(B)'
436 5
436 5
437 $ log 'descendants(2 or 3)'
437 $ log 'descendants(2 or 3)'
438 2
438 2
439 3
439 3
440 4
440 4
441 5
441 5
442 6
442 6
443 7
443 7
444 8
444 8
445 9
445 9
446 $ log 'file("b*")'
446 $ log 'file("b*")'
447 1
447 1
448 4
448 4
449 $ log 'filelog("b")'
449 $ log 'filelog("b")'
450 1
450 1
451 4
451 4
452 $ log 'filelog("../repo/b")'
452 $ log 'filelog("../repo/b")'
453 1
453 1
454 4
454 4
455 $ log 'follow()'
455 $ log 'follow()'
456 0
456 0
457 1
457 1
458 2
458 2
459 4
459 4
460 8
460 8
461 9
461 9
462 $ log 'grep("issue\d+")'
462 $ log 'grep("issue\d+")'
463 6
463 6
464 $ try 'grep("(")' # invalid regular expression
464 $ try 'grep("(")' # invalid regular expression
465 (func
465 (func
466 ('symbol', 'grep')
466 ('symbol', 'grep')
467 ('string', '('))
467 ('string', '('))
468 hg: parse error: invalid match pattern: unbalanced parenthesis
468 hg: parse error: invalid match pattern: unbalanced parenthesis
469 [255]
469 [255]
470 $ try 'grep("\bissue\d+")'
470 $ try 'grep("\bissue\d+")'
471 (func
471 (func
472 ('symbol', 'grep')
472 ('symbol', 'grep')
473 ('string', '\x08issue\\d+'))
473 ('string', '\x08issue\\d+'))
474 * set:
474 * set:
475 <filteredset
475 <filteredset
476 <fullreposet+ 0:9>>
476 <fullreposet+ 0:9>>
477 $ try 'grep(r"\bissue\d+")'
477 $ try 'grep(r"\bissue\d+")'
478 (func
478 (func
479 ('symbol', 'grep')
479 ('symbol', 'grep')
480 ('string', '\\bissue\\d+'))
480 ('string', '\\bissue\\d+'))
481 * set:
481 * set:
482 <filteredset
482 <filteredset
483 <fullreposet+ 0:9>>
483 <fullreposet+ 0:9>>
484 6
484 6
485 $ try 'grep(r"\")'
485 $ try 'grep(r"\")'
486 hg: parse error at 7: unterminated string
486 hg: parse error at 7: unterminated string
487 [255]
487 [255]
488 $ log 'head()'
488 $ log 'head()'
489 0
489 0
490 1
490 1
491 2
491 2
492 3
492 3
493 4
493 4
494 5
494 5
495 6
495 6
496 7
496 7
497 9
497 9
498 $ log 'heads(6::)'
498 $ log 'heads(6::)'
499 7
499 7
500 $ log 'keyword(issue)'
500 $ log 'keyword(issue)'
501 6
501 6
502 $ log 'keyword("test a")'
502 $ log 'keyword("test a")'
503 $ log 'limit(head(), 1)'
503 $ log 'limit(head(), 1)'
504 0
504 0
505 $ log 'matching(6)'
505 $ log 'matching(6)'
506 6
506 6
507 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
507 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
508 6
508 6
509 7
509 7
510
510
511 Testing min and max
511 Testing min and max
512
512
513 max: simple
513 max: simple
514
514
515 $ log 'max(contains(a))'
515 $ log 'max(contains(a))'
516 5
516 5
517
517
518 max: simple on unordered set)
518 max: simple on unordered set)
519
519
520 $ log 'max((4+0+2+5+7) and contains(a))'
520 $ log 'max((4+0+2+5+7) and contains(a))'
521 5
521 5
522
522
523 max: no result
523 max: no result
524
524
525 $ log 'max(contains(stringthatdoesnotappearanywhere))'
525 $ log 'max(contains(stringthatdoesnotappearanywhere))'
526
526
527 max: no result on unordered set
527 max: no result on unordered set
528
528
529 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
529 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
530
530
531 min: simple
531 min: simple
532
532
533 $ log 'min(contains(a))'
533 $ log 'min(contains(a))'
534 0
534 0
535
535
536 min: simple on unordered set
536 min: simple on unordered set
537
537
538 $ log 'min((4+0+2+5+7) and contains(a))'
538 $ log 'min((4+0+2+5+7) and contains(a))'
539 0
539 0
540
540
541 min: empty
541 min: empty
542
542
543 $ log 'min(contains(stringthatdoesnotappearanywhere))'
543 $ log 'min(contains(stringthatdoesnotappearanywhere))'
544
544
545 min: empty on unordered set
545 min: empty on unordered set
546
546
547 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
547 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
548
548
549
549
550 $ log 'merge()'
550 $ log 'merge()'
551 6
551 6
552 $ log 'branchpoint()'
552 $ log 'branchpoint()'
553 1
553 1
554 4
554 4
555 $ log 'modifies(b)'
555 $ log 'modifies(b)'
556 4
556 4
557 $ log 'modifies("path:b")'
557 $ log 'modifies("path:b")'
558 4
558 4
559 $ log 'modifies("*")'
559 $ log 'modifies("*")'
560 4
560 4
561 6
561 6
562 $ log 'modifies("set:modified()")'
562 $ log 'modifies("set:modified()")'
563 4
563 4
564 $ log 'id(5)'
564 $ log 'id(5)'
565 2
565 2
566 $ log 'only(9)'
566 $ log 'only(9)'
567 8
567 8
568 9
568 9
569 $ log 'only(8)'
569 $ log 'only(8)'
570 8
570 8
571 $ log 'only(9, 5)'
571 $ log 'only(9, 5)'
572 2
572 2
573 4
573 4
574 8
574 8
575 9
575 9
576 $ log 'only(7 + 9, 5 + 2)'
576 $ log 'only(7 + 9, 5 + 2)'
577 4
577 4
578 6
578 6
579 7
579 7
580 8
580 8
581 9
581 9
582
582
583 Test empty set input
583 Test empty set input
584 $ log 'only(p2())'
584 $ log 'only(p2())'
585 $ log 'only(p1(), p2())'
585 $ log 'only(p1(), p2())'
586 0
586 0
587 1
587 1
588 2
588 2
589 4
589 4
590 8
590 8
591 9
591 9
592
592
593 Test '%' operator
593 Test '%' operator
594
594
595 $ log '9%'
595 $ log '9%'
596 8
596 8
597 9
597 9
598 $ log '9%5'
598 $ log '9%5'
599 2
599 2
600 4
600 4
601 8
601 8
602 9
602 9
603 $ log '(7 + 9)%(5 + 2)'
603 $ log '(7 + 9)%(5 + 2)'
604 4
604 4
605 6
605 6
606 7
606 7
607 8
607 8
608 9
608 9
609
609
610 Test opreand of '%' is optimized recursively (issue4670)
610 Test opreand of '%' is optimized recursively (issue4670)
611
611
612 $ try --optimize '8:9-8%'
612 $ try --optimize '8:9-8%'
613 (onlypost
613 (onlypost
614 (minus
614 (minus
615 (range
615 (range
616 ('symbol', '8')
616 ('symbol', '8')
617 ('symbol', '9'))
617 ('symbol', '9'))
618 ('symbol', '8')))
618 ('symbol', '8')))
619 * optimized:
619 * optimized:
620 (func
620 (func
621 ('symbol', 'only')
621 ('symbol', 'only')
622 (and
622 (and
623 (range
623 (range
624 ('symbol', '8')
624 ('symbol', '8')
625 ('symbol', '9'))
625 ('symbol', '9'))
626 (not
626 (not
627 ('symbol', '8'))))
627 ('symbol', '8'))))
628 * set:
628 * set:
629 <baseset+ [8, 9]>
629 <baseset+ [8, 9]>
630 8
630 8
631 9
631 9
632 $ try --optimize '(9)%(5)'
632 $ try --optimize '(9)%(5)'
633 (only
633 (only
634 (group
634 (group
635 ('symbol', '9'))
635 ('symbol', '9'))
636 (group
636 (group
637 ('symbol', '5')))
637 ('symbol', '5')))
638 * optimized:
638 * optimized:
639 (func
639 (func
640 ('symbol', 'only')
640 ('symbol', 'only')
641 (list
641 (list
642 ('symbol', '9')
642 ('symbol', '9')
643 ('symbol', '5')))
643 ('symbol', '5')))
644 * set:
644 * set:
645 <baseset+ [8, 9, 2, 4]>
645 <baseset+ [8, 9, 2, 4]>
646 2
646 2
647 4
647 4
648 8
648 8
649 9
649 9
650
650
651 Test the order of operations
651 Test the order of operations
652
652
653 $ log '7 + 9%5 + 2'
653 $ log '7 + 9%5 + 2'
654 7
654 7
655 2
655 2
656 4
656 4
657 8
657 8
658 9
658 9
659
659
660 Test explicit numeric revision
660 Test explicit numeric revision
661 $ log 'rev(-2)'
661 $ log 'rev(-2)'
662 $ log 'rev(-1)'
662 $ log 'rev(-1)'
663 -1
663 -1
664 $ log 'rev(0)'
664 $ log 'rev(0)'
665 0
665 0
666 $ log 'rev(9)'
666 $ log 'rev(9)'
667 9
667 9
668 $ log 'rev(10)'
668 $ log 'rev(10)'
669 $ log 'rev(tip)'
669 $ log 'rev(tip)'
670 hg: parse error: rev expects a number
670 hg: parse error: rev expects a number
671 [255]
671 [255]
672
672
673 Test hexadecimal revision
673 Test hexadecimal revision
674 $ log 'id(2)'
674 $ log 'id(2)'
675 abort: 00changelog.i@2: ambiguous identifier!
675 abort: 00changelog.i@2: ambiguous identifier!
676 [255]
676 [255]
677 $ log 'id(23268)'
677 $ log 'id(23268)'
678 4
678 4
679 $ log 'id(2785f51eece)'
679 $ log 'id(2785f51eece)'
680 0
680 0
681 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532c)'
681 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532c)'
682 8
682 8
683 $ log 'id(d5d0dcbdc4a)'
683 $ log 'id(d5d0dcbdc4a)'
684 $ log 'id(d5d0dcbdc4w)'
684 $ log 'id(d5d0dcbdc4w)'
685 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532d)'
685 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532d)'
686 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532q)'
686 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532q)'
687 $ log 'id(1.0)'
687 $ log 'id(1.0)'
688 $ log 'id(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)'
688 $ log 'id(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)'
689
689
690 Test null revision
690 Test null revision
691 $ log '(null)'
691 $ log '(null)'
692 -1
692 -1
693 $ log '(null:0)'
693 $ log '(null:0)'
694 -1
694 -1
695 0
695 0
696 $ log '(0:null)'
696 $ log '(0:null)'
697 0
697 0
698 -1
698 -1
699 $ log 'null::0'
699 $ log 'null::0'
700 -1
700 -1
701 0
701 0
702 $ log 'null:tip - 0:'
702 $ log 'null:tip - 0:'
703 -1
703 -1
704 $ log 'null: and null::' | head -1
704 $ log 'null: and null::' | head -1
705 -1
705 -1
706 $ log 'null: or 0:' | head -2
706 $ log 'null: or 0:' | head -2
707 -1
707 -1
708 0
708 0
709 $ log 'ancestors(null)'
709 $ log 'ancestors(null)'
710 -1
710 -1
711 $ log 'reverse(null:)' | tail -2
711 $ log 'reverse(null:)' | tail -2
712 0
712 0
713 -1
713 -1
714 BROKEN: should be '-1'
714 BROKEN: should be '-1'
715 $ log 'first(null:)'
715 $ log 'first(null:)'
716 BROKEN: should be '-1'
716 BROKEN: should be '-1'
717 $ log 'min(null:)'
717 $ log 'min(null:)'
718 $ log 'tip:null and all()' | tail -2
718 $ log 'tip:null and all()' | tail -2
719 1
719 1
720 0
720 0
721
721
722 Test working-directory revision
722 Test working-directory revision
723 $ hg debugrevspec 'wdir()'
723 $ hg debugrevspec 'wdir()'
724 None
724 2147483647
725 $ hg debugrevspec 'tip or wdir()'
725 $ hg debugrevspec 'tip or wdir()'
726 9
726 9
727 None
727 2147483647
728 $ hg debugrevspec '0:tip and wdir()'
728 $ hg debugrevspec '0:tip and wdir()'
729 $ log '(all() + wdir()) & min(. + wdir())'
730 9
731 $ log '(all() + wdir()) & max(. + wdir())'
732 2147483647
733 $ log '(all() + wdir()) & first(wdir() + .)'
734 2147483647
735 $ log '(all() + wdir()) & last(. + wdir())'
736 2147483647
729
737
730 $ log 'outgoing()'
738 $ log 'outgoing()'
731 8
739 8
732 9
740 9
733 $ log 'outgoing("../remote1")'
741 $ log 'outgoing("../remote1")'
734 8
742 8
735 9
743 9
736 $ log 'outgoing("../remote2")'
744 $ log 'outgoing("../remote2")'
737 3
745 3
738 5
746 5
739 6
747 6
740 7
748 7
741 9
749 9
742 $ log 'p1(merge())'
750 $ log 'p1(merge())'
743 5
751 5
744 $ log 'p2(merge())'
752 $ log 'p2(merge())'
745 4
753 4
746 $ log 'parents(merge())'
754 $ log 'parents(merge())'
747 4
755 4
748 5
756 5
749 $ log 'p1(branchpoint())'
757 $ log 'p1(branchpoint())'
750 0
758 0
751 2
759 2
752 $ log 'p2(branchpoint())'
760 $ log 'p2(branchpoint())'
753 $ log 'parents(branchpoint())'
761 $ log 'parents(branchpoint())'
754 0
762 0
755 2
763 2
756 $ log 'removes(a)'
764 $ log 'removes(a)'
757 2
765 2
758 6
766 6
759 $ log 'roots(all())'
767 $ log 'roots(all())'
760 0
768 0
761 $ log 'reverse(2 or 3 or 4 or 5)'
769 $ log 'reverse(2 or 3 or 4 or 5)'
762 5
770 5
763 4
771 4
764 3
772 3
765 2
773 2
766 $ log 'reverse(all())'
774 $ log 'reverse(all())'
767 9
775 9
768 8
776 8
769 7
777 7
770 6
778 6
771 5
779 5
772 4
780 4
773 3
781 3
774 2
782 2
775 1
783 1
776 0
784 0
777 $ log 'reverse(all()) & filelog(b)'
785 $ log 'reverse(all()) & filelog(b)'
778 4
786 4
779 1
787 1
780 $ log 'rev(5)'
788 $ log 'rev(5)'
781 5
789 5
782 $ log 'sort(limit(reverse(all()), 3))'
790 $ log 'sort(limit(reverse(all()), 3))'
783 7
791 7
784 8
792 8
785 9
793 9
786 $ log 'sort(2 or 3 or 4 or 5, date)'
794 $ log 'sort(2 or 3 or 4 or 5, date)'
787 2
795 2
788 3
796 3
789 5
797 5
790 4
798 4
791 $ log 'tagged()'
799 $ log 'tagged()'
792 6
800 6
793 $ log 'tag()'
801 $ log 'tag()'
794 6
802 6
795 $ log 'tag(1.0)'
803 $ log 'tag(1.0)'
796 6
804 6
797 $ log 'tag(tip)'
805 $ log 'tag(tip)'
798 9
806 9
799
807
800 test sort revset
808 test sort revset
801 --------------------------------------------
809 --------------------------------------------
802
810
803 test when adding two unordered revsets
811 test when adding two unordered revsets
804
812
805 $ log 'sort(keyword(issue) or modifies(b))'
813 $ log 'sort(keyword(issue) or modifies(b))'
806 4
814 4
807 6
815 6
808
816
809 test when sorting a reversed collection in the same way it is
817 test when sorting a reversed collection in the same way it is
810
818
811 $ log 'sort(reverse(all()), -rev)'
819 $ log 'sort(reverse(all()), -rev)'
812 9
820 9
813 8
821 8
814 7
822 7
815 6
823 6
816 5
824 5
817 4
825 4
818 3
826 3
819 2
827 2
820 1
828 1
821 0
829 0
822
830
823 test when sorting a reversed collection
831 test when sorting a reversed collection
824
832
825 $ log 'sort(reverse(all()), rev)'
833 $ log 'sort(reverse(all()), rev)'
826 0
834 0
827 1
835 1
828 2
836 2
829 3
837 3
830 4
838 4
831 5
839 5
832 6
840 6
833 7
841 7
834 8
842 8
835 9
843 9
836
844
837
845
838 test sorting two sorted collections in different orders
846 test sorting two sorted collections in different orders
839
847
840 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
848 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
841 2
849 2
842 6
850 6
843 8
851 8
844 9
852 9
845
853
846 test sorting two sorted collections in different orders backwards
854 test sorting two sorted collections in different orders backwards
847
855
848 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
856 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
849 9
857 9
850 8
858 8
851 6
859 6
852 2
860 2
853
861
854 test subtracting something from an addset
862 test subtracting something from an addset
855
863
856 $ log '(outgoing() or removes(a)) - removes(a)'
864 $ log '(outgoing() or removes(a)) - removes(a)'
857 8
865 8
858 9
866 9
859
867
860 test intersecting something with an addset
868 test intersecting something with an addset
861
869
862 $ log 'parents(outgoing() or removes(a))'
870 $ log 'parents(outgoing() or removes(a))'
863 1
871 1
864 4
872 4
865 5
873 5
866 8
874 8
867
875
868 test that `or` operation combines elements in the right order:
876 test that `or` operation combines elements in the right order:
869
877
870 $ log '3:4 or 2:5'
878 $ log '3:4 or 2:5'
871 3
879 3
872 4
880 4
873 2
881 2
874 5
882 5
875 $ log '3:4 or 5:2'
883 $ log '3:4 or 5:2'
876 3
884 3
877 4
885 4
878 5
886 5
879 2
887 2
880 $ log 'sort(3:4 or 2:5)'
888 $ log 'sort(3:4 or 2:5)'
881 2
889 2
882 3
890 3
883 4
891 4
884 5
892 5
885 $ log 'sort(3:4 or 5:2)'
893 $ log 'sort(3:4 or 5:2)'
886 2
894 2
887 3
895 3
888 4
896 4
889 5
897 5
890
898
891 test that more than one `-r`s are combined in the right order and deduplicated:
899 test that more than one `-r`s are combined in the right order and deduplicated:
892
900
893 $ hg log -T '{rev}\n' -r 3 -r 3 -r 4 -r 5:2 -r 'ancestors(4)'
901 $ hg log -T '{rev}\n' -r 3 -r 3 -r 4 -r 5:2 -r 'ancestors(4)'
894 3
902 3
895 4
903 4
896 5
904 5
897 2
905 2
898 0
906 0
899 1
907 1
900
908
901 test that `or` operation skips duplicated revisions from right-hand side
909 test that `or` operation skips duplicated revisions from right-hand side
902
910
903 $ try 'reverse(1::5) or ancestors(4)'
911 $ try 'reverse(1::5) or ancestors(4)'
904 (or
912 (or
905 (func
913 (func
906 ('symbol', 'reverse')
914 ('symbol', 'reverse')
907 (dagrange
915 (dagrange
908 ('symbol', '1')
916 ('symbol', '1')
909 ('symbol', '5')))
917 ('symbol', '5')))
910 (func
918 (func
911 ('symbol', 'ancestors')
919 ('symbol', 'ancestors')
912 ('symbol', '4')))
920 ('symbol', '4')))
913 * set:
921 * set:
914 <addset
922 <addset
915 <baseset [5, 3, 1]>,
923 <baseset [5, 3, 1]>,
916 <generatorset+>>
924 <generatorset+>>
917 5
925 5
918 3
926 3
919 1
927 1
920 0
928 0
921 2
929 2
922 4
930 4
923 $ try 'sort(ancestors(4) or reverse(1::5))'
931 $ try 'sort(ancestors(4) or reverse(1::5))'
924 (func
932 (func
925 ('symbol', 'sort')
933 ('symbol', 'sort')
926 (or
934 (or
927 (func
935 (func
928 ('symbol', 'ancestors')
936 ('symbol', 'ancestors')
929 ('symbol', '4'))
937 ('symbol', '4'))
930 (func
938 (func
931 ('symbol', 'reverse')
939 ('symbol', 'reverse')
932 (dagrange
940 (dagrange
933 ('symbol', '1')
941 ('symbol', '1')
934 ('symbol', '5')))))
942 ('symbol', '5')))))
935 * set:
943 * set:
936 <addset+
944 <addset+
937 <generatorset+>,
945 <generatorset+>,
938 <baseset [5, 3, 1]>>
946 <baseset [5, 3, 1]>>
939 0
947 0
940 1
948 1
941 2
949 2
942 3
950 3
943 4
951 4
944 5
952 5
945
953
946 test optimization of trivial `or` operation
954 test optimization of trivial `or` operation
947
955
948 $ try --optimize '0|(1)|"2"|-2|tip|null'
956 $ try --optimize '0|(1)|"2"|-2|tip|null'
949 (or
957 (or
950 ('symbol', '0')
958 ('symbol', '0')
951 (group
959 (group
952 ('symbol', '1'))
960 ('symbol', '1'))
953 ('string', '2')
961 ('string', '2')
954 (negate
962 (negate
955 ('symbol', '2'))
963 ('symbol', '2'))
956 ('symbol', 'tip')
964 ('symbol', 'tip')
957 ('symbol', 'null'))
965 ('symbol', 'null'))
958 * optimized:
966 * optimized:
959 (func
967 (func
960 ('symbol', '_list')
968 ('symbol', '_list')
961 ('string', '0\x001\x002\x00-2\x00tip\x00null'))
969 ('string', '0\x001\x002\x00-2\x00tip\x00null'))
962 * set:
970 * set:
963 <baseset [0, 1, 2, 8, 9, -1]>
971 <baseset [0, 1, 2, 8, 9, -1]>
964 0
972 0
965 1
973 1
966 2
974 2
967 8
975 8
968 9
976 9
969 -1
977 -1
970
978
971 $ try --optimize '0|1|2:3'
979 $ try --optimize '0|1|2:3'
972 (or
980 (or
973 ('symbol', '0')
981 ('symbol', '0')
974 ('symbol', '1')
982 ('symbol', '1')
975 (range
983 (range
976 ('symbol', '2')
984 ('symbol', '2')
977 ('symbol', '3')))
985 ('symbol', '3')))
978 * optimized:
986 * optimized:
979 (or
987 (or
980 (func
988 (func
981 ('symbol', '_list')
989 ('symbol', '_list')
982 ('string', '0\x001'))
990 ('string', '0\x001'))
983 (range
991 (range
984 ('symbol', '2')
992 ('symbol', '2')
985 ('symbol', '3')))
993 ('symbol', '3')))
986 * set:
994 * set:
987 <addset
995 <addset
988 <baseset [0, 1]>,
996 <baseset [0, 1]>,
989 <spanset+ 2:3>>
997 <spanset+ 2:3>>
990 0
998 0
991 1
999 1
992 2
1000 2
993 3
1001 3
994
1002
995 $ try --optimize '0:1|2|3:4|5|6'
1003 $ try --optimize '0:1|2|3:4|5|6'
996 (or
1004 (or
997 (range
1005 (range
998 ('symbol', '0')
1006 ('symbol', '0')
999 ('symbol', '1'))
1007 ('symbol', '1'))
1000 ('symbol', '2')
1008 ('symbol', '2')
1001 (range
1009 (range
1002 ('symbol', '3')
1010 ('symbol', '3')
1003 ('symbol', '4'))
1011 ('symbol', '4'))
1004 ('symbol', '5')
1012 ('symbol', '5')
1005 ('symbol', '6'))
1013 ('symbol', '6'))
1006 * optimized:
1014 * optimized:
1007 (or
1015 (or
1008 (range
1016 (range
1009 ('symbol', '0')
1017 ('symbol', '0')
1010 ('symbol', '1'))
1018 ('symbol', '1'))
1011 ('symbol', '2')
1019 ('symbol', '2')
1012 (range
1020 (range
1013 ('symbol', '3')
1021 ('symbol', '3')
1014 ('symbol', '4'))
1022 ('symbol', '4'))
1015 (func
1023 (func
1016 ('symbol', '_list')
1024 ('symbol', '_list')
1017 ('string', '5\x006')))
1025 ('string', '5\x006')))
1018 * set:
1026 * set:
1019 <addset
1027 <addset
1020 <addset
1028 <addset
1021 <spanset+ 0:1>,
1029 <spanset+ 0:1>,
1022 <baseset [2]>>,
1030 <baseset [2]>>,
1023 <addset
1031 <addset
1024 <spanset+ 3:4>,
1032 <spanset+ 3:4>,
1025 <baseset [5, 6]>>>
1033 <baseset [5, 6]>>>
1026 0
1034 0
1027 1
1035 1
1028 2
1036 2
1029 3
1037 3
1030 4
1038 4
1031 5
1039 5
1032 6
1040 6
1033
1041
1034 test that `_list` should be narrowed by provided `subset`
1042 test that `_list` should be narrowed by provided `subset`
1035
1043
1036 $ log '0:2 and (null|1|2|3)'
1044 $ log '0:2 and (null|1|2|3)'
1037 1
1045 1
1038 2
1046 2
1039
1047
1040 test that `_list` should remove duplicates
1048 test that `_list` should remove duplicates
1041
1049
1042 $ log '0|1|2|1|2|-1|tip'
1050 $ log '0|1|2|1|2|-1|tip'
1043 0
1051 0
1044 1
1052 1
1045 2
1053 2
1046 9
1054 9
1047
1055
1048 test unknown revision in `_list`
1056 test unknown revision in `_list`
1049
1057
1050 $ log '0|unknown'
1058 $ log '0|unknown'
1051 abort: unknown revision 'unknown'!
1059 abort: unknown revision 'unknown'!
1052 [255]
1060 [255]
1053
1061
1054 test integer range in `_list`
1062 test integer range in `_list`
1055
1063
1056 $ log '-1|-10'
1064 $ log '-1|-10'
1057 9
1065 9
1058 0
1066 0
1059
1067
1060 $ log '-10|-11'
1068 $ log '-10|-11'
1061 abort: unknown revision '-11'!
1069 abort: unknown revision '-11'!
1062 [255]
1070 [255]
1063
1071
1064 $ log '9|10'
1072 $ log '9|10'
1065 abort: unknown revision '10'!
1073 abort: unknown revision '10'!
1066 [255]
1074 [255]
1067
1075
1068 test '0000' != '0' in `_list`
1076 test '0000' != '0' in `_list`
1069
1077
1070 $ log '0|0000'
1078 $ log '0|0000'
1071 0
1079 0
1072 -1
1080 -1
1073
1081
1074 test that chained `or` operations make balanced addsets
1082 test that chained `or` operations make balanced addsets
1075
1083
1076 $ try '0:1|1:2|2:3|3:4|4:5'
1084 $ try '0:1|1:2|2:3|3:4|4:5'
1077 (or
1085 (or
1078 (range
1086 (range
1079 ('symbol', '0')
1087 ('symbol', '0')
1080 ('symbol', '1'))
1088 ('symbol', '1'))
1081 (range
1089 (range
1082 ('symbol', '1')
1090 ('symbol', '1')
1083 ('symbol', '2'))
1091 ('symbol', '2'))
1084 (range
1092 (range
1085 ('symbol', '2')
1093 ('symbol', '2')
1086 ('symbol', '3'))
1094 ('symbol', '3'))
1087 (range
1095 (range
1088 ('symbol', '3')
1096 ('symbol', '3')
1089 ('symbol', '4'))
1097 ('symbol', '4'))
1090 (range
1098 (range
1091 ('symbol', '4')
1099 ('symbol', '4')
1092 ('symbol', '5')))
1100 ('symbol', '5')))
1093 * set:
1101 * set:
1094 <addset
1102 <addset
1095 <addset
1103 <addset
1096 <spanset+ 0:1>,
1104 <spanset+ 0:1>,
1097 <spanset+ 1:2>>,
1105 <spanset+ 1:2>>,
1098 <addset
1106 <addset
1099 <spanset+ 2:3>,
1107 <spanset+ 2:3>,
1100 <addset
1108 <addset
1101 <spanset+ 3:4>,
1109 <spanset+ 3:4>,
1102 <spanset+ 4:5>>>>
1110 <spanset+ 4:5>>>>
1103 0
1111 0
1104 1
1112 1
1105 2
1113 2
1106 3
1114 3
1107 4
1115 4
1108 5
1116 5
1109
1117
1110 test that chained `or` operations never eat up stack (issue4624)
1118 test that chained `or` operations never eat up stack (issue4624)
1111 (uses `0:1` instead of `0` to avoid future optimization of trivial revisions)
1119 (uses `0:1` instead of `0` to avoid future optimization of trivial revisions)
1112
1120
1113 $ hg log -T '{rev}\n' -r "`python -c "print '|'.join(['0:1'] * 500)"`"
1121 $ hg log -T '{rev}\n' -r "`python -c "print '|'.join(['0:1'] * 500)"`"
1114 0
1122 0
1115 1
1123 1
1116
1124
1117 test that repeated `-r` options never eat up stack (issue4565)
1125 test that repeated `-r` options never eat up stack (issue4565)
1118 (uses `-r 0::1` to avoid possible optimization at old-style parser)
1126 (uses `-r 0::1` to avoid possible optimization at old-style parser)
1119
1127
1120 $ hg log -T '{rev}\n' `python -c "for i in xrange(500): print '-r 0::1 ',"`
1128 $ hg log -T '{rev}\n' `python -c "for i in xrange(500): print '-r 0::1 ',"`
1121 0
1129 0
1122 1
1130 1
1123
1131
1124 check that conversion to only works
1132 check that conversion to only works
1125 $ try --optimize '::3 - ::1'
1133 $ try --optimize '::3 - ::1'
1126 (minus
1134 (minus
1127 (dagrangepre
1135 (dagrangepre
1128 ('symbol', '3'))
1136 ('symbol', '3'))
1129 (dagrangepre
1137 (dagrangepre
1130 ('symbol', '1')))
1138 ('symbol', '1')))
1131 * optimized:
1139 * optimized:
1132 (func
1140 (func
1133 ('symbol', 'only')
1141 ('symbol', 'only')
1134 (list
1142 (list
1135 ('symbol', '3')
1143 ('symbol', '3')
1136 ('symbol', '1')))
1144 ('symbol', '1')))
1137 * set:
1145 * set:
1138 <baseset+ [3]>
1146 <baseset+ [3]>
1139 3
1147 3
1140 $ try --optimize 'ancestors(1) - ancestors(3)'
1148 $ try --optimize 'ancestors(1) - ancestors(3)'
1141 (minus
1149 (minus
1142 (func
1150 (func
1143 ('symbol', 'ancestors')
1151 ('symbol', 'ancestors')
1144 ('symbol', '1'))
1152 ('symbol', '1'))
1145 (func
1153 (func
1146 ('symbol', 'ancestors')
1154 ('symbol', 'ancestors')
1147 ('symbol', '3')))
1155 ('symbol', '3')))
1148 * optimized:
1156 * optimized:
1149 (func
1157 (func
1150 ('symbol', 'only')
1158 ('symbol', 'only')
1151 (list
1159 (list
1152 ('symbol', '1')
1160 ('symbol', '1')
1153 ('symbol', '3')))
1161 ('symbol', '3')))
1154 * set:
1162 * set:
1155 <baseset+ []>
1163 <baseset+ []>
1156 $ try --optimize 'not ::2 and ::6'
1164 $ try --optimize 'not ::2 and ::6'
1157 (and
1165 (and
1158 (not
1166 (not
1159 (dagrangepre
1167 (dagrangepre
1160 ('symbol', '2')))
1168 ('symbol', '2')))
1161 (dagrangepre
1169 (dagrangepre
1162 ('symbol', '6')))
1170 ('symbol', '6')))
1163 * optimized:
1171 * optimized:
1164 (func
1172 (func
1165 ('symbol', 'only')
1173 ('symbol', 'only')
1166 (list
1174 (list
1167 ('symbol', '6')
1175 ('symbol', '6')
1168 ('symbol', '2')))
1176 ('symbol', '2')))
1169 * set:
1177 * set:
1170 <baseset+ [3, 4, 5, 6]>
1178 <baseset+ [3, 4, 5, 6]>
1171 3
1179 3
1172 4
1180 4
1173 5
1181 5
1174 6
1182 6
1175 $ try --optimize 'ancestors(6) and not ancestors(4)'
1183 $ try --optimize 'ancestors(6) and not ancestors(4)'
1176 (and
1184 (and
1177 (func
1185 (func
1178 ('symbol', 'ancestors')
1186 ('symbol', 'ancestors')
1179 ('symbol', '6'))
1187 ('symbol', '6'))
1180 (not
1188 (not
1181 (func
1189 (func
1182 ('symbol', 'ancestors')
1190 ('symbol', 'ancestors')
1183 ('symbol', '4'))))
1191 ('symbol', '4'))))
1184 * optimized:
1192 * optimized:
1185 (func
1193 (func
1186 ('symbol', 'only')
1194 ('symbol', 'only')
1187 (list
1195 (list
1188 ('symbol', '6')
1196 ('symbol', '6')
1189 ('symbol', '4')))
1197 ('symbol', '4')))
1190 * set:
1198 * set:
1191 <baseset+ [3, 5, 6]>
1199 <baseset+ [3, 5, 6]>
1192 3
1200 3
1193 5
1201 5
1194 6
1202 6
1195
1203
1196 we can use patterns when searching for tags
1204 we can use patterns when searching for tags
1197
1205
1198 $ log 'tag("1..*")'
1206 $ log 'tag("1..*")'
1199 abort: tag '1..*' does not exist!
1207 abort: tag '1..*' does not exist!
1200 [255]
1208 [255]
1201 $ log 'tag("re:1..*")'
1209 $ log 'tag("re:1..*")'
1202 6
1210 6
1203 $ log 'tag("re:[0-9].[0-9]")'
1211 $ log 'tag("re:[0-9].[0-9]")'
1204 6
1212 6
1205 $ log 'tag("literal:1.0")'
1213 $ log 'tag("literal:1.0")'
1206 6
1214 6
1207 $ log 'tag("re:0..*")'
1215 $ log 'tag("re:0..*")'
1208
1216
1209 $ log 'tag(unknown)'
1217 $ log 'tag(unknown)'
1210 abort: tag 'unknown' does not exist!
1218 abort: tag 'unknown' does not exist!
1211 [255]
1219 [255]
1212 $ log 'tag("re:unknown")'
1220 $ log 'tag("re:unknown")'
1213 $ log 'present(tag("unknown"))'
1221 $ log 'present(tag("unknown"))'
1214 $ log 'present(tag("re:unknown"))'
1222 $ log 'present(tag("re:unknown"))'
1215 $ log 'branch(unknown)'
1223 $ log 'branch(unknown)'
1216 abort: unknown revision 'unknown'!
1224 abort: unknown revision 'unknown'!
1217 [255]
1225 [255]
1218 $ log 'branch("re:unknown")'
1226 $ log 'branch("re:unknown")'
1219 $ log 'present(branch("unknown"))'
1227 $ log 'present(branch("unknown"))'
1220 $ log 'present(branch("re:unknown"))'
1228 $ log 'present(branch("re:unknown"))'
1221 $ log 'user(bob)'
1229 $ log 'user(bob)'
1222 2
1230 2
1223
1231
1224 $ log '4::8'
1232 $ log '4::8'
1225 4
1233 4
1226 8
1234 8
1227 $ log '4:8'
1235 $ log '4:8'
1228 4
1236 4
1229 5
1237 5
1230 6
1238 6
1231 7
1239 7
1232 8
1240 8
1233
1241
1234 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
1242 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
1235 4
1243 4
1236 2
1244 2
1237 5
1245 5
1238
1246
1239 $ log 'not 0 and 0:2'
1247 $ log 'not 0 and 0:2'
1240 1
1248 1
1241 2
1249 2
1242 $ log 'not 1 and 0:2'
1250 $ log 'not 1 and 0:2'
1243 0
1251 0
1244 2
1252 2
1245 $ log 'not 2 and 0:2'
1253 $ log 'not 2 and 0:2'
1246 0
1254 0
1247 1
1255 1
1248 $ log '(1 and 2)::'
1256 $ log '(1 and 2)::'
1249 $ log '(1 and 2):'
1257 $ log '(1 and 2):'
1250 $ log '(1 and 2):3'
1258 $ log '(1 and 2):3'
1251 $ log 'sort(head(), -rev)'
1259 $ log 'sort(head(), -rev)'
1252 9
1260 9
1253 7
1261 7
1254 6
1262 6
1255 5
1263 5
1256 4
1264 4
1257 3
1265 3
1258 2
1266 2
1259 1
1267 1
1260 0
1268 0
1261 $ log '4::8 - 8'
1269 $ log '4::8 - 8'
1262 4
1270 4
1263 $ log 'matching(1 or 2 or 3) and (2 or 3 or 1)'
1271 $ log 'matching(1 or 2 or 3) and (2 or 3 or 1)'
1264 2
1272 2
1265 3
1273 3
1266 1
1274 1
1267
1275
1268 $ log 'named("unknown")'
1276 $ log 'named("unknown")'
1269 abort: namespace 'unknown' does not exist!
1277 abort: namespace 'unknown' does not exist!
1270 [255]
1278 [255]
1271 $ log 'named("re:unknown")'
1279 $ log 'named("re:unknown")'
1272 abort: no namespace exists that match 'unknown'!
1280 abort: no namespace exists that match 'unknown'!
1273 [255]
1281 [255]
1274 $ log 'present(named("unknown"))'
1282 $ log 'present(named("unknown"))'
1275 $ log 'present(named("re:unknown"))'
1283 $ log 'present(named("re:unknown"))'
1276
1284
1277 $ log 'tag()'
1285 $ log 'tag()'
1278 6
1286 6
1279 $ log 'named("tags")'
1287 $ log 'named("tags")'
1280 6
1288 6
1281
1289
1282 issue2437
1290 issue2437
1283
1291
1284 $ log '3 and p1(5)'
1292 $ log '3 and p1(5)'
1285 3
1293 3
1286 $ log '4 and p2(6)'
1294 $ log '4 and p2(6)'
1287 4
1295 4
1288 $ log '1 and parents(:2)'
1296 $ log '1 and parents(:2)'
1289 1
1297 1
1290 $ log '2 and children(1:)'
1298 $ log '2 and children(1:)'
1291 2
1299 2
1292 $ log 'roots(all()) or roots(all())'
1300 $ log 'roots(all()) or roots(all())'
1293 0
1301 0
1294 $ hg debugrevspec 'roots(all()) or roots(all())'
1302 $ hg debugrevspec 'roots(all()) or roots(all())'
1295 0
1303 0
1296 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
1304 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
1297 9
1305 9
1298 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
1306 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
1299 4
1307 4
1300
1308
1301 issue2654: report a parse error if the revset was not completely parsed
1309 issue2654: report a parse error if the revset was not completely parsed
1302
1310
1303 $ log '1 OR 2'
1311 $ log '1 OR 2'
1304 hg: parse error at 2: invalid token
1312 hg: parse error at 2: invalid token
1305 [255]
1313 [255]
1306
1314
1307 or operator should preserve ordering:
1315 or operator should preserve ordering:
1308 $ log 'reverse(2::4) or tip'
1316 $ log 'reverse(2::4) or tip'
1309 4
1317 4
1310 2
1318 2
1311 9
1319 9
1312
1320
1313 parentrevspec
1321 parentrevspec
1314
1322
1315 $ log 'merge()^0'
1323 $ log 'merge()^0'
1316 6
1324 6
1317 $ log 'merge()^'
1325 $ log 'merge()^'
1318 5
1326 5
1319 $ log 'merge()^1'
1327 $ log 'merge()^1'
1320 5
1328 5
1321 $ log 'merge()^2'
1329 $ log 'merge()^2'
1322 4
1330 4
1323 $ log 'merge()^^'
1331 $ log 'merge()^^'
1324 3
1332 3
1325 $ log 'merge()^1^'
1333 $ log 'merge()^1^'
1326 3
1334 3
1327 $ log 'merge()^^^'
1335 $ log 'merge()^^^'
1328 1
1336 1
1329
1337
1330 $ log 'merge()~0'
1338 $ log 'merge()~0'
1331 6
1339 6
1332 $ log 'merge()~1'
1340 $ log 'merge()~1'
1333 5
1341 5
1334 $ log 'merge()~2'
1342 $ log 'merge()~2'
1335 3
1343 3
1336 $ log 'merge()~2^1'
1344 $ log 'merge()~2^1'
1337 1
1345 1
1338 $ log 'merge()~3'
1346 $ log 'merge()~3'
1339 1
1347 1
1340
1348
1341 $ log '(-3:tip)^'
1349 $ log '(-3:tip)^'
1342 4
1350 4
1343 6
1351 6
1344 8
1352 8
1345
1353
1346 $ log 'tip^foo'
1354 $ log 'tip^foo'
1347 hg: parse error: ^ expects a number 0, 1, or 2
1355 hg: parse error: ^ expects a number 0, 1, or 2
1348 [255]
1356 [255]
1349
1357
1350 Bogus function gets suggestions
1358 Bogus function gets suggestions
1351 $ log 'add()'
1359 $ log 'add()'
1352 hg: parse error: unknown identifier: add
1360 hg: parse error: unknown identifier: add
1353 (did you mean 'adds'?)
1361 (did you mean 'adds'?)
1354 [255]
1362 [255]
1355 $ log 'added()'
1363 $ log 'added()'
1356 hg: parse error: unknown identifier: added
1364 hg: parse error: unknown identifier: added
1357 (did you mean 'adds'?)
1365 (did you mean 'adds'?)
1358 [255]
1366 [255]
1359 $ log 'remo()'
1367 $ log 'remo()'
1360 hg: parse error: unknown identifier: remo
1368 hg: parse error: unknown identifier: remo
1361 (did you mean one of remote, removes?)
1369 (did you mean one of remote, removes?)
1362 [255]
1370 [255]
1363 $ log 'babar()'
1371 $ log 'babar()'
1364 hg: parse error: unknown identifier: babar
1372 hg: parse error: unknown identifier: babar
1365 [255]
1373 [255]
1366
1374
1367 Bogus function with a similar internal name doesn't suggest the internal name
1375 Bogus function with a similar internal name doesn't suggest the internal name
1368 $ log 'matches()'
1376 $ log 'matches()'
1369 hg: parse error: unknown identifier: matches
1377 hg: parse error: unknown identifier: matches
1370 (did you mean 'matching'?)
1378 (did you mean 'matching'?)
1371 [255]
1379 [255]
1372
1380
1373 Undocumented functions aren't suggested as similar either
1381 Undocumented functions aren't suggested as similar either
1374 $ log 'wdir2()'
1382 $ log 'wdir2()'
1375 hg: parse error: unknown identifier: wdir2
1383 hg: parse error: unknown identifier: wdir2
1376 [255]
1384 [255]
1377
1385
1378 multiple revspecs
1386 multiple revspecs
1379
1387
1380 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
1388 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
1381 8
1389 8
1382 9
1390 9
1383 4
1391 4
1384 5
1392 5
1385 6
1393 6
1386 7
1394 7
1387
1395
1388 test usage in revpair (with "+")
1396 test usage in revpair (with "+")
1389
1397
1390 (real pair)
1398 (real pair)
1391
1399
1392 $ hg diff -r 'tip^^' -r 'tip'
1400 $ hg diff -r 'tip^^' -r 'tip'
1393 diff -r 2326846efdab -r 24286f4ae135 .hgtags
1401 diff -r 2326846efdab -r 24286f4ae135 .hgtags
1394 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1402 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1395 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
1403 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
1396 @@ -0,0 +1,1 @@
1404 @@ -0,0 +1,1 @@
1397 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1405 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1398 $ hg diff -r 'tip^^::tip'
1406 $ hg diff -r 'tip^^::tip'
1399 diff -r 2326846efdab -r 24286f4ae135 .hgtags
1407 diff -r 2326846efdab -r 24286f4ae135 .hgtags
1400 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1408 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1401 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
1409 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
1402 @@ -0,0 +1,1 @@
1410 @@ -0,0 +1,1 @@
1403 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1411 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1404
1412
1405 (single rev)
1413 (single rev)
1406
1414
1407 $ hg diff -r 'tip^' -r 'tip^'
1415 $ hg diff -r 'tip^' -r 'tip^'
1408 $ hg diff -r 'tip^::tip^ or tip^'
1416 $ hg diff -r 'tip^::tip^ or tip^'
1409
1417
1410 (single rev that does not looks like a range)
1418 (single rev that does not looks like a range)
1411
1419
1412 $ hg diff -r 'tip^ or tip^'
1420 $ hg diff -r 'tip^ or tip^'
1413 diff -r d5d0dcbdc4d9 .hgtags
1421 diff -r d5d0dcbdc4d9 .hgtags
1414 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1422 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1415 +++ b/.hgtags * (glob)
1423 +++ b/.hgtags * (glob)
1416 @@ -0,0 +1,1 @@
1424 @@ -0,0 +1,1 @@
1417 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1425 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1418
1426
1419 (no rev)
1427 (no rev)
1420
1428
1421 $ hg diff -r 'author("babar") or author("celeste")'
1429 $ hg diff -r 'author("babar") or author("celeste")'
1422 abort: empty revision range
1430 abort: empty revision range
1423 [255]
1431 [255]
1424
1432
1425 aliases:
1433 aliases:
1426
1434
1427 $ echo '[revsetalias]' >> .hg/hgrc
1435 $ echo '[revsetalias]' >> .hg/hgrc
1428 $ echo 'm = merge()' >> .hg/hgrc
1436 $ echo 'm = merge()' >> .hg/hgrc
1429 (revset aliases can override builtin revsets)
1437 (revset aliases can override builtin revsets)
1430 $ echo 'p2($1) = p1($1)' >> .hg/hgrc
1438 $ echo 'p2($1) = p1($1)' >> .hg/hgrc
1431 $ echo 'sincem = descendants(m)' >> .hg/hgrc
1439 $ echo 'sincem = descendants(m)' >> .hg/hgrc
1432 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
1440 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
1433 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
1441 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
1434 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
1442 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
1435
1443
1436 $ try m
1444 $ try m
1437 ('symbol', 'm')
1445 ('symbol', 'm')
1438 (func
1446 (func
1439 ('symbol', 'merge')
1447 ('symbol', 'merge')
1440 None)
1448 None)
1441 * set:
1449 * set:
1442 <filteredset
1450 <filteredset
1443 <fullreposet+ 0:9>>
1451 <fullreposet+ 0:9>>
1444 6
1452 6
1445
1453
1446 $ HGPLAIN=1
1454 $ HGPLAIN=1
1447 $ export HGPLAIN
1455 $ export HGPLAIN
1448 $ try m
1456 $ try m
1449 ('symbol', 'm')
1457 ('symbol', 'm')
1450 abort: unknown revision 'm'!
1458 abort: unknown revision 'm'!
1451 [255]
1459 [255]
1452
1460
1453 $ HGPLAINEXCEPT=revsetalias
1461 $ HGPLAINEXCEPT=revsetalias
1454 $ export HGPLAINEXCEPT
1462 $ export HGPLAINEXCEPT
1455 $ try m
1463 $ try m
1456 ('symbol', 'm')
1464 ('symbol', 'm')
1457 (func
1465 (func
1458 ('symbol', 'merge')
1466 ('symbol', 'merge')
1459 None)
1467 None)
1460 * set:
1468 * set:
1461 <filteredset
1469 <filteredset
1462 <fullreposet+ 0:9>>
1470 <fullreposet+ 0:9>>
1463 6
1471 6
1464
1472
1465 $ unset HGPLAIN
1473 $ unset HGPLAIN
1466 $ unset HGPLAINEXCEPT
1474 $ unset HGPLAINEXCEPT
1467
1475
1468 $ try 'p2(.)'
1476 $ try 'p2(.)'
1469 (func
1477 (func
1470 ('symbol', 'p2')
1478 ('symbol', 'p2')
1471 ('symbol', '.'))
1479 ('symbol', '.'))
1472 (func
1480 (func
1473 ('symbol', 'p1')
1481 ('symbol', 'p1')
1474 ('symbol', '.'))
1482 ('symbol', '.'))
1475 * set:
1483 * set:
1476 <baseset+ [8]>
1484 <baseset+ [8]>
1477 8
1485 8
1478
1486
1479 $ HGPLAIN=1
1487 $ HGPLAIN=1
1480 $ export HGPLAIN
1488 $ export HGPLAIN
1481 $ try 'p2(.)'
1489 $ try 'p2(.)'
1482 (func
1490 (func
1483 ('symbol', 'p2')
1491 ('symbol', 'p2')
1484 ('symbol', '.'))
1492 ('symbol', '.'))
1485 * set:
1493 * set:
1486 <baseset+ []>
1494 <baseset+ []>
1487
1495
1488 $ HGPLAINEXCEPT=revsetalias
1496 $ HGPLAINEXCEPT=revsetalias
1489 $ export HGPLAINEXCEPT
1497 $ export HGPLAINEXCEPT
1490 $ try 'p2(.)'
1498 $ try 'p2(.)'
1491 (func
1499 (func
1492 ('symbol', 'p2')
1500 ('symbol', 'p2')
1493 ('symbol', '.'))
1501 ('symbol', '.'))
1494 (func
1502 (func
1495 ('symbol', 'p1')
1503 ('symbol', 'p1')
1496 ('symbol', '.'))
1504 ('symbol', '.'))
1497 * set:
1505 * set:
1498 <baseset+ [8]>
1506 <baseset+ [8]>
1499 8
1507 8
1500
1508
1501 $ unset HGPLAIN
1509 $ unset HGPLAIN
1502 $ unset HGPLAINEXCEPT
1510 $ unset HGPLAINEXCEPT
1503
1511
1504 test alias recursion
1512 test alias recursion
1505
1513
1506 $ try sincem
1514 $ try sincem
1507 ('symbol', 'sincem')
1515 ('symbol', 'sincem')
1508 (func
1516 (func
1509 ('symbol', 'descendants')
1517 ('symbol', 'descendants')
1510 (func
1518 (func
1511 ('symbol', 'merge')
1519 ('symbol', 'merge')
1512 None))
1520 None))
1513 * set:
1521 * set:
1514 <addset+
1522 <addset+
1515 <filteredset
1523 <filteredset
1516 <fullreposet+ 0:9>>,
1524 <fullreposet+ 0:9>>,
1517 <generatorset+>>
1525 <generatorset+>>
1518 6
1526 6
1519 7
1527 7
1520
1528
1521 test infinite recursion
1529 test infinite recursion
1522
1530
1523 $ echo 'recurse1 = recurse2' >> .hg/hgrc
1531 $ echo 'recurse1 = recurse2' >> .hg/hgrc
1524 $ echo 'recurse2 = recurse1' >> .hg/hgrc
1532 $ echo 'recurse2 = recurse1' >> .hg/hgrc
1525 $ try recurse1
1533 $ try recurse1
1526 ('symbol', 'recurse1')
1534 ('symbol', 'recurse1')
1527 hg: parse error: infinite expansion of revset alias "recurse1" detected
1535 hg: parse error: infinite expansion of revset alias "recurse1" detected
1528 [255]
1536 [255]
1529
1537
1530 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
1538 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
1531 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
1539 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
1532 $ try "level2(level1(1, 2), 3)"
1540 $ try "level2(level1(1, 2), 3)"
1533 (func
1541 (func
1534 ('symbol', 'level2')
1542 ('symbol', 'level2')
1535 (list
1543 (list
1536 (func
1544 (func
1537 ('symbol', 'level1')
1545 ('symbol', 'level1')
1538 (list
1546 (list
1539 ('symbol', '1')
1547 ('symbol', '1')
1540 ('symbol', '2')))
1548 ('symbol', '2')))
1541 ('symbol', '3')))
1549 ('symbol', '3')))
1542 (or
1550 (or
1543 ('symbol', '3')
1551 ('symbol', '3')
1544 (or
1552 (or
1545 ('symbol', '1')
1553 ('symbol', '1')
1546 ('symbol', '2')))
1554 ('symbol', '2')))
1547 * set:
1555 * set:
1548 <addset
1556 <addset
1549 <baseset [3]>,
1557 <baseset [3]>,
1550 <baseset [1, 2]>>
1558 <baseset [1, 2]>>
1551 3
1559 3
1552 1
1560 1
1553 2
1561 2
1554
1562
1555 test nesting and variable passing
1563 test nesting and variable passing
1556
1564
1557 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
1565 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
1558 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
1566 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
1559 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
1567 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
1560 $ try 'nested(2:5)'
1568 $ try 'nested(2:5)'
1561 (func
1569 (func
1562 ('symbol', 'nested')
1570 ('symbol', 'nested')
1563 (range
1571 (range
1564 ('symbol', '2')
1572 ('symbol', '2')
1565 ('symbol', '5')))
1573 ('symbol', '5')))
1566 (func
1574 (func
1567 ('symbol', 'max')
1575 ('symbol', 'max')
1568 (range
1576 (range
1569 ('symbol', '2')
1577 ('symbol', '2')
1570 ('symbol', '5')))
1578 ('symbol', '5')))
1571 * set:
1579 * set:
1572 <baseset [5]>
1580 <baseset [5]>
1573 5
1581 5
1574
1582
1575 test chained `or` operations are flattened at parsing phase
1583 test chained `or` operations are flattened at parsing phase
1576
1584
1577 $ echo 'chainedorops($1, $2, $3) = $1|$2|$3' >> .hg/hgrc
1585 $ echo 'chainedorops($1, $2, $3) = $1|$2|$3' >> .hg/hgrc
1578 $ try 'chainedorops(0:1, 1:2, 2:3)'
1586 $ try 'chainedorops(0:1, 1:2, 2:3)'
1579 (func
1587 (func
1580 ('symbol', 'chainedorops')
1588 ('symbol', 'chainedorops')
1581 (list
1589 (list
1582 (list
1590 (list
1583 (range
1591 (range
1584 ('symbol', '0')
1592 ('symbol', '0')
1585 ('symbol', '1'))
1593 ('symbol', '1'))
1586 (range
1594 (range
1587 ('symbol', '1')
1595 ('symbol', '1')
1588 ('symbol', '2')))
1596 ('symbol', '2')))
1589 (range
1597 (range
1590 ('symbol', '2')
1598 ('symbol', '2')
1591 ('symbol', '3'))))
1599 ('symbol', '3'))))
1592 (or
1600 (or
1593 (range
1601 (range
1594 ('symbol', '0')
1602 ('symbol', '0')
1595 ('symbol', '1'))
1603 ('symbol', '1'))
1596 (range
1604 (range
1597 ('symbol', '1')
1605 ('symbol', '1')
1598 ('symbol', '2'))
1606 ('symbol', '2'))
1599 (range
1607 (range
1600 ('symbol', '2')
1608 ('symbol', '2')
1601 ('symbol', '3')))
1609 ('symbol', '3')))
1602 * set:
1610 * set:
1603 <addset
1611 <addset
1604 <spanset+ 0:1>,
1612 <spanset+ 0:1>,
1605 <addset
1613 <addset
1606 <spanset+ 1:2>,
1614 <spanset+ 1:2>,
1607 <spanset+ 2:3>>>
1615 <spanset+ 2:3>>>
1608 0
1616 0
1609 1
1617 1
1610 2
1618 2
1611 3
1619 3
1612
1620
1613 test variable isolation, variable placeholders are rewritten as string
1621 test variable isolation, variable placeholders are rewritten as string
1614 then parsed and matched again as string. Check they do not leak too
1622 then parsed and matched again as string. Check they do not leak too
1615 far away.
1623 far away.
1616
1624
1617 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
1625 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
1618 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
1626 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
1619 $ try 'callinjection(2:5)'
1627 $ try 'callinjection(2:5)'
1620 (func
1628 (func
1621 ('symbol', 'callinjection')
1629 ('symbol', 'callinjection')
1622 (range
1630 (range
1623 ('symbol', '2')
1631 ('symbol', '2')
1624 ('symbol', '5')))
1632 ('symbol', '5')))
1625 (func
1633 (func
1626 ('symbol', 'descendants')
1634 ('symbol', 'descendants')
1627 (func
1635 (func
1628 ('symbol', 'max')
1636 ('symbol', 'max')
1629 ('string', '$1')))
1637 ('string', '$1')))
1630 abort: unknown revision '$1'!
1638 abort: unknown revision '$1'!
1631 [255]
1639 [255]
1632
1640
1633 $ echo 'injectparamasstring2 = max(_aliasarg("$1"))' >> .hg/hgrc
1641 $ echo 'injectparamasstring2 = max(_aliasarg("$1"))' >> .hg/hgrc
1634 $ echo 'callinjection2($1) = descendants(injectparamasstring2)' >> .hg/hgrc
1642 $ echo 'callinjection2($1) = descendants(injectparamasstring2)' >> .hg/hgrc
1635 $ try 'callinjection2(2:5)'
1643 $ try 'callinjection2(2:5)'
1636 (func
1644 (func
1637 ('symbol', 'callinjection2')
1645 ('symbol', 'callinjection2')
1638 (range
1646 (range
1639 ('symbol', '2')
1647 ('symbol', '2')
1640 ('symbol', '5')))
1648 ('symbol', '5')))
1641 abort: failed to parse the definition of revset alias "injectparamasstring2": unknown identifier: _aliasarg
1649 abort: failed to parse the definition of revset alias "injectparamasstring2": unknown identifier: _aliasarg
1642 [255]
1650 [255]
1643 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
1651 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
1644 ('symbol', 'tip')
1652 ('symbol', 'tip')
1645 warning: failed to parse the definition of revset alias "anotherbadone": at 7: not a prefix: end
1653 warning: failed to parse the definition of revset alias "anotherbadone": at 7: not a prefix: end
1646 warning: failed to parse the definition of revset alias "injectparamasstring2": unknown identifier: _aliasarg
1654 warning: failed to parse the definition of revset alias "injectparamasstring2": unknown identifier: _aliasarg
1647 * set:
1655 * set:
1648 <baseset [9]>
1656 <baseset [9]>
1649 9
1657 9
1650 >>> data = file('.hg/hgrc', 'rb').read()
1658 >>> data = file('.hg/hgrc', 'rb').read()
1651 >>> file('.hg/hgrc', 'wb').write(data.replace('_aliasarg', ''))
1659 >>> file('.hg/hgrc', 'wb').write(data.replace('_aliasarg', ''))
1652
1660
1653 $ try 'tip'
1661 $ try 'tip'
1654 ('symbol', 'tip')
1662 ('symbol', 'tip')
1655 * set:
1663 * set:
1656 <baseset [9]>
1664 <baseset [9]>
1657 9
1665 9
1658
1666
1659 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
1667 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
1660 ('symbol', 'tip')
1668 ('symbol', 'tip')
1661 warning: failed to parse the declaration of revset alias "bad name": at 4: invalid token
1669 warning: failed to parse the declaration of revset alias "bad name": at 4: invalid token
1662 * set:
1670 * set:
1663 <baseset [9]>
1671 <baseset [9]>
1664 9
1672 9
1665 $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc
1673 $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc
1666 $ try 'strictreplacing("foo", tip)'
1674 $ try 'strictreplacing("foo", tip)'
1667 (func
1675 (func
1668 ('symbol', 'strictreplacing')
1676 ('symbol', 'strictreplacing')
1669 (list
1677 (list
1670 ('string', 'foo')
1678 ('string', 'foo')
1671 ('symbol', 'tip')))
1679 ('symbol', 'tip')))
1672 (or
1680 (or
1673 ('symbol', 'tip')
1681 ('symbol', 'tip')
1674 (func
1682 (func
1675 ('symbol', 'desc')
1683 ('symbol', 'desc')
1676 ('string', '$1')))
1684 ('string', '$1')))
1677 * set:
1685 * set:
1678 <addset
1686 <addset
1679 <baseset [9]>,
1687 <baseset [9]>,
1680 <filteredset
1688 <filteredset
1681 <fullreposet+ 0:9>>>
1689 <fullreposet+ 0:9>>>
1682 9
1690 9
1683
1691
1684 $ try 'd(2:5)'
1692 $ try 'd(2:5)'
1685 (func
1693 (func
1686 ('symbol', 'd')
1694 ('symbol', 'd')
1687 (range
1695 (range
1688 ('symbol', '2')
1696 ('symbol', '2')
1689 ('symbol', '5')))
1697 ('symbol', '5')))
1690 (func
1698 (func
1691 ('symbol', 'reverse')
1699 ('symbol', 'reverse')
1692 (func
1700 (func
1693 ('symbol', 'sort')
1701 ('symbol', 'sort')
1694 (list
1702 (list
1695 (range
1703 (range
1696 ('symbol', '2')
1704 ('symbol', '2')
1697 ('symbol', '5'))
1705 ('symbol', '5'))
1698 ('symbol', 'date'))))
1706 ('symbol', 'date'))))
1699 * set:
1707 * set:
1700 <baseset [4, 5, 3, 2]>
1708 <baseset [4, 5, 3, 2]>
1701 4
1709 4
1702 5
1710 5
1703 3
1711 3
1704 2
1712 2
1705 $ try 'rs(2 or 3, date)'
1713 $ try 'rs(2 or 3, date)'
1706 (func
1714 (func
1707 ('symbol', 'rs')
1715 ('symbol', 'rs')
1708 (list
1716 (list
1709 (or
1717 (or
1710 ('symbol', '2')
1718 ('symbol', '2')
1711 ('symbol', '3'))
1719 ('symbol', '3'))
1712 ('symbol', 'date')))
1720 ('symbol', 'date')))
1713 (func
1721 (func
1714 ('symbol', 'reverse')
1722 ('symbol', 'reverse')
1715 (func
1723 (func
1716 ('symbol', 'sort')
1724 ('symbol', 'sort')
1717 (list
1725 (list
1718 (or
1726 (or
1719 ('symbol', '2')
1727 ('symbol', '2')
1720 ('symbol', '3'))
1728 ('symbol', '3'))
1721 ('symbol', 'date'))))
1729 ('symbol', 'date'))))
1722 * set:
1730 * set:
1723 <baseset [3, 2]>
1731 <baseset [3, 2]>
1724 3
1732 3
1725 2
1733 2
1726 $ try 'rs()'
1734 $ try 'rs()'
1727 (func
1735 (func
1728 ('symbol', 'rs')
1736 ('symbol', 'rs')
1729 None)
1737 None)
1730 hg: parse error: invalid number of arguments: 0
1738 hg: parse error: invalid number of arguments: 0
1731 [255]
1739 [255]
1732 $ try 'rs(2)'
1740 $ try 'rs(2)'
1733 (func
1741 (func
1734 ('symbol', 'rs')
1742 ('symbol', 'rs')
1735 ('symbol', '2'))
1743 ('symbol', '2'))
1736 hg: parse error: invalid number of arguments: 1
1744 hg: parse error: invalid number of arguments: 1
1737 [255]
1745 [255]
1738 $ try 'rs(2, data, 7)'
1746 $ try 'rs(2, data, 7)'
1739 (func
1747 (func
1740 ('symbol', 'rs')
1748 ('symbol', 'rs')
1741 (list
1749 (list
1742 (list
1750 (list
1743 ('symbol', '2')
1751 ('symbol', '2')
1744 ('symbol', 'data'))
1752 ('symbol', 'data'))
1745 ('symbol', '7')))
1753 ('symbol', '7')))
1746 hg: parse error: invalid number of arguments: 3
1754 hg: parse error: invalid number of arguments: 3
1747 [255]
1755 [255]
1748 $ try 'rs4(2 or 3, x, x, date)'
1756 $ try 'rs4(2 or 3, x, x, date)'
1749 (func
1757 (func
1750 ('symbol', 'rs4')
1758 ('symbol', 'rs4')
1751 (list
1759 (list
1752 (list
1760 (list
1753 (list
1761 (list
1754 (or
1762 (or
1755 ('symbol', '2')
1763 ('symbol', '2')
1756 ('symbol', '3'))
1764 ('symbol', '3'))
1757 ('symbol', 'x'))
1765 ('symbol', 'x'))
1758 ('symbol', 'x'))
1766 ('symbol', 'x'))
1759 ('symbol', 'date')))
1767 ('symbol', 'date')))
1760 (func
1768 (func
1761 ('symbol', 'reverse')
1769 ('symbol', 'reverse')
1762 (func
1770 (func
1763 ('symbol', 'sort')
1771 ('symbol', 'sort')
1764 (list
1772 (list
1765 (or
1773 (or
1766 ('symbol', '2')
1774 ('symbol', '2')
1767 ('symbol', '3'))
1775 ('symbol', '3'))
1768 ('symbol', 'date'))))
1776 ('symbol', 'date'))))
1769 * set:
1777 * set:
1770 <baseset [3, 2]>
1778 <baseset [3, 2]>
1771 3
1779 3
1772 2
1780 2
1773
1781
1774 issue4553: check that revset aliases override existing hash prefix
1782 issue4553: check that revset aliases override existing hash prefix
1775
1783
1776 $ hg log -qr e
1784 $ hg log -qr e
1777 6:e0cc66ef77e8
1785 6:e0cc66ef77e8
1778
1786
1779 $ hg log -qr e --config revsetalias.e="all()"
1787 $ hg log -qr e --config revsetalias.e="all()"
1780 0:2785f51eece5
1788 0:2785f51eece5
1781 1:d75937da8da0
1789 1:d75937da8da0
1782 2:5ed5505e9f1c
1790 2:5ed5505e9f1c
1783 3:8528aa5637f2
1791 3:8528aa5637f2
1784 4:2326846efdab
1792 4:2326846efdab
1785 5:904fa392b941
1793 5:904fa392b941
1786 6:e0cc66ef77e8
1794 6:e0cc66ef77e8
1787 7:013af1973af4
1795 7:013af1973af4
1788 8:d5d0dcbdc4d9
1796 8:d5d0dcbdc4d9
1789 9:24286f4ae135
1797 9:24286f4ae135
1790
1798
1791 $ hg log -qr e: --config revsetalias.e="0"
1799 $ hg log -qr e: --config revsetalias.e="0"
1792 0:2785f51eece5
1800 0:2785f51eece5
1793 1:d75937da8da0
1801 1:d75937da8da0
1794 2:5ed5505e9f1c
1802 2:5ed5505e9f1c
1795 3:8528aa5637f2
1803 3:8528aa5637f2
1796 4:2326846efdab
1804 4:2326846efdab
1797 5:904fa392b941
1805 5:904fa392b941
1798 6:e0cc66ef77e8
1806 6:e0cc66ef77e8
1799 7:013af1973af4
1807 7:013af1973af4
1800 8:d5d0dcbdc4d9
1808 8:d5d0dcbdc4d9
1801 9:24286f4ae135
1809 9:24286f4ae135
1802
1810
1803 $ hg log -qr :e --config revsetalias.e="9"
1811 $ hg log -qr :e --config revsetalias.e="9"
1804 0:2785f51eece5
1812 0:2785f51eece5
1805 1:d75937da8da0
1813 1:d75937da8da0
1806 2:5ed5505e9f1c
1814 2:5ed5505e9f1c
1807 3:8528aa5637f2
1815 3:8528aa5637f2
1808 4:2326846efdab
1816 4:2326846efdab
1809 5:904fa392b941
1817 5:904fa392b941
1810 6:e0cc66ef77e8
1818 6:e0cc66ef77e8
1811 7:013af1973af4
1819 7:013af1973af4
1812 8:d5d0dcbdc4d9
1820 8:d5d0dcbdc4d9
1813 9:24286f4ae135
1821 9:24286f4ae135
1814
1822
1815 $ hg log -qr e:
1823 $ hg log -qr e:
1816 6:e0cc66ef77e8
1824 6:e0cc66ef77e8
1817 7:013af1973af4
1825 7:013af1973af4
1818 8:d5d0dcbdc4d9
1826 8:d5d0dcbdc4d9
1819 9:24286f4ae135
1827 9:24286f4ae135
1820
1828
1821 $ hg log -qr :e
1829 $ hg log -qr :e
1822 0:2785f51eece5
1830 0:2785f51eece5
1823 1:d75937da8da0
1831 1:d75937da8da0
1824 2:5ed5505e9f1c
1832 2:5ed5505e9f1c
1825 3:8528aa5637f2
1833 3:8528aa5637f2
1826 4:2326846efdab
1834 4:2326846efdab
1827 5:904fa392b941
1835 5:904fa392b941
1828 6:e0cc66ef77e8
1836 6:e0cc66ef77e8
1829
1837
1830 issue2549 - correct optimizations
1838 issue2549 - correct optimizations
1831
1839
1832 $ log 'limit(1 or 2 or 3, 2) and not 2'
1840 $ log 'limit(1 or 2 or 3, 2) and not 2'
1833 1
1841 1
1834 $ log 'max(1 or 2) and not 2'
1842 $ log 'max(1 or 2) and not 2'
1835 $ log 'min(1 or 2) and not 1'
1843 $ log 'min(1 or 2) and not 1'
1836 $ log 'last(1 or 2, 1) and not 2'
1844 $ log 'last(1 or 2, 1) and not 2'
1837
1845
1838 issue4289 - ordering of built-ins
1846 issue4289 - ordering of built-ins
1839 $ hg log -M -q -r 3:2
1847 $ hg log -M -q -r 3:2
1840 3:8528aa5637f2
1848 3:8528aa5637f2
1841 2:5ed5505e9f1c
1849 2:5ed5505e9f1c
1842
1850
1843 test revsets started with 40-chars hash (issue3669)
1851 test revsets started with 40-chars hash (issue3669)
1844
1852
1845 $ ISSUE3669_TIP=`hg tip --template '{node}'`
1853 $ ISSUE3669_TIP=`hg tip --template '{node}'`
1846 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
1854 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
1847 9
1855 9
1848 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
1856 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
1849 8
1857 8
1850
1858
1851 test or-ed indirect predicates (issue3775)
1859 test or-ed indirect predicates (issue3775)
1852
1860
1853 $ log '6 or 6^1' | sort
1861 $ log '6 or 6^1' | sort
1854 5
1862 5
1855 6
1863 6
1856 $ log '6^1 or 6' | sort
1864 $ log '6^1 or 6' | sort
1857 5
1865 5
1858 6
1866 6
1859 $ log '4 or 4~1' | sort
1867 $ log '4 or 4~1' | sort
1860 2
1868 2
1861 4
1869 4
1862 $ log '4~1 or 4' | sort
1870 $ log '4~1 or 4' | sort
1863 2
1871 2
1864 4
1872 4
1865 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
1873 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
1866 0
1874 0
1867 1
1875 1
1868 2
1876 2
1869 3
1877 3
1870 4
1878 4
1871 5
1879 5
1872 6
1880 6
1873 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
1881 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
1874 0
1882 0
1875 1
1883 1
1876 2
1884 2
1877 3
1885 3
1878 4
1886 4
1879 5
1887 5
1880 6
1888 6
1881
1889
1882 tests for 'remote()' predicate:
1890 tests for 'remote()' predicate:
1883 #. (csets in remote) (id) (remote)
1891 #. (csets in remote) (id) (remote)
1884 1. less than local current branch "default"
1892 1. less than local current branch "default"
1885 2. same with local specified "default"
1893 2. same with local specified "default"
1886 3. more than local specified specified
1894 3. more than local specified specified
1887
1895
1888 $ hg clone --quiet -U . ../remote3
1896 $ hg clone --quiet -U . ../remote3
1889 $ cd ../remote3
1897 $ cd ../remote3
1890 $ hg update -q 7
1898 $ hg update -q 7
1891 $ echo r > r
1899 $ echo r > r
1892 $ hg ci -Aqm 10
1900 $ hg ci -Aqm 10
1893 $ log 'remote()'
1901 $ log 'remote()'
1894 7
1902 7
1895 $ log 'remote("a-b-c-")'
1903 $ log 'remote("a-b-c-")'
1896 2
1904 2
1897 $ cd ../repo
1905 $ cd ../repo
1898 $ log 'remote(".a.b.c.", "../remote3")'
1906 $ log 'remote(".a.b.c.", "../remote3")'
1899
1907
1900 tests for concatenation of strings/symbols by "##"
1908 tests for concatenation of strings/symbols by "##"
1901
1909
1902 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
1910 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
1903 (_concat
1911 (_concat
1904 (_concat
1912 (_concat
1905 (_concat
1913 (_concat
1906 ('symbol', '278')
1914 ('symbol', '278')
1907 ('string', '5f5'))
1915 ('string', '5f5'))
1908 ('symbol', '1ee'))
1916 ('symbol', '1ee'))
1909 ('string', 'ce5'))
1917 ('string', 'ce5'))
1910 ('string', '2785f51eece5')
1918 ('string', '2785f51eece5')
1911 * set:
1919 * set:
1912 <baseset [0]>
1920 <baseset [0]>
1913 0
1921 0
1914
1922
1915 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
1923 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
1916 $ try "cat4(278, '5f5', 1ee, 'ce5')"
1924 $ try "cat4(278, '5f5', 1ee, 'ce5')"
1917 (func
1925 (func
1918 ('symbol', 'cat4')
1926 ('symbol', 'cat4')
1919 (list
1927 (list
1920 (list
1928 (list
1921 (list
1929 (list
1922 ('symbol', '278')
1930 ('symbol', '278')
1923 ('string', '5f5'))
1931 ('string', '5f5'))
1924 ('symbol', '1ee'))
1932 ('symbol', '1ee'))
1925 ('string', 'ce5')))
1933 ('string', 'ce5')))
1926 (_concat
1934 (_concat
1927 (_concat
1935 (_concat
1928 (_concat
1936 (_concat
1929 ('symbol', '278')
1937 ('symbol', '278')
1930 ('string', '5f5'))
1938 ('string', '5f5'))
1931 ('symbol', '1ee'))
1939 ('symbol', '1ee'))
1932 ('string', 'ce5'))
1940 ('string', 'ce5'))
1933 ('string', '2785f51eece5')
1941 ('string', '2785f51eece5')
1934 * set:
1942 * set:
1935 <baseset [0]>
1943 <baseset [0]>
1936 0
1944 0
1937
1945
1938 (check concatenation in alias nesting)
1946 (check concatenation in alias nesting)
1939
1947
1940 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
1948 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
1941 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
1949 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
1942 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
1950 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
1943 0
1951 0
1944
1952
1945 (check operator priority)
1953 (check operator priority)
1946
1954
1947 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
1955 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
1948 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
1956 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
1949 0
1957 0
1950 4
1958 4
1951
1959
1952 $ cd ..
1960 $ cd ..
1953
1961
1954 prepare repository that has "default" branches of multiple roots
1962 prepare repository that has "default" branches of multiple roots
1955
1963
1956 $ hg init namedbranch
1964 $ hg init namedbranch
1957 $ cd namedbranch
1965 $ cd namedbranch
1958
1966
1959 $ echo default0 >> a
1967 $ echo default0 >> a
1960 $ hg ci -Aqm0
1968 $ hg ci -Aqm0
1961 $ echo default1 >> a
1969 $ echo default1 >> a
1962 $ hg ci -m1
1970 $ hg ci -m1
1963
1971
1964 $ hg branch -q stable
1972 $ hg branch -q stable
1965 $ echo stable2 >> a
1973 $ echo stable2 >> a
1966 $ hg ci -m2
1974 $ hg ci -m2
1967 $ echo stable3 >> a
1975 $ echo stable3 >> a
1968 $ hg ci -m3
1976 $ hg ci -m3
1969
1977
1970 $ hg update -q null
1978 $ hg update -q null
1971 $ echo default4 >> a
1979 $ echo default4 >> a
1972 $ hg ci -Aqm4
1980 $ hg ci -Aqm4
1973 $ echo default5 >> a
1981 $ echo default5 >> a
1974 $ hg ci -m5
1982 $ hg ci -m5
1975
1983
1976 "null" revision belongs to "default" branch (issue4683)
1984 "null" revision belongs to "default" branch (issue4683)
1977
1985
1978 $ log 'branch(null)'
1986 $ log 'branch(null)'
1979 0
1987 0
1980 1
1988 1
1981 4
1989 4
1982 5
1990 5
1983
1991
1984 "null" revision belongs to "default" branch, but it shouldn't appear in set
1992 "null" revision belongs to "default" branch, but it shouldn't appear in set
1985 unless explicitly specified (issue4682)
1993 unless explicitly specified (issue4682)
1986
1994
1987 $ log 'children(branch(default))'
1995 $ log 'children(branch(default))'
1988 1
1996 1
1989 2
1997 2
1990 5
1998 5
1991
1999
1992 $ cd ..
2000 $ cd ..
1993
2001
1994 test author/desc/keyword in problematic encoding
2002 test author/desc/keyword in problematic encoding
1995 # unicode: cp932:
2003 # unicode: cp932:
1996 # u30A2 0x83 0x41(= 'A')
2004 # u30A2 0x83 0x41(= 'A')
1997 # u30C2 0x83 0x61(= 'a')
2005 # u30C2 0x83 0x61(= 'a')
1998
2006
1999 $ hg init problematicencoding
2007 $ hg init problematicencoding
2000 $ cd problematicencoding
2008 $ cd problematicencoding
2001
2009
2002 $ python > setup.sh <<EOF
2010 $ python > setup.sh <<EOF
2003 > print u'''
2011 > print u'''
2004 > echo a > text
2012 > echo a > text
2005 > hg add text
2013 > hg add text
2006 > hg --encoding utf-8 commit -u '\u30A2' -m none
2014 > hg --encoding utf-8 commit -u '\u30A2' -m none
2007 > echo b > text
2015 > echo b > text
2008 > hg --encoding utf-8 commit -u '\u30C2' -m none
2016 > hg --encoding utf-8 commit -u '\u30C2' -m none
2009 > echo c > text
2017 > echo c > text
2010 > hg --encoding utf-8 commit -u none -m '\u30A2'
2018 > hg --encoding utf-8 commit -u none -m '\u30A2'
2011 > echo d > text
2019 > echo d > text
2012 > hg --encoding utf-8 commit -u none -m '\u30C2'
2020 > hg --encoding utf-8 commit -u none -m '\u30C2'
2013 > '''.encode('utf-8')
2021 > '''.encode('utf-8')
2014 > EOF
2022 > EOF
2015 $ sh < setup.sh
2023 $ sh < setup.sh
2016
2024
2017 test in problematic encoding
2025 test in problematic encoding
2018 $ python > test.sh <<EOF
2026 $ python > test.sh <<EOF
2019 > print u'''
2027 > print u'''
2020 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
2028 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
2021 > echo ====
2029 > echo ====
2022 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
2030 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
2023 > echo ====
2031 > echo ====
2024 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
2032 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
2025 > echo ====
2033 > echo ====
2026 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
2034 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
2027 > echo ====
2035 > echo ====
2028 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
2036 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
2029 > echo ====
2037 > echo ====
2030 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
2038 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
2031 > '''.encode('cp932')
2039 > '''.encode('cp932')
2032 > EOF
2040 > EOF
2033 $ sh < test.sh
2041 $ sh < test.sh
2034 0
2042 0
2035 ====
2043 ====
2036 1
2044 1
2037 ====
2045 ====
2038 2
2046 2
2039 ====
2047 ====
2040 3
2048 3
2041 ====
2049 ====
2042 0
2050 0
2043 2
2051 2
2044 ====
2052 ====
2045 1
2053 1
2046 3
2054 3
2047
2055
2048 test error message of bad revset
2056 test error message of bad revset
2049 $ hg log -r 'foo\\'
2057 $ hg log -r 'foo\\'
2050 hg: parse error at 3: syntax error in revset 'foo\\'
2058 hg: parse error at 3: syntax error in revset 'foo\\'
2051 [255]
2059 [255]
2052
2060
2053 $ cd ..
2061 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now