##// END OF EJS Templates
revset: drop magic of fullreposet membership test (issue4682)...
Yuya Nishihara -
r25265:e1645683 stable
parent child Browse files
Show More
@@ -1,3449 +1,3445 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 revqueue, revsnode = None, None
28 revqueue, revsnode = None, None
29 h = []
29 h = []
30
30
31 revs.sort(reverse=True)
31 revs.sort(reverse=True)
32 revqueue = util.deque(revs)
32 revqueue = util.deque(revs)
33 if revqueue:
33 if revqueue:
34 revsnode = revqueue.popleft()
34 revsnode = revqueue.popleft()
35 heapq.heappush(h, -revsnode)
35 heapq.heappush(h, -revsnode)
36
36
37 seen = set()
37 seen = set()
38 while h:
38 while h:
39 current = -heapq.heappop(h)
39 current = -heapq.heappop(h)
40 if current not in seen:
40 if current not in seen:
41 if revsnode and current == revsnode:
41 if revsnode and current == revsnode:
42 if revqueue:
42 if revqueue:
43 revsnode = revqueue.popleft()
43 revsnode = revqueue.popleft()
44 heapq.heappush(h, -revsnode)
44 heapq.heappush(h, -revsnode)
45 seen.add(current)
45 seen.add(current)
46 yield current
46 yield current
47 for parent in cl.parentrevs(current)[:cut]:
47 for parent in cl.parentrevs(current)[:cut]:
48 if parent != node.nullrev:
48 if parent != node.nullrev:
49 heapq.heappush(h, -parent)
49 heapq.heappush(h, -parent)
50
50
51 return generatorset(iterate(), iterasc=False)
51 return generatorset(iterate(), iterasc=False)
52
52
53 def _revdescendants(repo, revs, followfirst):
53 def _revdescendants(repo, revs, followfirst):
54 """Like revlog.descendants() but supports followfirst."""
54 """Like revlog.descendants() but supports followfirst."""
55 if followfirst:
55 if followfirst:
56 cut = 1
56 cut = 1
57 else:
57 else:
58 cut = None
58 cut = None
59
59
60 def iterate():
60 def iterate():
61 cl = repo.changelog
61 cl = repo.changelog
62 first = min(revs)
62 first = min(revs)
63 nullrev = node.nullrev
63 nullrev = node.nullrev
64 if first == nullrev:
64 if first == nullrev:
65 # Are there nodes with a null first parent and a non-null
65 # Are there nodes with a null first parent and a non-null
66 # second one? Maybe. Do we care? Probably not.
66 # second one? Maybe. Do we care? Probably not.
67 for i in cl:
67 for i in cl:
68 yield i
68 yield i
69 else:
69 else:
70 seen = set(revs)
70 seen = set(revs)
71 for i in cl.revs(first + 1):
71 for i in cl.revs(first + 1):
72 for x in cl.parentrevs(i)[:cut]:
72 for x in cl.parentrevs(i)[:cut]:
73 if x != nullrev and x in seen:
73 if x != nullrev and x in seen:
74 seen.add(i)
74 seen.add(i)
75 yield i
75 yield i
76 break
76 break
77
77
78 return generatorset(iterate(), iterasc=True)
78 return generatorset(iterate(), iterasc=True)
79
79
80 def _revsbetween(repo, roots, heads):
80 def _revsbetween(repo, roots, heads):
81 """Return all paths between roots and heads, inclusive of both endpoint
81 """Return all paths between roots and heads, inclusive of both endpoint
82 sets."""
82 sets."""
83 if not roots:
83 if not roots:
84 return baseset()
84 return baseset()
85 parentrevs = repo.changelog.parentrevs
85 parentrevs = repo.changelog.parentrevs
86 visit = list(heads)
86 visit = list(heads)
87 reachable = set()
87 reachable = set()
88 seen = {}
88 seen = {}
89 minroot = min(roots)
89 minroot = min(roots)
90 roots = set(roots)
90 roots = set(roots)
91 # open-code the post-order traversal due to the tiny size of
91 # open-code the post-order traversal due to the tiny size of
92 # sys.getrecursionlimit()
92 # sys.getrecursionlimit()
93 while visit:
93 while visit:
94 rev = visit.pop()
94 rev = visit.pop()
95 if rev in roots:
95 if rev in roots:
96 reachable.add(rev)
96 reachable.add(rev)
97 parents = parentrevs(rev)
97 parents = parentrevs(rev)
98 seen[rev] = parents
98 seen[rev] = parents
99 for parent in parents:
99 for parent in parents:
100 if parent >= minroot and parent not in seen:
100 if parent >= minroot and parent not in seen:
101 visit.append(parent)
101 visit.append(parent)
102 if not reachable:
102 if not reachable:
103 return baseset()
103 return baseset()
104 for rev in sorted(seen):
104 for rev in sorted(seen):
105 for parent in seen[rev]:
105 for parent in seen[rev]:
106 if parent in reachable:
106 if parent in reachable:
107 reachable.add(rev)
107 reachable.add(rev)
108 return baseset(sorted(reachable))
108 return baseset(sorted(reachable))
109
109
110 elements = {
110 elements = {
111 "(": (21, ("group", 1, ")"), ("func", 1, ")")),
111 "(": (21, ("group", 1, ")"), ("func", 1, ")")),
112 "##": (20, None, ("_concat", 20)),
112 "##": (20, None, ("_concat", 20)),
113 "~": (18, None, ("ancestor", 18)),
113 "~": (18, None, ("ancestor", 18)),
114 "^": (18, None, ("parent", 18), ("parentpost", 18)),
114 "^": (18, None, ("parent", 18), ("parentpost", 18)),
115 "-": (5, ("negate", 19), ("minus", 5)),
115 "-": (5, ("negate", 19), ("minus", 5)),
116 "::": (17, ("dagrangepre", 17), ("dagrange", 17),
116 "::": (17, ("dagrangepre", 17), ("dagrange", 17),
117 ("dagrangepost", 17)),
117 ("dagrangepost", 17)),
118 "..": (17, ("dagrangepre", 17), ("dagrange", 17),
118 "..": (17, ("dagrangepre", 17), ("dagrange", 17),
119 ("dagrangepost", 17)),
119 ("dagrangepost", 17)),
120 ":": (15, ("rangepre", 15), ("range", 15), ("rangepost", 15)),
120 ":": (15, ("rangepre", 15), ("range", 15), ("rangepost", 15)),
121 "not": (10, ("not", 10)),
121 "not": (10, ("not", 10)),
122 "!": (10, ("not", 10)),
122 "!": (10, ("not", 10)),
123 "and": (5, None, ("and", 5)),
123 "and": (5, None, ("and", 5)),
124 "&": (5, None, ("and", 5)),
124 "&": (5, None, ("and", 5)),
125 "%": (5, None, ("only", 5), ("onlypost", 5)),
125 "%": (5, None, ("only", 5), ("onlypost", 5)),
126 "or": (4, None, ("or", 4)),
126 "or": (4, None, ("or", 4)),
127 "|": (4, None, ("or", 4)),
127 "|": (4, None, ("or", 4)),
128 "+": (4, None, ("or", 4)),
128 "+": (4, None, ("or", 4)),
129 ",": (2, None, ("list", 2)),
129 ",": (2, None, ("list", 2)),
130 ")": (0, None, None),
130 ")": (0, None, None),
131 "symbol": (0, ("symbol",), None),
131 "symbol": (0, ("symbol",), None),
132 "string": (0, ("string",), None),
132 "string": (0, ("string",), None),
133 "end": (0, None, None),
133 "end": (0, None, None),
134 }
134 }
135
135
136 keywords = set(['and', 'or', 'not'])
136 keywords = set(['and', 'or', 'not'])
137
137
138 # default set of valid characters for the initial letter of symbols
138 # default set of valid characters for the initial letter of symbols
139 _syminitletters = set(c for c in [chr(i) for i in xrange(256)]
139 _syminitletters = set(c for c in [chr(i) for i in xrange(256)]
140 if c.isalnum() or c in '._@' or ord(c) > 127)
140 if c.isalnum() or c in '._@' or ord(c) > 127)
141
141
142 # default set of valid characters for non-initial letters of symbols
142 # default set of valid characters for non-initial letters of symbols
143 _symletters = set(c for c in [chr(i) for i in xrange(256)]
143 _symletters = set(c for c in [chr(i) for i in xrange(256)]
144 if c.isalnum() or c in '-._/@' or ord(c) > 127)
144 if c.isalnum() or c in '-._/@' or ord(c) > 127)
145
145
146 def tokenize(program, lookup=None, syminitletters=None, symletters=None):
146 def tokenize(program, lookup=None, syminitletters=None, symletters=None):
147 '''
147 '''
148 Parse a revset statement into a stream of tokens
148 Parse a revset statement into a stream of tokens
149
149
150 ``syminitletters`` is the set of valid characters for the initial
150 ``syminitletters`` is the set of valid characters for the initial
151 letter of symbols.
151 letter of symbols.
152
152
153 By default, character ``c`` is recognized as valid for initial
153 By default, character ``c`` is recognized as valid for initial
154 letter of symbols, if ``c.isalnum() or c in '._@' or ord(c) > 127``.
154 letter of symbols, if ``c.isalnum() or c in '._@' or ord(c) > 127``.
155
155
156 ``symletters`` is the set of valid characters for non-initial
156 ``symletters`` is the set of valid characters for non-initial
157 letters of symbols.
157 letters of symbols.
158
158
159 By default, character ``c`` is recognized as valid for non-initial
159 By default, character ``c`` is recognized as valid for non-initial
160 letters of symbols, if ``c.isalnum() or c in '-._/@' or ord(c) > 127``.
160 letters of symbols, if ``c.isalnum() or c in '-._/@' or ord(c) > 127``.
161
161
162 Check that @ is a valid unquoted token character (issue3686):
162 Check that @ is a valid unquoted token character (issue3686):
163 >>> list(tokenize("@::"))
163 >>> list(tokenize("@::"))
164 [('symbol', '@', 0), ('::', None, 1), ('end', None, 3)]
164 [('symbol', '@', 0), ('::', None, 1), ('end', None, 3)]
165
165
166 '''
166 '''
167 if syminitletters is None:
167 if syminitletters is None:
168 syminitletters = _syminitletters
168 syminitletters = _syminitletters
169 if symletters is None:
169 if symletters is None:
170 symletters = _symletters
170 symletters = _symletters
171
171
172 pos, l = 0, len(program)
172 pos, l = 0, len(program)
173 while pos < l:
173 while pos < l:
174 c = program[pos]
174 c = program[pos]
175 if c.isspace(): # skip inter-token whitespace
175 if c.isspace(): # skip inter-token whitespace
176 pass
176 pass
177 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
177 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
178 yield ('::', None, pos)
178 yield ('::', None, pos)
179 pos += 1 # skip ahead
179 pos += 1 # skip ahead
180 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
180 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
181 yield ('..', None, pos)
181 yield ('..', None, pos)
182 pos += 1 # skip ahead
182 pos += 1 # skip ahead
183 elif c == '#' and program[pos:pos + 2] == '##': # look ahead carefully
183 elif c == '#' and program[pos:pos + 2] == '##': # look ahead carefully
184 yield ('##', None, pos)
184 yield ('##', None, pos)
185 pos += 1 # skip ahead
185 pos += 1 # skip ahead
186 elif c in "():,-|&+!~^%": # handle simple operators
186 elif c in "():,-|&+!~^%": # handle simple operators
187 yield (c, None, pos)
187 yield (c, None, pos)
188 elif (c in '"\'' or c == 'r' and
188 elif (c in '"\'' or c == 'r' and
189 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
189 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
190 if c == 'r':
190 if c == 'r':
191 pos += 1
191 pos += 1
192 c = program[pos]
192 c = program[pos]
193 decode = lambda x: x
193 decode = lambda x: x
194 else:
194 else:
195 decode = lambda x: x.decode('string-escape')
195 decode = lambda x: x.decode('string-escape')
196 pos += 1
196 pos += 1
197 s = pos
197 s = pos
198 while pos < l: # find closing quote
198 while pos < l: # find closing quote
199 d = program[pos]
199 d = program[pos]
200 if d == '\\': # skip over escaped characters
200 if d == '\\': # skip over escaped characters
201 pos += 2
201 pos += 2
202 continue
202 continue
203 if d == c:
203 if d == c:
204 yield ('string', decode(program[s:pos]), s)
204 yield ('string', decode(program[s:pos]), s)
205 break
205 break
206 pos += 1
206 pos += 1
207 else:
207 else:
208 raise error.ParseError(_("unterminated string"), s)
208 raise error.ParseError(_("unterminated string"), s)
209 # gather up a symbol/keyword
209 # gather up a symbol/keyword
210 elif c in syminitletters:
210 elif c in syminitletters:
211 s = pos
211 s = pos
212 pos += 1
212 pos += 1
213 while pos < l: # find end of symbol
213 while pos < l: # find end of symbol
214 d = program[pos]
214 d = program[pos]
215 if d not in symletters:
215 if d not in symletters:
216 break
216 break
217 if d == '.' and program[pos - 1] == '.': # special case for ..
217 if d == '.' and program[pos - 1] == '.': # special case for ..
218 pos -= 1
218 pos -= 1
219 break
219 break
220 pos += 1
220 pos += 1
221 sym = program[s:pos]
221 sym = program[s:pos]
222 if sym in keywords: # operator keywords
222 if sym in keywords: # operator keywords
223 yield (sym, None, s)
223 yield (sym, None, s)
224 elif '-' in sym:
224 elif '-' in sym:
225 # some jerk gave us foo-bar-baz, try to check if it's a symbol
225 # some jerk gave us foo-bar-baz, try to check if it's a symbol
226 if lookup and lookup(sym):
226 if lookup and lookup(sym):
227 # looks like a real symbol
227 # looks like a real symbol
228 yield ('symbol', sym, s)
228 yield ('symbol', sym, s)
229 else:
229 else:
230 # looks like an expression
230 # looks like an expression
231 parts = sym.split('-')
231 parts = sym.split('-')
232 for p in parts[:-1]:
232 for p in parts[:-1]:
233 if p: # possible consecutive -
233 if p: # possible consecutive -
234 yield ('symbol', p, s)
234 yield ('symbol', p, s)
235 s += len(p)
235 s += len(p)
236 yield ('-', None, pos)
236 yield ('-', None, pos)
237 s += 1
237 s += 1
238 if parts[-1]: # possible trailing -
238 if parts[-1]: # possible trailing -
239 yield ('symbol', parts[-1], s)
239 yield ('symbol', parts[-1], s)
240 else:
240 else:
241 yield ('symbol', sym, s)
241 yield ('symbol', sym, s)
242 pos -= 1
242 pos -= 1
243 else:
243 else:
244 raise error.ParseError(_("syntax error in revset '%s'") %
244 raise error.ParseError(_("syntax error in revset '%s'") %
245 program, pos)
245 program, pos)
246 pos += 1
246 pos += 1
247 yield ('end', None, pos)
247 yield ('end', None, pos)
248
248
249 def parseerrordetail(inst):
249 def parseerrordetail(inst):
250 """Compose error message from specified ParseError object
250 """Compose error message from specified ParseError object
251 """
251 """
252 if len(inst.args) > 1:
252 if len(inst.args) > 1:
253 return _('at %s: %s') % (inst.args[1], inst.args[0])
253 return _('at %s: %s') % (inst.args[1], inst.args[0])
254 else:
254 else:
255 return inst.args[0]
255 return inst.args[0]
256
256
257 # helpers
257 # helpers
258
258
259 def getstring(x, err):
259 def getstring(x, err):
260 if x and (x[0] == 'string' or x[0] == 'symbol'):
260 if x and (x[0] == 'string' or x[0] == 'symbol'):
261 return x[1]
261 return x[1]
262 raise error.ParseError(err)
262 raise error.ParseError(err)
263
263
264 def getlist(x):
264 def getlist(x):
265 if not x:
265 if not x:
266 return []
266 return []
267 if x[0] == 'list':
267 if x[0] == 'list':
268 return getlist(x[1]) + [x[2]]
268 return getlist(x[1]) + [x[2]]
269 return [x]
269 return [x]
270
270
271 def getargs(x, min, max, err):
271 def getargs(x, min, max, err):
272 l = getlist(x)
272 l = getlist(x)
273 if len(l) < min or (max >= 0 and len(l) > max):
273 if len(l) < min or (max >= 0 and len(l) > max):
274 raise error.ParseError(err)
274 raise error.ParseError(err)
275 return l
275 return l
276
276
277 def isvalidsymbol(tree):
277 def isvalidsymbol(tree):
278 """Examine whether specified ``tree`` is valid ``symbol`` or not
278 """Examine whether specified ``tree`` is valid ``symbol`` or not
279 """
279 """
280 return tree[0] == 'symbol' and len(tree) > 1
280 return tree[0] == 'symbol' and len(tree) > 1
281
281
282 def getsymbol(tree):
282 def getsymbol(tree):
283 """Get symbol name from valid ``symbol`` in ``tree``
283 """Get symbol name from valid ``symbol`` in ``tree``
284
284
285 This assumes that ``tree`` is already examined by ``isvalidsymbol``.
285 This assumes that ``tree`` is already examined by ``isvalidsymbol``.
286 """
286 """
287 return tree[1]
287 return tree[1]
288
288
289 def isvalidfunc(tree):
289 def isvalidfunc(tree):
290 """Examine whether specified ``tree`` is valid ``func`` or not
290 """Examine whether specified ``tree`` is valid ``func`` or not
291 """
291 """
292 return tree[0] == 'func' and len(tree) > 1 and isvalidsymbol(tree[1])
292 return tree[0] == 'func' and len(tree) > 1 and isvalidsymbol(tree[1])
293
293
294 def getfuncname(tree):
294 def getfuncname(tree):
295 """Get function name from valid ``func`` in ``tree``
295 """Get function name from valid ``func`` in ``tree``
296
296
297 This assumes that ``tree`` is already examined by ``isvalidfunc``.
297 This assumes that ``tree`` is already examined by ``isvalidfunc``.
298 """
298 """
299 return getsymbol(tree[1])
299 return getsymbol(tree[1])
300
300
301 def getfuncargs(tree):
301 def getfuncargs(tree):
302 """Get list of function arguments from valid ``func`` in ``tree``
302 """Get list of function arguments from valid ``func`` in ``tree``
303
303
304 This assumes that ``tree`` is already examined by ``isvalidfunc``.
304 This assumes that ``tree`` is already examined by ``isvalidfunc``.
305 """
305 """
306 if len(tree) > 2:
306 if len(tree) > 2:
307 return getlist(tree[2])
307 return getlist(tree[2])
308 else:
308 else:
309 return []
309 return []
310
310
311 def getset(repo, subset, x):
311 def getset(repo, subset, x):
312 if not x:
312 if not x:
313 raise error.ParseError(_("missing argument"))
313 raise error.ParseError(_("missing argument"))
314 s = methods[x[0]](repo, subset, *x[1:])
314 s = methods[x[0]](repo, subset, *x[1:])
315 if util.safehasattr(s, 'isascending'):
315 if util.safehasattr(s, 'isascending'):
316 return s
316 return s
317 return baseset(s)
317 return baseset(s)
318
318
319 def _getrevsource(repo, r):
319 def _getrevsource(repo, r):
320 extra = repo[r].extra()
320 extra = repo[r].extra()
321 for label in ('source', 'transplant_source', 'rebase_source'):
321 for label in ('source', 'transplant_source', 'rebase_source'):
322 if label in extra:
322 if label in extra:
323 try:
323 try:
324 return repo[extra[label]].rev()
324 return repo[extra[label]].rev()
325 except error.RepoLookupError:
325 except error.RepoLookupError:
326 pass
326 pass
327 return None
327 return None
328
328
329 # operator methods
329 # operator methods
330
330
331 def stringset(repo, subset, x):
331 def stringset(repo, subset, x):
332 x = repo[x].rev()
332 x = repo[x].rev()
333 if x in subset:
333 if (x in subset
334 or x == node.nullrev and isinstance(subset, fullreposet)):
334 return baseset([x])
335 return baseset([x])
335 return baseset()
336 return baseset()
336
337
337 def symbolset(repo, subset, x):
338 def symbolset(repo, subset, x):
338 if x in symbols:
339 if x in symbols:
339 raise error.ParseError(_("can't use %s here") % x)
340 raise error.ParseError(_("can't use %s here") % x)
340 return stringset(repo, subset, x)
341 return stringset(repo, subset, x)
341
342
342 def rangeset(repo, subset, x, y):
343 def rangeset(repo, subset, x, y):
343 m = getset(repo, fullreposet(repo), x)
344 m = getset(repo, fullreposet(repo), x)
344 n = getset(repo, fullreposet(repo), y)
345 n = getset(repo, fullreposet(repo), y)
345
346
346 if not m or not n:
347 if not m or not n:
347 return baseset()
348 return baseset()
348 m, n = m.first(), n.last()
349 m, n = m.first(), n.last()
349
350
350 if m < n:
351 if m < n:
351 r = spanset(repo, m, n + 1)
352 r = spanset(repo, m, n + 1)
352 else:
353 else:
353 r = spanset(repo, m, n - 1)
354 r = spanset(repo, m, n - 1)
354 return r & subset
355 return r & subset
355
356
356 def dagrange(repo, subset, x, y):
357 def dagrange(repo, subset, x, y):
357 r = fullreposet(repo)
358 r = fullreposet(repo)
358 xs = _revsbetween(repo, getset(repo, r, x), getset(repo, r, y))
359 xs = _revsbetween(repo, getset(repo, r, x), getset(repo, r, y))
359 return xs & subset
360 return xs & subset
360
361
361 def andset(repo, subset, x, y):
362 def andset(repo, subset, x, y):
362 return getset(repo, getset(repo, subset, x), y)
363 return getset(repo, getset(repo, subset, x), y)
363
364
364 def orset(repo, subset, x, y):
365 def orset(repo, subset, x, y):
365 xl = getset(repo, subset, x)
366 xl = getset(repo, subset, x)
366 yl = getset(repo, subset - xl, y)
367 yl = getset(repo, subset - xl, y)
367 return xl + yl
368 return xl + yl
368
369
369 def notset(repo, subset, x):
370 def notset(repo, subset, x):
370 return subset - getset(repo, subset, x)
371 return subset - getset(repo, subset, x)
371
372
372 def listset(repo, subset, a, b):
373 def listset(repo, subset, a, b):
373 raise error.ParseError(_("can't use a list in this context"))
374 raise error.ParseError(_("can't use a list in this context"))
374
375
375 def func(repo, subset, a, b):
376 def func(repo, subset, a, b):
376 if a[0] == 'symbol' and a[1] in symbols:
377 if a[0] == 'symbol' and a[1] in symbols:
377 return symbols[a[1]](repo, subset, b)
378 return symbols[a[1]](repo, subset, b)
378 raise error.UnknownIdentifier(a[1], symbols.keys())
379 raise error.UnknownIdentifier(a[1], symbols.keys())
379
380
380 # functions
381 # functions
381
382
382 def adds(repo, subset, x):
383 def adds(repo, subset, x):
383 """``adds(pattern)``
384 """``adds(pattern)``
384 Changesets that add a file matching pattern.
385 Changesets that add a file matching pattern.
385
386
386 The pattern without explicit kind like ``glob:`` is expected to be
387 The pattern without explicit kind like ``glob:`` is expected to be
387 relative to the current directory and match against a file or a
388 relative to the current directory and match against a file or a
388 directory.
389 directory.
389 """
390 """
390 # i18n: "adds" is a keyword
391 # i18n: "adds" is a keyword
391 pat = getstring(x, _("adds requires a pattern"))
392 pat = getstring(x, _("adds requires a pattern"))
392 return checkstatus(repo, subset, pat, 1)
393 return checkstatus(repo, subset, pat, 1)
393
394
394 def ancestor(repo, subset, x):
395 def ancestor(repo, subset, x):
395 """``ancestor(*changeset)``
396 """``ancestor(*changeset)``
396 A greatest common ancestor of the changesets.
397 A greatest common ancestor of the changesets.
397
398
398 Accepts 0 or more changesets.
399 Accepts 0 or more changesets.
399 Will return empty list when passed no args.
400 Will return empty list when passed no args.
400 Greatest common ancestor of a single changeset is that changeset.
401 Greatest common ancestor of a single changeset is that changeset.
401 """
402 """
402 # i18n: "ancestor" is a keyword
403 # i18n: "ancestor" is a keyword
403 l = getlist(x)
404 l = getlist(x)
404 rl = fullreposet(repo)
405 rl = fullreposet(repo)
405 anc = None
406 anc = None
406
407
407 # (getset(repo, rl, i) for i in l) generates a list of lists
408 # (getset(repo, rl, i) for i in l) generates a list of lists
408 for revs in (getset(repo, rl, i) for i in l):
409 for revs in (getset(repo, rl, i) for i in l):
409 for r in revs:
410 for r in revs:
410 if anc is None:
411 if anc is None:
411 anc = repo[r]
412 anc = repo[r]
412 else:
413 else:
413 anc = anc.ancestor(repo[r])
414 anc = anc.ancestor(repo[r])
414
415
415 if anc is not None and anc.rev() in subset:
416 if anc is not None and anc.rev() in subset:
416 return baseset([anc.rev()])
417 return baseset([anc.rev()])
417 return baseset()
418 return baseset()
418
419
419 def _ancestors(repo, subset, x, followfirst=False):
420 def _ancestors(repo, subset, x, followfirst=False):
420 heads = getset(repo, fullreposet(repo), x)
421 heads = getset(repo, fullreposet(repo), x)
421 if not heads:
422 if not heads:
422 return baseset()
423 return baseset()
423 s = _revancestors(repo, heads, followfirst)
424 s = _revancestors(repo, heads, followfirst)
424 return subset & s
425 return subset & s
425
426
426 def ancestors(repo, subset, x):
427 def ancestors(repo, subset, x):
427 """``ancestors(set)``
428 """``ancestors(set)``
428 Changesets that are ancestors of a changeset in set.
429 Changesets that are ancestors of a changeset in set.
429 """
430 """
430 return _ancestors(repo, subset, x)
431 return _ancestors(repo, subset, x)
431
432
432 def _firstancestors(repo, subset, x):
433 def _firstancestors(repo, subset, x):
433 # ``_firstancestors(set)``
434 # ``_firstancestors(set)``
434 # Like ``ancestors(set)`` but follows only the first parents.
435 # Like ``ancestors(set)`` but follows only the first parents.
435 return _ancestors(repo, subset, x, followfirst=True)
436 return _ancestors(repo, subset, x, followfirst=True)
436
437
437 def ancestorspec(repo, subset, x, n):
438 def ancestorspec(repo, subset, x, n):
438 """``set~n``
439 """``set~n``
439 Changesets that are the Nth ancestor (first parents only) of a changeset
440 Changesets that are the Nth ancestor (first parents only) of a changeset
440 in set.
441 in set.
441 """
442 """
442 try:
443 try:
443 n = int(n[1])
444 n = int(n[1])
444 except (TypeError, ValueError):
445 except (TypeError, ValueError):
445 raise error.ParseError(_("~ expects a number"))
446 raise error.ParseError(_("~ expects a number"))
446 ps = set()
447 ps = set()
447 cl = repo.changelog
448 cl = repo.changelog
448 for r in getset(repo, fullreposet(repo), x):
449 for r in getset(repo, fullreposet(repo), x):
449 for i in range(n):
450 for i in range(n):
450 r = cl.parentrevs(r)[0]
451 r = cl.parentrevs(r)[0]
451 ps.add(r)
452 ps.add(r)
452 return subset & ps
453 return subset & ps
453
454
454 def author(repo, subset, x):
455 def author(repo, subset, x):
455 """``author(string)``
456 """``author(string)``
456 Alias for ``user(string)``.
457 Alias for ``user(string)``.
457 """
458 """
458 # i18n: "author" is a keyword
459 # i18n: "author" is a keyword
459 n = encoding.lower(getstring(x, _("author requires a string")))
460 n = encoding.lower(getstring(x, _("author requires a string")))
460 kind, pattern, matcher = _substringmatcher(n)
461 kind, pattern, matcher = _substringmatcher(n)
461 return subset.filter(lambda x: matcher(encoding.lower(repo[x].user())))
462 return subset.filter(lambda x: matcher(encoding.lower(repo[x].user())))
462
463
463 def bisect(repo, subset, x):
464 def bisect(repo, subset, x):
464 """``bisect(string)``
465 """``bisect(string)``
465 Changesets marked in the specified bisect status:
466 Changesets marked in the specified bisect status:
466
467
467 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
468 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
468 - ``goods``, ``bads`` : csets topologically good/bad
469 - ``goods``, ``bads`` : csets topologically good/bad
469 - ``range`` : csets taking part in the bisection
470 - ``range`` : csets taking part in the bisection
470 - ``pruned`` : csets that are goods, bads or skipped
471 - ``pruned`` : csets that are goods, bads or skipped
471 - ``untested`` : csets whose fate is yet unknown
472 - ``untested`` : csets whose fate is yet unknown
472 - ``ignored`` : csets ignored due to DAG topology
473 - ``ignored`` : csets ignored due to DAG topology
473 - ``current`` : the cset currently being bisected
474 - ``current`` : the cset currently being bisected
474 """
475 """
475 # i18n: "bisect" is a keyword
476 # i18n: "bisect" is a keyword
476 status = getstring(x, _("bisect requires a string")).lower()
477 status = getstring(x, _("bisect requires a string")).lower()
477 state = set(hbisect.get(repo, status))
478 state = set(hbisect.get(repo, status))
478 return subset & state
479 return subset & state
479
480
480 # Backward-compatibility
481 # Backward-compatibility
481 # - no help entry so that we do not advertise it any more
482 # - no help entry so that we do not advertise it any more
482 def bisected(repo, subset, x):
483 def bisected(repo, subset, x):
483 return bisect(repo, subset, x)
484 return bisect(repo, subset, x)
484
485
485 def bookmark(repo, subset, x):
486 def bookmark(repo, subset, x):
486 """``bookmark([name])``
487 """``bookmark([name])``
487 The named bookmark or all bookmarks.
488 The named bookmark or all bookmarks.
488
489
489 If `name` starts with `re:`, the remainder of the name is treated as
490 If `name` starts with `re:`, the remainder of the name is treated as
490 a regular expression. To match a bookmark that actually starts with `re:`,
491 a regular expression. To match a bookmark that actually starts with `re:`,
491 use the prefix `literal:`.
492 use the prefix `literal:`.
492 """
493 """
493 # i18n: "bookmark" is a keyword
494 # i18n: "bookmark" is a keyword
494 args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
495 args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
495 if args:
496 if args:
496 bm = getstring(args[0],
497 bm = getstring(args[0],
497 # i18n: "bookmark" is a keyword
498 # i18n: "bookmark" is a keyword
498 _('the argument to bookmark must be a string'))
499 _('the argument to bookmark must be a string'))
499 kind, pattern, matcher = _stringmatcher(bm)
500 kind, pattern, matcher = _stringmatcher(bm)
500 bms = set()
501 bms = set()
501 if kind == 'literal':
502 if kind == 'literal':
502 bmrev = repo._bookmarks.get(pattern, None)
503 bmrev = repo._bookmarks.get(pattern, None)
503 if not bmrev:
504 if not bmrev:
504 raise error.RepoLookupError(_("bookmark '%s' does not exist")
505 raise error.RepoLookupError(_("bookmark '%s' does not exist")
505 % bm)
506 % bm)
506 bms.add(repo[bmrev].rev())
507 bms.add(repo[bmrev].rev())
507 else:
508 else:
508 matchrevs = set()
509 matchrevs = set()
509 for name, bmrev in repo._bookmarks.iteritems():
510 for name, bmrev in repo._bookmarks.iteritems():
510 if matcher(name):
511 if matcher(name):
511 matchrevs.add(bmrev)
512 matchrevs.add(bmrev)
512 if not matchrevs:
513 if not matchrevs:
513 raise error.RepoLookupError(_("no bookmarks exist"
514 raise error.RepoLookupError(_("no bookmarks exist"
514 " that match '%s'") % pattern)
515 " that match '%s'") % pattern)
515 for bmrev in matchrevs:
516 for bmrev in matchrevs:
516 bms.add(repo[bmrev].rev())
517 bms.add(repo[bmrev].rev())
517 else:
518 else:
518 bms = set([repo[r].rev()
519 bms = set([repo[r].rev()
519 for r in repo._bookmarks.values()])
520 for r in repo._bookmarks.values()])
520 bms -= set([node.nullrev])
521 bms -= set([node.nullrev])
521 return subset & bms
522 return subset & bms
522
523
523 def branch(repo, subset, x):
524 def branch(repo, subset, x):
524 """``branch(string or set)``
525 """``branch(string or set)``
525 All changesets belonging to the given branch or the branches of the given
526 All changesets belonging to the given branch or the branches of the given
526 changesets.
527 changesets.
527
528
528 If `string` starts with `re:`, the remainder of the name is treated as
529 If `string` starts with `re:`, the remainder of the name is treated as
529 a regular expression. To match a branch that actually starts with `re:`,
530 a regular expression. To match a branch that actually starts with `re:`,
530 use the prefix `literal:`.
531 use the prefix `literal:`.
531 """
532 """
532 getbi = repo.revbranchcache().branchinfo
533 getbi = repo.revbranchcache().branchinfo
533
534
534 try:
535 try:
535 b = getstring(x, '')
536 b = getstring(x, '')
536 except error.ParseError:
537 except error.ParseError:
537 # not a string, but another revspec, e.g. tip()
538 # not a string, but another revspec, e.g. tip()
538 pass
539 pass
539 else:
540 else:
540 kind, pattern, matcher = _stringmatcher(b)
541 kind, pattern, matcher = _stringmatcher(b)
541 if kind == 'literal':
542 if kind == 'literal':
542 # note: falls through to the revspec case if no branch with
543 # note: falls through to the revspec case if no branch with
543 # this name exists
544 # this name exists
544 if pattern in repo.branchmap():
545 if pattern in repo.branchmap():
545 return subset.filter(lambda r: matcher(getbi(r)[0]))
546 return subset.filter(lambda r: matcher(getbi(r)[0]))
546 else:
547 else:
547 return subset.filter(lambda r: matcher(getbi(r)[0]))
548 return subset.filter(lambda r: matcher(getbi(r)[0]))
548
549
549 s = getset(repo, fullreposet(repo), x)
550 s = getset(repo, fullreposet(repo), x)
550 b = set()
551 b = set()
551 for r in s:
552 for r in s:
552 b.add(getbi(r)[0])
553 b.add(getbi(r)[0])
553 c = s.__contains__
554 c = s.__contains__
554 return subset.filter(lambda r: c(r) or getbi(r)[0] in b)
555 return subset.filter(lambda r: c(r) or getbi(r)[0] in b)
555
556
556 def bumped(repo, subset, x):
557 def bumped(repo, subset, x):
557 """``bumped()``
558 """``bumped()``
558 Mutable changesets marked as successors of public changesets.
559 Mutable changesets marked as successors of public changesets.
559
560
560 Only non-public and non-obsolete changesets can be `bumped`.
561 Only non-public and non-obsolete changesets can be `bumped`.
561 """
562 """
562 # i18n: "bumped" is a keyword
563 # i18n: "bumped" is a keyword
563 getargs(x, 0, 0, _("bumped takes no arguments"))
564 getargs(x, 0, 0, _("bumped takes no arguments"))
564 bumped = obsmod.getrevs(repo, 'bumped')
565 bumped = obsmod.getrevs(repo, 'bumped')
565 return subset & bumped
566 return subset & bumped
566
567
567 def bundle(repo, subset, x):
568 def bundle(repo, subset, x):
568 """``bundle()``
569 """``bundle()``
569 Changesets in the bundle.
570 Changesets in the bundle.
570
571
571 Bundle must be specified by the -R option."""
572 Bundle must be specified by the -R option."""
572
573
573 try:
574 try:
574 bundlerevs = repo.changelog.bundlerevs
575 bundlerevs = repo.changelog.bundlerevs
575 except AttributeError:
576 except AttributeError:
576 raise util.Abort(_("no bundle provided - specify with -R"))
577 raise util.Abort(_("no bundle provided - specify with -R"))
577 return subset & bundlerevs
578 return subset & bundlerevs
578
579
579 def checkstatus(repo, subset, pat, field):
580 def checkstatus(repo, subset, pat, field):
580 hasset = matchmod.patkind(pat) == 'set'
581 hasset = matchmod.patkind(pat) == 'set'
581
582
582 mcache = [None]
583 mcache = [None]
583 def matches(x):
584 def matches(x):
584 c = repo[x]
585 c = repo[x]
585 if not mcache[0] or hasset:
586 if not mcache[0] or hasset:
586 mcache[0] = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
587 mcache[0] = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
587 m = mcache[0]
588 m = mcache[0]
588 fname = None
589 fname = None
589 if not m.anypats() and len(m.files()) == 1:
590 if not m.anypats() and len(m.files()) == 1:
590 fname = m.files()[0]
591 fname = m.files()[0]
591 if fname is not None:
592 if fname is not None:
592 if fname not in c.files():
593 if fname not in c.files():
593 return False
594 return False
594 else:
595 else:
595 for f in c.files():
596 for f in c.files():
596 if m(f):
597 if m(f):
597 break
598 break
598 else:
599 else:
599 return False
600 return False
600 files = repo.status(c.p1().node(), c.node())[field]
601 files = repo.status(c.p1().node(), c.node())[field]
601 if fname is not None:
602 if fname is not None:
602 if fname in files:
603 if fname in files:
603 return True
604 return True
604 else:
605 else:
605 for f in files:
606 for f in files:
606 if m(f):
607 if m(f):
607 return True
608 return True
608
609
609 return subset.filter(matches)
610 return subset.filter(matches)
610
611
611 def _children(repo, narrow, parentset):
612 def _children(repo, narrow, parentset):
612 cs = set()
613 cs = set()
613 if not parentset:
614 if not parentset:
614 return baseset(cs)
615 return baseset(cs)
615 pr = repo.changelog.parentrevs
616 pr = repo.changelog.parentrevs
616 minrev = min(parentset)
617 minrev = min(parentset)
617 for r in narrow:
618 for r in narrow:
618 if r <= minrev:
619 if r <= minrev:
619 continue
620 continue
620 for p in pr(r):
621 for p in pr(r):
621 if p in parentset:
622 if p in parentset:
622 cs.add(r)
623 cs.add(r)
623 return baseset(cs)
624 return baseset(cs)
624
625
625 def children(repo, subset, x):
626 def children(repo, subset, x):
626 """``children(set)``
627 """``children(set)``
627 Child changesets of changesets in set.
628 Child changesets of changesets in set.
628 """
629 """
629 s = getset(repo, fullreposet(repo), x)
630 s = getset(repo, fullreposet(repo), x)
630 cs = _children(repo, subset, s)
631 cs = _children(repo, subset, s)
631 return subset & cs
632 return subset & cs
632
633
633 def closed(repo, subset, x):
634 def closed(repo, subset, x):
634 """``closed()``
635 """``closed()``
635 Changeset is closed.
636 Changeset is closed.
636 """
637 """
637 # i18n: "closed" is a keyword
638 # i18n: "closed" is a keyword
638 getargs(x, 0, 0, _("closed takes no arguments"))
639 getargs(x, 0, 0, _("closed takes no arguments"))
639 return subset.filter(lambda r: repo[r].closesbranch())
640 return subset.filter(lambda r: repo[r].closesbranch())
640
641
641 def contains(repo, subset, x):
642 def contains(repo, subset, x):
642 """``contains(pattern)``
643 """``contains(pattern)``
643 The revision's manifest contains a file matching pattern (but might not
644 The revision's manifest contains a file matching pattern (but might not
644 modify it). See :hg:`help patterns` for information about file patterns.
645 modify it). See :hg:`help patterns` for information about file patterns.
645
646
646 The pattern without explicit kind like ``glob:`` is expected to be
647 The pattern without explicit kind like ``glob:`` is expected to be
647 relative to the current directory and match against a file exactly
648 relative to the current directory and match against a file exactly
648 for efficiency.
649 for efficiency.
649 """
650 """
650 # i18n: "contains" is a keyword
651 # i18n: "contains" is a keyword
651 pat = getstring(x, _("contains requires a pattern"))
652 pat = getstring(x, _("contains requires a pattern"))
652
653
653 def matches(x):
654 def matches(x):
654 if not matchmod.patkind(pat):
655 if not matchmod.patkind(pat):
655 pats = pathutil.canonpath(repo.root, repo.getcwd(), pat)
656 pats = pathutil.canonpath(repo.root, repo.getcwd(), pat)
656 if pats in repo[x]:
657 if pats in repo[x]:
657 return True
658 return True
658 else:
659 else:
659 c = repo[x]
660 c = repo[x]
660 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
661 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
661 for f in c.manifest():
662 for f in c.manifest():
662 if m(f):
663 if m(f):
663 return True
664 return True
664 return False
665 return False
665
666
666 return subset.filter(matches)
667 return subset.filter(matches)
667
668
668 def converted(repo, subset, x):
669 def converted(repo, subset, x):
669 """``converted([id])``
670 """``converted([id])``
670 Changesets converted from the given identifier in the old repository if
671 Changesets converted from the given identifier in the old repository if
671 present, or all converted changesets if no identifier is specified.
672 present, or all converted changesets if no identifier is specified.
672 """
673 """
673
674
674 # There is exactly no chance of resolving the revision, so do a simple
675 # There is exactly no chance of resolving the revision, so do a simple
675 # string compare and hope for the best
676 # string compare and hope for the best
676
677
677 rev = None
678 rev = None
678 # i18n: "converted" is a keyword
679 # i18n: "converted" is a keyword
679 l = getargs(x, 0, 1, _('converted takes one or no arguments'))
680 l = getargs(x, 0, 1, _('converted takes one or no arguments'))
680 if l:
681 if l:
681 # i18n: "converted" is a keyword
682 # i18n: "converted" is a keyword
682 rev = getstring(l[0], _('converted requires a revision'))
683 rev = getstring(l[0], _('converted requires a revision'))
683
684
684 def _matchvalue(r):
685 def _matchvalue(r):
685 source = repo[r].extra().get('convert_revision', None)
686 source = repo[r].extra().get('convert_revision', None)
686 return source is not None and (rev is None or source.startswith(rev))
687 return source is not None and (rev is None or source.startswith(rev))
687
688
688 return subset.filter(lambda r: _matchvalue(r))
689 return subset.filter(lambda r: _matchvalue(r))
689
690
690 def date(repo, subset, x):
691 def date(repo, subset, x):
691 """``date(interval)``
692 """``date(interval)``
692 Changesets within the interval, see :hg:`help dates`.
693 Changesets within the interval, see :hg:`help dates`.
693 """
694 """
694 # i18n: "date" is a keyword
695 # i18n: "date" is a keyword
695 ds = getstring(x, _("date requires a string"))
696 ds = getstring(x, _("date requires a string"))
696 dm = util.matchdate(ds)
697 dm = util.matchdate(ds)
697 return subset.filter(lambda x: dm(repo[x].date()[0]))
698 return subset.filter(lambda x: dm(repo[x].date()[0]))
698
699
699 def desc(repo, subset, x):
700 def desc(repo, subset, x):
700 """``desc(string)``
701 """``desc(string)``
701 Search commit message for string. The match is case-insensitive.
702 Search commit message for string. The match is case-insensitive.
702 """
703 """
703 # i18n: "desc" is a keyword
704 # i18n: "desc" is a keyword
704 ds = encoding.lower(getstring(x, _("desc requires a string")))
705 ds = encoding.lower(getstring(x, _("desc requires a string")))
705
706
706 def matches(x):
707 def matches(x):
707 c = repo[x]
708 c = repo[x]
708 return ds in encoding.lower(c.description())
709 return ds in encoding.lower(c.description())
709
710
710 return subset.filter(matches)
711 return subset.filter(matches)
711
712
712 def _descendants(repo, subset, x, followfirst=False):
713 def _descendants(repo, subset, x, followfirst=False):
713 roots = getset(repo, fullreposet(repo), x)
714 roots = getset(repo, fullreposet(repo), x)
714 if not roots:
715 if not roots:
715 return baseset()
716 return baseset()
716 s = _revdescendants(repo, roots, followfirst)
717 s = _revdescendants(repo, roots, followfirst)
717
718
718 # Both sets need to be ascending in order to lazily return the union
719 # Both sets need to be ascending in order to lazily return the union
719 # in the correct order.
720 # in the correct order.
720 base = subset & roots
721 base = subset & roots
721 desc = subset & s
722 desc = subset & s
722 result = base + desc
723 result = base + desc
723 if subset.isascending():
724 if subset.isascending():
724 result.sort()
725 result.sort()
725 elif subset.isdescending():
726 elif subset.isdescending():
726 result.sort(reverse=True)
727 result.sort(reverse=True)
727 else:
728 else:
728 result = subset & result
729 result = subset & result
729 return result
730 return result
730
731
731 def descendants(repo, subset, x):
732 def descendants(repo, subset, x):
732 """``descendants(set)``
733 """``descendants(set)``
733 Changesets which are descendants of changesets in set.
734 Changesets which are descendants of changesets in set.
734 """
735 """
735 return _descendants(repo, subset, x)
736 return _descendants(repo, subset, x)
736
737
737 def _firstdescendants(repo, subset, x):
738 def _firstdescendants(repo, subset, x):
738 # ``_firstdescendants(set)``
739 # ``_firstdescendants(set)``
739 # Like ``descendants(set)`` but follows only the first parents.
740 # Like ``descendants(set)`` but follows only the first parents.
740 return _descendants(repo, subset, x, followfirst=True)
741 return _descendants(repo, subset, x, followfirst=True)
741
742
742 def destination(repo, subset, x):
743 def destination(repo, subset, x):
743 """``destination([set])``
744 """``destination([set])``
744 Changesets that were created by a graft, transplant or rebase operation,
745 Changesets that were created by a graft, transplant or rebase operation,
745 with the given revisions specified as the source. Omitting the optional set
746 with the given revisions specified as the source. Omitting the optional set
746 is the same as passing all().
747 is the same as passing all().
747 """
748 """
748 if x is not None:
749 if x is not None:
749 sources = getset(repo, fullreposet(repo), x)
750 sources = getset(repo, fullreposet(repo), x)
750 else:
751 else:
751 sources = fullreposet(repo)
752 sources = fullreposet(repo)
752
753
753 dests = set()
754 dests = set()
754
755
755 # subset contains all of the possible destinations that can be returned, so
756 # subset contains all of the possible destinations that can be returned, so
756 # iterate over them and see if their source(s) were provided in the arg set.
757 # iterate over them and see if their source(s) were provided in the arg set.
757 # Even if the immediate src of r is not in the arg set, src's source (or
758 # Even if the immediate src of r is not in the arg set, src's source (or
758 # further back) may be. Scanning back further than the immediate src allows
759 # further back) may be. Scanning back further than the immediate src allows
759 # transitive transplants and rebases to yield the same results as transitive
760 # transitive transplants and rebases to yield the same results as transitive
760 # grafts.
761 # grafts.
761 for r in subset:
762 for r in subset:
762 src = _getrevsource(repo, r)
763 src = _getrevsource(repo, r)
763 lineage = None
764 lineage = None
764
765
765 while src is not None:
766 while src is not None:
766 if lineage is None:
767 if lineage is None:
767 lineage = list()
768 lineage = list()
768
769
769 lineage.append(r)
770 lineage.append(r)
770
771
771 # The visited lineage is a match if the current source is in the arg
772 # The visited lineage is a match if the current source is in the arg
772 # set. Since every candidate dest is visited by way of iterating
773 # set. Since every candidate dest is visited by way of iterating
773 # subset, any dests further back in the lineage will be tested by a
774 # subset, any dests further back in the lineage will be tested by a
774 # different iteration over subset. Likewise, if the src was already
775 # different iteration over subset. Likewise, if the src was already
775 # selected, the current lineage can be selected without going back
776 # selected, the current lineage can be selected without going back
776 # further.
777 # further.
777 if src in sources or src in dests:
778 if src in sources or src in dests:
778 dests.update(lineage)
779 dests.update(lineage)
779 break
780 break
780
781
781 r = src
782 r = src
782 src = _getrevsource(repo, r)
783 src = _getrevsource(repo, r)
783
784
784 return subset.filter(dests.__contains__)
785 return subset.filter(dests.__contains__)
785
786
786 def divergent(repo, subset, x):
787 def divergent(repo, subset, x):
787 """``divergent()``
788 """``divergent()``
788 Final successors of changesets with an alternative set of final successors.
789 Final successors of changesets with an alternative set of final successors.
789 """
790 """
790 # i18n: "divergent" is a keyword
791 # i18n: "divergent" is a keyword
791 getargs(x, 0, 0, _("divergent takes no arguments"))
792 getargs(x, 0, 0, _("divergent takes no arguments"))
792 divergent = obsmod.getrevs(repo, 'divergent')
793 divergent = obsmod.getrevs(repo, 'divergent')
793 return subset & divergent
794 return subset & divergent
794
795
795 def draft(repo, subset, x):
796 def draft(repo, subset, x):
796 """``draft()``
797 """``draft()``
797 Changeset in draft phase."""
798 Changeset in draft phase."""
798 # i18n: "draft" is a keyword
799 # i18n: "draft" is a keyword
799 getargs(x, 0, 0, _("draft takes no arguments"))
800 getargs(x, 0, 0, _("draft takes no arguments"))
800 phase = repo._phasecache.phase
801 phase = repo._phasecache.phase
801 target = phases.draft
802 target = phases.draft
802 condition = lambda r: phase(repo, r) == target
803 condition = lambda r: phase(repo, r) == target
803 return subset.filter(condition, cache=False)
804 return subset.filter(condition, cache=False)
804
805
805 def extinct(repo, subset, x):
806 def extinct(repo, subset, x):
806 """``extinct()``
807 """``extinct()``
807 Obsolete changesets with obsolete descendants only.
808 Obsolete changesets with obsolete descendants only.
808 """
809 """
809 # i18n: "extinct" is a keyword
810 # i18n: "extinct" is a keyword
810 getargs(x, 0, 0, _("extinct takes no arguments"))
811 getargs(x, 0, 0, _("extinct takes no arguments"))
811 extincts = obsmod.getrevs(repo, 'extinct')
812 extincts = obsmod.getrevs(repo, 'extinct')
812 return subset & extincts
813 return subset & extincts
813
814
814 def extra(repo, subset, x):
815 def extra(repo, subset, x):
815 """``extra(label, [value])``
816 """``extra(label, [value])``
816 Changesets with the given label in the extra metadata, with the given
817 Changesets with the given label in the extra metadata, with the given
817 optional value.
818 optional value.
818
819
819 If `value` starts with `re:`, the remainder of the value is treated as
820 If `value` starts with `re:`, the remainder of the value is treated as
820 a regular expression. To match a value that actually starts with `re:`,
821 a regular expression. To match a value that actually starts with `re:`,
821 use the prefix `literal:`.
822 use the prefix `literal:`.
822 """
823 """
823
824
824 # i18n: "extra" is a keyword
825 # i18n: "extra" is a keyword
825 l = getargs(x, 1, 2, _('extra takes at least 1 and at most 2 arguments'))
826 l = getargs(x, 1, 2, _('extra takes at least 1 and at most 2 arguments'))
826 # i18n: "extra" is a keyword
827 # i18n: "extra" is a keyword
827 label = getstring(l[0], _('first argument to extra must be a string'))
828 label = getstring(l[0], _('first argument to extra must be a string'))
828 value = None
829 value = None
829
830
830 if len(l) > 1:
831 if len(l) > 1:
831 # i18n: "extra" is a keyword
832 # i18n: "extra" is a keyword
832 value = getstring(l[1], _('second argument to extra must be a string'))
833 value = getstring(l[1], _('second argument to extra must be a string'))
833 kind, value, matcher = _stringmatcher(value)
834 kind, value, matcher = _stringmatcher(value)
834
835
835 def _matchvalue(r):
836 def _matchvalue(r):
836 extra = repo[r].extra()
837 extra = repo[r].extra()
837 return label in extra and (value is None or matcher(extra[label]))
838 return label in extra and (value is None or matcher(extra[label]))
838
839
839 return subset.filter(lambda r: _matchvalue(r))
840 return subset.filter(lambda r: _matchvalue(r))
840
841
841 def filelog(repo, subset, x):
842 def filelog(repo, subset, x):
842 """``filelog(pattern)``
843 """``filelog(pattern)``
843 Changesets connected to the specified filelog.
844 Changesets connected to the specified filelog.
844
845
845 For performance reasons, visits only revisions mentioned in the file-level
846 For performance reasons, visits only revisions mentioned in the file-level
846 filelog, rather than filtering through all changesets (much faster, but
847 filelog, rather than filtering through all changesets (much faster, but
847 doesn't include deletes or duplicate changes). For a slower, more accurate
848 doesn't include deletes or duplicate changes). For a slower, more accurate
848 result, use ``file()``.
849 result, use ``file()``.
849
850
850 The pattern without explicit kind like ``glob:`` is expected to be
851 The pattern without explicit kind like ``glob:`` is expected to be
851 relative to the current directory and match against a file exactly
852 relative to the current directory and match against a file exactly
852 for efficiency.
853 for efficiency.
853
854
854 If some linkrev points to revisions filtered by the current repoview, we'll
855 If some linkrev points to revisions filtered by the current repoview, we'll
855 work around it to return a non-filtered value.
856 work around it to return a non-filtered value.
856 """
857 """
857
858
858 # i18n: "filelog" is a keyword
859 # i18n: "filelog" is a keyword
859 pat = getstring(x, _("filelog requires a pattern"))
860 pat = getstring(x, _("filelog requires a pattern"))
860 s = set()
861 s = set()
861 cl = repo.changelog
862 cl = repo.changelog
862
863
863 if not matchmod.patkind(pat):
864 if not matchmod.patkind(pat):
864 f = pathutil.canonpath(repo.root, repo.getcwd(), pat)
865 f = pathutil.canonpath(repo.root, repo.getcwd(), pat)
865 files = [f]
866 files = [f]
866 else:
867 else:
867 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[None])
868 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[None])
868 files = (f for f in repo[None] if m(f))
869 files = (f for f in repo[None] if m(f))
869
870
870 for f in files:
871 for f in files:
871 backrevref = {} # final value for: filerev -> changerev
872 backrevref = {} # final value for: filerev -> changerev
872 lowestchild = {} # lowest known filerev child of a filerev
873 lowestchild = {} # lowest known filerev child of a filerev
873 delayed = [] # filerev with filtered linkrev, for post-processing
874 delayed = [] # filerev with filtered linkrev, for post-processing
874 lowesthead = None # cache for manifest content of all head revisions
875 lowesthead = None # cache for manifest content of all head revisions
875 fl = repo.file(f)
876 fl = repo.file(f)
876 for fr in list(fl):
877 for fr in list(fl):
877 rev = fl.linkrev(fr)
878 rev = fl.linkrev(fr)
878 if rev not in cl:
879 if rev not in cl:
879 # changerev pointed in linkrev is filtered
880 # changerev pointed in linkrev is filtered
880 # record it for post processing.
881 # record it for post processing.
881 delayed.append((fr, rev))
882 delayed.append((fr, rev))
882 continue
883 continue
883 for p in fl.parentrevs(fr):
884 for p in fl.parentrevs(fr):
884 if 0 <= p and p not in lowestchild:
885 if 0 <= p and p not in lowestchild:
885 lowestchild[p] = fr
886 lowestchild[p] = fr
886 backrevref[fr] = rev
887 backrevref[fr] = rev
887 s.add(rev)
888 s.add(rev)
888
889
889 # Post-processing of all filerevs we skipped because they were
890 # Post-processing of all filerevs we skipped because they were
890 # filtered. If such filerevs have known and unfiltered children, this
891 # filtered. If such filerevs have known and unfiltered children, this
891 # means they have an unfiltered appearance out there. We'll use linkrev
892 # means they have an unfiltered appearance out there. We'll use linkrev
892 # adjustment to find one of these appearances. The lowest known child
893 # adjustment to find one of these appearances. The lowest known child
893 # will be used as a starting point because it is the best upper-bound we
894 # will be used as a starting point because it is the best upper-bound we
894 # have.
895 # have.
895 #
896 #
896 # This approach will fail when an unfiltered but linkrev-shadowed
897 # This approach will fail when an unfiltered but linkrev-shadowed
897 # appearance exists in a head changeset without unfiltered filerev
898 # appearance exists in a head changeset without unfiltered filerev
898 # children anywhere.
899 # children anywhere.
899 while delayed:
900 while delayed:
900 # must be a descending iteration. To slowly fill lowest child
901 # must be a descending iteration. To slowly fill lowest child
901 # information that is of potential use by the next item.
902 # information that is of potential use by the next item.
902 fr, rev = delayed.pop()
903 fr, rev = delayed.pop()
903 lkr = rev
904 lkr = rev
904
905
905 child = lowestchild.get(fr)
906 child = lowestchild.get(fr)
906
907
907 if child is None:
908 if child is None:
908 # search for existence of this file revision in a head revision.
909 # search for existence of this file revision in a head revision.
909 # There are three possibilities:
910 # There are three possibilities:
910 # - the revision exists in a head and we can find an
911 # - the revision exists in a head and we can find an
911 # introduction from there,
912 # introduction from there,
912 # - the revision does not exist in a head because it has been
913 # - the revision does not exist in a head because it has been
913 # changed since its introduction: we would have found a child
914 # changed since its introduction: we would have found a child
914 # and be in the other 'else' clause,
915 # and be in the other 'else' clause,
915 # - all versions of the revision are hidden.
916 # - all versions of the revision are hidden.
916 if lowesthead is None:
917 if lowesthead is None:
917 lowesthead = {}
918 lowesthead = {}
918 for h in repo.heads():
919 for h in repo.heads():
919 fnode = repo[h].manifest().get(f)
920 fnode = repo[h].manifest().get(f)
920 if fnode is not None:
921 if fnode is not None:
921 lowesthead[fl.rev(fnode)] = h
922 lowesthead[fl.rev(fnode)] = h
922 headrev = lowesthead.get(fr)
923 headrev = lowesthead.get(fr)
923 if headrev is None:
924 if headrev is None:
924 # content is nowhere unfiltered
925 # content is nowhere unfiltered
925 continue
926 continue
926 rev = repo[headrev][f].introrev()
927 rev = repo[headrev][f].introrev()
927 else:
928 else:
928 # the lowest known child is a good upper bound
929 # the lowest known child is a good upper bound
929 childcrev = backrevref[child]
930 childcrev = backrevref[child]
930 # XXX this does not guarantee returning the lowest
931 # XXX this does not guarantee returning the lowest
931 # introduction of this revision, but this gives a
932 # introduction of this revision, but this gives a
932 # result which is a good start and will fit in most
933 # result which is a good start and will fit in most
933 # cases. We probably need to fix the multiple
934 # cases. We probably need to fix the multiple
934 # introductions case properly (report each
935 # introductions case properly (report each
935 # introduction, even for identical file revisions)
936 # introduction, even for identical file revisions)
936 # once and for all at some point anyway.
937 # once and for all at some point anyway.
937 for p in repo[childcrev][f].parents():
938 for p in repo[childcrev][f].parents():
938 if p.filerev() == fr:
939 if p.filerev() == fr:
939 rev = p.rev()
940 rev = p.rev()
940 break
941 break
941 if rev == lkr: # no shadowed entry found
942 if rev == lkr: # no shadowed entry found
942 # XXX This should never happen unless some manifest points
943 # XXX This should never happen unless some manifest points
943 # to biggish file revisions (like a revision that uses a
944 # to biggish file revisions (like a revision that uses a
944 # parent that never appears in the manifest ancestors)
945 # parent that never appears in the manifest ancestors)
945 continue
946 continue
946
947
947 # Fill the data for the next iteration.
948 # Fill the data for the next iteration.
948 for p in fl.parentrevs(fr):
949 for p in fl.parentrevs(fr):
949 if 0 <= p and p not in lowestchild:
950 if 0 <= p and p not in lowestchild:
950 lowestchild[p] = fr
951 lowestchild[p] = fr
951 backrevref[fr] = rev
952 backrevref[fr] = rev
952 s.add(rev)
953 s.add(rev)
953
954
954 return subset & s
955 return subset & s
955
956
956 def first(repo, subset, x):
957 def first(repo, subset, x):
957 """``first(set, [n])``
958 """``first(set, [n])``
958 An alias for limit().
959 An alias for limit().
959 """
960 """
960 return limit(repo, subset, x)
961 return limit(repo, subset, x)
961
962
962 def _follow(repo, subset, x, name, followfirst=False):
963 def _follow(repo, subset, x, name, followfirst=False):
963 l = getargs(x, 0, 1, _("%s takes no arguments or a filename") % name)
964 l = getargs(x, 0, 1, _("%s takes no arguments or a filename") % name)
964 c = repo['.']
965 c = repo['.']
965 if l:
966 if l:
966 x = getstring(l[0], _("%s expected a filename") % name)
967 x = getstring(l[0], _("%s expected a filename") % name)
967 if x in c:
968 if x in c:
968 cx = c[x]
969 cx = c[x]
969 s = set(ctx.rev() for ctx in cx.ancestors(followfirst=followfirst))
970 s = set(ctx.rev() for ctx in cx.ancestors(followfirst=followfirst))
970 # include the revision responsible for the most recent version
971 # include the revision responsible for the most recent version
971 s.add(cx.introrev())
972 s.add(cx.introrev())
972 else:
973 else:
973 return baseset()
974 return baseset()
974 else:
975 else:
975 s = _revancestors(repo, baseset([c.rev()]), followfirst)
976 s = _revancestors(repo, baseset([c.rev()]), followfirst)
976
977
977 return subset & s
978 return subset & s
978
979
979 def follow(repo, subset, x):
980 def follow(repo, subset, x):
980 """``follow([file])``
981 """``follow([file])``
981 An alias for ``::.`` (ancestors of the working directory's first parent).
982 An alias for ``::.`` (ancestors of the working directory's first parent).
982 If a filename is specified, the history of the given file is followed,
983 If a filename is specified, the history of the given file is followed,
983 including copies.
984 including copies.
984 """
985 """
985 return _follow(repo, subset, x, 'follow')
986 return _follow(repo, subset, x, 'follow')
986
987
987 def _followfirst(repo, subset, x):
988 def _followfirst(repo, subset, x):
988 # ``followfirst([file])``
989 # ``followfirst([file])``
989 # Like ``follow([file])`` but follows only the first parent of
990 # Like ``follow([file])`` but follows only the first parent of
990 # every revision or file revision.
991 # every revision or file revision.
991 return _follow(repo, subset, x, '_followfirst', followfirst=True)
992 return _follow(repo, subset, x, '_followfirst', followfirst=True)
992
993
993 def getall(repo, subset, x):
994 def getall(repo, subset, x):
994 """``all()``
995 """``all()``
995 All changesets, the same as ``0:tip``.
996 All changesets, the same as ``0:tip``.
996 """
997 """
997 # i18n: "all" is a keyword
998 # i18n: "all" is a keyword
998 getargs(x, 0, 0, _("all takes no arguments"))
999 getargs(x, 0, 0, _("all takes no arguments"))
999 return subset & spanset(repo) # drop "null" if any
1000 return subset & spanset(repo) # drop "null" if any
1000
1001
1001 def grep(repo, subset, x):
1002 def grep(repo, subset, x):
1002 """``grep(regex)``
1003 """``grep(regex)``
1003 Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
1004 Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
1004 to ensure special escape characters are handled correctly. Unlike
1005 to ensure special escape characters are handled correctly. Unlike
1005 ``keyword(string)``, the match is case-sensitive.
1006 ``keyword(string)``, the match is case-sensitive.
1006 """
1007 """
1007 try:
1008 try:
1008 # i18n: "grep" is a keyword
1009 # i18n: "grep" is a keyword
1009 gr = re.compile(getstring(x, _("grep requires a string")))
1010 gr = re.compile(getstring(x, _("grep requires a string")))
1010 except re.error, e:
1011 except re.error, e:
1011 raise error.ParseError(_('invalid match pattern: %s') % e)
1012 raise error.ParseError(_('invalid match pattern: %s') % e)
1012
1013
1013 def matches(x):
1014 def matches(x):
1014 c = repo[x]
1015 c = repo[x]
1015 for e in c.files() + [c.user(), c.description()]:
1016 for e in c.files() + [c.user(), c.description()]:
1016 if gr.search(e):
1017 if gr.search(e):
1017 return True
1018 return True
1018 return False
1019 return False
1019
1020
1020 return subset.filter(matches)
1021 return subset.filter(matches)
1021
1022
1022 def _matchfiles(repo, subset, x):
1023 def _matchfiles(repo, subset, x):
1023 # _matchfiles takes a revset list of prefixed arguments:
1024 # _matchfiles takes a revset list of prefixed arguments:
1024 #
1025 #
1025 # [p:foo, i:bar, x:baz]
1026 # [p:foo, i:bar, x:baz]
1026 #
1027 #
1027 # builds a match object from them and filters subset. Allowed
1028 # builds a match object from them and filters subset. Allowed
1028 # prefixes are 'p:' for regular patterns, 'i:' for include
1029 # prefixes are 'p:' for regular patterns, 'i:' for include
1029 # patterns and 'x:' for exclude patterns. Use 'r:' prefix to pass
1030 # patterns and 'x:' for exclude patterns. Use 'r:' prefix to pass
1030 # a revision identifier, or the empty string to reference the
1031 # a revision identifier, or the empty string to reference the
1031 # working directory, from which the match object is
1032 # working directory, from which the match object is
1032 # initialized. Use 'd:' to set the default matching mode, default
1033 # initialized. Use 'd:' to set the default matching mode, default
1033 # to 'glob'. At most one 'r:' and 'd:' argument can be passed.
1034 # to 'glob'. At most one 'r:' and 'd:' argument can be passed.
1034
1035
1035 # i18n: "_matchfiles" is a keyword
1036 # i18n: "_matchfiles" is a keyword
1036 l = getargs(x, 1, -1, _("_matchfiles requires at least one argument"))
1037 l = getargs(x, 1, -1, _("_matchfiles requires at least one argument"))
1037 pats, inc, exc = [], [], []
1038 pats, inc, exc = [], [], []
1038 rev, default = None, None
1039 rev, default = None, None
1039 for arg in l:
1040 for arg in l:
1040 # i18n: "_matchfiles" is a keyword
1041 # i18n: "_matchfiles" is a keyword
1041 s = getstring(arg, _("_matchfiles requires string arguments"))
1042 s = getstring(arg, _("_matchfiles requires string arguments"))
1042 prefix, value = s[:2], s[2:]
1043 prefix, value = s[:2], s[2:]
1043 if prefix == 'p:':
1044 if prefix == 'p:':
1044 pats.append(value)
1045 pats.append(value)
1045 elif prefix == 'i:':
1046 elif prefix == 'i:':
1046 inc.append(value)
1047 inc.append(value)
1047 elif prefix == 'x:':
1048 elif prefix == 'x:':
1048 exc.append(value)
1049 exc.append(value)
1049 elif prefix == 'r:':
1050 elif prefix == 'r:':
1050 if rev is not None:
1051 if rev is not None:
1051 # i18n: "_matchfiles" is a keyword
1052 # i18n: "_matchfiles" is a keyword
1052 raise error.ParseError(_('_matchfiles expected at most one '
1053 raise error.ParseError(_('_matchfiles expected at most one '
1053 'revision'))
1054 'revision'))
1054 if value != '': # empty means working directory; leave rev as None
1055 if value != '': # empty means working directory; leave rev as None
1055 rev = value
1056 rev = value
1056 elif prefix == 'd:':
1057 elif prefix == 'd:':
1057 if default is not None:
1058 if default is not None:
1058 # i18n: "_matchfiles" is a keyword
1059 # i18n: "_matchfiles" is a keyword
1059 raise error.ParseError(_('_matchfiles expected at most one '
1060 raise error.ParseError(_('_matchfiles expected at most one '
1060 'default mode'))
1061 'default mode'))
1061 default = value
1062 default = value
1062 else:
1063 else:
1063 # i18n: "_matchfiles" is a keyword
1064 # i18n: "_matchfiles" is a keyword
1064 raise error.ParseError(_('invalid _matchfiles prefix: %s') % prefix)
1065 raise error.ParseError(_('invalid _matchfiles prefix: %s') % prefix)
1065 if not default:
1066 if not default:
1066 default = 'glob'
1067 default = 'glob'
1067
1068
1068 m = matchmod.match(repo.root, repo.getcwd(), pats, include=inc,
1069 m = matchmod.match(repo.root, repo.getcwd(), pats, include=inc,
1069 exclude=exc, ctx=repo[rev], default=default)
1070 exclude=exc, ctx=repo[rev], default=default)
1070
1071
1071 def matches(x):
1072 def matches(x):
1072 for f in repo[x].files():
1073 for f in repo[x].files():
1073 if m(f):
1074 if m(f):
1074 return True
1075 return True
1075 return False
1076 return False
1076
1077
1077 return subset.filter(matches)
1078 return subset.filter(matches)
1078
1079
1079 def hasfile(repo, subset, x):
1080 def hasfile(repo, subset, x):
1080 """``file(pattern)``
1081 """``file(pattern)``
1081 Changesets affecting files matched by pattern.
1082 Changesets affecting files matched by pattern.
1082
1083
1083 For a faster but less accurate result, consider using ``filelog()``
1084 For a faster but less accurate result, consider using ``filelog()``
1084 instead.
1085 instead.
1085
1086
1086 This predicate uses ``glob:`` as the default kind of pattern.
1087 This predicate uses ``glob:`` as the default kind of pattern.
1087 """
1088 """
1088 # i18n: "file" is a keyword
1089 # i18n: "file" is a keyword
1089 pat = getstring(x, _("file requires a pattern"))
1090 pat = getstring(x, _("file requires a pattern"))
1090 return _matchfiles(repo, subset, ('string', 'p:' + pat))
1091 return _matchfiles(repo, subset, ('string', 'p:' + pat))
1091
1092
1092 def head(repo, subset, x):
1093 def head(repo, subset, x):
1093 """``head()``
1094 """``head()``
1094 Changeset is a named branch head.
1095 Changeset is a named branch head.
1095 """
1096 """
1096 # i18n: "head" is a keyword
1097 # i18n: "head" is a keyword
1097 getargs(x, 0, 0, _("head takes no arguments"))
1098 getargs(x, 0, 0, _("head takes no arguments"))
1098 hs = set()
1099 hs = set()
1099 for b, ls in repo.branchmap().iteritems():
1100 for b, ls in repo.branchmap().iteritems():
1100 hs.update(repo[h].rev() for h in ls)
1101 hs.update(repo[h].rev() for h in ls)
1101 return baseset(hs).filter(subset.__contains__)
1102 return baseset(hs).filter(subset.__contains__)
1102
1103
1103 def heads(repo, subset, x):
1104 def heads(repo, subset, x):
1104 """``heads(set)``
1105 """``heads(set)``
1105 Members of set with no children in set.
1106 Members of set with no children in set.
1106 """
1107 """
1107 s = getset(repo, subset, x)
1108 s = getset(repo, subset, x)
1108 ps = parents(repo, subset, x)
1109 ps = parents(repo, subset, x)
1109 return s - ps
1110 return s - ps
1110
1111
1111 def hidden(repo, subset, x):
1112 def hidden(repo, subset, x):
1112 """``hidden()``
1113 """``hidden()``
1113 Hidden changesets.
1114 Hidden changesets.
1114 """
1115 """
1115 # i18n: "hidden" is a keyword
1116 # i18n: "hidden" is a keyword
1116 getargs(x, 0, 0, _("hidden takes no arguments"))
1117 getargs(x, 0, 0, _("hidden takes no arguments"))
1117 hiddenrevs = repoview.filterrevs(repo, 'visible')
1118 hiddenrevs = repoview.filterrevs(repo, 'visible')
1118 return subset & hiddenrevs
1119 return subset & hiddenrevs
1119
1120
1120 def keyword(repo, subset, x):
1121 def keyword(repo, subset, x):
1121 """``keyword(string)``
1122 """``keyword(string)``
1122 Search commit message, user name, and names of changed files for
1123 Search commit message, user name, and names of changed files for
1123 string. The match is case-insensitive.
1124 string. The match is case-insensitive.
1124 """
1125 """
1125 # i18n: "keyword" is a keyword
1126 # i18n: "keyword" is a keyword
1126 kw = encoding.lower(getstring(x, _("keyword requires a string")))
1127 kw = encoding.lower(getstring(x, _("keyword requires a string")))
1127
1128
1128 def matches(r):
1129 def matches(r):
1129 c = repo[r]
1130 c = repo[r]
1130 return util.any(kw in encoding.lower(t) for t in c.files() + [c.user(),
1131 return util.any(kw in encoding.lower(t) for t in c.files() + [c.user(),
1131 c.description()])
1132 c.description()])
1132
1133
1133 return subset.filter(matches)
1134 return subset.filter(matches)
1134
1135
1135 def limit(repo, subset, x):
1136 def limit(repo, subset, x):
1136 """``limit(set, [n])``
1137 """``limit(set, [n])``
1137 First n members of set, defaulting to 1.
1138 First n members of set, defaulting to 1.
1138 """
1139 """
1139 # i18n: "limit" is a keyword
1140 # i18n: "limit" is a keyword
1140 l = getargs(x, 1, 2, _("limit requires one or two arguments"))
1141 l = getargs(x, 1, 2, _("limit requires one or two arguments"))
1141 try:
1142 try:
1142 lim = 1
1143 lim = 1
1143 if len(l) == 2:
1144 if len(l) == 2:
1144 # i18n: "limit" is a keyword
1145 # i18n: "limit" is a keyword
1145 lim = int(getstring(l[1], _("limit requires a number")))
1146 lim = int(getstring(l[1], _("limit requires a number")))
1146 except (TypeError, ValueError):
1147 except (TypeError, ValueError):
1147 # i18n: "limit" is a keyword
1148 # i18n: "limit" is a keyword
1148 raise error.ParseError(_("limit expects a number"))
1149 raise error.ParseError(_("limit expects a number"))
1149 ss = subset
1150 ss = subset
1150 os = getset(repo, fullreposet(repo), l[0])
1151 os = getset(repo, fullreposet(repo), l[0])
1151 result = []
1152 result = []
1152 it = iter(os)
1153 it = iter(os)
1153 for x in xrange(lim):
1154 for x in xrange(lim):
1154 try:
1155 try:
1155 y = it.next()
1156 y = it.next()
1156 if y in ss:
1157 if y in ss:
1157 result.append(y)
1158 result.append(y)
1158 except (StopIteration):
1159 except (StopIteration):
1159 break
1160 break
1160 return baseset(result)
1161 return baseset(result)
1161
1162
1162 def last(repo, subset, x):
1163 def last(repo, subset, x):
1163 """``last(set, [n])``
1164 """``last(set, [n])``
1164 Last n members of set, defaulting to 1.
1165 Last n members of set, defaulting to 1.
1165 """
1166 """
1166 # i18n: "last" is a keyword
1167 # i18n: "last" is a keyword
1167 l = getargs(x, 1, 2, _("last requires one or two arguments"))
1168 l = getargs(x, 1, 2, _("last requires one or two arguments"))
1168 try:
1169 try:
1169 lim = 1
1170 lim = 1
1170 if len(l) == 2:
1171 if len(l) == 2:
1171 # i18n: "last" is a keyword
1172 # i18n: "last" is a keyword
1172 lim = int(getstring(l[1], _("last requires a number")))
1173 lim = int(getstring(l[1], _("last requires a number")))
1173 except (TypeError, ValueError):
1174 except (TypeError, ValueError):
1174 # i18n: "last" is a keyword
1175 # i18n: "last" is a keyword
1175 raise error.ParseError(_("last expects a number"))
1176 raise error.ParseError(_("last expects a number"))
1176 ss = subset
1177 ss = subset
1177 os = getset(repo, fullreposet(repo), l[0])
1178 os = getset(repo, fullreposet(repo), l[0])
1178 os.reverse()
1179 os.reverse()
1179 result = []
1180 result = []
1180 it = iter(os)
1181 it = iter(os)
1181 for x in xrange(lim):
1182 for x in xrange(lim):
1182 try:
1183 try:
1183 y = it.next()
1184 y = it.next()
1184 if y in ss:
1185 if y in ss:
1185 result.append(y)
1186 result.append(y)
1186 except (StopIteration):
1187 except (StopIteration):
1187 break
1188 break
1188 return baseset(result)
1189 return baseset(result)
1189
1190
1190 def maxrev(repo, subset, x):
1191 def maxrev(repo, subset, x):
1191 """``max(set)``
1192 """``max(set)``
1192 Changeset with highest revision number in set.
1193 Changeset with highest revision number in set.
1193 """
1194 """
1194 os = getset(repo, fullreposet(repo), x)
1195 os = getset(repo, fullreposet(repo), x)
1195 if os:
1196 if os:
1196 m = os.max()
1197 m = os.max()
1197 if m in subset:
1198 if m in subset:
1198 return baseset([m])
1199 return baseset([m])
1199 return baseset()
1200 return baseset()
1200
1201
1201 def merge(repo, subset, x):
1202 def merge(repo, subset, x):
1202 """``merge()``
1203 """``merge()``
1203 Changeset is a merge changeset.
1204 Changeset is a merge changeset.
1204 """
1205 """
1205 # i18n: "merge" is a keyword
1206 # i18n: "merge" is a keyword
1206 getargs(x, 0, 0, _("merge takes no arguments"))
1207 getargs(x, 0, 0, _("merge takes no arguments"))
1207 cl = repo.changelog
1208 cl = repo.changelog
1208 return subset.filter(lambda r: cl.parentrevs(r)[1] != -1)
1209 return subset.filter(lambda r: cl.parentrevs(r)[1] != -1)
1209
1210
1210 def branchpoint(repo, subset, x):
1211 def branchpoint(repo, subset, x):
1211 """``branchpoint()``
1212 """``branchpoint()``
1212 Changesets with more than one child.
1213 Changesets with more than one child.
1213 """
1214 """
1214 # i18n: "branchpoint" is a keyword
1215 # i18n: "branchpoint" is a keyword
1215 getargs(x, 0, 0, _("branchpoint takes no arguments"))
1216 getargs(x, 0, 0, _("branchpoint takes no arguments"))
1216 cl = repo.changelog
1217 cl = repo.changelog
1217 if not subset:
1218 if not subset:
1218 return baseset()
1219 return baseset()
1219 baserev = min(subset)
1220 baserev = min(subset)
1220 parentscount = [0]*(len(repo) - baserev)
1221 parentscount = [0]*(len(repo) - baserev)
1221 for r in cl.revs(start=baserev + 1):
1222 for r in cl.revs(start=baserev + 1):
1222 for p in cl.parentrevs(r):
1223 for p in cl.parentrevs(r):
1223 if p >= baserev:
1224 if p >= baserev:
1224 parentscount[p - baserev] += 1
1225 parentscount[p - baserev] += 1
1225 return subset.filter(lambda r: parentscount[r - baserev] > 1)
1226 return subset.filter(lambda r: parentscount[r - baserev] > 1)
1226
1227
1227 def minrev(repo, subset, x):
1228 def minrev(repo, subset, x):
1228 """``min(set)``
1229 """``min(set)``
1229 Changeset with lowest revision number in set.
1230 Changeset with lowest revision number in set.
1230 """
1231 """
1231 os = getset(repo, fullreposet(repo), x)
1232 os = getset(repo, fullreposet(repo), x)
1232 if os:
1233 if os:
1233 m = os.min()
1234 m = os.min()
1234 if m in subset:
1235 if m in subset:
1235 return baseset([m])
1236 return baseset([m])
1236 return baseset()
1237 return baseset()
1237
1238
1238 def modifies(repo, subset, x):
1239 def modifies(repo, subset, x):
1239 """``modifies(pattern)``
1240 """``modifies(pattern)``
1240 Changesets modifying files matched by pattern.
1241 Changesets modifying files matched by pattern.
1241
1242
1242 The pattern without explicit kind like ``glob:`` is expected to be
1243 The pattern without explicit kind like ``glob:`` is expected to be
1243 relative to the current directory and match against a file or a
1244 relative to the current directory and match against a file or a
1244 directory.
1245 directory.
1245 """
1246 """
1246 # i18n: "modifies" is a keyword
1247 # i18n: "modifies" is a keyword
1247 pat = getstring(x, _("modifies requires a pattern"))
1248 pat = getstring(x, _("modifies requires a pattern"))
1248 return checkstatus(repo, subset, pat, 0)
1249 return checkstatus(repo, subset, pat, 0)
1249
1250
1250 def named(repo, subset, x):
1251 def named(repo, subset, x):
1251 """``named(namespace)``
1252 """``named(namespace)``
1252 The changesets in a given namespace.
1253 The changesets in a given namespace.
1253
1254
1254 If `namespace` starts with `re:`, the remainder of the string is treated as
1255 If `namespace` starts with `re:`, the remainder of the string is treated as
1255 a regular expression. To match a namespace that actually starts with `re:`,
1256 a regular expression. To match a namespace that actually starts with `re:`,
1256 use the prefix `literal:`.
1257 use the prefix `literal:`.
1257 """
1258 """
1258 # i18n: "named" is a keyword
1259 # i18n: "named" is a keyword
1259 args = getargs(x, 1, 1, _('named requires a namespace argument'))
1260 args = getargs(x, 1, 1, _('named requires a namespace argument'))
1260
1261
1261 ns = getstring(args[0],
1262 ns = getstring(args[0],
1262 # i18n: "named" is a keyword
1263 # i18n: "named" is a keyword
1263 _('the argument to named must be a string'))
1264 _('the argument to named must be a string'))
1264 kind, pattern, matcher = _stringmatcher(ns)
1265 kind, pattern, matcher = _stringmatcher(ns)
1265 namespaces = set()
1266 namespaces = set()
1266 if kind == 'literal':
1267 if kind == 'literal':
1267 if pattern not in repo.names:
1268 if pattern not in repo.names:
1268 raise error.RepoLookupError(_("namespace '%s' does not exist")
1269 raise error.RepoLookupError(_("namespace '%s' does not exist")
1269 % ns)
1270 % ns)
1270 namespaces.add(repo.names[pattern])
1271 namespaces.add(repo.names[pattern])
1271 else:
1272 else:
1272 for name, ns in repo.names.iteritems():
1273 for name, ns in repo.names.iteritems():
1273 if matcher(name):
1274 if matcher(name):
1274 namespaces.add(ns)
1275 namespaces.add(ns)
1275 if not namespaces:
1276 if not namespaces:
1276 raise error.RepoLookupError(_("no namespace exists"
1277 raise error.RepoLookupError(_("no namespace exists"
1277 " that match '%s'") % pattern)
1278 " that match '%s'") % pattern)
1278
1279
1279 names = set()
1280 names = set()
1280 for ns in namespaces:
1281 for ns in namespaces:
1281 for name in ns.listnames(repo):
1282 for name in ns.listnames(repo):
1282 if name not in ns.deprecated:
1283 if name not in ns.deprecated:
1283 names.update(repo[n].rev() for n in ns.nodes(repo, name))
1284 names.update(repo[n].rev() for n in ns.nodes(repo, name))
1284
1285
1285 names -= set([node.nullrev])
1286 names -= set([node.nullrev])
1286 return subset & names
1287 return subset & names
1287
1288
1288 def node_(repo, subset, x):
1289 def node_(repo, subset, x):
1289 """``id(string)``
1290 """``id(string)``
1290 Revision non-ambiguously specified by the given hex string prefix.
1291 Revision non-ambiguously specified by the given hex string prefix.
1291 """
1292 """
1292 # i18n: "id" is a keyword
1293 # i18n: "id" is a keyword
1293 l = getargs(x, 1, 1, _("id requires one argument"))
1294 l = getargs(x, 1, 1, _("id requires one argument"))
1294 # i18n: "id" is a keyword
1295 # i18n: "id" is a keyword
1295 n = getstring(l[0], _("id requires a string"))
1296 n = getstring(l[0], _("id requires a string"))
1296 if len(n) == 40:
1297 if len(n) == 40:
1297 try:
1298 try:
1298 rn = repo.changelog.rev(node.bin(n))
1299 rn = repo.changelog.rev(node.bin(n))
1299 except (LookupError, TypeError):
1300 except (LookupError, TypeError):
1300 rn = None
1301 rn = None
1301 else:
1302 else:
1302 rn = None
1303 rn = None
1303 pm = repo.changelog._partialmatch(n)
1304 pm = repo.changelog._partialmatch(n)
1304 if pm is not None:
1305 if pm is not None:
1305 rn = repo.changelog.rev(pm)
1306 rn = repo.changelog.rev(pm)
1306
1307
1307 if rn is None:
1308 if rn is None:
1308 return baseset()
1309 return baseset()
1309 result = baseset([rn])
1310 result = baseset([rn])
1310 return result & subset
1311 return result & subset
1311
1312
1312 def obsolete(repo, subset, x):
1313 def obsolete(repo, subset, x):
1313 """``obsolete()``
1314 """``obsolete()``
1314 Mutable changeset with a newer version."""
1315 Mutable changeset with a newer version."""
1315 # i18n: "obsolete" is a keyword
1316 # i18n: "obsolete" is a keyword
1316 getargs(x, 0, 0, _("obsolete takes no arguments"))
1317 getargs(x, 0, 0, _("obsolete takes no arguments"))
1317 obsoletes = obsmod.getrevs(repo, 'obsolete')
1318 obsoletes = obsmod.getrevs(repo, 'obsolete')
1318 return subset & obsoletes
1319 return subset & obsoletes
1319
1320
1320 def only(repo, subset, x):
1321 def only(repo, subset, x):
1321 """``only(set, [set])``
1322 """``only(set, [set])``
1322 Changesets that are ancestors of the first set that are not ancestors
1323 Changesets that are ancestors of the first set that are not ancestors
1323 of any other head in the repo. If a second set is specified, the result
1324 of any other head in the repo. If a second set is specified, the result
1324 is ancestors of the first set that are not ancestors of the second set
1325 is ancestors of the first set that are not ancestors of the second set
1325 (i.e. ::<set1> - ::<set2>).
1326 (i.e. ::<set1> - ::<set2>).
1326 """
1327 """
1327 cl = repo.changelog
1328 cl = repo.changelog
1328 # i18n: "only" is a keyword
1329 # i18n: "only" is a keyword
1329 args = getargs(x, 1, 2, _('only takes one or two arguments'))
1330 args = getargs(x, 1, 2, _('only takes one or two arguments'))
1330 include = getset(repo, fullreposet(repo), args[0])
1331 include = getset(repo, fullreposet(repo), args[0])
1331 if len(args) == 1:
1332 if len(args) == 1:
1332 if not include:
1333 if not include:
1333 return baseset()
1334 return baseset()
1334
1335
1335 descendants = set(_revdescendants(repo, include, False))
1336 descendants = set(_revdescendants(repo, include, False))
1336 exclude = [rev for rev in cl.headrevs()
1337 exclude = [rev for rev in cl.headrevs()
1337 if not rev in descendants and not rev in include]
1338 if not rev in descendants and not rev in include]
1338 else:
1339 else:
1339 exclude = getset(repo, fullreposet(repo), args[1])
1340 exclude = getset(repo, fullreposet(repo), args[1])
1340
1341
1341 results = set(cl.findmissingrevs(common=exclude, heads=include))
1342 results = set(cl.findmissingrevs(common=exclude, heads=include))
1342 return subset & results
1343 return subset & results
1343
1344
1344 def origin(repo, subset, x):
1345 def origin(repo, subset, x):
1345 """``origin([set])``
1346 """``origin([set])``
1346 Changesets that were specified as a source for the grafts, transplants or
1347 Changesets that were specified as a source for the grafts, transplants or
1347 rebases that created the given revisions. Omitting the optional set is the
1348 rebases that created the given revisions. Omitting the optional set is the
1348 same as passing all(). If a changeset created by these operations is itself
1349 same as passing all(). If a changeset created by these operations is itself
1349 specified as a source for one of these operations, only the source changeset
1350 specified as a source for one of these operations, only the source changeset
1350 for the first operation is selected.
1351 for the first operation is selected.
1351 """
1352 """
1352 if x is not None:
1353 if x is not None:
1353 dests = getset(repo, fullreposet(repo), x)
1354 dests = getset(repo, fullreposet(repo), x)
1354 else:
1355 else:
1355 dests = fullreposet(repo)
1356 dests = fullreposet(repo)
1356
1357
1357 def _firstsrc(rev):
1358 def _firstsrc(rev):
1358 src = _getrevsource(repo, rev)
1359 src = _getrevsource(repo, rev)
1359 if src is None:
1360 if src is None:
1360 return None
1361 return None
1361
1362
1362 while True:
1363 while True:
1363 prev = _getrevsource(repo, src)
1364 prev = _getrevsource(repo, src)
1364
1365
1365 if prev is None:
1366 if prev is None:
1366 return src
1367 return src
1367 src = prev
1368 src = prev
1368
1369
1369 o = set([_firstsrc(r) for r in dests])
1370 o = set([_firstsrc(r) for r in dests])
1370 o -= set([None])
1371 o -= set([None])
1371 return subset & o
1372 return subset & o
1372
1373
1373 def outgoing(repo, subset, x):
1374 def outgoing(repo, subset, x):
1374 """``outgoing([path])``
1375 """``outgoing([path])``
1375 Changesets not found in the specified destination repository, or the
1376 Changesets not found in the specified destination repository, or the
1376 default push location.
1377 default push location.
1377 """
1378 """
1378 # Avoid cycles.
1379 # Avoid cycles.
1379 import discovery
1380 import discovery
1380 import hg
1381 import hg
1381 # i18n: "outgoing" is a keyword
1382 # i18n: "outgoing" is a keyword
1382 l = getargs(x, 0, 1, _("outgoing takes one or no arguments"))
1383 l = getargs(x, 0, 1, _("outgoing takes one or no arguments"))
1383 # i18n: "outgoing" is a keyword
1384 # i18n: "outgoing" is a keyword
1384 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
1385 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
1385 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
1386 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
1386 dest, branches = hg.parseurl(dest)
1387 dest, branches = hg.parseurl(dest)
1387 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1388 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1388 if revs:
1389 if revs:
1389 revs = [repo.lookup(rev) for rev in revs]
1390 revs = [repo.lookup(rev) for rev in revs]
1390 other = hg.peer(repo, {}, dest)
1391 other = hg.peer(repo, {}, dest)
1391 repo.ui.pushbuffer()
1392 repo.ui.pushbuffer()
1392 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
1393 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
1393 repo.ui.popbuffer()
1394 repo.ui.popbuffer()
1394 cl = repo.changelog
1395 cl = repo.changelog
1395 o = set([cl.rev(r) for r in outgoing.missing])
1396 o = set([cl.rev(r) for r in outgoing.missing])
1396 return subset & o
1397 return subset & o
1397
1398
1398 def p1(repo, subset, x):
1399 def p1(repo, subset, x):
1399 """``p1([set])``
1400 """``p1([set])``
1400 First parent of changesets in set, or the working directory.
1401 First parent of changesets in set, or the working directory.
1401 """
1402 """
1402 if x is None:
1403 if x is None:
1403 p = repo[x].p1().rev()
1404 p = repo[x].p1().rev()
1404 if p >= 0:
1405 if p >= 0:
1405 return subset & baseset([p])
1406 return subset & baseset([p])
1406 return baseset()
1407 return baseset()
1407
1408
1408 ps = set()
1409 ps = set()
1409 cl = repo.changelog
1410 cl = repo.changelog
1410 for r in getset(repo, fullreposet(repo), x):
1411 for r in getset(repo, fullreposet(repo), x):
1411 ps.add(cl.parentrevs(r)[0])
1412 ps.add(cl.parentrevs(r)[0])
1412 ps -= set([node.nullrev])
1413 ps -= set([node.nullrev])
1413 return subset & ps
1414 return subset & ps
1414
1415
1415 def p2(repo, subset, x):
1416 def p2(repo, subset, x):
1416 """``p2([set])``
1417 """``p2([set])``
1417 Second parent of changesets in set, or the working directory.
1418 Second parent of changesets in set, or the working directory.
1418 """
1419 """
1419 if x is None:
1420 if x is None:
1420 ps = repo[x].parents()
1421 ps = repo[x].parents()
1421 try:
1422 try:
1422 p = ps[1].rev()
1423 p = ps[1].rev()
1423 if p >= 0:
1424 if p >= 0:
1424 return subset & baseset([p])
1425 return subset & baseset([p])
1425 return baseset()
1426 return baseset()
1426 except IndexError:
1427 except IndexError:
1427 return baseset()
1428 return baseset()
1428
1429
1429 ps = set()
1430 ps = set()
1430 cl = repo.changelog
1431 cl = repo.changelog
1431 for r in getset(repo, fullreposet(repo), x):
1432 for r in getset(repo, fullreposet(repo), x):
1432 ps.add(cl.parentrevs(r)[1])
1433 ps.add(cl.parentrevs(r)[1])
1433 ps -= set([node.nullrev])
1434 ps -= set([node.nullrev])
1434 return subset & ps
1435 return subset & ps
1435
1436
1436 def parents(repo, subset, x):
1437 def parents(repo, subset, x):
1437 """``parents([set])``
1438 """``parents([set])``
1438 The set of all parents for all changesets in set, or the working directory.
1439 The set of all parents for all changesets in set, or the working directory.
1439 """
1440 """
1440 if x is None:
1441 if x is None:
1441 ps = set(p.rev() for p in repo[x].parents())
1442 ps = set(p.rev() for p in repo[x].parents())
1442 else:
1443 else:
1443 ps = set()
1444 ps = set()
1444 cl = repo.changelog
1445 cl = repo.changelog
1445 for r in getset(repo, fullreposet(repo), x):
1446 for r in getset(repo, fullreposet(repo), x):
1446 ps.update(cl.parentrevs(r))
1447 ps.update(cl.parentrevs(r))
1447 ps -= set([node.nullrev])
1448 ps -= set([node.nullrev])
1448 return subset & ps
1449 return subset & ps
1449
1450
1450 def parentspec(repo, subset, x, n):
1451 def parentspec(repo, subset, x, n):
1451 """``set^0``
1452 """``set^0``
1452 The set.
1453 The set.
1453 ``set^1`` (or ``set^``), ``set^2``
1454 ``set^1`` (or ``set^``), ``set^2``
1454 First or second parent, respectively, of all changesets in set.
1455 First or second parent, respectively, of all changesets in set.
1455 """
1456 """
1456 try:
1457 try:
1457 n = int(n[1])
1458 n = int(n[1])
1458 if n not in (0, 1, 2):
1459 if n not in (0, 1, 2):
1459 raise ValueError
1460 raise ValueError
1460 except (TypeError, ValueError):
1461 except (TypeError, ValueError):
1461 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
1462 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
1462 ps = set()
1463 ps = set()
1463 cl = repo.changelog
1464 cl = repo.changelog
1464 for r in getset(repo, fullreposet(repo), x):
1465 for r in getset(repo, fullreposet(repo), x):
1465 if n == 0:
1466 if n == 0:
1466 ps.add(r)
1467 ps.add(r)
1467 elif n == 1:
1468 elif n == 1:
1468 ps.add(cl.parentrevs(r)[0])
1469 ps.add(cl.parentrevs(r)[0])
1469 elif n == 2:
1470 elif n == 2:
1470 parents = cl.parentrevs(r)
1471 parents = cl.parentrevs(r)
1471 if len(parents) > 1:
1472 if len(parents) > 1:
1472 ps.add(parents[1])
1473 ps.add(parents[1])
1473 return subset & ps
1474 return subset & ps
1474
1475
1475 def present(repo, subset, x):
1476 def present(repo, subset, x):
1476 """``present(set)``
1477 """``present(set)``
1477 An empty set, if any revision in set isn't found; otherwise,
1478 An empty set, if any revision in set isn't found; otherwise,
1478 all revisions in set.
1479 all revisions in set.
1479
1480
1480 If any of specified revisions is not present in the local repository,
1481 If any of specified revisions is not present in the local repository,
1481 the query is normally aborted. But this predicate allows the query
1482 the query is normally aborted. But this predicate allows the query
1482 to continue even in such cases.
1483 to continue even in such cases.
1483 """
1484 """
1484 try:
1485 try:
1485 return getset(repo, subset, x)
1486 return getset(repo, subset, x)
1486 except error.RepoLookupError:
1487 except error.RepoLookupError:
1487 return baseset()
1488 return baseset()
1488
1489
1489 def public(repo, subset, x):
1490 def public(repo, subset, x):
1490 """``public()``
1491 """``public()``
1491 Changeset in public phase."""
1492 Changeset in public phase."""
1492 # i18n: "public" is a keyword
1493 # i18n: "public" is a keyword
1493 getargs(x, 0, 0, _("public takes no arguments"))
1494 getargs(x, 0, 0, _("public takes no arguments"))
1494 phase = repo._phasecache.phase
1495 phase = repo._phasecache.phase
1495 target = phases.public
1496 target = phases.public
1496 condition = lambda r: phase(repo, r) == target
1497 condition = lambda r: phase(repo, r) == target
1497 return subset.filter(condition, cache=False)
1498 return subset.filter(condition, cache=False)
1498
1499
1499 def remote(repo, subset, x):
1500 def remote(repo, subset, x):
1500 """``remote([id [,path]])``
1501 """``remote([id [,path]])``
1501 Local revision that corresponds to the given identifier in a
1502 Local revision that corresponds to the given identifier in a
1502 remote repository, if present. Here, the '.' identifier is a
1503 remote repository, if present. Here, the '.' identifier is a
1503 synonym for the current local branch.
1504 synonym for the current local branch.
1504 """
1505 """
1505
1506
1506 import hg # avoid start-up nasties
1507 import hg # avoid start-up nasties
1507 # i18n: "remote" is a keyword
1508 # i18n: "remote" is a keyword
1508 l = getargs(x, 0, 2, _("remote takes one, two or no arguments"))
1509 l = getargs(x, 0, 2, _("remote takes one, two or no arguments"))
1509
1510
1510 q = '.'
1511 q = '.'
1511 if len(l) > 0:
1512 if len(l) > 0:
1512 # i18n: "remote" is a keyword
1513 # i18n: "remote" is a keyword
1513 q = getstring(l[0], _("remote requires a string id"))
1514 q = getstring(l[0], _("remote requires a string id"))
1514 if q == '.':
1515 if q == '.':
1515 q = repo['.'].branch()
1516 q = repo['.'].branch()
1516
1517
1517 dest = ''
1518 dest = ''
1518 if len(l) > 1:
1519 if len(l) > 1:
1519 # i18n: "remote" is a keyword
1520 # i18n: "remote" is a keyword
1520 dest = getstring(l[1], _("remote requires a repository path"))
1521 dest = getstring(l[1], _("remote requires a repository path"))
1521 dest = repo.ui.expandpath(dest or 'default')
1522 dest = repo.ui.expandpath(dest or 'default')
1522 dest, branches = hg.parseurl(dest)
1523 dest, branches = hg.parseurl(dest)
1523 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1524 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1524 if revs:
1525 if revs:
1525 revs = [repo.lookup(rev) for rev in revs]
1526 revs = [repo.lookup(rev) for rev in revs]
1526 other = hg.peer(repo, {}, dest)
1527 other = hg.peer(repo, {}, dest)
1527 n = other.lookup(q)
1528 n = other.lookup(q)
1528 if n in repo:
1529 if n in repo:
1529 r = repo[n].rev()
1530 r = repo[n].rev()
1530 if r in subset:
1531 if r in subset:
1531 return baseset([r])
1532 return baseset([r])
1532 return baseset()
1533 return baseset()
1533
1534
1534 def removes(repo, subset, x):
1535 def removes(repo, subset, x):
1535 """``removes(pattern)``
1536 """``removes(pattern)``
1536 Changesets which remove files matching pattern.
1537 Changesets which remove files matching pattern.
1537
1538
1538 The pattern without explicit kind like ``glob:`` is expected to be
1539 The pattern without explicit kind like ``glob:`` is expected to be
1539 relative to the current directory and match against a file or a
1540 relative to the current directory and match against a file or a
1540 directory.
1541 directory.
1541 """
1542 """
1542 # i18n: "removes" is a keyword
1543 # i18n: "removes" is a keyword
1543 pat = getstring(x, _("removes requires a pattern"))
1544 pat = getstring(x, _("removes requires a pattern"))
1544 return checkstatus(repo, subset, pat, 2)
1545 return checkstatus(repo, subset, pat, 2)
1545
1546
1546 def rev(repo, subset, x):
1547 def rev(repo, subset, x):
1547 """``rev(number)``
1548 """``rev(number)``
1548 Revision with the given numeric identifier.
1549 Revision with the given numeric identifier.
1549 """
1550 """
1550 # i18n: "rev" is a keyword
1551 # i18n: "rev" is a keyword
1551 l = getargs(x, 1, 1, _("rev requires one argument"))
1552 l = getargs(x, 1, 1, _("rev requires one argument"))
1552 try:
1553 try:
1553 # i18n: "rev" is a keyword
1554 # i18n: "rev" is a keyword
1554 l = int(getstring(l[0], _("rev requires a number")))
1555 l = int(getstring(l[0], _("rev requires a number")))
1555 except (TypeError, ValueError):
1556 except (TypeError, ValueError):
1556 # i18n: "rev" is a keyword
1557 # i18n: "rev" is a keyword
1557 raise error.ParseError(_("rev expects a number"))
1558 raise error.ParseError(_("rev expects a number"))
1558 if l not in repo.changelog and l != node.nullrev:
1559 if l not in repo.changelog and l != node.nullrev:
1559 return baseset()
1560 return baseset()
1560 return subset & baseset([l])
1561 return subset & baseset([l])
1561
1562
1562 def matching(repo, subset, x):
1563 def matching(repo, subset, x):
1563 """``matching(revision [, field])``
1564 """``matching(revision [, field])``
1564 Changesets in which a given set of fields match the set of fields in the
1565 Changesets in which a given set of fields match the set of fields in the
1565 selected revision or set.
1566 selected revision or set.
1566
1567
1567 To match more than one field pass the list of fields to match separated
1568 To match more than one field pass the list of fields to match separated
1568 by spaces (e.g. ``author description``).
1569 by spaces (e.g. ``author description``).
1569
1570
1570 Valid fields are most regular revision fields and some special fields.
1571 Valid fields are most regular revision fields and some special fields.
1571
1572
1572 Regular revision fields are ``description``, ``author``, ``branch``,
1573 Regular revision fields are ``description``, ``author``, ``branch``,
1573 ``date``, ``files``, ``phase``, ``parents``, ``substate``, ``user``
1574 ``date``, ``files``, ``phase``, ``parents``, ``substate``, ``user``
1574 and ``diff``.
1575 and ``diff``.
1575 Note that ``author`` and ``user`` are synonyms. ``diff`` refers to the
1576 Note that ``author`` and ``user`` are synonyms. ``diff`` refers to the
1576 contents of the revision. Two revisions matching their ``diff`` will
1577 contents of the revision. Two revisions matching their ``diff`` will
1577 also match their ``files``.
1578 also match their ``files``.
1578
1579
1579 Special fields are ``summary`` and ``metadata``:
1580 Special fields are ``summary`` and ``metadata``:
1580 ``summary`` matches the first line of the description.
1581 ``summary`` matches the first line of the description.
1581 ``metadata`` is equivalent to matching ``description user date``
1582 ``metadata`` is equivalent to matching ``description user date``
1582 (i.e. it matches the main metadata fields).
1583 (i.e. it matches the main metadata fields).
1583
1584
1584 ``metadata`` is the default field which is used when no fields are
1585 ``metadata`` is the default field which is used when no fields are
1585 specified. You can match more than one field at a time.
1586 specified. You can match more than one field at a time.
1586 """
1587 """
1587 # i18n: "matching" is a keyword
1588 # i18n: "matching" is a keyword
1588 l = getargs(x, 1, 2, _("matching takes 1 or 2 arguments"))
1589 l = getargs(x, 1, 2, _("matching takes 1 or 2 arguments"))
1589
1590
1590 revs = getset(repo, fullreposet(repo), l[0])
1591 revs = getset(repo, fullreposet(repo), l[0])
1591
1592
1592 fieldlist = ['metadata']
1593 fieldlist = ['metadata']
1593 if len(l) > 1:
1594 if len(l) > 1:
1594 fieldlist = getstring(l[1],
1595 fieldlist = getstring(l[1],
1595 # i18n: "matching" is a keyword
1596 # i18n: "matching" is a keyword
1596 _("matching requires a string "
1597 _("matching requires a string "
1597 "as its second argument")).split()
1598 "as its second argument")).split()
1598
1599
1599 # Make sure that there are no repeated fields,
1600 # Make sure that there are no repeated fields,
1600 # expand the 'special' 'metadata' field type
1601 # expand the 'special' 'metadata' field type
1601 # and check the 'files' whenever we check the 'diff'
1602 # and check the 'files' whenever we check the 'diff'
1602 fields = []
1603 fields = []
1603 for field in fieldlist:
1604 for field in fieldlist:
1604 if field == 'metadata':
1605 if field == 'metadata':
1605 fields += ['user', 'description', 'date']
1606 fields += ['user', 'description', 'date']
1606 elif field == 'diff':
1607 elif field == 'diff':
1607 # a revision matching the diff must also match the files
1608 # a revision matching the diff must also match the files
1608 # since matching the diff is very costly, make sure to
1609 # since matching the diff is very costly, make sure to
1609 # also match the files first
1610 # also match the files first
1610 fields += ['files', 'diff']
1611 fields += ['files', 'diff']
1611 else:
1612 else:
1612 if field == 'author':
1613 if field == 'author':
1613 field = 'user'
1614 field = 'user'
1614 fields.append(field)
1615 fields.append(field)
1615 fields = set(fields)
1616 fields = set(fields)
1616 if 'summary' in fields and 'description' in fields:
1617 if 'summary' in fields and 'description' in fields:
1617 # If a revision matches its description it also matches its summary
1618 # If a revision matches its description it also matches its summary
1618 fields.discard('summary')
1619 fields.discard('summary')
1619
1620
1620 # We may want to match more than one field
1621 # We may want to match more than one field
1621 # Not all fields take the same amount of time to be matched
1622 # Not all fields take the same amount of time to be matched
1622 # Sort the selected fields in order of increasing matching cost
1623 # Sort the selected fields in order of increasing matching cost
1623 fieldorder = ['phase', 'parents', 'user', 'date', 'branch', 'summary',
1624 fieldorder = ['phase', 'parents', 'user', 'date', 'branch', 'summary',
1624 'files', 'description', 'substate', 'diff']
1625 'files', 'description', 'substate', 'diff']
1625 def fieldkeyfunc(f):
1626 def fieldkeyfunc(f):
1626 try:
1627 try:
1627 return fieldorder.index(f)
1628 return fieldorder.index(f)
1628 except ValueError:
1629 except ValueError:
1629 # assume an unknown field is very costly
1630 # assume an unknown field is very costly
1630 return len(fieldorder)
1631 return len(fieldorder)
1631 fields = list(fields)
1632 fields = list(fields)
1632 fields.sort(key=fieldkeyfunc)
1633 fields.sort(key=fieldkeyfunc)
1633
1634
1634 # Each field will be matched with its own "getfield" function
1635 # Each field will be matched with its own "getfield" function
1635 # which will be added to the getfieldfuncs array of functions
1636 # which will be added to the getfieldfuncs array of functions
1636 getfieldfuncs = []
1637 getfieldfuncs = []
1637 _funcs = {
1638 _funcs = {
1638 'user': lambda r: repo[r].user(),
1639 'user': lambda r: repo[r].user(),
1639 'branch': lambda r: repo[r].branch(),
1640 'branch': lambda r: repo[r].branch(),
1640 'date': lambda r: repo[r].date(),
1641 'date': lambda r: repo[r].date(),
1641 'description': lambda r: repo[r].description(),
1642 'description': lambda r: repo[r].description(),
1642 'files': lambda r: repo[r].files(),
1643 'files': lambda r: repo[r].files(),
1643 'parents': lambda r: repo[r].parents(),
1644 'parents': lambda r: repo[r].parents(),
1644 'phase': lambda r: repo[r].phase(),
1645 'phase': lambda r: repo[r].phase(),
1645 'substate': lambda r: repo[r].substate,
1646 'substate': lambda r: repo[r].substate,
1646 'summary': lambda r: repo[r].description().splitlines()[0],
1647 'summary': lambda r: repo[r].description().splitlines()[0],
1647 'diff': lambda r: list(repo[r].diff(git=True),)
1648 'diff': lambda r: list(repo[r].diff(git=True),)
1648 }
1649 }
1649 for info in fields:
1650 for info in fields:
1650 getfield = _funcs.get(info, None)
1651 getfield = _funcs.get(info, None)
1651 if getfield is None:
1652 if getfield is None:
1652 raise error.ParseError(
1653 raise error.ParseError(
1653 # i18n: "matching" is a keyword
1654 # i18n: "matching" is a keyword
1654 _("unexpected field name passed to matching: %s") % info)
1655 _("unexpected field name passed to matching: %s") % info)
1655 getfieldfuncs.append(getfield)
1656 getfieldfuncs.append(getfield)
1656 # convert the getfield array of functions into a "getinfo" function
1657 # convert the getfield array of functions into a "getinfo" function
1657 # which returns an array of field values (or a single value if there
1658 # which returns an array of field values (or a single value if there
1658 # is only one field to match)
1659 # is only one field to match)
1659 getinfo = lambda r: [f(r) for f in getfieldfuncs]
1660 getinfo = lambda r: [f(r) for f in getfieldfuncs]
1660
1661
1661 def matches(x):
1662 def matches(x):
1662 for rev in revs:
1663 for rev in revs:
1663 target = getinfo(rev)
1664 target = getinfo(rev)
1664 match = True
1665 match = True
1665 for n, f in enumerate(getfieldfuncs):
1666 for n, f in enumerate(getfieldfuncs):
1666 if target[n] != f(x):
1667 if target[n] != f(x):
1667 match = False
1668 match = False
1668 if match:
1669 if match:
1669 return True
1670 return True
1670 return False
1671 return False
1671
1672
1672 return subset.filter(matches)
1673 return subset.filter(matches)
1673
1674
1674 def reverse(repo, subset, x):
1675 def reverse(repo, subset, x):
1675 """``reverse(set)``
1676 """``reverse(set)``
1676 Reverse order of set.
1677 Reverse order of set.
1677 """
1678 """
1678 l = getset(repo, subset, x)
1679 l = getset(repo, subset, x)
1679 l.reverse()
1680 l.reverse()
1680 return l
1681 return l
1681
1682
1682 def roots(repo, subset, x):
1683 def roots(repo, subset, x):
1683 """``roots(set)``
1684 """``roots(set)``
1684 Changesets in set with no parent changeset in set.
1685 Changesets in set with no parent changeset in set.
1685 """
1686 """
1686 s = getset(repo, fullreposet(repo), x)
1687 s = getset(repo, fullreposet(repo), x)
1687 subset = baseset([r for r in s if r in subset])
1688 subset = baseset([r for r in s if r in subset])
1688 cs = _children(repo, subset, s)
1689 cs = _children(repo, subset, s)
1689 return subset - cs
1690 return subset - cs
1690
1691
1691 def secret(repo, subset, x):
1692 def secret(repo, subset, x):
1692 """``secret()``
1693 """``secret()``
1693 Changeset in secret phase."""
1694 Changeset in secret phase."""
1694 # i18n: "secret" is a keyword
1695 # i18n: "secret" is a keyword
1695 getargs(x, 0, 0, _("secret takes no arguments"))
1696 getargs(x, 0, 0, _("secret takes no arguments"))
1696 phase = repo._phasecache.phase
1697 phase = repo._phasecache.phase
1697 target = phases.secret
1698 target = phases.secret
1698 condition = lambda r: phase(repo, r) == target
1699 condition = lambda r: phase(repo, r) == target
1699 return subset.filter(condition, cache=False)
1700 return subset.filter(condition, cache=False)
1700
1701
1701 def sort(repo, subset, x):
1702 def sort(repo, subset, x):
1702 """``sort(set[, [-]key...])``
1703 """``sort(set[, [-]key...])``
1703 Sort set by keys. The default sort order is ascending, specify a key
1704 Sort set by keys. The default sort order is ascending, specify a key
1704 as ``-key`` to sort in descending order.
1705 as ``-key`` to sort in descending order.
1705
1706
1706 The keys can be:
1707 The keys can be:
1707
1708
1708 - ``rev`` for the revision number,
1709 - ``rev`` for the revision number,
1709 - ``branch`` for the branch name,
1710 - ``branch`` for the branch name,
1710 - ``desc`` for the commit message (description),
1711 - ``desc`` for the commit message (description),
1711 - ``user`` for user name (``author`` can be used as an alias),
1712 - ``user`` for user name (``author`` can be used as an alias),
1712 - ``date`` for the commit date
1713 - ``date`` for the commit date
1713 """
1714 """
1714 # i18n: "sort" is a keyword
1715 # i18n: "sort" is a keyword
1715 l = getargs(x, 1, 2, _("sort requires one or two arguments"))
1716 l = getargs(x, 1, 2, _("sort requires one or two arguments"))
1716 keys = "rev"
1717 keys = "rev"
1717 if len(l) == 2:
1718 if len(l) == 2:
1718 # i18n: "sort" is a keyword
1719 # i18n: "sort" is a keyword
1719 keys = getstring(l[1], _("sort spec must be a string"))
1720 keys = getstring(l[1], _("sort spec must be a string"))
1720
1721
1721 s = l[0]
1722 s = l[0]
1722 keys = keys.split()
1723 keys = keys.split()
1723 l = []
1724 l = []
1724 def invert(s):
1725 def invert(s):
1725 return "".join(chr(255 - ord(c)) for c in s)
1726 return "".join(chr(255 - ord(c)) for c in s)
1726 revs = getset(repo, subset, s)
1727 revs = getset(repo, subset, s)
1727 if keys == ["rev"]:
1728 if keys == ["rev"]:
1728 revs.sort()
1729 revs.sort()
1729 return revs
1730 return revs
1730 elif keys == ["-rev"]:
1731 elif keys == ["-rev"]:
1731 revs.sort(reverse=True)
1732 revs.sort(reverse=True)
1732 return revs
1733 return revs
1733 for r in revs:
1734 for r in revs:
1734 c = repo[r]
1735 c = repo[r]
1735 e = []
1736 e = []
1736 for k in keys:
1737 for k in keys:
1737 if k == 'rev':
1738 if k == 'rev':
1738 e.append(r)
1739 e.append(r)
1739 elif k == '-rev':
1740 elif k == '-rev':
1740 e.append(-r)
1741 e.append(-r)
1741 elif k == 'branch':
1742 elif k == 'branch':
1742 e.append(c.branch())
1743 e.append(c.branch())
1743 elif k == '-branch':
1744 elif k == '-branch':
1744 e.append(invert(c.branch()))
1745 e.append(invert(c.branch()))
1745 elif k == 'desc':
1746 elif k == 'desc':
1746 e.append(c.description())
1747 e.append(c.description())
1747 elif k == '-desc':
1748 elif k == '-desc':
1748 e.append(invert(c.description()))
1749 e.append(invert(c.description()))
1749 elif k in 'user author':
1750 elif k in 'user author':
1750 e.append(c.user())
1751 e.append(c.user())
1751 elif k in '-user -author':
1752 elif k in '-user -author':
1752 e.append(invert(c.user()))
1753 e.append(invert(c.user()))
1753 elif k == 'date':
1754 elif k == 'date':
1754 e.append(c.date()[0])
1755 e.append(c.date()[0])
1755 elif k == '-date':
1756 elif k == '-date':
1756 e.append(-c.date()[0])
1757 e.append(-c.date()[0])
1757 else:
1758 else:
1758 raise error.ParseError(_("unknown sort key %r") % k)
1759 raise error.ParseError(_("unknown sort key %r") % k)
1759 e.append(r)
1760 e.append(r)
1760 l.append(e)
1761 l.append(e)
1761 l.sort()
1762 l.sort()
1762 return baseset([e[-1] for e in l])
1763 return baseset([e[-1] for e in l])
1763
1764
1764 def subrepo(repo, subset, x):
1765 def subrepo(repo, subset, x):
1765 """``subrepo([pattern])``
1766 """``subrepo([pattern])``
1766 Changesets that add, modify or remove the given subrepo. If no subrepo
1767 Changesets that add, modify or remove the given subrepo. If no subrepo
1767 pattern is named, any subrepo changes are returned.
1768 pattern is named, any subrepo changes are returned.
1768 """
1769 """
1769 # i18n: "subrepo" is a keyword
1770 # i18n: "subrepo" is a keyword
1770 args = getargs(x, 0, 1, _('subrepo takes at most one argument'))
1771 args = getargs(x, 0, 1, _('subrepo takes at most one argument'))
1771 if len(args) != 0:
1772 if len(args) != 0:
1772 pat = getstring(args[0], _("subrepo requires a pattern"))
1773 pat = getstring(args[0], _("subrepo requires a pattern"))
1773
1774
1774 m = matchmod.exact(repo.root, repo.root, ['.hgsubstate'])
1775 m = matchmod.exact(repo.root, repo.root, ['.hgsubstate'])
1775
1776
1776 def submatches(names):
1777 def submatches(names):
1777 k, p, m = _stringmatcher(pat)
1778 k, p, m = _stringmatcher(pat)
1778 for name in names:
1779 for name in names:
1779 if m(name):
1780 if m(name):
1780 yield name
1781 yield name
1781
1782
1782 def matches(x):
1783 def matches(x):
1783 c = repo[x]
1784 c = repo[x]
1784 s = repo.status(c.p1().node(), c.node(), match=m)
1785 s = repo.status(c.p1().node(), c.node(), match=m)
1785
1786
1786 if len(args) == 0:
1787 if len(args) == 0:
1787 return s.added or s.modified or s.removed
1788 return s.added or s.modified or s.removed
1788
1789
1789 if s.added:
1790 if s.added:
1790 return util.any(submatches(c.substate.keys()))
1791 return util.any(submatches(c.substate.keys()))
1791
1792
1792 if s.modified:
1793 if s.modified:
1793 subs = set(c.p1().substate.keys())
1794 subs = set(c.p1().substate.keys())
1794 subs.update(c.substate.keys())
1795 subs.update(c.substate.keys())
1795
1796
1796 for path in submatches(subs):
1797 for path in submatches(subs):
1797 if c.p1().substate.get(path) != c.substate.get(path):
1798 if c.p1().substate.get(path) != c.substate.get(path):
1798 return True
1799 return True
1799
1800
1800 if s.removed:
1801 if s.removed:
1801 return util.any(submatches(c.p1().substate.keys()))
1802 return util.any(submatches(c.p1().substate.keys()))
1802
1803
1803 return False
1804 return False
1804
1805
1805 return subset.filter(matches)
1806 return subset.filter(matches)
1806
1807
1807 def _stringmatcher(pattern):
1808 def _stringmatcher(pattern):
1808 """
1809 """
1809 accepts a string, possibly starting with 're:' or 'literal:' prefix.
1810 accepts a string, possibly starting with 're:' or 'literal:' prefix.
1810 returns the matcher name, pattern, and matcher function.
1811 returns the matcher name, pattern, and matcher function.
1811 missing or unknown prefixes are treated as literal matches.
1812 missing or unknown prefixes are treated as literal matches.
1812
1813
1813 helper for tests:
1814 helper for tests:
1814 >>> def test(pattern, *tests):
1815 >>> def test(pattern, *tests):
1815 ... kind, pattern, matcher = _stringmatcher(pattern)
1816 ... kind, pattern, matcher = _stringmatcher(pattern)
1816 ... return (kind, pattern, [bool(matcher(t)) for t in tests])
1817 ... return (kind, pattern, [bool(matcher(t)) for t in tests])
1817
1818
1818 exact matching (no prefix):
1819 exact matching (no prefix):
1819 >>> test('abcdefg', 'abc', 'def', 'abcdefg')
1820 >>> test('abcdefg', 'abc', 'def', 'abcdefg')
1820 ('literal', 'abcdefg', [False, False, True])
1821 ('literal', 'abcdefg', [False, False, True])
1821
1822
1822 regex matching ('re:' prefix)
1823 regex matching ('re:' prefix)
1823 >>> test('re:a.+b', 'nomatch', 'fooadef', 'fooadefbar')
1824 >>> test('re:a.+b', 'nomatch', 'fooadef', 'fooadefbar')
1824 ('re', 'a.+b', [False, False, True])
1825 ('re', 'a.+b', [False, False, True])
1825
1826
1826 force exact matches ('literal:' prefix)
1827 force exact matches ('literal:' prefix)
1827 >>> test('literal:re:foobar', 'foobar', 're:foobar')
1828 >>> test('literal:re:foobar', 'foobar', 're:foobar')
1828 ('literal', 're:foobar', [False, True])
1829 ('literal', 're:foobar', [False, True])
1829
1830
1830 unknown prefixes are ignored and treated as literals
1831 unknown prefixes are ignored and treated as literals
1831 >>> test('foo:bar', 'foo', 'bar', 'foo:bar')
1832 >>> test('foo:bar', 'foo', 'bar', 'foo:bar')
1832 ('literal', 'foo:bar', [False, False, True])
1833 ('literal', 'foo:bar', [False, False, True])
1833 """
1834 """
1834 if pattern.startswith('re:'):
1835 if pattern.startswith('re:'):
1835 pattern = pattern[3:]
1836 pattern = pattern[3:]
1836 try:
1837 try:
1837 regex = re.compile(pattern)
1838 regex = re.compile(pattern)
1838 except re.error, e:
1839 except re.error, e:
1839 raise error.ParseError(_('invalid regular expression: %s')
1840 raise error.ParseError(_('invalid regular expression: %s')
1840 % e)
1841 % e)
1841 return 're', pattern, regex.search
1842 return 're', pattern, regex.search
1842 elif pattern.startswith('literal:'):
1843 elif pattern.startswith('literal:'):
1843 pattern = pattern[8:]
1844 pattern = pattern[8:]
1844 return 'literal', pattern, pattern.__eq__
1845 return 'literal', pattern, pattern.__eq__
1845
1846
1846 def _substringmatcher(pattern):
1847 def _substringmatcher(pattern):
1847 kind, pattern, matcher = _stringmatcher(pattern)
1848 kind, pattern, matcher = _stringmatcher(pattern)
1848 if kind == 'literal':
1849 if kind == 'literal':
1849 matcher = lambda s: pattern in s
1850 matcher = lambda s: pattern in s
1850 return kind, pattern, matcher
1851 return kind, pattern, matcher
1851
1852
1852 def tag(repo, subset, x):
1853 def tag(repo, subset, x):
1853 """``tag([name])``
1854 """``tag([name])``
1854 The specified tag by name, or all tagged revisions if no name is given.
1855 The specified tag by name, or all tagged revisions if no name is given.
1855
1856
1856 If `name` starts with `re:`, the remainder of the name is treated as
1857 If `name` starts with `re:`, the remainder of the name is treated as
1857 a regular expression. To match a tag that actually starts with `re:`,
1858 a regular expression. To match a tag that actually starts with `re:`,
1858 use the prefix `literal:`.
1859 use the prefix `literal:`.
1859 """
1860 """
1860 # i18n: "tag" is a keyword
1861 # i18n: "tag" is a keyword
1861 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
1862 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
1862 cl = repo.changelog
1863 cl = repo.changelog
1863 if args:
1864 if args:
1864 pattern = getstring(args[0],
1865 pattern = getstring(args[0],
1865 # i18n: "tag" is a keyword
1866 # i18n: "tag" is a keyword
1866 _('the argument to tag must be a string'))
1867 _('the argument to tag must be a string'))
1867 kind, pattern, matcher = _stringmatcher(pattern)
1868 kind, pattern, matcher = _stringmatcher(pattern)
1868 if kind == 'literal':
1869 if kind == 'literal':
1869 # avoid resolving all tags
1870 # avoid resolving all tags
1870 tn = repo._tagscache.tags.get(pattern, None)
1871 tn = repo._tagscache.tags.get(pattern, None)
1871 if tn is None:
1872 if tn is None:
1872 raise error.RepoLookupError(_("tag '%s' does not exist")
1873 raise error.RepoLookupError(_("tag '%s' does not exist")
1873 % pattern)
1874 % pattern)
1874 s = set([repo[tn].rev()])
1875 s = set([repo[tn].rev()])
1875 else:
1876 else:
1876 s = set([cl.rev(n) for t, n in repo.tagslist() if matcher(t)])
1877 s = set([cl.rev(n) for t, n in repo.tagslist() if matcher(t)])
1877 else:
1878 else:
1878 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
1879 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
1879 return subset & s
1880 return subset & s
1880
1881
1881 def tagged(repo, subset, x):
1882 def tagged(repo, subset, x):
1882 return tag(repo, subset, x)
1883 return tag(repo, subset, x)
1883
1884
1884 def unstable(repo, subset, x):
1885 def unstable(repo, subset, x):
1885 """``unstable()``
1886 """``unstable()``
1886 Non-obsolete changesets with obsolete ancestors.
1887 Non-obsolete changesets with obsolete ancestors.
1887 """
1888 """
1888 # i18n: "unstable" is a keyword
1889 # i18n: "unstable" is a keyword
1889 getargs(x, 0, 0, _("unstable takes no arguments"))
1890 getargs(x, 0, 0, _("unstable takes no arguments"))
1890 unstables = obsmod.getrevs(repo, 'unstable')
1891 unstables = obsmod.getrevs(repo, 'unstable')
1891 return subset & unstables
1892 return subset & unstables
1892
1893
1893
1894
1894 def user(repo, subset, x):
1895 def user(repo, subset, x):
1895 """``user(string)``
1896 """``user(string)``
1896 User name contains string. The match is case-insensitive.
1897 User name contains string. The match is case-insensitive.
1897
1898
1898 If `string` starts with `re:`, the remainder of the string is treated as
1899 If `string` starts with `re:`, the remainder of the string is treated as
1899 a regular expression. To match a user that actually contains `re:`, use
1900 a regular expression. To match a user that actually contains `re:`, use
1900 the prefix `literal:`.
1901 the prefix `literal:`.
1901 """
1902 """
1902 return author(repo, subset, x)
1903 return author(repo, subset, x)
1903
1904
1904 # experimental
1905 # experimental
1905 def wdir(repo, subset, x):
1906 def wdir(repo, subset, x):
1906 # i18n: "wdir" is a keyword
1907 # i18n: "wdir" is a keyword
1907 getargs(x, 0, 0, _("wdir takes no arguments"))
1908 getargs(x, 0, 0, _("wdir takes no arguments"))
1908 if None in subset:
1909 if None in subset or isinstance(subset, fullreposet):
1909 return baseset([None])
1910 return baseset([None])
1910 return baseset()
1911 return baseset()
1911
1912
1912 # for internal use
1913 # for internal use
1913 def _list(repo, subset, x):
1914 def _list(repo, subset, x):
1914 s = getstring(x, "internal error")
1915 s = getstring(x, "internal error")
1915 if not s:
1916 if not s:
1916 return baseset()
1917 return baseset()
1917 ls = [repo[r].rev() for r in s.split('\0')]
1918 ls = [repo[r].rev() for r in s.split('\0')]
1918 s = subset
1919 s = subset
1919 return baseset([r for r in ls if r in s])
1920 return baseset([r for r in ls if r in s])
1920
1921
1921 # for internal use
1922 # for internal use
1922 def _intlist(repo, subset, x):
1923 def _intlist(repo, subset, x):
1923 s = getstring(x, "internal error")
1924 s = getstring(x, "internal error")
1924 if not s:
1925 if not s:
1925 return baseset()
1926 return baseset()
1926 ls = [int(r) for r in s.split('\0')]
1927 ls = [int(r) for r in s.split('\0')]
1927 s = subset
1928 s = subset
1928 return baseset([r for r in ls if r in s])
1929 return baseset([r for r in ls if r in s])
1929
1930
1930 # for internal use
1931 # for internal use
1931 def _hexlist(repo, subset, x):
1932 def _hexlist(repo, subset, x):
1932 s = getstring(x, "internal error")
1933 s = getstring(x, "internal error")
1933 if not s:
1934 if not s:
1934 return baseset()
1935 return baseset()
1935 cl = repo.changelog
1936 cl = repo.changelog
1936 ls = [cl.rev(node.bin(r)) for r in s.split('\0')]
1937 ls = [cl.rev(node.bin(r)) for r in s.split('\0')]
1937 s = subset
1938 s = subset
1938 return baseset([r for r in ls if r in s])
1939 return baseset([r for r in ls if r in s])
1939
1940
1940 symbols = {
1941 symbols = {
1941 "adds": adds,
1942 "adds": adds,
1942 "all": getall,
1943 "all": getall,
1943 "ancestor": ancestor,
1944 "ancestor": ancestor,
1944 "ancestors": ancestors,
1945 "ancestors": ancestors,
1945 "_firstancestors": _firstancestors,
1946 "_firstancestors": _firstancestors,
1946 "author": author,
1947 "author": author,
1947 "bisect": bisect,
1948 "bisect": bisect,
1948 "bisected": bisected,
1949 "bisected": bisected,
1949 "bookmark": bookmark,
1950 "bookmark": bookmark,
1950 "branch": branch,
1951 "branch": branch,
1951 "branchpoint": branchpoint,
1952 "branchpoint": branchpoint,
1952 "bumped": bumped,
1953 "bumped": bumped,
1953 "bundle": bundle,
1954 "bundle": bundle,
1954 "children": children,
1955 "children": children,
1955 "closed": closed,
1956 "closed": closed,
1956 "contains": contains,
1957 "contains": contains,
1957 "converted": converted,
1958 "converted": converted,
1958 "date": date,
1959 "date": date,
1959 "desc": desc,
1960 "desc": desc,
1960 "descendants": descendants,
1961 "descendants": descendants,
1961 "_firstdescendants": _firstdescendants,
1962 "_firstdescendants": _firstdescendants,
1962 "destination": destination,
1963 "destination": destination,
1963 "divergent": divergent,
1964 "divergent": divergent,
1964 "draft": draft,
1965 "draft": draft,
1965 "extinct": extinct,
1966 "extinct": extinct,
1966 "extra": extra,
1967 "extra": extra,
1967 "file": hasfile,
1968 "file": hasfile,
1968 "filelog": filelog,
1969 "filelog": filelog,
1969 "first": first,
1970 "first": first,
1970 "follow": follow,
1971 "follow": follow,
1971 "_followfirst": _followfirst,
1972 "_followfirst": _followfirst,
1972 "grep": grep,
1973 "grep": grep,
1973 "head": head,
1974 "head": head,
1974 "heads": heads,
1975 "heads": heads,
1975 "hidden": hidden,
1976 "hidden": hidden,
1976 "id": node_,
1977 "id": node_,
1977 "keyword": keyword,
1978 "keyword": keyword,
1978 "last": last,
1979 "last": last,
1979 "limit": limit,
1980 "limit": limit,
1980 "_matchfiles": _matchfiles,
1981 "_matchfiles": _matchfiles,
1981 "max": maxrev,
1982 "max": maxrev,
1982 "merge": merge,
1983 "merge": merge,
1983 "min": minrev,
1984 "min": minrev,
1984 "modifies": modifies,
1985 "modifies": modifies,
1985 "named": named,
1986 "named": named,
1986 "obsolete": obsolete,
1987 "obsolete": obsolete,
1987 "only": only,
1988 "only": only,
1988 "origin": origin,
1989 "origin": origin,
1989 "outgoing": outgoing,
1990 "outgoing": outgoing,
1990 "p1": p1,
1991 "p1": p1,
1991 "p2": p2,
1992 "p2": p2,
1992 "parents": parents,
1993 "parents": parents,
1993 "present": present,
1994 "present": present,
1994 "public": public,
1995 "public": public,
1995 "remote": remote,
1996 "remote": remote,
1996 "removes": removes,
1997 "removes": removes,
1997 "rev": rev,
1998 "rev": rev,
1998 "reverse": reverse,
1999 "reverse": reverse,
1999 "roots": roots,
2000 "roots": roots,
2000 "sort": sort,
2001 "sort": sort,
2001 "secret": secret,
2002 "secret": secret,
2002 "subrepo": subrepo,
2003 "subrepo": subrepo,
2003 "matching": matching,
2004 "matching": matching,
2004 "tag": tag,
2005 "tag": tag,
2005 "tagged": tagged,
2006 "tagged": tagged,
2006 "user": user,
2007 "user": user,
2007 "unstable": unstable,
2008 "unstable": unstable,
2008 "wdir": wdir,
2009 "wdir": wdir,
2009 "_list": _list,
2010 "_list": _list,
2010 "_intlist": _intlist,
2011 "_intlist": _intlist,
2011 "_hexlist": _hexlist,
2012 "_hexlist": _hexlist,
2012 }
2013 }
2013
2014
2014 # symbols which can't be used for a DoS attack for any given input
2015 # symbols which can't be used for a DoS attack for any given input
2015 # (e.g. those which accept regexes as plain strings shouldn't be included)
2016 # (e.g. those which accept regexes as plain strings shouldn't be included)
2016 # functions that just return a lot of changesets (like all) don't count here
2017 # functions that just return a lot of changesets (like all) don't count here
2017 safesymbols = set([
2018 safesymbols = set([
2018 "adds",
2019 "adds",
2019 "all",
2020 "all",
2020 "ancestor",
2021 "ancestor",
2021 "ancestors",
2022 "ancestors",
2022 "_firstancestors",
2023 "_firstancestors",
2023 "author",
2024 "author",
2024 "bisect",
2025 "bisect",
2025 "bisected",
2026 "bisected",
2026 "bookmark",
2027 "bookmark",
2027 "branch",
2028 "branch",
2028 "branchpoint",
2029 "branchpoint",
2029 "bumped",
2030 "bumped",
2030 "bundle",
2031 "bundle",
2031 "children",
2032 "children",
2032 "closed",
2033 "closed",
2033 "converted",
2034 "converted",
2034 "date",
2035 "date",
2035 "desc",
2036 "desc",
2036 "descendants",
2037 "descendants",
2037 "_firstdescendants",
2038 "_firstdescendants",
2038 "destination",
2039 "destination",
2039 "divergent",
2040 "divergent",
2040 "draft",
2041 "draft",
2041 "extinct",
2042 "extinct",
2042 "extra",
2043 "extra",
2043 "file",
2044 "file",
2044 "filelog",
2045 "filelog",
2045 "first",
2046 "first",
2046 "follow",
2047 "follow",
2047 "_followfirst",
2048 "_followfirst",
2048 "head",
2049 "head",
2049 "heads",
2050 "heads",
2050 "hidden",
2051 "hidden",
2051 "id",
2052 "id",
2052 "keyword",
2053 "keyword",
2053 "last",
2054 "last",
2054 "limit",
2055 "limit",
2055 "_matchfiles",
2056 "_matchfiles",
2056 "max",
2057 "max",
2057 "merge",
2058 "merge",
2058 "min",
2059 "min",
2059 "modifies",
2060 "modifies",
2060 "obsolete",
2061 "obsolete",
2061 "only",
2062 "only",
2062 "origin",
2063 "origin",
2063 "outgoing",
2064 "outgoing",
2064 "p1",
2065 "p1",
2065 "p2",
2066 "p2",
2066 "parents",
2067 "parents",
2067 "present",
2068 "present",
2068 "public",
2069 "public",
2069 "remote",
2070 "remote",
2070 "removes",
2071 "removes",
2071 "rev",
2072 "rev",
2072 "reverse",
2073 "reverse",
2073 "roots",
2074 "roots",
2074 "sort",
2075 "sort",
2075 "secret",
2076 "secret",
2076 "matching",
2077 "matching",
2077 "tag",
2078 "tag",
2078 "tagged",
2079 "tagged",
2079 "user",
2080 "user",
2080 "unstable",
2081 "unstable",
2081 "wdir",
2082 "wdir",
2082 "_list",
2083 "_list",
2083 "_intlist",
2084 "_intlist",
2084 "_hexlist",
2085 "_hexlist",
2085 ])
2086 ])
2086
2087
2087 methods = {
2088 methods = {
2088 "range": rangeset,
2089 "range": rangeset,
2089 "dagrange": dagrange,
2090 "dagrange": dagrange,
2090 "string": stringset,
2091 "string": stringset,
2091 "symbol": symbolset,
2092 "symbol": symbolset,
2092 "and": andset,
2093 "and": andset,
2093 "or": orset,
2094 "or": orset,
2094 "not": notset,
2095 "not": notset,
2095 "list": listset,
2096 "list": listset,
2096 "func": func,
2097 "func": func,
2097 "ancestor": ancestorspec,
2098 "ancestor": ancestorspec,
2098 "parent": parentspec,
2099 "parent": parentspec,
2099 "parentpost": p1,
2100 "parentpost": p1,
2100 "only": only,
2101 "only": only,
2101 }
2102 }
2102
2103
2103 def optimize(x, small):
2104 def optimize(x, small):
2104 if x is None:
2105 if x is None:
2105 return 0, x
2106 return 0, x
2106
2107
2107 smallbonus = 1
2108 smallbonus = 1
2108 if small:
2109 if small:
2109 smallbonus = .5
2110 smallbonus = .5
2110
2111
2111 op = x[0]
2112 op = x[0]
2112 if op == 'minus':
2113 if op == 'minus':
2113 return optimize(('and', x[1], ('not', x[2])), small)
2114 return optimize(('and', x[1], ('not', x[2])), small)
2114 elif op == 'only':
2115 elif op == 'only':
2115 return optimize(('func', ('symbol', 'only'),
2116 return optimize(('func', ('symbol', 'only'),
2116 ('list', x[1], x[2])), small)
2117 ('list', x[1], x[2])), small)
2117 elif op == 'onlypost':
2118 elif op == 'onlypost':
2118 return optimize(('func', ('symbol', 'only'), x[1]), small)
2119 return optimize(('func', ('symbol', 'only'), x[1]), small)
2119 elif op == 'dagrangepre':
2120 elif op == 'dagrangepre':
2120 return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
2121 return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
2121 elif op == 'dagrangepost':
2122 elif op == 'dagrangepost':
2122 return optimize(('func', ('symbol', 'descendants'), x[1]), small)
2123 return optimize(('func', ('symbol', 'descendants'), x[1]), small)
2123 elif op == 'rangepre':
2124 elif op == 'rangepre':
2124 return optimize(('range', ('string', '0'), x[1]), small)
2125 return optimize(('range', ('string', '0'), x[1]), small)
2125 elif op == 'rangepost':
2126 elif op == 'rangepost':
2126 return optimize(('range', x[1], ('string', 'tip')), small)
2127 return optimize(('range', x[1], ('string', 'tip')), small)
2127 elif op == 'negate':
2128 elif op == 'negate':
2128 return optimize(('string',
2129 return optimize(('string',
2129 '-' + getstring(x[1], _("can't negate that"))), small)
2130 '-' + getstring(x[1], _("can't negate that"))), small)
2130 elif op in 'string symbol negate':
2131 elif op in 'string symbol negate':
2131 return smallbonus, x # single revisions are small
2132 return smallbonus, x # single revisions are small
2132 elif op == 'and':
2133 elif op == 'and':
2133 wa, ta = optimize(x[1], True)
2134 wa, ta = optimize(x[1], True)
2134 wb, tb = optimize(x[2], True)
2135 wb, tb = optimize(x[2], True)
2135
2136
2136 # (::x and not ::y)/(not ::y and ::x) have a fast path
2137 # (::x and not ::y)/(not ::y and ::x) have a fast path
2137 def isonly(revs, bases):
2138 def isonly(revs, bases):
2138 return (
2139 return (
2139 revs[0] == 'func'
2140 revs[0] == 'func'
2140 and getstring(revs[1], _('not a symbol')) == 'ancestors'
2141 and getstring(revs[1], _('not a symbol')) == 'ancestors'
2141 and bases[0] == 'not'
2142 and bases[0] == 'not'
2142 and bases[1][0] == 'func'
2143 and bases[1][0] == 'func'
2143 and getstring(bases[1][1], _('not a symbol')) == 'ancestors')
2144 and getstring(bases[1][1], _('not a symbol')) == 'ancestors')
2144
2145
2145 w = min(wa, wb)
2146 w = min(wa, wb)
2146 if isonly(ta, tb):
2147 if isonly(ta, tb):
2147 return w, ('func', ('symbol', 'only'), ('list', ta[2], tb[1][2]))
2148 return w, ('func', ('symbol', 'only'), ('list', ta[2], tb[1][2]))
2148 if isonly(tb, ta):
2149 if isonly(tb, ta):
2149 return w, ('func', ('symbol', 'only'), ('list', tb[2], ta[1][2]))
2150 return w, ('func', ('symbol', 'only'), ('list', tb[2], ta[1][2]))
2150
2151
2151 if wa > wb:
2152 if wa > wb:
2152 return w, (op, tb, ta)
2153 return w, (op, tb, ta)
2153 return w, (op, ta, tb)
2154 return w, (op, ta, tb)
2154 elif op == 'or':
2155 elif op == 'or':
2155 wa, ta = optimize(x[1], False)
2156 wa, ta = optimize(x[1], False)
2156 wb, tb = optimize(x[2], False)
2157 wb, tb = optimize(x[2], False)
2157 if wb < wa:
2158 if wb < wa:
2158 wb, wa = wa, wb
2159 wb, wa = wa, wb
2159 return max(wa, wb), (op, ta, tb)
2160 return max(wa, wb), (op, ta, tb)
2160 elif op == 'not':
2161 elif op == 'not':
2161 o = optimize(x[1], not small)
2162 o = optimize(x[1], not small)
2162 return o[0], (op, o[1])
2163 return o[0], (op, o[1])
2163 elif op == 'parentpost':
2164 elif op == 'parentpost':
2164 o = optimize(x[1], small)
2165 o = optimize(x[1], small)
2165 return o[0], (op, o[1])
2166 return o[0], (op, o[1])
2166 elif op == 'group':
2167 elif op == 'group':
2167 return optimize(x[1], small)
2168 return optimize(x[1], small)
2168 elif op in 'dagrange range list parent ancestorspec':
2169 elif op in 'dagrange range list parent ancestorspec':
2169 if op == 'parent':
2170 if op == 'parent':
2170 # x^:y means (x^) : y, not x ^ (:y)
2171 # x^:y means (x^) : y, not x ^ (:y)
2171 post = ('parentpost', x[1])
2172 post = ('parentpost', x[1])
2172 if x[2][0] == 'dagrangepre':
2173 if x[2][0] == 'dagrangepre':
2173 return optimize(('dagrange', post, x[2][1]), small)
2174 return optimize(('dagrange', post, x[2][1]), small)
2174 elif x[2][0] == 'rangepre':
2175 elif x[2][0] == 'rangepre':
2175 return optimize(('range', post, x[2][1]), small)
2176 return optimize(('range', post, x[2][1]), small)
2176
2177
2177 wa, ta = optimize(x[1], small)
2178 wa, ta = optimize(x[1], small)
2178 wb, tb = optimize(x[2], small)
2179 wb, tb = optimize(x[2], small)
2179 return wa + wb, (op, ta, tb)
2180 return wa + wb, (op, ta, tb)
2180 elif op == 'func':
2181 elif op == 'func':
2181 f = getstring(x[1], _("not a symbol"))
2182 f = getstring(x[1], _("not a symbol"))
2182 wa, ta = optimize(x[2], small)
2183 wa, ta = optimize(x[2], small)
2183 if f in ("author branch closed date desc file grep keyword "
2184 if f in ("author branch closed date desc file grep keyword "
2184 "outgoing user"):
2185 "outgoing user"):
2185 w = 10 # slow
2186 w = 10 # slow
2186 elif f in "modifies adds removes":
2187 elif f in "modifies adds removes":
2187 w = 30 # slower
2188 w = 30 # slower
2188 elif f == "contains":
2189 elif f == "contains":
2189 w = 100 # very slow
2190 w = 100 # very slow
2190 elif f == "ancestor":
2191 elif f == "ancestor":
2191 w = 1 * smallbonus
2192 w = 1 * smallbonus
2192 elif f in "reverse limit first _intlist":
2193 elif f in "reverse limit first _intlist":
2193 w = 0
2194 w = 0
2194 elif f in "sort":
2195 elif f in "sort":
2195 w = 10 # assume most sorts look at changelog
2196 w = 10 # assume most sorts look at changelog
2196 else:
2197 else:
2197 w = 1
2198 w = 1
2198 return w + wa, (op, x[1], ta)
2199 return w + wa, (op, x[1], ta)
2199 return 1, x
2200 return 1, x
2200
2201
2201 _aliasarg = ('func', ('symbol', '_aliasarg'))
2202 _aliasarg = ('func', ('symbol', '_aliasarg'))
2202 def _getaliasarg(tree):
2203 def _getaliasarg(tree):
2203 """If tree matches ('func', ('symbol', '_aliasarg'), ('string', X))
2204 """If tree matches ('func', ('symbol', '_aliasarg'), ('string', X))
2204 return X, None otherwise.
2205 return X, None otherwise.
2205 """
2206 """
2206 if (len(tree) == 3 and tree[:2] == _aliasarg
2207 if (len(tree) == 3 and tree[:2] == _aliasarg
2207 and tree[2][0] == 'string'):
2208 and tree[2][0] == 'string'):
2208 return tree[2][1]
2209 return tree[2][1]
2209 return None
2210 return None
2210
2211
2211 def _checkaliasarg(tree, known=None):
2212 def _checkaliasarg(tree, known=None):
2212 """Check tree contains no _aliasarg construct or only ones which
2213 """Check tree contains no _aliasarg construct or only ones which
2213 value is in known. Used to avoid alias placeholders injection.
2214 value is in known. Used to avoid alias placeholders injection.
2214 """
2215 """
2215 if isinstance(tree, tuple):
2216 if isinstance(tree, tuple):
2216 arg = _getaliasarg(tree)
2217 arg = _getaliasarg(tree)
2217 if arg is not None and (not known or arg not in known):
2218 if arg is not None and (not known or arg not in known):
2218 raise error.UnknownIdentifier('_aliasarg', [])
2219 raise error.UnknownIdentifier('_aliasarg', [])
2219 for t in tree:
2220 for t in tree:
2220 _checkaliasarg(t, known)
2221 _checkaliasarg(t, known)
2221
2222
2222 # the set of valid characters for the initial letter of symbols in
2223 # the set of valid characters for the initial letter of symbols in
2223 # alias declarations and definitions
2224 # alias declarations and definitions
2224 _aliassyminitletters = set(c for c in [chr(i) for i in xrange(256)]
2225 _aliassyminitletters = set(c for c in [chr(i) for i in xrange(256)]
2225 if c.isalnum() or c in '._@$' or ord(c) > 127)
2226 if c.isalnum() or c in '._@$' or ord(c) > 127)
2226
2227
2227 def _tokenizealias(program, lookup=None):
2228 def _tokenizealias(program, lookup=None):
2228 """Parse alias declaration/definition into a stream of tokens
2229 """Parse alias declaration/definition into a stream of tokens
2229
2230
2230 This allows symbol names to use also ``$`` as an initial letter
2231 This allows symbol names to use also ``$`` as an initial letter
2231 (for backward compatibility), and callers of this function should
2232 (for backward compatibility), and callers of this function should
2232 examine whether ``$`` is used also for unexpected symbols or not.
2233 examine whether ``$`` is used also for unexpected symbols or not.
2233 """
2234 """
2234 return tokenize(program, lookup=lookup,
2235 return tokenize(program, lookup=lookup,
2235 syminitletters=_aliassyminitletters)
2236 syminitletters=_aliassyminitletters)
2236
2237
2237 def _parsealiasdecl(decl):
2238 def _parsealiasdecl(decl):
2238 """Parse alias declaration ``decl``
2239 """Parse alias declaration ``decl``
2239
2240
2240 This returns ``(name, tree, args, errorstr)`` tuple:
2241 This returns ``(name, tree, args, errorstr)`` tuple:
2241
2242
2242 - ``name``: of declared alias (may be ``decl`` itself at error)
2243 - ``name``: of declared alias (may be ``decl`` itself at error)
2243 - ``tree``: parse result (or ``None`` at error)
2244 - ``tree``: parse result (or ``None`` at error)
2244 - ``args``: list of alias argument names (or None for symbol declaration)
2245 - ``args``: list of alias argument names (or None for symbol declaration)
2245 - ``errorstr``: detail about detected error (or None)
2246 - ``errorstr``: detail about detected error (or None)
2246
2247
2247 >>> _parsealiasdecl('foo')
2248 >>> _parsealiasdecl('foo')
2248 ('foo', ('symbol', 'foo'), None, None)
2249 ('foo', ('symbol', 'foo'), None, None)
2249 >>> _parsealiasdecl('$foo')
2250 >>> _parsealiasdecl('$foo')
2250 ('$foo', None, None, "'$' not for alias arguments")
2251 ('$foo', None, None, "'$' not for alias arguments")
2251 >>> _parsealiasdecl('foo::bar')
2252 >>> _parsealiasdecl('foo::bar')
2252 ('foo::bar', None, None, 'invalid format')
2253 ('foo::bar', None, None, 'invalid format')
2253 >>> _parsealiasdecl('foo bar')
2254 >>> _parsealiasdecl('foo bar')
2254 ('foo bar', None, None, 'at 4: invalid token')
2255 ('foo bar', None, None, 'at 4: invalid token')
2255 >>> _parsealiasdecl('foo()')
2256 >>> _parsealiasdecl('foo()')
2256 ('foo', ('func', ('symbol', 'foo')), [], None)
2257 ('foo', ('func', ('symbol', 'foo')), [], None)
2257 >>> _parsealiasdecl('$foo()')
2258 >>> _parsealiasdecl('$foo()')
2258 ('$foo()', None, None, "'$' not for alias arguments")
2259 ('$foo()', None, None, "'$' not for alias arguments")
2259 >>> _parsealiasdecl('foo($1, $2)')
2260 >>> _parsealiasdecl('foo($1, $2)')
2260 ('foo', ('func', ('symbol', 'foo')), ['$1', '$2'], None)
2261 ('foo', ('func', ('symbol', 'foo')), ['$1', '$2'], None)
2261 >>> _parsealiasdecl('foo(bar_bar, baz.baz)')
2262 >>> _parsealiasdecl('foo(bar_bar, baz.baz)')
2262 ('foo', ('func', ('symbol', 'foo')), ['bar_bar', 'baz.baz'], None)
2263 ('foo', ('func', ('symbol', 'foo')), ['bar_bar', 'baz.baz'], None)
2263 >>> _parsealiasdecl('foo($1, $2, nested($1, $2))')
2264 >>> _parsealiasdecl('foo($1, $2, nested($1, $2))')
2264 ('foo($1, $2, nested($1, $2))', None, None, 'invalid argument list')
2265 ('foo($1, $2, nested($1, $2))', None, None, 'invalid argument list')
2265 >>> _parsealiasdecl('foo(bar($1, $2))')
2266 >>> _parsealiasdecl('foo(bar($1, $2))')
2266 ('foo(bar($1, $2))', None, None, 'invalid argument list')
2267 ('foo(bar($1, $2))', None, None, 'invalid argument list')
2267 >>> _parsealiasdecl('foo("string")')
2268 >>> _parsealiasdecl('foo("string")')
2268 ('foo("string")', None, None, 'invalid argument list')
2269 ('foo("string")', None, None, 'invalid argument list')
2269 >>> _parsealiasdecl('foo($1, $2')
2270 >>> _parsealiasdecl('foo($1, $2')
2270 ('foo($1, $2', None, None, 'at 10: unexpected token: end')
2271 ('foo($1, $2', None, None, 'at 10: unexpected token: end')
2271 >>> _parsealiasdecl('foo("string')
2272 >>> _parsealiasdecl('foo("string')
2272 ('foo("string', None, None, 'at 5: unterminated string')
2273 ('foo("string', None, None, 'at 5: unterminated string')
2273 >>> _parsealiasdecl('foo($1, $2, $1)')
2274 >>> _parsealiasdecl('foo($1, $2, $1)')
2274 ('foo', None, None, 'argument names collide with each other')
2275 ('foo', None, None, 'argument names collide with each other')
2275 """
2276 """
2276 p = parser.parser(_tokenizealias, elements)
2277 p = parser.parser(_tokenizealias, elements)
2277 try:
2278 try:
2278 tree, pos = p.parse(decl)
2279 tree, pos = p.parse(decl)
2279 if (pos != len(decl)):
2280 if (pos != len(decl)):
2280 raise error.ParseError(_('invalid token'), pos)
2281 raise error.ParseError(_('invalid token'), pos)
2281
2282
2282 if isvalidsymbol(tree):
2283 if isvalidsymbol(tree):
2283 # "name = ...." style
2284 # "name = ...." style
2284 name = getsymbol(tree)
2285 name = getsymbol(tree)
2285 if name.startswith('$'):
2286 if name.startswith('$'):
2286 return (decl, None, None, _("'$' not for alias arguments"))
2287 return (decl, None, None, _("'$' not for alias arguments"))
2287 return (name, ('symbol', name), None, None)
2288 return (name, ('symbol', name), None, None)
2288
2289
2289 if isvalidfunc(tree):
2290 if isvalidfunc(tree):
2290 # "name(arg, ....) = ...." style
2291 # "name(arg, ....) = ...." style
2291 name = getfuncname(tree)
2292 name = getfuncname(tree)
2292 if name.startswith('$'):
2293 if name.startswith('$'):
2293 return (decl, None, None, _("'$' not for alias arguments"))
2294 return (decl, None, None, _("'$' not for alias arguments"))
2294 args = []
2295 args = []
2295 for arg in getfuncargs(tree):
2296 for arg in getfuncargs(tree):
2296 if not isvalidsymbol(arg):
2297 if not isvalidsymbol(arg):
2297 return (decl, None, None, _("invalid argument list"))
2298 return (decl, None, None, _("invalid argument list"))
2298 args.append(getsymbol(arg))
2299 args.append(getsymbol(arg))
2299 if len(args) != len(set(args)):
2300 if len(args) != len(set(args)):
2300 return (name, None, None,
2301 return (name, None, None,
2301 _("argument names collide with each other"))
2302 _("argument names collide with each other"))
2302 return (name, ('func', ('symbol', name)), args, None)
2303 return (name, ('func', ('symbol', name)), args, None)
2303
2304
2304 return (decl, None, None, _("invalid format"))
2305 return (decl, None, None, _("invalid format"))
2305 except error.ParseError, inst:
2306 except error.ParseError, inst:
2306 return (decl, None, None, parseerrordetail(inst))
2307 return (decl, None, None, parseerrordetail(inst))
2307
2308
2308 def _parsealiasdefn(defn, args):
2309 def _parsealiasdefn(defn, args):
2309 """Parse alias definition ``defn``
2310 """Parse alias definition ``defn``
2310
2311
2311 This function also replaces alias argument references in the
2312 This function also replaces alias argument references in the
2312 specified definition by ``_aliasarg(ARGNAME)``.
2313 specified definition by ``_aliasarg(ARGNAME)``.
2313
2314
2314 ``args`` is a list of alias argument names, or None if the alias
2315 ``args`` is a list of alias argument names, or None if the alias
2315 is declared as a symbol.
2316 is declared as a symbol.
2316
2317
2317 This returns "tree" as parsing result.
2318 This returns "tree" as parsing result.
2318
2319
2319 >>> args = ['$1', '$2', 'foo']
2320 >>> args = ['$1', '$2', 'foo']
2320 >>> print prettyformat(_parsealiasdefn('$1 or foo', args))
2321 >>> print prettyformat(_parsealiasdefn('$1 or foo', args))
2321 (or
2322 (or
2322 (func
2323 (func
2323 ('symbol', '_aliasarg')
2324 ('symbol', '_aliasarg')
2324 ('string', '$1'))
2325 ('string', '$1'))
2325 (func
2326 (func
2326 ('symbol', '_aliasarg')
2327 ('symbol', '_aliasarg')
2327 ('string', 'foo')))
2328 ('string', 'foo')))
2328 >>> try:
2329 >>> try:
2329 ... _parsealiasdefn('$1 or $bar', args)
2330 ... _parsealiasdefn('$1 or $bar', args)
2330 ... except error.ParseError, inst:
2331 ... except error.ParseError, inst:
2331 ... print parseerrordetail(inst)
2332 ... print parseerrordetail(inst)
2332 at 6: '$' not for alias arguments
2333 at 6: '$' not for alias arguments
2333 >>> args = ['$1', '$10', 'foo']
2334 >>> args = ['$1', '$10', 'foo']
2334 >>> print prettyformat(_parsealiasdefn('$10 or foobar', args))
2335 >>> print prettyformat(_parsealiasdefn('$10 or foobar', args))
2335 (or
2336 (or
2336 (func
2337 (func
2337 ('symbol', '_aliasarg')
2338 ('symbol', '_aliasarg')
2338 ('string', '$10'))
2339 ('string', '$10'))
2339 ('symbol', 'foobar'))
2340 ('symbol', 'foobar'))
2340 >>> print prettyformat(_parsealiasdefn('"$1" or "foo"', args))
2341 >>> print prettyformat(_parsealiasdefn('"$1" or "foo"', args))
2341 (or
2342 (or
2342 ('string', '$1')
2343 ('string', '$1')
2343 ('string', 'foo'))
2344 ('string', 'foo'))
2344 """
2345 """
2345 def tokenizedefn(program, lookup=None):
2346 def tokenizedefn(program, lookup=None):
2346 if args:
2347 if args:
2347 argset = set(args)
2348 argset = set(args)
2348 else:
2349 else:
2349 argset = set()
2350 argset = set()
2350
2351
2351 for t, value, pos in _tokenizealias(program, lookup=lookup):
2352 for t, value, pos in _tokenizealias(program, lookup=lookup):
2352 if t == 'symbol':
2353 if t == 'symbol':
2353 if value in argset:
2354 if value in argset:
2354 # emulate tokenization of "_aliasarg('ARGNAME')":
2355 # emulate tokenization of "_aliasarg('ARGNAME')":
2355 # "_aliasarg()" is an unknown symbol only used separate
2356 # "_aliasarg()" is an unknown symbol only used separate
2356 # alias argument placeholders from regular strings.
2357 # alias argument placeholders from regular strings.
2357 yield ('symbol', '_aliasarg', pos)
2358 yield ('symbol', '_aliasarg', pos)
2358 yield ('(', None, pos)
2359 yield ('(', None, pos)
2359 yield ('string', value, pos)
2360 yield ('string', value, pos)
2360 yield (')', None, pos)
2361 yield (')', None, pos)
2361 continue
2362 continue
2362 elif value.startswith('$'):
2363 elif value.startswith('$'):
2363 raise error.ParseError(_("'$' not for alias arguments"),
2364 raise error.ParseError(_("'$' not for alias arguments"),
2364 pos)
2365 pos)
2365 yield (t, value, pos)
2366 yield (t, value, pos)
2366
2367
2367 p = parser.parser(tokenizedefn, elements)
2368 p = parser.parser(tokenizedefn, elements)
2368 tree, pos = p.parse(defn)
2369 tree, pos = p.parse(defn)
2369 if pos != len(defn):
2370 if pos != len(defn):
2370 raise error.ParseError(_('invalid token'), pos)
2371 raise error.ParseError(_('invalid token'), pos)
2371 return tree
2372 return tree
2372
2373
2373 class revsetalias(object):
2374 class revsetalias(object):
2374 # whether own `error` information is already shown or not.
2375 # whether own `error` information is already shown or not.
2375 # this avoids showing same warning multiple times at each `findaliases`.
2376 # this avoids showing same warning multiple times at each `findaliases`.
2376 warned = False
2377 warned = False
2377
2378
2378 def __init__(self, name, value):
2379 def __init__(self, name, value):
2379 '''Aliases like:
2380 '''Aliases like:
2380
2381
2381 h = heads(default)
2382 h = heads(default)
2382 b($1) = ancestors($1) - ancestors(default)
2383 b($1) = ancestors($1) - ancestors(default)
2383 '''
2384 '''
2384 self.name, self.tree, self.args, self.error = _parsealiasdecl(name)
2385 self.name, self.tree, self.args, self.error = _parsealiasdecl(name)
2385 if self.error:
2386 if self.error:
2386 self.error = _('failed to parse the declaration of revset alias'
2387 self.error = _('failed to parse the declaration of revset alias'
2387 ' "%s": %s') % (self.name, self.error)
2388 ' "%s": %s') % (self.name, self.error)
2388 return
2389 return
2389
2390
2390 try:
2391 try:
2391 self.replacement = _parsealiasdefn(value, self.args)
2392 self.replacement = _parsealiasdefn(value, self.args)
2392 # Check for placeholder injection
2393 # Check for placeholder injection
2393 _checkaliasarg(self.replacement, self.args)
2394 _checkaliasarg(self.replacement, self.args)
2394 except error.ParseError, inst:
2395 except error.ParseError, inst:
2395 self.error = _('failed to parse the definition of revset alias'
2396 self.error = _('failed to parse the definition of revset alias'
2396 ' "%s": %s') % (self.name, parseerrordetail(inst))
2397 ' "%s": %s') % (self.name, parseerrordetail(inst))
2397
2398
2398 def _getalias(aliases, tree):
2399 def _getalias(aliases, tree):
2399 """If tree looks like an unexpanded alias, return it. Return None
2400 """If tree looks like an unexpanded alias, return it. Return None
2400 otherwise.
2401 otherwise.
2401 """
2402 """
2402 if isinstance(tree, tuple) and tree:
2403 if isinstance(tree, tuple) and tree:
2403 if tree[0] == 'symbol' and len(tree) == 2:
2404 if tree[0] == 'symbol' and len(tree) == 2:
2404 name = tree[1]
2405 name = tree[1]
2405 alias = aliases.get(name)
2406 alias = aliases.get(name)
2406 if alias and alias.args is None and alias.tree == tree:
2407 if alias and alias.args is None and alias.tree == tree:
2407 return alias
2408 return alias
2408 if tree[0] == 'func' and len(tree) > 1:
2409 if tree[0] == 'func' and len(tree) > 1:
2409 if tree[1][0] == 'symbol' and len(tree[1]) == 2:
2410 if tree[1][0] == 'symbol' and len(tree[1]) == 2:
2410 name = tree[1][1]
2411 name = tree[1][1]
2411 alias = aliases.get(name)
2412 alias = aliases.get(name)
2412 if alias and alias.args is not None and alias.tree == tree[:2]:
2413 if alias and alias.args is not None and alias.tree == tree[:2]:
2413 return alias
2414 return alias
2414 return None
2415 return None
2415
2416
2416 def _expandargs(tree, args):
2417 def _expandargs(tree, args):
2417 """Replace _aliasarg instances with the substitution value of the
2418 """Replace _aliasarg instances with the substitution value of the
2418 same name in args, recursively.
2419 same name in args, recursively.
2419 """
2420 """
2420 if not tree or not isinstance(tree, tuple):
2421 if not tree or not isinstance(tree, tuple):
2421 return tree
2422 return tree
2422 arg = _getaliasarg(tree)
2423 arg = _getaliasarg(tree)
2423 if arg is not None:
2424 if arg is not None:
2424 return args[arg]
2425 return args[arg]
2425 return tuple(_expandargs(t, args) for t in tree)
2426 return tuple(_expandargs(t, args) for t in tree)
2426
2427
2427 def _expandaliases(aliases, tree, expanding, cache):
2428 def _expandaliases(aliases, tree, expanding, cache):
2428 """Expand aliases in tree, recursively.
2429 """Expand aliases in tree, recursively.
2429
2430
2430 'aliases' is a dictionary mapping user defined aliases to
2431 'aliases' is a dictionary mapping user defined aliases to
2431 revsetalias objects.
2432 revsetalias objects.
2432 """
2433 """
2433 if not isinstance(tree, tuple):
2434 if not isinstance(tree, tuple):
2434 # Do not expand raw strings
2435 # Do not expand raw strings
2435 return tree
2436 return tree
2436 alias = _getalias(aliases, tree)
2437 alias = _getalias(aliases, tree)
2437 if alias is not None:
2438 if alias is not None:
2438 if alias.error:
2439 if alias.error:
2439 raise util.Abort(alias.error)
2440 raise util.Abort(alias.error)
2440 if alias in expanding:
2441 if alias in expanding:
2441 raise error.ParseError(_('infinite expansion of revset alias "%s" '
2442 raise error.ParseError(_('infinite expansion of revset alias "%s" '
2442 'detected') % alias.name)
2443 'detected') % alias.name)
2443 expanding.append(alias)
2444 expanding.append(alias)
2444 if alias.name not in cache:
2445 if alias.name not in cache:
2445 cache[alias.name] = _expandaliases(aliases, alias.replacement,
2446 cache[alias.name] = _expandaliases(aliases, alias.replacement,
2446 expanding, cache)
2447 expanding, cache)
2447 result = cache[alias.name]
2448 result = cache[alias.name]
2448 expanding.pop()
2449 expanding.pop()
2449 if alias.args is not None:
2450 if alias.args is not None:
2450 l = getlist(tree[2])
2451 l = getlist(tree[2])
2451 if len(l) != len(alias.args):
2452 if len(l) != len(alias.args):
2452 raise error.ParseError(
2453 raise error.ParseError(
2453 _('invalid number of arguments: %s') % len(l))
2454 _('invalid number of arguments: %s') % len(l))
2454 l = [_expandaliases(aliases, a, [], cache) for a in l]
2455 l = [_expandaliases(aliases, a, [], cache) for a in l]
2455 result = _expandargs(result, dict(zip(alias.args, l)))
2456 result = _expandargs(result, dict(zip(alias.args, l)))
2456 else:
2457 else:
2457 result = tuple(_expandaliases(aliases, t, expanding, cache)
2458 result = tuple(_expandaliases(aliases, t, expanding, cache)
2458 for t in tree)
2459 for t in tree)
2459 return result
2460 return result
2460
2461
2461 def findaliases(ui, tree, showwarning=None):
2462 def findaliases(ui, tree, showwarning=None):
2462 _checkaliasarg(tree)
2463 _checkaliasarg(tree)
2463 aliases = {}
2464 aliases = {}
2464 for k, v in ui.configitems('revsetalias'):
2465 for k, v in ui.configitems('revsetalias'):
2465 alias = revsetalias(k, v)
2466 alias = revsetalias(k, v)
2466 aliases[alias.name] = alias
2467 aliases[alias.name] = alias
2467 tree = _expandaliases(aliases, tree, [], {})
2468 tree = _expandaliases(aliases, tree, [], {})
2468 if showwarning:
2469 if showwarning:
2469 # warn about problematic (but not referred) aliases
2470 # warn about problematic (but not referred) aliases
2470 for name, alias in sorted(aliases.iteritems()):
2471 for name, alias in sorted(aliases.iteritems()):
2471 if alias.error and not alias.warned:
2472 if alias.error and not alias.warned:
2472 showwarning(_('warning: %s\n') % (alias.error))
2473 showwarning(_('warning: %s\n') % (alias.error))
2473 alias.warned = True
2474 alias.warned = True
2474 return tree
2475 return tree
2475
2476
2476 def foldconcat(tree):
2477 def foldconcat(tree):
2477 """Fold elements to be concatenated by `##`
2478 """Fold elements to be concatenated by `##`
2478 """
2479 """
2479 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
2480 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
2480 return tree
2481 return tree
2481 if tree[0] == '_concat':
2482 if tree[0] == '_concat':
2482 pending = [tree]
2483 pending = [tree]
2483 l = []
2484 l = []
2484 while pending:
2485 while pending:
2485 e = pending.pop()
2486 e = pending.pop()
2486 if e[0] == '_concat':
2487 if e[0] == '_concat':
2487 pending.extend(reversed(e[1:]))
2488 pending.extend(reversed(e[1:]))
2488 elif e[0] in ('string', 'symbol'):
2489 elif e[0] in ('string', 'symbol'):
2489 l.append(e[1])
2490 l.append(e[1])
2490 else:
2491 else:
2491 msg = _("\"##\" can't concatenate \"%s\" element") % (e[0])
2492 msg = _("\"##\" can't concatenate \"%s\" element") % (e[0])
2492 raise error.ParseError(msg)
2493 raise error.ParseError(msg)
2493 return ('string', ''.join(l))
2494 return ('string', ''.join(l))
2494 else:
2495 else:
2495 return tuple(foldconcat(t) for t in tree)
2496 return tuple(foldconcat(t) for t in tree)
2496
2497
2497 def parse(spec, lookup=None):
2498 def parse(spec, lookup=None):
2498 p = parser.parser(tokenize, elements)
2499 p = parser.parser(tokenize, elements)
2499 return p.parse(spec, lookup=lookup)
2500 return p.parse(spec, lookup=lookup)
2500
2501
2501 def posttreebuilthook(tree, repo):
2502 def posttreebuilthook(tree, repo):
2502 # hook for extensions to execute code on the optimized tree
2503 # hook for extensions to execute code on the optimized tree
2503 pass
2504 pass
2504
2505
2505 def match(ui, spec, repo=None):
2506 def match(ui, spec, repo=None):
2506 if not spec:
2507 if not spec:
2507 raise error.ParseError(_("empty query"))
2508 raise error.ParseError(_("empty query"))
2508 lookup = None
2509 lookup = None
2509 if repo:
2510 if repo:
2510 lookup = repo.__contains__
2511 lookup = repo.__contains__
2511 tree, pos = parse(spec, lookup)
2512 tree, pos = parse(spec, lookup)
2512 if (pos != len(spec)):
2513 if (pos != len(spec)):
2513 raise error.ParseError(_("invalid token"), pos)
2514 raise error.ParseError(_("invalid token"), pos)
2514 if ui:
2515 if ui:
2515 tree = findaliases(ui, tree, showwarning=ui.warn)
2516 tree = findaliases(ui, tree, showwarning=ui.warn)
2516 tree = foldconcat(tree)
2517 tree = foldconcat(tree)
2517 weight, tree = optimize(tree, True)
2518 weight, tree = optimize(tree, True)
2518 posttreebuilthook(tree, repo)
2519 posttreebuilthook(tree, repo)
2519 def mfunc(repo, subset=None):
2520 def mfunc(repo, subset=None):
2520 if subset is None:
2521 if subset is None:
2521 subset = fullreposet(repo)
2522 subset = fullreposet(repo)
2522 if util.safehasattr(subset, 'isascending'):
2523 if util.safehasattr(subset, 'isascending'):
2523 result = getset(repo, subset, tree)
2524 result = getset(repo, subset, tree)
2524 else:
2525 else:
2525 result = getset(repo, baseset(subset), tree)
2526 result = getset(repo, baseset(subset), tree)
2526 return result
2527 return result
2527 return mfunc
2528 return mfunc
2528
2529
2529 def formatspec(expr, *args):
2530 def formatspec(expr, *args):
2530 '''
2531 '''
2531 This is a convenience function for using revsets internally, and
2532 This is a convenience function for using revsets internally, and
2532 escapes arguments appropriately. Aliases are intentionally ignored
2533 escapes arguments appropriately. Aliases are intentionally ignored
2533 so that intended expression behavior isn't accidentally subverted.
2534 so that intended expression behavior isn't accidentally subverted.
2534
2535
2535 Supported arguments:
2536 Supported arguments:
2536
2537
2537 %r = revset expression, parenthesized
2538 %r = revset expression, parenthesized
2538 %d = int(arg), no quoting
2539 %d = int(arg), no quoting
2539 %s = string(arg), escaped and single-quoted
2540 %s = string(arg), escaped and single-quoted
2540 %b = arg.branch(), escaped and single-quoted
2541 %b = arg.branch(), escaped and single-quoted
2541 %n = hex(arg), single-quoted
2542 %n = hex(arg), single-quoted
2542 %% = a literal '%'
2543 %% = a literal '%'
2543
2544
2544 Prefixing the type with 'l' specifies a parenthesized list of that type.
2545 Prefixing the type with 'l' specifies a parenthesized list of that type.
2545
2546
2546 >>> formatspec('%r:: and %lr', '10 or 11', ("this()", "that()"))
2547 >>> formatspec('%r:: and %lr', '10 or 11', ("this()", "that()"))
2547 '(10 or 11):: and ((this()) or (that()))'
2548 '(10 or 11):: and ((this()) or (that()))'
2548 >>> formatspec('%d:: and not %d::', 10, 20)
2549 >>> formatspec('%d:: and not %d::', 10, 20)
2549 '10:: and not 20::'
2550 '10:: and not 20::'
2550 >>> formatspec('%ld or %ld', [], [1])
2551 >>> formatspec('%ld or %ld', [], [1])
2551 "_list('') or 1"
2552 "_list('') or 1"
2552 >>> formatspec('keyword(%s)', 'foo\\xe9')
2553 >>> formatspec('keyword(%s)', 'foo\\xe9')
2553 "keyword('foo\\\\xe9')"
2554 "keyword('foo\\\\xe9')"
2554 >>> b = lambda: 'default'
2555 >>> b = lambda: 'default'
2555 >>> b.branch = b
2556 >>> b.branch = b
2556 >>> formatspec('branch(%b)', b)
2557 >>> formatspec('branch(%b)', b)
2557 "branch('default')"
2558 "branch('default')"
2558 >>> formatspec('root(%ls)', ['a', 'b', 'c', 'd'])
2559 >>> formatspec('root(%ls)', ['a', 'b', 'c', 'd'])
2559 "root(_list('a\\x00b\\x00c\\x00d'))"
2560 "root(_list('a\\x00b\\x00c\\x00d'))"
2560 '''
2561 '''
2561
2562
2562 def quote(s):
2563 def quote(s):
2563 return repr(str(s))
2564 return repr(str(s))
2564
2565
2565 def argtype(c, arg):
2566 def argtype(c, arg):
2566 if c == 'd':
2567 if c == 'd':
2567 return str(int(arg))
2568 return str(int(arg))
2568 elif c == 's':
2569 elif c == 's':
2569 return quote(arg)
2570 return quote(arg)
2570 elif c == 'r':
2571 elif c == 'r':
2571 parse(arg) # make sure syntax errors are confined
2572 parse(arg) # make sure syntax errors are confined
2572 return '(%s)' % arg
2573 return '(%s)' % arg
2573 elif c == 'n':
2574 elif c == 'n':
2574 return quote(node.hex(arg))
2575 return quote(node.hex(arg))
2575 elif c == 'b':
2576 elif c == 'b':
2576 return quote(arg.branch())
2577 return quote(arg.branch())
2577
2578
2578 def listexp(s, t):
2579 def listexp(s, t):
2579 l = len(s)
2580 l = len(s)
2580 if l == 0:
2581 if l == 0:
2581 return "_list('')"
2582 return "_list('')"
2582 elif l == 1:
2583 elif l == 1:
2583 return argtype(t, s[0])
2584 return argtype(t, s[0])
2584 elif t == 'd':
2585 elif t == 'd':
2585 return "_intlist('%s')" % "\0".join(str(int(a)) for a in s)
2586 return "_intlist('%s')" % "\0".join(str(int(a)) for a in s)
2586 elif t == 's':
2587 elif t == 's':
2587 return "_list('%s')" % "\0".join(s)
2588 return "_list('%s')" % "\0".join(s)
2588 elif t == 'n':
2589 elif t == 'n':
2589 return "_hexlist('%s')" % "\0".join(node.hex(a) for a in s)
2590 return "_hexlist('%s')" % "\0".join(node.hex(a) for a in s)
2590 elif t == 'b':
2591 elif t == 'b':
2591 return "_list('%s')" % "\0".join(a.branch() for a in s)
2592 return "_list('%s')" % "\0".join(a.branch() for a in s)
2592
2593
2593 m = l // 2
2594 m = l // 2
2594 return '(%s or %s)' % (listexp(s[:m], t), listexp(s[m:], t))
2595 return '(%s or %s)' % (listexp(s[:m], t), listexp(s[m:], t))
2595
2596
2596 ret = ''
2597 ret = ''
2597 pos = 0
2598 pos = 0
2598 arg = 0
2599 arg = 0
2599 while pos < len(expr):
2600 while pos < len(expr):
2600 c = expr[pos]
2601 c = expr[pos]
2601 if c == '%':
2602 if c == '%':
2602 pos += 1
2603 pos += 1
2603 d = expr[pos]
2604 d = expr[pos]
2604 if d == '%':
2605 if d == '%':
2605 ret += d
2606 ret += d
2606 elif d in 'dsnbr':
2607 elif d in 'dsnbr':
2607 ret += argtype(d, args[arg])
2608 ret += argtype(d, args[arg])
2608 arg += 1
2609 arg += 1
2609 elif d == 'l':
2610 elif d == 'l':
2610 # a list of some type
2611 # a list of some type
2611 pos += 1
2612 pos += 1
2612 d = expr[pos]
2613 d = expr[pos]
2613 ret += listexp(list(args[arg]), d)
2614 ret += listexp(list(args[arg]), d)
2614 arg += 1
2615 arg += 1
2615 else:
2616 else:
2616 raise util.Abort('unexpected revspec format character %s' % d)
2617 raise util.Abort('unexpected revspec format character %s' % d)
2617 else:
2618 else:
2618 ret += c
2619 ret += c
2619 pos += 1
2620 pos += 1
2620
2621
2621 return ret
2622 return ret
2622
2623
2623 def prettyformat(tree):
2624 def prettyformat(tree):
2624 def _prettyformat(tree, level, lines):
2625 def _prettyformat(tree, level, lines):
2625 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
2626 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
2626 lines.append((level, str(tree)))
2627 lines.append((level, str(tree)))
2627 else:
2628 else:
2628 lines.append((level, '(%s' % tree[0]))
2629 lines.append((level, '(%s' % tree[0]))
2629 for s in tree[1:]:
2630 for s in tree[1:]:
2630 _prettyformat(s, level + 1, lines)
2631 _prettyformat(s, level + 1, lines)
2631 lines[-1:] = [(lines[-1][0], lines[-1][1] + ')')]
2632 lines[-1:] = [(lines[-1][0], lines[-1][1] + ')')]
2632
2633
2633 lines = []
2634 lines = []
2634 _prettyformat(tree, 0, lines)
2635 _prettyformat(tree, 0, lines)
2635 output = '\n'.join((' '*l + s) for l, s in lines)
2636 output = '\n'.join((' '*l + s) for l, s in lines)
2636 return output
2637 return output
2637
2638
2638 def depth(tree):
2639 def depth(tree):
2639 if isinstance(tree, tuple):
2640 if isinstance(tree, tuple):
2640 return max(map(depth, tree)) + 1
2641 return max(map(depth, tree)) + 1
2641 else:
2642 else:
2642 return 0
2643 return 0
2643
2644
2644 def funcsused(tree):
2645 def funcsused(tree):
2645 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
2646 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
2646 return set()
2647 return set()
2647 else:
2648 else:
2648 funcs = set()
2649 funcs = set()
2649 for s in tree[1:]:
2650 for s in tree[1:]:
2650 funcs |= funcsused(s)
2651 funcs |= funcsused(s)
2651 if tree[0] == 'func':
2652 if tree[0] == 'func':
2652 funcs.add(tree[1][1])
2653 funcs.add(tree[1][1])
2653 return funcs
2654 return funcs
2654
2655
2655 class abstractsmartset(object):
2656 class abstractsmartset(object):
2656
2657
2657 def __nonzero__(self):
2658 def __nonzero__(self):
2658 """True if the smartset is not empty"""
2659 """True if the smartset is not empty"""
2659 raise NotImplementedError()
2660 raise NotImplementedError()
2660
2661
2661 def __contains__(self, rev):
2662 def __contains__(self, rev):
2662 """provide fast membership testing"""
2663 """provide fast membership testing"""
2663 raise NotImplementedError()
2664 raise NotImplementedError()
2664
2665
2665 def __iter__(self):
2666 def __iter__(self):
2666 """iterate the set in the order it is supposed to be iterated"""
2667 """iterate the set in the order it is supposed to be iterated"""
2667 raise NotImplementedError()
2668 raise NotImplementedError()
2668
2669
2669 # Attributes containing a function to perform a fast iteration in a given
2670 # Attributes containing a function to perform a fast iteration in a given
2670 # direction. A smartset can have none, one, or both defined.
2671 # direction. A smartset can have none, one, or both defined.
2671 #
2672 #
2672 # Default value is None instead of a function returning None to avoid
2673 # Default value is None instead of a function returning None to avoid
2673 # initializing an iterator just for testing if a fast method exists.
2674 # initializing an iterator just for testing if a fast method exists.
2674 fastasc = None
2675 fastasc = None
2675 fastdesc = None
2676 fastdesc = None
2676
2677
2677 def isascending(self):
2678 def isascending(self):
2678 """True if the set will iterate in ascending order"""
2679 """True if the set will iterate in ascending order"""
2679 raise NotImplementedError()
2680 raise NotImplementedError()
2680
2681
2681 def isdescending(self):
2682 def isdescending(self):
2682 """True if the set will iterate in descending order"""
2683 """True if the set will iterate in descending order"""
2683 raise NotImplementedError()
2684 raise NotImplementedError()
2684
2685
2685 def min(self):
2686 def min(self):
2686 """return the minimum element in the set"""
2687 """return the minimum element in the set"""
2687 if self.fastasc is not None:
2688 if self.fastasc is not None:
2688 for r in self.fastasc():
2689 for r in self.fastasc():
2689 return r
2690 return r
2690 raise ValueError('arg is an empty sequence')
2691 raise ValueError('arg is an empty sequence')
2691 return min(self)
2692 return min(self)
2692
2693
2693 def max(self):
2694 def max(self):
2694 """return the maximum element in the set"""
2695 """return the maximum element in the set"""
2695 if self.fastdesc is not None:
2696 if self.fastdesc is not None:
2696 for r in self.fastdesc():
2697 for r in self.fastdesc():
2697 return r
2698 return r
2698 raise ValueError('arg is an empty sequence')
2699 raise ValueError('arg is an empty sequence')
2699 return max(self)
2700 return max(self)
2700
2701
2701 def first(self):
2702 def first(self):
2702 """return the first element in the set (user iteration perspective)
2703 """return the first element in the set (user iteration perspective)
2703
2704
2704 Return None if the set is empty"""
2705 Return None if the set is empty"""
2705 raise NotImplementedError()
2706 raise NotImplementedError()
2706
2707
2707 def last(self):
2708 def last(self):
2708 """return the last element in the set (user iteration perspective)
2709 """return the last element in the set (user iteration perspective)
2709
2710
2710 Return None if the set is empty"""
2711 Return None if the set is empty"""
2711 raise NotImplementedError()
2712 raise NotImplementedError()
2712
2713
2713 def __len__(self):
2714 def __len__(self):
2714 """return the length of the smartsets
2715 """return the length of the smartsets
2715
2716
2716 This can be expensive on smartset that could be lazy otherwise."""
2717 This can be expensive on smartset that could be lazy otherwise."""
2717 raise NotImplementedError()
2718 raise NotImplementedError()
2718
2719
2719 def reverse(self):
2720 def reverse(self):
2720 """reverse the expected iteration order"""
2721 """reverse the expected iteration order"""
2721 raise NotImplementedError()
2722 raise NotImplementedError()
2722
2723
2723 def sort(self, reverse=True):
2724 def sort(self, reverse=True):
2724 """get the set to iterate in an ascending or descending order"""
2725 """get the set to iterate in an ascending or descending order"""
2725 raise NotImplementedError()
2726 raise NotImplementedError()
2726
2727
2727 def __and__(self, other):
2728 def __and__(self, other):
2728 """Returns a new object with the intersection of the two collections.
2729 """Returns a new object with the intersection of the two collections.
2729
2730
2730 This is part of the mandatory API for smartset."""
2731 This is part of the mandatory API for smartset."""
2731 if isinstance(other, fullreposet):
2732 if isinstance(other, fullreposet):
2732 return self
2733 return self
2733 return self.filter(other.__contains__, cache=False)
2734 return self.filter(other.__contains__, cache=False)
2734
2735
2735 def __add__(self, other):
2736 def __add__(self, other):
2736 """Returns a new object with the union of the two collections.
2737 """Returns a new object with the union of the two collections.
2737
2738
2738 This is part of the mandatory API for smartset."""
2739 This is part of the mandatory API for smartset."""
2739 return addset(self, other)
2740 return addset(self, other)
2740
2741
2741 def __sub__(self, other):
2742 def __sub__(self, other):
2742 """Returns a new object with the substraction of the two collections.
2743 """Returns a new object with the substraction of the two collections.
2743
2744
2744 This is part of the mandatory API for smartset."""
2745 This is part of the mandatory API for smartset."""
2745 c = other.__contains__
2746 c = other.__contains__
2746 return self.filter(lambda r: not c(r), cache=False)
2747 return self.filter(lambda r: not c(r), cache=False)
2747
2748
2748 def filter(self, condition, cache=True):
2749 def filter(self, condition, cache=True):
2749 """Returns this smartset filtered by condition as a new smartset.
2750 """Returns this smartset filtered by condition as a new smartset.
2750
2751
2751 `condition` is a callable which takes a revision number and returns a
2752 `condition` is a callable which takes a revision number and returns a
2752 boolean.
2753 boolean.
2753
2754
2754 This is part of the mandatory API for smartset."""
2755 This is part of the mandatory API for smartset."""
2755 # builtin cannot be cached. but do not needs to
2756 # builtin cannot be cached. but do not needs to
2756 if cache and util.safehasattr(condition, 'func_code'):
2757 if cache and util.safehasattr(condition, 'func_code'):
2757 condition = util.cachefunc(condition)
2758 condition = util.cachefunc(condition)
2758 return filteredset(self, condition)
2759 return filteredset(self, condition)
2759
2760
2760 class baseset(abstractsmartset):
2761 class baseset(abstractsmartset):
2761 """Basic data structure that represents a revset and contains the basic
2762 """Basic data structure that represents a revset and contains the basic
2762 operation that it should be able to perform.
2763 operation that it should be able to perform.
2763
2764
2764 Every method in this class should be implemented by any smartset class.
2765 Every method in this class should be implemented by any smartset class.
2765 """
2766 """
2766 def __init__(self, data=()):
2767 def __init__(self, data=()):
2767 if not isinstance(data, list):
2768 if not isinstance(data, list):
2768 data = list(data)
2769 data = list(data)
2769 self._list = data
2770 self._list = data
2770 self._ascending = None
2771 self._ascending = None
2771
2772
2772 @util.propertycache
2773 @util.propertycache
2773 def _set(self):
2774 def _set(self):
2774 return set(self._list)
2775 return set(self._list)
2775
2776
2776 @util.propertycache
2777 @util.propertycache
2777 def _asclist(self):
2778 def _asclist(self):
2778 asclist = self._list[:]
2779 asclist = self._list[:]
2779 asclist.sort()
2780 asclist.sort()
2780 return asclist
2781 return asclist
2781
2782
2782 def __iter__(self):
2783 def __iter__(self):
2783 if self._ascending is None:
2784 if self._ascending is None:
2784 return iter(self._list)
2785 return iter(self._list)
2785 elif self._ascending:
2786 elif self._ascending:
2786 return iter(self._asclist)
2787 return iter(self._asclist)
2787 else:
2788 else:
2788 return reversed(self._asclist)
2789 return reversed(self._asclist)
2789
2790
2790 def fastasc(self):
2791 def fastasc(self):
2791 return iter(self._asclist)
2792 return iter(self._asclist)
2792
2793
2793 def fastdesc(self):
2794 def fastdesc(self):
2794 return reversed(self._asclist)
2795 return reversed(self._asclist)
2795
2796
2796 @util.propertycache
2797 @util.propertycache
2797 def __contains__(self):
2798 def __contains__(self):
2798 return self._set.__contains__
2799 return self._set.__contains__
2799
2800
2800 def __nonzero__(self):
2801 def __nonzero__(self):
2801 return bool(self._list)
2802 return bool(self._list)
2802
2803
2803 def sort(self, reverse=False):
2804 def sort(self, reverse=False):
2804 self._ascending = not bool(reverse)
2805 self._ascending = not bool(reverse)
2805
2806
2806 def reverse(self):
2807 def reverse(self):
2807 if self._ascending is None:
2808 if self._ascending is None:
2808 self._list.reverse()
2809 self._list.reverse()
2809 else:
2810 else:
2810 self._ascending = not self._ascending
2811 self._ascending = not self._ascending
2811
2812
2812 def __len__(self):
2813 def __len__(self):
2813 return len(self._list)
2814 return len(self._list)
2814
2815
2815 def isascending(self):
2816 def isascending(self):
2816 """Returns True if the collection is ascending order, False if not.
2817 """Returns True if the collection is ascending order, False if not.
2817
2818
2818 This is part of the mandatory API for smartset."""
2819 This is part of the mandatory API for smartset."""
2819 if len(self) <= 1:
2820 if len(self) <= 1:
2820 return True
2821 return True
2821 return self._ascending is not None and self._ascending
2822 return self._ascending is not None and self._ascending
2822
2823
2823 def isdescending(self):
2824 def isdescending(self):
2824 """Returns True if the collection is descending order, False if not.
2825 """Returns True if the collection is descending order, False if not.
2825
2826
2826 This is part of the mandatory API for smartset."""
2827 This is part of the mandatory API for smartset."""
2827 if len(self) <= 1:
2828 if len(self) <= 1:
2828 return True
2829 return True
2829 return self._ascending is not None and not self._ascending
2830 return self._ascending is not None and not self._ascending
2830
2831
2831 def first(self):
2832 def first(self):
2832 if self:
2833 if self:
2833 if self._ascending is None:
2834 if self._ascending is None:
2834 return self._list[0]
2835 return self._list[0]
2835 elif self._ascending:
2836 elif self._ascending:
2836 return self._asclist[0]
2837 return self._asclist[0]
2837 else:
2838 else:
2838 return self._asclist[-1]
2839 return self._asclist[-1]
2839 return None
2840 return None
2840
2841
2841 def last(self):
2842 def last(self):
2842 if self:
2843 if self:
2843 if self._ascending is None:
2844 if self._ascending is None:
2844 return self._list[-1]
2845 return self._list[-1]
2845 elif self._ascending:
2846 elif self._ascending:
2846 return self._asclist[-1]
2847 return self._asclist[-1]
2847 else:
2848 else:
2848 return self._asclist[0]
2849 return self._asclist[0]
2849 return None
2850 return None
2850
2851
2851 def __repr__(self):
2852 def __repr__(self):
2852 d = {None: '', False: '-', True: '+'}[self._ascending]
2853 d = {None: '', False: '-', True: '+'}[self._ascending]
2853 return '<%s%s %r>' % (type(self).__name__, d, self._list)
2854 return '<%s%s %r>' % (type(self).__name__, d, self._list)
2854
2855
2855 class filteredset(abstractsmartset):
2856 class filteredset(abstractsmartset):
2856 """Duck type for baseset class which iterates lazily over the revisions in
2857 """Duck type for baseset class which iterates lazily over the revisions in
2857 the subset and contains a function which tests for membership in the
2858 the subset and contains a function which tests for membership in the
2858 revset
2859 revset
2859 """
2860 """
2860 def __init__(self, subset, condition=lambda x: True):
2861 def __init__(self, subset, condition=lambda x: True):
2861 """
2862 """
2862 condition: a function that decide whether a revision in the subset
2863 condition: a function that decide whether a revision in the subset
2863 belongs to the revset or not.
2864 belongs to the revset or not.
2864 """
2865 """
2865 self._subset = subset
2866 self._subset = subset
2866 self._condition = condition
2867 self._condition = condition
2867 self._cache = {}
2868 self._cache = {}
2868
2869
2869 def __contains__(self, x):
2870 def __contains__(self, x):
2870 c = self._cache
2871 c = self._cache
2871 if x not in c:
2872 if x not in c:
2872 v = c[x] = x in self._subset and self._condition(x)
2873 v = c[x] = x in self._subset and self._condition(x)
2873 return v
2874 return v
2874 return c[x]
2875 return c[x]
2875
2876
2876 def __iter__(self):
2877 def __iter__(self):
2877 return self._iterfilter(self._subset)
2878 return self._iterfilter(self._subset)
2878
2879
2879 def _iterfilter(self, it):
2880 def _iterfilter(self, it):
2880 cond = self._condition
2881 cond = self._condition
2881 for x in it:
2882 for x in it:
2882 if cond(x):
2883 if cond(x):
2883 yield x
2884 yield x
2884
2885
2885 @property
2886 @property
2886 def fastasc(self):
2887 def fastasc(self):
2887 it = self._subset.fastasc
2888 it = self._subset.fastasc
2888 if it is None:
2889 if it is None:
2889 return None
2890 return None
2890 return lambda: self._iterfilter(it())
2891 return lambda: self._iterfilter(it())
2891
2892
2892 @property
2893 @property
2893 def fastdesc(self):
2894 def fastdesc(self):
2894 it = self._subset.fastdesc
2895 it = self._subset.fastdesc
2895 if it is None:
2896 if it is None:
2896 return None
2897 return None
2897 return lambda: self._iterfilter(it())
2898 return lambda: self._iterfilter(it())
2898
2899
2899 def __nonzero__(self):
2900 def __nonzero__(self):
2900 for r in self:
2901 for r in self:
2901 return True
2902 return True
2902 return False
2903 return False
2903
2904
2904 def __len__(self):
2905 def __len__(self):
2905 # Basic implementation to be changed in future patches.
2906 # Basic implementation to be changed in future patches.
2906 l = baseset([r for r in self])
2907 l = baseset([r for r in self])
2907 return len(l)
2908 return len(l)
2908
2909
2909 def sort(self, reverse=False):
2910 def sort(self, reverse=False):
2910 self._subset.sort(reverse=reverse)
2911 self._subset.sort(reverse=reverse)
2911
2912
2912 def reverse(self):
2913 def reverse(self):
2913 self._subset.reverse()
2914 self._subset.reverse()
2914
2915
2915 def isascending(self):
2916 def isascending(self):
2916 return self._subset.isascending()
2917 return self._subset.isascending()
2917
2918
2918 def isdescending(self):
2919 def isdescending(self):
2919 return self._subset.isdescending()
2920 return self._subset.isdescending()
2920
2921
2921 def first(self):
2922 def first(self):
2922 for x in self:
2923 for x in self:
2923 return x
2924 return x
2924 return None
2925 return None
2925
2926
2926 def last(self):
2927 def last(self):
2927 it = None
2928 it = None
2928 if self._subset.isascending:
2929 if self._subset.isascending:
2929 it = self.fastdesc
2930 it = self.fastdesc
2930 elif self._subset.isdescending:
2931 elif self._subset.isdescending:
2931 it = self.fastdesc
2932 it = self.fastdesc
2932 if it is None:
2933 if it is None:
2933 # slowly consume everything. This needs improvement
2934 # slowly consume everything. This needs improvement
2934 it = lambda: reversed(list(self))
2935 it = lambda: reversed(list(self))
2935 for x in it():
2936 for x in it():
2936 return x
2937 return x
2937 return None
2938 return None
2938
2939
2939 def __repr__(self):
2940 def __repr__(self):
2940 return '<%s %r>' % (type(self).__name__, self._subset)
2941 return '<%s %r>' % (type(self).__name__, self._subset)
2941
2942
2942 class addset(abstractsmartset):
2943 class addset(abstractsmartset):
2943 """Represent the addition of two sets
2944 """Represent the addition of two sets
2944
2945
2945 Wrapper structure for lazily adding two structures without losing much
2946 Wrapper structure for lazily adding two structures without losing much
2946 performance on the __contains__ method
2947 performance on the __contains__ method
2947
2948
2948 If the ascending attribute is set, that means the two structures are
2949 If the ascending attribute is set, that means the two structures are
2949 ordered in either an ascending or descending way. Therefore, we can add
2950 ordered in either an ascending or descending way. Therefore, we can add
2950 them maintaining the order by iterating over both at the same time
2951 them maintaining the order by iterating over both at the same time
2951 """
2952 """
2952 def __init__(self, revs1, revs2, ascending=None):
2953 def __init__(self, revs1, revs2, ascending=None):
2953 self._r1 = revs1
2954 self._r1 = revs1
2954 self._r2 = revs2
2955 self._r2 = revs2
2955 self._iter = None
2956 self._iter = None
2956 self._ascending = ascending
2957 self._ascending = ascending
2957 self._genlist = None
2958 self._genlist = None
2958 self._asclist = None
2959 self._asclist = None
2959
2960
2960 def __len__(self):
2961 def __len__(self):
2961 return len(self._list)
2962 return len(self._list)
2962
2963
2963 def __nonzero__(self):
2964 def __nonzero__(self):
2964 return bool(self._r1) or bool(self._r2)
2965 return bool(self._r1) or bool(self._r2)
2965
2966
2966 @util.propertycache
2967 @util.propertycache
2967 def _list(self):
2968 def _list(self):
2968 if not self._genlist:
2969 if not self._genlist:
2969 self._genlist = baseset(self._iterator())
2970 self._genlist = baseset(self._iterator())
2970 return self._genlist
2971 return self._genlist
2971
2972
2972 def _iterator(self):
2973 def _iterator(self):
2973 """Iterate over both collections without repeating elements
2974 """Iterate over both collections without repeating elements
2974
2975
2975 If the ascending attribute is not set, iterate over the first one and
2976 If the ascending attribute is not set, iterate over the first one and
2976 then over the second one checking for membership on the first one so we
2977 then over the second one checking for membership on the first one so we
2977 dont yield any duplicates.
2978 dont yield any duplicates.
2978
2979
2979 If the ascending attribute is set, iterate over both collections at the
2980 If the ascending attribute is set, iterate over both collections at the
2980 same time, yielding only one value at a time in the given order.
2981 same time, yielding only one value at a time in the given order.
2981 """
2982 """
2982 if self._ascending is None:
2983 if self._ascending is None:
2983 def gen():
2984 def gen():
2984 for r in self._r1:
2985 for r in self._r1:
2985 yield r
2986 yield r
2986 inr1 = self._r1.__contains__
2987 inr1 = self._r1.__contains__
2987 for r in self._r2:
2988 for r in self._r2:
2988 if not inr1(r):
2989 if not inr1(r):
2989 yield r
2990 yield r
2990 gen = gen()
2991 gen = gen()
2991 else:
2992 else:
2992 iter1 = iter(self._r1)
2993 iter1 = iter(self._r1)
2993 iter2 = iter(self._r2)
2994 iter2 = iter(self._r2)
2994 gen = self._iterordered(self._ascending, iter1, iter2)
2995 gen = self._iterordered(self._ascending, iter1, iter2)
2995 return gen
2996 return gen
2996
2997
2997 def __iter__(self):
2998 def __iter__(self):
2998 if self._ascending is None:
2999 if self._ascending is None:
2999 if self._genlist:
3000 if self._genlist:
3000 return iter(self._genlist)
3001 return iter(self._genlist)
3001 return iter(self._iterator())
3002 return iter(self._iterator())
3002 self._trysetasclist()
3003 self._trysetasclist()
3003 if self._ascending:
3004 if self._ascending:
3004 it = self.fastasc
3005 it = self.fastasc
3005 else:
3006 else:
3006 it = self.fastdesc
3007 it = self.fastdesc
3007 if it is None:
3008 if it is None:
3008 # consume the gen and try again
3009 # consume the gen and try again
3009 self._list
3010 self._list
3010 return iter(self)
3011 return iter(self)
3011 return it()
3012 return it()
3012
3013
3013 def _trysetasclist(self):
3014 def _trysetasclist(self):
3014 """populate the _asclist attribute if possible and necessary"""
3015 """populate the _asclist attribute if possible and necessary"""
3015 if self._genlist is not None and self._asclist is None:
3016 if self._genlist is not None and self._asclist is None:
3016 self._asclist = sorted(self._genlist)
3017 self._asclist = sorted(self._genlist)
3017
3018
3018 @property
3019 @property
3019 def fastasc(self):
3020 def fastasc(self):
3020 self._trysetasclist()
3021 self._trysetasclist()
3021 if self._asclist is not None:
3022 if self._asclist is not None:
3022 return self._asclist.__iter__
3023 return self._asclist.__iter__
3023 iter1 = self._r1.fastasc
3024 iter1 = self._r1.fastasc
3024 iter2 = self._r2.fastasc
3025 iter2 = self._r2.fastasc
3025 if None in (iter1, iter2):
3026 if None in (iter1, iter2):
3026 return None
3027 return None
3027 return lambda: self._iterordered(True, iter1(), iter2())
3028 return lambda: self._iterordered(True, iter1(), iter2())
3028
3029
3029 @property
3030 @property
3030 def fastdesc(self):
3031 def fastdesc(self):
3031 self._trysetasclist()
3032 self._trysetasclist()
3032 if self._asclist is not None:
3033 if self._asclist is not None:
3033 return self._asclist.__reversed__
3034 return self._asclist.__reversed__
3034 iter1 = self._r1.fastdesc
3035 iter1 = self._r1.fastdesc
3035 iter2 = self._r2.fastdesc
3036 iter2 = self._r2.fastdesc
3036 if None in (iter1, iter2):
3037 if None in (iter1, iter2):
3037 return None
3038 return None
3038 return lambda: self._iterordered(False, iter1(), iter2())
3039 return lambda: self._iterordered(False, iter1(), iter2())
3039
3040
3040 def _iterordered(self, ascending, iter1, iter2):
3041 def _iterordered(self, ascending, iter1, iter2):
3041 """produce an ordered iteration from two iterators with the same order
3042 """produce an ordered iteration from two iterators with the same order
3042
3043
3043 The ascending is used to indicated the iteration direction.
3044 The ascending is used to indicated the iteration direction.
3044 """
3045 """
3045 choice = max
3046 choice = max
3046 if ascending:
3047 if ascending:
3047 choice = min
3048 choice = min
3048
3049
3049 val1 = None
3050 val1 = None
3050 val2 = None
3051 val2 = None
3051
3052
3052 choice = max
3053 choice = max
3053 if ascending:
3054 if ascending:
3054 choice = min
3055 choice = min
3055 try:
3056 try:
3056 # Consume both iterators in an ordered way until one is
3057 # Consume both iterators in an ordered way until one is
3057 # empty
3058 # empty
3058 while True:
3059 while True:
3059 if val1 is None:
3060 if val1 is None:
3060 val1 = iter1.next()
3061 val1 = iter1.next()
3061 if val2 is None:
3062 if val2 is None:
3062 val2 = iter2.next()
3063 val2 = iter2.next()
3063 next = choice(val1, val2)
3064 next = choice(val1, val2)
3064 yield next
3065 yield next
3065 if val1 == next:
3066 if val1 == next:
3066 val1 = None
3067 val1 = None
3067 if val2 == next:
3068 if val2 == next:
3068 val2 = None
3069 val2 = None
3069 except StopIteration:
3070 except StopIteration:
3070 # Flush any remaining values and consume the other one
3071 # Flush any remaining values and consume the other one
3071 it = iter2
3072 it = iter2
3072 if val1 is not None:
3073 if val1 is not None:
3073 yield val1
3074 yield val1
3074 it = iter1
3075 it = iter1
3075 elif val2 is not None:
3076 elif val2 is not None:
3076 # might have been equality and both are empty
3077 # might have been equality and both are empty
3077 yield val2
3078 yield val2
3078 for val in it:
3079 for val in it:
3079 yield val
3080 yield val
3080
3081
3081 def __contains__(self, x):
3082 def __contains__(self, x):
3082 return x in self._r1 or x in self._r2
3083 return x in self._r1 or x in self._r2
3083
3084
3084 def sort(self, reverse=False):
3085 def sort(self, reverse=False):
3085 """Sort the added set
3086 """Sort the added set
3086
3087
3087 For this we use the cached list with all the generated values and if we
3088 For this we use the cached list with all the generated values and if we
3088 know they are ascending or descending we can sort them in a smart way.
3089 know they are ascending or descending we can sort them in a smart way.
3089 """
3090 """
3090 self._ascending = not reverse
3091 self._ascending = not reverse
3091
3092
3092 def isascending(self):
3093 def isascending(self):
3093 return self._ascending is not None and self._ascending
3094 return self._ascending is not None and self._ascending
3094
3095
3095 def isdescending(self):
3096 def isdescending(self):
3096 return self._ascending is not None and not self._ascending
3097 return self._ascending is not None and not self._ascending
3097
3098
3098 def reverse(self):
3099 def reverse(self):
3099 if self._ascending is None:
3100 if self._ascending is None:
3100 self._list.reverse()
3101 self._list.reverse()
3101 else:
3102 else:
3102 self._ascending = not self._ascending
3103 self._ascending = not self._ascending
3103
3104
3104 def first(self):
3105 def first(self):
3105 for x in self:
3106 for x in self:
3106 return x
3107 return x
3107 return None
3108 return None
3108
3109
3109 def last(self):
3110 def last(self):
3110 self.reverse()
3111 self.reverse()
3111 val = self.first()
3112 val = self.first()
3112 self.reverse()
3113 self.reverse()
3113 return val
3114 return val
3114
3115
3115 def __repr__(self):
3116 def __repr__(self):
3116 d = {None: '', False: '-', True: '+'}[self._ascending]
3117 d = {None: '', False: '-', True: '+'}[self._ascending]
3117 return '<%s%s %r, %r>' % (type(self).__name__, d, self._r1, self._r2)
3118 return '<%s%s %r, %r>' % (type(self).__name__, d, self._r1, self._r2)
3118
3119
3119 class generatorset(abstractsmartset):
3120 class generatorset(abstractsmartset):
3120 """Wrap a generator for lazy iteration
3121 """Wrap a generator for lazy iteration
3121
3122
3122 Wrapper structure for generators that provides lazy membership and can
3123 Wrapper structure for generators that provides lazy membership and can
3123 be iterated more than once.
3124 be iterated more than once.
3124 When asked for membership it generates values until either it finds the
3125 When asked for membership it generates values until either it finds the
3125 requested one or has gone through all the elements in the generator
3126 requested one or has gone through all the elements in the generator
3126 """
3127 """
3127 def __init__(self, gen, iterasc=None):
3128 def __init__(self, gen, iterasc=None):
3128 """
3129 """
3129 gen: a generator producing the values for the generatorset.
3130 gen: a generator producing the values for the generatorset.
3130 """
3131 """
3131 self._gen = gen
3132 self._gen = gen
3132 self._asclist = None
3133 self._asclist = None
3133 self._cache = {}
3134 self._cache = {}
3134 self._genlist = []
3135 self._genlist = []
3135 self._finished = False
3136 self._finished = False
3136 self._ascending = True
3137 self._ascending = True
3137 if iterasc is not None:
3138 if iterasc is not None:
3138 if iterasc:
3139 if iterasc:
3139 self.fastasc = self._iterator
3140 self.fastasc = self._iterator
3140 self.__contains__ = self._asccontains
3141 self.__contains__ = self._asccontains
3141 else:
3142 else:
3142 self.fastdesc = self._iterator
3143 self.fastdesc = self._iterator
3143 self.__contains__ = self._desccontains
3144 self.__contains__ = self._desccontains
3144
3145
3145 def __nonzero__(self):
3146 def __nonzero__(self):
3146 for r in self:
3147 for r in self:
3147 return True
3148 return True
3148 return False
3149 return False
3149
3150
3150 def __contains__(self, x):
3151 def __contains__(self, x):
3151 if x in self._cache:
3152 if x in self._cache:
3152 return self._cache[x]
3153 return self._cache[x]
3153
3154
3154 # Use new values only, as existing values would be cached.
3155 # Use new values only, as existing values would be cached.
3155 for l in self._consumegen():
3156 for l in self._consumegen():
3156 if l == x:
3157 if l == x:
3157 return True
3158 return True
3158
3159
3159 self._cache[x] = False
3160 self._cache[x] = False
3160 return False
3161 return False
3161
3162
3162 def _asccontains(self, x):
3163 def _asccontains(self, x):
3163 """version of contains optimised for ascending generator"""
3164 """version of contains optimised for ascending generator"""
3164 if x in self._cache:
3165 if x in self._cache:
3165 return self._cache[x]
3166 return self._cache[x]
3166
3167
3167 # Use new values only, as existing values would be cached.
3168 # Use new values only, as existing values would be cached.
3168 for l in self._consumegen():
3169 for l in self._consumegen():
3169 if l == x:
3170 if l == x:
3170 return True
3171 return True
3171 if l > x:
3172 if l > x:
3172 break
3173 break
3173
3174
3174 self._cache[x] = False
3175 self._cache[x] = False
3175 return False
3176 return False
3176
3177
3177 def _desccontains(self, x):
3178 def _desccontains(self, x):
3178 """version of contains optimised for descending generator"""
3179 """version of contains optimised for descending generator"""
3179 if x in self._cache:
3180 if x in self._cache:
3180 return self._cache[x]
3181 return self._cache[x]
3181
3182
3182 # Use new values only, as existing values would be cached.
3183 # Use new values only, as existing values would be cached.
3183 for l in self._consumegen():
3184 for l in self._consumegen():
3184 if l == x:
3185 if l == x:
3185 return True
3186 return True
3186 if l < x:
3187 if l < x:
3187 break
3188 break
3188
3189
3189 self._cache[x] = False
3190 self._cache[x] = False
3190 return False
3191 return False
3191
3192
3192 def __iter__(self):
3193 def __iter__(self):
3193 if self._ascending:
3194 if self._ascending:
3194 it = self.fastasc
3195 it = self.fastasc
3195 else:
3196 else:
3196 it = self.fastdesc
3197 it = self.fastdesc
3197 if it is not None:
3198 if it is not None:
3198 return it()
3199 return it()
3199 # we need to consume the iterator
3200 # we need to consume the iterator
3200 for x in self._consumegen():
3201 for x in self._consumegen():
3201 pass
3202 pass
3202 # recall the same code
3203 # recall the same code
3203 return iter(self)
3204 return iter(self)
3204
3205
3205 def _iterator(self):
3206 def _iterator(self):
3206 if self._finished:
3207 if self._finished:
3207 return iter(self._genlist)
3208 return iter(self._genlist)
3208
3209
3209 # We have to use this complex iteration strategy to allow multiple
3210 # We have to use this complex iteration strategy to allow multiple
3210 # iterations at the same time. We need to be able to catch revision
3211 # iterations at the same time. We need to be able to catch revision
3211 # removed from _consumegen and added to genlist in another instance.
3212 # removed from _consumegen and added to genlist in another instance.
3212 #
3213 #
3213 # Getting rid of it would provide an about 15% speed up on this
3214 # Getting rid of it would provide an about 15% speed up on this
3214 # iteration.
3215 # iteration.
3215 genlist = self._genlist
3216 genlist = self._genlist
3216 nextrev = self._consumegen().next
3217 nextrev = self._consumegen().next
3217 _len = len # cache global lookup
3218 _len = len # cache global lookup
3218 def gen():
3219 def gen():
3219 i = 0
3220 i = 0
3220 while True:
3221 while True:
3221 if i < _len(genlist):
3222 if i < _len(genlist):
3222 yield genlist[i]
3223 yield genlist[i]
3223 else:
3224 else:
3224 yield nextrev()
3225 yield nextrev()
3225 i += 1
3226 i += 1
3226 return gen()
3227 return gen()
3227
3228
3228 def _consumegen(self):
3229 def _consumegen(self):
3229 cache = self._cache
3230 cache = self._cache
3230 genlist = self._genlist.append
3231 genlist = self._genlist.append
3231 for item in self._gen:
3232 for item in self._gen:
3232 cache[item] = True
3233 cache[item] = True
3233 genlist(item)
3234 genlist(item)
3234 yield item
3235 yield item
3235 if not self._finished:
3236 if not self._finished:
3236 self._finished = True
3237 self._finished = True
3237 asc = self._genlist[:]
3238 asc = self._genlist[:]
3238 asc.sort()
3239 asc.sort()
3239 self._asclist = asc
3240 self._asclist = asc
3240 self.fastasc = asc.__iter__
3241 self.fastasc = asc.__iter__
3241 self.fastdesc = asc.__reversed__
3242 self.fastdesc = asc.__reversed__
3242
3243
3243 def __len__(self):
3244 def __len__(self):
3244 for x in self._consumegen():
3245 for x in self._consumegen():
3245 pass
3246 pass
3246 return len(self._genlist)
3247 return len(self._genlist)
3247
3248
3248 def sort(self, reverse=False):
3249 def sort(self, reverse=False):
3249 self._ascending = not reverse
3250 self._ascending = not reverse
3250
3251
3251 def reverse(self):
3252 def reverse(self):
3252 self._ascending = not self._ascending
3253 self._ascending = not self._ascending
3253
3254
3254 def isascending(self):
3255 def isascending(self):
3255 return self._ascending
3256 return self._ascending
3256
3257
3257 def isdescending(self):
3258 def isdescending(self):
3258 return not self._ascending
3259 return not self._ascending
3259
3260
3260 def first(self):
3261 def first(self):
3261 if self._ascending:
3262 if self._ascending:
3262 it = self.fastasc
3263 it = self.fastasc
3263 else:
3264 else:
3264 it = self.fastdesc
3265 it = self.fastdesc
3265 if it is None:
3266 if it is None:
3266 # we need to consume all and try again
3267 # we need to consume all and try again
3267 for x in self._consumegen():
3268 for x in self._consumegen():
3268 pass
3269 pass
3269 return self.first()
3270 return self.first()
3270 if self:
3271 if self:
3271 return it().next()
3272 return it().next()
3272 return None
3273 return None
3273
3274
3274 def last(self):
3275 def last(self):
3275 if self._ascending:
3276 if self._ascending:
3276 it = self.fastdesc
3277 it = self.fastdesc
3277 else:
3278 else:
3278 it = self.fastasc
3279 it = self.fastasc
3279 if it is None:
3280 if it is None:
3280 # we need to consume all and try again
3281 # we need to consume all and try again
3281 for x in self._consumegen():
3282 for x in self._consumegen():
3282 pass
3283 pass
3283 return self.first()
3284 return self.first()
3284 if self:
3285 if self:
3285 return it().next()
3286 return it().next()
3286 return None
3287 return None
3287
3288
3288 def __repr__(self):
3289 def __repr__(self):
3289 d = {False: '-', True: '+'}[self._ascending]
3290 d = {False: '-', True: '+'}[self._ascending]
3290 return '<%s%s>' % (type(self).__name__, d)
3291 return '<%s%s>' % (type(self).__name__, d)
3291
3292
3292 class spanset(abstractsmartset):
3293 class spanset(abstractsmartset):
3293 """Duck type for baseset class which represents a range of revisions and
3294 """Duck type for baseset class which represents a range of revisions and
3294 can work lazily and without having all the range in memory
3295 can work lazily and without having all the range in memory
3295
3296
3296 Note that spanset(x, y) behave almost like xrange(x, y) except for two
3297 Note that spanset(x, y) behave almost like xrange(x, y) except for two
3297 notable points:
3298 notable points:
3298 - when x < y it will be automatically descending,
3299 - when x < y it will be automatically descending,
3299 - revision filtered with this repoview will be skipped.
3300 - revision filtered with this repoview will be skipped.
3300
3301
3301 """
3302 """
3302 def __init__(self, repo, start=0, end=None):
3303 def __init__(self, repo, start=0, end=None):
3303 """
3304 """
3304 start: first revision included the set
3305 start: first revision included the set
3305 (default to 0)
3306 (default to 0)
3306 end: first revision excluded (last+1)
3307 end: first revision excluded (last+1)
3307 (default to len(repo)
3308 (default to len(repo)
3308
3309
3309 Spanset will be descending if `end` < `start`.
3310 Spanset will be descending if `end` < `start`.
3310 """
3311 """
3311 if end is None:
3312 if end is None:
3312 end = len(repo)
3313 end = len(repo)
3313 self._ascending = start <= end
3314 self._ascending = start <= end
3314 if not self._ascending:
3315 if not self._ascending:
3315 start, end = end + 1, start +1
3316 start, end = end + 1, start +1
3316 self._start = start
3317 self._start = start
3317 self._end = end
3318 self._end = end
3318 self._hiddenrevs = repo.changelog.filteredrevs
3319 self._hiddenrevs = repo.changelog.filteredrevs
3319
3320
3320 def sort(self, reverse=False):
3321 def sort(self, reverse=False):
3321 self._ascending = not reverse
3322 self._ascending = not reverse
3322
3323
3323 def reverse(self):
3324 def reverse(self):
3324 self._ascending = not self._ascending
3325 self._ascending = not self._ascending
3325
3326
3326 def _iterfilter(self, iterrange):
3327 def _iterfilter(self, iterrange):
3327 s = self._hiddenrevs
3328 s = self._hiddenrevs
3328 for r in iterrange:
3329 for r in iterrange:
3329 if r not in s:
3330 if r not in s:
3330 yield r
3331 yield r
3331
3332
3332 def __iter__(self):
3333 def __iter__(self):
3333 if self._ascending:
3334 if self._ascending:
3334 return self.fastasc()
3335 return self.fastasc()
3335 else:
3336 else:
3336 return self.fastdesc()
3337 return self.fastdesc()
3337
3338
3338 def fastasc(self):
3339 def fastasc(self):
3339 iterrange = xrange(self._start, self._end)
3340 iterrange = xrange(self._start, self._end)
3340 if self._hiddenrevs:
3341 if self._hiddenrevs:
3341 return self._iterfilter(iterrange)
3342 return self._iterfilter(iterrange)
3342 return iter(iterrange)
3343 return iter(iterrange)
3343
3344
3344 def fastdesc(self):
3345 def fastdesc(self):
3345 iterrange = xrange(self._end - 1, self._start - 1, -1)
3346 iterrange = xrange(self._end - 1, self._start - 1, -1)
3346 if self._hiddenrevs:
3347 if self._hiddenrevs:
3347 return self._iterfilter(iterrange)
3348 return self._iterfilter(iterrange)
3348 return iter(iterrange)
3349 return iter(iterrange)
3349
3350
3350 def __contains__(self, rev):
3351 def __contains__(self, rev):
3351 hidden = self._hiddenrevs
3352 hidden = self._hiddenrevs
3352 return ((self._start <= rev < self._end)
3353 return ((self._start <= rev < self._end)
3353 and not (hidden and rev in hidden))
3354 and not (hidden and rev in hidden))
3354
3355
3355 def __nonzero__(self):
3356 def __nonzero__(self):
3356 for r in self:
3357 for r in self:
3357 return True
3358 return True
3358 return False
3359 return False
3359
3360
3360 def __len__(self):
3361 def __len__(self):
3361 if not self._hiddenrevs:
3362 if not self._hiddenrevs:
3362 return abs(self._end - self._start)
3363 return abs(self._end - self._start)
3363 else:
3364 else:
3364 count = 0
3365 count = 0
3365 start = self._start
3366 start = self._start
3366 end = self._end
3367 end = self._end
3367 for rev in self._hiddenrevs:
3368 for rev in self._hiddenrevs:
3368 if (end < rev <= start) or (start <= rev < end):
3369 if (end < rev <= start) or (start <= rev < end):
3369 count += 1
3370 count += 1
3370 return abs(self._end - self._start) - count
3371 return abs(self._end - self._start) - count
3371
3372
3372 def isascending(self):
3373 def isascending(self):
3373 return self._ascending
3374 return self._ascending
3374
3375
3375 def isdescending(self):
3376 def isdescending(self):
3376 return not self._ascending
3377 return not self._ascending
3377
3378
3378 def first(self):
3379 def first(self):
3379 if self._ascending:
3380 if self._ascending:
3380 it = self.fastasc
3381 it = self.fastasc
3381 else:
3382 else:
3382 it = self.fastdesc
3383 it = self.fastdesc
3383 for x in it():
3384 for x in it():
3384 return x
3385 return x
3385 return None
3386 return None
3386
3387
3387 def last(self):
3388 def last(self):
3388 if self._ascending:
3389 if self._ascending:
3389 it = self.fastdesc
3390 it = self.fastdesc
3390 else:
3391 else:
3391 it = self.fastasc
3392 it = self.fastasc
3392 for x in it():
3393 for x in it():
3393 return x
3394 return x
3394 return None
3395 return None
3395
3396
3396 def __repr__(self):
3397 def __repr__(self):
3397 d = {False: '-', True: '+'}[self._ascending]
3398 d = {False: '-', True: '+'}[self._ascending]
3398 return '<%s%s %d:%d>' % (type(self).__name__, d,
3399 return '<%s%s %d:%d>' % (type(self).__name__, d,
3399 self._start, self._end - 1)
3400 self._start, self._end - 1)
3400
3401
3401 class fullreposet(spanset):
3402 class fullreposet(spanset):
3402 """a set containing all revisions in the repo
3403 """a set containing all revisions in the repo
3403
3404
3404 This class exists to host special optimization and magic to handle virtual
3405 This class exists to host special optimization and magic to handle virtual
3405 revisions such as "null".
3406 revisions such as "null".
3406 """
3407 """
3407
3408
3408 def __init__(self, repo):
3409 def __init__(self, repo):
3409 super(fullreposet, self).__init__(repo)
3410 super(fullreposet, self).__init__(repo)
3410
3411
3411 def __contains__(self, rev):
3412 # assumes the given rev is valid
3413 hidden = self._hiddenrevs
3414 return not (hidden and rev in hidden)
3415
3416 def __and__(self, other):
3412 def __and__(self, other):
3417 """As self contains the whole repo, all of the other set should also be
3413 """As self contains the whole repo, all of the other set should also be
3418 in self. Therefore `self & other = other`.
3414 in self. Therefore `self & other = other`.
3419
3415
3420 This boldly assumes the other contains valid revs only.
3416 This boldly assumes the other contains valid revs only.
3421 """
3417 """
3422 # other not a smartset, make is so
3418 # other not a smartset, make is so
3423 if not util.safehasattr(other, 'isascending'):
3419 if not util.safehasattr(other, 'isascending'):
3424 # filter out hidden revision
3420 # filter out hidden revision
3425 # (this boldly assumes all smartset are pure)
3421 # (this boldly assumes all smartset are pure)
3426 #
3422 #
3427 # `other` was used with "&", let's assume this is a set like
3423 # `other` was used with "&", let's assume this is a set like
3428 # object.
3424 # object.
3429 other = baseset(other - self._hiddenrevs)
3425 other = baseset(other - self._hiddenrevs)
3430
3426
3431 other.sort(reverse=self.isdescending())
3427 other.sort(reverse=self.isdescending())
3432 return other
3428 return other
3433
3429
3434 def prettyformatset(revs):
3430 def prettyformatset(revs):
3435 lines = []
3431 lines = []
3436 rs = repr(revs)
3432 rs = repr(revs)
3437 p = 0
3433 p = 0
3438 while p < len(rs):
3434 while p < len(rs):
3439 q = rs.find('<', p + 1)
3435 q = rs.find('<', p + 1)
3440 if q < 0:
3436 if q < 0:
3441 q = len(rs)
3437 q = len(rs)
3442 l = rs.count('<', 0, p) - rs.count('>', 0, p)
3438 l = rs.count('<', 0, p) - rs.count('>', 0, p)
3443 assert l >= 0
3439 assert l >= 0
3444 lines.append((l, rs[p:q].rstrip()))
3440 lines.append((l, rs[p:q].rstrip()))
3445 p = q
3441 p = q
3446 return '\n'.join(' ' * l + s for l, s in lines)
3442 return '\n'.join(' ' * l + s for l, s in lines)
3447
3443
3448 # tell hggettext to extract docstrings from these functions:
3444 # tell hggettext to extract docstrings from these functions:
3449 i18nfunctions = symbols.values()
3445 i18nfunctions = symbols.values()
@@ -1,2378 +1,2386 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)[0]
92 > tree = revset.parse(expr)[0]
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 (or
1472 (or
1473 (func
1473 (func
1474 ('symbol', 'branch')
1474 ('symbol', 'branch')
1475 ('string', 'default'))
1475 ('string', 'default'))
1476 (func
1476 (func
1477 ('symbol', 'branch')
1477 ('symbol', 'branch')
1478 ('string', 'branch')))
1478 ('string', 'branch')))
1479 (func
1479 (func
1480 ('symbol', 'branch')
1480 ('symbol', 'branch')
1481 ('string', 'branch')))))
1481 ('string', 'branch')))))
1482 $ testlog -k expand -k merge
1482 $ testlog -k expand -k merge
1483 []
1483 []
1484 (group
1484 (group
1485 (group
1485 (group
1486 (or
1486 (or
1487 (func
1487 (func
1488 ('symbol', 'keyword')
1488 ('symbol', 'keyword')
1489 ('string', 'expand'))
1489 ('string', 'expand'))
1490 (func
1490 (func
1491 ('symbol', 'keyword')
1491 ('symbol', 'keyword')
1492 ('string', 'merge')))))
1492 ('string', 'merge')))))
1493 $ testlog --only-merges
1493 $ testlog --only-merges
1494 []
1494 []
1495 (group
1495 (group
1496 (func
1496 (func
1497 ('symbol', 'merge')
1497 ('symbol', 'merge')
1498 None))
1498 None))
1499 $ testlog --no-merges
1499 $ testlog --no-merges
1500 []
1500 []
1501 (group
1501 (group
1502 (not
1502 (not
1503 (func
1503 (func
1504 ('symbol', 'merge')
1504 ('symbol', 'merge')
1505 None)))
1505 None)))
1506 $ testlog --date '2 0 to 4 0'
1506 $ testlog --date '2 0 to 4 0'
1507 []
1507 []
1508 (group
1508 (group
1509 (func
1509 (func
1510 ('symbol', 'date')
1510 ('symbol', 'date')
1511 ('string', '2 0 to 4 0')))
1511 ('string', '2 0 to 4 0')))
1512 $ hg log -G -d 'brace ) in a date'
1512 $ hg log -G -d 'brace ) in a date'
1513 abort: invalid date: 'brace ) in a date'
1513 abort: invalid date: 'brace ) in a date'
1514 [255]
1514 [255]
1515 $ testlog --prune 31 --prune 32
1515 $ testlog --prune 31 --prune 32
1516 []
1516 []
1517 (group
1517 (group
1518 (group
1518 (group
1519 (and
1519 (and
1520 (not
1520 (not
1521 (group
1521 (group
1522 (or
1522 (or
1523 ('string', '31')
1523 ('string', '31')
1524 (func
1524 (func
1525 ('symbol', 'ancestors')
1525 ('symbol', 'ancestors')
1526 ('string', '31')))))
1526 ('string', '31')))))
1527 (not
1527 (not
1528 (group
1528 (group
1529 (or
1529 (or
1530 ('string', '32')
1530 ('string', '32')
1531 (func
1531 (func
1532 ('symbol', 'ancestors')
1532 ('symbol', 'ancestors')
1533 ('string', '32'))))))))
1533 ('string', '32'))))))))
1534
1534
1535 Dedicated repo for --follow and paths filtering. The g is crafted to
1535 Dedicated repo for --follow and paths filtering. The g is crafted to
1536 have 2 filelog topological heads in a linear changeset graph.
1536 have 2 filelog topological heads in a linear changeset graph.
1537
1537
1538 $ cd ..
1538 $ cd ..
1539 $ hg init follow
1539 $ hg init follow
1540 $ cd follow
1540 $ cd follow
1541 $ testlog --follow
1541 $ testlog --follow
1542 []
1542 []
1543 []
1543 []
1544 $ testlog -rnull
1544 $ testlog -rnull
1545 ['null']
1545 ['null']
1546 []
1546 []
1547 $ echo a > a
1547 $ echo a > a
1548 $ echo aa > aa
1548 $ echo aa > aa
1549 $ echo f > f
1549 $ echo f > f
1550 $ hg ci -Am "add a" a aa f
1550 $ hg ci -Am "add a" a aa f
1551 $ hg cp a b
1551 $ hg cp a b
1552 $ hg cp f g
1552 $ hg cp f g
1553 $ hg ci -m "copy a b"
1553 $ hg ci -m "copy a b"
1554 $ mkdir dir
1554 $ mkdir dir
1555 $ hg mv b dir
1555 $ hg mv b dir
1556 $ echo g >> g
1556 $ echo g >> g
1557 $ echo f >> f
1557 $ echo f >> f
1558 $ hg ci -m "mv b dir/b"
1558 $ hg ci -m "mv b dir/b"
1559 $ hg mv a b
1559 $ hg mv a b
1560 $ hg cp -f f g
1560 $ hg cp -f f g
1561 $ echo a > d
1561 $ echo a > d
1562 $ hg add d
1562 $ hg add d
1563 $ hg ci -m "mv a b; add d"
1563 $ hg ci -m "mv a b; add d"
1564 $ hg mv dir/b e
1564 $ hg mv dir/b e
1565 $ hg ci -m "mv dir/b e"
1565 $ hg ci -m "mv dir/b e"
1566 $ hg log -G --template '({rev}) {desc|firstline}\n'
1566 $ hg log -G --template '({rev}) {desc|firstline}\n'
1567 @ (4) mv dir/b e
1567 @ (4) mv dir/b e
1568 |
1568 |
1569 o (3) mv a b; add d
1569 o (3) mv a b; add d
1570 |
1570 |
1571 o (2) mv b dir/b
1571 o (2) mv b dir/b
1572 |
1572 |
1573 o (1) copy a b
1573 o (1) copy a b
1574 |
1574 |
1575 o (0) add a
1575 o (0) add a
1576
1576
1577
1577
1578 $ testlog a
1578 $ testlog a
1579 []
1579 []
1580 (group
1580 (group
1581 (group
1581 (group
1582 (func
1582 (func
1583 ('symbol', 'filelog')
1583 ('symbol', 'filelog')
1584 ('string', 'a'))))
1584 ('string', 'a'))))
1585 $ testlog a b
1585 $ testlog a b
1586 []
1586 []
1587 (group
1587 (group
1588 (group
1588 (group
1589 (or
1589 (or
1590 (func
1590 (func
1591 ('symbol', 'filelog')
1591 ('symbol', 'filelog')
1592 ('string', 'a'))
1592 ('string', 'a'))
1593 (func
1593 (func
1594 ('symbol', 'filelog')
1594 ('symbol', 'filelog')
1595 ('string', 'b')))))
1595 ('string', 'b')))))
1596
1596
1597 Test falling back to slow path for non-existing files
1597 Test falling back to slow path for non-existing files
1598
1598
1599 $ testlog a c
1599 $ testlog a c
1600 []
1600 []
1601 (group
1601 (group
1602 (func
1602 (func
1603 ('symbol', '_matchfiles')
1603 ('symbol', '_matchfiles')
1604 (list
1604 (list
1605 (list
1605 (list
1606 (list
1606 (list
1607 ('string', 'r:')
1607 ('string', 'r:')
1608 ('string', 'd:relpath'))
1608 ('string', 'd:relpath'))
1609 ('string', 'p:a'))
1609 ('string', 'p:a'))
1610 ('string', 'p:c'))))
1610 ('string', 'p:c'))))
1611
1611
1612 Test multiple --include/--exclude/paths
1612 Test multiple --include/--exclude/paths
1613
1613
1614 $ testlog --include a --include e --exclude b --exclude e a e
1614 $ testlog --include a --include e --exclude b --exclude e a e
1615 []
1615 []
1616 (group
1616 (group
1617 (func
1617 (func
1618 ('symbol', '_matchfiles')
1618 ('symbol', '_matchfiles')
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 (list
1625 (list
1626 ('string', 'r:')
1626 ('string', 'r:')
1627 ('string', 'd:relpath'))
1627 ('string', 'd:relpath'))
1628 ('string', 'p:a'))
1628 ('string', 'p:a'))
1629 ('string', 'p:e'))
1629 ('string', 'p:e'))
1630 ('string', 'i:a'))
1630 ('string', 'i:a'))
1631 ('string', 'i:e'))
1631 ('string', 'i:e'))
1632 ('string', 'x:b'))
1632 ('string', 'x:b'))
1633 ('string', 'x:e'))))
1633 ('string', 'x:e'))))
1634
1634
1635 Test glob expansion of pats
1635 Test glob expansion of pats
1636
1636
1637 $ expandglobs=`$PYTHON -c "import mercurial.util; \
1637 $ expandglobs=`$PYTHON -c "import mercurial.util; \
1638 > print mercurial.util.expandglobs and 'true' or 'false'"`
1638 > print mercurial.util.expandglobs and 'true' or 'false'"`
1639 $ if [ $expandglobs = "true" ]; then
1639 $ if [ $expandglobs = "true" ]; then
1640 > testlog 'a*';
1640 > testlog 'a*';
1641 > else
1641 > else
1642 > testlog a*;
1642 > testlog a*;
1643 > fi;
1643 > fi;
1644 []
1644 []
1645 (group
1645 (group
1646 (group
1646 (group
1647 (func
1647 (func
1648 ('symbol', 'filelog')
1648 ('symbol', 'filelog')
1649 ('string', 'aa'))))
1649 ('string', 'aa'))))
1650
1650
1651 Test --follow on a non-existent directory
1651 Test --follow on a non-existent directory
1652
1652
1653 $ testlog -f dir
1653 $ testlog -f 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 abort: cannot follow file not in parent revision: "dir"
1656 abort: cannot follow file not in parent revision: "dir"
1657
1657
1658 Test --follow on a directory
1658 Test --follow on a directory
1659
1659
1660 $ hg up -q '.^'
1660 $ hg up -q '.^'
1661 $ testlog -f dir
1661 $ testlog -f dir
1662 []
1662 []
1663 (group
1663 (group
1664 (and
1664 (and
1665 (func
1665 (func
1666 ('symbol', 'ancestors')
1666 ('symbol', 'ancestors')
1667 ('symbol', '.'))
1667 ('symbol', '.'))
1668 (func
1668 (func
1669 ('symbol', '_matchfiles')
1669 ('symbol', '_matchfiles')
1670 (list
1670 (list
1671 (list
1671 (list
1672 ('string', 'r:')
1672 ('string', 'r:')
1673 ('string', 'd:relpath'))
1673 ('string', 'd:relpath'))
1674 ('string', 'p:dir')))))
1674 ('string', 'p:dir')))))
1675 $ hg up -q tip
1675 $ hg up -q tip
1676
1676
1677 Test --follow on file not in parent revision
1677 Test --follow on file not in parent revision
1678
1678
1679 $ testlog -f a
1679 $ testlog -f 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 abort: cannot follow file not in parent revision: "a"
1682 abort: cannot follow file not in parent revision: "a"
1683
1683
1684 Test --follow and patterns
1684 Test --follow and patterns
1685
1685
1686 $ testlog -f 'glob:*'
1686 $ testlog -f 'glob:*'
1687 []
1687 []
1688 (group
1688 (group
1689 (and
1689 (and
1690 (func
1690 (func
1691 ('symbol', 'ancestors')
1691 ('symbol', 'ancestors')
1692 ('symbol', '.'))
1692 ('symbol', '.'))
1693 (func
1693 (func
1694 ('symbol', '_matchfiles')
1694 ('symbol', '_matchfiles')
1695 (list
1695 (list
1696 (list
1696 (list
1697 ('string', 'r:')
1697 ('string', 'r:')
1698 ('string', 'd:relpath'))
1698 ('string', 'd:relpath'))
1699 ('string', 'p:glob:*')))))
1699 ('string', 'p:glob:*')))))
1700
1700
1701 Test --follow on a single rename
1701 Test --follow on a single rename
1702
1702
1703 $ hg up -q 2
1703 $ hg up -q 2
1704 $ testlog -f a
1704 $ testlog -f a
1705 []
1705 []
1706 (group
1706 (group
1707 (group
1707 (group
1708 (func
1708 (func
1709 ('symbol', 'follow')
1709 ('symbol', 'follow')
1710 ('string', 'a'))))
1710 ('string', 'a'))))
1711
1711
1712 Test --follow and multiple renames
1712 Test --follow and multiple renames
1713
1713
1714 $ hg up -q tip
1714 $ hg up -q tip
1715 $ testlog -f e
1715 $ testlog -f e
1716 []
1716 []
1717 (group
1717 (group
1718 (group
1718 (group
1719 (func
1719 (func
1720 ('symbol', 'follow')
1720 ('symbol', 'follow')
1721 ('string', 'e'))))
1721 ('string', 'e'))))
1722
1722
1723 Test --follow and multiple filelog heads
1723 Test --follow and multiple filelog heads
1724
1724
1725 $ hg up -q 2
1725 $ hg up -q 2
1726 $ testlog -f g
1726 $ testlog -f g
1727 []
1727 []
1728 (group
1728 (group
1729 (group
1729 (group
1730 (func
1730 (func
1731 ('symbol', 'follow')
1731 ('symbol', 'follow')
1732 ('string', 'g'))))
1732 ('string', 'g'))))
1733 $ cat log.nodes
1733 $ cat log.nodes
1734 nodetag 2
1734 nodetag 2
1735 nodetag 1
1735 nodetag 1
1736 nodetag 0
1736 nodetag 0
1737 $ hg up -q tip
1737 $ hg up -q tip
1738 $ testlog -f g
1738 $ testlog -f g
1739 []
1739 []
1740 (group
1740 (group
1741 (group
1741 (group
1742 (func
1742 (func
1743 ('symbol', 'follow')
1743 ('symbol', 'follow')
1744 ('string', 'g'))))
1744 ('string', 'g'))))
1745 $ cat log.nodes
1745 $ cat log.nodes
1746 nodetag 3
1746 nodetag 3
1747 nodetag 2
1747 nodetag 2
1748 nodetag 0
1748 nodetag 0
1749
1749
1750 Test --follow and multiple files
1750 Test --follow and multiple files
1751
1751
1752 $ testlog -f g e
1752 $ testlog -f g e
1753 []
1753 []
1754 (group
1754 (group
1755 (group
1755 (group
1756 (or
1756 (or
1757 (func
1757 (func
1758 ('symbol', 'follow')
1758 ('symbol', 'follow')
1759 ('string', 'g'))
1759 ('string', 'g'))
1760 (func
1760 (func
1761 ('symbol', 'follow')
1761 ('symbol', 'follow')
1762 ('string', 'e')))))
1762 ('string', 'e')))))
1763 $ cat log.nodes
1763 $ cat log.nodes
1764 nodetag 4
1764 nodetag 4
1765 nodetag 3
1765 nodetag 3
1766 nodetag 2
1766 nodetag 2
1767 nodetag 1
1767 nodetag 1
1768 nodetag 0
1768 nodetag 0
1769
1769
1770 Test --follow null parent
1770 Test --follow null parent
1771
1771
1772 $ hg up -q null
1772 $ hg up -q null
1773 $ testlog -f
1773 $ testlog -f
1774 []
1774 []
1775 []
1775 []
1776
1776
1777 Test --follow-first
1777 Test --follow-first
1778
1778
1779 $ hg up -q 3
1779 $ hg up -q 3
1780 $ echo ee > e
1780 $ echo ee > e
1781 $ hg ci -Am "add another e" e
1781 $ hg ci -Am "add another e" e
1782 created new head
1782 created new head
1783 $ hg merge --tool internal:other 4
1783 $ hg merge --tool internal:other 4
1784 0 files updated, 1 files merged, 1 files removed, 0 files unresolved
1784 0 files updated, 1 files merged, 1 files removed, 0 files unresolved
1785 (branch merge, don't forget to commit)
1785 (branch merge, don't forget to commit)
1786 $ echo merge > e
1786 $ echo merge > e
1787 $ hg ci -m "merge 5 and 4"
1787 $ hg ci -m "merge 5 and 4"
1788 $ testlog --follow-first
1788 $ testlog --follow-first
1789 []
1789 []
1790 (group
1790 (group
1791 (func
1791 (func
1792 ('symbol', '_firstancestors')
1792 ('symbol', '_firstancestors')
1793 (func
1793 (func
1794 ('symbol', 'rev')
1794 ('symbol', 'rev')
1795 ('symbol', '6'))))
1795 ('symbol', '6'))))
1796
1796
1797 Cannot compare with log --follow-first FILE as it never worked
1797 Cannot compare with log --follow-first FILE as it never worked
1798
1798
1799 $ hg log -G --print-revset --follow-first e
1799 $ hg log -G --print-revset --follow-first e
1800 []
1800 []
1801 (group
1801 (group
1802 (group
1802 (group
1803 (func
1803 (func
1804 ('symbol', '_followfirst')
1804 ('symbol', '_followfirst')
1805 ('string', 'e'))))
1805 ('string', 'e'))))
1806 $ hg log -G --follow-first e --template '{rev} {desc|firstline}\n'
1806 $ hg log -G --follow-first e --template '{rev} {desc|firstline}\n'
1807 @ 6 merge 5 and 4
1807 @ 6 merge 5 and 4
1808 |\
1808 |\
1809 o | 5 add another e
1809 o | 5 add another e
1810 | |
1810 | |
1811
1811
1812 Test --copies
1812 Test --copies
1813
1813
1814 $ hg log -G --copies --template "{rev} {desc|firstline} \
1814 $ hg log -G --copies --template "{rev} {desc|firstline} \
1815 > copies: {file_copies_switch}\n"
1815 > copies: {file_copies_switch}\n"
1816 @ 6 merge 5 and 4 copies:
1816 @ 6 merge 5 and 4 copies:
1817 |\
1817 |\
1818 | o 5 add another e copies:
1818 | o 5 add another e copies:
1819 | |
1819 | |
1820 o | 4 mv dir/b e copies: e (dir/b)
1820 o | 4 mv dir/b e copies: e (dir/b)
1821 |/
1821 |/
1822 o 3 mv a b; add d copies: b (a)g (f)
1822 o 3 mv a b; add d copies: b (a)g (f)
1823 |
1823 |
1824 o 2 mv b dir/b copies: dir/b (b)
1824 o 2 mv b dir/b copies: dir/b (b)
1825 |
1825 |
1826 o 1 copy a b copies: b (a)g (f)
1826 o 1 copy a b copies: b (a)g (f)
1827 |
1827 |
1828 o 0 add a copies:
1828 o 0 add a copies:
1829
1829
1830 Test "set:..." and parent revision
1830 Test "set:..." and parent revision
1831
1831
1832 $ hg up -q 4
1832 $ hg up -q 4
1833 $ testlog "set:copied()"
1833 $ testlog "set:copied()"
1834 []
1834 []
1835 (group
1835 (group
1836 (func
1836 (func
1837 ('symbol', '_matchfiles')
1837 ('symbol', '_matchfiles')
1838 (list
1838 (list
1839 (list
1839 (list
1840 ('string', 'r:')
1840 ('string', 'r:')
1841 ('string', 'd:relpath'))
1841 ('string', 'd:relpath'))
1842 ('string', 'p:set:copied()'))))
1842 ('string', 'p:set:copied()'))))
1843 $ testlog --include "set:copied()"
1843 $ testlog --include "set:copied()"
1844 []
1844 []
1845 (group
1845 (group
1846 (func
1846 (func
1847 ('symbol', '_matchfiles')
1847 ('symbol', '_matchfiles')
1848 (list
1848 (list
1849 (list
1849 (list
1850 ('string', 'r:')
1850 ('string', 'r:')
1851 ('string', 'd:relpath'))
1851 ('string', 'd:relpath'))
1852 ('string', 'i:set:copied()'))))
1852 ('string', 'i:set:copied()'))))
1853 $ testlog -r "sort(file('set:copied()'), -rev)"
1853 $ testlog -r "sort(file('set:copied()'), -rev)"
1854 ["sort(file('set:copied()'), -rev)"]
1854 ["sort(file('set:copied()'), -rev)"]
1855 []
1855 []
1856
1856
1857 Test --removed
1857 Test --removed
1858
1858
1859 $ testlog --removed
1859 $ testlog --removed
1860 []
1860 []
1861 []
1861 []
1862 $ testlog --removed a
1862 $ testlog --removed a
1863 []
1863 []
1864 (group
1864 (group
1865 (func
1865 (func
1866 ('symbol', '_matchfiles')
1866 ('symbol', '_matchfiles')
1867 (list
1867 (list
1868 (list
1868 (list
1869 ('string', 'r:')
1869 ('string', 'r:')
1870 ('string', 'd:relpath'))
1870 ('string', 'd:relpath'))
1871 ('string', 'p:a'))))
1871 ('string', 'p:a'))))
1872 $ testlog --removed --follow a
1872 $ testlog --removed --follow a
1873 []
1873 []
1874 (group
1874 (group
1875 (and
1875 (and
1876 (func
1876 (func
1877 ('symbol', 'ancestors')
1877 ('symbol', 'ancestors')
1878 ('symbol', '.'))
1878 ('symbol', '.'))
1879 (func
1879 (func
1880 ('symbol', '_matchfiles')
1880 ('symbol', '_matchfiles')
1881 (list
1881 (list
1882 (list
1882 (list
1883 ('string', 'r:')
1883 ('string', 'r:')
1884 ('string', 'd:relpath'))
1884 ('string', 'd:relpath'))
1885 ('string', 'p:a')))))
1885 ('string', 'p:a')))))
1886
1886
1887 Test --patch and --stat with --follow and --follow-first
1887 Test --patch and --stat with --follow and --follow-first
1888
1888
1889 $ hg up -q 3
1889 $ hg up -q 3
1890 $ hg log -G --git --patch b
1890 $ hg log -G --git --patch b
1891 o changeset: 1:216d4c92cf98
1891 o changeset: 1:216d4c92cf98
1892 | user: test
1892 | user: test
1893 | date: Thu Jan 01 00:00:00 1970 +0000
1893 | date: Thu Jan 01 00:00:00 1970 +0000
1894 | summary: copy a b
1894 | summary: copy a b
1895 |
1895 |
1896 | diff --git a/a b/b
1896 | diff --git a/a b/b
1897 | copy from a
1897 | copy from a
1898 | copy to b
1898 | copy to b
1899 |
1899 |
1900
1900
1901 $ hg log -G --git --stat b
1901 $ hg log -G --git --stat b
1902 o changeset: 1:216d4c92cf98
1902 o changeset: 1:216d4c92cf98
1903 | user: test
1903 | user: test
1904 | date: Thu Jan 01 00:00:00 1970 +0000
1904 | date: Thu Jan 01 00:00:00 1970 +0000
1905 | summary: copy a b
1905 | summary: copy a b
1906 |
1906 |
1907 | b | 0
1907 | b | 0
1908 | 1 files changed, 0 insertions(+), 0 deletions(-)
1908 | 1 files changed, 0 insertions(+), 0 deletions(-)
1909 |
1909 |
1910
1910
1911 $ hg log -G --git --patch --follow b
1911 $ hg log -G --git --patch --follow b
1912 o changeset: 1:216d4c92cf98
1912 o changeset: 1:216d4c92cf98
1913 | user: test
1913 | user: test
1914 | date: Thu Jan 01 00:00:00 1970 +0000
1914 | date: Thu Jan 01 00:00:00 1970 +0000
1915 | summary: copy a b
1915 | summary: copy a b
1916 |
1916 |
1917 | diff --git a/a b/b
1917 | diff --git a/a b/b
1918 | copy from a
1918 | copy from a
1919 | copy to b
1919 | copy to b
1920 |
1920 |
1921 o changeset: 0:f8035bb17114
1921 o changeset: 0:f8035bb17114
1922 user: test
1922 user: test
1923 date: Thu Jan 01 00:00:00 1970 +0000
1923 date: Thu Jan 01 00:00:00 1970 +0000
1924 summary: add a
1924 summary: add a
1925
1925
1926 diff --git a/a b/a
1926 diff --git a/a b/a
1927 new file mode 100644
1927 new file mode 100644
1928 --- /dev/null
1928 --- /dev/null
1929 +++ b/a
1929 +++ b/a
1930 @@ -0,0 +1,1 @@
1930 @@ -0,0 +1,1 @@
1931 +a
1931 +a
1932
1932
1933
1933
1934 $ hg log -G --git --stat --follow b
1934 $ hg log -G --git --stat --follow b
1935 o changeset: 1:216d4c92cf98
1935 o changeset: 1:216d4c92cf98
1936 | user: test
1936 | user: test
1937 | date: Thu Jan 01 00:00:00 1970 +0000
1937 | date: Thu Jan 01 00:00:00 1970 +0000
1938 | summary: copy a b
1938 | summary: copy a b
1939 |
1939 |
1940 | b | 0
1940 | b | 0
1941 | 1 files changed, 0 insertions(+), 0 deletions(-)
1941 | 1 files changed, 0 insertions(+), 0 deletions(-)
1942 |
1942 |
1943 o changeset: 0:f8035bb17114
1943 o changeset: 0:f8035bb17114
1944 user: test
1944 user: test
1945 date: Thu Jan 01 00:00:00 1970 +0000
1945 date: Thu Jan 01 00:00:00 1970 +0000
1946 summary: add a
1946 summary: add a
1947
1947
1948 a | 1 +
1948 a | 1 +
1949 1 files changed, 1 insertions(+), 0 deletions(-)
1949 1 files changed, 1 insertions(+), 0 deletions(-)
1950
1950
1951
1951
1952 $ hg up -q 6
1952 $ hg up -q 6
1953 $ hg log -G --git --patch --follow-first e
1953 $ hg log -G --git --patch --follow-first e
1954 @ changeset: 6:fc281d8ff18d
1954 @ changeset: 6:fc281d8ff18d
1955 |\ tag: tip
1955 |\ tag: tip
1956 | | parent: 5:99b31f1c2782
1956 | | parent: 5:99b31f1c2782
1957 | | parent: 4:17d952250a9d
1957 | | parent: 4:17d952250a9d
1958 | | user: test
1958 | | user: test
1959 | | date: Thu Jan 01 00:00:00 1970 +0000
1959 | | date: Thu Jan 01 00:00:00 1970 +0000
1960 | | summary: merge 5 and 4
1960 | | summary: merge 5 and 4
1961 | |
1961 | |
1962 | | diff --git a/e b/e
1962 | | diff --git a/e b/e
1963 | | --- a/e
1963 | | --- a/e
1964 | | +++ b/e
1964 | | +++ b/e
1965 | | @@ -1,1 +1,1 @@
1965 | | @@ -1,1 +1,1 @@
1966 | | -ee
1966 | | -ee
1967 | | +merge
1967 | | +merge
1968 | |
1968 | |
1969 o | changeset: 5:99b31f1c2782
1969 o | changeset: 5:99b31f1c2782
1970 | | parent: 3:5918b8d165d1
1970 | | parent: 3:5918b8d165d1
1971 | | user: test
1971 | | user: test
1972 | | date: Thu Jan 01 00:00:00 1970 +0000
1972 | | date: Thu Jan 01 00:00:00 1970 +0000
1973 | | summary: add another e
1973 | | summary: add another e
1974 | |
1974 | |
1975 | | diff --git a/e b/e
1975 | | diff --git a/e b/e
1976 | | new file mode 100644
1976 | | new file mode 100644
1977 | | --- /dev/null
1977 | | --- /dev/null
1978 | | +++ b/e
1978 | | +++ b/e
1979 | | @@ -0,0 +1,1 @@
1979 | | @@ -0,0 +1,1 @@
1980 | | +ee
1980 | | +ee
1981 | |
1981 | |
1982
1982
1983 Test old-style --rev
1983 Test old-style --rev
1984
1984
1985 $ hg tag 'foo-bar'
1985 $ hg tag 'foo-bar'
1986 $ testlog -r 'foo-bar'
1986 $ testlog -r 'foo-bar'
1987 ['foo-bar']
1987 ['foo-bar']
1988 []
1988 []
1989
1989
1990 Test --follow and forward --rev
1990 Test --follow and forward --rev
1991
1991
1992 $ hg up -q 6
1992 $ hg up -q 6
1993 $ echo g > g
1993 $ echo g > g
1994 $ hg ci -Am 'add g' g
1994 $ hg ci -Am 'add g' g
1995 created new head
1995 created new head
1996 $ hg up -q 2
1996 $ hg up -q 2
1997 $ hg log -G --template "{rev} {desc|firstline}\n"
1997 $ hg log -G --template "{rev} {desc|firstline}\n"
1998 o 8 add g
1998 o 8 add g
1999 |
1999 |
2000 | o 7 Added tag foo-bar for changeset fc281d8ff18d
2000 | o 7 Added tag foo-bar for changeset fc281d8ff18d
2001 |/
2001 |/
2002 o 6 merge 5 and 4
2002 o 6 merge 5 and 4
2003 |\
2003 |\
2004 | o 5 add another e
2004 | o 5 add another e
2005 | |
2005 | |
2006 o | 4 mv dir/b e
2006 o | 4 mv dir/b e
2007 |/
2007 |/
2008 o 3 mv a b; add d
2008 o 3 mv a b; add d
2009 |
2009 |
2010 @ 2 mv b dir/b
2010 @ 2 mv b dir/b
2011 |
2011 |
2012 o 1 copy a b
2012 o 1 copy a b
2013 |
2013 |
2014 o 0 add a
2014 o 0 add a
2015
2015
2016 $ hg export 'all()'
2016 $ hg export 'all()'
2017 # HG changeset patch
2017 # HG changeset patch
2018 # User test
2018 # User test
2019 # Date 0 0
2019 # Date 0 0
2020 # Thu Jan 01 00:00:00 1970 +0000
2020 # Thu Jan 01 00:00:00 1970 +0000
2021 # Node ID f8035bb17114da16215af3436ec5222428ace8ee
2021 # Node ID f8035bb17114da16215af3436ec5222428ace8ee
2022 # Parent 0000000000000000000000000000000000000000
2022 # Parent 0000000000000000000000000000000000000000
2023 add a
2023 add a
2024
2024
2025 diff -r 000000000000 -r f8035bb17114 a
2025 diff -r 000000000000 -r f8035bb17114 a
2026 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2026 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2027 +++ b/a Thu Jan 01 00:00:00 1970 +0000
2027 +++ b/a Thu Jan 01 00:00:00 1970 +0000
2028 @@ -0,0 +1,1 @@
2028 @@ -0,0 +1,1 @@
2029 +a
2029 +a
2030 diff -r 000000000000 -r f8035bb17114 aa
2030 diff -r 000000000000 -r f8035bb17114 aa
2031 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2031 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2032 +++ b/aa Thu Jan 01 00:00:00 1970 +0000
2032 +++ b/aa Thu Jan 01 00:00:00 1970 +0000
2033 @@ -0,0 +1,1 @@
2033 @@ -0,0 +1,1 @@
2034 +aa
2034 +aa
2035 diff -r 000000000000 -r f8035bb17114 f
2035 diff -r 000000000000 -r f8035bb17114 f
2036 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2036 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2037 +++ b/f Thu Jan 01 00:00:00 1970 +0000
2037 +++ b/f Thu Jan 01 00:00:00 1970 +0000
2038 @@ -0,0 +1,1 @@
2038 @@ -0,0 +1,1 @@
2039 +f
2039 +f
2040 # HG changeset patch
2040 # HG changeset patch
2041 # User test
2041 # User test
2042 # Date 0 0
2042 # Date 0 0
2043 # Thu Jan 01 00:00:00 1970 +0000
2043 # Thu Jan 01 00:00:00 1970 +0000
2044 # Node ID 216d4c92cf98ff2b4641d508b76b529f3d424c92
2044 # Node ID 216d4c92cf98ff2b4641d508b76b529f3d424c92
2045 # Parent f8035bb17114da16215af3436ec5222428ace8ee
2045 # Parent f8035bb17114da16215af3436ec5222428ace8ee
2046 copy a b
2046 copy a b
2047
2047
2048 diff -r f8035bb17114 -r 216d4c92cf98 b
2048 diff -r f8035bb17114 -r 216d4c92cf98 b
2049 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2049 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2050 +++ b/b Thu Jan 01 00:00:00 1970 +0000
2050 +++ b/b Thu Jan 01 00:00:00 1970 +0000
2051 @@ -0,0 +1,1 @@
2051 @@ -0,0 +1,1 @@
2052 +a
2052 +a
2053 diff -r f8035bb17114 -r 216d4c92cf98 g
2053 diff -r f8035bb17114 -r 216d4c92cf98 g
2054 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2054 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2055 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2055 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2056 @@ -0,0 +1,1 @@
2056 @@ -0,0 +1,1 @@
2057 +f
2057 +f
2058 # HG changeset patch
2058 # HG changeset patch
2059 # User test
2059 # User test
2060 # Date 0 0
2060 # Date 0 0
2061 # Thu Jan 01 00:00:00 1970 +0000
2061 # Thu Jan 01 00:00:00 1970 +0000
2062 # Node ID bb573313a9e8349099b6ea2b2fb1fc7f424446f3
2062 # Node ID bb573313a9e8349099b6ea2b2fb1fc7f424446f3
2063 # Parent 216d4c92cf98ff2b4641d508b76b529f3d424c92
2063 # Parent 216d4c92cf98ff2b4641d508b76b529f3d424c92
2064 mv b dir/b
2064 mv b dir/b
2065
2065
2066 diff -r 216d4c92cf98 -r bb573313a9e8 b
2066 diff -r 216d4c92cf98 -r bb573313a9e8 b
2067 --- a/b Thu Jan 01 00:00:00 1970 +0000
2067 --- a/b Thu Jan 01 00:00:00 1970 +0000
2068 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2068 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2069 @@ -1,1 +0,0 @@
2069 @@ -1,1 +0,0 @@
2070 -a
2070 -a
2071 diff -r 216d4c92cf98 -r bb573313a9e8 dir/b
2071 diff -r 216d4c92cf98 -r bb573313a9e8 dir/b
2072 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2072 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2073 +++ b/dir/b Thu Jan 01 00:00:00 1970 +0000
2073 +++ b/dir/b Thu Jan 01 00:00:00 1970 +0000
2074 @@ -0,0 +1,1 @@
2074 @@ -0,0 +1,1 @@
2075 +a
2075 +a
2076 diff -r 216d4c92cf98 -r bb573313a9e8 f
2076 diff -r 216d4c92cf98 -r bb573313a9e8 f
2077 --- a/f Thu Jan 01 00:00:00 1970 +0000
2077 --- a/f Thu Jan 01 00:00:00 1970 +0000
2078 +++ b/f Thu Jan 01 00:00:00 1970 +0000
2078 +++ b/f Thu Jan 01 00:00:00 1970 +0000
2079 @@ -1,1 +1,2 @@
2079 @@ -1,1 +1,2 @@
2080 f
2080 f
2081 +f
2081 +f
2082 diff -r 216d4c92cf98 -r bb573313a9e8 g
2082 diff -r 216d4c92cf98 -r bb573313a9e8 g
2083 --- a/g Thu Jan 01 00:00:00 1970 +0000
2083 --- a/g Thu Jan 01 00:00:00 1970 +0000
2084 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2084 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2085 @@ -1,1 +1,2 @@
2085 @@ -1,1 +1,2 @@
2086 f
2086 f
2087 +g
2087 +g
2088 # HG changeset patch
2088 # HG changeset patch
2089 # User test
2089 # User test
2090 # Date 0 0
2090 # Date 0 0
2091 # Thu Jan 01 00:00:00 1970 +0000
2091 # Thu Jan 01 00:00:00 1970 +0000
2092 # Node ID 5918b8d165d1364e78a66d02e66caa0133c5d1ed
2092 # Node ID 5918b8d165d1364e78a66d02e66caa0133c5d1ed
2093 # Parent bb573313a9e8349099b6ea2b2fb1fc7f424446f3
2093 # Parent bb573313a9e8349099b6ea2b2fb1fc7f424446f3
2094 mv a b; add d
2094 mv a b; add d
2095
2095
2096 diff -r bb573313a9e8 -r 5918b8d165d1 a
2096 diff -r bb573313a9e8 -r 5918b8d165d1 a
2097 --- a/a Thu Jan 01 00:00:00 1970 +0000
2097 --- a/a Thu Jan 01 00:00:00 1970 +0000
2098 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2098 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2099 @@ -1,1 +0,0 @@
2099 @@ -1,1 +0,0 @@
2100 -a
2100 -a
2101 diff -r bb573313a9e8 -r 5918b8d165d1 b
2101 diff -r bb573313a9e8 -r 5918b8d165d1 b
2102 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2102 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2103 +++ b/b Thu Jan 01 00:00:00 1970 +0000
2103 +++ b/b Thu Jan 01 00:00:00 1970 +0000
2104 @@ -0,0 +1,1 @@
2104 @@ -0,0 +1,1 @@
2105 +a
2105 +a
2106 diff -r bb573313a9e8 -r 5918b8d165d1 d
2106 diff -r bb573313a9e8 -r 5918b8d165d1 d
2107 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2107 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2108 +++ b/d Thu Jan 01 00:00:00 1970 +0000
2108 +++ b/d Thu Jan 01 00:00:00 1970 +0000
2109 @@ -0,0 +1,1 @@
2109 @@ -0,0 +1,1 @@
2110 +a
2110 +a
2111 diff -r bb573313a9e8 -r 5918b8d165d1 g
2111 diff -r bb573313a9e8 -r 5918b8d165d1 g
2112 --- a/g Thu Jan 01 00:00:00 1970 +0000
2112 --- a/g Thu Jan 01 00:00:00 1970 +0000
2113 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2113 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2114 @@ -1,2 +1,2 @@
2114 @@ -1,2 +1,2 @@
2115 f
2115 f
2116 -g
2116 -g
2117 +f
2117 +f
2118 # HG changeset patch
2118 # HG changeset patch
2119 # User test
2119 # User test
2120 # Date 0 0
2120 # Date 0 0
2121 # Thu Jan 01 00:00:00 1970 +0000
2121 # Thu Jan 01 00:00:00 1970 +0000
2122 # Node ID 17d952250a9d03cc3dc77b199ab60e959b9b0260
2122 # Node ID 17d952250a9d03cc3dc77b199ab60e959b9b0260
2123 # Parent 5918b8d165d1364e78a66d02e66caa0133c5d1ed
2123 # Parent 5918b8d165d1364e78a66d02e66caa0133c5d1ed
2124 mv dir/b e
2124 mv dir/b e
2125
2125
2126 diff -r 5918b8d165d1 -r 17d952250a9d dir/b
2126 diff -r 5918b8d165d1 -r 17d952250a9d dir/b
2127 --- a/dir/b Thu Jan 01 00:00:00 1970 +0000
2127 --- a/dir/b Thu Jan 01 00:00:00 1970 +0000
2128 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2128 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2129 @@ -1,1 +0,0 @@
2129 @@ -1,1 +0,0 @@
2130 -a
2130 -a
2131 diff -r 5918b8d165d1 -r 17d952250a9d e
2131 diff -r 5918b8d165d1 -r 17d952250a9d e
2132 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2132 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2133 +++ b/e Thu Jan 01 00:00:00 1970 +0000
2133 +++ b/e Thu Jan 01 00:00:00 1970 +0000
2134 @@ -0,0 +1,1 @@
2134 @@ -0,0 +1,1 @@
2135 +a
2135 +a
2136 # HG changeset patch
2136 # HG changeset patch
2137 # User test
2137 # User test
2138 # Date 0 0
2138 # Date 0 0
2139 # Thu Jan 01 00:00:00 1970 +0000
2139 # Thu Jan 01 00:00:00 1970 +0000
2140 # Node ID 99b31f1c2782e2deb1723cef08930f70fc84b37b
2140 # Node ID 99b31f1c2782e2deb1723cef08930f70fc84b37b
2141 # Parent 5918b8d165d1364e78a66d02e66caa0133c5d1ed
2141 # Parent 5918b8d165d1364e78a66d02e66caa0133c5d1ed
2142 add another e
2142 add another e
2143
2143
2144 diff -r 5918b8d165d1 -r 99b31f1c2782 e
2144 diff -r 5918b8d165d1 -r 99b31f1c2782 e
2145 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2145 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2146 +++ b/e Thu Jan 01 00:00:00 1970 +0000
2146 +++ b/e Thu Jan 01 00:00:00 1970 +0000
2147 @@ -0,0 +1,1 @@
2147 @@ -0,0 +1,1 @@
2148 +ee
2148 +ee
2149 # HG changeset patch
2149 # HG changeset patch
2150 # User test
2150 # User test
2151 # Date 0 0
2151 # Date 0 0
2152 # Thu Jan 01 00:00:00 1970 +0000
2152 # Thu Jan 01 00:00:00 1970 +0000
2153 # Node ID fc281d8ff18d999ad6497b3d27390bcd695dcc73
2153 # Node ID fc281d8ff18d999ad6497b3d27390bcd695dcc73
2154 # Parent 99b31f1c2782e2deb1723cef08930f70fc84b37b
2154 # Parent 99b31f1c2782e2deb1723cef08930f70fc84b37b
2155 # Parent 17d952250a9d03cc3dc77b199ab60e959b9b0260
2155 # Parent 17d952250a9d03cc3dc77b199ab60e959b9b0260
2156 merge 5 and 4
2156 merge 5 and 4
2157
2157
2158 diff -r 99b31f1c2782 -r fc281d8ff18d dir/b
2158 diff -r 99b31f1c2782 -r fc281d8ff18d dir/b
2159 --- a/dir/b Thu Jan 01 00:00:00 1970 +0000
2159 --- a/dir/b Thu Jan 01 00:00:00 1970 +0000
2160 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2160 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2161 @@ -1,1 +0,0 @@
2161 @@ -1,1 +0,0 @@
2162 -a
2162 -a
2163 diff -r 99b31f1c2782 -r fc281d8ff18d e
2163 diff -r 99b31f1c2782 -r fc281d8ff18d e
2164 --- a/e Thu Jan 01 00:00:00 1970 +0000
2164 --- a/e Thu Jan 01 00:00:00 1970 +0000
2165 +++ b/e Thu Jan 01 00:00:00 1970 +0000
2165 +++ b/e Thu Jan 01 00:00:00 1970 +0000
2166 @@ -1,1 +1,1 @@
2166 @@ -1,1 +1,1 @@
2167 -ee
2167 -ee
2168 +merge
2168 +merge
2169 # HG changeset patch
2169 # HG changeset patch
2170 # User test
2170 # User test
2171 # Date 0 0
2171 # Date 0 0
2172 # Thu Jan 01 00:00:00 1970 +0000
2172 # Thu Jan 01 00:00:00 1970 +0000
2173 # Node ID 02dbb8e276b8ab7abfd07cab50c901647e75c2dd
2173 # Node ID 02dbb8e276b8ab7abfd07cab50c901647e75c2dd
2174 # Parent fc281d8ff18d999ad6497b3d27390bcd695dcc73
2174 # Parent fc281d8ff18d999ad6497b3d27390bcd695dcc73
2175 Added tag foo-bar for changeset fc281d8ff18d
2175 Added tag foo-bar for changeset fc281d8ff18d
2176
2176
2177 diff -r fc281d8ff18d -r 02dbb8e276b8 .hgtags
2177 diff -r fc281d8ff18d -r 02dbb8e276b8 .hgtags
2178 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2178 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2179 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
2179 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
2180 @@ -0,0 +1,1 @@
2180 @@ -0,0 +1,1 @@
2181 +fc281d8ff18d999ad6497b3d27390bcd695dcc73 foo-bar
2181 +fc281d8ff18d999ad6497b3d27390bcd695dcc73 foo-bar
2182 # HG changeset patch
2182 # HG changeset patch
2183 # User test
2183 # User test
2184 # Date 0 0
2184 # Date 0 0
2185 # Thu Jan 01 00:00:00 1970 +0000
2185 # Thu Jan 01 00:00:00 1970 +0000
2186 # Node ID 24c2e826ddebf80f9dcd60b856bdb8e6715c5449
2186 # Node ID 24c2e826ddebf80f9dcd60b856bdb8e6715c5449
2187 # Parent fc281d8ff18d999ad6497b3d27390bcd695dcc73
2187 # Parent fc281d8ff18d999ad6497b3d27390bcd695dcc73
2188 add g
2188 add g
2189
2189
2190 diff -r fc281d8ff18d -r 24c2e826ddeb g
2190 diff -r fc281d8ff18d -r 24c2e826ddeb g
2191 --- a/g Thu Jan 01 00:00:00 1970 +0000
2191 --- a/g Thu Jan 01 00:00:00 1970 +0000
2192 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2192 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2193 @@ -1,2 +1,1 @@
2193 @@ -1,2 +1,1 @@
2194 -f
2194 -f
2195 -f
2195 -f
2196 +g
2196 +g
2197 $ testlog --follow -r6 -r8 -r5 -r7 -r4
2197 $ testlog --follow -r6 -r8 -r5 -r7 -r4
2198 ['6', '8', '5', '7', '4']
2198 ['6', '8', '5', '7', '4']
2199 (group
2199 (group
2200 (func
2200 (func
2201 ('symbol', 'descendants')
2201 ('symbol', 'descendants')
2202 (func
2202 (func
2203 ('symbol', 'rev')
2203 ('symbol', 'rev')
2204 ('symbol', '6'))))
2204 ('symbol', '6'))))
2205
2205
2206 Test --follow-first and forward --rev
2206 Test --follow-first and forward --rev
2207
2207
2208 $ testlog --follow-first -r6 -r8 -r5 -r7 -r4
2208 $ testlog --follow-first -r6 -r8 -r5 -r7 -r4
2209 ['6', '8', '5', '7', '4']
2209 ['6', '8', '5', '7', '4']
2210 (group
2210 (group
2211 (func
2211 (func
2212 ('symbol', '_firstdescendants')
2212 ('symbol', '_firstdescendants')
2213 (func
2213 (func
2214 ('symbol', 'rev')
2214 ('symbol', 'rev')
2215 ('symbol', '6'))))
2215 ('symbol', '6'))))
2216 --- log.nodes * (glob)
2216 --- log.nodes * (glob)
2217 +++ glog.nodes * (glob)
2217 +++ glog.nodes * (glob)
2218 @@ -1,3 +1,3 @@
2218 @@ -1,3 +1,3 @@
2219 -nodetag 6
2219 -nodetag 6
2220 nodetag 8
2220 nodetag 8
2221 nodetag 7
2221 nodetag 7
2222 +nodetag 6
2222 +nodetag 6
2223
2223
2224 Test --follow and backward --rev
2224 Test --follow and backward --rev
2225
2225
2226 $ testlog --follow -r6 -r5 -r7 -r8 -r4
2226 $ testlog --follow -r6 -r5 -r7 -r8 -r4
2227 ['6', '5', '7', '8', '4']
2227 ['6', '5', '7', '8', '4']
2228 (group
2228 (group
2229 (func
2229 (func
2230 ('symbol', 'ancestors')
2230 ('symbol', 'ancestors')
2231 (func
2231 (func
2232 ('symbol', 'rev')
2232 ('symbol', 'rev')
2233 ('symbol', '6'))))
2233 ('symbol', '6'))))
2234
2234
2235 Test --follow-first and backward --rev
2235 Test --follow-first and backward --rev
2236
2236
2237 $ testlog --follow-first -r6 -r5 -r7 -r8 -r4
2237 $ testlog --follow-first -r6 -r5 -r7 -r8 -r4
2238 ['6', '5', '7', '8', '4']
2238 ['6', '5', '7', '8', '4']
2239 (group
2239 (group
2240 (func
2240 (func
2241 ('symbol', '_firstancestors')
2241 ('symbol', '_firstancestors')
2242 (func
2242 (func
2243 ('symbol', 'rev')
2243 ('symbol', 'rev')
2244 ('symbol', '6'))))
2244 ('symbol', '6'))))
2245
2245
2246 Test --follow with --rev of graphlog extension
2246 Test --follow with --rev of graphlog extension
2247
2247
2248 $ hg --config extensions.graphlog= glog -qfr1
2248 $ hg --config extensions.graphlog= glog -qfr1
2249 o 1:216d4c92cf98
2249 o 1:216d4c92cf98
2250 |
2250 |
2251 o 0:f8035bb17114
2251 o 0:f8035bb17114
2252
2252
2253
2253
2254 Test subdir
2254 Test subdir
2255
2255
2256 $ hg up -q 3
2256 $ hg up -q 3
2257 $ cd dir
2257 $ cd dir
2258 $ testlog .
2258 $ testlog .
2259 []
2259 []
2260 (group
2260 (group
2261 (func
2261 (func
2262 ('symbol', '_matchfiles')
2262 ('symbol', '_matchfiles')
2263 (list
2263 (list
2264 (list
2264 (list
2265 ('string', 'r:')
2265 ('string', 'r:')
2266 ('string', 'd:relpath'))
2266 ('string', 'd:relpath'))
2267 ('string', 'p:.'))))
2267 ('string', 'p:.'))))
2268 $ testlog ../b
2268 $ testlog ../b
2269 []
2269 []
2270 (group
2270 (group
2271 (group
2271 (group
2272 (func
2272 (func
2273 ('symbol', 'filelog')
2273 ('symbol', 'filelog')
2274 ('string', '../b'))))
2274 ('string', '../b'))))
2275 $ testlog -f ../b
2275 $ testlog -f ../b
2276 []
2276 []
2277 (group
2277 (group
2278 (group
2278 (group
2279 (func
2279 (func
2280 ('symbol', 'follow')
2280 ('symbol', 'follow')
2281 ('string', 'b'))))
2281 ('string', 'b'))))
2282 $ cd ..
2282 $ cd ..
2283
2283
2284 Test --hidden
2284 Test --hidden
2285 (enable obsolete)
2285 (enable obsolete)
2286
2286
2287 $ cat >> $HGRCPATH << EOF
2287 $ cat >> $HGRCPATH << EOF
2288 > [experimental]
2288 > [experimental]
2289 > evolution=createmarkers
2289 > evolution=createmarkers
2290 > EOF
2290 > EOF
2291
2291
2292 $ hg debugobsolete `hg id --debug -i -r 8`
2292 $ hg debugobsolete `hg id --debug -i -r 8`
2293 $ testlog
2293 $ testlog
2294 []
2294 []
2295 []
2295 []
2296 $ testlog --hidden
2296 $ testlog --hidden
2297 []
2297 []
2298 []
2298 []
2299 $ hg log -G --template '{rev} {desc}\n'
2299 $ hg log -G --template '{rev} {desc}\n'
2300 o 7 Added tag foo-bar for changeset fc281d8ff18d
2300 o 7 Added tag foo-bar for changeset fc281d8ff18d
2301 |
2301 |
2302 o 6 merge 5 and 4
2302 o 6 merge 5 and 4
2303 |\
2303 |\
2304 | o 5 add another e
2304 | o 5 add another e
2305 | |
2305 | |
2306 o | 4 mv dir/b e
2306 o | 4 mv dir/b e
2307 |/
2307 |/
2308 @ 3 mv a b; add d
2308 @ 3 mv a b; add d
2309 |
2309 |
2310 o 2 mv b dir/b
2310 o 2 mv b dir/b
2311 |
2311 |
2312 o 1 copy a b
2312 o 1 copy a b
2313 |
2313 |
2314 o 0 add a
2314 o 0 add a
2315
2315
2316
2316
2317 A template without trailing newline should do something sane
2317 A template without trailing newline should do something sane
2318
2318
2319 $ hg log -G -r ::2 --template '{rev} {desc}'
2319 $ hg log -G -r ::2 --template '{rev} {desc}'
2320 o 2 mv b dir/b
2320 o 2 mv b dir/b
2321 |
2321 |
2322 o 1 copy a b
2322 o 1 copy a b
2323 |
2323 |
2324 o 0 add a
2324 o 0 add a
2325
2325
2326
2326
2327 Extra newlines must be preserved
2327 Extra newlines must be preserved
2328
2328
2329 $ hg log -G -r ::2 --template '\n{rev} {desc}\n\n'
2329 $ hg log -G -r ::2 --template '\n{rev} {desc}\n\n'
2330 o
2330 o
2331 | 2 mv b dir/b
2331 | 2 mv b dir/b
2332 |
2332 |
2333 o
2333 o
2334 | 1 copy a b
2334 | 1 copy a b
2335 |
2335 |
2336 o
2336 o
2337 0 add a
2337 0 add a
2338
2338
2339
2339
2340 The almost-empty template should do something sane too ...
2340 The almost-empty template should do something sane too ...
2341
2341
2342 $ hg log -G -r ::2 --template '\n'
2342 $ hg log -G -r ::2 --template '\n'
2343 o
2343 o
2344 |
2344 |
2345 o
2345 o
2346 |
2346 |
2347 o
2347 o
2348
2348
2349
2349
2350 issue3772
2350 issue3772
2351
2351
2352 $ hg log -G -r :null
2352 $ hg log -G -r :null
2353 o changeset: 0:f8035bb17114
2353 o changeset: 0:f8035bb17114
2354 | user: test
2354 | user: test
2355 | date: Thu Jan 01 00:00:00 1970 +0000
2355 | date: Thu Jan 01 00:00:00 1970 +0000
2356 | summary: add a
2356 | summary: add a
2357 |
2357 |
2358 o changeset: -1:000000000000
2358 o changeset: -1:000000000000
2359 user:
2359 user:
2360 date: Thu Jan 01 00:00:00 1970 +0000
2360 date: Thu Jan 01 00:00:00 1970 +0000
2361
2361
2362 $ hg log -G -r null:null
2362 $ hg log -G -r null:null
2363 o changeset: -1:000000000000
2363 o changeset: -1:000000000000
2364 user:
2364 user:
2365 date: Thu Jan 01 00:00:00 1970 +0000
2365 date: Thu Jan 01 00:00:00 1970 +0000
2366
2366
2367
2367
2368 should not draw line down to null due to the magic of fullreposet
2368 should not draw line down to null due to the magic of fullreposet
2369
2369
2370 $ hg log -G -r 'all()' | tail -6
2370 $ hg log -G -r 'all()' | tail -6
2371 |
2371 |
2372 o changeset: 0:f8035bb17114
2372 o changeset: 0:f8035bb17114
2373 user: test
2373 user: test
2374 date: Thu Jan 01 00:00:00 1970 +0000
2374 date: Thu Jan 01 00:00:00 1970 +0000
2375 summary: add a
2375 summary: add a
2376
2376
2377
2377
2378 $ hg log -G -r 'branch(default)' | tail -6
2379 |
2380 o changeset: 0:f8035bb17114
2381 user: test
2382 date: Thu Jan 01 00:00:00 1970 +0000
2383 summary: add a
2384
2385
2378 $ cd ..
2386 $ cd ..
@@ -1,1642 +1,1674 b''
1 $ HGENCODING=utf-8
1 $ HGENCODING=utf-8
2 $ export HGENCODING
2 $ export HGENCODING
3
3
4 $ try() {
4 $ try() {
5 > hg debugrevspec --debug "$@"
5 > hg debugrevspec --debug "$@"
6 > }
6 > }
7
7
8 $ log() {
8 $ log() {
9 > hg log --template '{rev}\n' -r "$1"
9 > hg log --template '{rev}\n' -r "$1"
10 > }
10 > }
11
11
12 $ hg init repo
12 $ hg init repo
13 $ cd repo
13 $ cd repo
14
14
15 $ echo a > a
15 $ echo a > a
16 $ hg branch a
16 $ hg branch a
17 marked working directory as branch a
17 marked working directory as branch a
18 (branches are permanent and global, did you want a bookmark?)
18 (branches are permanent and global, did you want a bookmark?)
19 $ hg ci -Aqm0
19 $ hg ci -Aqm0
20
20
21 $ echo b > b
21 $ echo b > b
22 $ hg branch b
22 $ hg branch b
23 marked working directory as branch b
23 marked working directory as branch b
24 (branches are permanent and global, did you want a bookmark?)
24 (branches are permanent and global, did you want a bookmark?)
25 $ hg ci -Aqm1
25 $ hg ci -Aqm1
26
26
27 $ rm a
27 $ rm a
28 $ hg branch a-b-c-
28 $ hg branch a-b-c-
29 marked working directory as branch a-b-c-
29 marked working directory as branch a-b-c-
30 (branches are permanent and global, did you want a bookmark?)
30 (branches are permanent and global, did you want a bookmark?)
31 $ hg ci -Aqm2 -u Bob
31 $ hg ci -Aqm2 -u Bob
32
32
33 $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
33 $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
34 2
34 2
35 $ hg log -r "extra('branch')" --template '{rev}\n'
35 $ hg log -r "extra('branch')" --template '{rev}\n'
36 0
36 0
37 1
37 1
38 2
38 2
39 $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
39 $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
40 0 a
40 0 a
41 2 a-b-c-
41 2 a-b-c-
42
42
43 $ hg co 1
43 $ hg co 1
44 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
44 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
45 $ hg branch +a+b+c+
45 $ hg branch +a+b+c+
46 marked working directory as branch +a+b+c+
46 marked working directory as branch +a+b+c+
47 (branches are permanent and global, did you want a bookmark?)
47 (branches are permanent and global, did you want a bookmark?)
48 $ hg ci -Aqm3
48 $ hg ci -Aqm3
49
49
50 $ hg co 2 # interleave
50 $ hg co 2 # interleave
51 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
51 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
52 $ echo bb > b
52 $ echo bb > b
53 $ hg branch -- -a-b-c-
53 $ hg branch -- -a-b-c-
54 marked working directory as branch -a-b-c-
54 marked working directory as branch -a-b-c-
55 (branches are permanent and global, did you want a bookmark?)
55 (branches are permanent and global, did you want a bookmark?)
56 $ hg ci -Aqm4 -d "May 12 2005"
56 $ hg ci -Aqm4 -d "May 12 2005"
57
57
58 $ hg co 3
58 $ hg co 3
59 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
59 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
60 $ hg branch !a/b/c/
60 $ hg branch !a/b/c/
61 marked working directory as branch !a/b/c/
61 marked working directory as branch !a/b/c/
62 (branches are permanent and global, did you want a bookmark?)
62 (branches are permanent and global, did you want a bookmark?)
63 $ hg ci -Aqm"5 bug"
63 $ hg ci -Aqm"5 bug"
64
64
65 $ hg merge 4
65 $ hg merge 4
66 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
66 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
67 (branch merge, don't forget to commit)
67 (branch merge, don't forget to commit)
68 $ hg branch _a_b_c_
68 $ hg branch _a_b_c_
69 marked working directory as branch _a_b_c_
69 marked working directory as branch _a_b_c_
70 (branches are permanent and global, did you want a bookmark?)
70 (branches are permanent and global, did you want a bookmark?)
71 $ hg ci -Aqm"6 issue619"
71 $ hg ci -Aqm"6 issue619"
72
72
73 $ hg branch .a.b.c.
73 $ hg branch .a.b.c.
74 marked working directory as branch .a.b.c.
74 marked working directory as branch .a.b.c.
75 (branches are permanent and global, did you want a bookmark?)
75 (branches are permanent and global, did you want a bookmark?)
76 $ hg ci -Aqm7
76 $ hg ci -Aqm7
77
77
78 $ hg branch all
78 $ hg branch all
79 marked working directory as branch all
79 marked working directory as branch all
80 (branches are permanent and global, did you want a bookmark?)
80 (branches are permanent and global, did you want a bookmark?)
81
81
82 $ hg co 4
82 $ hg co 4
83 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
83 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
84 $ hg branch Γ©
84 $ hg branch Γ©
85 marked working directory as branch \xc3\xa9 (esc)
85 marked working directory as branch \xc3\xa9 (esc)
86 (branches are permanent and global, did you want a bookmark?)
86 (branches are permanent and global, did you want a bookmark?)
87 $ hg ci -Aqm9
87 $ hg ci -Aqm9
88
88
89 $ hg tag -r6 1.0
89 $ hg tag -r6 1.0
90 $ hg bookmark -r6 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
90 $ hg bookmark -r6 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
91
91
92 $ hg clone --quiet -U -r 7 . ../remote1
92 $ hg clone --quiet -U -r 7 . ../remote1
93 $ hg clone --quiet -U -r 8 . ../remote2
93 $ hg clone --quiet -U -r 8 . ../remote2
94 $ echo "[paths]" >> .hg/hgrc
94 $ echo "[paths]" >> .hg/hgrc
95 $ echo "default = ../remote1" >> .hg/hgrc
95 $ echo "default = ../remote1" >> .hg/hgrc
96
96
97 trivial
97 trivial
98
98
99 $ try 0:1
99 $ try 0:1
100 (range
100 (range
101 ('symbol', '0')
101 ('symbol', '0')
102 ('symbol', '1'))
102 ('symbol', '1'))
103 * set:
103 * set:
104 <spanset+ 0:1>
104 <spanset+ 0:1>
105 0
105 0
106 1
106 1
107 $ try 3::6
107 $ try 3::6
108 (dagrange
108 (dagrange
109 ('symbol', '3')
109 ('symbol', '3')
110 ('symbol', '6'))
110 ('symbol', '6'))
111 * set:
111 * set:
112 <baseset [3, 5, 6]>
112 <baseset [3, 5, 6]>
113 3
113 3
114 5
114 5
115 6
115 6
116 $ try '0|1|2'
116 $ try '0|1|2'
117 (or
117 (or
118 (or
118 (or
119 ('symbol', '0')
119 ('symbol', '0')
120 ('symbol', '1'))
120 ('symbol', '1'))
121 ('symbol', '2'))
121 ('symbol', '2'))
122 * set:
122 * set:
123 <addset
123 <addset
124 <addset
124 <addset
125 <baseset [0]>,
125 <baseset [0]>,
126 <baseset [1]>>,
126 <baseset [1]>>,
127 <baseset [2]>>
127 <baseset [2]>>
128 0
128 0
129 1
129 1
130 2
130 2
131
131
132 names that should work without quoting
132 names that should work without quoting
133
133
134 $ try a
134 $ try a
135 ('symbol', 'a')
135 ('symbol', 'a')
136 * set:
136 * set:
137 <baseset [0]>
137 <baseset [0]>
138 0
138 0
139 $ try b-a
139 $ try b-a
140 (minus
140 (minus
141 ('symbol', 'b')
141 ('symbol', 'b')
142 ('symbol', 'a'))
142 ('symbol', 'a'))
143 * set:
143 * set:
144 <filteredset
144 <filteredset
145 <baseset [1]>>
145 <baseset [1]>>
146 1
146 1
147 $ try _a_b_c_
147 $ try _a_b_c_
148 ('symbol', '_a_b_c_')
148 ('symbol', '_a_b_c_')
149 * set:
149 * set:
150 <baseset [6]>
150 <baseset [6]>
151 6
151 6
152 $ try _a_b_c_-a
152 $ try _a_b_c_-a
153 (minus
153 (minus
154 ('symbol', '_a_b_c_')
154 ('symbol', '_a_b_c_')
155 ('symbol', 'a'))
155 ('symbol', 'a'))
156 * set:
156 * set:
157 <filteredset
157 <filteredset
158 <baseset [6]>>
158 <baseset [6]>>
159 6
159 6
160 $ try .a.b.c.
160 $ try .a.b.c.
161 ('symbol', '.a.b.c.')
161 ('symbol', '.a.b.c.')
162 * set:
162 * set:
163 <baseset [7]>
163 <baseset [7]>
164 7
164 7
165 $ try .a.b.c.-a
165 $ try .a.b.c.-a
166 (minus
166 (minus
167 ('symbol', '.a.b.c.')
167 ('symbol', '.a.b.c.')
168 ('symbol', 'a'))
168 ('symbol', 'a'))
169 * set:
169 * set:
170 <filteredset
170 <filteredset
171 <baseset [7]>>
171 <baseset [7]>>
172 7
172 7
173 $ try -- '-a-b-c-' # complains
173 $ try -- '-a-b-c-' # complains
174 hg: parse error at 7: not a prefix: end
174 hg: parse error at 7: not a prefix: end
175 [255]
175 [255]
176 $ log -a-b-c- # succeeds with fallback
176 $ log -a-b-c- # succeeds with fallback
177 4
177 4
178
178
179 $ try -- -a-b-c--a # complains
179 $ try -- -a-b-c--a # complains
180 (minus
180 (minus
181 (minus
181 (minus
182 (minus
182 (minus
183 (negate
183 (negate
184 ('symbol', 'a'))
184 ('symbol', 'a'))
185 ('symbol', 'b'))
185 ('symbol', 'b'))
186 ('symbol', 'c'))
186 ('symbol', 'c'))
187 (negate
187 (negate
188 ('symbol', 'a')))
188 ('symbol', 'a')))
189 abort: unknown revision '-a'!
189 abort: unknown revision '-a'!
190 [255]
190 [255]
191 $ try Γ©
191 $ try Γ©
192 ('symbol', '\xc3\xa9')
192 ('symbol', '\xc3\xa9')
193 * set:
193 * set:
194 <baseset [9]>
194 <baseset [9]>
195 9
195 9
196
196
197 no quoting needed
197 no quoting needed
198
198
199 $ log ::a-b-c-
199 $ log ::a-b-c-
200 0
200 0
201 1
201 1
202 2
202 2
203
203
204 quoting needed
204 quoting needed
205
205
206 $ try '"-a-b-c-"-a'
206 $ try '"-a-b-c-"-a'
207 (minus
207 (minus
208 ('string', '-a-b-c-')
208 ('string', '-a-b-c-')
209 ('symbol', 'a'))
209 ('symbol', 'a'))
210 * set:
210 * set:
211 <filteredset
211 <filteredset
212 <baseset [4]>>
212 <baseset [4]>>
213 4
213 4
214
214
215 $ log '1 or 2'
215 $ log '1 or 2'
216 1
216 1
217 2
217 2
218 $ log '1|2'
218 $ log '1|2'
219 1
219 1
220 2
220 2
221 $ log '1 and 2'
221 $ log '1 and 2'
222 $ log '1&2'
222 $ log '1&2'
223 $ try '1&2|3' # precedence - and is higher
223 $ try '1&2|3' # precedence - and is higher
224 (or
224 (or
225 (and
225 (and
226 ('symbol', '1')
226 ('symbol', '1')
227 ('symbol', '2'))
227 ('symbol', '2'))
228 ('symbol', '3'))
228 ('symbol', '3'))
229 * set:
229 * set:
230 <addset
230 <addset
231 <baseset []>,
231 <baseset []>,
232 <baseset [3]>>
232 <baseset [3]>>
233 3
233 3
234 $ try '1|2&3'
234 $ try '1|2&3'
235 (or
235 (or
236 ('symbol', '1')
236 ('symbol', '1')
237 (and
237 (and
238 ('symbol', '2')
238 ('symbol', '2')
239 ('symbol', '3')))
239 ('symbol', '3')))
240 * set:
240 * set:
241 <addset
241 <addset
242 <baseset [1]>,
242 <baseset [1]>,
243 <baseset []>>
243 <baseset []>>
244 1
244 1
245 $ try '1&2&3' # associativity
245 $ try '1&2&3' # associativity
246 (and
246 (and
247 (and
247 (and
248 ('symbol', '1')
248 ('symbol', '1')
249 ('symbol', '2'))
249 ('symbol', '2'))
250 ('symbol', '3'))
250 ('symbol', '3'))
251 * set:
251 * set:
252 <baseset []>
252 <baseset []>
253 $ try '1|(2|3)'
253 $ try '1|(2|3)'
254 (or
254 (or
255 ('symbol', '1')
255 ('symbol', '1')
256 (group
256 (group
257 (or
257 (or
258 ('symbol', '2')
258 ('symbol', '2')
259 ('symbol', '3'))))
259 ('symbol', '3'))))
260 * set:
260 * set:
261 <addset
261 <addset
262 <baseset [1]>,
262 <baseset [1]>,
263 <addset
263 <addset
264 <baseset [2]>,
264 <baseset [2]>,
265 <baseset [3]>>>
265 <baseset [3]>>>
266 1
266 1
267 2
267 2
268 3
268 3
269 $ log '1.0' # tag
269 $ log '1.0' # tag
270 6
270 6
271 $ log 'a' # branch
271 $ log 'a' # branch
272 0
272 0
273 $ log '2785f51ee'
273 $ log '2785f51ee'
274 0
274 0
275 $ log 'date(2005)'
275 $ log 'date(2005)'
276 4
276 4
277 $ log 'date(this is a test)'
277 $ log 'date(this is a test)'
278 hg: parse error at 10: unexpected token: symbol
278 hg: parse error at 10: unexpected token: symbol
279 [255]
279 [255]
280 $ log 'date()'
280 $ log 'date()'
281 hg: parse error: date requires a string
281 hg: parse error: date requires a string
282 [255]
282 [255]
283 $ log 'date'
283 $ log 'date'
284 hg: parse error: can't use date here
284 hg: parse error: can't use date here
285 [255]
285 [255]
286 $ log 'date('
286 $ log 'date('
287 hg: parse error at 5: not a prefix: end
287 hg: parse error at 5: not a prefix: end
288 [255]
288 [255]
289 $ log 'date(tip)'
289 $ log 'date(tip)'
290 abort: invalid date: 'tip'
290 abort: invalid date: 'tip'
291 [255]
291 [255]
292 $ log '"date"'
292 $ log '"date"'
293 abort: unknown revision 'date'!
293 abort: unknown revision 'date'!
294 [255]
294 [255]
295 $ log 'date(2005) and 1::'
295 $ log 'date(2005) and 1::'
296 4
296 4
297
297
298 ancestor can accept 0 or more arguments
298 ancestor can accept 0 or more arguments
299
299
300 $ log 'ancestor()'
300 $ log 'ancestor()'
301 $ log 'ancestor(1)'
301 $ log 'ancestor(1)'
302 1
302 1
303 $ log 'ancestor(4,5)'
303 $ log 'ancestor(4,5)'
304 1
304 1
305 $ log 'ancestor(4,5) and 4'
305 $ log 'ancestor(4,5) and 4'
306 $ log 'ancestor(0,0,1,3)'
306 $ log 'ancestor(0,0,1,3)'
307 0
307 0
308 $ log 'ancestor(3,1,5,3,5,1)'
308 $ log 'ancestor(3,1,5,3,5,1)'
309 1
309 1
310 $ log 'ancestor(0,1,3,5)'
310 $ log 'ancestor(0,1,3,5)'
311 0
311 0
312 $ log 'ancestor(1,2,3,4,5)'
312 $ log 'ancestor(1,2,3,4,5)'
313 1
313 1
314 $ log 'ancestors(5)'
314 $ log 'ancestors(5)'
315 0
315 0
316 1
316 1
317 3
317 3
318 5
318 5
319 $ log 'ancestor(ancestors(5))'
319 $ log 'ancestor(ancestors(5))'
320 0
320 0
321 $ log 'author(bob)'
321 $ log 'author(bob)'
322 2
322 2
323 $ log 'author("re:bob|test")'
323 $ log 'author("re:bob|test")'
324 0
324 0
325 1
325 1
326 2
326 2
327 3
327 3
328 4
328 4
329 5
329 5
330 6
330 6
331 7
331 7
332 8
332 8
333 9
333 9
334 $ log 'branch(Γ©)'
334 $ log 'branch(Γ©)'
335 8
335 8
336 9
336 9
337 $ log 'branch(a)'
337 $ log 'branch(a)'
338 0
338 0
339 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
339 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
340 0 a
340 0 a
341 2 a-b-c-
341 2 a-b-c-
342 3 +a+b+c+
342 3 +a+b+c+
343 4 -a-b-c-
343 4 -a-b-c-
344 5 !a/b/c/
344 5 !a/b/c/
345 6 _a_b_c_
345 6 _a_b_c_
346 7 .a.b.c.
346 7 .a.b.c.
347 $ log 'children(ancestor(4,5))'
347 $ log 'children(ancestor(4,5))'
348 2
348 2
349 3
349 3
350 $ log 'closed()'
350 $ log 'closed()'
351 $ log 'contains(a)'
351 $ log 'contains(a)'
352 0
352 0
353 1
353 1
354 3
354 3
355 5
355 5
356 $ log 'contains("../repo/a")'
356 $ log 'contains("../repo/a")'
357 0
357 0
358 1
358 1
359 3
359 3
360 5
360 5
361 $ log 'desc(B)'
361 $ log 'desc(B)'
362 5
362 5
363 $ log 'descendants(2 or 3)'
363 $ log 'descendants(2 or 3)'
364 2
364 2
365 3
365 3
366 4
366 4
367 5
367 5
368 6
368 6
369 7
369 7
370 8
370 8
371 9
371 9
372 $ log 'file("b*")'
372 $ log 'file("b*")'
373 1
373 1
374 4
374 4
375 $ log 'filelog("b")'
375 $ log 'filelog("b")'
376 1
376 1
377 4
377 4
378 $ log 'filelog("../repo/b")'
378 $ log 'filelog("../repo/b")'
379 1
379 1
380 4
380 4
381 $ log 'follow()'
381 $ log 'follow()'
382 0
382 0
383 1
383 1
384 2
384 2
385 4
385 4
386 8
386 8
387 9
387 9
388 $ log 'grep("issue\d+")'
388 $ log 'grep("issue\d+")'
389 6
389 6
390 $ try 'grep("(")' # invalid regular expression
390 $ try 'grep("(")' # invalid regular expression
391 (func
391 (func
392 ('symbol', 'grep')
392 ('symbol', 'grep')
393 ('string', '('))
393 ('string', '('))
394 hg: parse error: invalid match pattern: unbalanced parenthesis
394 hg: parse error: invalid match pattern: unbalanced parenthesis
395 [255]
395 [255]
396 $ try 'grep("\bissue\d+")'
396 $ try 'grep("\bissue\d+")'
397 (func
397 (func
398 ('symbol', 'grep')
398 ('symbol', 'grep')
399 ('string', '\x08issue\\d+'))
399 ('string', '\x08issue\\d+'))
400 * set:
400 * set:
401 <filteredset
401 <filteredset
402 <fullreposet+ 0:9>>
402 <fullreposet+ 0:9>>
403 $ try 'grep(r"\bissue\d+")'
403 $ try 'grep(r"\bissue\d+")'
404 (func
404 (func
405 ('symbol', 'grep')
405 ('symbol', 'grep')
406 ('string', '\\bissue\\d+'))
406 ('string', '\\bissue\\d+'))
407 * set:
407 * set:
408 <filteredset
408 <filteredset
409 <fullreposet+ 0:9>>
409 <fullreposet+ 0:9>>
410 6
410 6
411 $ try 'grep(r"\")'
411 $ try 'grep(r"\")'
412 hg: parse error at 7: unterminated string
412 hg: parse error at 7: unterminated string
413 [255]
413 [255]
414 $ log 'head()'
414 $ log 'head()'
415 0
415 0
416 1
416 1
417 2
417 2
418 3
418 3
419 4
419 4
420 5
420 5
421 6
421 6
422 7
422 7
423 9
423 9
424 $ log 'heads(6::)'
424 $ log 'heads(6::)'
425 7
425 7
426 $ log 'keyword(issue)'
426 $ log 'keyword(issue)'
427 6
427 6
428 $ log 'keyword("test a")'
428 $ log 'keyword("test a")'
429 $ log 'limit(head(), 1)'
429 $ log 'limit(head(), 1)'
430 0
430 0
431 $ log 'matching(6)'
431 $ log 'matching(6)'
432 6
432 6
433 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
433 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
434 6
434 6
435 7
435 7
436
436
437 Testing min and max
437 Testing min and max
438
438
439 max: simple
439 max: simple
440
440
441 $ log 'max(contains(a))'
441 $ log 'max(contains(a))'
442 5
442 5
443
443
444 max: simple on unordered set)
444 max: simple on unordered set)
445
445
446 $ log 'max((4+0+2+5+7) and contains(a))'
446 $ log 'max((4+0+2+5+7) and contains(a))'
447 5
447 5
448
448
449 max: no result
449 max: no result
450
450
451 $ log 'max(contains(stringthatdoesnotappearanywhere))'
451 $ log 'max(contains(stringthatdoesnotappearanywhere))'
452
452
453 max: no result on unordered set
453 max: no result on unordered set
454
454
455 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
455 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
456
456
457 min: simple
457 min: simple
458
458
459 $ log 'min(contains(a))'
459 $ log 'min(contains(a))'
460 0
460 0
461
461
462 min: simple on unordered set
462 min: simple on unordered set
463
463
464 $ log 'min((4+0+2+5+7) and contains(a))'
464 $ log 'min((4+0+2+5+7) and contains(a))'
465 0
465 0
466
466
467 min: empty
467 min: empty
468
468
469 $ log 'min(contains(stringthatdoesnotappearanywhere))'
469 $ log 'min(contains(stringthatdoesnotappearanywhere))'
470
470
471 min: empty on unordered set
471 min: empty on unordered set
472
472
473 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
473 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
474
474
475
475
476 $ log 'merge()'
476 $ log 'merge()'
477 6
477 6
478 $ log 'branchpoint()'
478 $ log 'branchpoint()'
479 1
479 1
480 4
480 4
481 $ log 'modifies(b)'
481 $ log 'modifies(b)'
482 4
482 4
483 $ log 'modifies("path:b")'
483 $ log 'modifies("path:b")'
484 4
484 4
485 $ log 'modifies("*")'
485 $ log 'modifies("*")'
486 4
486 4
487 6
487 6
488 $ log 'modifies("set:modified()")'
488 $ log 'modifies("set:modified()")'
489 4
489 4
490 $ log 'id(5)'
490 $ log 'id(5)'
491 2
491 2
492 $ log 'only(9)'
492 $ log 'only(9)'
493 8
493 8
494 9
494 9
495 $ log 'only(8)'
495 $ log 'only(8)'
496 8
496 8
497 $ log 'only(9, 5)'
497 $ log 'only(9, 5)'
498 2
498 2
499 4
499 4
500 8
500 8
501 9
501 9
502 $ log 'only(7 + 9, 5 + 2)'
502 $ log 'only(7 + 9, 5 + 2)'
503 4
503 4
504 6
504 6
505 7
505 7
506 8
506 8
507 9
507 9
508
508
509 Test empty set input
509 Test empty set input
510 $ log 'only(p2())'
510 $ log 'only(p2())'
511 $ log 'only(p1(), p2())'
511 $ log 'only(p1(), p2())'
512 0
512 0
513 1
513 1
514 2
514 2
515 4
515 4
516 8
516 8
517 9
517 9
518
518
519 Test '%' operator
519 Test '%' operator
520
520
521 $ log '9%'
521 $ log '9%'
522 8
522 8
523 9
523 9
524 $ log '9%5'
524 $ log '9%5'
525 2
525 2
526 4
526 4
527 8
527 8
528 9
528 9
529 $ log '(7 + 9)%(5 + 2)'
529 $ log '(7 + 9)%(5 + 2)'
530 4
530 4
531 6
531 6
532 7
532 7
533 8
533 8
534 9
534 9
535
535
536 Test opreand of '%' is optimized recursively (issue4670)
536 Test opreand of '%' is optimized recursively (issue4670)
537
537
538 $ try --optimize '8:9-8%'
538 $ try --optimize '8:9-8%'
539 (onlypost
539 (onlypost
540 (minus
540 (minus
541 (range
541 (range
542 ('symbol', '8')
542 ('symbol', '8')
543 ('symbol', '9'))
543 ('symbol', '9'))
544 ('symbol', '8')))
544 ('symbol', '8')))
545 * optimized:
545 * optimized:
546 (func
546 (func
547 ('symbol', 'only')
547 ('symbol', 'only')
548 (and
548 (and
549 (range
549 (range
550 ('symbol', '8')
550 ('symbol', '8')
551 ('symbol', '9'))
551 ('symbol', '9'))
552 (not
552 (not
553 ('symbol', '8'))))
553 ('symbol', '8'))))
554 * set:
554 * set:
555 <baseset+ [8, 9]>
555 <baseset+ [8, 9]>
556 8
556 8
557 9
557 9
558
558
559 Test the order of operations
559 Test the order of operations
560
560
561 $ log '7 + 9%5 + 2'
561 $ log '7 + 9%5 + 2'
562 7
562 7
563 2
563 2
564 4
564 4
565 8
565 8
566 9
566 9
567
567
568 Test explicit numeric revision
568 Test explicit numeric revision
569 $ log 'rev(-2)'
569 $ log 'rev(-2)'
570 $ log 'rev(-1)'
570 $ log 'rev(-1)'
571 -1
571 -1
572 $ log 'rev(0)'
572 $ log 'rev(0)'
573 0
573 0
574 $ log 'rev(9)'
574 $ log 'rev(9)'
575 9
575 9
576 $ log 'rev(10)'
576 $ log 'rev(10)'
577 $ log 'rev(tip)'
577 $ log 'rev(tip)'
578 hg: parse error: rev expects a number
578 hg: parse error: rev expects a number
579 [255]
579 [255]
580
580
581 Test hexadecimal revision
581 Test hexadecimal revision
582 $ log 'id(2)'
582 $ log 'id(2)'
583 abort: 00changelog.i@2: ambiguous identifier!
583 abort: 00changelog.i@2: ambiguous identifier!
584 [255]
584 [255]
585 $ log 'id(23268)'
585 $ log 'id(23268)'
586 4
586 4
587 $ log 'id(2785f51eece)'
587 $ log 'id(2785f51eece)'
588 0
588 0
589 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532c)'
589 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532c)'
590 8
590 8
591 $ log 'id(d5d0dcbdc4a)'
591 $ log 'id(d5d0dcbdc4a)'
592 $ log 'id(d5d0dcbdc4w)'
592 $ log 'id(d5d0dcbdc4w)'
593 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532d)'
593 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532d)'
594 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532q)'
594 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532q)'
595 $ log 'id(1.0)'
595 $ log 'id(1.0)'
596 $ log 'id(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)'
596 $ log 'id(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)'
597
597
598 Test null revision
598 Test null revision
599 $ log '(null)'
599 $ log '(null)'
600 -1
600 -1
601 $ log '(null:0)'
601 $ log '(null:0)'
602 -1
602 -1
603 0
603 0
604 $ log '(0:null)'
604 $ log '(0:null)'
605 0
605 0
606 -1
606 -1
607 $ log 'null::0'
607 $ log 'null::0'
608 -1
608 -1
609 0
609 0
610 $ log 'null:tip - 0:'
610 $ log 'null:tip - 0:'
611 -1
611 -1
612 $ log 'null: and null::' | head -1
612 $ log 'null: and null::' | head -1
613 -1
613 -1
614 $ log 'null: or 0:' | head -2
614 $ log 'null: or 0:' | head -2
615 -1
615 -1
616 0
616 0
617 $ log 'ancestors(null)'
617 $ log 'ancestors(null)'
618 -1
618 -1
619 $ log 'reverse(null:)' | tail -2
619 $ log 'reverse(null:)' | tail -2
620 0
620 0
621 -1
621 -1
622 BROKEN: should be '-1'
622 $ log 'first(null:)'
623 $ log 'first(null:)'
623 -1
624 BROKEN: should be '-1'
624 $ log 'min(null:)'
625 $ log 'min(null:)'
625 -1
626 $ log 'tip:null and all()' | tail -2
626 $ log 'tip:null and all()' | tail -2
627 1
627 1
628 0
628 0
629
629
630 Test working-directory revision
630 Test working-directory revision
631 $ hg debugrevspec 'wdir()'
631 $ hg debugrevspec 'wdir()'
632 None
632 None
633 BROKEN: should include 'None'
633 $ hg debugrevspec 'tip or wdir()'
634 $ hg debugrevspec 'tip or wdir()'
634 9
635 9
635 None
636 $ hg debugrevspec '0:tip and wdir()'
636 $ hg debugrevspec '0:tip and wdir()'
637
637
638 $ log 'outgoing()'
638 $ log 'outgoing()'
639 8
639 8
640 9
640 9
641 $ log 'outgoing("../remote1")'
641 $ log 'outgoing("../remote1")'
642 8
642 8
643 9
643 9
644 $ log 'outgoing("../remote2")'
644 $ log 'outgoing("../remote2")'
645 3
645 3
646 5
646 5
647 6
647 6
648 7
648 7
649 9
649 9
650 $ log 'p1(merge())'
650 $ log 'p1(merge())'
651 5
651 5
652 $ log 'p2(merge())'
652 $ log 'p2(merge())'
653 4
653 4
654 $ log 'parents(merge())'
654 $ log 'parents(merge())'
655 4
655 4
656 5
656 5
657 $ log 'p1(branchpoint())'
657 $ log 'p1(branchpoint())'
658 0
658 0
659 2
659 2
660 $ log 'p2(branchpoint())'
660 $ log 'p2(branchpoint())'
661 $ log 'parents(branchpoint())'
661 $ log 'parents(branchpoint())'
662 0
662 0
663 2
663 2
664 $ log 'removes(a)'
664 $ log 'removes(a)'
665 2
665 2
666 6
666 6
667 $ log 'roots(all())'
667 $ log 'roots(all())'
668 0
668 0
669 $ log 'reverse(2 or 3 or 4 or 5)'
669 $ log 'reverse(2 or 3 or 4 or 5)'
670 5
670 5
671 4
671 4
672 3
672 3
673 2
673 2
674 $ log 'reverse(all())'
674 $ log 'reverse(all())'
675 9
675 9
676 8
676 8
677 7
677 7
678 6
678 6
679 5
679 5
680 4
680 4
681 3
681 3
682 2
682 2
683 1
683 1
684 0
684 0
685 $ log 'reverse(all()) & filelog(b)'
685 $ log 'reverse(all()) & filelog(b)'
686 4
686 4
687 1
687 1
688 $ log 'rev(5)'
688 $ log 'rev(5)'
689 5
689 5
690 $ log 'sort(limit(reverse(all()), 3))'
690 $ log 'sort(limit(reverse(all()), 3))'
691 7
691 7
692 8
692 8
693 9
693 9
694 $ log 'sort(2 or 3 or 4 or 5, date)'
694 $ log 'sort(2 or 3 or 4 or 5, date)'
695 2
695 2
696 3
696 3
697 5
697 5
698 4
698 4
699 $ log 'tagged()'
699 $ log 'tagged()'
700 6
700 6
701 $ log 'tag()'
701 $ log 'tag()'
702 6
702 6
703 $ log 'tag(1.0)'
703 $ log 'tag(1.0)'
704 6
704 6
705 $ log 'tag(tip)'
705 $ log 'tag(tip)'
706 9
706 9
707
707
708 test sort revset
708 test sort revset
709 --------------------------------------------
709 --------------------------------------------
710
710
711 test when adding two unordered revsets
711 test when adding two unordered revsets
712
712
713 $ log 'sort(keyword(issue) or modifies(b))'
713 $ log 'sort(keyword(issue) or modifies(b))'
714 4
714 4
715 6
715 6
716
716
717 test when sorting a reversed collection in the same way it is
717 test when sorting a reversed collection in the same way it is
718
718
719 $ log 'sort(reverse(all()), -rev)'
719 $ log 'sort(reverse(all()), -rev)'
720 9
720 9
721 8
721 8
722 7
722 7
723 6
723 6
724 5
724 5
725 4
725 4
726 3
726 3
727 2
727 2
728 1
728 1
729 0
729 0
730
730
731 test when sorting a reversed collection
731 test when sorting a reversed collection
732
732
733 $ log 'sort(reverse(all()), rev)'
733 $ log 'sort(reverse(all()), rev)'
734 0
734 0
735 1
735 1
736 2
736 2
737 3
737 3
738 4
738 4
739 5
739 5
740 6
740 6
741 7
741 7
742 8
742 8
743 9
743 9
744
744
745
745
746 test sorting two sorted collections in different orders
746 test sorting two sorted collections in different orders
747
747
748 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
748 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
749 2
749 2
750 6
750 6
751 8
751 8
752 9
752 9
753
753
754 test sorting two sorted collections in different orders backwards
754 test sorting two sorted collections in different orders backwards
755
755
756 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
756 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
757 9
757 9
758 8
758 8
759 6
759 6
760 2
760 2
761
761
762 test subtracting something from an addset
762 test subtracting something from an addset
763
763
764 $ log '(outgoing() or removes(a)) - removes(a)'
764 $ log '(outgoing() or removes(a)) - removes(a)'
765 8
765 8
766 9
766 9
767
767
768 test intersecting something with an addset
768 test intersecting something with an addset
769
769
770 $ log 'parents(outgoing() or removes(a))'
770 $ log 'parents(outgoing() or removes(a))'
771 1
771 1
772 4
772 4
773 5
773 5
774 8
774 8
775
775
776 test that `or` operation combines elements in the right order:
776 test that `or` operation combines elements in the right order:
777
777
778 $ log '3:4 or 2:5'
778 $ log '3:4 or 2:5'
779 3
779 3
780 4
780 4
781 2
781 2
782 5
782 5
783 $ log '3:4 or 5:2'
783 $ log '3:4 or 5:2'
784 3
784 3
785 4
785 4
786 5
786 5
787 2
787 2
788 $ log 'sort(3:4 or 2:5)'
788 $ log 'sort(3:4 or 2:5)'
789 2
789 2
790 3
790 3
791 4
791 4
792 5
792 5
793 $ log 'sort(3:4 or 5:2)'
793 $ log 'sort(3:4 or 5:2)'
794 2
794 2
795 3
795 3
796 4
796 4
797 5
797 5
798
798
799 check that conversion to only works
799 check that conversion to only works
800 $ try --optimize '::3 - ::1'
800 $ try --optimize '::3 - ::1'
801 (minus
801 (minus
802 (dagrangepre
802 (dagrangepre
803 ('symbol', '3'))
803 ('symbol', '3'))
804 (dagrangepre
804 (dagrangepre
805 ('symbol', '1')))
805 ('symbol', '1')))
806 * optimized:
806 * optimized:
807 (func
807 (func
808 ('symbol', 'only')
808 ('symbol', 'only')
809 (list
809 (list
810 ('symbol', '3')
810 ('symbol', '3')
811 ('symbol', '1')))
811 ('symbol', '1')))
812 * set:
812 * set:
813 <baseset+ [3]>
813 <baseset+ [3]>
814 3
814 3
815 $ try --optimize 'ancestors(1) - ancestors(3)'
815 $ try --optimize 'ancestors(1) - ancestors(3)'
816 (minus
816 (minus
817 (func
817 (func
818 ('symbol', 'ancestors')
818 ('symbol', 'ancestors')
819 ('symbol', '1'))
819 ('symbol', '1'))
820 (func
820 (func
821 ('symbol', 'ancestors')
821 ('symbol', 'ancestors')
822 ('symbol', '3')))
822 ('symbol', '3')))
823 * optimized:
823 * optimized:
824 (func
824 (func
825 ('symbol', 'only')
825 ('symbol', 'only')
826 (list
826 (list
827 ('symbol', '1')
827 ('symbol', '1')
828 ('symbol', '3')))
828 ('symbol', '3')))
829 * set:
829 * set:
830 <baseset+ []>
830 <baseset+ []>
831 $ try --optimize 'not ::2 and ::6'
831 $ try --optimize 'not ::2 and ::6'
832 (and
832 (and
833 (not
833 (not
834 (dagrangepre
834 (dagrangepre
835 ('symbol', '2')))
835 ('symbol', '2')))
836 (dagrangepre
836 (dagrangepre
837 ('symbol', '6')))
837 ('symbol', '6')))
838 * optimized:
838 * optimized:
839 (func
839 (func
840 ('symbol', 'only')
840 ('symbol', 'only')
841 (list
841 (list
842 ('symbol', '6')
842 ('symbol', '6')
843 ('symbol', '2')))
843 ('symbol', '2')))
844 * set:
844 * set:
845 <baseset+ [3, 4, 5, 6]>
845 <baseset+ [3, 4, 5, 6]>
846 3
846 3
847 4
847 4
848 5
848 5
849 6
849 6
850 $ try --optimize 'ancestors(6) and not ancestors(4)'
850 $ try --optimize 'ancestors(6) and not ancestors(4)'
851 (and
851 (and
852 (func
852 (func
853 ('symbol', 'ancestors')
853 ('symbol', 'ancestors')
854 ('symbol', '6'))
854 ('symbol', '6'))
855 (not
855 (not
856 (func
856 (func
857 ('symbol', 'ancestors')
857 ('symbol', 'ancestors')
858 ('symbol', '4'))))
858 ('symbol', '4'))))
859 * optimized:
859 * optimized:
860 (func
860 (func
861 ('symbol', 'only')
861 ('symbol', 'only')
862 (list
862 (list
863 ('symbol', '6')
863 ('symbol', '6')
864 ('symbol', '4')))
864 ('symbol', '4')))
865 * set:
865 * set:
866 <baseset+ [3, 5, 6]>
866 <baseset+ [3, 5, 6]>
867 3
867 3
868 5
868 5
869 6
869 6
870
870
871 we can use patterns when searching for tags
871 we can use patterns when searching for tags
872
872
873 $ log 'tag("1..*")'
873 $ log 'tag("1..*")'
874 abort: tag '1..*' does not exist!
874 abort: tag '1..*' does not exist!
875 [255]
875 [255]
876 $ log 'tag("re:1..*")'
876 $ log 'tag("re:1..*")'
877 6
877 6
878 $ log 'tag("re:[0-9].[0-9]")'
878 $ log 'tag("re:[0-9].[0-9]")'
879 6
879 6
880 $ log 'tag("literal:1.0")'
880 $ log 'tag("literal:1.0")'
881 6
881 6
882 $ log 'tag("re:0..*")'
882 $ log 'tag("re:0..*")'
883
883
884 $ log 'tag(unknown)'
884 $ log 'tag(unknown)'
885 abort: tag 'unknown' does not exist!
885 abort: tag 'unknown' does not exist!
886 [255]
886 [255]
887 $ log 'tag("re:unknown")'
887 $ log 'tag("re:unknown")'
888 $ log 'present(tag("unknown"))'
888 $ log 'present(tag("unknown"))'
889 $ log 'present(tag("re:unknown"))'
889 $ log 'present(tag("re:unknown"))'
890 $ log 'branch(unknown)'
890 $ log 'branch(unknown)'
891 abort: unknown revision 'unknown'!
891 abort: unknown revision 'unknown'!
892 [255]
892 [255]
893 $ log 'branch("re:unknown")'
893 $ log 'branch("re:unknown")'
894 $ log 'present(branch("unknown"))'
894 $ log 'present(branch("unknown"))'
895 $ log 'present(branch("re:unknown"))'
895 $ log 'present(branch("re:unknown"))'
896 $ log 'user(bob)'
896 $ log 'user(bob)'
897 2
897 2
898
898
899 $ log '4::8'
899 $ log '4::8'
900 4
900 4
901 8
901 8
902 $ log '4:8'
902 $ log '4:8'
903 4
903 4
904 5
904 5
905 6
905 6
906 7
906 7
907 8
907 8
908
908
909 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
909 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
910 4
910 4
911 2
911 2
912 5
912 5
913
913
914 $ log 'not 0 and 0:2'
914 $ log 'not 0 and 0:2'
915 1
915 1
916 2
916 2
917 $ log 'not 1 and 0:2'
917 $ log 'not 1 and 0:2'
918 0
918 0
919 2
919 2
920 $ log 'not 2 and 0:2'
920 $ log 'not 2 and 0:2'
921 0
921 0
922 1
922 1
923 $ log '(1 and 2)::'
923 $ log '(1 and 2)::'
924 $ log '(1 and 2):'
924 $ log '(1 and 2):'
925 $ log '(1 and 2):3'
925 $ log '(1 and 2):3'
926 $ log 'sort(head(), -rev)'
926 $ log 'sort(head(), -rev)'
927 9
927 9
928 7
928 7
929 6
929 6
930 5
930 5
931 4
931 4
932 3
932 3
933 2
933 2
934 1
934 1
935 0
935 0
936 $ log '4::8 - 8'
936 $ log '4::8 - 8'
937 4
937 4
938 $ log 'matching(1 or 2 or 3) and (2 or 3 or 1)'
938 $ log 'matching(1 or 2 or 3) and (2 or 3 or 1)'
939 2
939 2
940 3
940 3
941 1
941 1
942
942
943 $ log 'named("unknown")'
943 $ log 'named("unknown")'
944 abort: namespace 'unknown' does not exist!
944 abort: namespace 'unknown' does not exist!
945 [255]
945 [255]
946 $ log 'named("re:unknown")'
946 $ log 'named("re:unknown")'
947 abort: no namespace exists that match 'unknown'!
947 abort: no namespace exists that match 'unknown'!
948 [255]
948 [255]
949 $ log 'present(named("unknown"))'
949 $ log 'present(named("unknown"))'
950 $ log 'present(named("re:unknown"))'
950 $ log 'present(named("re:unknown"))'
951
951
952 $ log 'tag()'
952 $ log 'tag()'
953 6
953 6
954 $ log 'named("tags")'
954 $ log 'named("tags")'
955 6
955 6
956
956
957 issue2437
957 issue2437
958
958
959 $ log '3 and p1(5)'
959 $ log '3 and p1(5)'
960 3
960 3
961 $ log '4 and p2(6)'
961 $ log '4 and p2(6)'
962 4
962 4
963 $ log '1 and parents(:2)'
963 $ log '1 and parents(:2)'
964 1
964 1
965 $ log '2 and children(1:)'
965 $ log '2 and children(1:)'
966 2
966 2
967 $ log 'roots(all()) or roots(all())'
967 $ log 'roots(all()) or roots(all())'
968 0
968 0
969 $ hg debugrevspec 'roots(all()) or roots(all())'
969 $ hg debugrevspec 'roots(all()) or roots(all())'
970 0
970 0
971 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
971 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
972 9
972 9
973 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
973 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
974 4
974 4
975
975
976 issue2654: report a parse error if the revset was not completely parsed
976 issue2654: report a parse error if the revset was not completely parsed
977
977
978 $ log '1 OR 2'
978 $ log '1 OR 2'
979 hg: parse error at 2: invalid token
979 hg: parse error at 2: invalid token
980 [255]
980 [255]
981
981
982 or operator should preserve ordering:
982 or operator should preserve ordering:
983 $ log 'reverse(2::4) or tip'
983 $ log 'reverse(2::4) or tip'
984 4
984 4
985 2
985 2
986 9
986 9
987
987
988 parentrevspec
988 parentrevspec
989
989
990 $ log 'merge()^0'
990 $ log 'merge()^0'
991 6
991 6
992 $ log 'merge()^'
992 $ log 'merge()^'
993 5
993 5
994 $ log 'merge()^1'
994 $ log 'merge()^1'
995 5
995 5
996 $ log 'merge()^2'
996 $ log 'merge()^2'
997 4
997 4
998 $ log 'merge()^^'
998 $ log 'merge()^^'
999 3
999 3
1000 $ log 'merge()^1^'
1000 $ log 'merge()^1^'
1001 3
1001 3
1002 $ log 'merge()^^^'
1002 $ log 'merge()^^^'
1003 1
1003 1
1004
1004
1005 $ log 'merge()~0'
1005 $ log 'merge()~0'
1006 6
1006 6
1007 $ log 'merge()~1'
1007 $ log 'merge()~1'
1008 5
1008 5
1009 $ log 'merge()~2'
1009 $ log 'merge()~2'
1010 3
1010 3
1011 $ log 'merge()~2^1'
1011 $ log 'merge()~2^1'
1012 1
1012 1
1013 $ log 'merge()~3'
1013 $ log 'merge()~3'
1014 1
1014 1
1015
1015
1016 $ log '(-3:tip)^'
1016 $ log '(-3:tip)^'
1017 4
1017 4
1018 6
1018 6
1019 8
1019 8
1020
1020
1021 $ log 'tip^foo'
1021 $ log 'tip^foo'
1022 hg: parse error: ^ expects a number 0, 1, or 2
1022 hg: parse error: ^ expects a number 0, 1, or 2
1023 [255]
1023 [255]
1024
1024
1025 Bogus function gets suggestions
1025 Bogus function gets suggestions
1026 $ log 'add()'
1026 $ log 'add()'
1027 hg: parse error: unknown identifier: add
1027 hg: parse error: unknown identifier: add
1028 (did you mean 'adds'?)
1028 (did you mean 'adds'?)
1029 [255]
1029 [255]
1030 $ log 'added()'
1030 $ log 'added()'
1031 hg: parse error: unknown identifier: added
1031 hg: parse error: unknown identifier: added
1032 (did you mean 'adds'?)
1032 (did you mean 'adds'?)
1033 [255]
1033 [255]
1034 $ log 'remo()'
1034 $ log 'remo()'
1035 hg: parse error: unknown identifier: remo
1035 hg: parse error: unknown identifier: remo
1036 (did you mean one of remote, removes?)
1036 (did you mean one of remote, removes?)
1037 [255]
1037 [255]
1038 $ log 'babar()'
1038 $ log 'babar()'
1039 hg: parse error: unknown identifier: babar
1039 hg: parse error: unknown identifier: babar
1040 [255]
1040 [255]
1041
1041
1042 multiple revspecs
1042 multiple revspecs
1043
1043
1044 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
1044 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
1045 8
1045 8
1046 9
1046 9
1047 4
1047 4
1048 5
1048 5
1049 6
1049 6
1050 7
1050 7
1051
1051
1052 test usage in revpair (with "+")
1052 test usage in revpair (with "+")
1053
1053
1054 (real pair)
1054 (real pair)
1055
1055
1056 $ hg diff -r 'tip^^' -r 'tip'
1056 $ hg diff -r 'tip^^' -r 'tip'
1057 diff -r 2326846efdab -r 24286f4ae135 .hgtags
1057 diff -r 2326846efdab -r 24286f4ae135 .hgtags
1058 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1058 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1059 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
1059 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
1060 @@ -0,0 +1,1 @@
1060 @@ -0,0 +1,1 @@
1061 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1061 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1062 $ hg diff -r 'tip^^::tip'
1062 $ hg diff -r 'tip^^::tip'
1063 diff -r 2326846efdab -r 24286f4ae135 .hgtags
1063 diff -r 2326846efdab -r 24286f4ae135 .hgtags
1064 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1064 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1065 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
1065 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
1066 @@ -0,0 +1,1 @@
1066 @@ -0,0 +1,1 @@
1067 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1067 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1068
1068
1069 (single rev)
1069 (single rev)
1070
1070
1071 $ hg diff -r 'tip^' -r 'tip^'
1071 $ hg diff -r 'tip^' -r 'tip^'
1072 $ hg diff -r 'tip^::tip^ or tip^'
1072 $ hg diff -r 'tip^::tip^ or tip^'
1073
1073
1074 (single rev that does not looks like a range)
1074 (single rev that does not looks like a range)
1075
1075
1076 $ hg diff -r 'tip^ or tip^'
1076 $ hg diff -r 'tip^ or tip^'
1077 diff -r d5d0dcbdc4d9 .hgtags
1077 diff -r d5d0dcbdc4d9 .hgtags
1078 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1078 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1079 +++ b/.hgtags * (glob)
1079 +++ b/.hgtags * (glob)
1080 @@ -0,0 +1,1 @@
1080 @@ -0,0 +1,1 @@
1081 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1081 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1082
1082
1083 (no rev)
1083 (no rev)
1084
1084
1085 $ hg diff -r 'author("babar") or author("celeste")'
1085 $ hg diff -r 'author("babar") or author("celeste")'
1086 abort: empty revision range
1086 abort: empty revision range
1087 [255]
1087 [255]
1088
1088
1089 aliases:
1089 aliases:
1090
1090
1091 $ echo '[revsetalias]' >> .hg/hgrc
1091 $ echo '[revsetalias]' >> .hg/hgrc
1092 $ echo 'm = merge()' >> .hg/hgrc
1092 $ echo 'm = merge()' >> .hg/hgrc
1093 (revset aliases can override builtin revsets)
1093 (revset aliases can override builtin revsets)
1094 $ echo 'p2($1) = p1($1)' >> .hg/hgrc
1094 $ echo 'p2($1) = p1($1)' >> .hg/hgrc
1095 $ echo 'sincem = descendants(m)' >> .hg/hgrc
1095 $ echo 'sincem = descendants(m)' >> .hg/hgrc
1096 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
1096 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
1097 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
1097 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
1098 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
1098 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
1099
1099
1100 $ try m
1100 $ try m
1101 ('symbol', 'm')
1101 ('symbol', 'm')
1102 (func
1102 (func
1103 ('symbol', 'merge')
1103 ('symbol', 'merge')
1104 None)
1104 None)
1105 * set:
1105 * set:
1106 <filteredset
1106 <filteredset
1107 <fullreposet+ 0:9>>
1107 <fullreposet+ 0:9>>
1108 6
1108 6
1109
1109
1110 $ HGPLAIN=1
1110 $ HGPLAIN=1
1111 $ export HGPLAIN
1111 $ export HGPLAIN
1112 $ try m
1112 $ try m
1113 ('symbol', 'm')
1113 ('symbol', 'm')
1114 abort: unknown revision 'm'!
1114 abort: unknown revision 'm'!
1115 [255]
1115 [255]
1116
1116
1117 $ HGPLAINEXCEPT=revsetalias
1117 $ HGPLAINEXCEPT=revsetalias
1118 $ export HGPLAINEXCEPT
1118 $ export HGPLAINEXCEPT
1119 $ try m
1119 $ try m
1120 ('symbol', 'm')
1120 ('symbol', 'm')
1121 (func
1121 (func
1122 ('symbol', 'merge')
1122 ('symbol', 'merge')
1123 None)
1123 None)
1124 * set:
1124 * set:
1125 <filteredset
1125 <filteredset
1126 <fullreposet+ 0:9>>
1126 <fullreposet+ 0:9>>
1127 6
1127 6
1128
1128
1129 $ unset HGPLAIN
1129 $ unset HGPLAIN
1130 $ unset HGPLAINEXCEPT
1130 $ unset HGPLAINEXCEPT
1131
1131
1132 $ try 'p2(.)'
1132 $ try 'p2(.)'
1133 (func
1133 (func
1134 ('symbol', 'p2')
1134 ('symbol', 'p2')
1135 ('symbol', '.'))
1135 ('symbol', '.'))
1136 (func
1136 (func
1137 ('symbol', 'p1')
1137 ('symbol', 'p1')
1138 ('symbol', '.'))
1138 ('symbol', '.'))
1139 * set:
1139 * set:
1140 <baseset+ [8]>
1140 <baseset+ [8]>
1141 8
1141 8
1142
1142
1143 $ HGPLAIN=1
1143 $ HGPLAIN=1
1144 $ export HGPLAIN
1144 $ export HGPLAIN
1145 $ try 'p2(.)'
1145 $ try 'p2(.)'
1146 (func
1146 (func
1147 ('symbol', 'p2')
1147 ('symbol', 'p2')
1148 ('symbol', '.'))
1148 ('symbol', '.'))
1149 * set:
1149 * set:
1150 <baseset+ []>
1150 <baseset+ []>
1151
1151
1152 $ HGPLAINEXCEPT=revsetalias
1152 $ HGPLAINEXCEPT=revsetalias
1153 $ export HGPLAINEXCEPT
1153 $ export HGPLAINEXCEPT
1154 $ try 'p2(.)'
1154 $ try 'p2(.)'
1155 (func
1155 (func
1156 ('symbol', 'p2')
1156 ('symbol', 'p2')
1157 ('symbol', '.'))
1157 ('symbol', '.'))
1158 (func
1158 (func
1159 ('symbol', 'p1')
1159 ('symbol', 'p1')
1160 ('symbol', '.'))
1160 ('symbol', '.'))
1161 * set:
1161 * set:
1162 <baseset+ [8]>
1162 <baseset+ [8]>
1163 8
1163 8
1164
1164
1165 $ unset HGPLAIN
1165 $ unset HGPLAIN
1166 $ unset HGPLAINEXCEPT
1166 $ unset HGPLAINEXCEPT
1167
1167
1168 test alias recursion
1168 test alias recursion
1169
1169
1170 $ try sincem
1170 $ try sincem
1171 ('symbol', 'sincem')
1171 ('symbol', 'sincem')
1172 (func
1172 (func
1173 ('symbol', 'descendants')
1173 ('symbol', 'descendants')
1174 (func
1174 (func
1175 ('symbol', 'merge')
1175 ('symbol', 'merge')
1176 None))
1176 None))
1177 * set:
1177 * set:
1178 <addset+
1178 <addset+
1179 <filteredset
1179 <filteredset
1180 <fullreposet+ 0:9>>,
1180 <fullreposet+ 0:9>>,
1181 <generatorset+>>
1181 <generatorset+>>
1182 6
1182 6
1183 7
1183 7
1184
1184
1185 test infinite recursion
1185 test infinite recursion
1186
1186
1187 $ echo 'recurse1 = recurse2' >> .hg/hgrc
1187 $ echo 'recurse1 = recurse2' >> .hg/hgrc
1188 $ echo 'recurse2 = recurse1' >> .hg/hgrc
1188 $ echo 'recurse2 = recurse1' >> .hg/hgrc
1189 $ try recurse1
1189 $ try recurse1
1190 ('symbol', 'recurse1')
1190 ('symbol', 'recurse1')
1191 hg: parse error: infinite expansion of revset alias "recurse1" detected
1191 hg: parse error: infinite expansion of revset alias "recurse1" detected
1192 [255]
1192 [255]
1193
1193
1194 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
1194 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
1195 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
1195 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
1196 $ try "level2(level1(1, 2), 3)"
1196 $ try "level2(level1(1, 2), 3)"
1197 (func
1197 (func
1198 ('symbol', 'level2')
1198 ('symbol', 'level2')
1199 (list
1199 (list
1200 (func
1200 (func
1201 ('symbol', 'level1')
1201 ('symbol', 'level1')
1202 (list
1202 (list
1203 ('symbol', '1')
1203 ('symbol', '1')
1204 ('symbol', '2')))
1204 ('symbol', '2')))
1205 ('symbol', '3')))
1205 ('symbol', '3')))
1206 (or
1206 (or
1207 ('symbol', '3')
1207 ('symbol', '3')
1208 (or
1208 (or
1209 ('symbol', '1')
1209 ('symbol', '1')
1210 ('symbol', '2')))
1210 ('symbol', '2')))
1211 * set:
1211 * set:
1212 <addset
1212 <addset
1213 <baseset [3]>,
1213 <baseset [3]>,
1214 <addset
1214 <addset
1215 <baseset [1]>,
1215 <baseset [1]>,
1216 <baseset [2]>>>
1216 <baseset [2]>>>
1217 3
1217 3
1218 1
1218 1
1219 2
1219 2
1220
1220
1221 test nesting and variable passing
1221 test nesting and variable passing
1222
1222
1223 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
1223 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
1224 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
1224 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
1225 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
1225 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
1226 $ try 'nested(2:5)'
1226 $ try 'nested(2:5)'
1227 (func
1227 (func
1228 ('symbol', 'nested')
1228 ('symbol', 'nested')
1229 (range
1229 (range
1230 ('symbol', '2')
1230 ('symbol', '2')
1231 ('symbol', '5')))
1231 ('symbol', '5')))
1232 (func
1232 (func
1233 ('symbol', 'max')
1233 ('symbol', 'max')
1234 (range
1234 (range
1235 ('symbol', '2')
1235 ('symbol', '2')
1236 ('symbol', '5')))
1236 ('symbol', '5')))
1237 * set:
1237 * set:
1238 <baseset [5]>
1238 <baseset [5]>
1239 5
1239 5
1240
1240
1241 test variable isolation, variable placeholders are rewritten as string
1241 test variable isolation, variable placeholders are rewritten as string
1242 then parsed and matched again as string. Check they do not leak too
1242 then parsed and matched again as string. Check they do not leak too
1243 far away.
1243 far away.
1244
1244
1245 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
1245 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
1246 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
1246 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
1247 $ try 'callinjection(2:5)'
1247 $ try 'callinjection(2:5)'
1248 (func
1248 (func
1249 ('symbol', 'callinjection')
1249 ('symbol', 'callinjection')
1250 (range
1250 (range
1251 ('symbol', '2')
1251 ('symbol', '2')
1252 ('symbol', '5')))
1252 ('symbol', '5')))
1253 (func
1253 (func
1254 ('symbol', 'descendants')
1254 ('symbol', 'descendants')
1255 (func
1255 (func
1256 ('symbol', 'max')
1256 ('symbol', 'max')
1257 ('string', '$1')))
1257 ('string', '$1')))
1258 abort: unknown revision '$1'!
1258 abort: unknown revision '$1'!
1259 [255]
1259 [255]
1260
1260
1261 $ echo 'injectparamasstring2 = max(_aliasarg("$1"))' >> .hg/hgrc
1261 $ echo 'injectparamasstring2 = max(_aliasarg("$1"))' >> .hg/hgrc
1262 $ echo 'callinjection2($1) = descendants(injectparamasstring2)' >> .hg/hgrc
1262 $ echo 'callinjection2($1) = descendants(injectparamasstring2)' >> .hg/hgrc
1263 $ try 'callinjection2(2:5)'
1263 $ try 'callinjection2(2:5)'
1264 (func
1264 (func
1265 ('symbol', 'callinjection2')
1265 ('symbol', 'callinjection2')
1266 (range
1266 (range
1267 ('symbol', '2')
1267 ('symbol', '2')
1268 ('symbol', '5')))
1268 ('symbol', '5')))
1269 abort: failed to parse the definition of revset alias "injectparamasstring2": unknown identifier: _aliasarg
1269 abort: failed to parse the definition of revset alias "injectparamasstring2": unknown identifier: _aliasarg
1270 [255]
1270 [255]
1271 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
1271 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
1272 ('symbol', 'tip')
1272 ('symbol', 'tip')
1273 warning: failed to parse the definition of revset alias "anotherbadone": at 7: not a prefix: end
1273 warning: failed to parse the definition of revset alias "anotherbadone": at 7: not a prefix: end
1274 warning: failed to parse the definition of revset alias "injectparamasstring2": unknown identifier: _aliasarg
1274 warning: failed to parse the definition of revset alias "injectparamasstring2": unknown identifier: _aliasarg
1275 * set:
1275 * set:
1276 <baseset [9]>
1276 <baseset [9]>
1277 9
1277 9
1278 >>> data = file('.hg/hgrc', 'rb').read()
1278 >>> data = file('.hg/hgrc', 'rb').read()
1279 >>> file('.hg/hgrc', 'wb').write(data.replace('_aliasarg', ''))
1279 >>> file('.hg/hgrc', 'wb').write(data.replace('_aliasarg', ''))
1280
1280
1281 $ try 'tip'
1281 $ try 'tip'
1282 ('symbol', 'tip')
1282 ('symbol', 'tip')
1283 * set:
1283 * set:
1284 <baseset [9]>
1284 <baseset [9]>
1285 9
1285 9
1286
1286
1287 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
1287 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
1288 ('symbol', 'tip')
1288 ('symbol', 'tip')
1289 warning: failed to parse the declaration of revset alias "bad name": at 4: invalid token
1289 warning: failed to parse the declaration of revset alias "bad name": at 4: invalid token
1290 * set:
1290 * set:
1291 <baseset [9]>
1291 <baseset [9]>
1292 9
1292 9
1293 $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc
1293 $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc
1294 $ try 'strictreplacing("foo", tip)'
1294 $ try 'strictreplacing("foo", tip)'
1295 (func
1295 (func
1296 ('symbol', 'strictreplacing')
1296 ('symbol', 'strictreplacing')
1297 (list
1297 (list
1298 ('string', 'foo')
1298 ('string', 'foo')
1299 ('symbol', 'tip')))
1299 ('symbol', 'tip')))
1300 (or
1300 (or
1301 ('symbol', 'tip')
1301 ('symbol', 'tip')
1302 (func
1302 (func
1303 ('symbol', 'desc')
1303 ('symbol', 'desc')
1304 ('string', '$1')))
1304 ('string', '$1')))
1305 * set:
1305 * set:
1306 <addset
1306 <addset
1307 <baseset [9]>,
1307 <baseset [9]>,
1308 <filteredset
1308 <filteredset
1309 <filteredset
1309 <filteredset
1310 <fullreposet+ 0:9>>>>
1310 <fullreposet+ 0:9>>>>
1311 9
1311 9
1312
1312
1313 $ try 'd(2:5)'
1313 $ try 'd(2:5)'
1314 (func
1314 (func
1315 ('symbol', 'd')
1315 ('symbol', 'd')
1316 (range
1316 (range
1317 ('symbol', '2')
1317 ('symbol', '2')
1318 ('symbol', '5')))
1318 ('symbol', '5')))
1319 (func
1319 (func
1320 ('symbol', 'reverse')
1320 ('symbol', 'reverse')
1321 (func
1321 (func
1322 ('symbol', 'sort')
1322 ('symbol', 'sort')
1323 (list
1323 (list
1324 (range
1324 (range
1325 ('symbol', '2')
1325 ('symbol', '2')
1326 ('symbol', '5'))
1326 ('symbol', '5'))
1327 ('symbol', 'date'))))
1327 ('symbol', 'date'))))
1328 * set:
1328 * set:
1329 <baseset [4, 5, 3, 2]>
1329 <baseset [4, 5, 3, 2]>
1330 4
1330 4
1331 5
1331 5
1332 3
1332 3
1333 2
1333 2
1334 $ try 'rs(2 or 3, date)'
1334 $ try 'rs(2 or 3, date)'
1335 (func
1335 (func
1336 ('symbol', 'rs')
1336 ('symbol', 'rs')
1337 (list
1337 (list
1338 (or
1338 (or
1339 ('symbol', '2')
1339 ('symbol', '2')
1340 ('symbol', '3'))
1340 ('symbol', '3'))
1341 ('symbol', 'date')))
1341 ('symbol', 'date')))
1342 (func
1342 (func
1343 ('symbol', 'reverse')
1343 ('symbol', 'reverse')
1344 (func
1344 (func
1345 ('symbol', 'sort')
1345 ('symbol', 'sort')
1346 (list
1346 (list
1347 (or
1347 (or
1348 ('symbol', '2')
1348 ('symbol', '2')
1349 ('symbol', '3'))
1349 ('symbol', '3'))
1350 ('symbol', 'date'))))
1350 ('symbol', 'date'))))
1351 * set:
1351 * set:
1352 <baseset [3, 2]>
1352 <baseset [3, 2]>
1353 3
1353 3
1354 2
1354 2
1355 $ try 'rs()'
1355 $ try 'rs()'
1356 (func
1356 (func
1357 ('symbol', 'rs')
1357 ('symbol', 'rs')
1358 None)
1358 None)
1359 hg: parse error: invalid number of arguments: 0
1359 hg: parse error: invalid number of arguments: 0
1360 [255]
1360 [255]
1361 $ try 'rs(2)'
1361 $ try 'rs(2)'
1362 (func
1362 (func
1363 ('symbol', 'rs')
1363 ('symbol', 'rs')
1364 ('symbol', '2'))
1364 ('symbol', '2'))
1365 hg: parse error: invalid number of arguments: 1
1365 hg: parse error: invalid number of arguments: 1
1366 [255]
1366 [255]
1367 $ try 'rs(2, data, 7)'
1367 $ try 'rs(2, data, 7)'
1368 (func
1368 (func
1369 ('symbol', 'rs')
1369 ('symbol', 'rs')
1370 (list
1370 (list
1371 (list
1371 (list
1372 ('symbol', '2')
1372 ('symbol', '2')
1373 ('symbol', 'data'))
1373 ('symbol', 'data'))
1374 ('symbol', '7')))
1374 ('symbol', '7')))
1375 hg: parse error: invalid number of arguments: 3
1375 hg: parse error: invalid number of arguments: 3
1376 [255]
1376 [255]
1377 $ try 'rs4(2 or 3, x, x, date)'
1377 $ try 'rs4(2 or 3, x, x, date)'
1378 (func
1378 (func
1379 ('symbol', 'rs4')
1379 ('symbol', 'rs4')
1380 (list
1380 (list
1381 (list
1381 (list
1382 (list
1382 (list
1383 (or
1383 (or
1384 ('symbol', '2')
1384 ('symbol', '2')
1385 ('symbol', '3'))
1385 ('symbol', '3'))
1386 ('symbol', 'x'))
1386 ('symbol', 'x'))
1387 ('symbol', 'x'))
1387 ('symbol', 'x'))
1388 ('symbol', 'date')))
1388 ('symbol', 'date')))
1389 (func
1389 (func
1390 ('symbol', 'reverse')
1390 ('symbol', 'reverse')
1391 (func
1391 (func
1392 ('symbol', 'sort')
1392 ('symbol', 'sort')
1393 (list
1393 (list
1394 (or
1394 (or
1395 ('symbol', '2')
1395 ('symbol', '2')
1396 ('symbol', '3'))
1396 ('symbol', '3'))
1397 ('symbol', 'date'))))
1397 ('symbol', 'date'))))
1398 * set:
1398 * set:
1399 <baseset [3, 2]>
1399 <baseset [3, 2]>
1400 3
1400 3
1401 2
1401 2
1402
1402
1403 issue4553: check that revset aliases override existing hash prefix
1403 issue4553: check that revset aliases override existing hash prefix
1404
1404
1405 $ hg log -qr e
1405 $ hg log -qr e
1406 6:e0cc66ef77e8
1406 6:e0cc66ef77e8
1407
1407
1408 $ hg log -qr e --config revsetalias.e="all()"
1408 $ hg log -qr e --config revsetalias.e="all()"
1409 0:2785f51eece5
1409 0:2785f51eece5
1410 1:d75937da8da0
1410 1:d75937da8da0
1411 2:5ed5505e9f1c
1411 2:5ed5505e9f1c
1412 3:8528aa5637f2
1412 3:8528aa5637f2
1413 4:2326846efdab
1413 4:2326846efdab
1414 5:904fa392b941
1414 5:904fa392b941
1415 6:e0cc66ef77e8
1415 6:e0cc66ef77e8
1416 7:013af1973af4
1416 7:013af1973af4
1417 8:d5d0dcbdc4d9
1417 8:d5d0dcbdc4d9
1418 9:24286f4ae135
1418 9:24286f4ae135
1419
1419
1420 $ hg log -qr e: --config revsetalias.e="0"
1420 $ hg log -qr e: --config revsetalias.e="0"
1421 0:2785f51eece5
1421 0:2785f51eece5
1422 1:d75937da8da0
1422 1:d75937da8da0
1423 2:5ed5505e9f1c
1423 2:5ed5505e9f1c
1424 3:8528aa5637f2
1424 3:8528aa5637f2
1425 4:2326846efdab
1425 4:2326846efdab
1426 5:904fa392b941
1426 5:904fa392b941
1427 6:e0cc66ef77e8
1427 6:e0cc66ef77e8
1428 7:013af1973af4
1428 7:013af1973af4
1429 8:d5d0dcbdc4d9
1429 8:d5d0dcbdc4d9
1430 9:24286f4ae135
1430 9:24286f4ae135
1431
1431
1432 $ hg log -qr :e --config revsetalias.e="9"
1432 $ hg log -qr :e --config revsetalias.e="9"
1433 0:2785f51eece5
1433 0:2785f51eece5
1434 1:d75937da8da0
1434 1:d75937da8da0
1435 2:5ed5505e9f1c
1435 2:5ed5505e9f1c
1436 3:8528aa5637f2
1436 3:8528aa5637f2
1437 4:2326846efdab
1437 4:2326846efdab
1438 5:904fa392b941
1438 5:904fa392b941
1439 6:e0cc66ef77e8
1439 6:e0cc66ef77e8
1440 7:013af1973af4
1440 7:013af1973af4
1441 8:d5d0dcbdc4d9
1441 8:d5d0dcbdc4d9
1442 9:24286f4ae135
1442 9:24286f4ae135
1443
1443
1444 $ hg log -qr e:
1444 $ hg log -qr e:
1445 6:e0cc66ef77e8
1445 6:e0cc66ef77e8
1446 7:013af1973af4
1446 7:013af1973af4
1447 8:d5d0dcbdc4d9
1447 8:d5d0dcbdc4d9
1448 9:24286f4ae135
1448 9:24286f4ae135
1449
1449
1450 $ hg log -qr :e
1450 $ hg log -qr :e
1451 0:2785f51eece5
1451 0:2785f51eece5
1452 1:d75937da8da0
1452 1:d75937da8da0
1453 2:5ed5505e9f1c
1453 2:5ed5505e9f1c
1454 3:8528aa5637f2
1454 3:8528aa5637f2
1455 4:2326846efdab
1455 4:2326846efdab
1456 5:904fa392b941
1456 5:904fa392b941
1457 6:e0cc66ef77e8
1457 6:e0cc66ef77e8
1458
1458
1459 issue2549 - correct optimizations
1459 issue2549 - correct optimizations
1460
1460
1461 $ log 'limit(1 or 2 or 3, 2) and not 2'
1461 $ log 'limit(1 or 2 or 3, 2) and not 2'
1462 1
1462 1
1463 $ log 'max(1 or 2) and not 2'
1463 $ log 'max(1 or 2) and not 2'
1464 $ log 'min(1 or 2) and not 1'
1464 $ log 'min(1 or 2) and not 1'
1465 $ log 'last(1 or 2, 1) and not 2'
1465 $ log 'last(1 or 2, 1) and not 2'
1466
1466
1467 issue4289 - ordering of built-ins
1467 issue4289 - ordering of built-ins
1468 $ hg log -M -q -r 3:2
1468 $ hg log -M -q -r 3:2
1469 3:8528aa5637f2
1469 3:8528aa5637f2
1470 2:5ed5505e9f1c
1470 2:5ed5505e9f1c
1471
1471
1472 test revsets started with 40-chars hash (issue3669)
1472 test revsets started with 40-chars hash (issue3669)
1473
1473
1474 $ ISSUE3669_TIP=`hg tip --template '{node}'`
1474 $ ISSUE3669_TIP=`hg tip --template '{node}'`
1475 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
1475 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
1476 9
1476 9
1477 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
1477 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
1478 8
1478 8
1479
1479
1480 test or-ed indirect predicates (issue3775)
1480 test or-ed indirect predicates (issue3775)
1481
1481
1482 $ log '6 or 6^1' | sort
1482 $ log '6 or 6^1' | sort
1483 5
1483 5
1484 6
1484 6
1485 $ log '6^1 or 6' | sort
1485 $ log '6^1 or 6' | sort
1486 5
1486 5
1487 6
1487 6
1488 $ log '4 or 4~1' | sort
1488 $ log '4 or 4~1' | sort
1489 2
1489 2
1490 4
1490 4
1491 $ log '4~1 or 4' | sort
1491 $ log '4~1 or 4' | sort
1492 2
1492 2
1493 4
1493 4
1494 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
1494 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
1495 0
1495 0
1496 1
1496 1
1497 2
1497 2
1498 3
1498 3
1499 4
1499 4
1500 5
1500 5
1501 6
1501 6
1502 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
1502 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
1503 0
1503 0
1504 1
1504 1
1505 2
1505 2
1506 3
1506 3
1507 4
1507 4
1508 5
1508 5
1509 6
1509 6
1510
1510
1511 tests for 'remote()' predicate:
1511 tests for 'remote()' predicate:
1512 #. (csets in remote) (id) (remote)
1512 #. (csets in remote) (id) (remote)
1513 1. less than local current branch "default"
1513 1. less than local current branch "default"
1514 2. same with local specified "default"
1514 2. same with local specified "default"
1515 3. more than local specified specified
1515 3. more than local specified specified
1516
1516
1517 $ hg clone --quiet -U . ../remote3
1517 $ hg clone --quiet -U . ../remote3
1518 $ cd ../remote3
1518 $ cd ../remote3
1519 $ hg update -q 7
1519 $ hg update -q 7
1520 $ echo r > r
1520 $ echo r > r
1521 $ hg ci -Aqm 10
1521 $ hg ci -Aqm 10
1522 $ log 'remote()'
1522 $ log 'remote()'
1523 7
1523 7
1524 $ log 'remote("a-b-c-")'
1524 $ log 'remote("a-b-c-")'
1525 2
1525 2
1526 $ cd ../repo
1526 $ cd ../repo
1527 $ log 'remote(".a.b.c.", "../remote3")'
1527 $ log 'remote(".a.b.c.", "../remote3")'
1528
1528
1529 tests for concatenation of strings/symbols by "##"
1529 tests for concatenation of strings/symbols by "##"
1530
1530
1531 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
1531 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
1532 (_concat
1532 (_concat
1533 (_concat
1533 (_concat
1534 (_concat
1534 (_concat
1535 ('symbol', '278')
1535 ('symbol', '278')
1536 ('string', '5f5'))
1536 ('string', '5f5'))
1537 ('symbol', '1ee'))
1537 ('symbol', '1ee'))
1538 ('string', 'ce5'))
1538 ('string', 'ce5'))
1539 ('string', '2785f51eece5')
1539 ('string', '2785f51eece5')
1540 * set:
1540 * set:
1541 <baseset [0]>
1541 <baseset [0]>
1542 0
1542 0
1543
1543
1544 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
1544 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
1545 $ try "cat4(278, '5f5', 1ee, 'ce5')"
1545 $ try "cat4(278, '5f5', 1ee, 'ce5')"
1546 (func
1546 (func
1547 ('symbol', 'cat4')
1547 ('symbol', 'cat4')
1548 (list
1548 (list
1549 (list
1549 (list
1550 (list
1550 (list
1551 ('symbol', '278')
1551 ('symbol', '278')
1552 ('string', '5f5'))
1552 ('string', '5f5'))
1553 ('symbol', '1ee'))
1553 ('symbol', '1ee'))
1554 ('string', 'ce5')))
1554 ('string', 'ce5')))
1555 (_concat
1555 (_concat
1556 (_concat
1556 (_concat
1557 (_concat
1557 (_concat
1558 ('symbol', '278')
1558 ('symbol', '278')
1559 ('string', '5f5'))
1559 ('string', '5f5'))
1560 ('symbol', '1ee'))
1560 ('symbol', '1ee'))
1561 ('string', 'ce5'))
1561 ('string', 'ce5'))
1562 ('string', '2785f51eece5')
1562 ('string', '2785f51eece5')
1563 * set:
1563 * set:
1564 <baseset [0]>
1564 <baseset [0]>
1565 0
1565 0
1566
1566
1567 (check concatenation in alias nesting)
1567 (check concatenation in alias nesting)
1568
1568
1569 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
1569 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
1570 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
1570 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
1571 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
1571 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
1572 0
1572 0
1573
1573
1574 (check operator priority)
1574 (check operator priority)
1575
1575
1576 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
1576 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
1577 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
1577 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
1578 0
1578 0
1579 4
1579 4
1580
1580
1581 $ cd ..
1581 $ cd ..
1582
1582
1583 prepare repository that has "default" branches of multiple roots
1584
1585 $ hg init namedbranch
1586 $ cd namedbranch
1587
1588 $ echo default0 >> a
1589 $ hg ci -Aqm0
1590 $ echo default1 >> a
1591 $ hg ci -m1
1592
1593 $ hg branch -q stable
1594 $ echo stable2 >> a
1595 $ hg ci -m2
1596 $ echo stable3 >> a
1597 $ hg ci -m3
1598
1599 $ hg update -q null
1600 $ echo default4 >> a
1601 $ hg ci -Aqm4
1602 $ echo default5 >> a
1603 $ hg ci -m5
1604
1605 "null" revision belongs to "default" branch, but it shouldn't appear in set
1606 unless explicitly specified (issue4682)
1607
1608 $ log 'children(branch(default))'
1609 1
1610 2
1611 5
1612
1613 $ cd ..
1614
1583 test author/desc/keyword in problematic encoding
1615 test author/desc/keyword in problematic encoding
1584 # unicode: cp932:
1616 # unicode: cp932:
1585 # u30A2 0x83 0x41(= 'A')
1617 # u30A2 0x83 0x41(= 'A')
1586 # u30C2 0x83 0x61(= 'a')
1618 # u30C2 0x83 0x61(= 'a')
1587
1619
1588 $ hg init problematicencoding
1620 $ hg init problematicencoding
1589 $ cd problematicencoding
1621 $ cd problematicencoding
1590
1622
1591 $ python > setup.sh <<EOF
1623 $ python > setup.sh <<EOF
1592 > print u'''
1624 > print u'''
1593 > echo a > text
1625 > echo a > text
1594 > hg add text
1626 > hg add text
1595 > hg --encoding utf-8 commit -u '\u30A2' -m none
1627 > hg --encoding utf-8 commit -u '\u30A2' -m none
1596 > echo b > text
1628 > echo b > text
1597 > hg --encoding utf-8 commit -u '\u30C2' -m none
1629 > hg --encoding utf-8 commit -u '\u30C2' -m none
1598 > echo c > text
1630 > echo c > text
1599 > hg --encoding utf-8 commit -u none -m '\u30A2'
1631 > hg --encoding utf-8 commit -u none -m '\u30A2'
1600 > echo d > text
1632 > echo d > text
1601 > hg --encoding utf-8 commit -u none -m '\u30C2'
1633 > hg --encoding utf-8 commit -u none -m '\u30C2'
1602 > '''.encode('utf-8')
1634 > '''.encode('utf-8')
1603 > EOF
1635 > EOF
1604 $ sh < setup.sh
1636 $ sh < setup.sh
1605
1637
1606 test in problematic encoding
1638 test in problematic encoding
1607 $ python > test.sh <<EOF
1639 $ python > test.sh <<EOF
1608 > print u'''
1640 > print u'''
1609 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
1641 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
1610 > echo ====
1642 > echo ====
1611 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
1643 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
1612 > echo ====
1644 > echo ====
1613 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
1645 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
1614 > echo ====
1646 > echo ====
1615 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
1647 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
1616 > echo ====
1648 > echo ====
1617 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
1649 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
1618 > echo ====
1650 > echo ====
1619 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
1651 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
1620 > '''.encode('cp932')
1652 > '''.encode('cp932')
1621 > EOF
1653 > EOF
1622 $ sh < test.sh
1654 $ sh < test.sh
1623 0
1655 0
1624 ====
1656 ====
1625 1
1657 1
1626 ====
1658 ====
1627 2
1659 2
1628 ====
1660 ====
1629 3
1661 3
1630 ====
1662 ====
1631 0
1663 0
1632 2
1664 2
1633 ====
1665 ====
1634 1
1666 1
1635 3
1667 3
1636
1668
1637 test error message of bad revset
1669 test error message of bad revset
1638 $ hg log -r 'foo\\'
1670 $ hg log -r 'foo\\'
1639 hg: parse error at 3: syntax error in revset 'foo\\'
1671 hg: parse error at 3: syntax error in revset 'foo\\'
1640 [255]
1672 [255]
1641
1673
1642 $ cd ..
1674 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now